Annotation of /tags/mkinitrd-6_1_12/isolinux/com32.inc
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
Original Path: trunk/mkinitrd-magellan/isolinux/com32.inc
File size: 8204 byte(s)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
Original Path: trunk/mkinitrd-magellan/isolinux/com32.inc
File size: 8204 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | niro | 532 | ;; $Id: com32.inc,v 1.1 2007-09-01 22:44:04 niro Exp $ |
2 | ;; ----------------------------------------------------------------------- | ||
3 | ;; | ||
4 | ;; Copyright 1994-2003 H. Peter Anvin - All Rights Reserved | ||
5 | ;; | ||
6 | ;; This program is free software; you can redistribute it and/or modify | ||
7 | ;; it under the terms of the GNU General Public License as published by | ||
8 | ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, | ||
9 | ;; Boston MA 02111-1307, USA; either version 2 of the License, or | ||
10 | ;; (at your option) any later version; incorporated herein by reference. | ||
11 | ;; | ||
12 | ;; ----------------------------------------------------------------------- | ||
13 | |||
14 | ;; | ||
15 | ;; com32.inc | ||
16 | ;; | ||
17 | ;; Common code for running a COM32 image | ||
18 | ;; | ||
19 | |||
20 | ; | ||
21 | ; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS | ||
22 | ; .com file. A COM32 image is loaded at address 0x101000, with %esp | ||
23 | ; set to the high end of usable memory. | ||
24 | ; | ||
25 | ; A COM32 image should begin with the magic bytes: | ||
26 | ; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and | ||
27 | ; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the | ||
28 | ; program with an error if run in 16-bit mode. | ||
29 | ; | ||
30 | pm_idt: equ 0x100000 | ||
31 | pm_entry: equ 0x101000 | ||
32 | |||
33 | bits 16 | ||
34 | section .data | ||
35 | align 2, db 0 | ||
36 | com32_pmidt: | ||
37 | dw 8*256 ; Limit | ||
38 | dd pm_idt ; Address | ||
39 | |||
40 | com32_rmidt: | ||
41 | dw 0ffffh ; Limit | ||
42 | dd 0 ; Address | ||
43 | |||
44 | section .text | ||
45 | is_com32_image: | ||
46 | push si ; Save file handle | ||
47 | push dx ; File length held in DX:AX | ||
48 | push ax | ||
49 | |||
50 | call make_plain_cmdline | ||
51 | ; Copy the command line into the low cmdline buffer | ||
52 | mov ax,real_mode_seg | ||
53 | mov fs,ax | ||
54 | mov si,cmd_line_here | ||
55 | mov di,command_line | ||
56 | mov cx,[CmdLinePtr] | ||
57 | inc cx ; Include final null | ||
58 | sub cx,si | ||
59 | fs rep movsb | ||
60 | |||
61 | call highmemsize ; We need the high memory size... | ||
62 | call comboot_setup_api ; Set up the COMBOOT-style API | ||
63 | |||
64 | mov edi,pm_entry ; Load address | ||
65 | pop eax ; File length | ||
66 | pop si ; File handle | ||
67 | xor dx,dx ; No padding | ||
68 | call load_high | ||
69 | call crlf | ||
70 | |||
71 | com32_start: | ||
72 | mov ebx,com32_call_start ; Where to go in PM | ||
73 | |||
74 | com32_enter_pm: | ||
75 | cli | ||
76 | mov ax,cs | ||
77 | mov ds,ax | ||
78 | mov [SavedSSSP],sp | ||
79 | mov [SavedSSSP+2],ss | ||
80 | cld | ||
81 | call a20_test | ||
82 | jnz .a20ok | ||
83 | call enable_a20 | ||
84 | |||
85 | .a20ok: | ||
86 | lgdt [bcopy_gdt] ; We can use the same GDT just fine | ||
87 | lidt [com32_pmidt] ; Set up the IDT | ||
88 | mov eax,cr0 | ||
89 | or al,1 | ||
90 | mov cr0,eax ; Enter protected mode | ||
91 | jmp 20h:.in_pm | ||
92 | |||
93 | bits 32 | ||
94 | .in_pm: | ||
95 | xor eax,eax ; Available for future use... | ||
96 | mov fs,eax | ||
97 | mov gs,eax | ||
98 | |||
99 | mov al,28h ; Set up data segments | ||
100 | mov es,eax | ||
101 | mov ds,eax | ||
102 | mov ss,eax | ||
103 | |||
104 | mov esp,[PMESP] ; Load protmode %esp if available | ||
105 | jmp ebx ; Go to where we need to go | ||
106 | |||
107 | ; | ||
108 | ; This is invoked right before the actually starting the COM32 | ||
109 | ; progam, in 32-bit mode... | ||
110 | ; | ||
111 | com32_call_start: | ||
112 | ; | ||
113 | ; Point the stack to the end of high memory | ||
114 | ; | ||
115 | mov esp,[word HighMemSize] | ||
116 | |||
117 | ; | ||
118 | ; Set up the protmode IDT and the interrupt jump buffers | ||
119 | ; We set these up in the system area at 0x100000, | ||
120 | ; but we could also put them beyond the stack. | ||
121 | ; | ||
122 | mov edi,pm_idt | ||
123 | |||
124 | ; Form an interrupt gate descriptor | ||
125 | mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff) | ||
126 | mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000) | ||
127 | xor ecx,ecx | ||
128 | inc ch ; ecx <- 256 | ||
129 | |||
130 | push ecx | ||
131 | .make_idt: | ||
132 | stosd | ||
133 | add eax,8 | ||
134 | xchg eax,ebx | ||
135 | stosd | ||
136 | xchg eax,ebx | ||
137 | loop .make_idt | ||
138 | |||
139 | pop ecx | ||
140 | |||
141 | ; Each entry in the interrupt jump buffer contains | ||
142 | ; the following instructions: | ||
143 | ; | ||
144 | ; 00000000 60 pushad | ||
145 | ; 00000001 B0xx mov al,<interrupt#> | ||
146 | ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt | ||
147 | |||
148 | mov eax,0e900b060h | ||
149 | mov ebx,com32_handle_interrupt-(pm_idt+8*256+8) | ||
150 | |||
151 | .make_ijb: | ||
152 | stosd | ||
153 | sub [edi-2],cl ; Interrupt # | ||
154 | xchg eax,ebx | ||
155 | stosd | ||
156 | sub eax,8 | ||
157 | xchg eax,ebx | ||
158 | loop .make_ijb | ||
159 | |||
160 | ; Now everything is set up for interrupts... | ||
161 | |||
162 | push dword com32_farcall ; Farcall entry point | ||
163 | push dword (1 << 16) ; 64K bounce buffer | ||
164 | push dword (comboot_seg << 4) ; Bounce buffer address | ||
165 | push dword com32_intcall ; Intcall entry point | ||
166 | push dword command_line ; Command line pointer | ||
167 | push dword 5 ; Argument count | ||
168 | sti ; Interrupts OK now | ||
169 | call pm_entry ; Run the program... | ||
170 | ; ... on return, fall through to com32_exit ... | ||
171 | |||
172 | com32_exit: | ||
173 | mov bx,com32_done ; Return to command loop | ||
174 | |||
175 | com32_enter_rm: | ||
176 | cli | ||
177 | cld | ||
178 | mov [PMESP],esp ; Save exit %esp | ||
179 | xor esp,esp ; Make sure the high bits are zero | ||
180 | jmp 08h:.in_pm16 ; Return to 16-bit mode first | ||
181 | |||
182 | bits 16 | ||
183 | .in_pm16: | ||
184 | mov ax,18h ; Real-mode-like segment | ||
185 | mov es,ax | ||
186 | mov ds,ax | ||
187 | mov ss,ax | ||
188 | mov fs,ax | ||
189 | mov gs,ax | ||
190 | |||
191 | lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT) | ||
192 | mov eax,cr0 | ||
193 | and al,~1 | ||
194 | mov cr0,eax | ||
195 | jmp 0:.in_rm | ||
196 | |||
197 | .in_rm: ; Back in real mode | ||
198 | mov ax,cs ; Set up sane segments | ||
199 | mov ds,ax | ||
200 | mov es,ax | ||
201 | mov fs,ax | ||
202 | mov gs,ax | ||
203 | lss sp,[SavedSSSP] ; Restore stack | ||
204 | jmp bx ; Go to whereever we need to go... | ||
205 | |||
206 | com32_done: | ||
207 | call disable_a20 | ||
208 | sti | ||
209 | jmp enter_command | ||
210 | |||
211 | ; | ||
212 | ; 16-bit support code | ||
213 | ; | ||
214 | bits 16 | ||
215 | |||
216 | ; | ||
217 | ; 16-bit interrupt-handling code | ||
218 | ; | ||
219 | com32_int_rm: | ||
220 | pushf ; Flags on stack | ||
221 | push cs ; Return segment | ||
222 | push word .cont ; Return address | ||
223 | push dword edx ; Segment:offset of IVT entry | ||
224 | retf ; Invoke IVT routine | ||
225 | .cont: ; ... on resume ... | ||
226 | mov ebx,com32_int_resume | ||
227 | jmp com32_enter_pm ; Go back to PM | ||
228 | |||
229 | ; | ||
230 | ; 16-bit system call handling code | ||
231 | ; | ||
232 | com32_sys_rm: | ||
233 | pop gs | ||
234 | pop fs | ||
235 | pop es | ||
236 | pop ds | ||
237 | popad | ||
238 | popfd | ||
239 | mov [cs:Com32SysSP],sp | ||
240 | retf ; Invoke routine | ||
241 | .return: | ||
242 | ; We clean up SP here because we don't know if the | ||
243 | ; routine returned with RET, RETF or IRET | ||
244 | mov sp,[cs:Com32SysSP] | ||
245 | pushfd | ||
246 | pushad | ||
247 | push ds | ||
248 | push es | ||
249 | push fs | ||
250 | push gs | ||
251 | mov ebx,com32_sys_resume | ||
252 | jmp com32_enter_pm | ||
253 | |||
254 | ; | ||
255 | ; 32-bit support code | ||
256 | ; | ||
257 | bits 32 | ||
258 | |||
259 | ; | ||
260 | ; This is invoked on getting an interrupt in protected mode. At | ||
261 | ; this point, we need to context-switch to real mode and invoke | ||
262 | ; the interrupt routine. | ||
263 | ; | ||
264 | ; When this gets invoked, the registers are saved on the stack and | ||
265 | ; AL contains the register number. | ||
266 | ; | ||
267 | com32_handle_interrupt: | ||
268 | movzx eax,al | ||
269 | xor ebx,ebx ; Actually makes the code smaller | ||
270 | mov edx,[ebx+eax*4] ; Get the segment:offset of the routine | ||
271 | mov bx,com32_int_rm | ||
272 | jmp com32_enter_rm ; Go to real mode | ||
273 | |||
274 | com32_int_resume: | ||
275 | popad | ||
276 | iret | ||
277 | |||
278 | ; | ||
279 | ; Intcall/farcall invocation. We manifest a structure on the real-mode stack, | ||
280 | ; containing the com32sys_t structure from <com32.h> as well as | ||
281 | ; the following entries (from low to high address): | ||
282 | ; - Target offset | ||
283 | ; - Target segment | ||
284 | ; - Return offset | ||
285 | ; - Return segment (== real mode cs == 0) | ||
286 | ; - Return flags | ||
287 | ; | ||
288 | com32_farcall: | ||
289 | pushfd ; Save IF among other things... | ||
290 | pushad ; We only need to save some, but... | ||
291 | |||
292 | mov eax,[esp+10*4] ; CS:IP | ||
293 | jmp com32_syscall | ||
294 | |||
295 | |||
296 | com32_intcall: | ||
297 | pushfd ; Save IF among other things... | ||
298 | pushad ; We only need to save some, but... | ||
299 | |||
300 | movzx eax,byte [esp+10*4] ; INT number | ||
301 | mov eax,[eax*4] ; Get CS:IP from low memory | ||
302 | |||
303 | com32_syscall: | ||
304 | cld | ||
305 | |||
306 | movzx edi,word [word SavedSSSP] | ||
307 | movzx ebx,word [word SavedSSSP+2] | ||
308 | sub edi,54 ; Allocate 54 bytes | ||
309 | mov [word SavedSSSP],di | ||
310 | shl ebx,4 | ||
311 | add edi,ebx ; Create linear address | ||
312 | |||
313 | mov esi,[esp+11*4] ; Source regs | ||
314 | xor ecx,ecx | ||
315 | mov cl,11 ; 44 bytes to copy | ||
316 | rep movsd | ||
317 | |||
318 | ; EAX is already set up to be CS:IP | ||
319 | stosd ; Save in stack frame | ||
320 | mov eax,com32_sys_rm.return ; Return seg:offs | ||
321 | stosd ; Save in stack frame | ||
322 | mov eax,[edi-12] ; Return flags | ||
323 | and eax,0x200cd7 ; Mask (potentially) unsafe flags | ||
324 | mov [edi-12],eax ; Primary flags entry | ||
325 | stosw ; Return flags | ||
326 | |||
327 | mov bx,com32_sys_rm | ||
328 | jmp com32_enter_rm ; Go to real mode | ||
329 | |||
330 | ; On return, the 44-byte return structure is on the | ||
331 | ; real-mode stack, plus the 10 additional bytes used | ||
332 | ; by the target address (see above.) | ||
333 | com32_sys_resume: | ||
334 | movzx esi,word [word SavedSSSP] | ||
335 | movzx eax,word [word SavedSSSP+2] | ||
336 | mov edi,[esp+12*4] ; Dest regs | ||
337 | shl eax,4 | ||
338 | add esi,eax ; Create linear address | ||
339 | and edi,edi ; NULL pointer? | ||
340 | jnz .do_copy | ||
341 | .no_copy: mov edi,esi ; Do a dummy copy-to-self | ||
342 | .do_copy: xor ecx,ecx | ||
343 | mov cl,11 ; 44 bytes | ||
344 | rep movsd ; Copy register block | ||
345 | |||
346 | add dword [word SavedSSSP],54 ; Remove from stack | ||
347 | |||
348 | popad | ||
349 | popfd | ||
350 | ret ; Return to 32-bit program | ||
351 | |||
352 | bits 16 | ||
353 | |||
354 | section .bss | ||
355 | alignb 4 | ||
356 | PMESP resd 1 ; Protected-mode ESP | ||
357 | Com32SysSP resw 1 ; SP saved during COM32 syscall | ||
358 | |||
359 | section .text |