summaryrefslogtreecommitdiff
path: root/util/mkelfImage/linux-i386/head.S
diff options
context:
space:
mode:
Diffstat (limited to 'util/mkelfImage/linux-i386/head.S')
-rw-r--r--util/mkelfImage/linux-i386/head.S476
1 files changed, 476 insertions, 0 deletions
diff --git a/util/mkelfImage/linux-i386/head.S b/util/mkelfImage/linux-i386/head.S
new file mode 100644
index 0000000000..c3990ac801
--- /dev/null
+++ b/util/mkelfImage/linux-i386/head.S
@@ -0,0 +1,476 @@
+/*
+ * exec_kernel/user_space/head.S
+ *
+ * Copyright (C) 2000, 2002, 2003 Eric Biederman
+ *
+ * Parts of this code were take from the linux startup
+ * code of linux-2.4.0-test9
+ *
+ * Other parts were taken from etherboot-5.0.5
+ */
+
+#define ASSEMBLY 1
+
+#define RELOC 0x10000
+#define PROT_CODE_SEG 0x10
+#define PROT_DATA_SEG 0x18
+#define REAL_CODE_SEG 0x08
+#define REAL_DATA_SEG 0x20
+
+ .equ CR0_PE,1
+
+.text
+.code32
+
+
+#include "convert.h"
+
+ .globl startup_32
+startup_32:
+ cld
+ cli
+
+ # Save the arguments safely out of the way
+ movl %eax, boot_type
+ movl %ebx, boot_data
+ cmp $0,%esp
+ jz 1f
+ movl 4(%esp), %eax
+ movl %eax, boot_param
+1:
+
+ movl stack_start, %esp
+
+ # Clear eflags
+ pushl $0
+ popfl
+
+ # Clear BSS
+ xorl %eax,%eax
+ movl $ _edata,%edi
+ movl $ _end,%ecx
+ subl %edi,%ecx
+ cld
+ rep
+ stosb
+
+ # Move the gdt where Linux will not smash it during decompression
+ movl $gdt, %esi
+ movl $GDTLOC, %edi
+ movl $(gdt_end - gdt), %ecx
+ rep movsb
+
+ # Linux makes stupid assumptions about the segments
+ # that are already setup, so setup a new gdt & ldt
+ # and then reload the segment registers.
+
+ lgdt gdt_48
+ lidt idt_48
+
+ # Load the data segment registers
+ movl $ PROT_DATA_SEG, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+
+ pushl $image_params # image build time parameters as forth arg
+ pushl boot_param # boot_param pointer as third arg
+ pushl boot_data # boot data pointer as second arg
+ pushl boot_type # boot data type as first argument
+ call convert_params
+
+ movl %eax, %esi # put the real mode pointer in a safe place
+ addl $16, %esp # pop the arguments
+
+
+ # Setup the registers before jumping to linux
+
+
+ # clear eflags
+ pushl $0
+ popfl
+
+ # Flag to indicate we are the bootstrap processor
+ xorl %ebx, %ebx
+
+ # Clear the unspecified registers for good measure
+ xorl %eax, %eax
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ xorl %edi, %edi
+ xorl %esp, %esp
+ xorl %ebp, %ebp
+
+
+ # Jump to the linux kernel
+ ljmp $ PROT_CODE_SEG , $ 0x100000
+
+
+ /* Routines to query the BIOS... */
+
+
+/**************************************************************************
+E820_MEMSIZE - Get a listing of memory regions
+**************************************************************************/
+#define SMAP 0x534d4150
+ .globl meme820
+meme820:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ movl 8(%ebp), %edi /* Address to return e820 structures at */
+ subl $RELOC, %edi
+ movl 12(%ebp), %esi /* Maximum number of e820 structurs to return */
+ pushl %esi
+ call _prot_to_real
+ .code16
+ xorl %ebx, %ebx
+jmpe820:
+ movl $0xe820, %eax
+ movl $SMAP, %edx
+ movl $20, %ecx
+ /* %di was setup earlier */
+ int $0x15
+ jc bail820
+
+ cmpl $SMAP, %eax
+ jne bail820
+
+good820:
+ /* If this is useable memory, we save it by simply advancing %di by
+ * sizeof(e820rec)
+ */
+ decl %esi
+ testl %esi,%esi
+ jz bail820
+
+ addw $20, %di
+again820:
+ cmpl $0, %ebx /* check to see if %ebx is set to EOF */
+ jne jmpe820
+
+bail820:
+ data32 call _real_to_prot
+ .code32
+ popl %eax
+ subl %esi, %eax /* Compute how many structure we read */
+
+ /* Restore everything else */
+ popl %edi
+ popl %esi
+ popl %ebx
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+
+/**************************************************************************
+MEME801 - Determine size of extended memory
+**************************************************************************/
+ .globl meme801
+meme801:
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ call _prot_to_real
+ .code16
+
+ stc # fix to work around buggy
+ xorw %cx,%cx # BIOSes which dont clear/set
+ xorw %dx,%dx # carry on pass/error of
+ # e801h memory size call
+ # or merely pass cx,dx though
+ # without changing them.
+ movw $0xe801,%ax
+ int $0x15
+ jc e801absent
+
+ cmpw $0x0, %cx # Kludge to handle BIOSes
+ jne e801usecxdx # which report their extended
+ cmpw $0x0, %dx # memory in AX/BX rather than
+ jne e801usecxdx # CX/DX. The spec I have read
+ movw %ax, %cx # seems to indicate AX/BX
+ movw %bx, %dx # are more reasonable anyway...
+
+e801usecxdx:
+ andl $0xffff, %edx # clear sign extend
+ shll $6, %edx # and go from 64k to 1k chunks
+ movl %edx, %eax # store extended memory size
+ andl $0xffff, %ecx # clear sign extend
+ addl %ecx, %eax # and add lower memory into
+
+ jmp e801out
+e801absent:
+ xorl %eax,%eax
+
+e801out:
+ data32 call _real_to_prot
+ .code32
+ /* Restore Everything */
+ popl %edi
+ popl %esi
+ popl %ebx
+ ret
+
+/**************************************************************************
+MEM88 - Determine size of extended memory
+**************************************************************************/
+ .globl mem88
+mem88:
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ call _prot_to_real
+ .code16
+
+ movb $0x88, %ah
+ int $0x15
+ andl $0xffff, %eax
+
+ data32 call _real_to_prot
+ .code32
+
+ /* Restore Everything */
+ popl %edi
+ popl %esi
+ popl %ebx
+ ret
+
+
+/**************************************************************************
+BASEMEMSIZE - Get size of the conventional (base) memory
+**************************************************************************/
+ .globl basememsize
+basememsize:
+ call _prot_to_real
+ .code16
+ int $0x12
+ movw %ax,%cx
+ DATA32 call _real_to_prot
+ .code32
+ movw %cx,%ax
+ ret
+
+/**************************************************************************
+_REAL_TO_PROT - Go from REAL mode to Protected Mode
+**************************************************************************/
+ .globl _real_to_prot
+_real_to_prot:
+ .code16
+ cli
+ cs
+ addr32 lgdt gdt_48 - RELOC
+ movl %cr0,%eax
+ orl $CR0_PE,%eax
+ movl %eax,%cr0 /* turn on protected mode */
+
+ /* flush prefetch queue, and reload %cs:%eip */
+ data32 ljmp $PROT_CODE_SEG,$1f
+1:
+ .code32
+ /* reload other segment registers */
+ movl $PROT_DATA_SEG,%eax
+ movl %eax,%ds
+ movl %eax,%es
+ movl %eax,%ss
+ addl $RELOC,%esp /* Fix up stack pointer */
+ xorl %eax,%eax
+ movl %eax,%fs
+ movl %eax,%gs
+ popl %eax /* Fix up return address */
+ addl $RELOC,%eax
+ pushl %eax
+
+ /* switch to protected mode idt */
+ cs
+ lidt idt_48
+ ret
+
+/**************************************************************************
+_PROT_TO_REAL - Go from Protected Mode to REAL Mode
+**************************************************************************/
+ .globl _prot_to_real
+_prot_to_real:
+ .code32
+ popl %eax
+ subl $RELOC,%eax /* Adjust return address */
+ pushl %eax
+ subl $RELOC,%esp /* Adjust stack pointer */
+ ljmp $REAL_CODE_SEG,$1f- RELOC /* jump to a 16 bit segment */
+1:
+ .code16
+ /* clear the PE bit of CR0 */
+ movl %cr0,%eax
+ andl $0!CR0_PE,%eax
+ movl %eax,%cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ data32 ljmp $(RELOC)>>4,$2f- RELOC
+2:
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%ss
+ movw %ax,%fs
+ movw %ax,%gs
+
+ /* Switch to the real mode idt */
+ cs
+ addr32 lidt idt_real - RELOC
+
+ sti
+ data32 ret /* There is a 32 bit return address on the stack */
+ .code32
+
+boot_type: .long 0
+boot_data: .long 0
+boot_param: .long 0
+
+idt_real:
+ .word 0x400 # idt limit = 256
+ .word 0, 0
+idt_48:
+ .word 0 # idt limit = 0
+ .word 0, 0 # idt base = 0L
+gdt_48:
+ .word gdt_end - gdt - 1 # gdt limit=40,
+ # (5 GDT entries)
+ .long GDTLOC # gdt base
+
+# Descriptor tables
+# These need to be in a seperate section so I can be
+# certain later activities dont stomp them
+gdt:
+ /* 0x00 */
+ .word 0, 0, 0, 0 # dummy
+
+ /* 0x08 */
+ /* 16 bit real mode code segment */
+ .word 0xffff,(RELOC&0xffff)
+ .byte (RELOC>>16),0x9b,0x00,(RELOC>>24)
+
+ /* 0x10 */
+ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
+ .word 0 # base address = 0
+ .word 0x9A00 # code read/exec
+ .word 0x00CF # granularity = 4096, 386
+ # (+5th nibble of limit)
+
+ /* 0x18 */
+ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
+ .word 0 # base address = 0
+ .word 0x9200 # data read/write
+ .word 0x00CF # granularity = 4096, 386
+ # (+5th nibble of limit)
+
+ /* 0x20 */
+ /* 16 bit real mode data segment */
+ .word 0xffff,(RELOC&0xffff)
+ .byte (RELOC>>16),0x93,0x00,(RELOC>>24)
+
+ /* For 2.5.x the kernel segments have moved */
+
+ /* 0x28 dummy */
+ .quad 0
+
+ /* 0x30 dummy */
+ .quad 0
+ /* 0x38 dummy */
+ .quad 0
+ /* 0x40 dummy */
+ .quad 0
+ /* 0x48 dummy */
+ .quad 0
+ /* 0x50 dummy */
+ .quad 0
+ /* 0x58 dummy */
+ .quad 0
+
+
+ /* 0x60 */
+ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
+ .word 0 # base address = 0
+ .word 0x9A00 # code read/exec
+ .word 0x00CF # granularity = 4096, 386
+ # (+5th nibble of limit)
+
+ /* 0x68 */
+ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
+ .word 0 # base address = 0
+ .word 0x9200 # data read/write
+ .word 0x00CF # granularity = 4096, 386
+ # (+5th nibble of limit)
+/*
+ * The layout of the per-CPU GDT under Linux:
+ *
+ * 0 - null
+ * 1 - reserved
+ * 2 - reserved
+ * 3 - reserved
+ *
+ * 4 - default user CS <==== new cacheline
+ * 5 - default user DS
+ *
+ * ------- start of TLS (Thread-Local Storage) segments:
+ *
+ * 6 - TLS segment #1 [ glibc's TLS segment ]
+ * 7 - TLS segment #2 [ Wine's %fs Win32 segment ]
+ * 8 - TLS segment #3
+ * 9 - reserved
+ * 10 - reserved
+ * 11 - reserved
+ *
+ * ------- start of kernel segments:
+ *
+ * 12 - kernel code segment <==== new cacheline
+ * 13 - kernel data segment
+ * 14 - TSS
+ * 15 - LDT
+ * 16 - PNPBIOS support (16->32 gate)
+ * 17 - PNPBIOS support
+ * 18 - PNPBIOS support
+ * 19 - PNPBIOS support
+ * 20 - PNPBIOS support
+ * 21 - APM BIOS support
+ * 22 - APM BIOS support
+ * 23 - APM BIOS support
+ */
+gdt_end:
+
+
+
+ .section ".trailer", "a"
+ /* Constants set at build time, these are at the very end of my image */
+ .balign 16
+ .global image_params
+image_params:
+
+convert_magic:
+ .long CONVERT_MAGIC
+gdt_size:
+ .long gdt_end - gdt
+bss_size:
+ .long bss_size
+ramdisk_flags:
+ .word 0
+root_dev:
+ .word DEFAULT_ROOT_DEV
+entry:
+ .long 0
+initrd_start:
+ .long 0
+initrd_size:
+ .long 0
+cmdline:
+ .asciz "BOOT_IMAGE=head.S console=ttyS0 ip=dhcp root=/dev/nfs"
+ .org cmdline + CMDLINE_MAX, 0
+cmdline_end: