Add option CONFIG_DISABLE_A20 to control disabling A20 on boot.
[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         cli         // In case something far-calls instead of using "int"
32         cld
33         pushl %eax              // Save registers clobbered by C code
34         pushl %ecx
35         pushl %edx
36         pushw %es
37         pushw %ds
38         movw %ss, %ax           // Move %ss to %ds
39         movw %ax, %ds
40         pushl %esp              // Backup %esp, then clear high bits
41         movzwl %sp, %esp
42         calll \cfunc
43         popl %esp               // Restore %esp (including high bits)
44         popw %ds                // Restore registers saved above
45         popw %es
46         popl %edx
47         popl %ecx
48         popl %eax
49         .endm
50
51         // Call a C function with current register list as an
52         // argument.  This backs up the registers and sets %eax
53         // to point to the backup.  On return, the registers are
54         // restored from the structure.
55         .macro ENTRY_ARG cfunc
56         cli
57         cld
58         pushl %eax              // Save registers (matches struct bregs)
59         pushl %ecx
60         pushl %edx
61         pushl %ebx
62         pushl %esi
63         pushl %edi
64         pushw %es
65         pushw %ds
66         movw %ss, %ax           // Move %ss to %ds
67         movw %ax, %ds
68         movl %esp, %ebx         // Backup %esp, then zero high bits
69         movzwl %sp, %esp
70         movl %esp, %eax         // First arg is pointer to struct bregs
71         calll \cfunc
72         movl %ebx, %esp         // Restore %esp (including high bits)
73         popw %ds                // Restore registers (from struct bregs)
74         popw %es
75         popl %edi
76         popl %esi
77         popl %ebx
78         popl %edx
79         popl %ecx
80         popl %eax
81         .endm
82
83         // As above, but don't mangle %esp
84         .macro ENTRY_ARG_ESP cfunc
85         cli
86         cld
87         pushl %eax              // Save registers (matches struct bregs)
88         pushl %ecx
89         pushl %edx
90         pushl %ebx
91         pushl %esi
92         pushl %edi
93         pushw %es
94         pushw %ds
95         movw %ss, %ax           // Move %ss to %ds
96         movw %ax, %ds
97         movl %esp, %eax         // First arg is pointer to struct bregs
98         calll \cfunc
99         popw %ds                // Restore registers (from struct bregs)
100         popw %es
101         popl %edi
102         popl %esi
103         popl %ebx
104         popl %edx
105         popl %ecx
106         popl %eax
107         .endm
108
109         // Reset stack, transition to 32bit mode, and call a C function.
110         // Clobbers %ax
111         .macro ENTRY_INTO32 cfunc
112         xorw %ax, %ax
113         movw %ax, %ss
114         movl $ BUILD_STACK_ADDR , %esp
115         pushl $ \cfunc
116         jmp transition32
117         .endm
118
119         // Declare a function
120         .macro DECLFUNC func
121         .section .text.asm.\func
122         .global \func
123         .endm
124
125
126 /****************************************************************
127  * Call trampolines
128  ****************************************************************/
129
130 // Place CPU into 32bit mode from 16bit mode.
131 // Clobbers: flags, segment registers, cr0, idt/gdt
132         DECLFUNC transition32
133 transition32:
134         pushl %eax
135
136         // Disable irqs (and clear direction flag)
137         cli
138         cld
139
140         // Disable nmi
141         movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
142         outb %al, $PORT_CMOS_INDEX
143         inb $PORT_CMOS_DATA, %al
144
145         // enable a20
146         inb $PORT_A20, %al
147         orb $A20_ENABLE_BIT, %al
148         outb %al, $PORT_A20
149
150         // Set segment descriptors
151         lidtw %cs:pmode_IDT_info
152         lgdtw %cs:rombios32_gdt_48
153
154         // Enable protected mode
155         movl %cr0, %eax
156         orl $CR0_PE, %eax
157         movl %eax, %cr0
158
159         // start 32bit protected mode code
160         ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
161
162         .code32
163 1:
164         // init data segments
165         movl $SEG32_MODE32_DS, %eax
166         movw %ax, %ds
167         movw %ax, %es
168         movw %ax, %ss
169         movw %ax, %fs
170         movw %ax, %gs
171
172         popl %eax
173         retl
174
175 // Call a 16bit function from 32bit mode.
176 // %eax = address of struct bregs
177 // Clobbers: %e[bcd]x, %e[ds]i, flags, segment registers, idt/gdt
178         DECLFUNC __call16_from32
179         .global __call16big_from32
180 __call16_from32:
181         pushl %eax
182
183         // restore data segment limits to 0xffff
184         movl $SEG32_MODE16_DS, %eax
185         movw %ax, %ds
186         movw %ax, %es
187         movw %ax, %ss
188         movw %ax, %fs
189         movw %ax, %gs
190
191 #if CONFIG_DISABLE_A20
192         // disable a20
193         inb $PORT_A20, %al
194         andb $~A20_ENABLE_BIT, %al
195         outb %al, $PORT_A20
196 #endif
197
198         // Jump to 16bit mode
199         ljmpw $SEG32_MODE16_CS, $1f
200
201 __call16big_from32:
202         pushl %eax
203
204         movl $SEG32_MODE16BIG_DS, %eax
205         movw %ax, %ds
206         movw %ax, %es
207         movw %ax, %ss
208         movw %ax, %fs
209         movw %ax, %gs
210
211         ljmpl $SEG32_MODE16BIG_CS, $(BUILD_BIOS_ADDR + 1f)
212
213         .code16gcc
214 1:
215         // Disable protected mode
216         movl %cr0, %eax
217         andl $~CR0_PE, %eax
218         movl %eax, %cr0
219
220         // far jump to flush CPU queue after transition to real mode
221         ljmpw $SEG_BIOS, $2f
222
223 2:
224         // restore IDT to normal real-mode defaults
225         lidtw %cs:rmode_IDT_info
226
227         // Clear segment registers
228         xorw %ax, %ax
229         movw %ax, %fs
230         movw %ax, %gs
231         movw %ax, %es
232         movw %ax, %ds
233         movw %ax, %ss  // Assume stack is in segment 0
234
235         popl %eax
236
237         // Make call.
238         calll __call16
239
240         // Return via transition32
241         jmp transition32
242
243
244 // Call a 16bit function from 16bit mode with a specified cpu register state
245 // %eax = address of struct bregs
246 // Clobbers: %e[bcd]x, %e[ds]i, flags
247         DECLFUNC __call16
248 __call16:
249         // Save %eax, %ebp
250         pushl %ebp
251         pushl %eax
252
253         // Setup for iretw call
254         pushw %cs
255         pushw $1f               // return point
256         pushw BREGS_flags(%eax) // flags
257         pushl BREGS_ip(%eax)    // CS:IP
258
259         // Load calling registers.
260         movl BREGS_edi(%eax), %edi
261         movl BREGS_esi(%eax), %esi
262         movl BREGS_ebx(%eax), %ebx
263         movl BREGS_edx(%eax), %edx
264         movl BREGS_ecx(%eax), %ecx
265         movw BREGS_es(%eax), %es
266         movw BREGS_ds(%eax), %ds
267         movl %ss:BREGS_eax(%eax), %eax
268
269         // Invoke call
270         iretw                   // XXX - just do a lcalll
271 1:
272         // Store flags, eax, ecx
273         pushfw
274         pushl %eax
275         movl 0x06(%esp), %eax
276         movl %ecx, %ss:BREGS_ecx(%eax)
277         movw %ds, %ss:BREGS_ds(%eax)
278         movw %ss, %cx
279         movw %cx, %ds           // Restore %ds == %ss
280         popl %ecx
281         movl %ecx, BREGS_eax(%eax)
282         popw %cx
283         movw %cx, BREGS_flags(%eax)
284
285         // Store remaining registers
286         movw %es, BREGS_es(%eax)
287         movl %edi, BREGS_edi(%eax)
288         movl %esi, BREGS_esi(%eax)
289         movl %ebx, BREGS_ebx(%eax)
290         movl %edx, BREGS_edx(%eax)
291
292         // Remove %eax, restore %ebp
293         popl %eax
294         popl %ebp
295
296         retl
297
298 // IRQ trampolines
299         .macro IRQ_TRAMPOLINE num
300         DECLFUNC irq_trampoline_0x\num
301         irq_trampoline_0x\num :
302         int $0x\num
303         lretw
304         .endm
305
306         IRQ_TRAMPOLINE 10
307         IRQ_TRAMPOLINE 13
308         IRQ_TRAMPOLINE 15
309         IRQ_TRAMPOLINE 16
310         IRQ_TRAMPOLINE 18
311         IRQ_TRAMPOLINE 19
312
313
314 /****************************************************************
315  * POST entry point
316  ****************************************************************/
317
318         DECLFUNC entry_post
319 entry_post:
320         // Enable cache
321         movl %cr0, %eax
322         andl $~(CR0_CD|CR0_NW), %eax
323         movl %eax, %cr0
324
325         // Disable interrupts
326         cli
327         cld
328
329         // Check for restart indicator.
330         movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
331         outb %al, $PORT_CMOS_INDEX
332         inb $PORT_CMOS_DATA, %al
333         cmpb $0x0, %al
334         jnz 1f
335
336         // Normal entry point
337         ENTRY_INTO32 _code32__start
338
339         // Entry point when a post call looks like a resume.
340 1:
341         // Save old shutdown status.
342         movl %eax, %ebx
343
344         // Clear shutdown status register.
345         movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
346         outb %al, $PORT_CMOS_INDEX
347         xorl %eax, %eax
348         outb %al, $PORT_CMOS_DATA
349
350         // Use a stack in EBDA
351         movw $SEG_BDA, %ax
352         movw %ax, %ds
353         movw BDA_ebda_seg, %ax
354         // XXX - should verify ebda_seg looks sane.
355         movw %ax, %ds
356         movw %ax, %ss
357         movl $EBDA_OFFSET_TOP_STACK, %esp
358
359         // Call handler.
360         movl %ebx, %eax
361         jmp handle_resume
362
363
364 /****************************************************************
365  * Misc. entry points.
366  ****************************************************************/
367
368 // PnP entry points
369         DECLFUNC entry_pnp_real
370         .global entry_pnp_prot
371 entry_pnp_prot:
372         pushl %esp
373         jmp 1f
374 entry_pnp_real:
375         pushl %esp              // Backup %esp, then clear high bits
376         movzwl %sp, %esp
377 1:
378         pushfl                  // Save registers clobbered by C code
379         pushl %eax
380         pushl %ecx
381         pushl %edx
382         pushw %es
383         pushw %ds
384         movw %ss, %cx           // Move %ss to %ds
385         movw %cx, %ds
386         lea 28(%esp), %eax      // %eax points to start of u16 args
387         calll handle_pnp
388         movw %ax, 12(%esp)      // Modify %eax to return %ax
389         popw %ds
390         popw %es
391         popl %edx
392         popl %ecx
393         popl %eax
394         popfl
395         popl %esp
396         lretw
397
398 // APM entry points
399         DECLFUNC apm16protected_entry
400 apm16protected_entry:
401         pushfw          // save flags
402         pushl %eax      // dummy
403         ENTRY_ARG handle_1553
404         addw $4, %sp    // pop dummy
405         popfw           // restore flags
406         lretw
407
408         .code32
409         DECLFUNC apm32protected_entry
410 apm32protected_entry:
411         pushfw
412         pushw %cs       // Setup for long jump to 16bit mode
413         pushw $1f
414         addw $8, 2(%esp)
415         ljmpw *(%esp)
416         .code16gcc
417 1:
418         ENTRY_ARG_ESP handle_1553
419
420         movw $2f,(%esp) // Setup for long jump back to 32bit mode
421         subw $8, 2(%esp)
422         ljmpw *(%esp)
423         .code32
424 2:
425         addl $4, %esp   // pop call address
426         popfw
427         lretl
428
429 // 32bit elf entry point
430         DECLFUNC post32
431 post32:
432         cli
433         cld
434         lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
435         lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
436         movl $SEG32_MODE32_DS, %eax
437         movw %ax, %ds
438         movw %ax, %es
439         movw %ax, %fs
440         movw %ax, %gs
441         movw %ax, %ss
442         movl $BUILD_STACK_ADDR, %esp
443         ljmpl $SEG32_MODE32_CS, $_code32__start
444
445         .code16gcc
446
447
448 /****************************************************************
449  * Interrupt entry points
450  ****************************************************************/
451
452         // Define an entry point for an interrupt (no args passed).
453         .macro IRQ_ENTRY num
454         .global entry_\num
455         entry_\num :
456         ENTRY handle_\num
457         iretw
458         .endm
459
460         // Define an entry point for an interrupt (can read/modify args).
461         .macro IRQ_ENTRY_ARG num
462         .global entry_\num
463         entry_\num :
464         ENTRY_ARG handle_\num
465         iretw
466         .endm
467
468         // Macros that put each handler into its own section
469         .macro DECL_IRQ_ENTRY num
470         .section .text.asm.entry_\num
471         IRQ_ENTRY \num
472         .endm
473         .macro DECL_IRQ_ENTRY_ARG num
474         .section .text.asm.entry_\num
475         IRQ_ENTRY_ARG \num
476         .endm
477
478         DECL_IRQ_ENTRY_ARG 13
479         DECL_IRQ_ENTRY_ARG 12
480         DECL_IRQ_ENTRY_ARG 11
481         DECL_IRQ_ENTRY 76
482         DECL_IRQ_ENTRY 70
483         DECL_IRQ_ENTRY 74
484         DECL_IRQ_ENTRY 75
485         DECL_IRQ_ENTRY hwpic1
486         DECL_IRQ_ENTRY hwpic2
487
488         // int 18/19 are special - they reset stack and call into 32bit mode.
489         DECLFUNC entry_19
490 entry_19:
491         ENTRY_INTO32 _code32_handle_19
492
493         DECLFUNC entry_18
494 entry_18:
495         ENTRY_INTO32 _code32_handle_18
496
497
498 /****************************************************************
499  * Fixed position entry points
500  ****************************************************************/
501
502         // Specify a location in the fixed part of bios area.
503         .macro ORG addr
504         .section .fixedaddr.\addr
505         .endm
506
507         ORG 0xe05b
508 entry_post_official:
509         jmp entry_post
510
511         ORG 0xe2c3
512         IRQ_ENTRY 02
513
514         ORG 0xe3fe
515         .global entry_13_official
516 entry_13_official:
517         jmp entry_13
518
519         // 0xe401 - OldFDPT in disk.c
520
521         ORG 0xe6f2
522         .global entry_19_official
523 entry_19_official:
524         jmp entry_19
525
526         // 0xe6f5 - BIOS_CONFIG_TABLE in misc.c
527
528         // 0xe729 - BaudTable in serial.c
529
530         ORG 0xe739
531         IRQ_ENTRY_ARG 14
532
533         ORG 0xe82e
534         IRQ_ENTRY_ARG 16
535
536         ORG 0xe987
537         IRQ_ENTRY 09
538
539         ORG 0xec59
540         IRQ_ENTRY_ARG 40
541
542         ORG 0xef57
543         IRQ_ENTRY 0e
544
545         // 0xefc7 - diskette_param_table in floppy.c
546
547         ORG 0xefd2
548         IRQ_ENTRY_ARG 17
549
550         ORG 0xf045
551 entry_10_0x0f:
552         // XXX - INT 10 Functions 0-Fh Entry Point
553         iretw
554
555         ORG 0xf065
556         IRQ_ENTRY_ARG 10
557
558         // 0xf0a4 - VideoParams in misc.c
559
560         ORG 0xf841
561         .global entry_12_official
562 entry_12_official:
563         jmp entry_12
564
565         ORG 0xf84d
566         .global entry_11_official
567 entry_11_official:
568         jmp entry_11
569
570         ORG 0xf859
571         IRQ_ENTRY_ARG 15
572
573         // 0xfa6e - vgafont8 in font.c
574
575         ORG 0xfe6e
576         IRQ_ENTRY_ARG 1a
577
578         ORG 0xfea5
579         IRQ_ENTRY 08
580
581         // 0xfef3 - InitVectors in misc.c
582
583         // 0xff00 - BiosCopyright in misc.c
584
585         ORG 0xff53
586         .global entry_iret_official
587 entry_iret_official:
588         iretw
589
590         ORG 0xff54
591         IRQ_ENTRY_ARG 05
592
593         ORG 0xfff0 // Power-up Entry Point
594         .global reset_vector
595 reset_vector:
596         ljmpw $SEG_BIOS, $entry_post_official
597
598         // 0xfff5 - BiosDate in misc.c
599
600         // 0xfffe - BiosModelId in misc.c
601
602         // 0xffff - BiosChecksum in misc.c
603
604         .end