[prev in list] [next in list] [prev in thread] [next in thread] 

List:       bochs-dev
Subject:    Re: [Bochs-developers] Enhancing support for PCI
From:       "Sebastian Herbszt" <herbszt () gmx ! de>
Date:       2008-10-19 23:01:09
Message-ID: 69B591EF5CB2450FB26E683FE6638719 () FSCPC
[Download RAW message or body]

Mark Marshall wrote:

> My patch has a few parts:
> 
> Extend the bx_pci_device_stub_c so that it can contain an EEPROM image. 
>  This will be needed by any PCI device that has an EEPROM, so this 
> seemed like the best place for it.
> 
> Extend bx_pcivga_c and bx_svga_cirrus_c so that they expose their option 
> ROM's through the EEPROM BAR.
> 
> Change rombios32.c so that after we have allocated all of the BARs for 
> all PCI devices we then copy the option ROMs into shadow memory in the 
> 0xC0000 to 0xE0000 region.  The BIOS should check that the VID and PID 
> match the option ROM, but I have disabled this test at the moment - it 
> will cause big problems with the VGA BIOSes (as they are used with 
> different hardware).  I don't think this is a problem.

#ifdef sounds reasonable

> Change romios.c so that we only scan for the VGA after we have done the 
> rombios32 initialisation.  The VGA option ROM will only exist after this 
> code has run.  I've also added a function that makes the option ROMs 
> readonly once the init functions have been called.
> 
> 
> I'm aware that this is not perfect in places.  The main problem that I'm 
> having is letting all of the different parts of the system know what is 
> going on.
> 
> problem 1)
> If we do have an option ROM loaded then I think this will clash with my 
> code.  I'm not sure how we tell the BIOS that there really is a ROM in 
> the address map.  I'm guessing that in a real PCI PC there can't be any 
> ROM in the first 1Meg.  (they are all shadows).  I don't know what 
> happens if you have both PCI and ISA devices (I think some more reading 
> is needed)

I think the pci option rom loading code should scan the option rom space
for existing (valid) roms and then use the spare space:
optromimage1: file=optionalrom.bin, address=0xd0000
does load an option rom for an isa device. New code does detect it and reads
it size and then updates pci_bios_rom_addr.

> problem 2)
> Communicating the option ROM layout to rombios.c.  After we have called 
> all of the init functions we need to write-protect the shadowed memory. 
>  We should probably indicate which bits have option rom in them and 
> which bits don't.  We can then leave unused sections as RAM for use by DOS.

Your current code does only write protect memory associated with PAM1 and
PAM3. I think for now it should be done for PAM2 and PAM4 too.

> problem 3)
> The option ROMs should be called in order, one at a time.  The best 
> thing would be to have the rombios32 code drop back to 16-bit mode and 
> call the option ROM init function.  This would allow us to pack the ROM 
> images more.  The option ROMs should also be called with the PCI bus, 
> device and function as a parameter, which is hard to do in the current 
> setup.

Or the eeprom loading code could be done in rombios.c instead of rombios32.c.
Any reason you have done it in rombios32.c?

> problem 4)
> I've not written code for configs with BX_PCIBIOS set but without 
> BX_ROMBIOS32.
> 
> I think the best fix for 1 is do disallow the use of the option-rom 
> command when we are using PCI.  This will be unpopular, because change 
> always is, but it will make things more 'correct'.  I'm not sure how 
> this firs in with PCs that have both PCI and ISA buses?

I think bochs can be configured with an ISA video card (CL-GD5430) and
a ne2k pci card. We should still allow that configuration.

> Problems 2 & 3 can be fixed by making the rombios32 code drop back to 
> 16-bit mode, and then call the init functions itself.  We will then need 
> to use the rom_scan code in rombios.c to build the IPL table.
> 
> Do people care about 4?
> 
> I look for to your feedback,

I suggest using the optromimage1-4 syntax for non-pci roms.
i440fxsupport one could be extended for eeprom support, like
i440fxsupport: enabled=1, slot1=pcivga,eeprom=VGABIOS-lgpl-latest

> RCS file: /cvsroot/bochs/bochs/main.cc,v
> retrieving revision 1.383
> diff -u -r1.383 main.cc
> --- main.cc 1 Oct 2008 11:36:04 -0000 1.383
> +++ main.cc 17 Oct 2008 09:14:59 -0000
> @@ -1042,7 +1042,9 @@
>   // First load the BIOS and VGABIOS
>   BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_ROM_PATH)->getptr(),
>                       SIM->get_param_num(BXPN_ROM_ADDRESS)->get(), 0);
> +#if !BX_SUPPORT_PCI
>   BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr(), 0xc0000, 1);
> +#endif

maybe runtime check here if the vga card is isa or pci instead of the !BX_SUPPORT_PCI

>   // Then load the optional ROM images
>   if (strcmp(SIM->get_param_string(BXPN_OPTROM1_PATH)->getptr(), "") !=0)
> Index: bios/rombios.c
> ===================================================================
> RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v
> retrieving revision 1.214
> diff -u -r1.214 rombios.c
> --- bios/rombios.c 1 Oct 2008 07:41:22 -0000 1.214
> +++ bios/rombios.c 17 Oct 2008 09:15:08 -0000
> @@ -9732,6 +9732,30 @@
>   db 0 ;; reserved
> pci_routing_table_structure_end:
> 
> +pcibios_protect_roms:
> +  wbinvd
> +
> +  mov al, #0x09
> +  xor bx, bx
> +  mov di, #0x5A
> +  call pcibios_real
> +  and cx, #0xDDDD
> +  mov al, #0x0C
> +  xor bx, bx
> +  mov di, #0x5A
> +  call pcibios_real
> +
> +  mov al, #0x09
> +  xor bx, bx
> +  mov di, #0x5C
> +  call pcibios_real
> +  and cx, #0xDDDD
> +  mov al, #0x0C
> +  xor bx, bx
> +  mov di, #0x5C
> +  call pcibios_real
> +  ret
> +

maybe check if we're on a 440fx compatible PMC

> #if !BX_ROMBIOS32
> pci_irq_list:
>   db 11, 10, 9, 5;
> @@ -10539,12 +10563,6 @@
> #endif
>   out  0xa1, AL ;slave  pic: unmask IRQ 12, 13, 14
> 
> -  mov  cx, #0xc000  ;; init vga bios
> -  mov  ax, #0xc780
> -  call rom_scan
> -
> -  call _print_bios_banner
> -
> #if BX_ROMBIOS32
>   call rombios32_init
> #else
> @@ -10585,10 +10603,16 @@
> 
>   call _init_boot_vectors
> 
> -  mov  cx, #0xc800  ;; init option roms
> +  mov  cx, #0xc000  ;; init vga bios & option roms
>   mov  ax, #0xe000
>   call rom_scan

i moved the vga rom scan before rombios32_init so we could use
vga output in rombios32.c. Since it's not used so far we can move it
back

> +#if BX_PCIBIOS
> +  call pcibios_protect_roms
> +#endif
> +
> +  call _print_bios_banner
> +
> #if BX_ELTORITO_BOOT
>   call _interactive_bootkey
> #endif // BX_ELTORITO_BOOT
> Index: bios/rombios32.c
> ===================================================================
> RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v
> retrieving revision 1.32
> diff -u -r1.32 rombios32.c
> --- bios/rombios32.c 15 Oct 2008 19:04:09 -0000 1.32
> +++ bios/rombios32.c 17 Oct 2008 09:15:09 -0000
> @@ -548,6 +548,7 @@
> static uint32_t pci_bios_io_addr;
> static uint32_t pci_bios_mem_addr;
> static uint32_t pci_bios_bigmem_addr;
> +static uint32_t pci_bios_rom_addr;
> /* host irqs corresponding to PCI irqs A-D */
> static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
> static PCIDevice i440_pcidev;
> @@ -751,7 +752,9 @@
> {
>     int class;
>     uint32_t *paddr;
> -    int i, pin, pic_irq, vendor_id, device_id;
> +    int i, pin, pic_irq, vendor_id, device_id, start_slot;
> +
> +    start_slot = 0;
> 
>     class = pci_config_readw(d, PCI_CLASS_DEVICE);
>     vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
> @@ -776,10 +779,12 @@
>         }
>         break;
>     case 0x0300:
> -        if (vendor_id != 0x1234)
> -            goto default_map;
> -        /* VGA: map frame buffer to default Bochs VBE address */
> -        pci_set_io_region_addr(d, 0, 0xE0000000);
> +        if (vendor_id == 0x1234) {
> +     /* VGA: map frame buffer to default Bochs VBE address */
> +     pci_set_io_region_addr(d, 0, 0xE0000000);
> +     start_slot = 1;
> + }
> + goto default_map;
>         break;
>     case 0x0800:
>         /* PIC */
> @@ -801,7 +806,7 @@
>     default:
>     default_map:
>         /* default memory mappings */
> -        for(i = 0; i < PCI_NUM_REGIONS; i++) {
> +        for(i = start_slot; i < PCI_NUM_REGIONS; i++) {
>             int ofs;
>             uint32_t val, size ;
> 
> @@ -851,6 +856,132 @@
>     }
> }
> 
> +#define PCI_EEPROM_CHECK_FOR_PCIR
> +#define PCI_EEPROM_ACCEPT_ANY
> +
> +static void pci_bios_init_rom(PCIDevice *d, int class)
> +{
> +    uint32_t i, addr, end_addr;
> +    uint32_t shadow;
> +    uint8_t isa_header[3];

use a structure?

> +    uint32_t start_size;
> +#ifdef PCI_EEPROM_CHECK_FOR_PCIR
> +    uint8_t pci_ptr[2];
> +    uint32_t pci_header_addr;
> +    uint8_t pci_header[24];

use a structure?

> +    int vendor_id, device_id;
> +#endif
> +
> +    addr = pci_config_readl(d, 0x30) & ~0xF;

hide 0x30 behind something like PCI_ROM_ADDRESS

> +    if (addr == 0)
> + return;
> +
> +    memcpy(isa_header, (void *)addr, 3);
> +
> +    BX_INFO("PCI: EEPROM %02x %02x %02x (%x)\n",
> +     isa_header[0], isa_header[1], isa_header[2], addr);
> +
> +    if (isa_header[0] != 0x55 || isa_header[1] != 0xaa) {

rom_header.signature?

> + BX_INFO("PCI: Bad ISA header\n");
> + goto done;
> +    }
> +
> +    start_size = isa_header[2] * 512;

rom_header.size?

> +
> +#ifdef PCI_EEPROM_CHECK_FOR_PCIR
> +    memcpy(pci_ptr, (void *)(addr + 0x18), 2);

something like PCIR_HEADER_OFFSET?

> +    pci_header_addr = addr + readw(pci_ptr);
> +
> +    memcpy(pci_header, (void *)pci_header_addr, 24);

sizeof pci_header?

> +
> +    if (pci_header[0] != 'P' ||
> + pci_header[1] != 'C' ||
> + pci_header[2] != 'I' ||
> + pci_header[3] != 'R') {

pci_header.signature?

> + BX_INFO("PCI: Bad PCIR header\n");
> +#ifndef PCI_EEPROM_ACCEPT_ANY
> + goto done;
> +#endif
> +    } else {
> + vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
> + device_id = pci_config_readw(d, PCI_DEVICE_ID);
> +
> + if (readw(pci_header+4) != vendor_id ||
> +     readw(pci_header+6) != device_id ||
> +     readw(pci_header+14) != class) {

pci_header.vendor_id, pci_header.device_id and
pci_header.class

> +     BX_INFO("PCI: VID, PID & class don't match  "
> +     "(pci) %04x %04x %04x / (eeprom) %04x %04x %04x\n",
> +     vendor_id, device_id, class,
> +     readw(pci_header+4), readw(pci_header+6),
> +     readw(pci_header+13));
> +#ifndef PCI_EEPROM_ACCEPT_ANY
> +     goto done;
> +#endif
> + }
> +    }
> +#endif
> +
> +    end_addr = pci_bios_rom_addr + ((start_size + 0x3FFF) & ~0x3FFF);
> +
> +    /* remap the expansion BIOS to shadow RAM and keep it read/write
> +       until after we have run the init function */
> +
> +    /* We have to read this as two uint16's because it is unaligned. */
> +    shadow = pci_config_readw(&i440_pcidev, 0x5a);
> +    shadow |= pci_config_readw(&i440_pcidev, 0x5c) << 16;
> +    for (i = pci_bios_rom_addr; i < end_addr; i += 0x4000) {
> + int page = (i - 0xC0000) / 0x4000;
> + shadow |= 0x3 << (page * 4);
> +    }
> +    pci_config_writew(&i440_pcidev, 0x5a, shadow);
> +    pci_config_writew(&i440_pcidev, 0x5c, shadow >> 16);
> +
> +    /* copy the image to shadow memory */
> +    memcpy((void *)pci_bios_rom_addr, (void *)addr, start_size);
> +
> +    BX_INFO("PCI: Shadowed ROM %08x -> %08x (%x)\n",
> +     addr, pci_bios_rom_addr, start_size);
> +
> +    pci_bios_rom_addr = end_addr;
> +
> +done:
> +    /* Disable the EEPROM BAR */
> +    pci_config_writel(d, 0x30, 0);
> +
> +    /* To be fully accurate we should now call the init function of
> +     * the option ROM.  We should pass in the Bus,Device,Function in
> +     * AX.  After the init function has finished we should recheck the
> +     * size field, and possibly shrink the amount of shadow memory
> +     * used. */
> +}
> +
> +/* We can copy the option ROMs to anywhere in the 0xC0000 - 0xE0000
> + * area, the only restricition is that the VGA ROM must be mapped to
> + * 0xC0000.  To make this easy we do two passes.  On the first pass we
> + * do the VGA and on the second pass we do everything else.
> + *
> + * If there are two or more VGAs we should only do the first one.
> + */
> +
> +static void pci_bios_init_vga_rom(PCIDevice *d)
> +{
> +    int class;
> +    /* Check to see if we have done a VGA yet? */
> +    if (pci_bios_rom_addr != 0xC0000)
> + return;
> +    class = pci_config_readw(d, PCI_CLASS_DEVICE);
> +    if (class == 0x0300)
> + pci_bios_init_rom(d, class);
> +}
> +
> +static void pci_bios_init_non_vga_rom(PCIDevice *d)
> +{
> +    int class;
> +    class = pci_config_readw(d, PCI_CLASS_DEVICE);
> +    if (class != 0x0300)
> + pci_bios_init_rom(d, class);
> +}
> +
> void pci_for_each_device(void (*init_func)(PCIDevice *d))
> {
>     PCIDevice d1, *d = &d1;
> @@ -875,12 +1006,16 @@
>     pci_bios_io_addr = 0xc000;
>     pci_bios_mem_addr = 0xf0000000;
>     pci_bios_bigmem_addr = ram_size;
> +    pci_bios_rom_addr= 0x0C0000;

should be auto-detected for the ISA option-rom case

>     if (pci_bios_bigmem_addr < 0x90000000)
>         pci_bios_bigmem_addr = 0x90000000;
> 
>     pci_for_each_device(pci_bios_init_bridges);
> 
>     pci_for_each_device(pci_bios_init_device);
> +
> +    pci_for_each_device(pci_bios_init_vga_rom);
> +    pci_for_each_device(pci_bios_init_non_vga_rom);
> }
> 
> /****************************************************/

- Sebastian


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
bochs-developers mailing list
bochs-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bochs-developers
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic