Step one of cleaning and fixing cardbus:

- Fix some especially bad style in the CIS BAR tuple parsing code.
 - activate Option ROMS correctly.
 - de-obfuscate the Option ROM image selection code.
 - Fix mis-interpretation of the PCI spec that prevented Option ROMs whose
   CIS section wasn't in the first image from working.
 - Fix mis-interpretation of the PCI spec that prevented CIS's mapped into
   MEMIO space from working at all.
 - Reject invalid CIS pointers.

Reviewed by:	imp
This commit is contained in:
scottl 2002-11-12 08:23:27 +00:00
parent e4a311f35f
commit 57f021e104

View File

@ -265,51 +265,48 @@ DECODE_PROTOTYPE(funce)
DECODE_PROTOTYPE(bar)
{
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int type;
int reg;
u_int32_t bar;
if (len != 6) {
printf("*** ERROR *** BAR length not 6 (%d)\n", len);
return (EINVAL);
} else {
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int type;
int reg;
u_int32_t bar;
reg = *(u_int16_t*)tupledata;
len = *(u_int32_t*)(tupledata + 2);
if (reg & TPL_BAR_REG_AS) {
type = SYS_RES_IOPORT;
} else {
type = SYS_RES_MEMORY;
}
bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
if (bar < 0 || bar > 5 ||
(type == SYS_RES_IOPORT && bar == 5)) {
device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n",
reg, bar);
return (0);
}
bar = CARDBUS_BASE0_REG + bar * 4;
if (type == SYS_RES_MEMORY) {
if (bar & TPL_BAR_REG_PREFETCHABLE)
dinfo->mprefetchable |= BARBIT(bar);
if (bar & TPL_BAR_REG_BELOW1MB)
dinfo->mbelow1mb |= BARBIT(bar);
} else if (type == SYS_RES_IOPORT) {
if (bar & TPL_BAR_REG_BELOW1MB)
dinfo->ibelow1mb |= BARBIT(bar);
}
DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, "
"len=%04x%s%s\n",
(type==SYS_RES_MEMORY)?"MEM":"IO", bar, len,
(type==SYS_RES_MEMORY&&dinfo->mprefetchable&BARBIT(bar))?
" (Prefetchable)":"",
type==SYS_RES_MEMORY?
((dinfo->mbelow1mb&BARBIT(bar))?" (Below 1Mb)":"")
:(dinfo->ibelow1mb&BARBIT(bar))?" (Below 1Mb)":""
));
resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
}
reg = *(u_int16_t*)tupledata;
len = *(u_int32_t*)(tupledata + 2);
if (reg & TPL_BAR_REG_AS) {
type = SYS_RES_IOPORT;
} else {
type = SYS_RES_MEMORY;
}
bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
if (bar < 0 || bar > 5 ||
(type == SYS_RES_IOPORT && bar == 5)) {
device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n",
reg, bar);
return (0);
}
bar = CARDBUS_BASE0_REG + bar * 4;
if (type == SYS_RES_MEMORY) {
if (bar & TPL_BAR_REG_PREFETCHABLE)
dinfo->mprefetchable |= BARBIT(bar);
if (bar & TPL_BAR_REG_BELOW1MB)
dinfo->mbelow1mb |= BARBIT(bar);
} else if (type == SYS_RES_IOPORT) {
if (bar & TPL_BAR_REG_BELOW1MB)
dinfo->ibelow1mb |= BARBIT(bar);
}
DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
(type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
(type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
" (Prefetchable)" : "", type == SYS_RES_MEMORY ?
((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") :
(dinfo->ibelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "" ));
resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
return (0);
}
@ -412,7 +409,7 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start,
switch (CARDBUS_CIS_SPACE(*start)) {
case CARDBUS_CIS_ASI_TUPLE:
/* CIS in tuple space need no initialization */
/* CIS in PCI config space need no initialization */
return ((struct resource*)~0UL);
case CARDBUS_CIS_ASI_BAR0:
case CARDBUS_CIS_ASI_BAR1:
@ -421,11 +418,16 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start,
case CARDBUS_CIS_ASI_BAR4:
case CARDBUS_CIS_ASI_BAR5:
*rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
pci_write_config(child, *rid, 0xffffffff, 4);
break;
case CARDBUS_CIS_ASI_ROM:
*rid = CARDBUS_ROM_REG;
#if 0
/*
* This mask doesn't contain the bit that actually enables
* the Option ROM.
*/
pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
#endif
break;
default:
device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
@ -434,12 +436,20 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start,
}
/* figure out how much space we need */
pci_write_config(child, *rid, 0xffffffff, 4);
testval = pci_read_config(child, *rid, 4);
if (testval & 1) {
/*
* This bit has a different meaning depending if we are dealing
* with normal a normal BAR or an Option ROM BAR.
*/
if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
return (NULL);
}
size = CARDBUS_MAPREG_MEM_SIZE(testval);
/* XXX Is this some kind of hack? */
if (size < 4096)
size = 4096;
/* allocate the memory space to read CIS */
@ -460,57 +470,73 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start,
if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
bus_space_tag_t bt;
bus_space_handle_t bh;
int imagenum;
u_int32_t imagesize;
int mystart = 0;
u_int32_t imagebase = 0;
u_int32_t pcidata;
u_int16_t romsig;
int romnum = 0;
int dataptr;
int imagenum;
bt = rman_get_bustag(res);
bh = rman_get_bushandle(res);
imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
for (romnum = 0;; romnum++) {
if (bus_space_read_2(bt, bh,
mystart+CARDBUS_EXROM_SIGNATURE) != 0xaa55) {
romsig = bus_space_read_2(bt, bh,
imagebase + CARDBUS_EXROM_SIGNATURE);
if (romsig != 0xaa55) {
device_printf(cbdev, "Bad header in rom %d: "
"[%x] %04x\n", romnum, mystart +
CARDBUS_EXROM_SIGNATURE,
bus_space_read_2(bt, bh,
mystart+CARDBUS_EXROM_SIGNATURE));
"[%x] %04x\n", romnum, imagebase +
CARDBUS_EXROM_SIGNATURE, romsig);
bus_release_resource(cbdev, SYS_RES_MEMORY,
*rid, res);
*rid = 0;
return (NULL);
}
dataptr = mystart + bus_space_read_2(bt, bh,
mystart + CARDBUS_EXROM_DATA_PTR);
/*
* If this was the Option ROM image that we were
* looking for, then we are done.
*/
if (romnum == imagenum)
break;
/* Find out where the next Option ROM image is */
pcidata = imagebase + bus_space_read_2(bt, bh,
imagebase + CARDBUS_EXROM_DATA_PTR);
imagesize = bus_space_read_2(bt, bh,
dataptr + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
if (imagesize == 0) {
/*
* XXX some ROMs seem to have this as zero,
* can we assume this means 1 block?
*/
device_printf(cbdev, "Warning, size of Option "
"ROM image %d is 0 bytes, assuming 512 "
"bytes.\n", romnum);
imagesize = 1;
}
/* Image size is in 512 byte units */
imagesize <<= 9;
if (romnum == imagenum)
break;
if ((bus_space_read_1(bt, bh, mystart +
CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0) {
device_printf(cbdev, "Cannot read CIS: "
"Not enough images of rom\n");
if ((bus_space_read_1(bt, bh, pcidata +
CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 1) {
device_printf(cbdev, "Cannot find CIS in "
"Option ROM\n");
bus_release_resource(cbdev, SYS_RES_MEMORY,
*rid, res);
*rid = 0;
return (NULL);
}
mystart += imagesize;
imagebase += imagesize;
}
*start = mystart + CARDBUS_CIS_ADDR(*start);
*start = imagebase + CARDBUS_CIS_ADDR(*start);
} else {
*start = CARDBUS_CIS_SPACE(*start);
*start = CARDBUS_CIS_ADDR(*start);
}
return (res);
}
@ -553,7 +579,8 @@ cardbus_parse_cis(device_t cbdev, device_t child,
bzero(tupledata, MAXTUPLESIZE);
expect_linktarget = TRUE;
start = pci_read_config(child, CARDBUS_CIS_REG, 4);
if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0)
return (ENXIO);
off = 0;
res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
if (res == NULL)