From 6c3b9d9f30f75301ae62b291cdc9e049a657d954 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 1 Oct 2025 16:39:06 -0500 Subject: [PATCH] add pci --- .gitignore | 9 ++++ atom/opcodes.py | 34 ++++++++----- atom/parse.py | 64 +++++++++++++++++++---- pci/Makefile | 19 +++++++ pci/main.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 235 insertions(+), 22 deletions(-) create mode 100644 pci/Makefile create mode 100644 pci/main.c diff --git a/.gitignore b/.gitignore index f3d74a9..49b8a83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,11 @@ *.pyc *~ + +*.cmd +*.symvers +*.o +*.kko +*.order +*.mod +*.mod.* +*.ko diff --git a/atom/opcodes.py b/atom/opcodes.py index a37e795..a63cf3a 100644 --- a/atom/opcodes.py +++ b/atom/opcodes.py @@ -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")) diff --git a/atom/parse.py b/atom/parse.py index 8710ea5..f44ee96 100644 --- a/atom/parse.py +++ b/atom/parse.py @@ -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) diff --git a/pci/Makefile b/pci/Makefile new file mode 100644 index 0000000..4178392 --- /dev/null +++ b/pci/Makefile @@ -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 diff --git a/pci/main.c b/pci/main.c new file mode 100644 index 0000000..6ee4867 --- /dev/null +++ b/pci/main.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("R500 module"); +MODULE_VERSION("0.1"); + +module_init(r500_module_init); +module_exit(r500_module_exit);