Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  *  header.S
0004  *
0005  *  Copyright (C) 1991, 1992 Linus Torvalds
0006  *
0007  *  Based on bootsect.S and setup.S
0008  *  modified by more people than can be counted
0009  *
0010  *  Rewritten as a common file by H. Peter Anvin (Apr 2007)
0011  *
0012  * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
0013  * addresses must be multiplied by 16 to obtain their respective linear
0014  * addresses. To avoid confusion, linear addresses are written using leading
0015  * hex while segment addresses are written as segment:offset.
0016  *
0017  */
0018 #include <linux/pe.h>
0019 #include <asm/segment.h>
0020 #include <asm/boot.h>
0021 #include <asm/page_types.h>
0022 #include <asm/setup.h>
0023 #include <asm/bootparam.h>
0024 #include "boot.h"
0025 #include "voffset.h"
0026 #include "zoffset.h"
0027 
0028 BOOTSEG     = 0x07C0        /* original address of boot-sector */
0029 SYSSEG      = 0x1000        /* historical load address >> 4 */
0030 
0031 #ifndef SVGA_MODE
0032 #define SVGA_MODE ASK_VGA
0033 #endif
0034 
0035 #ifndef ROOT_RDONLY
0036 #define ROOT_RDONLY 1
0037 #endif
0038 
0039     .code16
0040     .section ".bstext", "ax"
0041 
0042     .global bootsect_start
0043 bootsect_start:
0044 #ifdef CONFIG_EFI_STUB
0045     # "MZ", MS-DOS header
0046     .word   MZ_MAGIC
0047 #endif
0048 
0049     # Normalize the start address
0050     ljmp    $BOOTSEG, $start2
0051 
0052 start2:
0053     movw    %cs, %ax
0054     movw    %ax, %ds
0055     movw    %ax, %es
0056     movw    %ax, %ss
0057     xorw    %sp, %sp
0058     sti
0059     cld
0060 
0061     movw    $bugger_off_msg, %si
0062 
0063 msg_loop:
0064     lodsb
0065     andb    %al, %al
0066     jz  bs_die
0067     movb    $0xe, %ah
0068     movw    $7, %bx
0069     int $0x10
0070     jmp msg_loop
0071 
0072 bs_die:
0073     # Allow the user to press a key, then reboot
0074     xorw    %ax, %ax
0075     int $0x16
0076     int $0x19
0077 
0078     # int 0x19 should never return.  In case it does anyway,
0079     # invoke the BIOS reset code...
0080     ljmp    $0xf000,$0xfff0
0081 
0082 #ifdef CONFIG_EFI_STUB
0083     .org    0x3c
0084     #
0085     # Offset to the PE header.
0086     #
0087     .long   pe_header
0088 #endif /* CONFIG_EFI_STUB */
0089 
0090     .section ".bsdata", "a"
0091 bugger_off_msg:
0092     .ascii  "Use a boot loader.\r\n"
0093     .ascii  "\n"
0094     .ascii  "Remove disk and press any key to reboot...\r\n"
0095     .byte   0
0096 
0097 #ifdef CONFIG_EFI_STUB
0098 pe_header:
0099     .long   PE_MAGIC
0100 
0101 coff_header:
0102 #ifdef CONFIG_X86_32
0103     .set    image_file_add_flags, IMAGE_FILE_32BIT_MACHINE
0104     .set    pe_opt_magic, PE_OPT_MAGIC_PE32
0105     .word   IMAGE_FILE_MACHINE_I386
0106 #else
0107     .set    image_file_add_flags, 0
0108     .set    pe_opt_magic, PE_OPT_MAGIC_PE32PLUS
0109     .word   IMAGE_FILE_MACHINE_AMD64
0110 #endif
0111     .word   section_count           # nr_sections
0112     .long   0               # TimeDateStamp
0113     .long   0               # PointerToSymbolTable
0114     .long   1               # NumberOfSymbols
0115     .word   section_table - optional_header # SizeOfOptionalHeader
0116     .word   IMAGE_FILE_EXECUTABLE_IMAGE | \
0117         image_file_add_flags        | \
0118         IMAGE_FILE_DEBUG_STRIPPED   | \
0119         IMAGE_FILE_LINE_NUMS_STRIPPED   # Characteristics
0120 
0121 optional_header:
0122     .word   pe_opt_magic
0123     .byte   0x02                # MajorLinkerVersion
0124     .byte   0x14                # MinorLinkerVersion
0125 
0126     # Filled in by build.c
0127     .long   0               # SizeOfCode
0128 
0129     .long   0               # SizeOfInitializedData
0130     .long   0               # SizeOfUninitializedData
0131 
0132     # Filled in by build.c
0133     .long   0x0000              # AddressOfEntryPoint
0134 
0135     .long   0x0200              # BaseOfCode
0136 #ifdef CONFIG_X86_32
0137     .long   0               # data
0138 #endif
0139 
0140 extra_header_fields:
0141     # PE specification requires ImageBase to be 64k aligned
0142     .set    image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
0143 #ifdef CONFIG_X86_32
0144     .long   image_base          # ImageBase
0145 #else
0146     .quad   image_base          # ImageBase
0147 #endif
0148     .long   0x20                # SectionAlignment
0149     .long   0x20                # FileAlignment
0150     .word   0               # MajorOperatingSystemVersion
0151     .word   0               # MinorOperatingSystemVersion
0152     .word   LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
0153     .word   LINUX_EFISTUB_MINOR_VERSION # MinorImageVersion
0154     .word   0               # MajorSubsystemVersion
0155     .word   0               # MinorSubsystemVersion
0156     .long   0               # Win32VersionValue
0157 
0158     #
0159     # The size of the bzImage is written in tools/build.c
0160     #
0161     .long   0               # SizeOfImage
0162 
0163     .long   0x200               # SizeOfHeaders
0164     .long   0               # CheckSum
0165     .word   IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
0166 #ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES
0167     .word   IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics
0168 #else
0169     .word   0               # DllCharacteristics
0170 #endif
0171 #ifdef CONFIG_X86_32
0172     .long   0               # SizeOfStackReserve
0173     .long   0               # SizeOfStackCommit
0174     .long   0               # SizeOfHeapReserve
0175     .long   0               # SizeOfHeapCommit
0176 #else
0177     .quad   0               # SizeOfStackReserve
0178     .quad   0               # SizeOfStackCommit
0179     .quad   0               # SizeOfHeapReserve
0180     .quad   0               # SizeOfHeapCommit
0181 #endif
0182     .long   0               # LoaderFlags
0183     .long   (section_table - .) / 8     # NumberOfRvaAndSizes
0184 
0185     .quad   0               # ExportTable
0186     .quad   0               # ImportTable
0187     .quad   0               # ResourceTable
0188     .quad   0               # ExceptionTable
0189     .quad   0               # CertificationTable
0190     .quad   0               # BaseRelocationTable
0191 
0192     # Section table
0193 section_table:
0194     #
0195     # The offset & size fields are filled in by build.c.
0196     #
0197     .ascii  ".setup"
0198     .byte   0
0199     .byte   0
0200     .long   0
0201     .long   0x0             # startup_{32,64}
0202     .long   0               # Size of initialized data
0203                         # on disk
0204     .long   0x0             # startup_{32,64}
0205     .long   0               # PointerToRelocations
0206     .long   0               # PointerToLineNumbers
0207     .word   0               # NumberOfRelocations
0208     .word   0               # NumberOfLineNumbers
0209     .long   IMAGE_SCN_CNT_CODE      | \
0210         IMAGE_SCN_MEM_READ      | \
0211         IMAGE_SCN_MEM_EXECUTE       | \
0212         IMAGE_SCN_ALIGN_16BYTES     # Characteristics
0213 
0214     #
0215     # The EFI application loader requires a relocation section
0216     # because EFI applications must be relocatable. The .reloc
0217     # offset & size fields are filled in by build.c.
0218     #
0219     .ascii  ".reloc"
0220     .byte   0
0221     .byte   0
0222     .long   0
0223     .long   0
0224     .long   0               # SizeOfRawData
0225     .long   0               # PointerToRawData
0226     .long   0               # PointerToRelocations
0227     .long   0               # PointerToLineNumbers
0228     .word   0               # NumberOfRelocations
0229     .word   0               # NumberOfLineNumbers
0230     .long   IMAGE_SCN_CNT_INITIALIZED_DATA  | \
0231         IMAGE_SCN_MEM_READ      | \
0232         IMAGE_SCN_MEM_DISCARDABLE   | \
0233         IMAGE_SCN_ALIGN_1BYTES      # Characteristics
0234 
0235 #ifdef CONFIG_EFI_MIXED
0236     #
0237     # The offset & size fields are filled in by build.c.
0238     #
0239     .asciz  ".compat"
0240     .long   0
0241     .long   0x0
0242     .long   0               # Size of initialized data
0243                         # on disk
0244     .long   0x0
0245     .long   0               # PointerToRelocations
0246     .long   0               # PointerToLineNumbers
0247     .word   0               # NumberOfRelocations
0248     .word   0               # NumberOfLineNumbers
0249     .long   IMAGE_SCN_CNT_INITIALIZED_DATA  | \
0250         IMAGE_SCN_MEM_READ      | \
0251         IMAGE_SCN_MEM_DISCARDABLE   | \
0252         IMAGE_SCN_ALIGN_1BYTES      # Characteristics
0253 #endif
0254 
0255     #
0256     # The offset & size fields are filled in by build.c.
0257     #
0258     .ascii  ".text"
0259     .byte   0
0260     .byte   0
0261     .byte   0
0262     .long   0
0263     .long   0x0             # startup_{32,64}
0264     .long   0               # Size of initialized data
0265                         # on disk
0266     .long   0x0             # startup_{32,64}
0267     .long   0               # PointerToRelocations
0268     .long   0               # PointerToLineNumbers
0269     .word   0               # NumberOfRelocations
0270     .word   0               # NumberOfLineNumbers
0271     .long   IMAGE_SCN_CNT_CODE      | \
0272         IMAGE_SCN_MEM_READ      | \
0273         IMAGE_SCN_MEM_EXECUTE       | \
0274         IMAGE_SCN_ALIGN_16BYTES     # Characteristics
0275 
0276     .set    section_count, (. - section_table) / 40
0277 #endif /* CONFIG_EFI_STUB */
0278 
0279     # Kernel attributes; used by setup.  This is part 1 of the
0280     # header, from the old boot sector.
0281 
0282     .section ".header", "a"
0283     .globl  sentinel
0284 sentinel:   .byte 0xff, 0xff        /* Used to detect broken loaders */
0285 
0286     .globl  hdr
0287 hdr:
0288 setup_sects:    .byte 0         /* Filled in by build.c */
0289 root_flags: .word ROOT_RDONLY
0290 syssize:    .long 0         /* Filled in by build.c */
0291 ram_size:   .word 0         /* Obsolete */
0292 vid_mode:   .word SVGA_MODE
0293 root_dev:   .word 0         /* Filled in by build.c */
0294 boot_flag:  .word 0xAA55
0295 
0296     # offset 512, entry point
0297 
0298     .globl  _start
0299 _start:
0300         # Explicitly enter this as bytes, or the assembler
0301         # tries to generate a 3-byte jump here, which causes
0302         # everything else to push off to the wrong offset.
0303         .byte   0xeb        # short (2-byte) jump
0304         .byte   start_of_setup-1f
0305 1:
0306 
0307     # Part 2 of the header, from the old setup.S
0308 
0309         .ascii  "HdrS"      # header signature
0310         .word   0x020f      # header version number (>= 0x0105)
0311                     # or else old loadlin-1.5 will fail)
0312         .globl realmode_swtch
0313 realmode_swtch: .word   0, 0        # default_switch, SETUPSEG
0314 start_sys_seg:  .word   SYSSEG      # obsolete and meaningless, but just
0315                     # in case something decided to "use" it
0316         .word   kernel_version-512 # pointing to kernel version string
0317                     # above section of header is compatible
0318                     # with loadlin-1.5 (header v1.5). Don't
0319                     # change it.
0320 
0321 type_of_loader: .byte   0       # 0 means ancient bootloader, newer
0322                     # bootloaders know to change this.
0323                     # See Documentation/x86/boot.rst for
0324                     # assigned ids
0325 
0326 # flags, unused bits must be zero (RFU) bit within loadflags
0327 loadflags:
0328         .byte   LOADED_HIGH # The kernel is to be loaded high
0329 
0330 setup_move_size: .word  0x8000      # size to move, when setup is not
0331                     # loaded at 0x90000. We will move setup
0332                     # to 0x90000 then just before jumping
0333                     # into the kernel. However, only the
0334                     # loader knows how much data behind
0335                     # us also needs to be loaded.
0336 
0337 code32_start:               # here loaders can put a different
0338                     # start address for 32-bit code.
0339         .long   0x100000    # 0x100000 = default for big kernel
0340 
0341 ramdisk_image:  .long   0       # address of loaded ramdisk image
0342                     # Here the loader puts the 32-bit
0343                     # address where it loaded the image.
0344                     # This only will be read by the kernel.
0345 
0346 ramdisk_size:   .long   0       # its size in bytes
0347 
0348 bootsect_kludge:
0349         .long   0       # obsolete
0350 
0351 heap_end_ptr:   .word   _end+STACK_SIZE-512
0352                     # (Header version 0x0201 or later)
0353                     # space from here (exclusive) down to
0354                     # end of setup code can be used by setup
0355                     # for local heap purposes.
0356 
0357 ext_loader_ver:
0358         .byte   0       # Extended boot loader version
0359 ext_loader_type:
0360         .byte   0       # Extended boot loader type
0361 
0362 cmd_line_ptr:   .long   0       # (Header version 0x0202 or later)
0363                     # If nonzero, a 32-bit pointer
0364                     # to the kernel command line.
0365                     # The command line should be
0366                     # located between the start of
0367                     # setup and the end of low
0368                     # memory (0xa0000), or it may
0369                     # get overwritten before it
0370                     # gets read.  If this field is
0371                     # used, there is no longer
0372                     # anything magical about the
0373                     # 0x90000 segment; the setup
0374                     # can be located anywhere in
0375                     # low memory 0x10000 or higher.
0376 
0377 initrd_addr_max: .long 0x7fffffff
0378                     # (Header version 0x0203 or later)
0379                     # The highest safe address for
0380                     # the contents of an initrd
0381                     # The current kernel allows up to 4 GB,
0382                     # but leave it at 2 GB to avoid
0383                     # possible bootloader bugs.
0384 
0385 kernel_alignment:  .long CONFIG_PHYSICAL_ALIGN  #physical addr alignment
0386                         #required for protected mode
0387                         #kernel
0388 #ifdef CONFIG_RELOCATABLE
0389 relocatable_kernel:    .byte 1
0390 #else
0391 relocatable_kernel:    .byte 0
0392 #endif
0393 min_alignment:      .byte MIN_KERNEL_ALIGN_LG2  # minimum alignment
0394 
0395 xloadflags:
0396 #ifdef CONFIG_X86_64
0397 # define XLF0 XLF_KERNEL_64         /* 64-bit kernel */
0398 #else
0399 # define XLF0 0
0400 #endif
0401 
0402 #if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
0403    /* kernel/boot_param/ramdisk could be loaded above 4g */
0404 # define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
0405 #else
0406 # define XLF1 0
0407 #endif
0408 
0409 #ifdef CONFIG_EFI_STUB
0410 # ifdef CONFIG_EFI_MIXED
0411 #  define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
0412 # else
0413 #  ifdef CONFIG_X86_64
0414 #   define XLF23 XLF_EFI_HANDOVER_64        /* 64-bit EFI handover ok */
0415 #  else
0416 #   define XLF23 XLF_EFI_HANDOVER_32        /* 32-bit EFI handover ok */
0417 #  endif
0418 # endif
0419 #else
0420 # define XLF23 0
0421 #endif
0422 
0423 #if defined(CONFIG_X86_64) && defined(CONFIG_EFI) && defined(CONFIG_KEXEC_CORE)
0424 # define XLF4 XLF_EFI_KEXEC
0425 #else
0426 # define XLF4 0
0427 #endif
0428 
0429 #ifdef CONFIG_X86_64
0430 #ifdef CONFIG_X86_5LEVEL
0431 #define XLF56 (XLF_5LEVEL|XLF_5LEVEL_ENABLED)
0432 #else
0433 #define XLF56 XLF_5LEVEL
0434 #endif
0435 #else
0436 #define XLF56 0
0437 #endif
0438 
0439             .word XLF0 | XLF1 | XLF23 | XLF4 | XLF56
0440 
0441 cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
0442                                                 #added with boot protocol
0443                                                 #version 2.06
0444 
0445 hardware_subarch:   .long 0         # subarchitecture, added with 2.07
0446                         # default to 0 for normal x86 PC
0447 
0448 hardware_subarch_data:  .quad 0
0449 
0450 payload_offset:     .long ZO_input_data
0451 payload_length:     .long ZO_z_input_len
0452 
0453 setup_data:     .quad 0         # 64-bit physical pointer to
0454                         # single linked list of
0455                         # struct setup_data
0456 
0457 pref_address:       .quad LOAD_PHYSICAL_ADDR    # preferred load addr
0458 
0459 #
0460 # Getting to provably safe in-place decompression is hard. Worst case
0461 # behaviours need to be analyzed. Here let's take the decompression of
0462 # a gzip-compressed kernel as example, to illustrate it:
0463 #
0464 # The file layout of gzip compressed kernel is:
0465 #
0466 #    magic[2]
0467 #    method[1]
0468 #    flags[1]
0469 #    timestamp[4]
0470 #    extraflags[1]
0471 #    os[1]
0472 #    compressed data blocks[N]
0473 #    crc[4] orig_len[4]
0474 #
0475 # ... resulting in +18 bytes overhead of uncompressed data.
0476 #
0477 # (For more information, please refer to RFC 1951 and RFC 1952.)
0478 #
0479 # Files divided into blocks
0480 # 1 bit (last block flag)
0481 # 2 bits (block type)
0482 #
0483 # 1 block occurs every 32K -1 bytes or when there 50% compression
0484 # has been achieved. The smallest block type encoding is always used.
0485 #
0486 # stored:
0487 #    32 bits length in bytes.
0488 #
0489 # fixed:
0490 #    magic fixed tree.
0491 #    symbols.
0492 #
0493 # dynamic:
0494 #    dynamic tree encoding.
0495 #    symbols.
0496 #
0497 #
0498 # The buffer for decompression in place is the length of the uncompressed
0499 # data, plus a small amount extra to keep the algorithm safe. The
0500 # compressed data is placed at the end of the buffer.  The output pointer
0501 # is placed at the start of the buffer and the input pointer is placed
0502 # where the compressed data starts. Problems will occur when the output
0503 # pointer overruns the input pointer.
0504 #
0505 # The output pointer can only overrun the input pointer if the input
0506 # pointer is moving faster than the output pointer.  A condition only
0507 # triggered by data whose compressed form is larger than the uncompressed
0508 # form.
0509 #
0510 # The worst case at the block level is a growth of the compressed data
0511 # of 5 bytes per 32767 bytes.
0512 #
0513 # The worst case internal to a compressed block is very hard to figure.
0514 # The worst case can at least be bounded by having one bit that represents
0515 # 32764 bytes and then all of the rest of the bytes representing the very
0516 # very last byte.
0517 #
0518 # All of which is enough to compute an amount of extra data that is required
0519 # to be safe.  To avoid problems at the block level allocating 5 extra bytes
0520 # per 32767 bytes of data is sufficient.  To avoid problems internal to a
0521 # block adding an extra 32767 bytes (the worst case uncompressed block size)
0522 # is sufficient, to ensure that in the worst case the decompressed data for
0523 # block will stop the byte before the compressed data for a block begins.
0524 # To avoid problems with the compressed data's meta information an extra 18
0525 # bytes are needed.  Leading to the formula:
0526 #
0527 # extra_bytes = (uncompressed_size >> 12) + 32768 + 18
0528 #
0529 # Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
0530 # Adding 32768 instead of 32767 just makes for round numbers.
0531 #
0532 # Above analysis is for decompressing gzip compressed kernel only. Up to
0533 # now 6 different decompressor are supported all together. And among them
0534 # xz stores data in chunks and has maximum chunk of 64K. Hence safety
0535 # margin should be updated to cover all decompressors so that we don't
0536 # need to deal with each of them separately. Please check
0537 # the description in lib/decompressor_xxx.c for specific information.
0538 #
0539 # extra_bytes = (uncompressed_size >> 12) + 65536 + 128
0540 #
0541 # LZ4 is even worse: data that cannot be further compressed grows by 0.4%,
0542 # or one byte per 256 bytes. OTOH, we can safely get rid of the +128 as
0543 # the size-dependent part now grows so fast.
0544 #
0545 # extra_bytes = (uncompressed_size >> 8) + 65536
0546 #
0547 # ZSTD compressed data grows by at most 3 bytes per 128K, and only has a 22
0548 # byte fixed overhead but has a maximum block size of 128K, so it needs a
0549 # larger margin.
0550 #
0551 # extra_bytes = (uncompressed_size >> 8) + 131072
0552 
0553 #define ZO_z_extra_bytes    ((ZO_z_output_len >> 8) + 131072)
0554 #if ZO_z_output_len > ZO_z_input_len
0555 # define ZO_z_extract_offset    (ZO_z_output_len + ZO_z_extra_bytes - \
0556                  ZO_z_input_len)
0557 #else
0558 # define ZO_z_extract_offset    ZO_z_extra_bytes
0559 #endif
0560 
0561 /*
0562  * The extract_offset has to be bigger than ZO head section. Otherwise when
0563  * the head code is running to move ZO to the end of the buffer, it will
0564  * overwrite the head code itself.
0565  */
0566 #if (ZO__ehead - ZO_startup_32) > ZO_z_extract_offset
0567 # define ZO_z_min_extract_offset ((ZO__ehead - ZO_startup_32 + 4095) & ~4095)
0568 #else
0569 # define ZO_z_min_extract_offset ((ZO_z_extract_offset + 4095) & ~4095)
0570 #endif
0571 
0572 #define ZO_INIT_SIZE    (ZO__end - ZO_startup_32 + ZO_z_min_extract_offset)
0573 
0574 #define VO_INIT_SIZE    (VO__end - VO__text)
0575 #if ZO_INIT_SIZE > VO_INIT_SIZE
0576 # define INIT_SIZE ZO_INIT_SIZE
0577 #else
0578 # define INIT_SIZE VO_INIT_SIZE
0579 #endif
0580 
0581 init_size:      .long INIT_SIZE     # kernel initialization size
0582 handover_offset:    .long 0         # Filled in by build.c
0583 kernel_info_offset: .long 0         # Filled in by build.c
0584 
0585 # End of setup header #####################################################
0586 
0587     .section ".entrytext", "ax"
0588 start_of_setup:
0589 # Force %es = %ds
0590     movw    %ds, %ax
0591     movw    %ax, %es
0592     cld
0593 
0594 # Apparently some ancient versions of LILO invoked the kernel with %ss != %ds,
0595 # which happened to work by accident for the old code.  Recalculate the stack
0596 # pointer if %ss is invalid.  Otherwise leave it alone, LOADLIN sets up the
0597 # stack behind its own code, so we can't blindly put it directly past the heap.
0598 
0599     movw    %ss, %dx
0600     cmpw    %ax, %dx    # %ds == %ss?
0601     movw    %sp, %dx
0602     je  2f      # -> assume %sp is reasonably set
0603 
0604     # Invalid %ss, make up a new stack
0605     movw    $_end, %dx
0606     testb   $CAN_USE_HEAP, loadflags
0607     jz  1f
0608     movw    heap_end_ptr, %dx
0609 1:  addw    $STACK_SIZE, %dx
0610     jnc 2f
0611     xorw    %dx, %dx    # Prevent wraparound
0612 
0613 2:  # Now %dx should point to the end of our stack space
0614     andw    $~3, %dx    # dword align (might as well...)
0615     jnz 3f
0616     movw    $0xfffc, %dx    # Make sure we're not zero
0617 3:  movw    %ax, %ss
0618     movzwl  %dx, %esp   # Clear upper half of %esp
0619     sti         # Now we should have a working stack
0620 
0621 # We will have entered with %cs = %ds+0x20, normalize %cs so
0622 # it is on par with the other segments.
0623     pushw   %ds
0624     pushw   $6f
0625     lretw
0626 6:
0627 
0628 # Check signature at end of setup
0629     cmpl    $0x5a5aaa55, setup_sig
0630     jne setup_bad
0631 
0632 # Zero the bss
0633     movw    $__bss_start, %di
0634     movw    $_end+3, %cx
0635     xorl    %eax, %eax
0636     subw    %di, %cx
0637     shrw    $2, %cx
0638     rep; stosl
0639 
0640 # Jump to C code (should not return)
0641     calll   main
0642 
0643 # Setup corrupt somehow...
0644 setup_bad:
0645     movl    $setup_corrupt, %eax
0646     calll   puts
0647     # Fall through...
0648 
0649     .globl  die
0650     .type   die, @function
0651 die:
0652     hlt
0653     jmp die
0654 
0655     .size   die, .-die
0656 
0657     .section ".initdata", "a"
0658 setup_corrupt:
0659     .byte   7
0660     .string "No setup signature found...\n"