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