From mboxrd@z Thu Jan 1 00:00:00 1970 From: Suriyan Ramasami Date: Wed, 10 Apr 2013 21:27:29 -0700 Subject: [U-Boot] [PATCH v2 8/8] ARM: Present a menu of bootable options on boot In-Reply-To: References: <1365599537-14138-1-git-send-email-suriyan.r@gmail.com> <1365599537-14138-9-git-send-email-suriyan.r@gmail.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de I shall probably move it to a generic location with a more generic name. Any reocmmendations? - Suriyan On Wed, Apr 10, 2013 at 6:43 PM, Rob Herring wrote: > On Wed, Apr 10, 2013 at 8:12 AM, Suriyan Ramasami > wrote: > > Initialize usb and ide. > > Scan through the usb for storage and boot capable partitions. > > Scan through the ide interface for boot capable partitions. > > Present such bootable options to the user to choose to boot from > > If the user does not choose any choose the default option > > the default option is the option chosen by the user the last time > > If no such default option exists, boot from the first possible > > bootable option. > > This all sounds very generic but... > > > > > Signed-off-by: Suriyan Ramasami > > --- > > Changes in v2: > > - Coding style changes > > > > board/Seagate/goflexhome/goflexhomemenu.c | 415 > +++++++++++++++++++++++++++++ > > but this is not a generic location. This feature would interest me and > probably Stephen as well. > > Rob > > > 1 files changed, 415 insertions(+), 0 deletions(-) > > create mode 100644 board/Seagate/goflexhome/goflexhomemenu.c > > > > diff --git a/board/Seagate/goflexhome/goflexhomemenu.c > b/board/Seagate/goflexhome/goflexhomemenu.c > > new file mode 100644 > > index 0000000..6169cf8 > > --- /dev/null > > +++ b/board/Seagate/goflexhome/goflexhomemenu.c > > @@ -0,0 +1,415 @@ > > +/* > > + * Copyright (C) 2013 Suriyan Ramasami > > + * > > + * See file CREDITS for list of people who contributed to this > > + * project. > > + * > > + * This program is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU General Public License as > > + * published by the Free Software Foundation; either version 2 of > > + * the License, or (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License > > + * along with this program; if not, write to the Free Software > > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > + * MA 02110-1301 USA > > + */ > > + > > +#include > > + > > +#if defined(CONFIG_MENU) > > +/* Menu related code begins here */ > > + > > +/* Added to use the various usb/fat/ext4fs interfaces */ > > +#include > > +#include > > +#include > > + > > +#define MENU_MAX_DEVICES 10 > > +#define MENU_MAX_PARTITIONS 10 > > +#define MENU_MAX_BOOTABLES 10 > > + > > +#define MENU_EXIT 1 > > +#define MENU_SHOW 2 > > + > > +#define MENU_DEFAULT_BOOTARGS \ > > + "setenv bootargs ${console} ubi.mtd=2,2048 " \ > > + "root=ubi0:root rootfstype=ubifs debug" > > + > > +#define MENU_DEFAULT_BOOTCMD \ > > + "setenv bootcmd nand read.e 0x800000 0x100000 0x600000" > > + > > +#define MENU_PROMPT_BOOTCMD \ > > + "setenv bootcmd echo Dropping you to u-boot" > > + > > +#define MENU_CHOSEN_BOOTARGS \ > > + "setenv bootargs $console rootdelay=10 root=${menu_root} debug" > > + > > +#define MENU_OPTIONS_HEADER \ > > + > "Bootables:\nChoice\tIntface\tDrive\tDevice\tPart\tFS\tFileName\n" \ > > + "---------------------------------------------------------------" > > + > > +#define MENU_DEFAULT_NOBOOTABLES \ > > + "* Last boot options (None, and no bootables found!" > > + > > +struct menu_bootables { > > + char interface[5]; > > + char drive; > > + int device; > > + int partition; > > + char filename[64]; > > + char fstype; /* f => fat, e => ext2/4 0 => invalid */ > > +}; > > + > > +static void goflexhome_menuprint(void *print_buffer) > > +{ > > + printf("%s\n", (char *)print_buffer); > > +} > > + > > +/* > > + * We shall use menu_<> variables to capture the state of past menu > > + * choices. > > + * menu_bootargs corresponds to bootargs > > + * menu_bootcmd corresponds to bootcmd > > + * menu_choice corresponds to the last choice that was picked > > + * menu_choice will be NULL the first time and also > > + * if a choice was never made. In that case we should pick > > + * to boot from the 1st bootable option if present. > > +*/ > > +static int goflexhome_evaluate_env(void) > > +{ > > +char *s; > > + > > + run_command("run menu_bootargs", 0); > > + s = getenv("bootargs"); > > + printf("bootargs is %s\n", s); > > + run_command("run menu_bootcmd", 0); > > + s = getenv("bootcmd"); > > + printf("bootcmd is %s\n", s); > > + if (run_command("run bootcmd", 0) != 0) { > > + /* We failed to boot, present the menu */ > > + return MENU_SHOW; > > + } > > + if (strncmp(s, "echo", 4) == 0) { > > + /* User wants the u-boot prmpt */ > > + return MENU_EXIT; > > + } > > + run_command("bootm", 0); > > + > > + /* We are here, we failed to boot */ > > + return MENU_SHOW; > > +} > > + > > +static int goflexhome_handle_choice(struct menu_bootables > menu_bootlist[], > > + char *choice) > > +{ > > +char *s, *last_menu_choice; > > +char menu_command[128]; > > +char load_command[16]; > > +int index; > > +int call_saveenv; > > + > > + call_saveenv = 0; > > + if (choice == NULL) { > > + /* Exit menu and let it do its auto boot */ > > + return MENU_EXIT; > > + } > > + printf("\nYou chose: %s\n", choice); > > + > > + last_menu_choice = getenv("menu_choice"); > > + if (last_menu_choice == NULL) { > > + /* User has not yet chosen before */ > > + /* Lets default to boot from nand */ > > + setenv("menu_bootargs", MENU_DEFAULT_BOOTARGS); > > + setenv("menu_bootcmd", MENU_DEFAULT_BOOTCMD); > > + call_saveenv = 1; > > + } > > + if (choice[0] == '*') { > > + /* User wants same thing that was chosen the last time */ > > + return MENU_EXIT; > > + } > > + if (last_menu_choice && strcmp(choice, last_menu_choice) != 0) { > > + /* Save the choice chosen */ > > + setenv("menu_choice", choice); > > + call_saveenv = 1; > > + } > > + if (choice[0] == '+') { > > + /* User wants u-boot prompt */ > > + s = getenv("menu_bootcmd"); > > + if (strcmp(s, MENU_PROMPT_BOOTCMD) != 0) { > > + setenv("menu_bootcmd", MENU_PROMPT_BOOTCMD); > > + saveenv(); > > + } > > + return MENU_EXIT; > > + } > > + > > + /* Steps to set the env variables to the chosen values */ > > + index = simple_strtoul(choice, NULL, 10); > > + sprintf(menu_command, "/dev/sd%c%d", menu_bootlist[index].drive, > > + menu_bootlist[index].partition); > > + s = getenv("menu_root"); > > + if (strcmp(s, menu_command) != 0) { > > + setenv("menu_root", menu_command); > > + call_saveenv = 1; > > + } > > + s = getenv("menu_bootargs"); > > + if (strcmp(s, MENU_CHOSEN_BOOTARGS) != 0) { > > + setenv("menu_bootargs", MENU_CHOSEN_BOOTARGS); > > + call_saveenv = 1; > > + } > > + switch (menu_bootlist[index].fstype) { > > + case 'e': > > + strcpy(load_command, "ext4load"); > > + break; > > + default: > > + return MENU_EXIT; > > + } > > + > > + /* Lets try to load and check the image */ > > + sprintf(menu_command, "%s %s %d:%d %x %s", > > + load_command, > > + menu_bootlist[index].interface, > > + menu_bootlist[index].device, > > + menu_bootlist[index].partition, > > + CONFIG_SYS_LOAD_ADDR, > > + menu_bootlist[index].filename); > > + if (run_command(menu_command, 0) != 0) { > > + /* Could not load image */ > > + printf("Selected image could not be loaded ...\n"); > > + return MENU_SHOW; > > + } > > + sprintf(menu_command, "iminfo %x", CONFIG_SYS_LOAD_ADDR); > > + if (run_command(menu_command, 0) != 0) { > > + /* The image is not a valid image */ > > + printf("Selected image is not valid ...\n"); > > + return MENU_SHOW; > > + } > > + > > + sprintf(menu_command, "setenv bootcmd %s %s %d:%d %x %s", > > + load_command, > > + menu_bootlist[index].interface, > > + menu_bootlist[index].device, > > + menu_bootlist[index].partition, > > + CONFIG_SYS_LOAD_ADDR, > > + menu_bootlist[index].filename); > > + s = getenv("menu_bootcmd"); > > + if (strcmp(s, menu_command) != 0) { > > + setenv("menu_bootcmd", menu_command); > > + call_saveenv = 1; > > + } > > + if (call_saveenv) > > + saveenv(); > > + return MENU_EXIT; > > +} > > + > > +static int goflexhome_menu(struct menu_bootables menu_bootlist[], int > bootdelay) > > +{ > > +int index; > > +struct menu *m; > > +char menu_key[MENU_MAX_BOOTABLES][5]; > > +char menu_entry[MENU_MAX_BOOTABLES][64]; > > +char *menu_choice; > > +char *last_menu_choice; > > +char choice_menu_entry[64]; > > +char choice_menu[3]; > > + > > + m = menu_create(MENU_OPTIONS_HEADER, 60, 1, goflexhome_menuprint, > > + NULL, NULL); > > + for (index = 0; index < MENU_MAX_BOOTABLES; index++) { > > + if (menu_bootlist[index].fstype == '0') > > + break; > > + snprintf(menu_key[index], sizeof(menu_key[index]), "%d", > index); > > + snprintf(menu_entry[index], sizeof(menu_entry[index]), > > + "%d\t%s\t%c\t%d\t%d\t%c\t%s", index, > > + menu_bootlist[index].interface, > > + menu_bootlist[index].drive, > > + menu_bootlist[index].device, > > + menu_bootlist[index].partition, > > + menu_bootlist[index].fstype, > > + menu_bootlist[index].filename); > > + if (menu_item_add(m, menu_key[index], menu_entry[index]) > != 1) { > > + menu_destroy(m); > > + return MENU_EXIT; > > + } > > + } > > + > > + /* Prep for what should be the default menu choice */ > > + /* If chosen before, choose the last boot options */ > > + /* If nothing chosen yet, then choose the first bootable option > */ > > + /* If nothing chosen yet, and no first bootable option, then > boot */ > > + /* from nand */ > > + last_menu_choice = getenv("menu_choice"); > > + sprintf(choice_menu, "*"); > > + if (last_menu_choice) { > > + sprintf(choice_menu_entry, "* Last boot options (%s)", > > + last_menu_choice); > > + } else { > > + /* There was no last boot option */ > > + /* If there is at least 1 boot entry, make that the > default */ > > + if (menu_bootlist[0].fstype != '0') { > > + setenv("menu_choice", menu_entry[0]); > > + sprintf(choice_menu_entry, menu_entry[0]); > > + } else { > > + sprintf(choice_menu_entry, > MENU_DEFAULT_NOBOOTABLES); > > + } > > + } > > + if (menu_item_add(m, choice_menu, choice_menu_entry) != 1) { > > + menu_destroy(m); > > + return MENU_EXIT; > > + } > > + /* Mark this as the default choice. */ > > + menu_default_set(m, "*"); > > + if (menu_item_add(m, "+", "+ UBoot prompt") != 1) { > > + menu_destroy(m); > > + return MENU_EXIT; > > + } > > + > > + menu_get_choice(m, (void **)&menu_choice); > > + return goflexhome_handle_choice(menu_bootlist, menu_choice); > > +} > > + > > +static void goflexhome_filesearch(struct menu_bootables menu_bootlist[], > > + int *bootindex) { > > +char *filenames[] = { "/uImage", "/boot/uImage", "" }; > > +int index; > > + > > + index = 0; > > + while (filenames[index][0] != '\0') { > > + switch (menu_bootlist[*bootindex].fstype) { > > + case 'e': > > + if (ext4fs_open(filenames[index]) == -1) { > > + index++; > > + continue; > > + } > > + break; > > + > > + default: > > + break; > > + } > > + > > + /* Got a hit, record it */ > > + strcpy(menu_bootlist[*bootindex].filename, > filenames[index]); > > + index++; > > + (*bootindex)++; > > + if (*bootindex >= MENU_MAX_BOOTABLES) > > + break; > > + /* Prep next bootlist structure */ > > + memcpy(&menu_bootlist[*bootindex], > > + &menu_bootlist[*bootindex - 1], > > + sizeof(struct menu_bootables)); > > + } > > +} > > + > > +static void goflexhome_populate_partitions(struct menu_bootables > *menu_bootlist, > > + block_dev_desc_t *dev_desc, > > + int *bootindex) > > +{ > > +int part; > > +disk_partition_t disk_part; > > + > > + part = menu_bootlist[*bootindex].partition; > > + > > + /* Get the partition structure */ > > + if (get_partition_info(dev_desc, part, &disk_part)) > > + return; > > + > > + /* Try to check if its extX */ > > + if (ext4fs_probe(dev_desc, &disk_part) == 0) { > > + menu_bootlist[*bootindex].fstype = 'e'; > > + goflexhome_filesearch(menu_bootlist, bootindex); > > + ext4fs_close(); > > + return; > > + } > > +} > > + > > +static void goflexhome_populate_devices(struct menu_bootables > menu_bootlist[], > > + int *bootindex) > > +{ > > +block_dev_desc_t *dev_desc; > > +int device; > > +int part; > > + > > + /* Populate bootlist from each device and the partitions within > */ > > + for (device = 0; device < MENU_MAX_DEVICES; device++) { > > + dev_desc = get_dev(menu_bootlist[*bootindex].interface, > device); > > + if (dev_desc == NULL) > > + continue; > > + menu_bootlist[*bootindex].device = device; > > + for (part = 0; part < MENU_MAX_PARTITIONS; part++) { > > + menu_bootlist[*bootindex].partition = part; > > + goflexhome_populate_partitions(menu_bootlist, > dev_desc, > > + bootindex); > > + } > > + } > > +} > > + > > +/* menu_bootlist[] can hold a max of MENU_MAX_BOOTABLES entries */ > > +static void goflexhome_populate_bootlist(struct menu_bootables > menu_bootlist[]) > > +{ > > +/* ide is always first */ > > +char *interfaces[] = { "ide", "usb", "" }; > > +int bootindex; > > +int i; > > + > > + bootindex = 0; > > + i = 0; > > + /* Lets initialize the usb sub system */ > > + usb_init(); > > + usb_stor_scan(0); > > + > > + /* This scans the partitions in the IDE storage */ > > + ide_init(); > > + > > + /* Populate bootlist from each interface */ > > + while ((interfaces[i][0] != '\0') && > > + (bootindex < MENU_MAX_BOOTABLES)) { > > + strcpy(menu_bootlist[bootindex].interface, > interfaces[i]); > > + goflexhome_populate_devices(menu_bootlist, &bootindex); > > + i++; > > + } > > + if (bootindex < MENU_MAX_BOOTABLES) { > > + /* End marker of list */ > > + menu_bootlist[bootindex].fstype = '0'; > > + } > > + > > + /* Lets set the drive letter */ > > + menu_bootlist[0].drive = 'a'; > > + for (i = 1; i < bootindex; i++) { > > + if (menu_bootlist[i].fstype == '0') > > + break; > > + /* Increase drive letter when interface changes */ > > + /* Or when device numbers change for same interface */ > > + menu_bootlist[i].drive = menu_bootlist[i - 1].drive; > > + if (strcmp(menu_bootlist[i].interface, > > + menu_bootlist[i - 1].interface) != 0) { > > + menu_bootlist[i].drive++; > > + } else { > > + if (menu_bootlist[i].device > > > + menu_bootlist[i - 1].device) { > > + menu_bootlist[i].drive++; > > + } > > + } > > + } > > +} > > + > > +int menu_show(int bootdelay) > > +{ > > +struct menu_bootables menu_bootlist[MENU_MAX_BOOTABLES]; > > +int retval; > > + > > + goflexhome_populate_bootlist(menu_bootlist); > > + do { > > + retval = goflexhome_menu(menu_bootlist, bootdelay); > > + if (retval == MENU_EXIT) > > + retval = goflexhome_evaluate_env(); > > + } while (retval == MENU_SHOW); > > + > > + return 0; > > +} > > + > > +#endif /* CONFIG_MENU */ > > -- > > 1.7.1 > > > > _______________________________________________ > > U-Boot mailing list > > U-Boot at lists.denx.de > > http://lists.denx.de/mailman/listinfo/u-boot >