xref: /rk3399_rockchip-uboot/arch/x86/lib/zimage.c (revision f08fa7a2018495c6f2a5eaba5f6d8fdcbc67e6c6)
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors.
3  * (C) Copyright 2002
4  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24 
25 /*
26  * Linux x86 zImage and bzImage loading
27  *
28  * based on the procdure described in
29  * linux/Documentation/i386/boot.txt
30  */
31 
32 #include <common.h>
33 #include <asm/io.h>
34 #include <asm/ptrace.h>
35 #include <asm/zimage.h>
36 #include <asm/realmode.h>
37 #include <asm/byteorder.h>
38 #include <asm/bootparam.h>
39 
40 /*
41  * Memory lay-out:
42  *
43  * relative to setup_base (which is 0x90000 currently)
44  *
45  *	0x0000-0x7FFF	Real mode kernel
46  *	0x8000-0x8FFF	Stack and heap
47  *	0x9000-0x90FF	Kernel command line
48  */
49 #define DEFAULT_SETUP_BASE	0x90000
50 #define COMMAND_LINE_OFFSET	0x9000
51 #define HEAP_END_OFFSET		0x8e00
52 
53 #define COMMAND_LINE_SIZE	2048
54 
55 unsigned generic_install_e820_map(unsigned max_entries,
56 				  struct e820entry *entries)
57 {
58 	return 0;
59 }
60 
61 unsigned install_e820_map(unsigned max_entries,
62 			  struct e820entry *entries)
63 	__attribute__((weak, alias("generic_install_e820_map")));
64 
65 static void build_command_line(char *command_line, int auto_boot)
66 {
67 	char *env_command_line;
68 
69 	command_line[0] = '\0';
70 
71 	env_command_line =  getenv("bootargs");
72 
73 	/* set console= argument if we use a serial console */
74 	if (!strstr(env_command_line, "console=")) {
75 		if (!strcmp(getenv("stdout"), "serial")) {
76 
77 			/* We seem to use serial console */
78 			sprintf(command_line, "console=ttyS0,%s ",
79 				getenv("baudrate"));
80 		}
81 	}
82 
83 	if (auto_boot)
84 		strcat(command_line, "auto ");
85 
86 	if (env_command_line)
87 		strcat(command_line, env_command_line);
88 
89 	printf("Kernel command line: \"%s\"\n", command_line);
90 }
91 
92 void *load_zimage(char *image, unsigned long kernel_size,
93 		  unsigned long initrd_addr, unsigned long initrd_size,
94 		  int auto_boot, void **load_address)
95 {
96 	struct boot_params *setup_base;
97 	int setup_size;
98 	int bootproto;
99 	int big_image;
100 
101 	struct boot_params *params = (struct boot_params *)image;
102 	struct setup_header *hdr = &params->hdr;
103 
104 	/* base address for real-mode segment */
105 	setup_base = (struct boot_params *)DEFAULT_SETUP_BASE;
106 
107 	if (KERNEL_MAGIC != hdr->boot_flag) {
108 		printf("Error: Invalid Boot Flag "
109 			"(found 0x%04x, expected 0x%04x)\n",
110 			hdr->boot_flag, KERNEL_MAGIC);
111 		return 0;
112 	} else {
113 		printf("Valid Boot Flag\n");
114 	}
115 
116 	/* determine boot protocol version */
117 	if (KERNEL_V2_MAGIC == hdr->header) {
118 		printf("Magic signature found\n");
119 
120 		bootproto = hdr->version;
121 	} else {
122 		/* Very old kernel */
123 		printf("Magic signature not found\n");
124 		bootproto = 0x0100;
125 	}
126 
127 	/* determine size of setup */
128 	if (0 == hdr->setup_sects) {
129 		printf("Setup Sectors = 0 (defaulting to 4)\n");
130 		setup_size = 5 * 512;
131 	} else {
132 		setup_size = (hdr->setup_sects + 1) * 512;
133 	}
134 
135 	printf("Setup Size = 0x%8.8lx\n", (ulong)setup_size);
136 
137 	if (setup_size > SETUP_MAX_SIZE)
138 		printf("Error: Setup is too large (%d bytes)\n", setup_size);
139 
140 	/* Determine image type */
141 	big_image = (bootproto >= 0x0200) &&
142 		    (hdr->loadflags & BIG_KERNEL_FLAG);
143 
144 	/* Determine load address */
145 	if (big_image)
146 		*load_address = (void *)BZIMAGE_LOAD_ADDR;
147 	else
148 		*load_address = (void *)ZIMAGE_LOAD_ADDR;
149 
150 #if defined CONFIG_ZBOOT_32
151 	printf("Building boot_params at 0x%8.8lx\n", (ulong)setup_base);
152 	memset(setup_base, 0, sizeof(*setup_base));
153 	setup_base->hdr = params->hdr;
154 
155 	setup_base->e820_entries = install_e820_map(
156 		ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map);
157 #else
158 	/* load setup */
159 	printf("Moving Real-Mode Code to 0x%8.8lx (%d bytes)\n",
160 	       (ulong)setup_base, setup_size);
161 	memmove(setup_base, image, setup_size);
162 #endif
163 
164 	printf("Using boot protocol version %x.%02x\n",
165 	       (bootproto & 0xff00) >> 8, bootproto & 0xff);
166 
167 	if (bootproto == 0x0100) {
168 		setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
169 		setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET;
170 
171 		/*
172 		 * A very old kernel MUST have its real-mode code
173 		 * loaded at 0x90000
174 		 */
175 		if ((u32)setup_base != 0x90000) {
176 			/* Copy the real-mode kernel */
177 			memmove((void *)0x90000, setup_base, setup_size);
178 
179 			/* Copy the command line */
180 			memmove((void *)0x99000,
181 				(u8 *)setup_base + COMMAND_LINE_OFFSET,
182 				COMMAND_LINE_SIZE);
183 
184 			 /* Relocated */
185 			setup_base = (struct boot_params *)0x90000;
186 		}
187 
188 		/* It is recommended to clear memory up to the 32K mark */
189 		memset((u8 *)0x90000 + setup_size, 0,
190 		       SETUP_MAX_SIZE - setup_size);
191 	}
192 
193 	/* We are now setting up the real-mode version of the header */
194 	hdr = &setup_base->hdr;
195 
196 	if (bootproto >= 0x0200) {
197 		hdr->type_of_loader = 8;
198 
199 		if (hdr->setup_sects >= 15) {
200 			printf("Linux kernel version %s\n",
201 			       (char *)params +
202 			       hdr->kernel_version + 0x200);
203 		} else {
204 			printf("Setup Sectors < 15 - "
205 			       "Cannot print kernel version.\n");
206 		}
207 
208 		if (initrd_addr) {
209 			printf("Initial RAM disk at linear address "
210 			       "0x%08lx, size %ld bytes\n",
211 			       initrd_addr, initrd_size);
212 
213 			hdr->ramdisk_image = initrd_addr;
214 			hdr->ramdisk_size = initrd_size;
215 		}
216 	}
217 
218 	if (bootproto >= 0x0201) {
219 		hdr->heap_end_ptr = HEAP_END_OFFSET;
220 		hdr->loadflags |= HEAP_FLAG;
221 	}
222 
223 	if (bootproto >= 0x0202) {
224 		hdr->cmd_line_ptr =
225 			(uintptr_t)setup_base + COMMAND_LINE_OFFSET;
226 	} else if (bootproto >= 0x0200) {
227 		setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
228 		setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET;
229 
230 		hdr->setup_move_size = 0x9100;
231 	}
232 
233 	if (bootproto >= 0x0204)
234 		kernel_size = hdr->syssize * 16;
235 	else
236 		kernel_size -= setup_size;
237 
238 
239 	if (big_image) {
240 		if ((kernel_size) > BZIMAGE_MAX_SIZE) {
241 			printf("Error: bzImage kernel too big! "
242 				"(size: %ld, max: %d)\n",
243 				kernel_size, BZIMAGE_MAX_SIZE);
244 			return 0;
245 		}
246 	} else if ((kernel_size) > ZIMAGE_MAX_SIZE) {
247 		printf("Error: zImage kernel too big! (size: %ld, max: %d)\n",
248 		       kernel_size, ZIMAGE_MAX_SIZE);
249 		return 0;
250 	}
251 
252 	/* build command line at COMMAND_LINE_OFFSET */
253 	build_command_line((char *)setup_base + COMMAND_LINE_OFFSET, auto_boot);
254 
255 	printf("Loading %czImage at address 0x%08x (%ld bytes)\n",
256 	       big_image ? 'b' : ' ', (u32)*load_address, kernel_size);
257 
258 	memmove(*load_address, image + setup_size, kernel_size);
259 
260 	/* ready for booting */
261 	return setup_base;
262 }
263 
264 void boot_zimage(void *setup_base, void *load_address)
265 {
266 	printf("\nStarting kernel ...\n\n");
267 
268 #if defined CONFIG_ZBOOT_32
269 	/*
270 	 * Set %ebx, %ebp, and %edi to 0, %esi to point to the boot_params
271 	 * structure, and then jump to the kernel. We assume that %cs is
272 	 * 0x10, 4GB flat, and read/execute, and the data segments are 0x18,
273 	 * 4GB flat, and read/write. U-boot is setting them up that way for
274 	 * itself in arch/i386/cpu/cpu.c.
275 	 */
276 	__asm__ __volatile__ (
277 	"movl $0, %%ebp		\n"
278 	"cli			\n"
279 	"jmp %[kernel_entry]	\n"
280 	:: [kernel_entry]"a"(load_address),
281 	   [boot_params] "S"(setup_base),
282 	   "b"(0), "D"(0)
283 	:  "%ebp"
284 	);
285 #else
286 	struct pt_regs regs;
287 
288 	memset(&regs, 0, sizeof(struct pt_regs));
289 	regs.xds = (u32)setup_base >> 4;
290 	regs.xes = regs.xds;
291 	regs.xss = regs.xds;
292 	regs.esp = 0x9000;
293 	regs.eflags = 0;
294 	enter_realmode(((u32)setup_base + SETUP_START_OFFSET) >> 4, 0,
295 		       &regs, &regs);
296 #endif
297 }
298 
299 int do_zboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
300 {
301 	void *base_ptr;
302 	void *bzImage_addr = NULL;
303 	void *load_address;
304 	char *s;
305 	ulong bzImage_size = 0;
306 
307 	disable_interrupts();
308 
309 	/* Setup board for maximum PC/AT Compatibility */
310 	setup_pcat_compatibility();
311 
312 	if (argc >= 2) {
313 		/* argv[1] holds the address of the bzImage */
314 		s = argv[1];
315 	} else {
316 		s = getenv("fileaddr");
317 	}
318 
319 	if (s)
320 		bzImage_addr = (void *)simple_strtoul(s, NULL, 16);
321 
322 	if (argc >= 3)
323 		/* argv[2] holds the size of the bzImage */
324 		bzImage_size = simple_strtoul(argv[2], NULL, 16);
325 
326 	/* Lets look for */
327 	base_ptr = load_zimage(bzImage_addr, bzImage_size, 0, 0, 0,
328 		&load_address);
329 
330 	if (!base_ptr) {
331 		printf("## Kernel loading failed ...\n");
332 	} else {
333 		printf("## Transferring control to Linux "
334 		       "(at address %08x) ...\n",
335 		       (u32)base_ptr);
336 
337 		/* we assume that the kernel is in place */
338 		boot_zimage(base_ptr, load_address);
339 		/* does not return */
340 	}
341 
342 	return -1;
343 }
344 
345 U_BOOT_CMD(
346 	zboot, 2, 0,	do_zboot,
347 	"Boot bzImage",
348 	""
349 );
350