Change license from GPLv3 to LGPLv3.
[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 LGPLv3 license.
7
8 #include "config.h" // CONFIG_*
9 #include "ioport.h" // PORT_A20
10 #include "bregs.h" // CR0_*
11 #include "cmos.h" // CMOS_RESET_CODE
12 #include "../out/asm-offsets.h" // BREGS_*
13
14
15 /****************************************************************
16  * Include of 16bit C code
17  ****************************************************************/
18
19         .code16gcc
20 .include "out/ccode.16.s"
21
22
23 /****************************************************************
24  * Entry macros
25  ****************************************************************/
26
27         // Call a C function - this does the minimal work necessary to
28         // call into C.  It sets up %ds, backs up %es, and backs up
29         // those registers that are call clobbered by the C compiler.
30         .macro ENTRY cfunc
31         cld
32         pushl %eax              // Save registers clobbered by C code
33         pushl %ecx
34         pushl %edx
35         pushw %es
36         pushw %ds
37         movw %ss, %ax           // Move %ss to %ds
38         movw %ax, %ds
39         pushl %esp              // Backup %esp, then clear high bits
40         movzwl %sp, %esp
41         calll \cfunc
42         popl %esp               // Restore %esp (including high bits)
43         popw %ds                // Restore registers saved above
44         popw %es
45         popl %edx
46         popl %ecx
47         popl %eax
48         .endm
49
50         // Call a C function with current register list as an
51         // argument.  This backs up the registers and sets %eax
52         // to point to the backup.  On return, the registers are
53         // restored from the structure.
54         .macro ENTRY_ARG cfunc
55         cld
56         pushl %eax              // Save registers (matches struct bregs)
57         pushl %ecx
58         pushl %edx
59         pushl %ebx
60         pushl %esi
61         pushl %edi
62         pushw %es
63         pushw %ds
64         movw %ss, %ax           // Move %ss to %ds
65         movw %ax, %ds
66         movl %esp, %ebx         // Backup %esp, then zero high bits
67         movzwl %sp, %esp
68         movl %esp, %eax         // First arg is pointer to struct bregs
69         calll \cfunc
70         movl %ebx, %esp         // Restore %esp (including high bits)
71         popw %ds                // Restore registers (from struct bregs)
72         popw %es
73         popl %edi
74         popl %esi
75         popl %ebx
76         popl %edx
77         popl %ecx
78         popl %eax
79         .endm
80
81         // As above, but don't mangle %esp
82         .macro ENTRY_ARG_ESP cfunc
83         cld
84         pushl %eax              // Save registers (matches struct bregs)
85         pushl %ecx
86         pushl %edx
87         pushl %ebx
88         pushl %esi
89         pushl %edi
90         pushw %es
91         pushw %ds
92         movw %ss, %ax           // Move %ss to %ds
93         movw %ax, %ds
94         movl %esp, %eax         // First arg is pointer to struct bregs
95         calll \cfunc
96         popw %ds                // Restore registers (from struct bregs)
97         popw %es
98         popl %edi
99         popl %esi
100         popl %ebx
101         popl %edx
102         popl %ecx
103         popl %eax
104         .endm
105
106         // Macro to reset the 16bit stack
107         // Clobbers %ax
108         .macro RESET_STACK
109         xorw %ax, %ax
110         movw %ax, %ss
111         movl $ BUILD_STACK_ADDR , %esp
112         cld
113         .endm
114
115         // Specify a location in the fixed part of bios area.
116         .macro ORG addr
117         .section .text.fixed.addr
118         .org \addr - BUILD_START_FIXED
119         .endm
120
121
122 /****************************************************************
123  * POST handler
124  ****************************************************************/
125
126         ORG 0xe05b
127 post16:
128         // enable cache
129         movl %cr0, %eax
130         andl $~(CR0_CD|CR0_NW), %eax
131         movl %eax, %cr0
132
133         // Check for restart indicator.
134         movl $CMOS_RESET_CODE, %eax
135         outb %al, $PORT_CMOS_INDEX
136         inb $PORT_CMOS_DATA, %al
137         cmpb $0x0, %al
138         jnz entry_resume
139
140         // Normal entry point
141         RESET_STACK
142
143         pushl $_code32__start
144
145         // Fall through to transition32 function below
146
147
148 /****************************************************************
149  * Call trampolines
150  ****************************************************************/
151
152 // Place CPU into 32bit mode from 16bit mode.
153 // Clobbers: %eax, flags, stack registers, cr0, idt/gdt
154 transition32:
155         // Disable irqs
156         cli
157
158         // enable a20
159         inb $PORT_A20, %al
160         orb $A20_ENABLE_BIT, %al
161         outb %al, $PORT_A20
162
163         // Set segment descriptors
164         lidtw %cs:pmode_IDT_info
165         lgdtw %cs:rombios32_gdt_48
166
167         // Enable protected mode
168         movl %cr0, %eax
169         orl $CR0_PE, %eax
170         movl %eax, %cr0
171
172         // start 32bit protected mode code
173         ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
174
175         .code32
176 1:
177         // init data segments
178         movl $SEG32_MODE32_DS, %eax
179         movw %ax, %ds
180         movw %ax, %es
181         movw %ax, %ss
182         movw %ax, %fs
183         movw %ax, %gs
184
185         retl
186
187 // Call a 16bit function from 32bit mode.
188 // %eax = address of struct bregs
189 // Clobbers: all gp registers, flags, stack registers, cr0, idt/gdt
190         .global __call16_from32, __call16big_from32
191 __call16_from32:
192         pushl %eax
193
194         // restore data segment limits to 0xffff
195         movl $SEG32_MODE16_DS, %eax
196         movw %ax, %ds
197         movw %ax, %es
198         movw %ax, %ss
199         movw %ax, %fs
200         movw %ax, %gs
201
202         // disable a20
203         inb $PORT_A20, %al
204         andb $~A20_ENABLE_BIT, %al
205         outb %al, $PORT_A20
206
207         // Jump to 16bit mode
208         ljmpw $SEG32_MODE16_CS, $1f
209
210 __call16big_from32:
211         pushl %eax
212
213         movl $SEG32_MODE16BIG_DS, %eax
214         movw %ax, %ds
215         movw %ax, %es
216         movw %ax, %ss
217         movw %ax, %fs
218         movw %ax, %gs
219
220         ljmpl $SEG32_MODE16BIG_CS, $(BUILD_BIOS_ADDR + 1f)
221
222         .code16gcc
223 1:
224         // Disable protected mode
225         movl %cr0, %eax
226         andl $~CR0_PE, %eax
227         movl %eax, %cr0
228
229         // far jump to flush CPU queue after transition to real mode
230         ljmpw $SEG_BIOS, $2f
231
232 2:
233         // restore IDT to normal real-mode defaults
234         lidtw %cs:rmode_IDT_info
235
236         // Clear segment registers
237         xorw %ax, %ax
238         movw %ax, %fs
239         movw %ax, %gs
240         movw %ax, %es
241         movw %ax, %ds
242         movw %ax, %ss  // Assume stack is in segment 0
243
244         popl %eax
245
246         // Set __call16 return address to be transition32
247         pushl $transition32
248
249         // Fall through to __call16
250
251
252 // Call a 16bit function from 16bit mode with a specified cpu register state
253 // %eax = address of struct bregs
254 // Clobbers: all gp registers, es
255         .global __call16
256 __call16:
257         // Save eax
258         pushl %eax
259
260         // Setup for iretw call
261         pushw $SEG_BIOS
262         pushw $1f               // return point
263         pushw BREGS_flags(%eax) // flags
264         pushl BREGS_ip(%eax)    // CS:IP
265
266         // Load calling registers.
267         movl BREGS_edi(%eax), %edi
268         movl BREGS_esi(%eax), %esi
269         movl BREGS_ebx(%eax), %ebx
270         movl BREGS_edx(%eax), %edx
271         movl BREGS_ecx(%eax), %ecx
272         movw BREGS_es(%eax), %es
273         movw BREGS_ds(%eax), %ds
274         movl %ss:BREGS_eax(%eax), %eax
275
276         // Invoke call
277         iretw                   // XXX - just do a lcalll
278 1:
279         // Store flags, eax, ecx
280         pushfw
281         pushl %eax
282         movl 0x06(%esp), %eax
283         movl %ecx, %ss:BREGS_ecx(%eax)
284         movw %ds, %ss:BREGS_ds(%eax)
285         movw %ss, %cx
286         movw %cx, %ds           // Restore %ds == %ss
287         popl %ecx
288         movl %ecx, BREGS_eax(%eax)
289         popw %cx
290         movw %cx, BREGS_flags(%eax)
291
292         // Store remaining registers
293         movw %es, BREGS_es(%eax)
294         movl %edi, BREGS_edi(%eax)
295         movl %esi, BREGS_esi(%eax)
296         movl %ebx, BREGS_ebx(%eax)
297         movl %edx, BREGS_edx(%eax)
298
299         // Remove %eax
300         popl %eax
301
302         cld
303
304         retl
305
306 // Entry point when a post call looks like a resume.
307 // %eax = shutdown status from cmos
308 entry_resume:
309         // Save old shutdown status.
310         movl %eax, %ebx
311
312         // Clear shutdown status register.
313         movl $CMOS_RESET_CODE, %eax
314         outb %al, $PORT_CMOS_INDEX
315         xorl %eax, %eax
316         outb %al, $PORT_CMOS_DATA
317
318         // Use a stack in EBDA
319         movw $SEG_BDA, %ax
320         movw %ax, %ds
321         movw BDA_ebda_seg, %ax
322         movw %ax, %ss
323         movw %ax, %ds
324         movl $EBDA_OFFSET_TOP_STACK, %esp
325
326         // Call handler.
327         movl %ebx, %eax
328         cld
329         cli
330         jmp handle_resume
331
332 // PnP trampolines
333         .global entry_pnp_real, entry_pnp_prot
334 entry_pnp_prot:
335         pushl %esp
336         jmp 1f
337 entry_pnp_real:
338         pushl %esp              // Backup %esp, then clear high bits
339         movzwl %sp, %esp
340 1:
341         pushfl                  // Save registers clobbered by C code
342         pushl %eax
343         pushl %ecx
344         pushl %edx
345         pushw %es
346         pushw %ds
347         movw %ss, %cx           // Move %ss to %ds
348         movw %cx, %ds
349         lea 28(%esp), %eax      // %eax points to start of u16 args
350         calll handle_pnp
351         movw %ax, 12(%esp)      // Modify %eax to return %ax
352         popw %ds
353         popw %es
354         popl %edx
355         popl %ecx
356         popl %eax
357         popfl
358         popl %esp
359         lretw
360
361 // APM trampolines
362         .global apm16protected_entry
363 apm16protected_entry:
364         pushfw          // save flags
365         pushl %eax      // dummy
366         ENTRY_ARG handle_1553
367         addw $4, %sp    // pop dummy
368         popfw           // restore flags
369         lretw
370
371         .code32
372         .global apm32protected_entry
373 apm32protected_entry:
374         pushfw
375         pushw %cs       // Setup for long jump to 16bit mode
376         pushw $1f
377         addw $8, 2(%esp)
378         ljmpw *(%esp)
379         .code16gcc
380 1:
381         ENTRY_ARG_ESP handle_1553
382
383         movw $2f,(%esp) // Setup for long jump back to 32bit mode
384         subw $8, 2(%esp)
385         ljmpw *(%esp)
386         .code32
387 2:
388         addl $4, %esp   // pop call address
389         popfw
390         lretl
391
392 // 32bit elf entry point
393         .global post32
394 post32:
395         cli
396         cld
397         lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
398         lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
399         movl $BUILD_STACK_ADDR, %esp
400         ljmpl $SEG32_MODE32_CS, $_code32__start
401
402         .code16gcc
403
404 // Shutdown a CPU.  We want this in the 0xf000 section to ensure that
405 // the code wont be overwritten with something else.  (Should
406 // something spurious wake up the CPU, we want to be sure that the hlt
407 // insn will still be present and will shutdown the CPU.)
408         .global permanent_halt
409 permanent_halt:
410         cli
411 1:      hlt
412         jmp 1b
413
414         // IRQ trampolines
415         .macro IRQ_TRAMPOLINE num
416         .global irq_trampoline_0x\num
417         irq_trampoline_0x\num :
418         int $0x\num
419         lretw
420         .endm
421
422         IRQ_TRAMPOLINE 02
423         IRQ_TRAMPOLINE 10
424         IRQ_TRAMPOLINE 13
425         IRQ_TRAMPOLINE 15
426         IRQ_TRAMPOLINE 16
427         IRQ_TRAMPOLINE 18
428         IRQ_TRAMPOLINE 19
429         IRQ_TRAMPOLINE 1c
430         IRQ_TRAMPOLINE 4a
431
432
433 /****************************************************************
434  * Interrupt entry points
435  ****************************************************************/
436
437         // Define an entry point for an interrupt (no args passed).
438         .macro IRQ_ENTRY num
439         .global entry_\num
440         entry_\num :
441         cli         // In case something far-calls instead of using "int"
442         ENTRY handle_\num
443         iretw
444         .endm
445
446         // Define an entry point for an interrupt (can read/modify args).
447         .macro IRQ_ENTRY_ARG num
448         .global entry_\num
449         entry_\num :
450         cli         // In case something far-calls instead of using "int"
451         ENTRY_ARG handle_\num
452         iretw
453         .endm
454
455         ORG 0xe2c3
456         IRQ_ENTRY nmi
457
458 /****************************************************************
459  * GDT and IDT tables (between 0xe2c3 - 0xe3fe)
460  ****************************************************************/
461
462 // Protected mode IDT descriptor
463 //
464 // I just make the limit 0, so the machine will shutdown
465 // if an exception occurs during protected mode memory
466 // transfers.
467 //
468 // Set base to f0000 to correspond to beginning of BIOS,
469 // in case I actually define an IDT later
470 // Set limit to 0
471         .type pmode_IDT_info, @object
472 pmode_IDT_info:
473         .word 0x0000  // limit 15:00
474         .long 0xf0000 // base 16:47
475
476 // Real mode IDT descriptor
477 //
478 // Set to typical real-mode values.
479 // base  = 000000
480 // limit =   03ff
481         .type rmode_IDT_info, @object
482 rmode_IDT_info:
483         .word 0x03ff  // limit 15:00
484         .long 0       // base 16:47
485
486         .type rombios32_gdt_48, @object
487 rombios32_gdt_48:
488         .word (rombios32_gdt_end - rombios32_gdt)
489         .long (BUILD_BIOS_ADDR + rombios32_gdt)
490
491         .balign 8
492         .type rombios32_gdt, @object
493 rombios32_gdt:
494         .word 0, 0, 0, 0
495         .word 0, 0, 0, 0
496         // 32 bit flat code segment (SEG32_MODE32_CS)
497         .word 0xffff, 0, 0x9b00, 0x00cf
498         // 32 bit flat data segment (SEG32_MODE32_DS)
499         .word 0xffff, 0, 0x9300, 0x00cf
500         // 16 bit code segment base=0xf0000 limit=0xffff (SEG32_MODE16_CS)
501         .word 0xffff, 0, 0x9b0f, 0x0000
502         // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS)
503         .word 0xffff, 0, 0x9300, 0x0000
504         // 16 bit code segment base=0 limit=0xffffffff (SEG32_MODE16BIG_CS)
505         .word 0xffff, 0, 0x9b00, 0x008f
506         // 16 bit data segment base=0 limit=0xffffffff (SEG32_MODE16BIG_DS)
507         .word 0xffff, 0, 0x9300, 0x008f
508 rombios32_gdt_end:
509
510
511 /****************************************************************
512  * Interrupt entry points (continued)
513  ****************************************************************/
514
515         ORG 0xe3fe
516         .global entry_13_official
517 entry_13_official:
518         jmp entry_13
519
520         ORG 0xe401
521         .type __fdpt, @object
522 __fdpt:
523         // XXX - Fixed Disk Parameter Table
524
525         ORG 0xe6f2
526         .global entry_19_official
527 entry_19_official:
528         jmp entry_19
529
530         ORG 0xe6f5
531 .include "out/cbt.proc.16.s"
532         .text
533
534         ORG 0xe729
535         .type __brgt, @object
536 __brgt:
537         // XXX - Baud Rate Generator Table
538
539         ORG 0xe739
540         IRQ_ENTRY_ARG 14
541
542         ORG 0xe82e
543         IRQ_ENTRY_ARG 16
544
545         ORG 0xe987
546         IRQ_ENTRY 09
547
548         ORG 0xec59
549         IRQ_ENTRY_ARG 40
550
551         ORG 0xef57
552         IRQ_ENTRY 0e
553
554         ORG 0xefc7
555 .include "out/floppy_dbt.proc.16.s"
556         .text
557
558         ORG 0xefd2
559         IRQ_ENTRY_ARG 17
560
561         ORG 0xf045
562 __int10_0x0f:
563         // XXX - INT 10 Functions 0-Fh Entry Point
564         iretw
565
566         ORG 0xf065
567         IRQ_ENTRY_ARG 10
568
569         ORG 0xf0a4
570         .type __int1d, @object
571 __int1d:
572         // XXX - INT 1D - SYSTEM DATA - VIDEO PARAMETER TABLES
573         .space 0x58
574
575         .global freespace2_start, freespace2_end
576 freespace2_start:
577
578         ORG 0xf841
579 freespace2_end:
580         .global entry_12_official
581 entry_12_official:
582         jmp entry_12
583
584         ORG 0xf84d
585         .global entry_11_official
586 entry_11_official:
587         jmp entry_11
588
589         ORG 0xf859
590         IRQ_ENTRY_ARG 15
591
592         // Fit other misc defs if the freespace between 0xf859-0xfa6e
593
594         IRQ_ENTRY_ARG 13
595         IRQ_ENTRY_ARG 12
596         IRQ_ENTRY_ARG 11
597         IRQ_ENTRY 76
598         IRQ_ENTRY 1c
599         IRQ_ENTRY 70
600         IRQ_ENTRY 74
601         IRQ_ENTRY 75
602         IRQ_ENTRY hwpic1
603         IRQ_ENTRY hwpic2
604
605         // int 18/19 are special - they reset the stack and do not return.
606 entry_19:
607         RESET_STACK
608         pushl $_code32_handle_19
609         jmp transition32
610
611         .global entry_18
612 entry_18:
613         RESET_STACK
614         pushl $_code32_handle_18
615         jmp transition32
616
617         ORG 0xfa6e
618 .include "out/font.proc.16.s"
619         .text
620
621         ORG 0xfe6e
622         IRQ_ENTRY_ARG 1a
623
624         ORG 0xfea5
625         IRQ_ENTRY 08
626
627         ORG 0xfef3
628 __initvector:
629         // XXX - Initial Interrupt Vector Offsets Loaded by POST
630
631         ORG 0xff00
632         .type __copyright, @object
633 __copyright:
634         // XXX - BIOS_COPYRIGHT_STRING
635         .asciz "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
636
637         ORG 0xff53
638         .global dummy_iret_handler
639 dummy_iret_handler:
640         iretw
641
642         ORG 0xff54
643         IRQ_ENTRY_ARG 05
644
645         ORG 0xfff0 // Power-up Entry Point
646         .global reset_vector
647 reset_vector:
648         ljmpw $SEG_BIOS, $post16
649
650         ORG 0xfff5
651         .type __biosdate, @object
652 __biosdate:
653         // BIOS build date
654         .ascii "06/23/99"
655
656         ORG 0xfffe
657         .type __model_id, @object
658 __model_id:
659         .byte CONFIG_MODEL_ID
660
661         .global bios_checksum
662         .type bios_checksum, @object
663 bios_checksum:
664         .byte 0x00
665
666         .end