xref: /openbmc/u-boot/cmd/qfw.c (revision c68c03f52badc90951dbf8a054c0e500e04bf365)
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