x86 boot enhancements, Clean up the 32bit entry points 6/11
PATCH 1/1 x86 boot enhancements, Clean up the 32bit entry points 6/11
Linus please apply,
In general allow any kernel entry point to work given any set of initial register values, while saving the original registers values so the C code can do something with it if we desire.
- trampoline.S fix comments, and enter the kernel at secondary_startup_32 instead of startup_32
- trampoline.S fix gdt_48 to have the correct gdt limit
- Save all of the registers we get from any 32bit entry point, and don't assume they have any particular value.
- head.S split up startup_32
- secondary_startup_32 handles the SMP case
- move finding the command line to startup.c
- Don't copy the kernel parameters to the initial_zero_page, instead just pass setup.c where they are located.
- Seperate the segments used by setup.S from the rest of the kernel. This way bootloader can continue to make assumptions about which segments setup.S uses while the rest of the kernel can do whatever is convinient.
- Move boot specific defines into boot.h
Eric
arch/i386/boot/compressed/head.S +71 -27
@@ -25,24 +25,30 @@ #include <linux/linkage.h> #include <asm/segment.h> +#include <asm/boot.h> .globl startup_32 startup_32: cld cli - movl $(__KERNEL_DS),%eax - movl %eax,%ds - movl %eax,%es - movl %eax,%fs - movl %eax,%gs - lss SYMBOL_NAME(stack_start),%esp - xorl %eax,%eax -1: incl %eax # check that A20 really IS enabled - movl %eax,0x000000 # loop forever if it isn't - cmpl %eax,0x100000 - je 1b + /* + * Save the initial registers + */ + movl %eax, eax + movl %ebx, ebx + movl %ecx, ecx + movl %edx, edx + movl %esi, esi + movl %edi, edi + movl %esp, esp + movl %ebp, ebp + + /* + * Setup the stack + */ + movl SYMBOL_NAME(stack_start), %esp /* * Initialize eflags. Some BIOS's leave bits like NT set. This would
@@ -66,16 +72,10 @@ */ subl $16,%esp # place for structure on the stack movl %esp,%eax - pushl %esi # real mode pointer as second arg pushl %eax # address of structure as first arg call SYMBOL_NAME(decompress_kernel) orl %eax,%eax - jnz 3f - popl %esi # discard address - popl %esi # real mode pointer - xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 - + jz out /* * We come here, if we were loaded high. * We need to move the move-in-place routine down to 0x1000
@@ -83,8 +83,21 @@ * which we got from the stack. */ 3: - movl $move_routine_start,%esi - movl $0x1000,%edi + /* Relocate the move routine */ + movl $move_routine_start,%esi #src + movl %eax,%edi #dest + movl %eax, %ebp #saved dest + movl %edi, %eax + subl %esi, %eax # The relocation factor + addl %eax, reloc1 + addl %eax, reloc2 + addl %eax, reloc3 + addl %eax, reloc4 + addl %eax, reloc5 + addl %eax, reloc6 + addl %eax, reloc7 + addl %eax, reloc8 + addl %eax, reloc9 movl $move_routine_end,%ecx subl %esi,%ecx addl $3,%ecx
@@ -93,20 +106,23 @@ rep movsl + /* Load it's arguments and jump to the move routine */ popl %esi # discard the address - popl %ebx # real mode pointer popl %esi # low_buffer_start popl %ecx # lcount popl %edx # high_buffer_start popl %eax # hcount - movl $0x100000,%edi + movl $HIGH_BASE,%edi cli # make sure we don't get interrupted - ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine + jmpl *%ebp /* * Routine (template) for moving the decompressed kernel in place, - * if we were high loaded. This _must_ PIC-code ! + * if we were high loaded. This _must_ be PIC-code ! + * Or it must be anotated with lables so it can be manually relocated. */ + .globl move_routine_start, move_routine_end + .balign 4 move_routine_start: movl %ecx,%ebp shrl $2,%ecx
@@ -122,7 +138,35 @@ shrl $2,%ecx rep movsl - movl %ebx,%esi # Restore setup pointer - xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 +out: + .byte 0xa1 # movl eax, %eax +reloc1: .long eax + .byte 0x8b, 0x1d # movl ebx, %ebx +reloc2: .long ebx + .byte 0x8b, 0x0d # movl ecx, %ecx +reloc3: .long ecx + .byte 0x8b, 0x15 # movl edx, %edx +reloc4: .long edx + .byte 0x8b, 0x35 # movl esi, %esi +reloc5: .long esi + .byte 0x8b, 0x3d # movl edi, %edi +reloc6: .long edi + .byte 0x8b, 0x25 # movl esp, %esp +reloc7: .long esp + .byte 0x8b, 0x2d # movl ebp, %ebp +reloc8: .long ebp + .byte 0xff, 0x25 # jmpl *(kernel_start) +reloc9: .long kernel_start + .balign 4 +ENTRY(initial_regs) +eax: .long 0x12345678 /* eax */ +ebx: .long 0x12345678 /* ebx */ +ecx: .long 0x12345678 /* ecx */ +edx: .long 0x12345678 /* edx */ +esi: .long 0x12345678 /* esi */ +edi: .long 0x12345678 /* edi */ +esp: .long 0x12345678 /* esp */ +ebp: .long 0x12345678 /* ebp */ +kernel_start: + .long HIGH_BASE move_routine_end:
arch/i386/boot/compressed/misc.c +40 -21
124 lines not on this page · raw message
arch/i386/boot/setup.S +18 -3
@@ -64,6 +64,12 @@ #define DELTA_BOOTSECT 512 +/* Segments used by setup.S */ +#define __SETUP_CS 0x10 +#define __SETUP_DS 0x18 +#define __SETUP_REAL_CS 0x20 +#define __SETUP_REAL_DS 0x28 + INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
@@ -784,13 +790,22 @@ jmp flush_instr flush_instr: - xorw %bx, %bx # Flag to indicate a boot xorl %esi, %esi # Pointer to real-mode code movw %cs, %si subw $DELTA_INITSEG, %si shll $4, %esi # Convert to 32-bit pointer + movl $ENTRY16, %ebp # Magic to indicate 16bit entry + +# Setup the data segments + movw $(__SETUP_DS), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + # NOTE: For high loaded big kernels we need a -# jmpi 0x100000,__KERNEL_CS +# jmpi 0x100000,__SETUP_CS # # but we yet haven't reloaded the CS register, so the default size # of the target offset still is 16 bit.
@@ -801,7 +816,7 @@ .byte 0x66, 0xea # prefix + jmpi-opcode code32: .long 0x1000 # will be set to 0x100000 # for big kernels - .word __KERNEL_CS + .word __SETUP_CS # Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE
arch/i386/kernel/head.S +101 -103
268 lines not on this page · raw message
arch/i386/kernel/setup.c +90 -22
163 lines not on this page · raw message
arch/i386/kernel/trampoline.S +10 -10
@@ -12,10 +12,6 @@ * In fact we don't actually need a stack so we don't * set one up. * - * We jump into the boot/compressed/head.S code. So you'd - * better be running a compressed kernel image or you - * won't get very far. - * * On entry to trampoline_data, the processor is in real mode * with 16-bit addressing and 16-bit data. CS has some value * and IP is zero. Thus, data addresses need to be absolute
@@ -23,12 +19,16 @@ * * If you work on this file, check the object module with objdump * --full-contents --reloc to make sure there are no relocation - * entries except for the gdt one.. + * entries except for gdt & secondary_startup_32.. */ #include <linux/linkage.h> +#include <linux/threads.h> #include <asm/segment.h> #include <asm/page.h> +#include <asm/desc.h> + +#define GDT_ENTRIES (__TSS(NR_CPUS)) .data
@@ -42,7 +42,6 @@ mov %cs, %ax # Code and data in the same place mov %ax, %ds - mov $1, %bx # Flag an SMP trampoline cli # We should be safe anyway movl $0xA5A5A5A5, trampoline_data - r_base
@@ -56,16 +55,17 @@ lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmpl $__KERNEL_CS, $0x00100000 - # jump to startup_32 in arch/i386/kernel/head.S + # jump to secondary_startup_32 in arch/i386/kernel/head.S + ljmpl $__KERNEL_CS, $(SYMBOL_NAME(secondary_startup_32) - __PAGE_OFFSET) + idt_48: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L gdt_48: - .word 0x0800 # gdt limit = 2048, 256 GDT entries - .long gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) + .word GDT_ENTRIES*8-1 # gdt limit + .long SYMBOL_NAME(gdt_table)-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) .globl SYMBOL_NAME(trampoline_end) SYMBOL_NAME_LABEL(trampoline_end)
include/asm-i386/boot.h +10 -0
@@ -26,4 +26,14 @@#define EXTENDED_VGA 0xfffe/* 80x50 mode */ #define ASK_VGA 0xfffd/* ask for it at bootup */ +/* Entry point ID constants */ +#define ENTRY16 0x73726468/* 'hdrs' */ +#define ENTRY32 0x53524448/* 'HDRS' */ + +/* Maximum command line size */ +#define COMMAND_LINE_SIZE 256 + +/* Initial page table size 8MB */ +#define INITIAL_PAGE_TABLE_SIZE 0x800000 +#endif
include/asm-i386/boot_param.h +10 -0
@@ -1,6 +1,16 @@ #ifndef __I386_BOOT_PARAM_H #define __I386_BOOT_PARAM_H +struct initial_regs32 { + const __u32 eax; + const __u32 ebx; + const __u32 ecx; + const __u32 edx; + const __u32 esi; + const __u32 edi; + const __u32 esp; + const __u32 ebp; +}; struct drive_info_struct { __u8 dummy[32]; }; struct sys_desc_table { __u16 length;