#include "config.h" // CONFIG_*
#include "disk.h" // cdrom_boot
#include "bregs.h" // struct bregs
-#include "boot.h" // struct ipl_s
+#include "boot.h" // func defs
#include "cmos.h" // inb_cmos
-#include "paravirt.h"
-
-struct ipl_s IPL;
+#include "paravirt.h" // romfile_loadfile
+#include "pci.h" //pci_bdf_to_*
/****************************************************************
* Boot priority ordering
****************************************************************/
+static char **Bootorder;
+static int BootorderCount;
+
static void
loadBootOrder(void)
{
+ if (!CONFIG_BOOTORDER)
+ return;
+
char *f = romfile_loadfile("bootorder", NULL);
if (!f)
return;
- int i;
- IPL.fw_bootorder_count = 1;
+ int i = 0;
+ BootorderCount = 1;
while (f[i]) {
if (f[i] == '\n')
- IPL.fw_bootorder_count++;
+ BootorderCount++;
i++;
}
- IPL.fw_bootorder = malloc_tmphigh(IPL.fw_bootorder_count*sizeof(char*));
- if (!IPL.fw_bootorder) {
+ Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*));
+ if (!Bootorder) {
warn_noalloc();
free(f);
+ BootorderCount = 0;
return;
}
dprintf(3, "boot order:\n");
i = 0;
do {
- IPL.fw_bootorder[i] = f;
+ Bootorder[i] = f;
f = strchr(f, '\n');
- if (f) {
- *f = '\0';
- f++;
- dprintf(3, "%d: %s\n", i, IPL.fw_bootorder[i]);
- i++;
+ if (f)
+ *(f++) = '\0';
+ nullTrailingSpace(Bootorder[i]);
+ dprintf(3, "%d: %s\n", i+1, Bootorder[i]);
+ i++;
+ } while (f);
+}
+
+// See if 'str' starts with 'glob' - if glob contains an '*' character
+// it will match any number of characters in str that aren't a '/' or
+// the next glob character.
+static char *
+glob_prefix(const char *glob, const char *str)
+{
+ for (;;) {
+ if (!*glob && (!*str || *str == '/'))
+ return (char*)str;
+ if (*glob == '*') {
+ if (!*str || *str == '/' || *str == glob[1])
+ glob++;
+ else
+ str++;
+ continue;
}
- } while(f);
+ if (*glob != *str)
+ return NULL;
+ glob++;
+ str++;
+ }
}
-int bootprio_find_pci_device(int bdf)
+// Search the bootorder list for the given glob pattern.
+static int
+find_prio(const char *glob)
{
+ dprintf(1, "Searching bootorder for: %s\n", glob);
+ int i;
+ for (i = 0; i < BootorderCount; i++)
+ if (glob_prefix(glob, Bootorder[i]))
+ return i+1;
return -1;
}
-int bootprio_find_ata_device(int bdf, int chanid, int slave)
+#define FW_PCI_DOMAIN "/pci@i0cf8"
+
+static char *
+build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
{
- return -1;
+ // Build the string path of a bdf - for example: /pci@i0cf8/isa@1,2
+ char *p = buf;
+ if (pci->parent) {
+ p = build_pci_path(p, max, "pci-bridge", pci->parent);
+ } else {
+ if (pci->rootbus)
+ p += snprintf(p, max, "/pci-root@%x", pci->rootbus);
+ p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
+ }
+
+ int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf);
+ p += snprintf(p, buf+max-p, "/%s@%x", devname, dev);
+ if (fn)
+ p += snprintf(p, buf+max-p, ",%x", fn);
+ return p;
}
-int bootprio_find_fdc_device(int bfd, int port, int fdid)
+int bootprio_find_pci_device(struct pci_device *pci)
{
- return -1;
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find pci device - for example: /pci@i0cf8/ethernet@5
+ char desc[256];
+ build_pci_path(desc, sizeof(desc), "*", pci);
+ return find_prio(desc);
}
-int bootprio_find_pci_rom(int bdf, int instance)
+int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
{
- return -1;
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", chanid, slave);
+ return find_prio(desc);
+}
+
+int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find floppy - for example: /pci@i0cf8/isa@1/fdc@03f1/floppy@0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "isa", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid);
+ return find_prio(desc);
+}
+
+int bootprio_find_pci_rom(struct pci_device *pci, int instance)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find pci rom - for example: /pci@i0cf8/scsi@3:rom2
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ if (instance)
+ snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
+ return find_prio(desc);
}
int bootprio_find_named_rom(const char *name, int instance)
{
- return -1;
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find named rom - for example: /rom@genroms/linuxboot.bin
+ char desc[256], *p;
+ p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name);
+ if (instance)
+ snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
+ return find_prio(desc);
+}
+
+int bootprio_find_usb(struct pci_device *pci, u64 path)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find usb - for example: /pci@i0cf8/usb@1,2/hub@1/network@0/ethernet@0
+ int i;
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "usb", pci);
+ for (i=56; i>0; i-=8) {
+ int port = (path >> i) & 0xff;
+ if (port != 0xff)
+ p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port);
+ }
+ snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff));
+ return find_prio(desc);
}
* Boot setup
****************************************************************/
+static int CheckFloppySig = 1;
+
#define DEFAULT_PRIO 9999
static int DefaultFloppyPrio = 101;
return;
SET_EBDA(boot_sequence, 0xffff);
- IPL.checkfloppysig = 1;
if (!CONFIG_COREBOOT) {
// On emulators, get boot order from nvram.
if (inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1)
- IPL.checkfloppysig = 0;
+ CheckFloppySig = 0;
u32 bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
| ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio
const char *description;
struct bootentry_s *next;
};
-
static struct bootentry_s *BootList;
+#define IPL_TYPE_FLOPPY 0x01
+#define IPL_TYPE_HARDDISK 0x02
+#define IPL_TYPE_CDROM 0x03
+#define IPL_TYPE_CBFS 0x20
+#define IPL_TYPE_BEV 0x80
+#define IPL_TYPE_BCV 0x81
+
static void
bootentry_add(int type, int prio, u32 data, const char *desc)
{
be->type = type;
be->priority = prio;
be->data = data;
- be->description = desc;
+ be->description = desc ?: "?";
+ dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n"
+ , be->description, type, prio, data);
// Add entry in sorted order.
struct bootentry_s **pprev;
}
void
-boot_add_floppy(struct drive_s *drive_g, int prio)
+boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio)
{
bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
- , (u32)drive_g, drive_g->desc);
+ , (u32)drive_g, desc);
}
void
-boot_add_hd(struct drive_s *drive_g, int prio)
+boot_add_hd(struct drive_s *drive_g, const char *desc, int prio)
{
bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
- , (u32)drive_g, drive_g->desc);
+ , (u32)drive_g, desc);
}
void
-boot_add_cd(struct drive_s *drive_g, int prio)
+boot_add_cd(struct drive_s *drive_g, const char *desc, int prio)
{
bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
- , (u32)drive_g, drive_g->desc);
+ , (u32)drive_g, desc);
}
// Add a CBFS payload entry
* Boot menu and BCV execution
****************************************************************/
+#define DEFAULT_BOOTMENU_WAIT 2500
+
// Show IPL option menu.
static void
interactive_bootmenu(void)
printf("Press F12 for boot menu.\n\n");
+ u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
enable_bootsplash();
- int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
+ int scan_code = get_keystroke(menutime);
disable_bootsplash();
if (scan_code != 0x86)
/* not F12 */
pos->priority = 0;
}
+// BEV (Boot Execution Vector) list
+struct bev_s {
+ int type;
+ u32 vector;
+};
+static struct bev_s BEV[20];
+static int BEVCount;
static int HaveHDBoot, HaveFDBoot;
static void
return;
if (type == IPL_TYPE_FLOPPY && HaveFDBoot++)
return;
- if (IPL.bevcount >= ARRAY_SIZE(IPL.bev))
+ if (BEVCount >= ARRAY_SIZE(BEV))
return;
- struct ipl_entry_s *bev = &IPL.bev[IPL.bevcount++];
+ struct bev_s *bev = &BEV[BEVCount++];
bev->type = type;
bev->vector = vector;
}
// Jump to a bootup entry point.
static void
-call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
+call_boot_entry(struct segoff_s bootsegip, u8 bootdrv)
{
- dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
+ dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset);
struct bregs br;
memset(&br, 0, sizeof(br));
br.flags = F_IF;
- br.code = SEGOFF(bootseg, bootip);
+ br.code = bootsegip;
// Set the magic number in ax and the boot drive in dl.
br.dl = bootdrv;
br.ax = 0xaa55;
u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
- call_boot_entry(bootseg, bootip, bootdrv);
+ call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
}
// Boot from a CD-ROM
static void
-boot_cdrom(struct ipl_entry_s *ie)
+boot_cdrom(struct drive_s *drive_g)
{
if (! CONFIG_CDROM_BOOT)
return;
-
- if (!ie->vector)
- return;
printf("Booting from DVD/CD...\n");
- struct drive_s *drive_g = (void*)ie->vector;
int status = cdrom_boot(drive_g);
if (status) {
printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
- call_boot_entry(bootseg, bootip, bootdrv);
+ call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
}
// Boot from a CBFS payload
static void
-boot_cbfs(struct ipl_entry_s *ie)
+boot_cbfs(struct cbfs_file *file)
{
if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
return;
printf("Booting from CBFS...\n");
- cbfs_run_payload((void*)ie->vector);
+ cbfs_run_payload(file);
+}
+
+// Boot from a BEV entry on an optionrom.
+static void
+boot_rom(u32 vector)
+{
+ printf("Booting from ROM...\n");
+ struct segoff_s so;
+ so.segoff = vector;
+ call_boot_entry(so, 0);
}
+// Determine next boot method and attempt a boot using it.
static void
do_boot(u16 seq_nr)
{
if (! CONFIG_BOOT)
panic("Boot support not compiled in.\n");
- if (seq_nr >= IPL.bevcount) {
+ if (seq_nr >= BEVCount) {
printf("No bootable device.\n");
// Loop with irqs enabled - this allows ctrl+alt+delete to work.
for (;;)
}
// Boot the given BEV type.
- struct ipl_entry_s *ie = &IPL.bev[seq_nr];
+ struct bev_s *ie = &BEV[seq_nr];
switch (ie->type) {
case IPL_TYPE_FLOPPY:
printf("Booting from Floppy...\n");
- boot_disk(0x00, IPL.checkfloppysig);
+ boot_disk(0x00, CheckFloppySig);
break;
case IPL_TYPE_HARDDISK:
printf("Booting from Hard Disk...\n");
boot_disk(0x80, 1);
break;
case IPL_TYPE_CDROM:
- boot_cdrom(ie);
+ boot_cdrom((void*)ie->vector);
break;
case IPL_TYPE_CBFS:
- boot_cbfs(ie);
+ boot_cbfs((void*)ie->vector);
break;
case IPL_TYPE_BEV:
- printf("Booting from ROM...\n");
- call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0);
+ boot_rom(ie->vector);
break;
}