xref: /OK3568_Linux_fs/u-boot/doc/uImage.FIT/x86-fit-boot.txt (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593SmuzhiyunBooting Linux on x86 with FIT
2*4882a593Smuzhiyun=============================
3*4882a593Smuzhiyun
4*4882a593SmuzhiyunBackground
5*4882a593Smuzhiyun----------
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun(corrections to the text below are welcome)
8*4882a593Smuzhiyun
9*4882a593SmuzhiyunGenerally Linux x86 uses its own very complex booting method. There is a setup
10*4882a593Smuzhiyunbinary which contains all sorts of parameters and a compressed self-extracting
11*4882a593Smuzhiyunbinary for the kernel itself, often with a small built-in serial driver to
12*4882a593Smuzhiyundisplay decompression progress.
13*4882a593Smuzhiyun
14*4882a593SmuzhiyunThe x86 CPU has various processor modes. I am no expert on these, but my
15*4882a593Smuzhiyununderstanding is that an x86 CPU (even a really new one) starts up in a 16-bit
16*4882a593Smuzhiyun'real' mode where only 1MB of memory is visible, moves to 32-bit 'protected'
17*4882a593Smuzhiyunmode where 4GB is visible (or more with special memory access techniques) and
18*4882a593Smuzhiyunthen to 64-bit 'long' mode if 64-bit execution is required.
19*4882a593Smuzhiyun
20*4882a593SmuzhiyunPartly the self-extracting nature of Linux was introduced to cope with boot
21*4882a593Smuzhiyunloaders that were barely capable of loading anything. Even changing to 32-bit
22*4882a593Smuzhiyunmode was something of a challenge, so putting this logic in the kernel seemed
23*4882a593Smuzhiyunto make sense.
24*4882a593Smuzhiyun
25*4882a593SmuzhiyunBit by bit more and more logic has been added to this post-boot pre-Linux
26*4882a593Smuzhiyunwrapper:
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun- Changing to 32-bit mode
29*4882a593Smuzhiyun- Decompression
30*4882a593Smuzhiyun- Serial output (with drivers for various chips)
31*4882a593Smuzhiyun- Load address randomisation
32*4882a593Smuzhiyun- Elf loader complete with relocation (for the above)
33*4882a593Smuzhiyun- Random number generator via 3 methods (again for the above)
34*4882a593Smuzhiyun- Some sort of EFI mini-loader (1000+ glorious lines of code)
35*4882a593Smuzhiyun- Locating and tacking on a device tree and ramdisk
36*4882a593Smuzhiyun
37*4882a593SmuzhiyunTo my mind, if you sit back and look at things from first principles, this
38*4882a593Smuzhiyundoesn't make a huge amount of sense. Any boot loader worth its salts already
39*4882a593Smuzhiyunhas most of the above features and more besides. The boot loader already knows
40*4882a593Smuzhiyunthe layout of memory, has a serial driver, can decompress things, includes an
41*4882a593SmuzhiyunELF loader and supports device tree and ramdisks. The decision to duplicate
42*4882a593Smuzhiyunall these features in a Linux wrapper caters for the lowest common
43*4882a593Smuzhiyundenominator: a boot loader which consists of a BIOS call to load something off
44*4882a593Smuzhiyundisk, followed by a jmp instruction.
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun(Aside: On ARM systems, we worry that the boot loader won't know where to load
47*4882a593Smuzhiyunthe kernel. It might be easier to just provide that information in the image,
48*4882a593Smuzhiyunor in the boot loader rather than adding a self-relocator to put it in the
49*4882a593Smuzhiyunright place. Or just use ELF?
50*4882a593Smuzhiyun
51*4882a593SmuzhiyunAs a result, the x86 kernel boot process is needlessly complex. The file
52*4882a593Smuzhiyunformat is also complex, and obfuscates the contents to a degree that it is
53*4882a593Smuzhiyunquite a challenge to extract anything from it. This bzImage format has become
54*4882a593Smuzhiyunso prevalent that is actually isn't possible to produce the 'raw' kernel build
55*4882a593Smuzhiyunoutputs with the standard Makefile (as it is on ARM for example, at least at
56*4882a593Smuzhiyunthe time of writing).
57*4882a593Smuzhiyun
58*4882a593SmuzhiyunThis document describes an alternative boot process which uses simple raw
59*4882a593Smuzhiyunimages which are loaded into the right place by the boot loader and then
60*4882a593Smuzhiyunexecuted.
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun
63*4882a593SmuzhiyunBuild the kernel
64*4882a593Smuzhiyun----------------
65*4882a593Smuzhiyun
66*4882a593SmuzhiyunNote: these instructions assume a 32-bit kernel. U-Boot also supports directly
67*4882a593Smuzhiyunbooting a 64-bit kernel by jumping into 64-bit mode first (see below).
68*4882a593Smuzhiyun
69*4882a593SmuzhiyunYou can build the kernel as normal with 'make'. This will create a file called
70*4882a593Smuzhiyun'vmlinux'. This is a standard ELF file and you can look at it if you like:
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun$ objdump -h vmlinux
73*4882a593Smuzhiyun
74*4882a593Smuzhiyunvmlinux:     file format elf32-i386
75*4882a593Smuzhiyun
76*4882a593SmuzhiyunSections:
77*4882a593SmuzhiyunIdx Name          Size      VMA       LMA       File off  Algn
78*4882a593Smuzhiyun  0 .text         00416850  81000000  01000000  00001000  2**5
79*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
80*4882a593Smuzhiyun  1 .notes        00000024  81416850  01416850  00417850  2**2
81*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, READONLY, CODE
82*4882a593Smuzhiyun  2 __ex_table    00000c50  81416880  01416880  00417880  2**3
83*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
84*4882a593Smuzhiyun  3 .rodata       00154b9e  81418000  01418000  00419000  2**5
85*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
86*4882a593Smuzhiyun  4 __bug_table   0000597c  8156cba0  0156cba0  0056dba0  2**0
87*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
88*4882a593Smuzhiyun  5 .pci_fixup    00001b80  8157251c  0157251c  0057351c  2**2
89*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
90*4882a593Smuzhiyun  6 .tracedata    00000024  8157409c  0157409c  0057509c  2**0
91*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
92*4882a593Smuzhiyun  7 __ksymtab     00007ec0  815740c0  015740c0  005750c0  2**2
93*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
94*4882a593Smuzhiyun  8 __ksymtab_gpl 00004a28  8157bf80  0157bf80  0057cf80  2**2
95*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
96*4882a593Smuzhiyun  9 __ksymtab_strings 0001d6fc  815809a8  015809a8  005819a8  2**0
97*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, READONLY, DATA
98*4882a593Smuzhiyun 10 __init_rodata 00001c3c  8159e0a4  0159e0a4  0059f0a4  2**2
99*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
100*4882a593Smuzhiyun 11 __param       00000ff0  8159fce0  0159fce0  005a0ce0  2**2
101*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
102*4882a593Smuzhiyun 12 __modver      00000330  815a0cd0  015a0cd0  005a1cd0  2**2
103*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
104*4882a593Smuzhiyun 13 .data         00063000  815a1000  015a1000  005a2000  2**12
105*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, DATA
106*4882a593Smuzhiyun 14 .init.text    0002f104  81604000  01604000  00605000  2**2
107*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
108*4882a593Smuzhiyun 15 .init.data    00040cdc  81634000  01634000  00635000  2**12
109*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, DATA
110*4882a593Smuzhiyun 16 .x86_cpu_dev.init 0000001c  81674cdc  01674cdc  00675cdc  2**2
111*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
112*4882a593Smuzhiyun 17 .altinstructions 0000267c  81674cf8  01674cf8  00675cf8  2**0
113*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
114*4882a593Smuzhiyun 18 .altinstr_replacement 00000942  81677374  01677374  00678374  2**0
115*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, READONLY, CODE
116*4882a593Smuzhiyun 19 .iommu_table  00000014  81677cb8  01677cb8  00678cb8  2**2
117*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
118*4882a593Smuzhiyun 20 .apicdrivers  00000004  81677cd0  01677cd0  00678cd0  2**2
119*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, DATA
120*4882a593Smuzhiyun 21 .exit.text    00001a80  81677cd8  01677cd8  00678cd8  2**0
121*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
122*4882a593Smuzhiyun 22 .data..percpu 00007880  8167a000  0167a000  0067b000  2**12
123*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, DATA
124*4882a593Smuzhiyun 23 .smp_locks    00003000  81682000  01682000  00683000  2**2
125*4882a593Smuzhiyun                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
126*4882a593Smuzhiyun 24 .bss          000a1000  81685000  01685000  00686000  2**12
127*4882a593Smuzhiyun                  ALLOC
128*4882a593Smuzhiyun 25 .brk          00424000  81726000  01726000  00686000  2**0
129*4882a593Smuzhiyun                  ALLOC
130*4882a593Smuzhiyun 26 .comment      00000049  00000000  00000000  00686000  2**0
131*4882a593Smuzhiyun                  CONTENTS, READONLY
132*4882a593Smuzhiyun 27 .GCC.command.line 0003e055  00000000  00000000  00686049  2**0
133*4882a593Smuzhiyun                  CONTENTS, READONLY
134*4882a593Smuzhiyun 28 .debug_aranges 0000f4c8  00000000  00000000  006c40a0  2**3
135*4882a593Smuzhiyun                  CONTENTS, RELOC, READONLY, DEBUGGING
136*4882a593Smuzhiyun 29 .debug_info   0440b0df  00000000  00000000  006d3568  2**0
137*4882a593Smuzhiyun                  CONTENTS, RELOC, READONLY, DEBUGGING
138*4882a593Smuzhiyun 30 .debug_abbrev 0022a83b  00000000  00000000  04ade647  2**0
139*4882a593Smuzhiyun                  CONTENTS, READONLY, DEBUGGING
140*4882a593Smuzhiyun 31 .debug_line   004ead0d  00000000  00000000  04d08e82  2**0
141*4882a593Smuzhiyun                  CONTENTS, RELOC, READONLY, DEBUGGING
142*4882a593Smuzhiyun 32 .debug_frame  0010a960  00000000  00000000  051f3b90  2**2
143*4882a593Smuzhiyun                  CONTENTS, RELOC, READONLY, DEBUGGING
144*4882a593Smuzhiyun 33 .debug_str    001b442d  00000000  00000000  052fe4f0  2**0
145*4882a593Smuzhiyun                  CONTENTS, READONLY, DEBUGGING
146*4882a593Smuzhiyun 34 .debug_loc    007c7fa9  00000000  00000000  054b291d  2**0
147*4882a593Smuzhiyun                  CONTENTS, RELOC, READONLY, DEBUGGING
148*4882a593Smuzhiyun 35 .debug_ranges 00098828  00000000  00000000  05c7a8c8  2**3
149*4882a593Smuzhiyun                  CONTENTS, RELOC, READONLY, DEBUGGING
150*4882a593Smuzhiyun
151*4882a593SmuzhiyunThere is also the setup binary mentioned earlier. This is at
152*4882a593Smuzhiyunarch/x86/boot/setup.bin and is about 12KB in size. It includes the command
153*4882a593Smuzhiyunline and various settings need by the kernel. Arguably the boot loader should
154*4882a593Smuzhiyunprovide all of this also, but setting it up is some complex that the kernel
155*4882a593Smuzhiyunhelps by providing a head start.
156*4882a593Smuzhiyun
157*4882a593SmuzhiyunAs you can see the code loads to address 0x01000000 and everything else
158*4882a593Smuzhiyunfollows after that. We could load this image using the 'bootelf' command but
159*4882a593Smuzhiyunwe would still need to provide the setup binary. This is not supported by
160*4882a593SmuzhiyunU-Boot although I suppose you could mostly script it. This would permit the
161*4882a593Smuzhiyunuse of a relocatable kernel.
162*4882a593Smuzhiyun
163*4882a593SmuzhiyunAll we need to boot is the vmlinux file and the setup.bin file.
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun
166*4882a593SmuzhiyunCreate a FIT
167*4882a593Smuzhiyun------------
168*4882a593Smuzhiyun
169*4882a593SmuzhiyunTo create a FIT you will need a source file describing what should go in the
170*4882a593SmuzhiyunFIT. See kernel.its for an example for x86 and also instructions on setting
171*4882a593Smuzhiyunthe 'arch' value for booting 64-bit kernels if desired. Put this into a file
172*4882a593Smuzhiyuncalled image.its.
173*4882a593Smuzhiyun
174*4882a593SmuzhiyunNote that setup is loaded to the special address of 0x90000 (a special address
175*4882a593Smuzhiyunyou just have to know) and the kernel is loaded to 0x01000000 (the address you
176*4882a593Smuzhiyunsaw above). This means that you will need to load your FIT to a different
177*4882a593Smuzhiyunaddress so that U-Boot doesn't overwrite it when decompressing. Something like
178*4882a593Smuzhiyun0x02000000 will do so you can set CONFIG_SYS_LOAD_ADDR to that.
179*4882a593Smuzhiyun
180*4882a593SmuzhiyunIn that example the kernel is compressed with lzo. Also we need to provide a
181*4882a593Smuzhiyunflat binary, not an ELF. So the steps needed to set things are are:
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun   # Create a flat binary
184*4882a593Smuzhiyun   objcopy -O binary vmlinux vmlinux.bin
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun   # Compress it into LZO format
187*4882a593Smuzhiyun   lzop vmlinux.bin
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun   # Build a FIT image
190*4882a593Smuzhiyun   mkimage -f image.its image.fit
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun(be careful to run the mkimage from your U-Boot tools directory since it
193*4882a593Smuzhiyunwill have x86_setup support.)
194*4882a593Smuzhiyun
195*4882a593SmuzhiyunYou can take a look at the resulting fit file if you like:
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun$ dumpimage -l image.fit
198*4882a593SmuzhiyunFIT description: Simple image with single Linux kernel on x86
199*4882a593SmuzhiyunCreated:         Tue Oct  7 10:57:24 2014
200*4882a593Smuzhiyun Image 0 (kernel@1)
201*4882a593Smuzhiyun  Description:  Vanilla Linux kernel
202*4882a593Smuzhiyun  Created:      Tue Oct  7 10:57:24 2014
203*4882a593Smuzhiyun  Type:         Kernel Image
204*4882a593Smuzhiyun  Compression:  lzo compressed
205*4882a593Smuzhiyun  Data Size:    4591767 Bytes = 4484.15 kB = 4.38 MB
206*4882a593Smuzhiyun  Architecture: Intel x86
207*4882a593Smuzhiyun  OS:           Linux
208*4882a593Smuzhiyun  Load Address: 0x01000000
209*4882a593Smuzhiyun  Entry Point:  0x00000000
210*4882a593Smuzhiyun  Hash algo:    sha1
211*4882a593Smuzhiyun  Hash value:   446b5163ebfe0fb6ee20cbb7a8501b263cd92392
212*4882a593Smuzhiyun Image 1 (setup@1)
213*4882a593Smuzhiyun  Description:  Linux setup.bin
214*4882a593Smuzhiyun  Created:      Tue Oct  7 10:57:24 2014
215*4882a593Smuzhiyun  Type:         x86 setup.bin
216*4882a593Smuzhiyun  Compression:  uncompressed
217*4882a593Smuzhiyun  Data Size:    12912 Bytes = 12.61 kB = 0.01 MB
218*4882a593Smuzhiyun  Hash algo:    sha1
219*4882a593Smuzhiyun  Hash value:   a1f2099cf47ff9816236cd534c77af86e713faad
220*4882a593Smuzhiyun Default Configuration: 'config@1'
221*4882a593Smuzhiyun Configuration 0 (config@1)
222*4882a593Smuzhiyun  Description:  Boot Linux kernel
223*4882a593Smuzhiyun  Kernel:       kernel@1
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun
226*4882a593SmuzhiyunBooting the FIT
227*4882a593Smuzhiyun---------------
228*4882a593Smuzhiyun
229*4882a593SmuzhiyunTo make it boot you need to load it and then use 'bootm' to boot it. A
230*4882a593Smuzhiyunsuitable script to do this from a network server is:
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun   bootp
233*4882a593Smuzhiyun   tftp image.fit
234*4882a593Smuzhiyun   bootm
235*4882a593Smuzhiyun
236*4882a593SmuzhiyunThis will load the image from the network and boot it. The command line (from
237*4882a593Smuzhiyunthe 'bootargs' environment variable) will be passed to the kernel.
238*4882a593Smuzhiyun
239*4882a593SmuzhiyunIf you want a ramdisk you can add it as normal with FIT. If you want a device
240*4882a593Smuzhiyuntree then x86 doesn't normally use those - it has ACPI instead.
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun
243*4882a593SmuzhiyunWhy Bother?
244*4882a593Smuzhiyun-----------
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun1. It demystifies the process of booting an x86 kernel
247*4882a593Smuzhiyun2. It allows use of the standard U-Boot boot file format
248*4882a593Smuzhiyun3. It allows U-Boot to perform decompression - problems will provide an error
249*4882a593Smuzhiyunmessage and you are still in the boot loader. It is possible to investigate.
250*4882a593Smuzhiyun4. It avoids all the pre-loader code in the kernel which is quite complex to
251*4882a593Smuzhiyunfollow
252*4882a593Smuzhiyun5. You can use verified/secure boot and other features which haven't yet been
253*4882a593Smuzhiyunadded to the pre-Linux
254*4882a593Smuzhiyun6. It makes x86 more like other architectures in the way it boots a kernel.
255*4882a593SmuzhiyunYou can potentially use the same file format for the kernel, and the same
256*4882a593Smuzhiyunprocedure for building and packaging it.
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun
259*4882a593SmuzhiyunReferences
260*4882a593Smuzhiyun----------
261*4882a593Smuzhiyun
262*4882a593SmuzhiyunIn the Linux kernel, Documentation/x86/boot.txt defines the boot protocol for
263*4882a593Smuzhiyunthe kernel including the setup.bin format. This is handled in U-Boot in
264*4882a593Smuzhiyunarch/x86/lib/zimage.c and arch/x86/lib/bootm.c.
265*4882a593Smuzhiyun
266*4882a593SmuzhiyunVarious files in the same directory as this file describe the FIT format.
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun--
270*4882a593SmuzhiyunSimon Glass
271*4882a593Smuzhiyunsjg@chromium.org
272*4882a593Smuzhiyun7-Oct-2014
273