diff options
Diffstat (limited to 'arch/i386/boot/compressed/head.S')
-rw-r--r-- | arch/i386/boot/compressed/head.S | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S new file mode 100644 index 000000000000..c5e80b69e7d4 --- /dev/null +++ b/arch/i386/boot/compressed/head.S | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * linux/boot/head.S | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992, 1993 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * head.S contains the 32-bit startup code. | ||
9 | * | ||
10 | * NOTE!!! Startup happens at absolute address 0x00001000, which is also where | ||
11 | * the page directory will exist. The startup code will be overwritten by | ||
12 | * the page directory. [According to comments etc elsewhere on a compressed | ||
13 | * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] | ||
14 | * | ||
15 | * Page 0 is deliberately kept safe, since System Management Mode code in | ||
16 | * laptops may need to access the BIOS data stored there. This is also | ||
17 | * useful for future device drivers that either access the BIOS via VM86 | ||
18 | * mode. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | ||
23 | */ | ||
24 | .text | ||
25 | |||
26 | #include <linux/linkage.h> | ||
27 | #include <asm/segment.h> | ||
28 | |||
29 | .globl startup_32 | ||
30 | |||
31 | startup_32: | ||
32 | cld | ||
33 | cli | ||
34 | movl $(__BOOT_DS),%eax | ||
35 | movl %eax,%ds | ||
36 | movl %eax,%es | ||
37 | movl %eax,%fs | ||
38 | movl %eax,%gs | ||
39 | |||
40 | lss stack_start,%esp | ||
41 | xorl %eax,%eax | ||
42 | 1: incl %eax # check that A20 really IS enabled | ||
43 | movl %eax,0x000000 # loop forever if it isn't | ||
44 | cmpl %eax,0x100000 | ||
45 | je 1b | ||
46 | |||
47 | /* | ||
48 | * Initialize eflags. Some BIOS's leave bits like NT set. This would | ||
49 | * confuse the debugger if this code is traced. | ||
50 | * XXX - best to initialize before switching to protected mode. | ||
51 | */ | ||
52 | pushl $0 | ||
53 | popfl | ||
54 | /* | ||
55 | * Clear BSS | ||
56 | */ | ||
57 | xorl %eax,%eax | ||
58 | movl $_edata,%edi | ||
59 | movl $_end,%ecx | ||
60 | subl %edi,%ecx | ||
61 | cld | ||
62 | rep | ||
63 | stosb | ||
64 | /* | ||
65 | * Do the decompression, and jump to the new kernel.. | ||
66 | */ | ||
67 | subl $16,%esp # place for structure on the stack | ||
68 | movl %esp,%eax | ||
69 | pushl %esi # real mode pointer as second arg | ||
70 | pushl %eax # address of structure as first arg | ||
71 | call decompress_kernel | ||
72 | orl %eax,%eax | ||
73 | jnz 3f | ||
74 | popl %esi # discard address | ||
75 | popl %esi # real mode pointer | ||
76 | xorl %ebx,%ebx | ||
77 | ljmp $(__BOOT_CS), $0x100000 | ||
78 | |||
79 | /* | ||
80 | * We come here, if we were loaded high. | ||
81 | * We need to move the move-in-place routine down to 0x1000 | ||
82 | * and then start it with the buffer addresses in registers, | ||
83 | * which we got from the stack. | ||
84 | */ | ||
85 | 3: | ||
86 | movl $move_routine_start,%esi | ||
87 | movl $0x1000,%edi | ||
88 | movl $move_routine_end,%ecx | ||
89 | subl %esi,%ecx | ||
90 | addl $3,%ecx | ||
91 | shrl $2,%ecx | ||
92 | cld | ||
93 | rep | ||
94 | movsl | ||
95 | |||
96 | popl %esi # discard the address | ||
97 | popl %ebx # real mode pointer | ||
98 | popl %esi # low_buffer_start | ||
99 | popl %ecx # lcount | ||
100 | popl %edx # high_buffer_start | ||
101 | popl %eax # hcount | ||
102 | movl $0x100000,%edi | ||
103 | cli # make sure we don't get interrupted | ||
104 | ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine | ||
105 | |||
106 | /* | ||
107 | * Routine (template) for moving the decompressed kernel in place, | ||
108 | * if we were high loaded. This _must_ PIC-code ! | ||
109 | */ | ||
110 | move_routine_start: | ||
111 | movl %ecx,%ebp | ||
112 | shrl $2,%ecx | ||
113 | rep | ||
114 | movsl | ||
115 | movl %ebp,%ecx | ||
116 | andl $3,%ecx | ||
117 | rep | ||
118 | movsb | ||
119 | movl %edx,%esi | ||
120 | movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 | ||
121 | addl $3,%ecx | ||
122 | shrl $2,%ecx | ||
123 | rep | ||
124 | movsl | ||
125 | movl %ebx,%esi # Restore setup pointer | ||
126 | xorl %ebx,%ebx | ||
127 | ljmp $(__BOOT_CS), $0x100000 | ||
128 | move_routine_end: | ||