Cleanup a20 code.
[seabios.git] / src / romlayout.S
1 // Rom layout and bios assembler to C interface.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
8 #include "config.h" // CONFIG_*
9 #include "ioport.h" // PORT_A20
10
11
12 /****************************************************************
13  * Include of 16bit C code
14  ****************************************************************/
15
16         .code16gcc
17 .include "out/blob.16.s"
18
19
20 /****************************************************************
21  * Entry macros
22  ****************************************************************/
23
24         // Call a C function - this does the minimal work necessary to
25         // call into C.  It sets up %ds, backs up %es, and backs up
26         // those registers that are call clobbered by the C compiler.
27         .macro ENTRY cfunc
28         cld
29         pushl %eax              // Save registers clobbered by C code
30         pushl %ecx
31         pushl %edx
32         pushw %es
33         pushw %ds
34         movw %ss, %ax           // Move %ss to %ds
35         movw %ax, %ds
36         pushl %esp              // Backup %esp, then clear high bits
37         movzwl %sp, %esp
38         calll \cfunc
39         popl %esp               // Restore %esp (including high bits)
40         popw %ds                // Restore registers saved above
41         popw %es
42         popl %edx
43         popl %ecx
44         popl %eax
45         .endm
46
47         // Call a C function with current register list as an
48         // argument.  This backs up the registers and sets %eax
49         // to point to the backup.  On return, the registers are
50         // restored from the structure.
51         .macro ENTRY_ARG cfunc
52         cld
53         pushl %eax              // Save registers (matches struct bregs)
54         pushl %ecx
55         pushl %edx
56         pushl %ebx
57         pushl %esi
58         pushl %edi
59         pushw %es
60         pushw %ds
61         movw %ss, %ax           // Move %ss to %ds
62         movw %ax, %ds
63         movl %esp, %ebx         // Backup %esp, then zero high bits
64         movzwl %sp, %esp
65         movl %esp, %eax         // First arg is pointer to struct bregs
66         calll \cfunc
67         movl %ebx, %esp         // Restore %esp (including high bits)
68         popw %ds                // Restore registers (from struct bregs)
69         popw %es
70         popl %edi
71         popl %esi
72         popl %ebx
73         popl %edx
74         popl %ecx
75         popl %eax
76         .endm
77
78         // As above, but don't mangle %esp
79         .macro ENTRY_ARG_ESP cfunc
80         cld
81         pushl %eax              // Save registers (matches struct bregs)
82         pushl %ecx
83         pushl %edx
84         pushl %ebx
85         pushl %esi
86         pushl %edi
87         pushw %es
88         pushw %ds
89         movw %ss, %ax           // Move %ss to %ds
90         movw %ax, %ds
91         movl %esp, %eax         // First arg is pointer to struct bregs
92         calll \cfunc
93         popw %ds                // Restore registers (from struct bregs)
94         popw %es
95         popl %edi
96         popl %esi
97         popl %ebx
98         popl %edx
99         popl %ecx
100         popl %eax
101         .endm
102
103         // Macro to reset the 16bit stack
104         // Clobbers %ax
105         .macro RESET_STACK
106         xorw %ax, %ax
107         movw %ax, %ss
108         movl $ BUILD_STACK_ADDR , %esp
109         cld
110         .endm
111
112         // Specify a location in the fixed part of bios area.
113         .macro ORG addr
114         .section .text.fixed.addr
115         .org \addr - BUILD_START_FIXED
116         .endm
117
118
119 /****************************************************************
120  * POST handler
121  ****************************************************************/
122
123         ORG 0xe05b
124 post16:
125         // enable cache
126         movl %cr0, %eax
127         andl $0x9fffffff, %eax
128         movl %eax, %cr0
129
130         // init the stack pointer
131         RESET_STACK
132
133         pushl $_code32__start
134
135         // Fall through to transition32 function below
136
137
138 /****************************************************************
139  * Call trampolines
140  ****************************************************************/
141
142 // Place CPU into 32bit mode from 16bit mode.
143 // Clobbers: %eax, flags, stack registers, cr0, idt/gdt
144 transition32:
145         // Disable irqs
146         cli
147
148         // enable a20
149         inb $PORT_A20, %al
150         orb $A20_ENABLE_BIT, %al
151         outb %al, $PORT_A20
152
153         // Set segment descriptors
154         lidt %cs:pmode_IDT_info
155         lgdt %cs:rombios32_gdt_48
156
157         // set PE bit in CR0
158         movl  %cr0, %eax
159         orb   $0x01, %al
160         movl  %eax, %cr0
161
162         // start protected mode code
163         ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
164
165         .code32
166 1:
167         // init data segments
168         movl $SEG32_MODE32_DS, %eax
169         movw %ax, %ds
170         movw %ax, %es
171         movw %ax, %ss
172         xorl %eax, %eax
173         movw %ax, %fs
174         movw %ax, %gs
175
176         retl
177
178 // Call a 16bit function from 32bit mode.
179 // %eax = address of struct bregs
180 // Clobbers: all gp registers, flags, stack registers, cr0, idt/gdt
181         .global __call16_from32
182 __call16_from32:
183         pushl %eax
184
185         // restore data segment limits to 0xffff
186         movw $SEG32_MODE16_DS, %ax
187         movw %ax, %ds
188         movw %ax, %es
189         movw %ax, %ss
190         movw %ax, %fs
191         movw %ax, %gs
192
193         // disable a20
194         inb $PORT_A20, %al
195         andb $~A20_ENABLE_BIT, %al
196         outb %al, $PORT_A20
197
198         // Jump to 16bit mode
199         ljmpw $SEG32_MODE16_CS, $1f
200
201         .code16gcc
202 1:
203         // reset PE bit in CR0
204         movl %cr0, %eax
205         andb $0xfe, %al
206         movl %eax, %cr0
207
208         // far jump to flush CPU queue after transition to real mode
209         ljmpw $SEG_BIOS, $2f
210
211 2:
212         // restore IDT to normal real-mode defaults
213         lidt %cs:rmode_IDT_info
214
215         // Clear segment registers
216         xorw %ax, %ax
217         movw %ax, %fs
218         movw %ax, %gs
219         movw %ax, %es
220         movw %ax, %ds
221         movw %ax, %ss  // Assume stack is in segment 0
222
223         popl %eax
224
225         // Set __call16 return address to be transition32
226         pushl $transition32
227
228         // Fall through to __call16
229
230
231 // Call a 16bit function from 16bit mode with a specified cpu register state
232 // %eax = address of struct bregs
233 // Clobbers: all gp registers, es
234         .global __call16
235 __call16:
236         // Save eax
237         pushl %eax
238
239         // Setup for iretw call
240         pushw $SEG_BIOS
241         pushw $1f               // return point
242         pushw 0x20(%eax)        // flags
243         pushl 0x1c(%eax)        // CS:IP
244
245         // Load calling registers.
246         movl 0x04(%eax), %edi
247         movl 0x08(%eax), %esi
248         movl 0x0c(%eax), %ebx
249         movl 0x10(%eax), %edx
250         movl 0x14(%eax), %ecx
251         movw 0x02(%eax), %es    // XXX - should load %ds too
252         movl 0x18(%eax), %eax
253
254         // Invoke call
255         iretw                   // XXX - just do a lcalll
256 1:
257         // Store flags, eax, ecx
258         pushfw
259         pushl %eax
260         movl 0x06(%esp), %eax
261         movl %ecx, %ss:0x14(%eax)       // Save %ecx
262         movw %ss, %cx
263         movw %cx, %ds                   // Restore %ds == %ss
264         popl %ecx
265         movl %ecx, 0x18(%eax)           // Save %eax
266         popw %cx
267         movw %cx, 0x20(%eax)            // Save flags
268
269         // Store remaining registers
270         movw %es, 0x02(%eax)
271         movl %edi, 0x04(%eax)
272         movl %esi, 0x08(%eax)
273         movl %ebx, 0x0c(%eax)
274         movl %edx, 0x10(%eax)
275
276         // Remove %eax
277         popl %eax
278
279         cld
280
281         retl
282
283
284 // APM trampolines
285         .global apm16protected_entry
286 apm16protected_entry:
287         pushfw          // save flags
288         pushl %eax      // dummy
289         ENTRY_ARG handle_1553
290         addw $4, %sp    // pop dummy
291         popfw           // restore flags
292         lretw
293
294         .code32
295         .global apm32protected_entry
296 apm32protected_entry:
297         pushfw
298         pushw %cs       // Setup for long jump to 16bit mode
299         pushw $1f
300         addw $8, 2(%esp)
301         ljmpw *(%esp)
302         .code16gcc
303 1:
304         ENTRY_ARG_ESP handle_1553
305
306         movw $2f,(%esp) // Setup for long jump back to 32bit mode
307         subw $8, 2(%esp)
308         ljmpw *(%esp)
309         .code32
310 2:
311         addl $4, %esp   // pop call address
312         popfw
313         lretl
314
315 // 32bit elf entry point
316         .global post32
317 post32:
318         cli
319         cld
320         lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
321         lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
322         movl $BUILD_STACK_ADDR, %esp
323         ljmpl $SEG32_MODE32_CS, $_code32__start
324
325         .code16gcc
326
327 // Shutdown a CPU.  We want this in the 0xf000 section to ensure that
328 // the code wont be overwritten with something else.  (Should
329 // something spurious wake up the CPU, we want to be sure that the hlt
330 // insn will still be present and will shutdown the CPU.)
331         .global permanent_halt
332 permanent_halt:
333         cli
334 1:      hlt
335         jmp 1b
336
337
338 /****************************************************************
339  * GDT and IDT tables
340  ****************************************************************/
341
342 // Protected mode IDT descriptor
343 //
344 // I just make the limit 0, so the machine will shutdown
345 // if an exception occurs during protected mode memory
346 // transfers.
347 //
348 // Set base to f0000 to correspond to beginning of BIOS,
349 // in case I actually define an IDT later
350 // Set limit to 0
351 pmode_IDT_info:
352         .word 0x0000  // limit 15:00
353         .long 0xf0000 // base 16:47
354
355 // Real mode IDT descriptor
356 //
357 // Set to typical real-mode values.
358 // base  = 000000
359 // limit =   03ff
360 rmode_IDT_info:
361         .word 0x03ff  // limit 15:00
362         .long 0       // base 16:47
363
364 rombios32_gdt_48:
365         .word 0x30
366         .word rombios32_gdt
367         .word 0x000f
368
369         .balign 8
370 rombios32_gdt:
371         .word 0, 0, 0, 0
372         .word 0, 0, 0, 0
373         // 32 bit flat code segment (SEG32_MODE32_CS)
374         .word 0xffff, 0, 0x9b00, 0x00cf
375         // 32 bit flat data segment (SEG32_MODE32_DS)
376         .word 0xffff, 0, 0x9300, 0x00cf
377         // 16 bit code segment base=0xf0000 limit=0xffff (SEG32_MODE16_CS)
378         .word 0xffff, 0, 0x9b0f, 0x0000
379         // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS)
380         .word 0xffff, 0, 0x9300, 0x0000
381
382 // We need a copy of this string in the 0xf000 segment, but we are not
383 // actually a PnP BIOS, so make sure it is *not* aligned, so OSes will
384 // not see it if they scan.
385         .global pnp_string
386         .balign 2
387         .byte 0
388 pnp_string:
389         .ascii "$PnP"
390
391
392 /****************************************************************
393  * Interrupt entry points
394  ****************************************************************/
395
396         // Define an entry point for an interrupt (no args passed).
397         .macro IRQ_ENTRY num
398         .global entry_\num
399         entry_\num :
400         cli         // In case something far-calls instead of using "int"
401         ENTRY handle_\num
402         iretw
403         .endm
404
405         // Define an entry point for an interrupt (can read/modify args).
406         .macro IRQ_ENTRY_ARG num
407         .global entry_\num
408         entry_\num :
409         cli         // In case something far-calls instead of using "int"
410         ENTRY_ARG handle_\num
411         iretw
412         .endm
413
414         ORG 0xe2c3
415         IRQ_ENTRY nmi
416
417         IRQ_ENTRY_ARG 13
418         IRQ_ENTRY_ARG 12
419         IRQ_ENTRY_ARG 11
420         IRQ_ENTRY 76
421         IRQ_ENTRY 1c
422         IRQ_ENTRY 70
423
424         ORG 0xe3fe
425         jmp entry_13
426
427         ORG 0xe401
428         // XXX - Fixed Disk Parameter Table
429
430         ORG 0xe6f2
431         jmp entry_19
432
433         ORG 0xe6f5
434 .include "out/cbt.proc.16.s"
435         .text
436
437         ORG 0xe729
438         // XXX - Baud Rate Generator Table
439
440         ORG 0xe739
441         IRQ_ENTRY_ARG 14
442
443         IRQ_ENTRY 74
444         IRQ_ENTRY 75
445
446         // int 18/19 are special - they reset the stack and do not return.
447         .global entry_19
448 entry_19:
449         RESET_STACK
450         pushl $_code32_handle_19
451         jmp transition32
452
453         .global entry_18
454 entry_18:
455         RESET_STACK
456         pushl $_code32_handle_18
457         jmp transition32
458
459         // IRQ trampolines
460         .macro IRQ_TRAMPOLINE num
461         .global irq_trampoline_0x\num
462         irq_trampoline_0x\num :
463         int $0x\num
464         lretw
465         .endm
466
467         IRQ_TRAMPOLINE 02
468         IRQ_TRAMPOLINE 10
469         IRQ_TRAMPOLINE 13
470         IRQ_TRAMPOLINE 15
471         IRQ_TRAMPOLINE 16
472         IRQ_TRAMPOLINE 18
473         IRQ_TRAMPOLINE 19
474         IRQ_TRAMPOLINE 1c
475         IRQ_TRAMPOLINE 4a
476
477         ORG 0xe82e
478         IRQ_ENTRY_ARG 16
479
480 entry_hwirq:
481         ENTRY handle_hwirq
482
483         ORG 0xe987
484         IRQ_ENTRY 09
485
486         ORG 0xec59
487         IRQ_ENTRY_ARG 40
488
489         ORG 0xef57
490         IRQ_ENTRY 0e
491
492         ORG 0xefc7
493 .include "out/floppy_dbt.proc.16.s"
494         .text
495
496         ORG 0xefd2
497         IRQ_ENTRY_ARG 17
498
499         ORG 0xf045
500         // XXX int 10
501         iretw
502
503         ORG 0xf065
504         IRQ_ENTRY_ARG 10
505
506         ORG 0xf0a4
507         // XXX int 1D
508         iretw
509
510         .global freespace2_start, freespace2_end
511 freespace2_start:
512
513         ORG 0xf841
514 freespace2_end:
515         jmp entry_12
516
517         ORG 0xf84d
518         jmp entry_11
519
520         ORG 0xf859
521         IRQ_ENTRY_ARG 15
522
523         ORG 0xfa6e
524 .include "out/font.proc.16.s"
525         .text
526
527         ORG 0xfe6e
528         IRQ_ENTRY_ARG 1a
529
530         ORG 0xfea5
531         IRQ_ENTRY 08
532
533         ORG 0xfef3
534         // XXX - Initial Interrupt Vector Offsets Loaded by POST
535
536         ORG 0xff00
537         // XXX - BIOS_COPYRIGHT_STRING
538         .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
539
540         ORG 0xff53
541         .global dummy_iret_handler
542 dummy_iret_handler:
543         iretw
544
545         ORG 0xff54
546         IRQ_ENTRY_ARG 05
547
548         ORG 0xfff0 // Power-up Entry Point
549         ljmpw $SEG_BIOS, $post16
550
551         ORG 0xfff5
552         // BIOS build date
553         .ascii "06/23/99"
554
555         ORG 0xfffe
556         .byte CONFIG_MODEL_ID
557
558         .global bios_checksum
559 bios_checksum:
560         .byte 0x00
561
562         .end