Add support for up to 35 boot menu entries (2 pages if >18). To solve the
">10" problem currently experienced by SeaBIOS users (there are no 11, 12, etc.
keys on a keyboard - so impossible to choose the last menu entries if you got
>10 entries because of multiple hard drives / secondary payloads / floppies)
- the boot menu has been extended to the letter keys. NOTE: TPM menu has been
moved from T to M letter: it is at the end of keyboard's 3rd row of letters and
"Trusted" is adjective while "Module" is a noun; alternatively could press '-'.
Also, add support for a numpad. Small USB numpad could be really convenient for
choosing the boot entries at coreboot boards used as (maybe headless) servers.
'/' char on numpad could be used to open the boot menu or to exit it. If there
are >10 boot menu entries - the numpad console interface will be enabled: press
one or two digit keys and then ENTER to confirm your choice, or remove a digit
by pressing the '.Del' key. Also you could call TPM with '-' key at any moment,
or boot with a single key press of your fullsize keyboard.
Signed-off-by: Mike Banon <mikebdp2 at gmail.com>
(patch body is after the testing instructions below)
This "advanced_bootmenu" patch is much more useful when used together
with my "multiple_floppies" patch:
[SeaBIOS] [PATCH v2] ramdisk: search for all available floppy images
instead of one
https://mail.coreboot.org/pipermail/seabios/2018-December/012670.html
Sadly I haven't done the suggestions by Kevin (I have so many unfinished tasks)
so the "multiple_floppies" patch is also not merged yet. But you could install
both patches to your coreboot by executing this script while at ./coreboot dir:
https://pastebin.com/raw/hv9sSuMU
And here is a coreboot image for QEMU with these two patches applied and my
collection of wonderful and useful floppies added to popular the entries list:
https://github.com/mikebdp2/floparchive/blob/master/coreboot.rom?raw=true
Descriptions of the most prominent floppies could be found here:
http://dangerousprototypes.com/docs/Lenovo_G505S_hacking#Useful_floppies
Run this coreboot.rom by executing this QEMU command: (some floppies are 64-bit)
qemu-system-x86_64 -L . -m 768 -localtime -vga vmware -net nic,model=rtl8139 \
-net user -soundhw ac97 -bios ./coreboot.rom -boot menu=on -serial stdio
Best regards,
Mike Banon
diff --git a/src/boot.c b/src/boot.c
index 9f82f3c..f94dd27 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -463,6 +463,7 @@ get_keystroke(int msec)
* Boot menu and BCV execution
****************************************************************/
+#define BOOTMENU_PAGE_SIZE 18
#define DEFAULT_BOOTMENU_WAIT 2500
// Show IPL option menu.
@@ -478,59 +479,282 @@ interactive_bootmenu(void)
;
char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
- int menukey = romfile_loadint("etc/boot-menu-key", 1);
- printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n");
+ int menukey = romfile_loadint("etc/boot-menu-key", 1); // custom menukey
+ printf("%s", bootmsg ?: "\nPress ESC or \\ / slash for boot menu.\n\n");
free(bootmsg);
u32 menutime = romfile_loadint("etc/boot-menu-wait",
DEFAULT_BOOTMENU_WAIT);
enable_bootsplash();
int scan_code = get_keystroke(menutime);
disable_bootsplash();
- if (scan_code != menukey)
+ if (scan_code != menukey && // custom menukey
+ scan_code != 1 && // ESC
+ scan_code != 43 && // '\' char on keyboard
+ scan_code != 53 && // '/' char on keyboard
+ scan_code != 98) { // '/' char on numpad
+ if (scan_code == -1)
+ printf("No key pressed.\n");
+ else
+ printf("Not a menukey pressed.\n");
return;
+ }
while (get_keystroke(0) >= 0)
;
- printf("Select boot device:\n\n");
wait_threads();
- // Show menu items
+ char keyboard_keys[35] = {'1','2','3','4','5','6','7','8','9','0',
+ 'q','w','e','r','t','y','u','i','o','p',
+ 'a','s','d','f','g','h','j','k','l',
+ 'z','x','c','v','b','n'}; /* m = TPM */
+ int numpad_scancodes[10] = { 82, 79, 80, 81, 75, 76, 77, 71, 72, 73 };
+ int numpi = 0; // Key index: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
+ int digits = 0; // Numerical length of a current choice number.
+ int decode = 0; // Decode the current choice number into a letter?
+ int entry_id = 0;
+ char desc[77];
+
+ printf("Select boot device");
+
+ // Show menu items after counting them and determining a number of pages.
+ // Only 35 boot menu items (36 if to count a TPM) are supported currently.
+
int maxmenu = 0;
struct bootentry_s *pos;
- hlist_for_each_entry(pos, &BootList, node) {
- char desc[77];
+ hlist_for_each_entry(pos, &BootList, node)
maxmenu++;
- printf("%d. %s\n", maxmenu
+
+ if (maxmenu > 10) {
+ if (maxmenu > 35)
+ maxmenu = 35;
+ if (maxmenu > BOOTMENU_PAGE_SIZE)
+ printf(" - page 1 :");
+ else
+ printf(": ");
+ printf(" // press ENTER after your numpad input");
+ if (maxmenu > BOOTMENU_PAGE_SIZE)
+ printf(" - if any -\n "
+ " // - or to switch between the pages...\n");
+ else
+ printf(" (if any)\n\n");
+ } else {
+ printf(":\n\n");
+ }
+
+ hlist_for_each_entry(pos, &BootList, node) {
+ if (entry_id == BOOTMENU_PAGE_SIZE) // Show only the first page.
+ break;
+ printf("%c. %s\n", keyboard_keys[entry_id]
, strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+ entry_id++;
}
+ int tpm_cshm = 0;
if (tpm_can_show_menu()) {
- printf("\nt. TPM Configuration\n");
+ tpm_cshm = 1;
+ printf("\nm-. TPM Configuration");
}
-
- // Get key press. If the menu key is ESC, do not restart boot unless
- // 1.5 seconds have passed. Otherwise users (trained by years of
- // repeatedly hitting keys to enter the BIOS) will end up hitting ESC
- // multiple times and immediately booting the primary boot device.
- int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0);
+ printf("\n> ");
+
+ // Do not restart boot on menukey press, unless DEFAULT_BOOTMENU_WAIT msecs
+ // have passed. Otherwise users (trained by years of repeatedly
hitting keys
+ // to enter the BIOS) will end up hitting menukey multiple times and
+ // immediately booting the primary boot device.
+ int esc_accepted_time = irqtimer_calc(DEFAULT_BOOTMENU_WAIT);
+ int choice = 0, kb_choice = 0;
+ int page_num = 1;
+ int enter = 0;
+ int backspace = 0;
+ int tpm_show_menu = 0;
for (;;) {
scan_code = get_keystroke(1000);
- if (scan_code == 1 && !irqtimer_check(esc_accepted_time))
- continue;
- if (tpm_can_show_menu() && scan_code == 20 /* t */) {
+ if (scan_code == menukey || // custom menukey
+ scan_code == 1 || // ESC
+ scan_code == 43 || // '\' char on keyboard
+ scan_code == 53 || // '/' char on keyboard
+ scan_code == 98) { // '/' char on numpad
+ if (!irqtimer_check(esc_accepted_time))
+ continue;
+ if (digits == 2) // Remove the decoded "(*)"
+ printf(" \b\b\b");
+ /* Remove the existing input before printing a message. */
+ for (; digits > 0; digits--)
+ printf("\b \b");
+ printf("Menukey pressed.\n");
+ return;
+ }
+ kb_choice = 0;
+ /* 4 rows of keyboard_keys: 1 row with numbers, 3 rows with letters.
+ Use any of them to select a boot device (except the TPM
'm-' keys) */
+ // 1st range: 1-9 and 0 (10) keys <==> 2-11 scan codes <==>
1-10 choice
+ if (scan_code >= 2 && scan_code <= 11) kb_choice = scan_code - 1;
+ // 2nd range: Q-P row of letters <==> 16-25 scan codes <==>
11-20 choice
+ if (scan_code >= 16 && scan_code <= 25) kb_choice = scan_code - 5;
+ // 3rd range: A-L row of letters <==> 30-38 scan codes <==>
21-29 choice
+ if (scan_code >= 30 && scan_code <= 38) kb_choice = scan_code - 9;
+ // 4th range: Z-N row of letters <==> 44-49 scan codes <==>
30-35 choice
+ if (scan_code >= 44 && scan_code <= 49) kb_choice = scan_code - 14;
+ // ENTER: (28) on keyboard, (96) on numpad.
+ if (scan_code == 28 || scan_code == 96)
+ enter = 1;
+ // BCKSPC: '<-'(14) and 'Delete'(111) on keyboard, '.Del'(83)
on numpad.
+ if (scan_code == 14 || scan_code == 111 || scan_code == 83)
+ backspace = 1;
+ // TPM keys: 'm'(50) and '-'(12) chars on keyboard, '-'(74) on numpad.
+ if ((scan_code == 50 || scan_code == 12 || scan_code == 74)
&& tpm_cshm)
+ tpm_show_menu = 1;
+
+ if (kb_choice != 0 || tpm_show_menu) {
+ if (kb_choice > maxmenu) {
+ if (!tpm_show_menu)
+ continue;
+ } else {
+ choice = kb_choice;
+ }
+ if (digits == 2) // Remove the decoded "(*)"
+ printf(" \b\b\b");
+ /* Remove the existing input before printing a choice. */
+ for (; digits > 0; digits--)
+ printf("\b \b");
+ if (!tpm_show_menu) {
+ // Choice is any of the detected boot devices ==> lets boot!
+ break;
+ }
+ } else {
+ // Internal/USB Numpad console interface.
+ if (digits < 9) {
+ for (numpi = 0; numpi < 10; numpi++) {
+ if (scan_code == numpad_scancodes[numpi]) {
+ if (maxmenu <= 10) { // Console interface is
not needed.
+ if ((numpi != 0 && numpi <= maxmenu) ||
+ (numpi == 0 && 10 <= maxmenu)) { // 10(0)
+ choice = numpi;
+ enter = 1; // Fake ENTER to boot this
entry now.
+ } else { // If no such an entry, don't try to boot.
+ break;
+ }
+ } else {
+ if (digits == 2) {
+ printf(" \b\b\b"); // Remove the
decoded "(*)"
+ if (choice == 0) {
+ printf("\b\b \b\b"); // Remove "10".
+ digits = 0;
+ }
+ }
+ choice = 10 * choice + numpi;
+ }
+ if (choice > 0) {
+ printf("%d", numpi); // Print the entered digit.
+ digits++;
+ } else {
+ if (10 <= maxmenu)
+ printf("10(0)\b\b\b");
+ else
+ printf("10(?)\b\b\b");
+ digits = 2;
+ }
+ if (choice > 9 && digits == 2) // Decode into a letter.
+ decode = 1;
+ break;
+ }
+ }
+ }
+ if (backspace && digits > 0) {
+ backspace = 0;
+ choice = choice / 10;
+ if (digits == 2) {
+ printf(" \b\b\b"); // Remove the decoded "(*)"
+ // 0 turned into 10: one more Backspace is needed
to remove.
+ if (choice == 0) {
+ printf("\b \b");
+ digits--;
+ }
+ }
+ printf("\b \b"); // Remove the last entered digit.
+ digits--;
+ if (choice > 9 && digits == 2) // Decode into a letter.
+ decode = 1;
+ }
+ if (decode) { // Decode the current choice number into a letter.
+ decode = 0;
+ if (choice <= maxmenu) {
+ printf("(%c)", keyboard_keys[choice-1]);
+ } else {
+ if (tpm_cshm && choice == 36)
+ printf("(m)"); // For TPM.
+ else
+ printf("(?)"); // No matching letter found.
+ }
+ printf("\b\b\b"); // Move a cursor before the "(*)"
+ }
+ }
+
+ if (enter) {
+ enter = 0;
+ if (choice == 0) {
+ if (digits == 2) { // for 0 that turned into 10
+ if (10 <= maxmenu)
+ break;
+ else
+ continue;
+ }
+ // If there are two pages - switch between them.
+ if (maxmenu > BOOTMENU_PAGE_SIZE) {
+ entry_id = 0;
+ page_num = 3 - page_num; // 3 - 1 = 2; 3 - 2 = 1.
+ printf("\n\nSelect boot device - page %d :"
+ " // press ENTER after your numpad input"
+ " - if any -\n "
+ " // - or to switch between the pages...\n",
+ page_num);
+ hlist_for_each_entry(pos, &BootList, node) {
+ if ((page_num == 1 && entry_id ==
BOOTMENU_PAGE_SIZE) ||
+ (page_num == 2 && entry_id == 35))
+ break;
+ if (page_num == 1 || entry_id >= BOOTMENU_PAGE_SIZE)
+ printf("%c. %s\n", keyboard_keys[entry_id],
+ strtcpy(desc, pos->description,
ARRAY_SIZE(desc)));
+ entry_id++;
+ }
+ if (tpm_cshm)
+ printf("\nm-. TPM Configuration");
+ printf("\n> ");
+ }
+ } else {
+ if (choice > maxmenu) {
+ if (tpm_cshm && choice == 36)
+ tpm_show_menu = 1;
+ } else {
+ // Choice is any of the detected boot devices ==>
lets boot!
+ break;
+ }
+ }
+ }
+
+ if (tpm_show_menu) {
+ tpm_show_menu = 0;
+ choice = 0;
+ if (digits == 0)
+ printf("TPM key pressed.");
+ else
+ digits = 0;
printf("\n");
tpm_menu();
+ printf("> ");
}
- if (scan_code >= 1 && scan_code <= maxmenu+1)
- break;
+ }
+
+ if (choice == 0) // 10(0)
+ choice = 10;
+
+ if (digits == 0 && choice < 36) {
+ printf("%c", keyboard_keys[choice-1]);
+ if (choice > 9) // Decode into a number.
+ printf("(%d)", choice);
}
printf("\n");
- if (scan_code == 0x01)
- // ESC
- return;
// Find entry and make top priority.
- int choice = scan_code - 1;
hlist_for_each_entry(pos, &BootList, node) {
if (! --choice)
break;
diff --git a/src/config.h b/src/config.h
index 93c8dbc..f85cc14 100644
--- a/src/config.h
+++ b/src/config.h
@@ -19,7 +19,7 @@
// Space to reserve in high-memory for tables
#define BUILD_MAX_HIGHTABLE (256*1024)
// Largest supported externaly facing drive id
-#define BUILD_MAX_EXTDRIVE 16
+#define BUILD_MAX_EXTDRIVE 36
// Number of bytes the smbios may be and still live in the f-segment
#define BUILD_MAX_SMBIOS_FSEG 600
// Maximum number of bytes the mptable may be and still be copied to f-segment
Hi,
I'm working on stuffing a bootable Linux distro into coreboot. In QEMU I
already succeded by using coreboot's built-in kernel loading mechanism, but
that's without SeaBIOS.
I'd love to have it as a SeaBIOS payload so I can also boot other things,
but I guess I'd have to create a custom-sized floppy image for this or
figure out how to create an ELF payload out of a Linux kernel (I'm open to
either, but I wasn't able to find any documentation on the ELF method).
The guy who put Win 3.1 in coreboot attempted the floppy method, but
according to his article he did not find success with this method due to
unknown and complex issues in the floppy-side logic of SeaBIOS.
So, I'm making the question explicit: What would it take to support
custom-sized floppy images? In particular, I'm thinking of a 16MB device...
Alternatively, would it be possible to create an ELF file out of a Linux
kernel+initrd / bootable image?
Cheers,
Rafael
Some USB keyboards report 9 or 10-byte max packet sizes, instead
of the 8-byte max specified by the USB HID spec. Handle this by
increasing the size of the keyevent struct to 10 bytes, and using the key
array size of the usbkeyinfo struct as loop bounds rather than that of the
keyevent struct (since the former will always be smaller, and within spec).
Test: built/boot on Google Pixel Slate, observe keyboard functional
Signed-off-by: Matt DeVillier <matt.devillier(a)gmail.com>
---
src/hw/usb-hid.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c
index fa4d9a2..bce1b5f 100644
--- a/src/hw/usb-hid.c
+++ b/src/hw/usb-hid.c
@@ -8,6 +8,7 @@
#include "config.h" // CONFIG_*
#include "output.h" // dprintf
#include "ps2port.h" // ATKBD_CMD_GETID
+#include <string.h> //memset
#include "usb.h" // usb_ctrlrequest
#include "usb-hid.h" // usb_keyboard_setup
#include "util.h" // process_key
@@ -59,8 +60,10 @@ usb_kbd_setup(struct usbdevice_s *usbdev
// XXX - this enables the first found keyboard (could be random)
return -1;
- if (epdesc->wMaxPacketSize != 8)
+ if (epdesc->wMaxPacketSize > 10) {
+ dprintf(1, "USB keyboard endpoint wMaxPacketSize > 10; aborting\n");
return -1;
+ }
// Enable "boot" protocol.
int ret = set_protocol(usbdev->defpipe, 0);
@@ -163,11 +166,15 @@ static u16 ModifierToScanCode[] VAR16 = {
#define RELEASEBIT 0x80
-// Format of USB keyboard event data
+// Format of USB keyboard event data.
+// Some keyboards use a 9/10 byte packet size,
+// so account for that here to prevent buffer
+// overflow. We'll ignore the 9th/10th bytes
+// as it's out of spec.
struct keyevent {
u8 modifiers;
u8 reserved;
- u8 keys[6];
+ u8 keys[8];
};
// Translate data from KeyToScanCode[] to calls to process_key().
@@ -253,7 +260,7 @@ handle_key(struct keyevent *data)
break;
int j;
for (j=0;; j++) {
- if (j>=ARRAY_SIZE(data->keys)) {
+ if (j>=ARRAY_SIZE(old.keys)) {
// Key released.
procscankey(key, RELEASEBIT, data->modifiers);
if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
@@ -274,7 +281,7 @@ handle_key(struct keyevent *data)
// Process new keys
procmodkey(data->modifiers & ~old.modifiers, 0);
old.modifiers = data->modifiers;
- for (i=0; i<ARRAY_SIZE(data->keys); i++) {
+ for (i=0; i<ARRAY_SIZE(old.keys); i++) {
u8 key = data->keys[i];
if (!key)
continue;
--
2.20.1
This patch aimed to avoid problem with uninitialized virtio-blk and
virtio-scsi boot devices.
Currently, 12 KiB of memory is allocated for each virtio-blk/scsi, so
no more than about 10 devices can be initialized. If the device is not
initialized, we cannot boot from it. So, if we have more than 10 devices,
we can't boot from any of the following (11, 12, etc.).
We can initialize only bootable devices, i.e. listed in boot order list,
that this patch does.
Alexey Kirillov (2):
boot: Detect strict boot order (HALT record) in function
virtio: Do not init non-bootable devices
src/boot.c | 5 +++++
src/hw/virtio-blk.c | 11 ++++++++++-
src/hw/virtio-scsi.c | 11 ++++++++++-
src/util.h | 1 +
4 files changed, 26 insertions(+), 2 deletions(-)
--
2.17.1
Hi Michael & Lists,
I'd like to ask for ideas with the following problem we have.
(1) There is a functional iPXE + WDS setup, with iPXE built as a
traditional BIOS PCI option ROM, using CONFIG=qemu. Accordingly the
platform is qemu, with SeaBIOS, and the NIC is virtio-net-pci.
I don't know anything about the particulars of the WDS setup at this
point, only that the boot loader program it exposes is WDSNBP.COM.
(2) The setup works fine when iPXE is built at commit 4e85b2708fa0
("[virtio] Use host-specified MTU when available", 2017-01-23).
(3) When iPXE is built at commit 133f4c47baef ("[build] Handle
R_X86_64_PLT32 from binutils 2.31", 2018-09-17), the setup breaks.
The symptom is that iPXE fetches WDSNBP.COM just fine, but WDSNBP.COM,
rather than doing whatever it does otherwise, keeps PXE-booting itself
(3+ times), and finally aborts.
Consider the following log output (my undertanding is that all this is
logged by WDSNBP.COM):
> Downloaded WDSNBP...
>
> Press F12 for network service boot
> Architecture: x64
> WDSNBP started using DHCP Referral.
> Contacting Server: ... (Gateway: ...)
> Contacting Server: ...
> TFTP Download: boot\x86\wdsnbp.com
This block repeats approx. 3 times, after which the following is
displayed:
> Windows Deployment Services: PXE Boot Aborted.
> Could not boot image: Error 0x7f8d8101 (http://ipxe.org/7f8d8101)
> No more network devices
>
> No bootable device
My understanding is that the first line from this last block is printed
by WDSNBP.COM, the second line by iPXE (in pxe_start_nbp()), the third
line also by iPXE, and the last one by SeaBIOS.
This seems to indicate that WDSNBP.COM exits with an error code, and
pxe_start_nbp() logs it as "Error 0x7f8d8101".
(4) Now, after a bit of searching the web, I've found the following
articles, which indicate that the WDS (= server side) setup is
incorrect:
(4a) "disable NetBios over TCPIP, on the WDS server"
https://techthoughts.info/pxe-booting-wds-dhcp-scope-vs-ip-helpers/#comment…https://social.technet.microsoft.com/Forums/ie/en-US/f3883e8b-1039-477d-999…
(4b) "cover all combinations of forward and backwards slashes in
ReadFilter, on the WDS server"
http://ipxe.org/appnote/chainload_wds#tftp_loops
However: the regression appears to be a function of *only* the git
commit at which we build iPXE. It seems so deterministic that we
bisected commit range 4e85b2708fa0..133f4c47baef. (Hence we have not
captured the network traffic yet, nor have we investigated the WDS
server config.)
The "culprit" commit is ea29122a70c6 ("[http] Include error messages for
4xx and 5xx response codes", 2017-12-28).
(5) Which makes no sense to me, unfortunately. :(
Commit ea29122a70c6 adds the "http_errors" array to the code. According
to
src/include/ipxe/tables.h
and the build artifact
src/bin/1af41000.rom.tmp.map
this new array is placed in a new section called
.textdata.tbl.errortab.01
Trying to retro-fit those facts to the symptom encountered, I came up
with the idea that *maybe* the new array (or section) causes a memory
allocation failure in WDSNBP.COM -- due to increased memory footprint of
iPXE. Which then leads to the misbehavior of WDSNBP.COM.
After all, WDSNBP.COM is a 16-bit real-mode program:
https://support.microsoft.com/en-us/help/4468601/pxe-boot-in-configuration-…
so it could be susceptible to the size & fragmentation of the RAM that
is under 640KB.
(6) Unfortunately, this "low RAM exhaustion" idea doesn't seem to hold
water. There are at least two counter-arguments:
(6a) if I revert commit ea29122a70c6 on top of commit 133f4c47baef, then
the issue does *not* go away.
(The issue also does not go away if I remove the "netdev_errors" array,
also on top of commit 133f4c47baef -- that's a larger array.)
(... In theory anyway, this might not necessarily disprove the memory
exhaustion idea. What if the iPXE footprint grows, over the
ea29122a70c6..133f4c47baef so much, for independent reasons, that
reverting ea29122a70c6 at the end cannot compensate for that increase?)
(6b) I added "DEBUG=pxe_call:1" to the "make" command, and compared the
debug messages printed by pxe_start_nbp(), between 4e85b2708fa0 and
133f4c47baef. Alas, the debug messages are identical:
> PXE NBP starting with netdev net0, code 9c6c:0802, data 9cf0:2ce0
which to me suggests that there is no change in the amount of memory
that is made available to WDSNBP.COM -- its code and data continue to
start at 0x9_CEC2 and 0x9_FBE0, respectively.
Any hints as to what could be going wrong?
Thanks!
Laszlo
This patch aimed to avoid problem with uninitialized virtio-blk and
virtio-scsi boot devices.
Currently, 12 KiB of memory is allocated for each virtio-blk/scsi, so
no more than about 10 devices can be initialized. If the device is not
initialized, we cannot boot from it. So, if we have more than 10 devices,
we can't boot from any of the following (11, 12, etc.).
We can initialize only bootable devices, i.e. listed in boot order list,
that this patch does.
Alexey Kirillov (1):
virtio: do not init non-bootable devices
docs/Runtime_config.md | 1 +
src/hw/virtio-blk.c | 10 ++++++++++
src/hw/virtio-scsi.c | 10 ++++++++++
3 files changed, 21 insertions(+)
--
2.17.1
On physical hardware, some PCI devices are not detectable when UEFI
BIOS invokes our InitializeYourself() function. But they are
guaranteed to be available before UEFI invokes our PreparToBoot()
function. So in the case of running CSM on physical hardware, we execute
pci_probe_devices() at PrepareToBoot() stage.
Signed-off-by: Bin Gao <gaobin(a)amazon.com>
---
src/fw/csm.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/fw/csm.c b/src/fw/csm.c
index 8359bcb..82d375c 100644
--- a/src/fw/csm.c
+++ b/src/fw/csm.c
@@ -63,7 +63,9 @@ static void
csm_maininit(struct bregs *regs)
{
interface_init();
- pci_probe_devices();
+
+ if (CONFIG_CSM && CONFIG_QEMU_HARDWARE)
+ pci_probe_devices();
csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
@@ -143,6 +145,13 @@ handle_csm_0002(struct bregs *regs)
return;
}
+ // On physical hardware, some PCI devices are not detectable when
+ // UEFI invokes our InitializeYourself() function. But they
+ // are guaranteed to be available before UEFI invokes our
+ // PreparToBoot() function.
+ if (CONFIG_CSM && !CONFIG_QEMU_HARDWARE)
+ pci_probe_devices();
+
dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
struct e820entry *p = (void *)csm_compat_table.E820Pointer;
--
2.17.1
Some USB keyboards report 9 or 10-byte max packet sizes, instead
of the 8-byte max specified by the USB HID spec. Handle this by
increasing the size of the keyevent struct to 10 bytes, zeroizing
it before use, and using the key array size of the usbkeyinfo
struct as loop bounds rather than that of the keyevent struct
(since the former will always be smaller, and within spec) to
prevent buffer overflow.
Test: built/boot on Google Pixel Slate, observe keyboard functional
Signed-off-by: Matt DeVillier <matt.devillier(a)gmail.com>
---
src/hw/usb-hid.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c
index fa4d9a2..bce1b5f 100644
--- a/src/hw/usb-hid.c
+++ b/src/hw/usb-hid.c
@@ -8,6 +8,7 @@
#include "config.h" // CONFIG_*
#include "output.h" // dprintf
#include "ps2port.h" // ATKBD_CMD_GETID
+#include <string.h> //memset
#include "usb.h" // usb_ctrlrequest
#include "usb-hid.h" // usb_keyboard_setup
#include "util.h" // process_key
@@ -59,8 +60,10 @@ usb_kbd_setup(struct usbdevice_s *usbdev
// XXX - this enables the first found keyboard (could be random)
return -1;
- if (epdesc->wMaxPacketSize != 8)
+ if (epdesc->wMaxPacketSize > 10) {
+ dprintf(1, "USB keyboard endpoint wMaxPacketSize > 10; aborting\n");
return -1;
+ }
// Enable "boot" protocol.
int ret = set_protocol(usbdev->defpipe, 0);
@@ -163,11 +166,15 @@ static u16 ModifierToScanCode[] VAR16 = {
#define RELEASEBIT 0x80
-// Format of USB keyboard event data
+// Format of USB keyboard event data.
+// Some keyboards use a 9/10 byte packet size,
+// so account for that here to prevent buffer
+// overflow. We'll ignore the 9th/10th bytes
+// as it's out of spec.
struct keyevent {
u8 modifiers;
u8 reserved;
- u8 keys[6];
+ u8 keys[8];
};
// Translate data from KeyToScanCode[] to calls to process_key().
@@ -253,7 +260,7 @@ handle_key(struct keyevent *data)
break;
int j;
for (j=0;; j++) {
- if (j>=ARRAY_SIZE(data->keys)) {
+ if (j>=ARRAY_SIZE(old.keys)) {
// Key released.
procscankey(key, RELEASEBIT, data->modifiers);
if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
@@ -274,7 +281,7 @@ handle_key(struct keyevent *data)
// Process new keys
procmodkey(data->modifiers & ~old.modifiers, 0);
old.modifiers = data->modifiers;
- for (i=0; i<ARRAY_SIZE(data->keys); i++) {
+ for (i=0; i<ARRAY_SIZE(old.keys); i++) {
u8 key = data->keys[i];
if (!key)
continue;
@@ -310,6 +317,8 @@ usb_check_key(void)
for (;;) {
struct keyevent data;
+ // zeroize struct as most keyboards won't fill it
+ memset(&data, 0, sizeof(data));
int ret = usb_poll_intr(pipe, &data);
if (ret)
break;
--
2.20.1
Some USB keyboards report 9 or 10-byte max packet sizes, instead
of the 8-byte max specified by the USB HID spec. Handle this by
increasing the size of the keyevent struct to 10 bytes, zeroizing
it before use, and using the key array size of the usbkeyinfo
struct as loop bounds rather than that of the keyevent struct
(since the former will always be smaller, and within spec).
Test: built/boot on Google Pixel Slate, observe keyboard functional
Signed-off-by: Matt DeVillier <matt.devillier(a)gmail.com>
---
src/hw/usb-hid.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c
index fa4d9a2..cedec0b 100644
--- a/src/hw/usb-hid.c
+++ b/src/hw/usb-hid.c
@@ -8,6 +8,7 @@
#include "config.h" // CONFIG_*
#include "output.h" // dprintf
#include "ps2port.h" // ATKBD_CMD_GETID
+#include <string.h> //memset
#include "usb.h" // usb_ctrlrequest
#include "usb-hid.h" // usb_keyboard_setup
#include "util.h" // process_key
@@ -59,7 +60,7 @@ usb_kbd_setup(struct usbdevice_s *usbdev
// XXX - this enables the first found keyboard (could be random)
return -1;
- if (epdesc->wMaxPacketSize != 8)
+ if (epdesc->wMaxPacketSize > 10)
return -1;
// Enable "boot" protocol.
@@ -163,11 +164,15 @@ static u16 ModifierToScanCode[] VAR16 = {
#define RELEASEBIT 0x80
-// Format of USB keyboard event data
+// Format of USB keyboard event data.
+// Some keyboards use a 9/10 byte packet size,
+// so account for that here to prevent buffer
+// overflow. We'll ignore the 9th/10th bytes
+// as it's out of spec.
struct keyevent {
u8 modifiers;
u8 reserved;
- u8 keys[6];
+ u8 keys[8];
};
// Translate data from KeyToScanCode[] to calls to process_key().
@@ -253,7 +258,7 @@ handle_key(struct keyevent *data)
break;
int j;
for (j=0;; j++) {
- if (j>=ARRAY_SIZE(data->keys)) {
+ if (j>=ARRAY_SIZE(old.keys)) {
// Key released.
procscankey(key, RELEASEBIT, data->modifiers);
if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
@@ -274,7 +279,7 @@ handle_key(struct keyevent *data)
// Process new keys
procmodkey(data->modifiers & ~old.modifiers, 0);
old.modifiers = data->modifiers;
- for (i=0; i<ARRAY_SIZE(data->keys); i++) {
+ for (i=0; i<ARRAY_SIZE(old.keys); i++) {
u8 key = data->keys[i];
if (!key)
continue;
@@ -310,6 +315,8 @@ usb_check_key(void)
for (;;) {
struct keyevent data;
+ //zeroize struct as most keyboards won't fill it
+ memset(&data, 0, sizeof(data));
int ret = usb_poll_intr(pipe, &data);
if (ret)
break;
--
2.20.1