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