blob: 03e33a3ee02b6e78fe17d81c0aa07389d86e71e8 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk2262cfe2002-11-18 00:14:45 +00002/*
Gabe Blackd3a2bc32011-12-05 12:09:23 +00003 * Copyright (c) 2011 The Chromium OS Authors.
wdenk2262cfe2002-11-18 00:14:45 +00004 * (C) Copyright 2002
Albert ARIBAUDfa82f872011-08-04 18:45:45 +02005 * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
wdenk2262cfe2002-11-18 00:14:45 +00006 */
7
wdenk8bde7f72003-06-27 21:31:46 +00008/*
Graeme Russdbf71152011-04-13 19:43:26 +10009 * Linux x86 zImage and bzImage loading
wdenk8bde7f72003-06-27 21:31:46 +000010 *
11 * based on the procdure described in
wdenk2262cfe2002-11-18 00:14:45 +000012 * linux/Documentation/i386/boot.txt
13 */
14
15#include <common.h>
Simon Glass09140112020-05-10 11:40:03 -060016#include <command.h>
Simon Glasscdbff9f2019-08-01 09:46:50 -060017#include <env.h>
Simon Glass36bf4462019-11-14 12:57:42 -070018#include <irq_func.h>
Ivan Gorinov5d732922018-03-26 18:06:54 -070019#include <malloc.h>
Simon Glass776cc202020-04-08 16:57:36 -060020#include <acpi/acpi_table.h>
wdenk2262cfe2002-11-18 00:14:45 +000021#include <asm/io.h>
22#include <asm/ptrace.h>
23#include <asm/zimage.h>
wdenk2262cfe2002-11-18 00:14:45 +000024#include <asm/byteorder.h>
Simon Glass0d0ba592014-10-19 21:11:20 -060025#include <asm/bootm.h>
Graeme Russ95ffaba2010-04-24 00:05:49 +100026#include <asm/bootparam.h>
Vadim Bendebury3cdc18a2012-10-23 18:04:34 +000027#ifdef CONFIG_SYS_COREBOOT
28#include <asm/arch/timestamp.h>
29#endif
Stefan Reinauer61e0ea92012-10-23 18:04:37 +000030#include <linux/compiler.h>
Ivan Gorinov5d732922018-03-26 18:06:54 -070031#include <linux/libfdt.h>
wdenk2262cfe2002-11-18 00:14:45 +000032
33/*
34 * Memory lay-out:
wdenk8bde7f72003-06-27 21:31:46 +000035 *
wdenk2262cfe2002-11-18 00:14:45 +000036 * relative to setup_base (which is 0x90000 currently)
wdenk8bde7f72003-06-27 21:31:46 +000037 *
38 * 0x0000-0x7FFF Real mode kernel
wdenk2262cfe2002-11-18 00:14:45 +000039 * 0x8000-0x8FFF Stack and heap
40 * 0x9000-0x90FF Kernel command line
41 */
Graeme Russ83088af2011-11-08 02:33:15 +000042#define DEFAULT_SETUP_BASE 0x90000
43#define COMMAND_LINE_OFFSET 0x9000
44#define HEAP_END_OFFSET 0x8e00
wdenk2262cfe2002-11-18 00:14:45 +000045
Graeme Russ83088af2011-11-08 02:33:15 +000046#define COMMAND_LINE_SIZE 2048
wdenk2262cfe2002-11-18 00:14:45 +000047
Simon Glasse8148372020-09-05 14:50:38 -060048/**
49 * struct zboot_state - Current state of the boot
50 *
51 * @bzimage_addr: Address of the bzImage to boot
52 * @bzimage_size: Size of the bzImage, or 0 to detect this
53 * @initrd_addr: Address of the initial ramdisk, or 0 if none
54 * @initrd_size: Size of the initial ramdisk, or 0 if none
55 * @load_address: Address where the bzImage is moved before booting, either
56 * BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
Simon Glass88f1cd62020-09-05 14:50:44 -060057 * @base_ptr: Pointer to the boot parameters, typically at address
58 * DEFAULT_SETUP_BASE
Simon Glasse8148372020-09-05 14:50:38 -060059 */
60struct zboot_state {
61 ulong bzimage_addr;
62 ulong bzimage_size;
63 ulong initrd_addr;
64 ulong initrd_size;
65 ulong load_address;
Simon Glass88f1cd62020-09-05 14:50:44 -060066 struct boot_params *base_ptr;
Simon Glasse8148372020-09-05 14:50:38 -060067} state;
68
Simon Glass5588e772020-09-05 14:50:43 -060069enum {
70 ZBOOT_STATE_START = BIT(0),
Simon Glass1d9e4bb2020-09-05 14:50:46 -060071 ZBOOT_STATE_LOAD = BIT(1),
Simon Glass3e597592020-09-05 14:50:47 -060072 ZBOOT_STATE_SETUP = BIT(2),
73 ZBOOT_STATE_INFO = BIT(3),
74 ZBOOT_STATE_GO = BIT(4),
Simon Glass5588e772020-09-05 14:50:43 -060075
Simon Glass3e597592020-09-05 14:50:47 -060076 ZBOOT_STATE_COUNT = 5,
Simon Glass5588e772020-09-05 14:50:43 -060077};
78
wdenk2262cfe2002-11-18 00:14:45 +000079static void build_command_line(char *command_line, int auto_boot)
80{
81 char *env_command_line;
wdenk8bde7f72003-06-27 21:31:46 +000082
wdenk2262cfe2002-11-18 00:14:45 +000083 command_line[0] = '\0';
wdenk8bde7f72003-06-27 21:31:46 +000084
Simon Glass00caae62017-08-03 12:22:12 -060085 env_command_line = env_get("bootargs");
wdenk8bde7f72003-06-27 21:31:46 +000086
wdenk2262cfe2002-11-18 00:14:45 +000087 /* set console= argument if we use a serial console */
Graeme Russ83088af2011-11-08 02:33:15 +000088 if (!strstr(env_command_line, "console=")) {
Simon Glass00caae62017-08-03 12:22:12 -060089 if (!strcmp(env_get("stdout"), "serial")) {
wdenk8bde7f72003-06-27 21:31:46 +000090
wdenk2262cfe2002-11-18 00:14:45 +000091 /* We seem to use serial console */
wdenk8bde7f72003-06-27 21:31:46 +000092 sprintf(command_line, "console=ttyS0,%s ",
Simon Glass00caae62017-08-03 12:22:12 -060093 env_get("baudrate"));
wdenk2262cfe2002-11-18 00:14:45 +000094 }
95 }
wdenk8bde7f72003-06-27 21:31:46 +000096
Graeme Russ83088af2011-11-08 02:33:15 +000097 if (auto_boot)
wdenk2262cfe2002-11-18 00:14:45 +000098 strcat(command_line, "auto ");
wdenk8bde7f72003-06-27 21:31:46 +000099
Graeme Russ83088af2011-11-08 02:33:15 +0000100 if (env_command_line)
wdenk2262cfe2002-11-18 00:14:45 +0000101 strcat(command_line, env_command_line);
wdenk8bde7f72003-06-27 21:31:46 +0000102
wdenk2262cfe2002-11-18 00:14:45 +0000103 printf("Kernel command line: \"%s\"\n", command_line);
104}
105
Gabe Black69370d12011-12-05 12:09:26 +0000106static int kernel_magic_ok(struct setup_header *hdr)
107{
108 if (KERNEL_MAGIC != hdr->boot_flag) {
109 printf("Error: Invalid Boot Flag "
110 "(found 0x%04x, expected 0x%04x)\n",
111 hdr->boot_flag, KERNEL_MAGIC);
112 return 0;
113 } else {
114 printf("Valid Boot Flag\n");
115 return 1;
116 }
117}
118
Simon Glassc038f3b2020-09-05 14:50:40 -0600119static int get_boot_protocol(struct setup_header *hdr, bool verbose)
Gabe Black69370d12011-12-05 12:09:26 +0000120{
121 if (hdr->header == KERNEL_V2_MAGIC) {
Simon Glassc038f3b2020-09-05 14:50:40 -0600122 if (verbose)
123 printf("Magic signature found\n");
Gabe Black69370d12011-12-05 12:09:26 +0000124 return hdr->version;
125 } else {
126 /* Very old kernel */
Simon Glassc038f3b2020-09-05 14:50:40 -0600127 if (verbose)
128 printf("Magic signature not found\n");
Gabe Black69370d12011-12-05 12:09:26 +0000129 return 0x0100;
130 }
131}
132
Ivan Gorinov5d732922018-03-26 18:06:54 -0700133static int setup_device_tree(struct setup_header *hdr, const void *fdt_blob)
134{
Simon Glassc038f3b2020-09-05 14:50:40 -0600135 int bootproto = get_boot_protocol(hdr, false);
Ivan Gorinov5d732922018-03-26 18:06:54 -0700136 struct setup_data *sd;
137 int size;
138
139 if (bootproto < 0x0209)
140 return -ENOTSUPP;
141
142 if (!fdt_blob)
143 return 0;
144
145 size = fdt_totalsize(fdt_blob);
146 if (size < 0)
147 return -EINVAL;
148
149 size += sizeof(struct setup_data);
150 sd = (struct setup_data *)malloc(size);
151 if (!sd) {
152 printf("Not enough memory for DTB setup data\n");
153 return -ENOMEM;
154 }
155
156 sd->next = hdr->setup_data;
157 sd->type = SETUP_DTB;
158 sd->len = fdt_totalsize(fdt_blob);
159 memcpy(sd->data, fdt_blob, sd->len);
160 hdr->setup_data = (unsigned long)sd;
161
162 return 0;
163}
164
Simon Glassc038f3b2020-09-05 14:50:40 -0600165static const char *get_kernel_version(struct boot_params *params,
166 void *kernel_base)
167{
168 struct setup_header *hdr = &params->hdr;
169 int bootproto;
170
171 bootproto = get_boot_protocol(hdr, false);
172 if (bootproto < 0x0200 || hdr->setup_sects < 15)
173 return NULL;
174
175 return kernel_base + hdr->kernel_version + 0x200;
176}
177
Gabe Black69370d12011-12-05 12:09:26 +0000178struct boot_params *load_zimage(char *image, unsigned long kernel_size,
Simon Glass76539382014-10-10 08:21:56 -0600179 ulong *load_addressp)
wdenk2262cfe2002-11-18 00:14:45 +0000180{
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000181 struct boot_params *setup_base;
Simon Glassc038f3b2020-09-05 14:50:40 -0600182 const char *version;
wdenk2262cfe2002-11-18 00:14:45 +0000183 int setup_size;
184 int bootproto;
185 int big_image;
wdenk8bde7f72003-06-27 21:31:46 +0000186
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000187 struct boot_params *params = (struct boot_params *)image;
188 struct setup_header *hdr = &params->hdr;
wdenk8bde7f72003-06-27 21:31:46 +0000189
Graeme Russ83088af2011-11-08 02:33:15 +0000190 /* base address for real-mode segment */
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000191 setup_base = (struct boot_params *)DEFAULT_SETUP_BASE;
wdenk8bde7f72003-06-27 21:31:46 +0000192
Gabe Black69370d12011-12-05 12:09:26 +0000193 if (!kernel_magic_ok(hdr))
wdenk2262cfe2002-11-18 00:14:45 +0000194 return 0;
wdenk8bde7f72003-06-27 21:31:46 +0000195
wdenk2262cfe2002-11-18 00:14:45 +0000196 /* determine size of setup */
Graeme Russ95ffaba2010-04-24 00:05:49 +1000197 if (0 == hdr->setup_sects) {
198 printf("Setup Sectors = 0 (defaulting to 4)\n");
wdenk2262cfe2002-11-18 00:14:45 +0000199 setup_size = 5 * 512;
200 } else {
Graeme Russ95ffaba2010-04-24 00:05:49 +1000201 setup_size = (hdr->setup_sects + 1) * 512;
wdenk2262cfe2002-11-18 00:14:45 +0000202 }
wdenk8bde7f72003-06-27 21:31:46 +0000203
Graeme Russ95ffaba2010-04-24 00:05:49 +1000204 printf("Setup Size = 0x%8.8lx\n", (ulong)setup_size);
205
Graeme Russ83088af2011-11-08 02:33:15 +0000206 if (setup_size > SETUP_MAX_SIZE)
wdenk2262cfe2002-11-18 00:14:45 +0000207 printf("Error: Setup is too large (%d bytes)\n", setup_size);
wdenk8bde7f72003-06-27 21:31:46 +0000208
Gabe Black69370d12011-12-05 12:09:26 +0000209 /* determine boot protocol version */
Simon Glassc038f3b2020-09-05 14:50:40 -0600210 bootproto = get_boot_protocol(hdr, true);
Gabe Black69370d12011-12-05 12:09:26 +0000211
212 printf("Using boot protocol version %x.%02x\n",
213 (bootproto & 0xff00) >> 8, bootproto & 0xff);
214
Simon Glassc038f3b2020-09-05 14:50:40 -0600215 version = get_kernel_version(params, image);
216 if (version)
217 printf("Linux kernel version %s\n", version);
218 else
219 printf("Setup Sectors < 15 - Cannot print kernel version\n");
Gabe Black69370d12011-12-05 12:09:26 +0000220
wdenk2262cfe2002-11-18 00:14:45 +0000221 /* Determine image type */
Graeme Russ83088af2011-11-08 02:33:15 +0000222 big_image = (bootproto >= 0x0200) &&
223 (hdr->loadflags & BIG_KERNEL_FLAG);
wdenk8bde7f72003-06-27 21:31:46 +0000224
Graeme Russ95ffaba2010-04-24 00:05:49 +1000225 /* Determine load address */
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000226 if (big_image)
Simon Glass76539382014-10-10 08:21:56 -0600227 *load_addressp = BZIMAGE_LOAD_ADDR;
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000228 else
Simon Glass76539382014-10-10 08:21:56 -0600229 *load_addressp = ZIMAGE_LOAD_ADDR;
wdenk8bde7f72003-06-27 21:31:46 +0000230
Gabe Black233dbc12011-12-05 12:09:24 +0000231 printf("Building boot_params at 0x%8.8lx\n", (ulong)setup_base);
232 memset(setup_base, 0, sizeof(*setup_base));
233 setup_base->hdr = params->hdr;
wdenk8bde7f72003-06-27 21:31:46 +0000234
Gabe Black69370d12011-12-05 12:09:26 +0000235 if (bootproto >= 0x0204)
236 kernel_size = hdr->syssize * 16;
237 else
238 kernel_size -= setup_size;
wdenk8bde7f72003-06-27 21:31:46 +0000239
wdenk8bde7f72003-06-27 21:31:46 +0000240 if (bootproto == 0x0100) {
Graeme Russ83088af2011-11-08 02:33:15 +0000241 /*
242 * A very old kernel MUST have its real-mode code
243 * loaded at 0x90000
244 */
Simon Glass42fd8c12017-01-16 07:03:35 -0700245 if ((ulong)setup_base != 0x90000) {
wdenk2262cfe2002-11-18 00:14:45 +0000246 /* Copy the real-mode kernel */
Graeme Russ83088af2011-11-08 02:33:15 +0000247 memmove((void *)0x90000, setup_base, setup_size);
wdenk8bde7f72003-06-27 21:31:46 +0000248
Graeme Russ83088af2011-11-08 02:33:15 +0000249 /* Copy the command line */
250 memmove((void *)0x99000,
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000251 (u8 *)setup_base + COMMAND_LINE_OFFSET,
Graeme Russ83088af2011-11-08 02:33:15 +0000252 COMMAND_LINE_SIZE);
253
254 /* Relocated */
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000255 setup_base = (struct boot_params *)0x90000;
wdenk2262cfe2002-11-18 00:14:45 +0000256 }
wdenk8bde7f72003-06-27 21:31:46 +0000257
wdenk2262cfe2002-11-18 00:14:45 +0000258 /* It is recommended to clear memory up to the 32K mark */
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000259 memset((u8 *)0x90000 + setup_size, 0,
260 SETUP_MAX_SIZE - setup_size);
wdenk2262cfe2002-11-18 00:14:45 +0000261 }
wdenk8bde7f72003-06-27 21:31:46 +0000262
Gabe Black69370d12011-12-05 12:09:26 +0000263 if (big_image) {
264 if (kernel_size > BZIMAGE_MAX_SIZE) {
265 printf("Error: bzImage kernel too big! "
266 "(size: %ld, max: %d)\n",
267 kernel_size, BZIMAGE_MAX_SIZE);
268 return 0;
269 }
270 } else if ((kernel_size) > ZIMAGE_MAX_SIZE) {
271 printf("Error: zImage kernel too big! (size: %ld, max: %d)\n",
272 kernel_size, ZIMAGE_MAX_SIZE);
273 return 0;
274 }
Graeme Russ95ffaba2010-04-24 00:05:49 +1000275
Simon Glass76539382014-10-10 08:21:56 -0600276 printf("Loading %s at address %lx (%ld bytes)\n",
277 big_image ? "bzImage" : "zImage", *load_addressp, kernel_size);
Gabe Black69370d12011-12-05 12:09:26 +0000278
Simon Glass76539382014-10-10 08:21:56 -0600279 memmove((void *)*load_addressp, image + setup_size, kernel_size);
Gabe Black69370d12011-12-05 12:09:26 +0000280
281 return setup_base;
282}
283
284int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
285 unsigned long initrd_addr, unsigned long initrd_size)
286{
287 struct setup_header *hdr = &setup_base->hdr;
Simon Glassc038f3b2020-09-05 14:50:40 -0600288 int bootproto = get_boot_protocol(hdr, false);
Gabe Black69370d12011-12-05 12:09:26 +0000289
Gabe Black69370d12011-12-05 12:09:26 +0000290 setup_base->e820_entries = install_e820_map(
291 ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map);
Gabe Black69370d12011-12-05 12:09:26 +0000292
293 if (bootproto == 0x0100) {
294 setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
295 setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET;
296 }
wdenk2262cfe2002-11-18 00:14:45 +0000297 if (bootproto >= 0x0200) {
Simon Glass00630f62020-09-05 14:50:41 -0600298 hdr->type_of_loader = 0x80; /* U-Boot version 0 */
wdenk2262cfe2002-11-18 00:14:45 +0000299 if (initrd_addr) {
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000300 printf("Initial RAM disk at linear address "
301 "0x%08lx, size %ld bytes\n",
wdenk2262cfe2002-11-18 00:14:45 +0000302 initrd_addr, initrd_size);
wdenk8bde7f72003-06-27 21:31:46 +0000303
Graeme Russ95ffaba2010-04-24 00:05:49 +1000304 hdr->ramdisk_image = initrd_addr;
305 hdr->ramdisk_size = initrd_size;
wdenk2262cfe2002-11-18 00:14:45 +0000306 }
307 }
wdenk8bde7f72003-06-27 21:31:46 +0000308
wdenk2262cfe2002-11-18 00:14:45 +0000309 if (bootproto >= 0x0201) {
Graeme Russ95ffaba2010-04-24 00:05:49 +1000310 hdr->heap_end_ptr = HEAP_END_OFFSET;
311 hdr->loadflags |= HEAP_FLAG;
wdenk2262cfe2002-11-18 00:14:45 +0000312 }
wdenk8bde7f72003-06-27 21:31:46 +0000313
Simon Glass97d1e0c2014-10-19 21:11:21 -0600314 if (cmd_line) {
315 if (bootproto >= 0x0202) {
316 hdr->cmd_line_ptr = (uintptr_t)cmd_line;
317 } else if (bootproto >= 0x0200) {
318 setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
319 setup_base->screen_info.cl_offset =
320 (uintptr_t)cmd_line - (uintptr_t)setup_base;
Graeme Russ95ffaba2010-04-24 00:05:49 +1000321
Simon Glass97d1e0c2014-10-19 21:11:21 -0600322 hdr->setup_move_size = 0x9100;
323 }
324
325 /* build command line at COMMAND_LINE_OFFSET */
326 build_command_line(cmd_line, auto_boot);
wdenk2262cfe2002-11-18 00:14:45 +0000327 }
wdenk2262cfe2002-11-18 00:14:45 +0000328
Simon Glass30b372d2020-09-05 14:50:39 -0600329 if (IS_ENABLED(CONFIG_INTEL_MID) && bootproto >= 0x0207)
Andy Shevchenko378960d2018-01-10 19:40:14 +0200330 hdr->hardware_subarch = X86_SUBARCH_INTEL_MID;
Andy Shevchenko378960d2018-01-10 19:40:14 +0200331
Simon Glass30b372d2020-09-05 14:50:39 -0600332 if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE))
333 setup_base->acpi_rsdp_addr = acpi_get_rsdp_addr();
Andy Shevchenkod905aa82019-09-13 18:42:00 +0300334
Ivan Gorinov5d732922018-03-26 18:06:54 -0700335 setup_device_tree(hdr, (const void *)env_get_hex("fdtaddr", 0));
Bin Menga4520022015-07-06 16:31:36 +0800336 setup_video(&setup_base->screen_info);
337
Simon Glass30b372d2020-09-05 14:50:39 -0600338 if (IS_ENABLED(CONFIG_EFI_STUB))
339 setup_efi_info(&setup_base->efi_info);
Bin Meng1fdeacd2018-08-23 08:24:10 -0700340
Gabe Black69370d12011-12-05 12:09:26 +0000341 return 0;
wdenk2262cfe2002-11-18 00:14:45 +0000342}
343
Simon Glass5588e772020-09-05 14:50:43 -0600344static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
345 char *const argv[])
Graeme Russ95ffaba2010-04-24 00:05:49 +1000346{
Simon Glass5588e772020-09-05 14:50:43 -0600347 const char *s;
Graeme Russ95ffaba2010-04-24 00:05:49 +1000348
Simon Glasse8148372020-09-05 14:50:38 -0600349 memset(&state, '\0', sizeof(state));
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000350 if (argc >= 2) {
Graeme Russabe98f42010-10-07 20:03:19 +1100351 /* argv[1] holds the address of the bzImage */
352 s = argv[1];
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000353 } else {
Simon Glass00caae62017-08-03 12:22:12 -0600354 s = env_get("fileaddr");
Gabe Blackd3a2bc32011-12-05 12:09:23 +0000355 }
Graeme Russ95ffaba2010-04-24 00:05:49 +1000356
Graeme Russabe98f42010-10-07 20:03:19 +1100357 if (s)
Simon Glasse8148372020-09-05 14:50:38 -0600358 state.bzimage_addr = simple_strtoul(s, NULL, 16);
Graeme Russabe98f42010-10-07 20:03:19 +1100359
Gabe Black6f9d9982011-12-05 12:09:27 +0000360 if (argc >= 3) {
Graeme Russabe98f42010-10-07 20:03:19 +1100361 /* argv[2] holds the size of the bzImage */
Simon Glasse8148372020-09-05 14:50:38 -0600362 state.bzimage_size = simple_strtoul(argv[2], NULL, 16);
Gabe Black6f9d9982011-12-05 12:09:27 +0000363 }
364
365 if (argc >= 4)
Simon Glasse8148372020-09-05 14:50:38 -0600366 state.initrd_addr = simple_strtoul(argv[3], NULL, 16);
Gabe Black6f9d9982011-12-05 12:09:27 +0000367 if (argc >= 5)
Simon Glasse8148372020-09-05 14:50:38 -0600368 state.initrd_size = simple_strtoul(argv[4], NULL, 16);
Graeme Russ95ffaba2010-04-24 00:05:49 +1000369
Simon Glass1d9e4bb2020-09-05 14:50:46 -0600370 return 0;
371}
372
373static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
374 char *const argv[])
375{
376 struct boot_params *base_ptr;
377
Simon Glasse8148372020-09-05 14:50:38 -0600378 base_ptr = load_zimage((void *)state.bzimage_addr, state.bzimage_size,
379 &state.load_address);
Graeme Russ83088af2011-11-08 02:33:15 +0000380 if (!base_ptr) {
Simon Glass2c363cb2014-10-10 08:21:59 -0600381 puts("## Kernel loading failed ...\n");
Simon Glass1d9e4bb2020-09-05 14:50:46 -0600382 return CMD_RET_FAILURE;
Graeme Russ95ffaba2010-04-24 00:05:49 +1000383 }
Simon Glass88f1cd62020-09-05 14:50:44 -0600384 state.base_ptr = base_ptr;
Simon Glass126f47c2020-09-05 14:50:48 -0600385 if (env_set_hex("zbootbase", (ulong)base_ptr) ||
386 env_set_hex("zbootaddr", state.load_address))
387 return CMD_RET_FAILURE;
Simon Glasse8148372020-09-05 14:50:38 -0600388
Simon Glass3e597592020-09-05 14:50:47 -0600389 return 0;
390}
391
392static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
393 char *const argv[])
394{
395 struct boot_params *base_ptr = state.base_ptr;
396 int ret;
397
398 if (!base_ptr) {
399 printf("base is not set: use 'zboot load' first\n");
400 return CMD_RET_FAILURE;
401 }
402 ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
403 0, state.initrd_addr, state.initrd_size);
404 if (ret) {
Simon Glass2c363cb2014-10-10 08:21:59 -0600405 puts("Setting up boot parameters failed ...\n");
Simon Glass3e597592020-09-05 14:50:47 -0600406 return CMD_RET_FAILURE;
Gabe Black69370d12011-12-05 12:09:26 +0000407 }
408
Simon Glass88f1cd62020-09-05 14:50:44 -0600409 return 0;
410}
411
Simon Glass6f873f52020-09-05 14:50:45 -0600412static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc,
413 char *const argv[])
414{
415 printf("Kernel loaded at %08lx, setup_base=%p\n",
416 state.load_address, state.base_ptr);
417
418 return 0;
419}
420
Simon Glass88f1cd62020-09-05 14:50:44 -0600421static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
422 char *const argv[])
423{
424 int ret;
425
Simon Glasse9d31b32020-09-05 14:50:42 -0600426 disable_interrupts();
Simon Glass88f1cd62020-09-05 14:50:44 -0600427
Gabe Black69370d12011-12-05 12:09:26 +0000428 /* we assume that the kernel is in place */
Simon Glass88f1cd62020-09-05 14:50:44 -0600429 ret = boot_linux_kernel((ulong)state.base_ptr, state.load_address,
430 false);
431 printf("Kernel returned! (err=%d)\n", ret);
432
433 return CMD_RET_FAILURE;
Graeme Russ95ffaba2010-04-24 00:05:49 +1000434}
435
Simon Glass5588e772020-09-05 14:50:43 -0600436/* Note: This defines the complete_zboot() function */
437U_BOOT_SUBCMDS(zboot,
438 U_BOOT_CMD_MKENT(start, 6, 1, do_zboot_start, "", ""),
Simon Glass1d9e4bb2020-09-05 14:50:46 -0600439 U_BOOT_CMD_MKENT(load, 1, 1, do_zboot_load, "", ""),
Simon Glass3e597592020-09-05 14:50:47 -0600440 U_BOOT_CMD_MKENT(setup, 1, 1, do_zboot_setup, "", ""),
Simon Glass6f873f52020-09-05 14:50:45 -0600441 U_BOOT_CMD_MKENT(info, 1, 1, do_zboot_info, "", ""),
Simon Glass88f1cd62020-09-05 14:50:44 -0600442 U_BOOT_CMD_MKENT(go, 1, 1, do_zboot_go, "", ""),
Simon Glass5588e772020-09-05 14:50:43 -0600443)
444
445int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc,
446 char *const argv[], int state_mask)
447{
448 int i;
449
450 for (i = 0; i < ZBOOT_STATE_COUNT; i++) {
451 struct cmd_tbl *cmd = &zboot_subcmds[i];
452 int mask = 1 << i;
453 int ret;
454
455 if (mask & state_mask) {
456 ret = cmd->cmd(cmd, flag, argc, argv);
457 if (ret)
458 return ret;
459 }
460 }
461
462 return 0;
463}
464
465int do_zboot_parent(struct cmd_tbl *cmdtp, int flag, int argc,
466 char *const argv[], int *repeatable)
467{
468 /* determine if we have a sub command */
469 if (argc > 1) {
470 char *endp;
471
472 simple_strtoul(argv[1], &endp, 16);
473 /*
474 * endp pointing to nul means that argv[1] was just a valid
475 * number, so pass it along to the normal processing
476 */
477 if (*endp)
478 return do_zboot(cmdtp, flag, argc, argv, repeatable);
479 }
480
Simon Glass88f1cd62020-09-05 14:50:44 -0600481 do_zboot_states(cmdtp, flag, argc, argv, ZBOOT_STATE_START |
Simon Glass3e597592020-09-05 14:50:47 -0600482 ZBOOT_STATE_LOAD | ZBOOT_STATE_SETUP |
483 ZBOOT_STATE_INFO | ZBOOT_STATE_GO);
Simon Glass5588e772020-09-05 14:50:43 -0600484
485 return CMD_RET_FAILURE;
486}
487
488U_BOOT_CMDREP_COMPLETE(
489 zboot, 6, do_zboot_parent, "Boot bzImage",
Gabe Black6f9d9982011-12-05 12:09:27 +0000490 "[addr] [size] [initrd addr] [initrd size]\n"
491 " addr - The optional starting address of the bzimage.\n"
492 " If not set it defaults to the environment\n"
493 " variable \"fileaddr\".\n"
494 " size - The optional size of the bzimage. Defaults to\n"
495 " zero.\n"
496 " initrd addr - The address of the initrd image to use, if any.\n"
497 " initrd size - The size of the initrd image to use, if any.\n"
Simon Glass5588e772020-09-05 14:50:43 -0600498 "\n"
499 "Sub-commands to do part of the zboot sequence:\n"
Simon Glass88f1cd62020-09-05 14:50:44 -0600500 "\tstart [addr [arg ...]] - specify arguments\n"
Simon Glass1d9e4bb2020-09-05 14:50:46 -0600501 "\tload - load OS image\n"
Simon Glass3e597592020-09-05 14:50:47 -0600502 "\tsetup - set up table\n"
Simon Glass6f873f52020-09-05 14:50:45 -0600503 "\tinfo - show summary info\n"
Simon Glass88f1cd62020-09-05 14:50:44 -0600504 "\tgo - start OS\n",
Simon Glass5588e772020-09-05 14:50:43 -0600505 complete_zboot
Graeme Russ95ffaba2010-04-24 00:05:49 +1000506);