1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com> 4 */ 5 6 #include <common.h> 7 #include <command.h> 8 #include <errno.h> 9 #include <qfw.h> 10 11 /* 12 * This function prepares kernel for zboot. It loads kernel data 13 * to 'load_addr', initrd to 'initrd_addr' and kernel command 14 * line using qemu fw_cfg interface. 15 */ 16 static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr) 17 { 18 char *data_addr; 19 uint32_t setup_size, kernel_size, cmdline_size, initrd_size; 20 21 qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size); 22 qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_size); 23 24 if (setup_size == 0 || kernel_size == 0) { 25 printf("warning: no kernel available\n"); 26 return -1; 27 } 28 29 data_addr = load_addr; 30 qemu_fwcfg_read_entry(FW_CFG_SETUP_DATA, 31 le32_to_cpu(setup_size), data_addr); 32 data_addr += le32_to_cpu(setup_size); 33 34 qemu_fwcfg_read_entry(FW_CFG_KERNEL_DATA, 35 le32_to_cpu(kernel_size), data_addr); 36 data_addr += le32_to_cpu(kernel_size); 37 38 data_addr = initrd_addr; 39 qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size); 40 if (initrd_size == 0) { 41 printf("warning: no initrd available\n"); 42 } else { 43 qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA, 44 le32_to_cpu(initrd_size), data_addr); 45 data_addr += le32_to_cpu(initrd_size); 46 } 47 48 qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size); 49 if (cmdline_size) { 50 qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA, 51 le32_to_cpu(cmdline_size), data_addr); 52 /* 53 * if kernel cmdline only contains '\0', (e.g. no -append 54 * when invoking qemu), do not update bootargs 55 */ 56 if (*data_addr != '\0') { 57 if (env_set("bootargs", data_addr) < 0) 58 printf("warning: unable to change bootargs\n"); 59 } 60 } 61 62 printf("loading kernel to address %p size %x", load_addr, 63 le32_to_cpu(kernel_size)); 64 if (initrd_size) 65 printf(" initrd %p size %x\n", 66 initrd_addr, 67 le32_to_cpu(initrd_size)); 68 else 69 printf("\n"); 70 71 return 0; 72 } 73 74 static int qemu_fwcfg_list_firmware(void) 75 { 76 int ret; 77 struct fw_cfg_file_iter iter; 78 struct fw_file *file; 79 80 /* make sure fw_list is loaded */ 81 ret = qemu_fwcfg_read_firmware_list(); 82 if (ret) 83 return ret; 84 85 86 for (file = qemu_fwcfg_file_iter_init(&iter); 87 !qemu_fwcfg_file_iter_end(&iter); 88 file = qemu_fwcfg_file_iter_next(&iter)) { 89 printf("%-56s\n", file->cfg.name); 90 } 91 92 return 0; 93 } 94 95 static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag, 96 int argc, char * const argv[]) 97 { 98 if (qemu_fwcfg_list_firmware() < 0) 99 return CMD_RET_FAILURE; 100 101 return 0; 102 } 103 104 static int qemu_fwcfg_do_cpus(cmd_tbl_t *cmdtp, int flag, 105 int argc, char * const argv[]) 106 { 107 int ret = qemu_fwcfg_online_cpus(); 108 if (ret < 0) { 109 printf("QEMU fw_cfg interface not found\n"); 110 return CMD_RET_FAILURE; 111 } 112 113 printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus()); 114 115 return 0; 116 } 117 118 static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag, 119 int argc, char * const argv[]) 120 { 121 char *env; 122 void *load_addr; 123 void *initrd_addr; 124 125 env = env_get("loadaddr"); 126 load_addr = env ? 127 (void *)simple_strtoul(env, NULL, 16) : 128 #ifdef CONFIG_LOADADDR 129 (void *)CONFIG_LOADADDR; 130 #else 131 NULL; 132 #endif 133 134 env = env_get("ramdiskaddr"); 135 initrd_addr = env ? 136 (void *)simple_strtoul(env, NULL, 16) : 137 #ifdef CONFIG_RAMDISK_ADDR 138 (void *)CONFIG_RAMDISK_ADDR; 139 #else 140 NULL; 141 #endif 142 143 if (argc == 2) { 144 load_addr = (void *)simple_strtoul(argv[0], NULL, 16); 145 initrd_addr = (void *)simple_strtoul(argv[1], NULL, 16); 146 } else if (argc == 1) { 147 load_addr = (void *)simple_strtoul(argv[0], NULL, 16); 148 } 149 150 if (!load_addr || !initrd_addr) { 151 printf("missing load or initrd address\n"); 152 return CMD_RET_FAILURE; 153 } 154 155 return qemu_fwcfg_setup_kernel(load_addr, initrd_addr); 156 } 157 158 static cmd_tbl_t fwcfg_commands[] = { 159 U_BOOT_CMD_MKENT(list, 0, 1, qemu_fwcfg_do_list, "", ""), 160 U_BOOT_CMD_MKENT(cpus, 0, 1, qemu_fwcfg_do_cpus, "", ""), 161 U_BOOT_CMD_MKENT(load, 2, 1, qemu_fwcfg_do_load, "", ""), 162 }; 163 164 static int do_qemu_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 165 { 166 int ret; 167 cmd_tbl_t *fwcfg_cmd; 168 169 if (!qemu_fwcfg_present()) { 170 printf("QEMU fw_cfg interface not found\n"); 171 return CMD_RET_USAGE; 172 } 173 174 fwcfg_cmd = find_cmd_tbl(argv[1], fwcfg_commands, 175 ARRAY_SIZE(fwcfg_commands)); 176 argc -= 2; 177 argv += 2; 178 if (!fwcfg_cmd || argc > fwcfg_cmd->maxargs) 179 return CMD_RET_USAGE; 180 181 ret = fwcfg_cmd->cmd(fwcfg_cmd, flag, argc, argv); 182 183 return cmd_process_error(fwcfg_cmd, ret); 184 } 185 186 U_BOOT_CMD( 187 qfw, 4, 1, do_qemu_fw, 188 "QEMU firmware interface", 189 "<command>\n" 190 " - list : print firmware(s) currently loaded\n" 191 " - cpus : print online cpu number\n" 192 " - load <kernel addr> <initrd addr> : load kernel and initrd (if any), and setup for zboot\n" 193 ) 194