FreeBSD Bugzilla – Attachment 201259 Details for
Bug 207940
stand/efi/boot1: Add boot partition selection
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
boot1.c patch rev4 for stable/12 and head after r332751
boot1.c.NNonaka-rev4_after-head-r332751.diff (text/plain), 15.44 KB, created by
Tomoaki AOKI
on 2019-01-19 01:07:01 UTC
(
hide
)
Description:
boot1.c patch rev4 for stable/12 and head after r332751
Filename:
MIME Type:
Creator:
Tomoaki AOKI
Created:
2019-01-19 01:07:01 UTC
Size:
15.44 KB
patch
obsolete
>--- stand/efi/boot1/boot1.c.orig 2018-02-11 19:57:57.048971000 +0900 >+++ stand/efi/boot1/boot1.c 2018-02-12 09:59:58.282714000 +0900 >@@ -29,6 +29,7 @@ > > #include <efi.h> > #include <eficonsctl.h> >+#include <efilib.h> > #include <efichar.h> > > #include "boot_module.h" >@@ -50,11 +51,52 @@ static const boot_module_t *boot_modules > /* The initial number of handles used to query EFI for partitions. */ > #define NUM_HANDLES_INIT 24 > >+/* For boot partition menu */ >+static int devpath_node_str(char *, size_t, EFI_DEVICE_PATH *); >+int devpath_strlcat(char *, size_t, EFI_DEVICE_PATH *); >+char *devpath_str(EFI_DEVICE_PATH *); >+void efi_cons_putchar(int); >+int efi_cons_getchar(void); >+int efi_cons_poll(void); >+int getchar(void); >+char *humanize_number_kmgt(UINT64); >+static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; >+static SIMPLE_INPUT_INTERFACE *conin; >+ > static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; > static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; > static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; > static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; > >+#define DEFAULT_FGCOLOR EFI_LIGHTGRAY >+#define DEFAULT_BGCOLOR EFI_BLACK >+ >+/* For boot partition menu */ >+char *humanize_number_kmgt(UINT64 size) { >+ static char buf2[6]; >+ UINT64 size0; >+ >+ if (size < 1024) >+ sprintf(buf2, "%luB", size); >+ else if (size0 = (size*10+512)/1024, size0 < 100) >+ sprintf(buf2, "%lu.%luK", size0 / 10, size0 % 10); >+ else if (size0 = (size+512)/1024, size0 < 1024) >+ sprintf(buf2, "%luK", size0); >+ else if (size0 = (size*10/1024+512)/1024, size0 < 100) >+ sprintf(buf2, "%lu.%luM", size0 / 10, size0 % 10); >+ else if (size0 = (size/1024+512)/1024, size0 < 1024) >+ sprintf(buf2, "%luM", size0); >+ else if (size0 = (size*10/1024/1024+512)/1024, size0 < 100) >+ sprintf(buf2, "%lu.%luG", size0 / 10, size0 % 10); >+ else if (size0 = (size/1024/1024+512)/1024, size0 < 1024) >+ sprintf(buf2, "%luG", size0); >+ else if (size0 = (size*10/1024/1024/1024+512)/1024, size0 < 100) >+ sprintf(buf2, "%lu.%luT", size0 / 10, size0 % 10); >+ else >+ sprintf(buf2, "%luT", (size/1024/1024/1024+512)/1024); >+ return(buf2); >+} >+ > /* > * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures > * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from >@@ -177,6 +219,181 @@ devpath_last(EFI_DEVICE_PATH *devpath) > } > > /* >+ * Put back for boot partition menu support. >+ * devpath_node_str is a basic output method for a devpath node which >+ * only understands a subset of the available sub types. >+ * >+ * If we switch to UEFI 2.x then we should update it to use: >+ * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. >+ */ >+static int >+devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) >+{ >+ switch (devpath->Type) { >+ case MESSAGING_DEVICE_PATH: >+ switch (devpath->SubType) { >+ case MSG_ATAPI_DP: { >+ ATAPI_DEVICE_PATH *atapi; >+ >+ atapi = (ATAPI_DEVICE_PATH *)(void *)devpath; >+ return snprintf(buf, size, "ata(%s,%s,0x%x)", >+ (atapi->PrimarySecondary == 1) ? "Sec" : "Pri", >+ (atapi->SlaveMaster == 1) ? "Slave" : "Master", >+ atapi->Lun); >+ } >+ case MSG_USB_DP: { >+ USB_DEVICE_PATH *usb; >+ >+ usb = (USB_DEVICE_PATH *)devpath; >+ return snprintf(buf, size, "usb(0x%02x,0x%02x)", >+ usb->ParentPortNumber, usb->InterfaceNumber); >+ } >+ case MSG_SCSI_DP: { >+ SCSI_DEVICE_PATH *scsi; >+ >+ scsi = (SCSI_DEVICE_PATH *)(void *)devpath; >+ return snprintf(buf, size, "scsi(0x%02x,0x%02x)", >+ scsi->Pun, scsi->Lun); >+ } >+ case MSG_SATA_DP: { >+ SATA_DEVICE_PATH *sata; >+ >+ sata = (SATA_DEVICE_PATH *)(void *)devpath; >+ return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)", >+ sata->HBAPortNumber, sata->PortMultiplierPortNumber, >+ sata->Lun); >+ } >+ default: >+ return snprintf(buf, size, "msg(0x%02x)", >+ devpath->SubType); >+ } >+ break; >+ case HARDWARE_DEVICE_PATH: >+ switch (devpath->SubType) { >+ case HW_PCI_DP: { >+ PCI_DEVICE_PATH *pci; >+ >+ pci = (PCI_DEVICE_PATH *)devpath; >+ return snprintf(buf, size, "pci(0x%02x,0x%02x)", >+ pci->Device, pci->Function); >+ } >+ default: >+ return snprintf(buf, size, "hw(0x%02x)", >+ devpath->SubType); >+ } >+ break; >+ case ACPI_DEVICE_PATH: { >+ ACPI_HID_DEVICE_PATH *acpi; >+ >+ acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath; >+ if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { >+ switch (EISA_ID_TO_NUM(acpi->HID)) { >+ case 0x0a03: >+ return snprintf(buf, size, "pciroot(0x%x)", >+ acpi->UID); >+ case 0x0a08: >+ return snprintf(buf, size, "pcieroot(0x%x)", >+ acpi->UID); >+ case 0x0604: >+ return snprintf(buf, size, "floppy(0x%x)", >+ acpi->UID); >+ case 0x0301: >+ return snprintf(buf, size, "keyboard(0x%x)", >+ acpi->UID); >+ case 0x0501: >+ return snprintf(buf, size, "serial(0x%x)", >+ acpi->UID); >+ case 0x0401: >+ return snprintf(buf, size, "parallelport(0x%x)", >+ acpi->UID); >+ default: >+ return snprintf(buf, size, "acpi(pnp%04x,0x%x)", >+ EISA_ID_TO_NUM(acpi->HID), acpi->UID); >+ } >+ } >+ >+ return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID, >+ acpi->UID); >+ } >+ case MEDIA_DEVICE_PATH: >+ switch (devpath->SubType) { >+ case MEDIA_CDROM_DP: { >+ CDROM_DEVICE_PATH *cdrom; >+ >+ cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; >+ return snprintf(buf, size, "cdrom(%x)", >+ cdrom->BootEntry); >+ } >+ case MEDIA_HARDDRIVE_DP: { >+ HARDDRIVE_DEVICE_PATH *hd; >+ >+ hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; >+ return snprintf(buf, size, "hd(p%d) (%s)", >+ hd->PartitionNumber, >+ humanize_number_kmgt(hd->PartitionSize * 512)); >+ } >+ default: >+ return snprintf(buf, size, "media(0x%02x)", >+ devpath->SubType); >+ } >+ case BBS_DEVICE_PATH: >+ return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType); >+ case END_DEVICE_PATH_TYPE: >+ return (0); >+ } >+ >+ return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, >+ devpath->SubType); >+} >+ >+/* >+ * devpath_strlcat appends a text description of devpath to buf but not more >+ * than size - 1 characters followed by NUL-terminator. >+ */ >+int >+devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) >+{ >+ size_t len, used; >+ const char *sep; >+ >+ sep = ""; >+ used = 0; >+ while (!IsDevicePathEnd(devpath)) { >+ len = snprintf(buf, size - used, "%s", sep); >+ used += len; >+ if (used > size) >+ return (used); >+ buf += len; >+ >+ len = devpath_node_str(buf, size - used, devpath); >+ used += len; >+ if (used > size) >+ return (used); >+ buf += len; >+ devpath = NextDevicePathNode(devpath); >+ sep = ":"; >+ } >+ >+ return (used); >+} >+ >+/* >+ * devpath_str is convenience method which returns the text description of >+ * devpath using a static buffer, so it isn't thread safe! >+ */ >+char * >+devpath_str(EFI_DEVICE_PATH *devpath) >+{ >+ static char buf[256]; >+ >+ devpath_strlcat(buf, sizeof(buf), devpath); >+ >+ return buf; >+} >+ >+ >+ >+/* > * load_loader attempts to load the loader image data. > * > * It tries each module and its respective devices, identified by mod->probe, >@@ -211,6 +428,187 @@ load_loader(const boot_module_t **modp, > return (EFI_NOT_FOUND); > } > >+/* For boot partition menu */ >+/* quick dirty work. */ >+#define NUM_DEV_LIST 35 >+ >+typedef struct { >+ const boot_module_t *modp; >+ dev_info_t *devinfop; >+} moddev_t; >+ >+static moddev_t dev_list[NUM_DEV_LIST]; >+ >+static int >+list_devices(void) >+{ >+ UINTN i, j; >+ dev_info_t *dev; >+ const boot_module_t *mod; >+ >+ j = 0; >+ for (i = 0; i < NUM_BOOT_MODULES; i++) { >+ if (boot_modules[i] == NULL) >+ continue; >+ mod = boot_modules[i]; >+ for (dev = mod->devices(); dev != NULL; dev = dev->next) { >+ dev_list[j].devinfop = dev; >+ dev_list[j].modp = mod; >+ j++; >+ if (j >= NUM_DEV_LIST) >+ break; >+ } >+ } >+ >+ return (j); >+} >+ >+#define SELECT_TIMEOUT 10 >+ >+static char >+idx2char(int i) >+{ >+ return (i<10 ? '0'+i : 'a'+i-10); >+} >+ >+static int >+char2idx(char c) >+{ >+ return ((c >= '0' && c <= '9') ? c - '0' : >+ (c >= 'A' && c <= 'Z') ? c - 'A' + 10 : >+ (c >= 'a' && c <= 'z') ? c - 'a' + 10 : >+ -1 ); >+} >+ >+static void >+move_to_tol() >+{ >+ int x,y; >+ >+ x = conout->Mode->CursorColumn; >+ y = conout->Mode->CursorRow; >+ conout->SetCursorPosition(conout, 0, y); >+} >+ >+static EFI_STATUS >+select_bootdev(int ndevs, const boot_module_t **modp, dev_info_t **devinfop, >+ void **bufp, size_t *bufsize) >+{ >+ int i; >+ int c, n; >+ int time_left; >+ EFI_STATUS status; >+ EFI_EVENT timer; >+ EFI_EVENT events[2]; >+ UINTN idx; >+ dev_info_t *dev; >+ const boot_module_t *mod; >+ >+ if ((ndevs <= 0) || (ndevs >= NUM_DEV_LIST)) { >+ return (EFI_NOT_FOUND); >+ } else if (ndevs == 1) { >+ /* Only one condidate. */ >+ *modp = mod = dev_list[0].modp; >+ *devinfop = dev = dev_list[0].devinfop; >+ return (mod->load(PATH_LOADER_EFI, dev, >+ bufp, bufsize)); >+ } >+ /* Two or more candidate exist. */ >+ status = BS->CreateEvent(EVT_TIMER, 0, 0, NULL, &timer); >+ if (status != EFI_SUCCESS) { >+ printf("Can't allocate timer event.\n"); >+ return (status); >+ } >+ printf(" 0: AutoSelected Partition (Default): 0\n"); >+ for (i = 0; i < ndevs; i++) { >+ if (dev_list[i].devinfop->preferred == TRUE) >+ c = '*'; >+ else >+ c = ' '; >+ printf(" %c%c: %s: %s: %c\n", c, idx2char(i+1), >+ dev_list[i].modp->name, >+ devpath_str(dev_list[i].devinfop->devpath), >+ idx2char(i+1)); >+ } >+ /* One alpha-num selection only. Is this big enough ?? */ >+ BS->SetTimer(timer, TimerPeriodic, 10000000); >+ events[0] = timer; >+ events[1] = conin->WaitForKey; >+ time_left = SELECT_TIMEOUT; >+ >+ while (1) { >+ if (time_left > 0) { >+ printf("Select from 0 to %c. Timeout in %2d seconds," >+ " [Space] to pause : ", >+ idx2char(ndevs), time_left); >+ } >+ status = BS->WaitForEvent(2, events, &idx); >+ if (status != EFI_SUCCESS) { >+ BS->CloseEvent(timer); >+ return (status); >+ } >+ if (idx == 0) { >+ time_left--; >+ if (time_left <=0) { >+ printf("\nTimeout. " >+ "Partition is AutoSelected.\n"); >+ n = 0; >+ break; >+ } else { >+ move_to_tol(); >+ } >+ } >+ if (idx == 1) { >+ c = getchar(); >+ if ((c == '\n') || (c == '\r')) { >+ putchar('\n'); >+ n = 0; >+ break; >+ } else if ((time_left > 0) && (c == ' ')) { >+ BS->SetTimer(timer, TimerCancel, 0); >+ time_left = -1; >+ printf("\nTimer stopeed.\n Please Key in: "); >+ } >+ n = char2idx(c); >+ if ((n >= 0) && (n <= ndevs)) { >+ BS->SetTimer(timer, TimerCancel, 0); >+ time_left = -1; >+ printf("\n %c is selected.\n", c); >+ if (n == 0) { /* AutoSelect */ >+ break; >+ } else { >+ mod = dev_list[n-1].modp; >+ dev = dev_list[n-1].devinfop; >+ status = mod->load(PATH_LOADER_EFI, >+ dev, bufp, bufsize); >+ if (status == EFI_SUCCESS) { >+ break; >+ } >+ printf("Failed to load '%s'\n", >+ PATH_LOADER_EFI); >+ printf("Please select again: "); >+ } >+ } else { >+ /* Invalid charecter. */ >+ move_to_tol(); >+ } >+ } >+ }; >+ BS->CloseEvent(timer); >+ if (n == 0) { /* AutoSelect */ >+ status = load_loader(modp, devinfop, bufp, bufsize, TRUE); >+ if (status != EFI_SUCCESS) { >+ status = load_loader(modp, devinfop, bufp, bufsize, >+ FALSE); >+ } >+ } else { >+ *modp = dev_list[n-1].modp; >+ *devinfop = dev_list[n-1].devinfop; >+ status = EFI_SUCCESS; >+ } >+ return (status); >+} >+ > /* > * try_boot only returns if it fails to load the loader. If it succeeds > * it simply boots, otherwise it returns the status of last EFI call. >@@ -219,22 +627,23 @@ static EFI_STATUS > try_boot(void) > { > size_t bufsize, loadersize, cmdsize; >- void *buf, *loaderbuf; >+ void *buf = NULL, *loaderbuf = NULL; /* For boot partition menu */ > char *cmd; > dev_info_t *dev; > const boot_module_t *mod; > EFI_HANDLE loaderhandle; > EFI_LOADED_IMAGE *loaded_image; > EFI_STATUS status; >+ int ndevs; /* For boot partition menu */ >+ >+ /* For boot partition menu */ >+ ndevs = list_devices(); >+ status = select_bootdev(ndevs, &mod, &dev, &loaderbuf, &loadersize); > >- status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); > if (status != EFI_SUCCESS) { >- status = load_loader(&mod, &dev, &loaderbuf, &loadersize, >- FALSE); >- if (status != EFI_SUCCESS) { >- printf("Failed to load '%s'\n", PATH_LOADER_EFI); >- return (status); >- } >+ /* For boot partition menu */ >+ printf("Failed to load '%s'\n", PATH_LOADER_EFI); >+ return (EFI_NOT_FOUND); > } > > /* >@@ -284,6 +683,10 @@ try_boot(void) > loaded_image->LoadOptionsSize = cmdsize; > loaded_image->LoadOptions = cmd; > >+ /* For boot partition menu */ >+ printf("Boot from: %s in 1 second\n", devpath_str(dev->devpath)); >+ BS->Stall(1000000); >+ > DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); > DSTALL(1000000); > DPRINTF("."); >@@ -420,26 +823,15 @@ probe_handle_status(EFI_HANDLE h, EFI_DE > DSTALL(500000); > } > >-EFI_STATUS >-efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) >+ >+/* Divide efi_main into two for boot partition menu */ >+static EFI_STATUS >+init_console() > { >- EFI_HANDLE *handles; >- EFI_LOADED_IMAGE *img; >- EFI_DEVICE_PATH *imgpath; > EFI_STATUS status; > EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; >- SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; >- UINTN i, hsize, nhandles; >- CHAR16 *text; >- UINT16 boot_current; >- size_t sz; >- UINT16 boot_order[100]; > >- /* Basic initialization*/ >- ST = Xsystab; >- IH = Ximage; >- BS = ST->BootServices; >- RS = ST->RuntimeServices; >+ UINTN i, cols, rows; > > /* Set up the console, so printf works. */ > status = BS->LocateProtocol(&ConsoleControlGUID, NULL, >@@ -451,13 +845,42 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_T > * Reset the console enable the cursor. Later we'll choose a bette > * console size through GOP/UGA. > */ >+ conin = ST->ConIn; > conout = ST->ConOut; >+ conin->Reset(conin, TRUE); > conout->Reset(conout, TRUE); > /* Explicitly set conout to mode 0, 80x25 */ > conout->SetMode(conout, 0); >+ >+ conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, >+ DEFAULT_BGCOLOR)); > conout->EnableCursor(conout, TRUE); > conout->ClearScreen(conout); > >+ return (status); >+} >+ >+EFI_STATUS >+efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) >+{ >+ EFI_HANDLE *handles; >+ EFI_LOADED_IMAGE *img; >+ EFI_DEVICE_PATH *imgpath; >+ EFI_STATUS status; >+ UINTN i, hsize, nhandles; >+ CHAR16 *text; >+ UINT16 boot_current; >+ size_t sz; >+ UINT16 boot_order[100]; >+ >+ /* Basic initialization*/ >+ ST = Xsystab; >+ IH = Ximage; >+ BS = Xsystab->BootServices; >+ RS = ST->RuntimeServices; >+ >+ init_console(); >+ > printf("\n>> FreeBSD EFI boot block\n"); > printf(" Loader path: %s\n\n", PATH_LOADER_EFI); > printf(" Initializing modules:"); >@@ -609,17 +1031,61 @@ efi_panic(EFI_STATUS s, const char *fmt, > BS->Exit(IH, s, 0, NULL); > } > >+/* Make putchar as wrapper for newly added efi_cons_putchar() for boot partition menu */ > void > putchar(int c) > { >+ efi_cons_putchar(c); >+} >+ >+void >+efi_cons_putchar(int c) >+{ > CHAR16 buf[2]; > > if (c == '\n') { > buf[0] = '\r'; > buf[1] = 0; >- ST->ConOut->OutputString(ST->ConOut, buf); >+ conout->OutputString(conout, buf); > } > buf[0] = c; > buf[1] = 0; >- ST->ConOut->OutputString(ST->ConOut, buf); >+ conout->OutputString(conout, buf); >+} >+ >+int >+getchar(void) >+{ >+ return efi_cons_getchar(); > } >+ >+ >+int >+efi_cons_getchar() >+{ >+ EFI_INPUT_KEY key; >+ EFI_STATUS status; >+ UINTN junk; >+ >+ /* Try to read a key stroke. We wait for one if none is pending. */ >+ status = conin->ReadKeyStroke(conin, &key); >+ if (status == EFI_NOT_READY) { >+ BS->WaitForEvent(1, &conin->WaitForKey, &junk); >+ status = conin->ReadKeyStroke(conin, &key); >+ } >+ switch (key.ScanCode) { >+ case 0x17: /* ESC */ >+ return (0x1b); /* esc */ >+ } >+ >+ /* this can return */ >+ return (key.UnicodeChar); >+} >+ >+int >+efi_cons_poll() >+{ >+ /* This can clear the signaled state. */ >+ return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); >+} >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 207940
:
168070
|
168264
|
168291
|
169420
|
170131
|
170241
|
194818
| 201259 |
201260
|
205099
|
205561
|
205563
|
212457
|
212647
|
246766