x86-fit-boot.txt 12 KB

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