Below it code that scans and loads PCI option ROMs, doesn’t quite work as expected with the ati-vga or nv-geforce. Ati-vga seems to run the fcode twice and while Qemu does initialize the display the screen stay dark, nv-geforce emulation is incomplete and lacks the hooks needed to initialize the display or even read the EDID of qemu’s virtual display.
More testing to come…..
I’ll test it with PCI Passthrough of some real PCI cards as soon as I can.
diff --git a/drivers/pci.c b/drivers/pci.c
index f30e427..4db3c18 100644
--- a/drivers/pci.c
+++ b/drivers/pci.c
@@ -60,6 +60,8 @@ const pci_arch_t *arch;
#define IS_PREFETCHABLE 0x40000000
#define IS_ALIASED 0x20000000
+static int execute_fcode_rom(const pci_config_t *config);
+
static int encode_int32_cells(int num_cells, u32 *prop, ucell val)
{
int i = 0;
@@ -408,22 +410,72 @@ static void ob_pci_unmap(ucell virt, ucell size) {
static void
ob_pci_bus_map_in(int *idx)
{
- uint32_t ba;
- ucell size;
- ucell virt;
-
- PCI_DPRINTF("ob_pci_bar_map_in idx=%p\n", idx);
-
- size = POP();
- POP();
- POP();
- ba = POP();
-
- virt = ob_pci_map(ba, size);
-
- PUSH(virt);
-}
-
+ fword("pci-map-in");
+ }
+
+ static void
+ ob_pci_bus_map_out(int *idx)
+ {
+ /* Should call pci-map-out but nothing to do in it yet */
+ fword("2drop");
+ }
+
+
+ static void
+ ob_pci_config_read8(int *idx)
+ {
+ cell hi = POP();
+ pci_addr addr = PCI_ADDR(PCI_BUS(hi), PCI_DEV(hi), PCI_FN(hi));
+ uint8_t val = pci_config_read8(addr, hi & 0xff);
+ PUSH(val);
+ }
+
+ static void
+ ob_pci_config_write8(int *idx)
+ {
+ cell hi = POP();
+ pci_addr addr = PCI_ADDR(PCI_BUS(hi), PCI_DEV(hi), PCI_FN(hi));
+ cell val = POP();
+ pci_config_write8(addr, hi & 0xff, val);
+ }
+
+ static void
+ ob_pci_config_read16(int *idx)
+ {
+ cell hi = POP();
+ pci_addr addr = PCI_ADDR(PCI_BUS(hi), PCI_DEV(hi), PCI_FN(hi));
+ uint16_t val = pci_config_read16(addr, hi & 0xff);
+ PUSH(val);
+ }
+
+ static void
+ ob_pci_config_write16(int *idx)
+ {
+ cell hi = POP();
+ pci_addr addr = PCI_ADDR(PCI_BUS(hi), PCI_DEV(hi), PCI_FN(hi));
+ cell val = POP();
+ pci_config_write16(addr, hi & 0xff, val);
+ }
+
+
+ static void
+ ob_pci_config_read32(int *idx)
+ {
+ cell hi = POP();
+ pci_addr addr = PCI_ADDR(PCI_BUS(hi), PCI_DEV(hi), PCI_FN(hi));
+ uint32_t val = pci_config_read32(addr, hi & 0xff);
+ PUSH(val);
+ }
+
+ static void
+ ob_pci_config_write32(int *idx)
+ {
+ cell hi = POP();
+ pci_addr addr = PCI_ADDR(PCI_BUS(hi), PCI_DEV(hi), PCI_FN(hi));
+ cell val = POP();
+ pci_config_write32(addr, hi & 0xff, val);
+ }
+/* Patch stops here!*/
static void
ob_pci_dma_alloc(int *idx)
{
@@ -459,7 +511,14 @@ NODE_METHODS(ob_pci_bus_node) = {
{ "close", ob_pci_close },
{ "decode-unit", ob_pci_decode_unit },
{ "encode-unit", ob_pci_encode_unit },
- { "pci-map-in", ob_pci_bus_map_in },
+ { "map-in", ob_pci_bus_map_in },
+ { "map-out", ob_pci_bus_map_out },
+ { "config-b@", ob_pci_config_read8 },
+ { "config-b!", ob_pci_config_write8 },
+ { "config-w@", ob_pci_config_read16 },
+ { "config-w!", ob_pci_config_write16 },
+ { "config-l@", ob_pci_config_read32 },
+ { "config-l!", ob_pci_config_write32 },
{ "dma-alloc", ob_pci_dma_alloc },
{ "dma-free", ob_pci_dma_free },
{ "dma-map-in", ob_pci_dma_map_in },
@@ -473,7 +532,14 @@ static void
ob_pci_bridge_map_in(int *idx)
{
/* As per the IEEE-1275 PCI specification, chain up to the parent */
- call_parent_method("pci-map-in");
+ call_parent_method("map-in");
+ }
+
+ static void
+ ob_pci_bridge_map_out(int *idx)
+ {
+ /* As per the IEEE-1275 PCI specification, chain up to the parent */
+ call_parent_method("map-out");
}
NODE_METHODS(ob_pci_bridge_node) = {
@@ -481,7 +547,8 @@ NODE_METHODS(ob_pci_bridge_node) = {
{ "close", ob_pci_close },
{ "decode-unit", ob_pci_decode_unit },
{ "encode-unit", ob_pci_encode_unit },
- { "pci-map-in", ob_pci_bridge_map_in },
+ { "map-in", ob_pci_bridge_map_in },
+ { "map-out", ob_pci_bridge_map_out },
{ "dma-alloc", ob_pci_dma_alloc },
{ "dma-free", ob_pci_dma_free },
{ "dma-map-in", ob_pci_dma_map_in },
@@ -1004,8 +1071,10 @@ int macio_keylargo_config_cb (const pci_config_t *config)
int vga_config_cb (const pci_config_t *config)
{
+ PCI_DPRINTF("=== VGA CONFIG CALLBACK CALLED for %s ===\n", config->path);
+
#ifdef CONFIG_PPC
- unsigned long rom;
+ unsigned long rom;
uint32_t rom_size, size, bar;
phandle_t ph;
#endif
@@ -1040,9 +1109,12 @@ int vga_config_cb (const pci_config_t *config)
}
#endif
- /* Currently we don't read FCode from the hardware but execute
- * it directly */
- feval("['] vga-driver-fcode 2 cells + 1 byte-load");
+ /* Try to execute FCode from option ROM first, fall back to built-in */
+ if (!execute_fcode_rom(config)) {
+ /* Currently we don't read FCode from the hardware but execute
+ * it directly */
+ feval("['] vga-driver-fcode 2 cells + 1 byte-load");
+ }
#ifdef CONFIG_MOL
/* Install special words for Mac On Linux */
@@ -1245,6 +1317,142 @@ void ob_pci_enable_bus_master(const pci_config_t *config)
pci_config_write16(addr, PCI_COMMAND, cmd);
}
+static int execute_fcode_rom(const pci_config_t *config)
+{
+ printk("=== EXECUTE_FCODE_ROM CALLED for %s ===\n", config->path);
+ printk("ROM assigned[6]=0x%x, sizes[6]=0x%x\n", config->assigned[6], config->sizes[6]);
+
+ unsigned long rom;
+ uint32_t rom_size;
+ uint16_t rom_command;
+ const uint8_t *fcode_data;
+
+ /* Check if device has an option ROM */
+ if (!config->assigned[6] || !config->sizes[6]) {
+ /* Try to detect and configure ROM BAR manually */
+ pci_addr addr = PCI_ADDR(PCI_BUS(config->dev), PCI_DEV(config->dev), PCI_FN(config->dev));
+ uint32_t rom_bar = pci_config_read32(addr, PCI_ROM_ADDRESS);
+
+ printk("Raw ROM BAR: 0x%x\n", rom_bar);
+
+ /* Try to probe for ROM size */
+ pci_config_write32(addr, PCI_ROM_ADDRESS, 0xFFFFFFFE);
+ uint32_t rom_size_mask = pci_config_read32(addr, PCI_ROM_ADDRESS);
+ pci_config_write32(addr, PCI_ROM_ADDRESS, rom_bar);
+
+ printk("ROM size mask: 0x%x\n", rom_size_mask);
+
+ if (rom_size_mask != 0 && rom_size_mask != 0xFFFFFFFF) {
+ rom_size = ~(rom_size_mask & ~1) + 1;
+ printk("Detected ROM size: 0x%x\n", rom_size);
+
+ /* Try to assign ROM address */
+ rom_bar = 0x88000000; /* Try a reasonable address */
+ pci_config_write32(addr, PCI_ROM_ADDRESS, rom_bar | 1); /* Enable ROM */
+
+ rom = pci_bus_addr_to_host_addr(MEMORY_SPACE_32, rom_bar);
+ printk("Assigned ROM to address: 0x%lx\n", rom);
+ } else {
+ printk("No ROM detected\n");
+ return 0;
+ }
+ } else {
+ rom = pci_bus_addr_to_host_addr(MEMORY_SPACE_32,
+ config->assigned[6] & ~0x0000000F);
+ rom_size = config->sizes[6];
+ }
+
+ /* Enable ROM access */
+ rom_command = pci_config_read16(config->dev, PCI_COMMAND);
+ rom_command |= PCI_COMMAND_MEMORY;
+ pci_config_write16(config->dev, PCI_COMMAND, rom_command);
+
+ /* Map the ROM to enable reading */
+ uint32_t rom_bar = pci_config_read32(config->dev, PCI_ROM_ADDRESS);
+ rom_bar |= PCI_ROM_ADDRESS_ENABLE;
+ pci_config_write32(config->dev, PCI_ROM_ADDRESS, rom_bar);
+
+ fcode_data = (const uint8_t *)rom;
+
+ printk("Checking FCode at ROM address 0x%lx, size 0x%x\n", rom, rom_size);
+ printk("First 16 bytes: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ fcode_data[0], fcode_data[1], fcode_data[2], fcode_data[3],
+ fcode_data[4], fcode_data[5], fcode_data[6], fcode_data[7],
+ fcode_data[8], fcode_data[9], fcode_data[10], fcode_data[11],
+ fcode_data[12], fcode_data[13], fcode_data[14], fcode_data[15]);
+
+ /* Check for FCode signature */
+ if (rom_size >= 8) {
+ /* Standard PC option ROM header check */
+ if (fcode_data[0] == 0x55 && fcode_data[1] == 0xAA) {
+ /* Look for FCode within the ROM */
+ const uint8_t *search_ptr = fcode_data;
+ uint32_t search_remaining = rom_size;
+
+ while (search_remaining >= 8) {
+ /* Check for FCode start token (0xF1) */
+ if (search_ptr[0] == 0xF1) {
+ /* Found potential FCode - verify it's properly formatted */
+ uint8_t format = search_ptr[1];
+ uint32_t length = (search_ptr[4] << 24) | (search_ptr[5] << 16) |
+ (search_ptr[6] << 8) | search_ptr[7];
+
+ if (format == 0x08 && length > 8 && (length + (search_ptr - fcode_data)) <= rom_size) {
+ printk("Found FCode in option ROM for %s, length 0x%x at offset 0x%x\n",
+ config->path, length, search_ptr - fcode_data);
+
+ printk("FCode header: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ search_ptr[0], search_ptr[1], search_ptr[2], search_ptr[3],
+ search_ptr[4], search_ptr[5], search_ptr[6], search_ptr[7]);
+
+ /* Execute the FCode directly in current device context */
+ PUSH((ucell)search_ptr);
+ PUSH(1); /* Use 1, not the actual length */
+ fword("byte-load");
+
+ printk("FCode execution completed for %s\n", config->path);
+ return 1;
+ }
+ }
+ search_ptr++;
+ search_remaining--;
+ }
+ }
+ /* Direct FCode format (starts with 0xF1) */
+ else if (fcode_data[0] == 0xF1) {
+ uint8_t format = fcode_data[1];
+ uint32_t length = (fcode_data[4] << 24) | (fcode_data[5] << 16) |
+ (fcode_data[6] << 8) | fcode_data[7];
+
+ if (format == 0x08 && length <= rom_size && length > 8) {
+ printk("Found direct FCode in option ROM for %s, length 0x%x\n",
+ config->path, length);
+
+ printk("FCode header: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ fcode_data[0], fcode_data[1], fcode_data[2], fcode_data[3],
+ fcode_data[4], fcode_data[5], fcode_data[6], fcode_data[7]);
+
+ /* Set up FCode interpreter context */
+ feval("\" /packages/fcode-interpreter\" open-package to my-self");
+
+ /* Select this device */
+ push_str(config->path);
+ feval("select-dev");
+
+ /* Execute the FCode using the working method */
+ PUSH((ucell)fcode_data);
+ PUSH(1); /* Use 1, not the actual length */
+ feval("byte-load");
+
+ printk("FCode execution completed for %s\n", config->path);
+ return 1;
+ }
+ }
+ }
+
+ printk("execute_fcode_rom finished, no FCode found\n");
+ return 0;
+}
static void ob_pci_add_properties(phandle_t phandle,
pci_addr addr, const pci_dev_t *pci_dev,
const pci_config_t *config, int num_bars)
@@ -1351,6 +1559,11 @@ static void ob_pci_add_properties(phandle_t phandle,
if (is_apple() && is_oldworld())
pci_set_AAPL_address(config);
+
+ /* Auto-execute FCode option ROMs */
+ if (execute_fcode_rom(config)) {
+ PCI_DPRINTF("FCode option ROM executed for %s\n", config->path);
+ }
PCI_DPRINTF("\n");
}