Support boot menu during last stage of post.
Improve description of option roms.
Support printf of "%.s" to force printing strings on stack.
Enhance memcpy so that it also works in real-mode.
# Source files
SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c mouse.c output.c \
boot.c ata.c cdrom.c apm.c util.c pcibios.c pci.c
-SRC32=post.c output.c rombios32.c util.c ata.c kbd.c pci.c
+SRC32=post.c output.c rombios32.c util.c ata.c kbd.c pci.c boot.c post_menu.c
TABLESRC=font.c cbt.c floppy_dbt.c
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
struct ipl_entry_s table[8];
u16 count;
u16 sequence;
+ u16 bootfirst;
};
#define IPL_TYPE_FLOPPY 0x01
"", "Floppy","Hard Disk","CD-Rom", "Network"
};
-static void
-print_boot_device(u16 type)
+void
+printf_bootdev(u16 bootdev)
{
+ u16 type = GET_EBDA(ipl.table[bootdev].type);
+
/* NIC appears as type 0x80 */
if (type == IPL_TYPE_BEV)
type = 0x4;
if (type == 0 || type > 0x4)
BX_PANIC("Bad drive type\n");
- printf("Booting from %s...\n", drivetypes[type]);
+ printf("%s", drivetypes[type]);
+
+ /* print product string if BEV */
+ void *far_description = (void*)GET_EBDA(ipl.table[bootdev].description);
+ if (type == 4 && far_description != 0) {
+ char description[33];
+ /* first 32 bytes are significant */
+ memcpy(MAKE_FARPTR(GET_SEG(SS), &description), far_description, 32);
+ /* terminate string */
+ description[32] = 0;
+ printf(" [%.s]", description);
+ }
+}
- // XXX - latest cvs has BEV description
+static void
+print_boot_device(u16 bootdev)
+{
+ printf("Booting from ");
+ printf_bootdev(bootdev);
+ printf("...\n");
}
//--------------------------------------------------------------------------
SET_EBDA(ipl.sequence, seq_nr);
- u16 bootseg;
- u8 bootdrv = 0;
- u16 bootdev, bootip;
-
- bootdev = inb_cmos(CMOS_BIOS_BOOTFLAG2);
+ u16 bootdev = inb_cmos(CMOS_BIOS_BOOTFLAG2);
bootdev |= ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4);
bootdev >>= 4 * seq_nr;
bootdev &= 0xf;
+
+ /* Read user selected device */
+ u16 bootfirst = GET_EBDA(ipl.bootfirst);
+ if (bootfirst != 0xFFFF) {
+ bootdev = bootfirst;
+ /* Reset boot sequence */
+ SET_EBDA(ipl.bootfirst, 0xFFFF);
+ SET_EBDA(ipl.sequence, 0xFFFF);
+ }
+
if (bootdev == 0)
BX_PANIC("No bootable device.\n");
BX_INFO("Invalid boot device (0x%x)\n", bootdev);
return;
}
- u16 type = GET_EBDA(ipl.table[bootdev].type);
/* Do the loading, and set up vector as a far pointer to the boot
* address, and bootdrv as the boot drive */
- print_boot_device(type);
+ print_boot_device(bootdev);
+
+ u16 type = GET_EBDA(ipl.table[bootdev].type);
+ u16 bootseg, bootip;
+ u8 bootdrv = 0;
struct bregs cr;
switch(type) {
case IPL_TYPE_FLOPPY: /* FDD */
val = va_arg(args, int);
putc(action, val);
break;
+ case '.':
+ // Hack to support "%.s" - meaning string on stack.
+ if (GET_VAR(CS, *(u8*)(n+1)) != 's')
+ break;
+ n++;
+ sarg = va_arg(args, const char *);
+ puts(action, sarg);
+ break;
case 's':
sarg = va_arg(args, const char *);
puts_cs(action, sarg);
ebda->ipl.count = ip - ebda->ipl.table;
ebda->ipl.sequence = 0xffff;
+ ebda->ipl.bootfirst = 0xffff;
}
static void
u16 desc = *(u16*)&rom[0x1a+0x10];
if (desc)
- ip->description = (FARPTR_TO_SEG(rom) << 16) | desc;
+ ip->description = (u32)MAKE_FARPTR(FARPTR_TO_SEG(rom), desc);
ebda->ipl.count++;
}
rom_scan(0xc8000, 0xe0000);
+ interactive_bootmenu();
+
// reset the memory (some boot loaders such as syslinux suppose
// that the memory is set to zero)
memset((void*)0x40000, 0, 0x40000); // XXX - shouldn't use globals
--- /dev/null
+// Menu presented during final phase of "post".
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "biosvar.h" // GET_EBDA
+#include "util.h" // usleep
+
+static u8
+check_for_keystroke()
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ah = 1;
+ call16_int(0x16, &br);
+ return !(br.flags & F_ZF);
+}
+
+static u8
+get_keystroke()
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ call16_int(0x16, &br);
+ return br.ah;
+}
+
+static void
+udelay_and_check_for_keystroke(u32 usec, int count)
+{
+ int i;
+ for (i = 1; i <= count; i++) {
+ usleep(usec);
+ if (check_for_keystroke())
+ break;
+ }
+}
+
+void
+interactive_bootmenu()
+{
+ while (check_for_keystroke())
+ get_keystroke();
+
+ printf("Press F12 for boot menu.\n\n");
+
+ udelay_and_check_for_keystroke(500000, 5);
+ if (! check_for_keystroke())
+ return;
+ u8 scan_code = get_keystroke();
+ if (scan_code != 0x58)
+ /* not F12 */
+ return;
+
+ while (check_for_keystroke())
+ get_keystroke();
+
+ printf("Select boot device:\n\n");
+
+ int count = GET_EBDA(ipl.count);
+ int i;
+ for (i = 0; i < count; i++) {
+ printf("%d. ", i+1);
+ printf_bootdev(i);
+ printf("\n");
+ }
+
+ for (;;) {
+ scan_code = get_keystroke();
+ if (scan_code == 0x01 || scan_code == 0x58)
+ /* ESC or F12 */
+ break;
+ if (scan_code <= count + 1) {
+ SET_EBDA(ipl.bootfirst, scan_code - 1);
+ break;
+ }
+ }
+ printf("\n");
+}
IRQ_TRAMPOLINE 10
IRQ_TRAMPOLINE 13
IRQ_TRAMPOLINE 15
+ IRQ_TRAMPOLINE 16
IRQ_TRAMPOLINE 18
IRQ_TRAMPOLINE 19
IRQ_TRAMPOLINE 1c
}
void *
-memcpy(void *d1, const void *s1, size_t len)
+memcpy(void *far_d1, const void *far_s1, size_t len)
{
- u8 *d = d1;
- const u8 *s = s1;
+ u8 *d = far_d1;
+ u8 *s = (u8*)far_s1;
- while (len--)
- *d++ = *s++;
+ while (len--) {
+ SET_FARPTR(*d, GET_FARPTR(*s));
+ d++;
+ s++;
+ }
- return d1;
+ return far_d1;
}
void
// rombios32.c
void rombios32_init(void);
+// boot.c
+void printf_bootdev(u16 bootdev);
+
+// post_menu.c
+void interactive_bootmenu();
+
#endif // util.h