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