123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- /*
- * header.S
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * Based on bootsect.S and setup.S
- * modified by more people than can be counted
- *
- * Rewritten as a common file by H. Peter Anvin (Apr 2007)
- *
- * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
- * addresses must be multiplied by 16 to obtain their respective linear
- * addresses. To avoid confusion, linear addresses are written using leading
- * hex while segment addresses are written as segment:offset.
- *
- */
- #include <asm/segment.h>
- #include <generated/utsrelease.h>
- #include <asm/boot.h>
- #include <asm/e820.h>
- #include <asm/page_types.h>
- #include <asm/setup.h>
- #include <asm/bootparam.h>
- #include "boot.h"
- #include "voffset.h"
- #include "zoffset.h"
- BOOTSEG = 0x07C0 /* original address of boot-sector */
- SYSSEG = 0x1000 /* historical load address >> 4 */
- #ifndef SVGA_MODE
- #define SVGA_MODE ASK_VGA
- #endif
- #ifndef ROOT_RDONLY
- #define ROOT_RDONLY 1
- #endif
- .code16
- .section ".bstext", "ax"
- .global bootsect_start
- bootsect_start:
- #ifdef CONFIG_EFI_STUB
- # "MZ", MS-DOS header
- .byte 0x4d
- .byte 0x5a
- #endif
- # Normalize the start address
- ljmp $BOOTSEG, $start2
- start2:
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- xorw %sp, %sp
- sti
- cld
- movw $bugger_off_msg, %si
- msg_loop:
- lodsb
- andb %al, %al
- jz bs_die
- movb $0xe, %ah
- movw $7, %bx
- int $0x10
- jmp msg_loop
- bs_die:
- # Allow the user to press a key, then reboot
- xorw %ax, %ax
- int $0x16
- int $0x19
- # int 0x19 should never return. In case it does anyway,
- # invoke the BIOS reset code...
- ljmp $0xf000,$0xfff0
- #ifdef CONFIG_EFI_STUB
- .org 0x3c
- #
- # Offset to the PE header.
- #
- .long pe_header
- #endif /* CONFIG_EFI_STUB */
- .section ".bsdata", "a"
- bugger_off_msg:
- .ascii "Use a boot loader.\r\n"
- .ascii "\n"
- .ascii "Remove disk and press any key to reboot...\r\n"
- .byte 0
- #ifdef CONFIG_EFI_STUB
- pe_header:
- .ascii "PE"
- .word 0
- coff_header:
- #ifdef CONFIG_X86_32
- .word 0x14c # i386
- #else
- .word 0x8664 # x86-64
- #endif
- .word 4 # nr_sections
- .long 0 # TimeDateStamp
- .long 0 # PointerToSymbolTable
- .long 1 # NumberOfSymbols
- .word section_table - optional_header # SizeOfOptionalHeader
- #ifdef CONFIG_X86_32
- .word 0x306 # Characteristics.
- # IMAGE_FILE_32BIT_MACHINE |
- # IMAGE_FILE_DEBUG_STRIPPED |
- # IMAGE_FILE_EXECUTABLE_IMAGE |
- # IMAGE_FILE_LINE_NUMS_STRIPPED
- #else
- .word 0x206 # Characteristics
- # IMAGE_FILE_DEBUG_STRIPPED |
- # IMAGE_FILE_EXECUTABLE_IMAGE |
- # IMAGE_FILE_LINE_NUMS_STRIPPED
- #endif
- optional_header:
- #ifdef CONFIG_X86_32
- .word 0x10b # PE32 format
- #else
- .word 0x20b # PE32+ format
- #endif
- .byte 0x02 # MajorLinkerVersion
- .byte 0x14 # MinorLinkerVersion
- # Filled in by build.c
- .long 0 # SizeOfCode
- .long 0 # SizeOfInitializedData
- .long 0 # SizeOfUninitializedData
- # Filled in by build.c
- .long 0x0000 # AddressOfEntryPoint
- .long 0x0200 # BaseOfCode
- #ifdef CONFIG_X86_32
- .long 0 # data
- #endif
- extra_header_fields:
- #ifdef CONFIG_X86_32
- .long 0 # ImageBase
- #else
- .quad 0 # ImageBase
- #endif
- .long 0x20 # SectionAlignment
- .long 0x20 # FileAlignment
- .word 0 # MajorOperatingSystemVersion
- .word 0 # MinorOperatingSystemVersion
- .word 0 # MajorImageVersion
- .word 0 # MinorImageVersion
- .word 0 # MajorSubsystemVersion
- .word 0 # MinorSubsystemVersion
- .long 0 # Win32VersionValue
- #
- # The size of the bzImage is written in tools/build.c
- #
- .long 0 # SizeOfImage
- .long 0x200 # SizeOfHeaders
- .long 0 # CheckSum
- .word 0xa # Subsystem (EFI application)
- .word 0 # DllCharacteristics
- #ifdef CONFIG_X86_32
- .long 0 # SizeOfStackReserve
- .long 0 # SizeOfStackCommit
- .long 0 # SizeOfHeapReserve
- .long 0 # SizeOfHeapCommit
- #else
- .quad 0 # SizeOfStackReserve
- .quad 0 # SizeOfStackCommit
- .quad 0 # SizeOfHeapReserve
- .quad 0 # SizeOfHeapCommit
- #endif
- .long 0 # LoaderFlags
- .long 0x6 # NumberOfRvaAndSizes
- .quad 0 # ExportTable
- .quad 0 # ImportTable
- .quad 0 # ResourceTable
- .quad 0 # ExceptionTable
- .quad 0 # CertificationTable
- .quad 0 # BaseRelocationTable
- # Section table
- section_table:
- #
- # The offset & size fields are filled in by build.c.
- #
- .ascii ".setup"
- .byte 0
- .byte 0
- .long 0
- .long 0x0 # startup_{32,64}
- .long 0 # Size of initialized data
- # on disk
- .long 0x0 # startup_{32,64}
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long 0x60500020 # Characteristics (section flags)
- #
- # The EFI application loader requires a relocation section
- # because EFI applications must be relocatable. The .reloc
- # offset & size fields are filled in by build.c.
- #
- .ascii ".reloc"
- .byte 0
- .byte 0
- .long 0
- .long 0
- .long 0 # SizeOfRawData
- .long 0 # PointerToRawData
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long 0x42100040 # Characteristics (section flags)
- #
- # The offset & size fields are filled in by build.c.
- #
- .ascii ".text"
- .byte 0
- .byte 0
- .byte 0
- .long 0
- .long 0x0 # startup_{32,64}
- .long 0 # Size of initialized data
- # on disk
- .long 0x0 # startup_{32,64}
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long 0x60500020 # Characteristics (section flags)
- #
- # The offset & size fields are filled in by build.c.
- #
- .ascii ".bss"
- .byte 0
- .byte 0
- .byte 0
- .byte 0
- .long 0
- .long 0x0
- .long 0 # Size of initialized data
- # on disk
- .long 0x0
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long 0xc8000080 # Characteristics (section flags)
- #endif /* CONFIG_EFI_STUB */
- # Kernel attributes; used by setup. This is part 1 of the
- # header, from the old boot sector.
- .section ".header", "a"
- .globl sentinel
- sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */
- .globl hdr
- hdr:
- setup_sects: .byte 0 /* Filled in by build.c */
- root_flags: .word ROOT_RDONLY
- syssize: .long 0 /* Filled in by build.c */
- ram_size: .word 0 /* Obsolete */
- vid_mode: .word SVGA_MODE
- root_dev: .word 0 /* Filled in by build.c */
- boot_flag: .word 0xAA55
- # offset 512, entry point
- .globl _start
- _start:
- # Explicitly enter this as bytes, or the assembler
- # tries to generate a 3-byte jump here, which causes
- # everything else to push off to the wrong offset.
- .byte 0xeb # short (2-byte) jump
- .byte start_of_setup-1f
- 1:
- # Part 2 of the header, from the old setup.S
- .ascii "HdrS" # header signature
- .word 0x020d # header version number (>= 0x0105)
- # or else old loadlin-1.5 will fail)
- .globl realmode_swtch
- realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
- start_sys_seg: .word SYSSEG # obsolete and meaningless, but just
- # in case something decided to "use" it
- .word kernel_version-512 # pointing to kernel version string
- # above section of header is compatible
- # with loadlin-1.5 (header v1.5). Don't
- # change it.
- type_of_loader: .byte 0 # 0 means ancient bootloader, newer
- # bootloaders know to change this.
- # See Documentation/x86/boot.txt for
- # assigned ids
- # flags, unused bits must be zero (RFU) bit within loadflags
- loadflags:
- .byte LOADED_HIGH # The kernel is to be loaded high
- setup_move_size: .word 0x8000 # size to move, when setup is not
- # loaded at 0x90000. We will move setup
- # to 0x90000 then just before jumping
- # into the kernel. However, only the
- # loader knows how much data behind
- # us also needs to be loaded.
- code32_start: # here loaders can put a different
- # start address for 32-bit code.
- .long 0x100000 # 0x100000 = default for big kernel
- ramdisk_image: .long 0 # address of loaded ramdisk image
- # Here the loader puts the 32-bit
- # address where it loaded the image.
- # This only will be read by the kernel.
- ramdisk_size: .long 0 # its size in bytes
- bootsect_kludge:
- .long 0 # obsolete
- heap_end_ptr: .word _end+STACK_SIZE-512
- # (Header version 0x0201 or later)
- # space from here (exclusive) down to
- # end of setup code can be used by setup
- # for local heap purposes.
- ext_loader_ver:
- .byte 0 # Extended boot loader version
- ext_loader_type:
- .byte 0 # Extended boot loader type
- cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
- # If nonzero, a 32-bit pointer
- # to the kernel command line.
- # The command line should be
- # located between the start of
- # setup and the end of low
- # memory (0xa0000), or it may
- # get overwritten before it
- # gets read. If this field is
- # used, there is no longer
- # anything magical about the
- # 0x90000 segment; the setup
- # can be located anywhere in
- # low memory 0x10000 or higher.
- initrd_addr_max: .long 0x7fffffff
- # (Header version 0x0203 or later)
- # The highest safe address for
- # the contents of an initrd
- # The current kernel allows up to 4 GB,
- # but leave it at 2 GB to avoid
- # possible bootloader bugs.
- kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment
- #required for protected mode
- #kernel
- #ifdef CONFIG_RELOCATABLE
- relocatable_kernel: .byte 1
- #else
- relocatable_kernel: .byte 0
- #endif
- min_alignment: .byte MIN_KERNEL_ALIGN_LG2 # minimum alignment
- xloadflags:
- #ifdef CONFIG_X86_64
- # define XLF0 XLF_KERNEL_64 /* 64-bit kernel */
- #else
- # define XLF0 0
- #endif
- #if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
- /* kernel/boot_param/ramdisk could be loaded above 4g */
- # define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
- #else
- # define XLF1 0
- #endif
- #ifdef CONFIG_EFI_STUB
- # ifdef CONFIG_EFI_MIXED
- # define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
- # else
- # ifdef CONFIG_X86_64
- # define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
- # else
- # define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
- # endif
- # endif
- #else
- # define XLF23 0
- #endif
- #if defined(CONFIG_X86_64) && defined(CONFIG_EFI) && defined(CONFIG_KEXEC_CORE)
- # define XLF4 XLF_EFI_KEXEC
- #else
- # define XLF4 0
- #endif
- .word XLF0 | XLF1 | XLF23 | XLF4
- cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
- #added with boot protocol
- #version 2.06
- hardware_subarch: .long 0 # subarchitecture, added with 2.07
- # default to 0 for normal x86 PC
- hardware_subarch_data: .quad 0
- payload_offset: .long ZO_input_data
- payload_length: .long ZO_z_input_len
- setup_data: .quad 0 # 64-bit physical pointer to
- # single linked list of
- # struct setup_data
- pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
- #
- # Getting to provably safe in-place decompression is hard. Worst case
- # behaviours need to be analyzed. Here let's take the decompression of
- # a gzip-compressed kernel as example, to illustrate it:
- #
- # The file layout of gzip compressed kernel is:
- #
- # magic[2]
- # method[1]
- # flags[1]
- # timestamp[4]
- # extraflags[1]
- # os[1]
- # compressed data blocks[N]
- # crc[4] orig_len[4]
- #
- # ... resulting in +18 bytes overhead of uncompressed data.
- #
- # (For more information, please refer to RFC 1951 and RFC 1952.)
- #
- # Files divided into blocks
- # 1 bit (last block flag)
- # 2 bits (block type)
- #
- # 1 block occurs every 32K -1 bytes or when there 50% compression
- # has been achieved. The smallest block type encoding is always used.
- #
- # stored:
- # 32 bits length in bytes.
- #
- # fixed:
- # magic fixed tree.
- # symbols.
- #
- # dynamic:
- # dynamic tree encoding.
- # symbols.
- #
- #
- # The buffer for decompression in place is the length of the uncompressed
- # data, plus a small amount extra to keep the algorithm safe. The
- # compressed data is placed at the end of the buffer. The output pointer
- # is placed at the start of the buffer and the input pointer is placed
- # where the compressed data starts. Problems will occur when the output
- # pointer overruns the input pointer.
- #
- # The output pointer can only overrun the input pointer if the input
- # pointer is moving faster than the output pointer. A condition only
- # triggered by data whose compressed form is larger than the uncompressed
- # form.
- #
- # The worst case at the block level is a growth of the compressed data
- # of 5 bytes per 32767 bytes.
- #
- # The worst case internal to a compressed block is very hard to figure.
- # The worst case can at least be bounded by having one bit that represents
- # 32764 bytes and then all of the rest of the bytes representing the very
- # very last byte.
- #
- # All of which is enough to compute an amount of extra data that is required
- # to be safe. To avoid problems at the block level allocating 5 extra bytes
- # per 32767 bytes of data is sufficient. To avoid problems internal to a
- # block adding an extra 32767 bytes (the worst case uncompressed block size)
- # is sufficient, to ensure that in the worst case the decompressed data for
- # block will stop the byte before the compressed data for a block begins.
- # To avoid problems with the compressed data's meta information an extra 18
- # bytes are needed. Leading to the formula:
- #
- # extra_bytes = (uncompressed_size >> 12) + 32768 + 18
- #
- # Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
- # Adding 32768 instead of 32767 just makes for round numbers.
- #
- # Above analysis is for decompressing gzip compressed kernel only. Up to
- # now 6 different decompressor are supported all together. And among them
- # xz stores data in chunks and has maximum chunk of 64K. Hence safety
- # margin should be updated to cover all decompressors so that we don't
- # need to deal with each of them separately. Please check
- # the description in lib/decompressor_xxx.c for specific information.
- #
- # extra_bytes = (uncompressed_size >> 12) + 65536 + 128
- #define ZO_z_extra_bytes ((ZO_z_output_len >> 12) + 65536 + 128)
- #if ZO_z_output_len > ZO_z_input_len
- # define ZO_z_extract_offset (ZO_z_output_len + ZO_z_extra_bytes - \
- ZO_z_input_len)
- #else
- # define ZO_z_extract_offset ZO_z_extra_bytes
- #endif
- /*
- * The extract_offset has to be bigger than ZO head section. Otherwise when
- * the head code is running to move ZO to the end of the buffer, it will
- * overwrite the head code itself.
- */
- #if (ZO__ehead - ZO_startup_32) > ZO_z_extract_offset
- # define ZO_z_min_extract_offset ((ZO__ehead - ZO_startup_32 + 4095) & ~4095)
- #else
- # define ZO_z_min_extract_offset ((ZO_z_extract_offset + 4095) & ~4095)
- #endif
- #define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_min_extract_offset)
- #define VO_INIT_SIZE (VO__end - VO__text)
- #if ZO_INIT_SIZE > VO_INIT_SIZE
- # define INIT_SIZE ZO_INIT_SIZE
- #else
- # define INIT_SIZE VO_INIT_SIZE
- #endif
- init_size: .long INIT_SIZE # kernel initialization size
- handover_offset: .long 0 # Filled in by build.c
- # End of setup header #####################################################
- .section ".entrytext", "ax"
- start_of_setup:
- # Force %es = %ds
- movw %ds, %ax
- movw %ax, %es
- cld
- # Apparently some ancient versions of LILO invoked the kernel with %ss != %ds,
- # which happened to work by accident for the old code. Recalculate the stack
- # pointer if %ss is invalid. Otherwise leave it alone, LOADLIN sets up the
- # stack behind its own code, so we can't blindly put it directly past the heap.
- movw %ss, %dx
- cmpw %ax, %dx # %ds == %ss?
- movw %sp, %dx
- je 2f # -> assume %sp is reasonably set
- # Invalid %ss, make up a new stack
- movw $_end, %dx
- testb $CAN_USE_HEAP, loadflags
- jz 1f
- movw heap_end_ptr, %dx
- 1: addw $STACK_SIZE, %dx
- jnc 2f
- xorw %dx, %dx # Prevent wraparound
- 2: # Now %dx should point to the end of our stack space
- andw $~3, %dx # dword align (might as well...)
- jnz 3f
- movw $0xfffc, %dx # Make sure we're not zero
- 3: movw %ax, %ss
- movzwl %dx, %esp # Clear upper half of %esp
- sti # Now we should have a working stack
- # We will have entered with %cs = %ds+0x20, normalize %cs so
- # it is on par with the other segments.
- pushw %ds
- pushw $6f
- lretw
- 6:
- # Check signature at end of setup
- cmpl $0x5a5aaa55, setup_sig
- jne setup_bad
- # Zero the bss
- movw $__bss_start, %di
- movw $_end+3, %cx
- xorl %eax, %eax
- subw %di, %cx
- shrw $2, %cx
- rep; stosl
- # Jump to C code (should not return)
- calll main
- # Setup corrupt somehow...
- setup_bad:
- movl $setup_corrupt, %eax
- calll puts
- # Fall through...
- .globl die
- .type die, @function
- die:
- hlt
- jmp die
- .size die, .-die
- .section ".initdata", "a"
- setup_corrupt:
- .byte 7
- .string "No setup signature found...\n"
|