FreeBSD Bugzilla – Attachment 205561 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.stable12.diff
boot1.c.stable12.diff (text/plain), 10.77 KB, created by
Naomichi Nonaka
on 2019-07-07 11:31:22 UTC
(
hide
)
Description:
boot1.c.stable12.diff
Filename:
MIME Type:
Creator:
Naomichi Nonaka
Created:
2019-07-07 11:31:22 UTC
Size:
10.77 KB
patch
obsolete
>--- stand/efi/boot1/boot1.c.orig 2018-12-07 09:02:34.000000000 +0900 >+++ stand/efi/boot1/boot1.c 2019-07-07 16:52:22.406821000 +0900 >@@ -36,6 +36,8 @@ > > static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); > >+static EFI_STATUS try_boot(const boot_module_t *mod, dev_info_t *dev, void *loaderbuf, size_t loadersize); >+ > static const boot_module_t *boot_modules[] = > { > #ifdef EFI_ZFS_BOOT >@@ -79,26 +81,6 @@ > } > > /* >- * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, >- * FALSE otherwise. >- */ >-static BOOLEAN >-nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) >-{ >- size_t len; >- >- if (imgpath == NULL || imgpath->Type != devpath->Type || >- imgpath->SubType != devpath->SubType) >- return (FALSE); >- >- len = DevicePathNodeLength(imgpath); >- if (len != DevicePathNodeLength(devpath)) >- return (FALSE); >- >- return (memcmp(imgpath, devpath, (size_t)len) == 0); >-} >- >-/* > * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes > * in imgpath and devpath match up to their respective occurrences of a > * media node, FALSE otherwise. >@@ -115,7 +97,7 @@ > IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) > return (TRUE); > >- if (!nodes_match(imgpath, devpath)) >+ if (!efi_devpath_match_node(imgpath, devpath)) > return (FALSE); > > imgpath = NextDevicePathNode(imgpath); >@@ -125,20 +107,253 @@ > return (FALSE); > } > >+/* quick and dirty work for boot partition menu */ >+ >+#define NUM_DEV_LIST 35 >+#define SELECT_TIMEOUT 10 >+ >+typedef struct { >+ const boot_module_t *modp; >+ dev_info_t *devinfop; >+} moddev_t; >+ >+static moddev_t dev_list[NUM_DEV_LIST]; >+ >+static 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); >+} >+ >+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() >+{ >+ SIMPLE_TEXT_OUTPUT_INTERFACE *conout; >+ int x,y; >+ >+ conout = ST->ConOut; >+ x = conout->Mode->CursorColumn; >+ y = conout->Mode->CursorRow; >+ conout->SetCursorPosition(conout, 0, y); >+} >+ >+int >+getchar(void) >+{ >+ EFI_INPUT_KEY key; >+ EFI_STATUS status; >+ UINTN junk; >+ >+ /* Try to read a key stroke. We wait for one if none is pending. */ >+ status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); >+ if (status == EFI_NOT_READY) { >+ BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &junk); >+ status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); >+ } >+ switch (key.ScanCode) { >+ case 0x17: /* ESC */ >+ return (0x1b); /* esc */ >+ } >+ >+ /* this can return */ >+ return (key.UnicodeChar); >+} >+ > /* >- * devpath_last returns the last non-path end node in devpath. >+ * Output of EFI_DEVICE_PATH_TO_TEXT_PROTOCOL is not easy to read. >+ " I hope this looks better. > */ >-static EFI_DEVICE_PATH * >-devpath_last(EFI_DEVICE_PATH *devpath) >+static int >+mediapath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) > { >+ switch (devpath->Type) { >+ case MEDIA_DEVICE_PATH: >+ switch (devpath->SubType) { >+ case MEDIA_CDROM_DP: { >+ CDROM_DEVICE_PATH *cdrom; > >- while (!IsDevicePathEnd(NextDevicePathNode(devpath))) >- devpath = NextDevicePathNode(devpath); >+ cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; >+ return snprintf(buf, size, "cdrom(%x)", >+ cdrom->BootEntry); >+ } >+ case MEDIA_HARDDRIVE_DP: { >+ HARDDRIVE_DEVICE_PATH *hd; > >- return (devpath); >+ 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); >+ } >+ } >+ >+ return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, >+ devpath->SubType); > } > > /* >+ * mediapath_str is convenience method which returns the text description of >+ * mediapath using a static buffer, so it isn't thread safe! >+ */ >+char * >+mediapath_str(EFI_DEVICE_PATH *devpath) >+{ >+ static char buf[256]; >+ >+ mediapath_node_str(buf, sizeof(buf), devpath); >+ >+ return buf; >+} >+ >+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); >+} >+ >+ >+static int >+get_sel(int ndevs,int time_left) >+{ >+ int i; >+ int c, n; >+ EFI_STATUS status; >+ EFI_EVENT timer; >+ EFI_EVENT events[2]; >+ EFI_DEVICE_PATH *mediapath; >+ UINTN idx; >+ dev_info_t *dev; >+ CHAR16 *text; >+ >+ status = BS->CreateEvent(EVT_TIMER, 0, 0, NULL, &timer); >+ if (status != EFI_SUCCESS) { >+ printf("Can't allocate timer event.\n"); >+ return (-1); >+ } >+ printf(" 0: AutoSelected Partition (Default): 0\n"); >+ for (i = 0; i < ndevs; i++) { >+ if (dev_list[i].devinfop->preferred == TRUE) >+ c = '*'; >+ else >+ c = ' '; >+ mediapath = efi_devpath_to_media_path( >+ dev_list[i].devinfop->devpath); >+ printf(" %c%c: %s: %s: %c\n", c, idx2char(i+1), >+ dev_list[i].modp->name, >+ mediapath_str(mediapath), >+ idx2char(i+1)); >+ } >+ /* One alpha-num selection only. Is this big enough ?? */ >+ BS->SetTimer(timer, TimerPeriodic, 10000000); >+ events[0] = timer; >+ events[1] = ST->ConIn->WaitForKey; >+ >+ 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 (-1); >+ } >+ 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); >+ break; >+ } else { >+ /* Invalid charecter. */ >+ move_to_tol(); >+ } >+ } >+ }; >+ BS->CloseEvent(timer); >+ return (n); >+} >+ >+/* > * load_loader attempts to load the loader image data. > * > * It tries each module and its respective devices, identified by mod->probe, >@@ -173,32 +388,96 @@ > return (EFI_NOT_FOUND); > } > >+static EFI_STATUS >+select_loader(const boot_module_t **modp, dev_info_t **devinfop, >+ void **bufp, size_t *bufsize) >+{ >+ int n; >+ int time_left; >+ EFI_STATUS status; >+ dev_info_t *dev; >+ const boot_module_t *mod; >+ int ndevs; >+ >+ ndevs = list_devices(); >+ 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. */ >+ >+ /* Reset the console input. */ >+ ST->ConIn->Reset(ST->ConIn, TRUE); >+ >+ time_left = SELECT_TIMEOUT; >+ while (1) { >+ n = get_sel(ndevs, time_left); >+ if (n < 0) { >+ return (EFI_NOT_FOUND); >+ } else 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: "); >+ time_left = -1; >+ } >+ } >+ 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); >+} >+ >+void >+sel_boot(void) >+{ >+ size_t loadersize; >+ void *loaderbuf = NULL; >+ dev_info_t *dev; >+ const boot_module_t *mod; >+ EFI_STATUS status; >+ >+ status = select_loader(&mod, &dev, &loaderbuf, &loadersize); >+ if (status != EFI_SUCCESS) { >+ printf("Failed to load '%s'\n", PATH_LOADER_EFI); >+ return; >+ } >+ >+ try_boot(mod, dev, loaderbuf, loadersize); >+} >+ > /* > * 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. > */ >-static EFI_STATUS >-try_boot(void) >+EFI_STATUS >+try_boot(const boot_module_t *mod, dev_info_t *dev, void *loaderbuf, size_t loadersize) > { >- size_t bufsize, loadersize, cmdsize; >- void *buf, *loaderbuf; >+ size_t bufsize, cmdsize; >+ void *buf; > char *cmd; >- dev_info_t *dev; >- const boot_module_t *mod; > EFI_HANDLE loaderhandle; > EFI_LOADED_IMAGE *loaded_image; > EFI_STATUS status; > >- 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); >- } >- } >- > /* > * Read in and parse the command line from /boot.config or /boot/config, > * if present. We'll pass it the next stage via a simple ASCII >@@ -225,7 +504,7 @@ > buf = NULL; > } > >- if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), >+ if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(dev->devpath), > loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { > printf("Failed to load image provided by %s, size: %zu, (%lu)\n", > mod->name, loadersize, EFI_ERROR_CODE(status)); >@@ -522,7 +801,7 @@ > boot_modules[i]->status(); > } > >- try_boot(); >+ sel_boot(); > > /* If we get here, we're out of luck... */ > efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
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