On 10/15/2010 03:51 PM, Stefan Weil wrote:
PCI device with different device ids sometimes share the same rom code. Only the device id and the checksum differ in a boot rom for such devices.
BTW, SeaBIOS doesn't reject ROMs when they're loaded via rombar, only when they're loaded via romfile.
Maybe it's better to use fw_cfg to explicitly tell SeaBIOS to ignore the PCI device id in the rom header for a certain device?
Regards,
Anthony Liguori
The i825xx ethernet controller family is a typical example which is implemented in hw/eepro100.c. It uses at least 3 different device ids, so normally 3 boot roms would be needed.
By automatically patching the device id (and the checksum) in qemu, all emulated family members can share the same boot rom.
Cc: Markus Armbrusterarmbru@redhat.com Cc: Michael S. Tsirkinmst@redhat.com Signed-off-by: Stefan Weilweil@mail.berlios.de
hw/pci.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-)
diff --git a/hw/pci.c b/hw/pci.c index 1280d4d..c1f8218 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1797,6 +1797,57 @@ static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, p cpu_register_physical_memory(addr, size, pdev->rom_offset); }
+/* Patch the PCI device id in a PCI rom image if necessary.
- This is needed for an option rom which is used for more than one device. */
+static void pci_patch_device_id(PCIDevice *pdev, uint8_t *ptr, int size) +{
- uint16_t vendor_id;
- uint16_t device_id;
- uint16_t rom_vendor_id;
- uint16_t rom_device_id;
- uint16_t rom_magic;
- uint16_t pcir_offset;
- /* Words in rom data are little endian (like in PCI configuration),
so they can be read / written with pci_get_word / pci_set_word. */
- /* Only a valid rom will be patched. */
- rom_magic = pci_get_word(ptr);
- if (rom_magic != 0xaa55) {
PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
return;
- }
- pcir_offset = pci_get_word(ptr + 0x18);
- if (pcir_offset + 8>= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
return;
- }
- vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
- device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
- rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
- rom_device_id = pci_get_word(ptr + pcir_offset + 6);
- /* Don't patch a rom with wrong vendor id (might be changed if needed). */
- if (vendor_id != rom_vendor_id) {
return;
- }
- PCI_DPRINTF("ROM id %04x%04x / PCI id %04x%04x\n",
vendor_id, device_id, rom_vendor_id, rom_device_id);
- if (device_id != rom_device_id) {
/* Patch device id and checksum (at offset 6 for etherboot roms). */
uint8_t checksum;
checksum = ptr[6];
checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id>> 8);
checksum -= (uint8_t)device_id + (uint8_t)(device_id>> 8);
PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
ptr[6] = checksum;
pci_set_word(ptr + pcir_offset + 6, device_id);
- }
+}
- /* Add an option rom for the device */ static int pci_add_option_rom(PCIDevice *pdev) {
@@ -1849,6 +1900,8 @@ static int pci_add_option_rom(PCIDevice *pdev) load_image(path, ptr); qemu_free(path);
- pci_patch_device_id(pdev, ptr, size);
pci_register_bar(pdev, PCI_ROM_SLOT, size, 0, pci_map_option_rom);
On 10/15/10 23:05, Anthony Liguori wrote:
On 10/15/2010 03:51 PM, Stefan Weil wrote:
PCI device with different device ids sometimes share the same rom code. Only the device id and the checksum differ in a boot rom for such devices.
BTW, SeaBIOS doesn't reject ROMs when they're loaded via rombar, only when they're loaded via romfile.
SeaBIOS rejects them when loaded from the rom bar and doesn't reject them when loaded via fw_cfg.
Using the rom bar is the prefered way though, fw_cfg is only there for compatibility with older versions.
Maybe it's better to use fw_cfg to explicitly tell SeaBIOS to ignore the PCI device id in the rom header for a certain device?
Patching the rom is fine IMHO. Why create + use a separate communication path when we can use a much simpler approach?
cheers, Gerd
On 10/18/2010 05:09 AM, Gerd Hoffmann wrote:
On 10/15/10 23:05, Anthony Liguori wrote:
On 10/15/2010 03:51 PM, Stefan Weil wrote:
PCI device with different device ids sometimes share the same rom code. Only the device id and the checksum differ in a boot rom for such devices.
BTW, SeaBIOS doesn't reject ROMs when they're loaded via rombar, only when they're loaded via romfile.
SeaBIOS rejects them when loaded from the rom bar and doesn't reject them when loaded via fw_cfg.
What I meant was, rombar=0 in qdev. Sometimes my fingers don't work the same way my brain does :-)
Using the rom bar is the prefered way though, fw_cfg is only there for compatibility with older versions.
Maybe it's better to use fw_cfg to explicitly tell SeaBIOS to ignore the PCI device id in the rom header for a certain device?
Patching the rom is fine IMHO. Why create + use a separate communication path when we can use a much simpler approach?
How does this interact with PCI device passthrough?
We clearly can't patch in that case whereas if we had a hint to SeaBIOS, it would still work.
Regards,
Anthony Liguori
cheers, Gerd
On 10/18/2010 08:39 PM, Anthony Liguori wrote:
SeaBIOS rejects them when loaded from the rom bar and doesn't reject them when loaded via fw_cfg.
What I meant was, rombar=0 in qdev. Sometimes my fingers don't work the same way my brain does :-)
Are you using qmp or the human monitor protocol?
On 10/21/2010 05:09 AM, Avi Kivity wrote:
On 10/18/2010 08:39 PM, Anthony Liguori wrote:
SeaBIOS rejects them when loaded from the rom bar and doesn't reject them when loaded via fw_cfg.
What I meant was, rombar=0 in qdev. Sometimes my fingers don't work the same way my brain does :-)
Are you using qmp or the human monitor protocol?
I'm still running on a DCE/RPC implementation from the early 80s.
Regards,
Anthony Liguori
On 10/21/2010 03:14 PM, Anthony Liguori wrote:
On 10/21/2010 05:09 AM, Avi Kivity wrote:
On 10/18/2010 08:39 PM, Anthony Liguori wrote:
SeaBIOS rejects them when loaded from the rom bar and doesn't reject them when loaded via fw_cfg.
What I meant was, rombar=0 in qdev. Sometimes my fingers don't work the same way my brain does :-)
Are you using qmp or the human monitor protocol?
I'm still running on a DCE/RPC implementation from the early 80s.
Well, I hope you keep it up to date. I wouldn't want a vulnerability inserted into qemu by an attacker controlling a maintainer's hands.