1// SPDX-License-Identifier: GPL-2.0+ 2 3#include <common.h> 4#include <command.h> 5#include <env.h> 6#include <fs.h> 7#include <pxe_utils.h> 8 9/** 10 * struct sysboot_info - useful information for sysboot helpers 11 * 12 * @fstype: Filesystem type (FS_TYPE_...) 13 * @ifname: Interface name (e.g. "ide", "scsi") 14 * @dev_part_str is in the format: 15 * <dev>.<hw_part>:<part> where <dev> is the device number, 16 * <hw_part> is the optional hardware partition number and 17 * <part> is the partition number 18 */ 19struct sysboot_info { 20 int fstype; 21 const char *ifname; 22 const char *dev_part_str; 23}; 24 25static int sysboot_read_file(struct pxe_context *ctx, const char *file_path, 26 char *file_addr, ulong *sizep) 27{ 28 struct sysboot_info *info = ctx->userdata; 29 loff_t len_read; 30 ulong addr; 31 int ret; 32 33 addr = simple_strtoul(file_addr, NULL, 16); 34 ret = fs_set_blk_dev(info->ifname, info->dev_part_str, info->fstype); 35 if (ret) 36 return ret; 37 ret = fs_read(file_path, addr, 0, 0, &len_read); 38 if (ret) 39 return ret; 40 *sizep = len_read; 41 42 return 0; 43} 44 45/* 46 * Boots a system using a local disk syslinux/extlinux file 47 * 48 * Returns 0 on success, 1 on error. 49 */ 50static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc, 51 char *const argv[]) 52{ 53 unsigned long pxefile_addr_r; 54 struct pxe_context ctx; 55 char *pxefile_addr_str; 56 struct sysboot_info info; 57 char *filename; 58 int prompt = 0; 59 int ret; 60 61 if (argc > 1 && strstr(argv[1], "-p")) { 62 prompt = 1; 63 argc--; 64 argv++; 65 } 66 67 if (argc < 4) 68 return cmd_usage(cmdtp); 69 70 if (argc < 5) { 71 pxefile_addr_str = from_env("pxefile_addr_r"); 72 if (!pxefile_addr_str) 73 return 1; 74 } else { 75 pxefile_addr_str = argv[4]; 76 } 77 78 if (argc < 6) { 79 filename = env_get("bootfile"); 80 if (!filename) { 81 printf("Specify a filename or set the ${bootfile} environment variable\n"); 82 return 1; 83 } 84 } else { 85 filename = argv[5]; 86 env_set("bootfile", filename); 87 } 88 89 if (strstr(argv[3], "ext2")) { 90 info.fstype = FS_TYPE_EXT; 91 } else if (strstr(argv[3], "fat")) { 92 info.fstype = FS_TYPE_FAT; 93 } else if (strstr(argv[3], "any")) { 94 info.fstype = FS_TYPE_ANY; 95 } else { 96 printf("Invalid filesystem: %s\n", argv[3]); 97 return 1; 98 } 99 info.ifname = argv[1]; 100 info.dev_part_str = argv[2]; 101 102 if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) { 103 printf("Invalid pxefile address: %s\n", pxefile_addr_str); 104 return 1; 105 } 106 107 if (pxe_setup_ctx(&ctx, cmdtp, sysboot_read_file, &info, true, 108 filename, false)) { 109 printf("Out of memory\n"); 110 return CMD_RET_FAILURE; 111 } 112 113 if (get_pxe_file(&ctx, filename, pxefile_addr_r) < 0) { 114 printf("Error reading config file\n"); 115 pxe_destroy_ctx(&ctx); 116 return 1; 117 } 118 119 ret = pxe_process(&ctx, pxefile_addr_r, prompt); 120 pxe_destroy_ctx(&ctx); 121 if (ret) 122 return CMD_RET_FAILURE; 123 124 return 0; 125} 126 127U_BOOT_CMD(sysboot, 7, 1, do_sysboot, 128 "command to get and boot from syslinux files", 129 "[-p] <interface> <dev[:part]> <ext2|fat|any> [addr] [filename]\n" 130 " - load and parse syslinux menu file 'filename' from ext2, fat\n" 131 " or any filesystem on 'dev' on 'interface' to address 'addr'" 132); 133