More fixes to the extlinux installer; change back to writable types
[profile/ivi/syslinux.git] / com32.inc
1 ;; $Id$
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                 call load_high
68                 call crlf
69
70 com32_start:
71                 mov ebx,com32_call_start        ; Where to go in PM
72
73 com32_enter_pm:
74                 cli
75                 mov ax,cs
76                 mov ds,ax
77                 mov [SavedSSSP],sp
78                 mov [SavedSSSP+2],ss
79                 cld
80                 call a20_test
81                 jnz .a20ok
82                 call enable_a20
83
84 .a20ok:
85                 lgdt [bcopy_gdt]        ; We can use the same GDT just fine
86                 lidt [com32_pmidt]      ; Set up the IDT
87                 mov eax,cr0
88                 or al,1
89                 mov cr0,eax             ; Enter protected mode
90                 jmp 20h:.in_pm
91                 
92                 bits 32
93 .in_pm:
94                 xor eax,eax             ; Available for future use...
95                 mov fs,eax
96                 mov gs,eax
97
98                 mov al,28h              ; Set up data segments
99                 mov es,eax
100                 mov ds,eax
101                 mov ss,eax
102
103                 mov esp,[PMESP]         ; Load protmode %esp if available
104                 jmp ebx                 ; Go to where we need to go
105
106 ;
107 ; This is invoked right before the actually starting the COM32
108 ; progam, in 32-bit mode...
109 ;
110 com32_call_start:
111                 ;
112                 ; Point the stack to the end of high memory
113                 ;
114                 mov esp,[word HighMemSize]
115
116                 ;
117                 ; Set up the protmode IDT and the interrupt jump buffers
118                 ; We set these up in the system area at 0x100000,
119                 ; but we could also put them beyond the stack.
120                 ;
121                 mov edi,pm_idt
122
123                 ; Form an interrupt gate descriptor
124                 mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
125                 mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
126                 xor ecx,ecx
127                 inc ch                          ; ecx <- 256
128
129                 push ecx
130 .make_idt:
131                 stosd
132                 add eax,8
133                 xchg eax,ebx
134                 stosd
135                 xchg eax,ebx
136                 loop .make_idt
137
138                 pop ecx
139
140                 ; Each entry in the interrupt jump buffer contains
141                 ; the following instructions:
142                 ;
143                 ; 00000000 60                pushad
144                 ; 00000001 B0xx              mov al,<interrupt#>
145                 ; 00000003 E9xxxxxxxx        jmp com32_handle_interrupt
146
147                 mov eax,0e900b060h
148                 mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
149
150 .make_ijb:
151                 stosd
152                 sub [edi-2],cl                  ; Interrupt #
153                 xchg eax,ebx
154                 stosd
155                 sub eax,8
156                 xchg eax,ebx
157                 loop .make_ijb
158
159                 ; Now everything is set up for interrupts...
160
161                 push dword com32_farcall        ; Farcall entry point
162                 push dword (1 << 16)            ; 64K bounce buffer
163                 push dword (comboot_seg << 4)   ; Bounce buffer address
164                 push dword com32_intcall        ; Intcall entry point
165                 push dword command_line         ; Command line pointer
166                 push dword 5                    ; Argument count
167                 sti                             ; Interrupts OK now
168                 call pm_entry                   ; Run the program...
169                 ; ... on return, fall through to com32_exit ...
170
171 com32_exit:
172                 mov bx,com32_done       ; Return to command loop
173
174 com32_enter_rm:
175                 cli
176                 cld
177                 mov [PMESP],esp         ; Save exit %esp
178                 xor esp,esp             ; Make sure the high bits are zero
179                 jmp 08h:.in_pm16        ; Return to 16-bit mode first
180
181                 bits 16
182 .in_pm16:
183                 mov ax,18h              ; Real-mode-like segment
184                 mov es,ax
185                 mov ds,ax
186                 mov ss,ax
187                 mov fs,ax
188                 mov gs,ax
189
190                 lidt [com32_rmidt]      ; Real-mode IDT (rm needs no GDT)
191                 mov eax,cr0
192                 and al,~1
193                 mov cr0,eax
194                 jmp 0:.in_rm
195
196 .in_rm:                                 ; Back in real mode
197                 mov ax,cs               ; Set up sane segments
198                 mov ds,ax
199                 mov es,ax
200                 mov fs,ax
201                 mov gs,ax
202                 lss sp,[SavedSSSP]      ; Restore stack
203                 jmp bx                  ; Go to whereever we need to go...
204
205 com32_done:
206                 call disable_a20
207                 sti
208                 jmp enter_command
209
210 ;
211 ; 16-bit support code
212 ;
213                 bits 16
214
215 ;
216 ; 16-bit interrupt-handling code
217 ;
218 com32_int_rm:
219                 pushf                           ; Flags on stack
220                 push cs                         ; Return segment
221                 push word .cont                 ; Return address
222                 push dword edx                  ; Segment:offset of IVT entry
223                 retf                            ; Invoke IVT routine
224 .cont:          ; ... on resume ...
225                 mov ebx,com32_int_resume
226                 jmp com32_enter_pm              ; Go back to PM
227
228 ;
229 ; 16-bit system call handling code
230 ;
231 com32_sys_rm:
232                 pop gs
233                 pop fs
234                 pop es
235                 pop ds
236                 popad
237                 popfd
238                 mov [cs:Com32SysSP],sp
239                 retf                            ; Invoke routine
240 .return:
241                 ; We clean up SP here because we don't know if the
242                 ; routine returned with RET, RETF or IRET
243                 mov sp,[cs:Com32SysSP]
244                 pushfd
245                 pushad
246                 push ds
247                 push es
248                 push fs
249                 push gs
250                 mov ebx,com32_sys_resume
251                 jmp com32_enter_pm
252
253 ;
254 ; 32-bit support code
255 ;
256                 bits 32
257
258 ;
259 ; This is invoked on getting an interrupt in protected mode.  At
260 ; this point, we need to context-switch to real mode and invoke
261 ; the interrupt routine.
262 ;
263 ; When this gets invoked, the registers are saved on the stack and
264 ; AL contains the register number.
265 ;
266 com32_handle_interrupt:
267                 movzx eax,al
268                 xor ebx,ebx             ; Actually makes the code smaller
269                 mov edx,[ebx+eax*4]     ; Get the segment:offset of the routine
270                 mov bx,com32_int_rm
271                 jmp com32_enter_rm      ; Go to real mode
272
273 com32_int_resume:
274                 popad
275                 iret
276
277 ;
278 ; Intcall/farcall invocation.  We manifest a structure on the real-mode stack,
279 ; containing the com32sys_t structure from <com32.h> as well as
280 ; the following entries (from low to high address):
281 ; - Target offset
282 ; - Target segment
283 ; - Return offset
284 ; - Return segment (== real mode cs == 0)
285 ; - Return flags
286 ;
287 com32_farcall:
288                 pushfd                          ; Save IF among other things...
289                 pushad                          ; We only need to save some, but...
290
291                 mov eax,[esp+10*4]              ; CS:IP
292                 jmp com32_syscall
293
294
295 com32_intcall:
296                 pushfd                          ; Save IF among other things...
297                 pushad                          ; We only need to save some, but...
298
299                 movzx eax,byte [esp+10*4]       ; INT number
300                 mov eax,[eax*4]                 ; Get CS:IP from low memory
301
302 com32_syscall:
303                 cld
304
305                 movzx edi,word [word SavedSSSP]
306                 movzx ebx,word [word SavedSSSP+2]
307                 sub edi,54              ; Allocate 54 bytes
308                 mov [word SavedSSSP],di
309                 shl ebx,4
310                 add edi,ebx             ; Create linear address
311
312                 mov esi,[esp+11*4]      ; Source regs
313                 xor ecx,ecx
314                 mov cl,11               ; 44 bytes to copy
315                 rep movsd
316
317                 ; EAX is already set up to be CS:IP
318                 stosd                   ; Save in stack frame
319                 mov eax,com32_sys_rm.return     ; Return seg:offs
320                 stosd                   ; Save in stack frame
321                 mov eax,[edi-12]        ; Return flags
322                 and eax,0x200cd7        ; Mask (potentially) unsafe flags
323                 mov [edi-12],eax        ; Primary flags entry
324                 stosw                   ; Return flags
325
326                 mov bx,com32_sys_rm
327                 jmp com32_enter_rm      ; Go to real mode
328
329                 ; On return, the 44-byte return structure is on the
330                 ; real-mode stack, plus the 10 additional bytes used
331                 ; by the target address (see above.)
332 com32_sys_resume:
333                 movzx esi,word [word SavedSSSP]
334                 movzx eax,word [word SavedSSSP+2]
335                 mov edi,[esp+12*4]      ; Dest regs
336                 shl eax,4
337                 add esi,eax             ; Create linear address
338                 and edi,edi             ; NULL pointer?
339                 jnz .do_copy
340 .no_copy:       mov edi,esi             ; Do a dummy copy-to-self
341 .do_copy:       xor ecx,ecx
342                 mov cl,11               ; 44 bytes
343                 rep movsd               ; Copy register block
344
345                 add dword [word SavedSSSP],54   ; Remove from stack
346
347                 popad
348                 popfd
349                 ret                     ; Return to 32-bit program
350
351                 bits 16
352
353                 section .bss
354                 alignb 4
355 PMESP           resd 1                  ; Protected-mode ESP
356 Com32SysSP      resw 1                  ; SP saved during COM32 syscall
357
358                 section .text