summaryrefslogtreecommitdiffstats
path: root/sys/boot/efi
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2016-02-08 19:34:17 +0000
committerimp <imp@FreeBSD.org>2016-02-08 19:34:17 +0000
commitcee34e38648fd1e400693c209cf61fa32a9974e4 (patch)
treec986f92c40c8f1159c088f580c0cb7d82174c25a /sys/boot/efi
parent42e09be9c23e730d42b331384d128dbba8719c04 (diff)
downloadFreeBSD-src-cee34e38648fd1e400693c209cf61fa32a9974e4.zip
FreeBSD-src-cee34e38648fd1e400693c209cf61fa32a9974e4.tar.gz
Implement -P for boot loader. It's a bit easier to implement here than
in boot1, like is normally done. When a keyboard appears in the UEFI device tree, assume -D -h, just like on a BIOS boot. # It is unclear if an ACPI keyboard appearing in the tree means there's # a real keyboard or not. A USB keyboard doesn't seem to appear unless # it is really there. Differential Revision: https://reviews.freebsd.org/D5223
Diffstat (limited to 'sys/boot/efi')
-rw-r--r--sys/boot/efi/loader/main.c96
1 files changed, 93 insertions, 3 deletions
diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c
index 4c3bc7a..361d3bb 100644
--- a/sys/boot/efi/loader/main.c
+++ b/sys/boot/efi/loader/main.c
@@ -66,6 +66,7 @@ EFI_GUID hoblist = HOB_LIST_TABLE_GUID;
EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
EFI_GUID fdtdtb = FDT_TABLE_GUID;
+EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
#ifdef EFI_ZFS_BOOT
static void efi_zfs_probe(void);
@@ -94,6 +95,88 @@ cp16to8(const CHAR16 *src, char *dst, size_t len)
dst[i] = (char)src[i];
}
+static int
+has_keyboard(void)
+{
+ EFI_STATUS status;
+ EFI_DEVICE_PATH *path;
+ EFI_HANDLE *hin, *hin_end, *walker;
+ UINTN sz;
+ int retval = 0;
+
+ /*
+ * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
+ * do the typical dance to get the right sized buffer.
+ */
+ sz = 0;
+ hin = NULL;
+ status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ hin = (EFI_HANDLE *)malloc(sz);
+ status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
+ hin);
+ if (EFI_ERROR(status))
+ free(hin);
+ }
+ if (EFI_ERROR(status))
+ return retval;
+
+ /*
+ * Look at each of the handles. If it supports the device path protocol,
+ * use it to get the device path for this handle. Then see if that
+ * device path matches either the USB device path for keyboards or the
+ * legacy device path for keyboards.
+ */
+ hin_end = &hin[sz / sizeof(*hin)];
+ for (walker = hin; walker < hin_end; walker++) {
+ status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
+ if (EFI_ERROR(status))
+ continue;
+
+ while (!IsDevicePathEnd(path)) {
+ /*
+ * Check for the ACPI keyboard node. All PNP3xx nodes
+ * are keyboards of different flavors. Note: It is
+ * unclear of there's always a keyboard node when
+ * there's a keyboard controller, or if there's only one
+ * when a keyboard is detected at boot.
+ */
+ if (DevicePathType(path) == ACPI_DEVICE_PATH &&
+ (DevicePathSubType(path) == ACPI_DP ||
+ DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
+ ACPI_HID_DEVICE_PATH *acpi;
+
+ acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
+ if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
+ (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
+ retval = 1;
+ goto out;
+ }
+ /*
+ * Check for USB keyboard node, if present. Unlike a
+ * PS/2 keyboard, these definitely only appear when
+ * connected to the system.
+ */
+ } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
+ DevicePathSubType(path) == MSG_USB_CLASS_DP) {
+ USB_CLASS_DEVICE_PATH *usb;
+
+ usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
+ if (usb->DeviceClass == 3 && /* HID */
+ usb->DeviceSubClass == 1 && /* Boot devices */
+ usb->DeviceProtocol == 1) { /* Boot keyboards */
+ retval = 1;
+ goto out;
+ }
+ }
+ path = NextDevicePathNode(path);
+ }
+ }
+out:
+ free(hin);
+ return retval;
+}
+
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
@@ -104,6 +187,7 @@ main(int argc, CHAR16 *argv[])
struct devsw *dev;
uint64_t pool_guid;
UINTN k;
+ int has_kbd;
archsw.arch_autoload = efi_autoload;
archsw.arch_getdev = efi_getdev;
@@ -115,6 +199,8 @@ main(int argc, CHAR16 *argv[])
archsw.arch_zfs_probe = efi_zfs_probe;
#endif
+ has_kbd = has_keyboard();
+
/*
* XXX Chicken-and-egg problem; we want to have console output
* early, but some console attributes may depend on reading from
@@ -150,15 +236,19 @@ main(int argc, CHAR16 *argv[])
case 'D':
howto |= RB_MULTIPLE;
break;
- case 'm':
- howto |= RB_MUTE;
- break;
case 'h':
howto |= RB_SERIAL;
break;
+ case 'm':
+ howto |= RB_MUTE;
+ break;
case 'p':
howto |= RB_PAUSE;
break;
+ case 'P':
+ if (!has_kbd)
+ howto |= RB_SERIAL | RB_MULTIPLE;
+ break;
case 'r':
howto |= RB_DFLTROOT;
break;
OpenPOWER on IntegriCloud