X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=probe_roms.c;h=b0b088332bb6ab5f4acb8541a9f0b8b0e5676111;hb=2ecda5a3fa0382c615aebe11111c671357137378;hp=06ec3f5a4485c78e6c8ffc7ccadb65ef2cf57169;hpb=45b662b611a6fbbdd018a65b6f205e91df884c37;p=thirdparty%2Fmdadm.git diff --git a/probe_roms.c b/probe_roms.c index 06ec3f5a..b0b08833 100644 --- a/probe_roms.c +++ b/probe_roms.c @@ -20,6 +20,7 @@ */ #include "probe_roms.h" +#include "mdadm.h" #include #include #include @@ -30,9 +31,9 @@ static void *rom_mem = MAP_FAILED; static int rom_fd = -1; -const static int rom_len = 0xf0000 - 0xc0000; /* option-rom memory region */ +static const int rom_len = 0xf0000 - 0xc0000; /* option-rom memory region */ static int _sigbus; -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +static unsigned long rom_align; static void sigbus(int sig) { @@ -76,11 +77,20 @@ void probe_roms_exit(void) } } -int probe_roms_init(void) +int probe_roms_init(unsigned long align) { - int fd; + int fd = -1; int rc = 0; + /* valid values are 2048 and 512. 512 is for PCI-3.0 compliant + * systems, or systems that do not have dangerous/legacy ISA + * devices. 2048 should always be safe + */ + if (align == 512 || align == 2048) + rom_align = align; + else + return -1; + if (signal(SIGBUS, sigbus) == SIG_ERR) rc = -1; if (rc == 0) { @@ -96,9 +106,11 @@ int probe_roms_init(void) if (rc == 0) rom_fd = fd; - else + else { + if (fd >= 0) + close(fd); probe_roms_exit(); - + } return rc; } @@ -117,50 +129,60 @@ static void *isa_bus_to_virt(unsigned long addr) struct resource { unsigned long start; unsigned long end; + unsigned long data; const char *name; }; static struct resource system_rom_resource = { .name = "System ROM", .start = 0xf0000, + .data = 0, .end = 0xfffff, }; static struct resource extension_rom_resource = { .name = "Extension ROM", .start = 0xe0000, + .data = 0, .end = 0xeffff, }; static struct resource adapter_rom_resources[] = { { - .name = "Adapter ROM", + .name = "Adapter ROM", .start = 0xc8000, + .data = 0, .end = 0, }, { - .name = "Adapter ROM", + .name = "Adapter ROM", .start = 0, + .data = 0, .end = 0, }, { - .name = "Adapter ROM", + .name = "Adapter ROM", .start = 0, + .data = 0, .end = 0, }, { - .name = "Adapter ROM", + .name = "Adapter ROM", .start = 0, + .data = 0, .end = 0, }, { - .name = "Adapter ROM", + .name = "Adapter ROM", .start = 0, + .data = 0, .end = 0, }, { - .name = "Adapter ROM", + .name = "Adapter ROM", .start = 0, + .data = 0, .end = 0, } }; static struct resource video_rom_resource = { - .name = "Video ROM", + .name = "Video ROM", .start = 0xc0000, + .data = 0, .end = 0xc7fff, }; @@ -186,7 +208,7 @@ static int romchecksum(const unsigned char *rom, unsigned long length) int scan_adapter_roms(scan_fn fn) { /* let scan_fn examing each of the adapter roms found by probe_roms */ - int i; + unsigned int i; int found; if (rom_fd < 0) @@ -198,7 +220,8 @@ int scan_adapter_roms(scan_fn fn) if (res->start) { found = fn(isa_bus_to_virt(res->start), - isa_bus_to_virt(res->end)); + isa_bus_to_virt(res->end), + isa_bus_to_virt(res->data)); if (found) break; } else @@ -208,19 +231,25 @@ int scan_adapter_roms(scan_fn fn) return found; } +static unsigned long align(unsigned long addr, unsigned long alignment) +{ + return (addr + alignment - 1) & ~(alignment - 1); +} + void probe_roms(void) { const void *rom; unsigned long start, length, upper; unsigned char c; - int i; + unsigned int i; + __u16 val=0; if (rom_fd < 0) return; /* video rom */ upper = adapter_rom_resources[0].start; - for (start = video_rom_resource.start; start < upper; start += 2048) { + for (start = video_rom_resource.start; start < upper; start += rom_align) { rom = isa_bus_to_virt(start); if (!romsignature(rom)) continue; @@ -239,7 +268,7 @@ void probe_roms(void) break; } - start = (video_rom_resource.end + 1 + 2047) & ~2047UL; + start = align(video_rom_resource.end + 1, rom_align); if (start < upper) start = upper; @@ -255,7 +284,7 @@ void probe_roms(void) } /* check for adapter roms on 2k boundaries */ - for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { + for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += rom_align) { rom = isa_bus_to_virt(start); if (!romsignature(rom)) continue; @@ -266,14 +295,23 @@ void probe_roms(void) /* 0 < length <= 0x7f * 512, historically */ length = c * 512; + /* Retrieve 16-bit pointer to PCI Data Structure (offset 18h-19h) + * The data can be within 64KB forward of the first location + * of this code image. The pointer is in little-endian order + */ + + if (probe_address16(rom + 0x18, &val) != 0) + continue; + val = __le16_to_cpu(val); + /* but accept any length that fits if checksum okay */ if (!length || start + length > upper || !romchecksum(rom, length)) continue; adapter_rom_resources[i].start = start; + adapter_rom_resources[i].data = start + (unsigned long) val; adapter_rom_resources[i].end = start + length - 1; - start = adapter_rom_resources[i++].end & ~2047UL; + start = adapter_rom_resources[i++].end & ~(rom_align - 1); } } -