Add basic support for mini2440 board to barebox.
[barebox-mini2440.git] / commands / linux16.c
blobb15812f1d9bff71b2d93462f825eb1ad825681cf
1 /*
2 * Copyright (C) 2009 Juergen Beisert, Pengutronix
4 * In parts from the GRUB2 project:
6 * GRUB -- GRand Unified Bootloader
7 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc.
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.
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.
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
26 #include <common.h>
27 #include <command.h>
28 #include <environment.h>
29 #include <fs.h>
30 #include <errno.h>
31 #include <malloc.h>
32 #include <asm/syslib.h>
34 /** FIXME */
35 #define LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */
37 /** FIXME */
38 #define LINUX_FLAG_BIG_KERNEL 0x1
40 /** FIXME */
41 #define LINUX_BOOT_LOADER_TYPE 0x72
43 /** FIXME */
44 #define LINUX_DEFAULT_SETUP_SECTS 4
46 /** FIXME */
47 #define LINUX_MAX_SETUP_SECTS 64
49 /** FIXME */
50 #define LINUX_OLD_REAL_MODE_SEGMT 0x9000
52 /** FIXME */
53 #define LINUX_OLD_REAL_MODE_ADDR (LINUX_OLD_REAL_MODE_SEGMT << 4)
55 /** FIXME */
56 #define LINUX_HEAP_END_OFFSET (LINUX_OLD_REAL_MODE_SEGMT - 0x200)
58 /** FIXME */
59 #define LINUX_FLAG_CAN_USE_HEAP 0x80
61 /** Define kernel command lines's start offset in the setup segment */
62 #define LINUX_CL_OFFSET 0x9000
64 /** Define kernel command lines's end offset */
65 #define LINUX_CL_END_OFFSET 0x90FF
67 /** FIXME */
68 #define LINUX_CL_MAGIC 0xA33F
70 /** FIXME */
71 #define LINUX_SETUP_MOVE_SIZE 0x9100
73 /** Sector size */
74 #define DISK_SECTOR_BITS 9
75 #define DISK_SECTOR_SIZE 0x200
77 /** Where to load a bzImage */
78 #define LINUX_BZIMAGE_ADDR 0x100000
80 struct linux_kernel_header {
81 /* first sector of the image */
82 uint8_t code1[0x0020];
83 uint16_t cl_magic; /**< Magic number 0xA33F */
84 uint16_t cl_offset; /**< The offset of command line */
85 uint8_t code2[0x01F1 - 0x0020 - 2 - 2];
86 uint8_t setup_sects; /**< The size of the setup in sectors */
87 uint16_t root_flags; /**< If the root is mounted readonly */
88 uint16_t syssize; /**< obsolete */
89 uint16_t swap_dev; /**< obsolete */
90 uint16_t ram_size; /**< obsolete */
91 uint16_t vid_mode; /**< Video mode control */
92 uint16_t root_dev; /**< Default root device number */
93 uint16_t boot_flag; /**< 0xAA55 magic number */
95 /* second sector of the image */
96 uint16_t jump; /**< Jump instruction (this is code!) */
97 uint32_t header; /**< Magic signature "HdrS" */
98 uint16_t version; /**< Boot protocol version supported */
99 uint32_t realmode_swtch; /**< Boot loader hook */
100 uint16_t start_sys; /**< The load-low segment (obsolete) */
101 uint16_t kernel_version; /**< Points to kernel version string */
102 uint8_t type_of_loader; /**< Boot loader identifier */
103 #define LINUX_LOADER_ID_LILO 0x0
104 #define LINUX_LOADER_ID_LOADLIN 0x1
105 #define LINUX_LOADER_ID_BOOTSECT 0x2
106 #define LINUX_LOADER_ID_SYSLINUX 0x3
107 #define LINUX_LOADER_ID_ETHERBOOT 0x4
108 #define LINUX_LOADER_ID_ELILO 0x5
109 #define LINUX_LOADER_ID_GRUB 0x7
110 #define LINUX_LOADER_ID_UBOOT 0x8
111 #define LINUX_LOADER_ID_XEN 0x9
112 #define LINUX_LOADER_ID_GUJIN 0xa
113 #define LINUX_LOADER_ID_QEMU 0xb
114 uint8_t loadflags; /**< Boot protocol option flags */
115 uint16_t setup_move_size; /**< Move to high memory size */
116 uint32_t code32_start; /**< Boot loader hook */
117 uint32_t ramdisk_image; /**< initrd load address */
118 uint32_t ramdisk_size; /**< initrd size */
119 uint32_t bootsect_kludge; /**< obsolete */
120 uint16_t heap_end_ptr; /**< Free memory after setup end */
121 uint8_t ext_loader_ver; /**< boot loader's extension of the version number */
122 uint8_t ext_loader_type; /**< boot loader's extension of its type */
123 char *cmd_line_ptr; /**< Points to the kernel command line */
124 uint32_t initrd_addr_max; /**< Highest address for initrd */
125 #if 0
126 /* for the records only. These members are defined in
127 * more recent Linux kernels
129 uint32_t kernel_alignment; /**< Alignment unit required by the kernel */
130 uint8_t relocatable_kernel; /** */
131 uint8_t min_alignment; /** */
132 uint32_t cmdline_size; /** */
133 uint32_t hardware_subarch; /** */
134 uint64_t hardware_subarch_data; /** */
135 uint32_t payload_offset; /** */
136 uint32_t payload_length; /** */
137 uint64_t setup_data; /** */
138 uint64_t pref_address; /** */
139 uint32_t init_size; /** */
140 #endif
141 } __attribute__ ((packed));
144 * Load an x86 Linux kernel bzImage and start it
145 * @param cmdtp FIXME
146 * @param argc parameter count
147 * @param argv list of parameter
149 * Loads an x86 bzImage, checks for its integrity, stores the two parts
150 * (setup = 'real mode code' and kernel = 'protected mode code') to their
151 * default locations, switches back to real mode and runs the setup code.
153 static int do_linux16(cmd_tbl_t *cmdtp, int argc, char *argv[])
155 struct linux_kernel_header *lh = NULL;
156 int rc;
157 unsigned setup_sects;
158 unsigned real_mode_size;
159 size_t image_size;
160 const char *cmdline = getenv("bootargs");
162 if (argc < 2) {
163 perror("linux16");
164 return 1;
167 lh = read_file(argv[1], &image_size);
168 if (lh == NULL) {
169 printf("Cannot read file '%s'\n", argv[1]);
170 return 1;
173 if (lh->boot_flag != 0xaa55) {
174 printf("File '%s' has invalid magic number\n", argv[1]);
175 rc = 1;
176 goto on_error;
179 if (lh->setup_sects > LINUX_MAX_SETUP_SECTS) {
180 printf("File '%s' contains too many setup sectors\n", argv[1]);
181 rc = 1;
182 goto on_error;
185 setup_sects = lh->setup_sects;
187 printf("Found a %d.%d image header\n", lh->version >> 8, lh->version & 0xFF);
189 if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200) {
190 /* kernel is recent enough */
192 if (!(lh->loadflags & LINUX_FLAG_BIG_KERNEL)) {
193 printf("Cannot load a classic zImage. Use a bzImage instead\n");
194 goto on_error;
196 lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; /* TODO */
198 if (lh->version >= 0x0201) {
199 lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;
200 lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP;
203 if (lh->version >= 0x0202)
204 lh->cmd_line_ptr = (void*)(LINUX_OLD_REAL_MODE_ADDR + LINUX_CL_OFFSET); /* FIXME */
205 else {
206 lh->cl_magic = LINUX_CL_MAGIC;
207 lh->cl_offset = LINUX_CL_OFFSET;
208 lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
210 } else {
211 printf("Kernel too old to handle\n");
212 rc = 1;
213 goto on_error;
216 if (strlen(cmdline) >= (LINUX_CL_END_OFFSET - LINUX_CL_OFFSET)) {
217 printf("Kernel command line exceeds the available space\n");
218 rc = 1;
219 goto on_error;
222 /* If SETUP_SECTS is not set, set it to the default. */
223 if (setup_sects == 0) {
224 printf("Fixing setup sector count\n");
225 setup_sects = LINUX_DEFAULT_SETUP_SECTS;
228 if (setup_sects >= 15) {
229 void *src = lh;
230 if (lh->kernel_version != 0)
231 printf("Kernel version: '%s'\n", src + lh->kernel_version + DISK_SECTOR_SIZE);
235 * Size of the real mode part to handle in a separate way
237 real_mode_size = (setup_sects << DISK_SECTOR_BITS) + DISK_SECTOR_SIZE;
240 * real mode space hole extended memory
241 * |---------------------------------------------->|----------->|------------------------------>
242 * 0 0xa0000 0x100000
243 * <-1-|----------2-----------><-3- |
244 * 0x7e00 0x90000
245 * <-4--|-5--> |---------6------------->
247 * 1) real mode stack
248 * 2) barebox code
249 * 3) flat mode stack
250 * 4) realmode stack when starting a Linux kernel
251 * 5) Kernel's real mode setup code
252 * 6) compressed kernel image
255 * Parts of the image we know:
256 * - real mode part
257 * - kernel payload
260 * NOTE: This part is dangerous, as it copies some image content to
261 * various locations in the main memory. This could overwrite important
262 * data of the running barebox (hopefully not)
264 /* copy the real mode part of the image to the 9th segment */
265 memcpy((void*)LINUX_OLD_REAL_MODE_ADDR, lh, LINUX_SETUP_MOVE_SIZE);
267 /* TODO add 'BOOT_IMAGE=<file>' and 'auto' if no user intervention was done (in front of all other params) */
268 /* copy also the command line into this area */
269 memcpy((void*)(LINUX_OLD_REAL_MODE_ADDR + LINUX_CL_OFFSET), cmdline, strlen(cmdline) + 1);
270 printf("Using kernel command line: '%s'\n", cmdline);
272 /* copy the compressed image part to its final address the setup code expects it
273 * Note: The protected mode part starts at offset (setup_sects + 1) * 512
275 memcpy((void*)LINUX_BZIMAGE_ADDR, ((void*)lh) + real_mode_size, image_size - real_mode_size);
278 * switch back to real mode now and start the real mode part of the
279 * image at address "(LINUX_OLD_REAL_MODE_ADDR >> 4) + 0x20:0x0000"
280 * which means "0x9020:0x000" -> 0x90200
282 bios_start_linux(LINUX_OLD_REAL_MODE_SEGMT); /* does not return */
284 on_error:
285 if (lh != NULL)
286 free(lh);
288 return rc;
291 static const __maybe_unused char cmd_linux16_help[] =
292 "Usage: linux16 <file>\n"
293 "Boot a linux kernel via real mode code\n";
296 BAREBOX_CMD_START(linux16)
297 .cmd = do_linux16,
298 .usage = "boot linux kernel",
299 BAREBOX_CMD_HELP(cmd_linux16_help)
300 BAREBOX_CMD_END
303 * @file
304 * @brief Boot support for Linux on x86
308 * @page linux16_command linux16: Boot a bzImage kernel on x86
310 * Usage is: linux16 \<file\>
312 * Boot a linux kernel via real mode code. Only kernel images in the
313 * @p bzImage format are supported.
317 * @page x86_boot_preparation Linux Preparation on x86
319 * Due to some real mode constraints, starting Linux is somehow tricky.
320 * Currently only @p bzImages are supported, because @p zImages would
321 * interfere with the @a barebox runtime.
322 * Also older load header versions than 2.00 aren't supported.
324 * The memory layout immediately before starting the Linux kernel:
326 @verbatim
327 real mode space hole extended memory
328 |---------------------------------------------->|----------->|------------------------------>
329 0 0x7e00 0x90000 0xa0000 0x100000
330 <-1-|----------2-----------><-3- |
331 <-4--|-5--> |---------6------------->
332 @endverbatim
334 * @li 1 = @a barebox's real mode stack
335 * @li 2 = @a barebox's code
336 * @li 3 = @a barebox's flat mode stack
337 * @li 4 = real mode stack, when starting the Linux kernel
338 * @li 5 = Kernel's real mode setup code
339 * @li 6 = compressed kernel image
341 * A more detailed memory layout for kernel's real mode setup code
343 @verbatim
345 0x90000 0x97fff 0x99000 0x990ff
346 ---|------------------------------------------|----------------|--------------------|
347 |<-------- max setup code size ----------->|<--heap/stack-->|<-- command line -->|
349 @endverbatim
351 * The regular entry point into the setup code is 0x90200 (2nd sector)
353 * To start the kernel, it's own setup code will be called. To do so, it
354 * must be called in real mode. So, @a barebox switches back to real mode
355 * a last time and does a jump to the setup code entry point. Now its up to
356 * the setup code to deflate the kernel, switching to its own protected mode
357 * setup and starting the kernel itself.
359 * @note This scenario only works, if a BIOS is still present. In this case
360 * there is no need for @a barebox to forward any system related information
361 * to the kernel. Everything is detected by kernel's setup code.