This commit is contained in:
Zack Buhman 2025-10-01 16:39:06 -05:00
parent b6acb18500
commit 6c3b9d9f30
5 changed files with 235 additions and 22 deletions

9
.gitignore vendored
View File

@ -1,2 +1,11 @@
*.pyc
*~
*.cmd
*.symvers
*.o
*.kko
*.order
*.mod
*.mod.*
*.ko

View File

@ -123,22 +123,32 @@ _opcodes = """
121 debug debug 0
"""
_str_i_d = {
"reg": 0,
"ps": 1,
"ws": 2,
"fb": 3,
"id": 4,
"imm": 5,
"pll": 6,
"mc": 7,
}
_i_str_d = {
v: k for k, v in _str_i_d.items()
}
def str_to_i(s):
d = {
"reg": 0,
"ps": 1,
"ws": 2,
"fb": 3,
"id": 4,
"imm": 5,
"pll": 6,
"mc": 7,
}
if s in d:
return d[s]
if s in _str_i_d:
return _str_i_d[s]
else:
return s
def i_to_str(i):
if i in _i_str_d:
return _i_str_d[i]
else:
return i
opcodes = {
int(k): (a, b, str_to_i(c))
for k, a, b, c in map(str.split, _opcodes.strip().split("\n"))

View File

@ -1,6 +1,6 @@
import sys
import struct
from opcodes import opcodes
from opcodes import opcodes, i_to_str
import types
with open(sys.argv[1], 'rb') as f:
@ -26,6 +26,15 @@ def rstr(offset, length):
global rom
return bytes(rom[offset:offset + length])
def uN(offset, N):
if N == 1:
return u8(offset)
if N == 2:
return u16(offset)
if N == 4:
return u32(offset)
assert False, N
ATOM_BIOS_MAGIC = 0xaa55
ATOM_ATI_MAGIC_OFFSET = 0x30
ATOM_ATI_MAGIC = b" 761295520"
@ -190,31 +199,64 @@ def dest_src_size(arg, src):
case _:
return 1
def print_size(n, size):
if size == 1:
print(f"{n:02x}", end='')
elif size == 2:
print(f"{n:04x}", end='')
else:
assert False, size
def opcode_type_dest_src(offset, dest_type):
attr = u8(offset)
arg = (attr >> 0) & 0b111
src = (attr >> 3) & 0b111
return (
1
+ dest_arg_size(dest_type)
+ dest_src_size(arg, src)
)
arg_size = dest_arg_size(dest_type)
src_size = dest_src_size(arg, src)
arg_value = uN(offset + 1, arg_size)
src_value = uN(offset + 1 + arg_size, src_size)
print_size(arg_value, arg_size)
print(" <- ", end='')
print_size(src_value, src_size)
return 1 + arg_size + src_size
def opcode_type_1x16(offset, dest_type):
arg = u16(offset)
print_size(arg, 2)
return 2
def opcode_type_setregblock(offset, dest_type):
arg = u16(offset)
print_size(arg, 2)
return 2
def opcode_type_dest(offset, dest_type):
attr = u8(offset)
src = (attr >> 3) & 0b111
return 1 + dest_src_size(dest_type, src)
src_size = dest_src_size(dest_type, src)
src_arg = uN(offset + 1, src_size)
print_size(src_arg, src_size)
return 1 + src_size
def opcode_type_shift(offset, dest_type):
attr = u8(offset)
src = (attr >> 3) & 0b111
return 1 + dest_src_size(dest_type, src)
src_size = dest_src_size(dest_type, src)
src_arg = uN(offset + 1, src_size)
print_size(src_arg, src_size)
shift_arg = u8(offset + 1 + src_size)
print(" by ", end='')
print_size(shift_arg, 1)
return 1 + src_size + 1
def opcode_0(offset, dest_type):
return 0
@ -237,10 +279,12 @@ def disassemble(start, length):
opcode = u8(offset)
arg_type, name, dest_type = opcodes[opcode]
pc = (offset - start) + 6
print(f"{pc:04x} opcode {opcode:02x} {name}:{dest_type}")
offset += 1
handler = argument_handlers[arg_type]
offset += handler(offset, dest_type)
print(f"{pc:04x} opcode {opcode:02x} {name.rjust(12)} {i_to_str(dest_type).ljust(8)} ", end='')
length = handler(offset, dest_type)
offset += length
print()
def parse_table(names, table):
structure_size = u16(table + 0)

19
pci/Makefile Normal file
View File

@ -0,0 +1,19 @@
BINARY := test_pci_module
KERNEL := /lib/modules/$(shell uname -r)/build
ARCH := x86
C_FLAGS := -Wall
KMOD_DIR := $(shell pwd)
OBJECTS := main.o
ccflags-y += $(C_FLAGS)
obj-m += $(BINARY).o
$(BINARY)-y := $(OBJECTS)
$(BINARY).ko:
make -C $(KERNEL) M=$(KMOD_DIR) modules
clean:
rm -f $(BINARY).ko

131
pci/main.c Normal file
View File

@ -0,0 +1,131 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#define R500 "r500"
static struct pci_device_id r500_id_table[] = {
{ PCI_DEVICE(0x121a, 0x0002) },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, r500_id_table);
static int r500_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void r500_remove(struct pci_dev *pdev);
static struct pci_driver r500 = {
.name = R500,
.id_table = r500_id_table,
.probe = r500_probe,
.remove = r500_remove
};
struct r500_priv {
volatile u32 __iomem *hwmem;
};
/* */
static int __init r500_module_init(void)
{
return pci_register_driver(&r500);
}
static void __exit r500_module_exit(void)
{
pci_unregister_driver(&r500);
}
void release_device(struct pci_dev *pdev);
void release_device(struct pci_dev *pdev)
{
/* Free memory region */
pci_release_region(pdev, pci_select_bars(pdev, IORESOURCE_MEM));
/* And disable device */
pci_disable_device(pdev);
}
/* This function is called by the kernel */
static int r500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int bar, err;
u16 vendor, device;
unsigned long mmio_start, mmio_len;
struct r500_priv *drv_priv;
pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
pci_read_config_word(pdev, PCI_DEVICE_ID, &device);
printk(KERN_INFO "vid: %04x pid: %04x\n", vendor, device);
/* Request IO BAR */
bar = pci_select_bars(pdev, IORESOURCE_MEM);
/* Enable device memory */
err = pci_enable_device_mem(pdev);
if (err) {
printk(KERN_INFO "pci_enable_device_mem error\n");
return err;
}
/* Request memory region for the BAR */
err = pci_request_region(pdev, bar, R500);
if (err) {
printk(KERN_INFO "pci_request_region error\n");
pci_disable_device(pdev);
return err;
}
/* Get start and stop memory offsets */
mmio_start = pci_resource_start(pdev, 0);
mmio_len = pci_resource_len(pdev, 0);
printk(KERN_INFO "mmio_start %p mmio_len %p\n", (void*)mmio_start, (void*)mmio_len);
/* Allocate memory for the module private data */
drv_priv = kzalloc(sizeof(struct r500_priv), GFP_KERNEL);
if (!drv_priv) {
release_device(pdev);
return -ENOMEM;
}
/* Remap BAR to the local pointer */
drv_priv->hwmem = ioremap(mmio_start, mmio_len);
if (!drv_priv->hwmem) {
release_device(pdev);
return -EIO;
}
/* Set module private data */
/* Now we can access mapped "hwmem" from the any module's function */
pci_set_drvdata(pdev, drv_priv);
return 0;
}
/* Clean up */
static void r500_remove(struct pci_dev *pdev)
{
struct r500_priv *drv_priv = pci_get_drvdata(pdev);
if (drv_priv) {
if (drv_priv->hwmem) {
iounmap(drv_priv->hwmem);
}
kfree(drv_priv);
}
release_device(pdev);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zachary Buhman <zack@buhman.org>");
MODULE_DESCRIPTION("R500 module");
MODULE_VERSION("0.1");
module_init(r500_module_init);
module_exit(r500_module_exit);