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