1 ;; -----------------------------------------------------------------------
3 ;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
5 ;; This program is free software; you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 ;; Boston MA 02111-1307, USA; either version 2 of the License, or
9 ;; (at your option) any later version; incorporated herein by reference.
11 ;; -----------------------------------------------------------------------
16 ;; Common code for running a COM32 image
20 ; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS
21 ; .com file. A COM32 image is loaded at address 0x101000, with %esp
22 ; set to the high end of usable memory.
24 ; A COM32 image should begin with the magic bytes:
25 ; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and
26 ; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the
27 ; program with an error if run in 16-bit mode.
30 pm_entry: equ 0x101000
45 push si ; Save file handle
46 push eax ; Save file length
48 call make_plain_cmdline
49 ; Copy the command line into the low cmdline buffer
55 inc cx ; Include final null
59 call comboot_setup_api ; Set up the COMBOOT-style API
61 mov edi,pm_entry ; Load address
64 xor dx,dx ; No padding
65 mov bx,abort_check ; Don't print dots, but allow abort
69 mov ebx,com32_call_start ; Where to go in PM
76 mov [RealModeSSSP+2],ss
83 mov byte [bcopy_gdt.TSS+5],89h ; Mark TSS unbusy
85 lgdt [bcopy_gdt] ; We can use the same GDT just fine
86 lidt [com32_pmidt] ; Set up the IDT
89 mov cr0,eax ; Enter protected mode
94 xor eax,eax ; Available for future use...
99 mov al,PM_DS32 ; Set up data segments
104 mov al,PM_TSS ; Be nice to Intel's VT by
105 ltr ax ; giving it a valid TR
107 mov esp,[PMESP] ; Load protmode %esp if available
108 jmp ebx ; Go to where we need to go
111 ; This is invoked right before the actually starting the COM32
112 ; progam, in 32-bit mode...
116 ; Point the stack to the end of (permitted) high memory
118 mov esp,[word HighMemRsvd]
119 xor sp,sp ; Align to a 64K boundary
122 ; Set up the protmode IDT and the interrupt jump buffers
123 ; We set these up in the system area at 0x100000,
124 ; but we could also put them beyond the stack.
128 ; Form an interrupt gate descriptor
129 mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
130 mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
145 ; Each entry in the interrupt jump buffer contains
146 ; the following instructions:
149 ; 00000001 B0xx mov al,<interrupt#>
150 ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt
153 mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
157 sub [edi-2],cl ; Interrupt #
164 ; Now everything is set up for interrupts...
166 push dword com32_cfarcall ; Cfarcall entry point
167 push dword com32_farcall ; Farcall entry point
168 push dword (1 << 16) ; 64K bounce buffer
169 push dword (comboot_seg << 4) ; Bounce buffer address
170 push dword com32_intcall ; Intcall entry point
171 push dword command_line ; Command line pointer
172 push dword 6 ; Argument count
173 sti ; Interrupts OK now
174 call pm_entry ; Run the program...
175 ; ... on return, fall through to com32_exit ...
178 mov bx,com32_done ; Return to command loop
183 mov [PMESP],esp ; Save exit %esp
184 xor esp,esp ; Make sure the high bits are zero
185 jmp PM_CS16:.in_pm16 ; Return to 16-bit mode first
189 mov ax,PM_DS16_RM ; Real-mode-like segment
196 lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT)
202 .in_rm: ; Back in real mode
203 mov ax,cs ; Set up sane segments
208 lss sp,[RealModeSSSP] ; Restore stack
209 jmp bx ; Go to whereever we need to go...
219 ; 16-bit support code
224 ; 16-bit interrupt-handling code
227 pushf ; Flags on stack
228 push cs ; Return segment
229 push word .cont ; Return address
230 push dword edx ; Segment:offset of IVT entry
231 retf ; Invoke IVT routine
232 .cont: ; ... on resume ...
233 mov ebx,com32_int_resume
234 jmp com32_enter_pm ; Go back to PM
237 ; 16-bit intcall/farcall handling code
246 mov [cs:Com32SysSP],sp
247 retf ; Invoke routine
249 ; We clean up SP here because we don't know if the
250 ; routine returned with RET, RETF or IRET
251 mov sp,[cs:Com32SysSP]
258 mov ebx,com32_syscall.resume
262 ; 16-bit cfarcall handing code
267 mov sp,[cs:Com32SysSP]
268 mov [cs:RealModeEAX],eax
269 mov ebx,com32_cfarcall.resume
273 ; 32-bit support code
278 ; This is invoked on getting an interrupt in protected mode. At
279 ; this point, we need to context-switch to real mode and invoke
280 ; the interrupt routine.
282 ; When this gets invoked, the registers are saved on the stack and
283 ; AL contains the register number.
285 com32_handle_interrupt:
287 xor ebx,ebx ; Actually makes the code smaller
288 mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
290 jmp com32_enter_rm ; Go to real mode
297 ; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
298 ; containing the com32sys_t structure from <com32.h> as well as
299 ; the following entries (from low to high address):
303 ; - Return segment (== real mode cs == 0)
307 pushfd ; Save IF among other things...
308 pushad ; We only need to save some, but...
310 mov eax,[esp+10*4] ; CS:IP
315 pushfd ; Save IF among other things...
316 pushad ; We only need to save some, but...
318 movzx eax,byte [esp+10*4] ; INT number
319 mov eax,[eax*4] ; Get CS:IP from low memory
324 movzx edi,word [word RealModeSSSP]
325 movzx ebx,word [word RealModeSSSP+2]
326 sub edi,54 ; Allocate 54 bytes
327 mov [word RealModeSSSP],di
329 add edi,ebx ; Create linear address
331 mov esi,[esp+11*4] ; Source regs
333 mov cl,11 ; 44 bytes to copy
336 ; EAX is already set up to be CS:IP
337 stosd ; Save in stack frame
338 mov eax,com32_sys_rm.return ; Return seg:offs
339 stosd ; Save in stack frame
340 mov eax,[edi-12] ; Return flags
341 and eax,0x200cd7 ; Mask (potentially) unsafe flags
342 mov [edi-12],eax ; Primary flags entry
346 jmp com32_enter_rm ; Go to real mode
348 ; On return, the 44-byte return structure is on the
349 ; real-mode stack, plus the 10 additional bytes used
350 ; by the target address (see above.)
352 movzx esi,word [word RealModeSSSP]
353 movzx eax,word [word RealModeSSSP+2]
354 mov edi,[esp+12*4] ; Dest regs
356 add esi,eax ; Create linear address
357 and edi,edi ; NULL pointer?
359 .no_copy: mov edi,esi ; Do a dummy copy-to-self
360 .do_copy: xor ecx,ecx
362 rep movsd ; Copy register block
364 add dword [word RealModeSSSP],54 ; Remove from stack
368 ret ; Return to 32-bit program
371 ; Cfarcall invocation. We copy the stack frame to the real-mode stack,
372 ; followed by the return CS:IP and the CS:IP of the target function.
379 mov ecx,[esp+12*4] ; Size of stack frame
381 movzx edi,word [word RealModeSSSP]
382 movzx ebx,word [word RealModeSSSP+2]
383 mov [word Com32SysSP],di
384 sub edi,ecx ; Allocate space for stack frame
386 sub edi,4*2 ; Return pointer, return value
387 mov [word RealModeSSSP],di
389 add edi,ebx ; Create linear address
391 mov eax,[esp+10*4] ; CS:IP
392 stosd ; Save to stack frame
393 mov eax,com32_cfar_rm.return ; Return seg:off
395 mov esi,[esp+11*4] ; Stack frame
396 mov eax,ecx ; Copy the stack frame
408 mov eax,[word RealModeEAX]
416 RealModeSSSP resd 1 ; Real-mode SS:SP
417 RealModeEAX resd 1 ; Real mode EAX
418 PMESP resd 1 ; Protected-mode ESP
419 Com32SysSP resw 1 ; SP saved during COM32 syscall