| /* |
| * linux/boot/head.S |
| * |
| * Copyright (C) 1991, 1992, 1993 Linus Torvalds |
| */ |
| |
| /* |
| * head.S contains the 32-bit startup code. |
| * |
| * NOTE!!! Startup happens at absolute address 0x00001000, which is also where |
| * the page directory will exist. The startup code will be overwritten by |
| * the page directory. [According to comments etc elsewhere on a compressed |
| * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] |
| * |
| * Page 0 is deliberately kept safe, since System Management Mode code in |
| * laptops may need to access the BIOS data stored there. This is also |
| * useful for future device drivers that either access the BIOS via VM86 |
| * mode. |
| */ |
| |
| /* |
| * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 |
| */ |
| .text |
| |
| #include <linux/linkage.h> |
| #include <asm/segment.h> |
| #include <asm/page.h> |
| |
| .globl startup_32 |
| |
| startup_32: |
| cld |
| cli |
| movl $(__BOOT_DS),%eax |
| movl %eax,%ds |
| movl %eax,%es |
| movl %eax,%fs |
| movl %eax,%gs |
| |
| lss 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 |
| |
| /* |
| * Initialize eflags. Some BIOS's leave bits like NT set. This would |
| * confuse the debugger if this code is traced. |
| * XXX - best to initialize before switching to protected mode. |
| */ |
| pushl $0 |
| popfl |
| /* |
| * Clear BSS |
| */ |
| xorl %eax,%eax |
| movl $_edata,%edi |
| movl $_end,%ecx |
| subl %edi,%ecx |
| cld |
| rep |
| stosb |
| /* |
| * Do the decompression, and jump to the new kernel.. |
| */ |
| 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 decompress_kernel |
| orl %eax,%eax |
| jnz 3f |
| popl %esi # discard address |
| popl %esi # real mode pointer |
| xorl %ebx,%ebx |
| ljmp $(__BOOT_CS), $__PHYSICAL_START |
| |
| /* |
| * We come here, if we were loaded high. |
| * We need to move the move-in-place routine down to 0x1000 |
| * and then start it with the buffer addresses in registers, |
| * which we got from the stack. |
| */ |
| 3: |
| movl $move_routine_start,%esi |
| movl $0x1000,%edi |
| movl $move_routine_end,%ecx |
| subl %esi,%ecx |
| addl $3,%ecx |
| shrl $2,%ecx |
| cld |
| rep |
| movsl |
| |
| 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 $__PHYSICAL_START,%edi |
| cli # make sure we don't get interrupted |
| ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine |
| |
| /* |
| * Routine (template) for moving the decompressed kernel in place, |
| * if we were high loaded. This _must_ PIC-code ! |
| */ |
| move_routine_start: |
| movl %ecx,%ebp |
| shrl $2,%ecx |
| rep |
| movsl |
| movl %ebp,%ecx |
| andl $3,%ecx |
| rep |
| movsb |
| movl %edx,%esi |
| movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 |
| addl $3,%ecx |
| shrl $2,%ecx |
| rep |
| movsl |
| movl %ebx,%esi # Restore setup pointer |
| xorl %ebx,%ebx |
| ljmp $(__BOOT_CS), $__PHYSICAL_START |
| move_routine_end: |