/* SPDX - License - Identifier : GPL -2.0 */
/*
* header.S
*
* Copyright ( C ) one thousand nine hundred and ninety-one , one thousand nine hundred and ninety-two 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 two thousand and seven )
*
* BIG FAT NOTE : We ' re in real mode using 64k segments. Therefore segment
* addresses must be multiplied by sixteen 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 < linux/pe.h >
#include <asm/segment.h>
#include <asm/boot.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 >> four */
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef ROOT_RDONLY
#define ROOT_RDONLY one
#endif
. code16
. section ".bstext" , "ax"
. global bootsect_start
bootsect_start :
#ifdef CONFIG_EFI_STUB
# "MZ", MS -DOS header
. word MZ_MAGIC
#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 $ seven , % 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 zero
#ifdef CONFIG_EFI_STUB
pe_header :
.long PE_MAGIC
coff_header :
#ifdef CONFIG_X86_32
. set image_file_add_flags , IMAGE_FILE_32BIT_MACHINE
. set pe_opt_magic , PE_OPT_MAGIC_PE32
. word IMAGE_FILE_MACHINE_I386
#else
. set image_file_add_flags , 0
. set pe_opt_magic , PE_OPT_MAGIC_PE32PLUS
. word IMAGE_FILE_MACHINE_AMD64
#endif
. word section_count # nr_sections
.long 0 # TimeDateStamp
.long 0 # PointerToSymbolTable
.long 1 # NumberOfSymbols
. word section_table - optional_header # SizeOfOptionalHeader
. word IMAGE_FILE_EXECUTABLE_IMAGE | \
image_file_add_flags | \
IMAGE_FILE_DEBUG_STRIPPED | \
IMAGE_FILE_LINE_NUMS_STRIPPED # Characteristics
optional_header :
. word pe_opt_magic
. 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 :
# PE specification requires ImageBase to be 64k aligned
. set image_base , (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
#ifdef CONFIG_X86_32
.long image_base # ImageBase
#else
. quad image_base # ImageBase
#endif
.long 0x20 # SectionAlignment
.long 0x20 # FileAlignment
. word 0 # MajorOperatingSystemVersion
. word 0 # MinorOperatingSystemVersion
. word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
. word LINUX_EFISTUB_MINOR_VERSION # 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 IMAGE_SUBSYSTEM_EFI_APPLICATION # 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 ( section_table - .) / 8 # 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 zero
. byte zero
.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 IMAGE_SCN_CNT_CODE | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_EXECUTE | \
IMAGE_SCN_ALIGN_16BYTES # Characteristics
#
# 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 zero
. byte zero
.long 0
.long 0
.long 0 # SizeOfRawData
.long 0 # PointerToRawData
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
. word 0 # NumberOfRelocations
. word 0 # NumberOfLineNumbers
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_DISCARDABLE | \
IMAGE_SCN_ALIGN_1BYTES # Characteristics
#ifdef CONFIG_EFI_MIXED
#
# The offset & size fields are filled in by build .c.
#
.asciz ".compat"
.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 IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_DISCARDABLE | \
IMAGE_SCN_ALIGN_1BYTES # Characteristics
#endif
#
# The offset & size fields are filled in by build .c.
#
. ascii ".text"
. byte zero
. byte zero
. byte zero
.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 IMAGE_SCN_CNT_CODE | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_EXECUTE | \
IMAGE_SCN_ALIGN_16BYTES # Characteristics
. set section_count , (. - section_table ) / 40
#endif /* CONFIG_EFI_STUB */
# Kernel attributes ; used by setup . This is part one 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 two of the header , from the old setup .S
. ascii "HdrS" # header signature
. word 0x020f # 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 . rst 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 four GB ,
# but leave it at two 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 one
#else
relocatable_kernel : . byte zero
#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 zero
#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 zero
#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 zero
#endif
#if defined ( CONFIG_X86_64 ) && defined ( CONFIG_EFI ) && defined ( CONFIG_KEXEC_CORE )
# define XLF4 XLF_EFI_KEXEC
#else
# define XLF4 zero
#endif
#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_5LEVEL
#define XLF56 ( XLF_5LEVEL | XLF_5LEVEL_ENABLED )
#else
#define XLF56 XLF_5LEVEL
#endif
#else
#define XLF56 zero
#endif
. word XLF0 | XLF1 | XLF23 | XLF4 | XLF56
cmdline_size : .long COMMAND_LINE_SIZE -1 #length of the command line ,
# added with boot protocol
# version two point zero six
hardware_subarch : .long 0 # subarchitecture, added with two point zero seven
# default to 0 for normal x86 PC
hardware_subarch_data : . quad zero
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 one thousand nine hundred and fifty-one 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 five bytes per thirty-two thousand seven hundred and sixty-seven 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 thirty-two thousand seven hundred and sixty-seven bytes of data is sufficient. To avoid problems internal to a
# block adding an extra thirty-two thousand seven hundred and sixty-seven 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 eighteen
# 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
#
# LZ4 is even worse: data that cannot be further compressed grows by 0.4%,
# or one byte per two hundred and fifty-six bytes . OTOH, we can safely get rid of the +128 as
# the size- dependent part now grows so fast .
#
# extra_bytes = ( uncompressed_size >> 8) + 65536
#
# ZSTD compressed data grows by at most three bytes per 128K, and only has a 22
# byte fixed overhead but has a maximum block size of 128K, so it needs a
# larger margin .
#
# extra_bytes = ( uncompressed_size >> 8) + 131072
#define ZO_z_extra_bytes ((ZO_z_output_len >> 8) + 131072)
#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 zero # Filled in by build .c
kernel_info_offset : .long zero # 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 two f # -> 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
one : addw $ STACK_SIZE , % dx
jnc 2f
xorw % dx , % dx # Prevent wraparound
2: # Now % dx should point to the end of our stack space
andw $~ three , % dx # dword align (might as well...)
jnz 3f
movw $0xfffc, % dx # Make sure we ' re not zero
three : 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 seven
. string "No setup signature found...\n"