add roms/pcbios
[armpft.git] / pc-bios / optionrom / multiboot.S
blobe6cbefdc923ce4c23ab2e115467b4fb5b6e8e5b2
1 /*
2  * Multiboot Option ROM
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright Novell Inc, 2009
18  *   Authors: Alexander Graf <agraf@suse.de>
19  */
21 #define NO_QEMU_PROTOS
22 #include "../../hw/fw_cfg.h"
24 #define BIOS_CFG_IOPORT_CFG     0x510
25 #define BIOS_CFG_IOPORT_DATA    0x511
27 #define MULTIBOOT_MAGIC         0x2badb002
29 /* Read a variable from the fw_cfg device.
30    Clobbers:    %edx
31    Out:         %eax */
32 .macro read_fw VAR
33         mov             $\VAR, %ax
34         mov             $BIOS_CFG_IOPORT_CFG, %dx
35         outw            %ax, (%dx)
36         mov             $BIOS_CFG_IOPORT_DATA, %dx
37         inb             (%dx), %al
38         shl             $8, %eax
39         inb             (%dx), %al
40         shl             $8, %eax
41         inb             (%dx), %al
42         shl             $8, %eax
43         inb             (%dx), %al
44         bswap           %eax
45 .endm
47 .code16
48 .text
49         .global         _start
50 _start:
51         .short          0xaa55
52         .byte           1 /* (_end - _start) / 512 */
53         push            %eax
54         push            %ds
56         /* setup ds so we can access the IVT */
57         xor             %ax, %ax
58         mov             %ax, %ds
60         /* save old int 19 */
61         mov             (0x19*4), %eax
62         mov             %eax, %cs:old_int19
64         /* install our int 19 handler */
65         movw            $int19_handler, (0x19*4)
66         mov             %cs, (0x19*4+2)
68         pop             %ds
69         pop             %eax
70         lret
72 int19_handler:
73         /* DS = CS */
74         movw            %cs, %ax
75         movw            %ax, %ds
77         /* fall through */
79 run_multiboot:
81         cli
82         cld
84         mov             %cs, %eax
85         shl             $0x4, %eax
87         /* fix the gdt descriptor to be PC relative */
88         mov             (gdt_desc+2), %ebx
89         add             %eax, %ebx
90         mov             %ebx, (gdt_desc+2)
92         /* fix the prot mode indirect jump to be PC relative */
93         mov             (prot_jump), %ebx
94         add             %eax, %ebx
95         mov             %ebx, (prot_jump)
97         /* FS = bootinfo_struct */
98         read_fw         FW_CFG_INITRD_ADDR
99         shr             $4, %eax
100         mov             %ax, %fs
102         /* ES = mmap_addr */
103         read_fw         FW_CFG_INITRD_SIZE
104         shr             $4, %eax
105         mov             %ax, %es
107         /* Initialize multiboot mmap structs using int 0x15(e820) */
108         xor             %ebx, %ebx
109         /* mmap start after first size */
110         movl            $4, %edi
112 mmap_loop:
113         /* entry size (mmap struct) & max buffer size (int15) */
114         movl            $20, %ecx
115         /* store entry size */
116         /* old as(1) doesn't like this insn so emit the bytes instead:
117         movl            %ecx, %es:-4(%edi)
118         */
119         .dc.b           0x26,0x67,0x66,0x89,0x4f,0xfc
120         /* e820 */
121         movl            $0x0000e820, %eax
122         /* 'SMAP' magic */
123         movl            $0x534d4150, %edx
124         int             $0x15
126 mmap_check_entry:
127         /* last entry? then we're done */
128         jb              mmap_done
129         and             %bx, %bx
130         jz              mmap_done
131         /* valid entry, so let's loop on */
133 mmap_store_entry:
134         /* %ax = entry_number * 24 */
135         mov             $24, %ax
136         mul             %bx
137         mov             %ax, %di
138         movw            %di, %fs:0x2c
139         /* %di = 4 + (entry_number * 24) */
140         add             $4, %di
141         jmp             mmap_loop
143 mmap_done:
144 real_to_prot:
145         /* Load the GDT before going into protected mode */
146 lgdt:
147         data32 lgdt     %cs:gdt_desc
149         /* get us to protected mode now */
150         movl            $1, %eax
151         movl            %eax, %cr0
153         /* the LJMP sets CS for us and gets us to 32-bit */
154 ljmp:
155         data32 ljmp     *%cs:prot_jump
157 prot_mode:
158 .code32
160         /* initialize all other segments */
161         movl            $0x10, %eax
162         movl            %eax, %ss
163         movl            %eax, %ds
164         movl            %eax, %es
165         movl            %eax, %fs
166         movl            %eax, %gs
168         /* Jump off to the kernel */
169         read_fw         FW_CFG_KERNEL_ADDR
170         mov             %eax, %ecx
172         /* EBX contains a pointer to the bootinfo struct */
173         read_fw         FW_CFG_INITRD_ADDR
174         movl            %eax, %ebx
176         /* EAX has to contain the magic */
177         movl            $MULTIBOOT_MAGIC, %eax
178 ljmp2:
179         jmp             *%ecx
181 /* Variables */
182 .align 4, 0
183 old_int19:      .long 0
185 prot_jump:      .long prot_mode
186                 .short 8
188 .align 4, 0
189 gdt:
190         /* 0x00 */
191 .byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
193         /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
194 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
196         /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
197 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
199         /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */
200 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
202         /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */
203 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
205 gdt_desc:
206 .short  (5 * 8) - 1
207 .long   gdt
209 .align 512, 0
210 _end: