Also changed the order of patches as you asked.
Gleb Natapov (3): Record boot priority for each BAID/BCV/BEV. Sort IPLs according to their boot priority. Add functions for boot device path parsing.
src/ahci.c | 4 +- src/ata.c | 10 ++- src/boot.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++---- src/boot.h | 15 +++- src/floppy.c | 22 +++++- src/optionroms.c | 19 ++++- src/usb-msc.c | 2 +- src/virtio-blk.c | 2 +- 8 files changed, 292 insertions(+), 33 deletions(-)
For each BAID/BCV/BEV lookup its boot priority in boot order file. If there is no entry for a device there assign it the lowest boot priority.
Signed-off-by: Gleb Natapov gleb@redhat.com --- src/ahci.c | 4 ++-- src/ata.c | 10 ++++++++-- src/boot.c | 38 ++++++++++++++++++++++++++++++++++---- src/boot.h | 15 +++++++++++---- src/floppy.c | 22 ++++++++++++++++++++-- src/optionroms.c | 19 ++++++++++++++++--- src/usb-msc.c | 2 +- src/virtio-blk.c | 2 +- 8 files changed, 93 insertions(+), 19 deletions(-)
diff --git a/src/ahci.c b/src/ahci.c index 70c0f1c..a209c86 100644 --- a/src/ahci.c +++ b/src/ahci.c @@ -382,7 +382,7 @@ ahci_port_init(struct ahci_ctrl_s *ctrl, u32 pnr) // Setup disk geometry translation. setup_translation(&port->drive); // Register with bcv system. - add_bcv_internal(&port->drive); + add_bcv_internal(&port->drive, MAX_BOOT_PRIO); } else { // found cdrom (atapi) port->drive.blksize = CDROM_SECTOR_SIZE; @@ -397,7 +397,7 @@ ahci_port_init(struct ahci_ctrl_s *ctrl, u32 pnr) // fill cdidmap if (iscd) { map_cd_drive(&port->drive); - add_baid_cdrom(&port->drive); + add_baid_cdrom(&port->drive, MAX_BOOT_PRIO); } } dprintf(1, "%s\n", port->drive.desc); diff --git a/src/ata.c b/src/ata.c index d971480..e45de50 100644 --- a/src/ata.c +++ b/src/ata.c @@ -783,8 +783,11 @@ init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
// fill cdidmap if (iscd) { + int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_bdf, + adrive_g->chan_gf->chanid, + adrive_g->slave); map_cd_drive(&adrive_g->drive); - add_baid_cdrom(&adrive_g->drive); + add_baid_cdrom(&adrive_g->drive, prio); }
return adrive_g; @@ -834,8 +837,11 @@ init_drive_ata(struct atadrive_s *dummy, u16 *buffer) // Setup disk geometry translation. setup_translation(&adrive_g->drive);
+ int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_bdf, + adrive_g->chan_gf->chanid, + adrive_g->slave); // Register with bcv system. - add_bcv_internal(&adrive_g->drive); + add_bcv_internal(&adrive_g->drive, prio);
return adrive_g; } diff --git a/src/boot.c b/src/boot.c index 5137345..8a9246e 100644 --- a/src/boot.c +++ b/src/boot.c @@ -113,7 +113,7 @@ boot_setup(void)
// Add a BEV vector for a given pnp compatible option rom. void -add_bev(u16 seg, u16 bev, u16 desc) +add_bev(u16 seg, u16 bev, u16 desc, u8 prio) { if (! CONFIG_BOOT) return; @@ -127,11 +127,12 @@ add_bev(u16 seg, u16 bev, u16 desc) if (desc) d = MAKE_FLATPTR(seg, desc); ie->description = d; + ie->prio = prio; }
// Add a IPL entry for BAID cdrom. void -add_baid_cdrom(struct drive_s *drive_g) +add_baid_cdrom(struct drive_s *drive_g, u8 prio) { if (! CONFIG_CDROM_BOOT) return; @@ -146,11 +147,18 @@ add_baid_cdrom(struct drive_s *drive_g) ie->type = IPL_TYPE_CDROM; ie->vector = (u32)drive_g; ie->description = "DVD/CD"; + ie->prio = prio; +} + +void set_floppy_baid_prio(u8 prio) +{ + struct ipl_entry_s *ie = &IPL.bev[0]; + ie->prio = prio; }
// Add a bcv entry for an expansion card harddrive or legacy option rom void -add_bcv(u16 seg, u16 ip, u16 desc) +add_bcv(u16 seg, u16 ip, u16 desc, u8 prio) { if (! CONFIG_BOOT) return; @@ -164,11 +172,12 @@ add_bcv(u16 seg, u16 ip, u16 desc) if (desc) d = MAKE_FLATPTR(seg, desc); ie->description = d; + ie->prio = prio; }
// Add a bcv entry for an internal harddrive void -add_bcv_internal(struct drive_s *drive_g) +add_bcv_internal(struct drive_s *drive_g, u8 prio) { if (! CONFIG_BOOT) return; @@ -196,6 +205,7 @@ add_bcv_internal(struct drive_s *drive_g) ie->type = BCV_TYPE_INTERNAL; ie->vector = (u32)drive_g; ie->description = ""; + ie->prio = prio; }
@@ -571,3 +581,23 @@ handle_19(void) SET_EBDA(boot_sequence, 0); do_boot(0); } + +u8 bootprio_find_pci_device(int bdf) +{ + return MAX_BOOT_PRIO; +} + +u8 bootprio_find_ata_device(int bdf, int chanid, int slave) +{ + return MAX_BOOT_PRIO; +} + +u8 bootprio_find_fdc_device(int bfd, int port, int fdid) +{ + return MAX_BOOT_PRIO; +} + +u8 bootprio_find_named_rom(const char *name) +{ + return MAX_BOOT_PRIO; +} diff --git a/src/boot.h b/src/boot.h index 778aebd..5a4c6ea 100644 --- a/src/boot.h +++ b/src/boot.h @@ -12,6 +12,7 @@ struct ipl_entry_s { u16 subchoice; u32 vector; const char *description; + u8 prio; };
struct ipl_s { @@ -33,6 +34,7 @@ struct ipl_s { #define BCV_TYPE_EXTERNAL 0x80 #define BCV_TYPE_INTERNAL 0x02
+#define MAX_BOOT_PRIO 255
/**************************************************************** * Function defs @@ -41,12 +43,17 @@ struct ipl_s { // boot.c extern struct ipl_s IPL; void boot_setup(void); -void add_bev(u16 seg, u16 bev, u16 desc); -void add_bcv(u16 seg, u16 ip, u16 desc); +void add_bev(u16 seg, u16 bev, u16 desc, u8 prio); +void add_bcv(u16 seg, u16 ip, u16 desc, u8 prio); struct drive_s; -void add_bcv_internal(struct drive_s *drive_g); -void add_baid_cdrom(struct drive_s *drive_g); +void add_bcv_internal(struct drive_s *drive_g, u8 prio); +void add_baid_cdrom(struct drive_s *drive_g, u8 prio); +void set_floppy_baid_prio(u8 prio);
void boot_prep(void); +u8 bootprio_find_pci_device(int bdf); +u8 bootprio_find_ata_device(int bdf, int chanid, int slave); +u8 bootprio_find_fdc_device(int bfd, int port, int fdid); +u8 bootprio_find_named_rom(const char *name);
#endif // __BOOT_H diff --git a/src/floppy.c b/src/floppy.c index 6491b96..7dd3083 100644 --- a/src/floppy.c +++ b/src/floppy.c @@ -13,6 +13,9 @@ #include "cmos.h" // inb_cmos #include "pic.h" // eoi_pic1 #include "bregs.h" // struct bregs +#include "pci.h" // pci_to_bdf +#include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA +#include "boot.h" // bootprio_find_fdc_device
#define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors #define FLOPPY_DATALEN 0xff // Not used - because size code is 0x02 @@ -131,10 +134,25 @@ floppy_setup(void) // XXX - disable floppies on coreboot for now. } else { u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE); - if (type & 0xf0) + unsigned int prio0 = -1, prio1 = -1; + int bdf = pci_find_class(PCI_CLASS_BRIDGE_ISA); /* isa-to-pci bridge */ + + if (type & 0xf0) { addFloppy(0, type >> 4, DTYPE_FLOPPY); - if (type & 0x0f) + prio0 = bootprio_find_fdc_device(bdf, 0x3f0, 0); + } + if (type & 0x0f) { addFloppy(1, type & 0x0f, DTYPE_FLOPPY); + prio1 = bootprio_find_fdc_device(bdf, 0x3f0, 1); + } + if (prio1 < prio0) { + /* if B has lower boot priority swap it with A */ + struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0]; + Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][1]; + Drives.idmap[EXTTYPE_FLOPPY][1] = tmp; + set_floppy_baid_prio(prio1); + } else + set_floppy_baid_prio(prio0); }
outb(0x02, PORT_DMA1_MASK_REG); diff --git a/src/optionroms.c b/src/optionroms.c index 19672f7..171ec1c 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -75,6 +75,7 @@ struct pnp_data { u32 RomEnd = BUILD_ROM_START;
+ /**************************************************************** * Helper functions ****************************************************************/ @@ -220,6 +221,17 @@ setRomSource(u64 *sources, struct rom_header *rom, u64 source) sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN] = source; }
+static u8 +getRomPriority(u64 *sources, struct rom_header *rom) +{ + u64 source = sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN]; + if (!source) + return -1; + if (source & RS_PCIROM) + return bootprio_find_pci_device(source); + return bootprio_find_named_rom(romfile_name(source)); +} +
/**************************************************************** * Roms in CBFS @@ -408,21 +420,22 @@ optionrom_setup(void) pos += OPTION_ROM_ALIGN; continue; } + u8 romprio = getRomPriority(sources, rom); pos += ALIGN(rom->size * 512, OPTION_ROM_ALIGN); struct pnp_data *pnp = get_pnp_rom(rom); if (! pnp) { // Legacy rom. - add_bcv(FLATPTR_TO_SEG(rom), OPTION_ROM_INITVECTOR, 0); + add_bcv(FLATPTR_TO_SEG(rom), OPTION_ROM_INITVECTOR, 0, romprio); continue; } // PnP rom. if (pnp->bev) // Can boot system - add to IPL list. - add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname); + add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname, romprio); else // Check for BCV (there may be multiple). while (pnp && pnp->bcv) { - add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname); + add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname, romprio); pnp = get_pnp_next(rom, pnp); } } diff --git a/src/usb-msc.c b/src/usb-msc.c index 080efdc..c3ffe0b 100644 --- a/src/usb-msc.c +++ b/src/usb-msc.c @@ -171,7 +171,7 @@ setup_drive_hd(struct disk_op_s *op) setup_translation(op->drive_g);
// Register with bcv system. - add_bcv_internal(op->drive_g); + add_bcv_internal(op->drive_g, MAX_BOOT_PRIO);
return 0; } diff --git a/src/virtio-blk.c b/src/virtio-blk.c index 7a25826..3d2b7a6 100644 --- a/src/virtio-blk.c +++ b/src/virtio-blk.c @@ -153,7 +153,7 @@ init_virtio_blk(u16 bdf) vdrive_g->drive.pchs.spt = cfg.sectors;
setup_translation(&vdrive_g->drive); - add_bcv_internal(&vdrive_g->drive); + add_bcv_internal(&vdrive_g->drive, bootprio_find_pci_device(bdf));
snprintf(desc, MAXDESCSIZE, "Virtio disk PCI:%x:%x", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
Signed-off-by: Gleb Natapov gleb@redhat.com --- src/boot.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/src/boot.c b/src/boot.c index 8a9246e..f93c1b3 100644 --- a/src/boot.c +++ b/src/boot.c @@ -375,6 +375,41 @@ run_bcv(struct ipl_entry_s *ie) } }
+/* Bubble sort! Should be good enough for 8 elements */ +static void sort_ipls(struct ipl_entry_s *ipls, int iplscount) +{ + int stop; + + if (iplscount == 0) + return; + + do { + int i; + stop = 1; + for (i = 0; i < iplscount - 1; i++) { + if (ipls[i].prio > ipls[i+1].prio) { + struct ipl_entry_s tmp; + tmp = ipls[i]; + ipls[i] = ipls[i+1]; + ipls[i+1] = tmp; + stop = 0; + } + } + } while (!stop); +} + +static void order_boot_devices(void) +{ + if (IPL.fw_bootorder_count == 0) + return; + + sort_ipls(IPL.bcv, IPL.bcvcount); + /* Hard disk IPL inherits priority of the bootable bcv */ + IPL.bev[1].prio = IPL.bcv[0].prio; + sort_ipls(IPL.bev, IPL.bevcount); + IPL.bootorder = 0x87654321; +} + // Prepare for boot - show menu and run bcvs. void boot_prep(void) @@ -386,24 +421,38 @@ boot_prep(void)
// XXX - show available drives?
+ order_boot_devices(); + // Allow user to modify BCV/IPL order. interactive_bootmenu(); wait_threads();
- // Setup floppy boot order - int override = IPL.bev[0].subchoice; - struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0]; - Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][override]; - Drives.idmap[EXTTYPE_FLOPPY][override] = tmp; - - // Run BCVs - override = IPL.bev[1].subchoice; - if (override < IPL.bcvcount) - run_bcv(&IPL.bcv[override]); - int i; - for (i=0; i<IPL.bcvcount; i++) - if (i != override) - run_bcv(&IPL.bcv[i]); + int j; + for (j = 0; j < IPL.bevcount; j++) { + int override; + switch (IPL.bev[j].type) { + case IPL_TYPE_FLOPPY: + // Setup floppy boot order + override = IPL.bev[j].subchoice; + struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0]; + Drives.idmap[EXTTYPE_FLOPPY][0] = + Drives.idmap[EXTTYPE_FLOPPY][override]; + Drives.idmap[EXTTYPE_FLOPPY][override] = tmp; + break; + case IPL_TYPE_HARDDISK: + // Run BCVs + override = IPL.bev[j].subchoice; + if (override < IPL.bcvcount) + run_bcv(&IPL.bcv[override]); + int i; + for (i=0; i<IPL.bcvcount; i++) + if (i != override) + run_bcv(&IPL.bcv[i]); + break; + default: + break; + } + } }
Add functions that find boot device path for pci/ata/floppy/rom devices.
Signed-off-by: Gleb Natapov gleb@redhat.com --- src/boot.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/src/boot.c b/src/boot.c index f93c1b3..1b6bbaf 100644 --- a/src/boot.c +++ b/src/boot.c @@ -13,6 +13,7 @@ #include "boot.h" // struct ipl_s #include "cmos.h" // inb_cmos #include "paravirt.h" +#include "pci.h" //pci_bdf_to_*
struct ipl_s IPL;
@@ -631,22 +632,157 @@ handle_19(void) do_boot(0); }
-u8 bootprio_find_pci_device(int bdf) +/* + * function returns string representing firts device path element in 'dp' + * and puts pointer to the rest of the device path into 'end' + */ +static char *dev_path_get_node(const char *dp, const char **end) +{ + int len; + char *node; + + dp += 1; /* skip '/' */ + + *end = strchr(dp, '/'); + + if (*end == NULL) { + len = strlen(dp); /* last path element */ + *end = dp + len; + } else + len = *end - dp; + + if (len == 0) + return NULL; + + node = malloc_tmphigh(len + 1); + if (!node) { + warn_noalloc(); + return NULL; + } + memcpy(node, dp, len); + node[len] = '\0'; + + return node; +} + +static int match_unit_address(const char *pe, const char *unit_address) +{ + char *s = strchr(pe, '@'); + + if (s == NULL) + return 0; + + return !strcmp(s + 1, unit_address); +} + +static int match_next_node_address(const char *path, const char *addr, + const char **rest) +{ + char *node = dev_path_get_node(path, rest); + + if (!node) + return 0; + + int r = match_unit_address(node, addr); + free(node); + + return r; +} + +static int match_pci_node(const char *path, int bdf, const char **rest) +{ + char pci[7]; + int dev = pci_bdf_to_dev(bdf), fn = pci_bdf_to_fn(bdf); + + if (!fn) + snprintf(pci, sizeof(pci), "%x", dev); + else + snprintf(pci, sizeof(pci), "%x,%x", dev, fn); + + return match_next_node_address(path, pci, rest); +} + +#define FW_PCI_DOMAIN "/pci@i0cf8" + +static u8 find_pci_device(int bdf, u8 start_idx, const char **rest) { + u8 i; + + for (i = start_idx; i < IPL.fw_bootorder_count; i++) { + const char *path = IPL.fw_bootorder[i]; + + /* is pci domain? */ + if (memcmp(path, FW_PCI_DOMAIN, strlen(FW_PCI_DOMAIN))) + continue; + + if (match_pci_node(path + strlen(FW_PCI_DOMAIN), bdf, rest)) + return i; + } + return MAX_BOOT_PRIO; }
+u8 bootprio_find_pci_device(int bdf) +{ + const char *rest; + + return find_pci_device(bdf, 0, &rest); +} + u8 bootprio_find_ata_device(int bdf, int chanid, int slave) { - return MAX_BOOT_PRIO; + const char *rest; + u8 idx = 0; + + if (bdf == -1) + return MAX_BOOT_PRIO; /* support only pci machine for now */ + + while((idx = find_pci_device(bdf, idx, &rest)) != MAX_BOOT_PRIO) { + if (match_next_node_address(rest, chanid ? "1" : "0", &rest) && + match_next_node_address(rest, slave ? "1" : "0", &rest)) + break; + idx++; + } + + return idx; }
-u8 bootprio_find_fdc_device(int bfd, int port, int fdid) + +u8 bootprio_find_fdc_device(int bdf, int port, int fdid) { - return MAX_BOOT_PRIO; + const char *rest; + u8 idx = 0; + char addr[5]; + + if (bdf == -1) + return MAX_BOOT_PRIO; /* support only pci machine for now */ + + snprintf(addr, sizeof addr, "%04x", port); + + while((idx = find_pci_device(bdf, idx, &rest)) != MAX_BOOT_PRIO) { + if (match_next_node_address(rest, addr, &rest) && + match_next_node_address(rest, fdid ? "1" : "0", &rest)) + break; + idx++; + } + + return idx; }
u8 bootprio_find_named_rom(const char *name) { + u8 i; + + for (i = 0; i < IPL.fw_bootorder_count; i++) { + const char *path = IPL.fw_bootorder[i]; + + /* is this rom file? */ + if (memcmp(path, "/rom@", strlen("/rom@"))) + continue; + + if (strcmp(path + strlen("/rom@"), name)) + return i; + } + return MAX_BOOT_PRIO; }
On Sun, Dec 26, 2010 at 05:33:24PM +0200, Gleb Natapov wrote:
Signed-off-by: Gleb Natapov gleb@redhat.com
src/boot.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/src/boot.c b/src/boot.c index 8a9246e..f93c1b3 100644 --- a/src/boot.c +++ b/src/boot.c @@ -375,6 +375,41 @@ run_bcv(struct ipl_entry_s *ie) } }
+/* Bubble sort! Should be good enough for 8 elements */ +static void sort_ipls(struct ipl_entry_s *ipls, int iplscount)
There's a lot of boot re-ordering that can occur:
For internal hard drives, the drives are added to the BCV list in sorted order based on drive type/cntl_id (add_bcv_internal). For floppies and cdroms, the drive mapping is added in sorted order based on drive type/cntl_id (add_ordered_drive). For floppies, the mapping can be overridden by priority (patch 1). All BCVs and BEVs are then sorted based on priority (patch 2). The boot menu allows one to select a device, which can reorder the floppy mapping, reorder the execution of the BCV list, and/or alter IPL.bootorder (boot_prep). Finally, the BEV list is executed in the order given in IPL.bootorder (do_boot).
This seems complex - I think refactoring is called for.
I think we could replace the BCV list with a "bootable device list" that holds all floppies, internal hard drives, cdroms, BEVs, BCVs, ramdisks, and CBFS entries. Each entry added to this list would be inserted in sorted order based on priority/type/cntl_id. The boot menu would then show one entry per item in this list and allow a user to override the boot - which would move the given item to the front of the list. The code would then walk the list mapping drives, calling BCVs, and adding items to the BEV list. The BEV list would only be constructed after the boot menu - it would be created in the final priority order (no need for IPL.bootorder).
I'll put together some patches to demonstrate what I'm thinking.
-Kevin