2 ;; -----------------------------------------------------------------------
4 ;; Copyright 1994-2003 H. Peter Anvin - All Rights Reserved
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.
12 ;; -----------------------------------------------------------------------
17 ;; Common code for running a COM32 image
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.
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.
31 pm_entry: equ 0x101000
44 push si ; Save file handle
45 push dx ; File length held in DX:AX
48 call make_plain_cmdline
49 ; Copy the command line into the low cmdline buffer
55 inc cx ; Include final null
59 call highmemsize ; We need the high memory size...
60 call comboot_setup_api ; Set up the COMBOOT-style API
62 mov edi,pm_entry ; Load address
69 mov ebx,com32_call_start ; Where to go in PM
83 lgdt [bcopy_gdt] ; We can use the same GDT just fine
84 lidt [com32_pmidt] ; Set up the IDT
87 mov cr0,eax ; Enter protected mode
92 xor eax,eax ; Available for future use...
96 mov al,28h ; Set up data segments
101 mov esp,[PMESP] ; Load protmode %esp if available
102 jmp ebx ; Go to where we need to go
105 ; This is invoked right before the actually starting the COM32
106 ; progam, in 32-bit mode...
110 ; Point the stack to the end of high memory
112 mov esp,[word HighMemSize]
115 ; Set up the protmode IDT and the interrupt jump buffers
116 ; We set these up in the system area at 0x100000,
117 ; but we could also put them beyond the stack.
121 ; Form an interrupt gate descriptor
122 mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
123 mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
138 ; Each entry in the interrupt jump buffer contains
139 ; the following instructions:
142 ; 00000001 B0xx mov al,<interrupt#>
143 ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt
146 mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
150 sub [edi-2],cl ; Interrupt #
157 ; Now everything is set up for interrupts...
159 push dword com32_farcall ; Farcall entry point
160 push dword (1 << 16) ; 64K bounce buffer
161 push dword (comboot_seg << 4) ; Bounce buffer address
162 push dword com32_intcall ; Intcall entry point
163 push dword command_line ; Command line pointer
164 push dword 5 ; Argument count
165 sti ; Interrupts OK now
166 call pm_entry ; Run the program...
167 ; ... on return, fall through to com32_exit ...
170 mov bx,com32_done ; Return to command loop
175 mov [PMESP],esp ; Save exit %esp
176 xor esp,esp ; Make sure the high bits are zero
177 jmp 08h:.in_pm16 ; Return to 16-bit mode first
181 mov ax,18h ; Real-mode-like segment
188 lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT)
194 .in_rm: ; Back in real mode
195 mov ax,cs ; Set up sane segments
200 lss sp,[SavedSSSP] ; Restore stack
201 jmp bx ; Go to whereever we need to go...
209 ; 16-bit support code
214 ; 16-bit interrupt-handling code
217 pushf ; Flags on stack
218 push cs ; Return segment
219 push word .cont ; Return address
220 push dword edx ; Segment:offset of IVT entry
221 retf ; Invoke IVT routine
222 .cont: ; ... on resume ...
223 mov ebx,com32_int_resume
224 jmp com32_enter_pm ; Go back to PM
227 ; 16-bit system call handling code
236 mov [cs:Com32SysSP],sp
237 retf ; Invoke routine
239 ; We clean up SP here because we don't know if the
240 ; routine returned with RET, RETF or IRET
241 mov sp,[cs:Com32SysSP]
248 mov ebx,com32_sys_resume
252 ; 32-bit support code
257 ; This is invoked on getting an interrupt in protected mode. At
258 ; this point, we need to context-switch to real mode and invoke
259 ; the interrupt routine.
261 ; When this gets invoked, the registers are saved on the stack and
262 ; AL contains the register number.
264 com32_handle_interrupt:
266 xor ebx,ebx ; Actually makes the code smaller
267 mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
269 jmp com32_enter_rm ; Go to real mode
276 ; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
277 ; containing the com32sys_t structure from <com32.h> as well as
278 ; the following entries (from low to high address):
282 ; - Return segment (== real mode cs == 0)
286 pushfd ; Save IF among other things...
287 pushad ; We only need to save some, but...
289 mov eax,[esp+10*4] ; CS:IP
294 pushfd ; Save IF among other things...
295 pushad ; We only need to save some, but...
297 movzx eax,byte [esp+10*4] ; INT number
298 mov eax,[eax*4] ; Get CS:IP from low memory
303 movzx edi,word [word SavedSSSP]
304 movzx ebx,word [word SavedSSSP+2]
305 sub edi,54 ; Allocate 54 bytes
306 mov [word SavedSSSP],di
308 add edi,ebx ; Create linear address
310 mov esi,[esp+11*4] ; Source regs
312 mov cl,11 ; 44 bytes to copy
315 ; EAX is already set up to be CS:IP
316 stosd ; Save in stack frame
317 mov eax,com32_sys_rm.return ; Return seg:offs
318 stosd ; Save in stack frame
319 mov eax,[edi-12] ; Return flags
320 and eax,0x200cd7 ; Mask (potentially) unsafe flags
321 mov [edi-12],eax ; Primary flags entry
325 jmp com32_enter_rm ; Go to real mode
327 ; On return, the 44-byte return structure is on the
328 ; real-mode stack, plus the 10 additional bytes used
329 ; by the target address (see above.)
331 movzx esi,word [word SavedSSSP]
332 movzx eax,word [word SavedSSSP+2]
333 mov edi,[esp+12*4] ; Dest regs
335 add esi,eax ; Create linear address
336 and edi,edi ; NULL pointer?
338 .no_copy: mov edi,esi ; Do a dummy copy-to-self
339 .do_copy: xor ecx,ecx
341 rep movsd ; Copy register block
343 add dword [word SavedSSSP],54 ; Remove from stack
347 ret ; Return to 32-bit program