[CLT2012]
[reactos.git] / boot / freeldr / freeldr / arch / i386 / multiboot.S
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <asm.inc>
21 #include <arch/pc/x86common.h>
22 #include <multiboot.h>
23
24 /* Multiboot support
25 *
26 * Allows freeldr to be loaded as a "multiboot kernel" by
27 * other boot loaders like GRUB.
28 * This code is not referenced from anywhere. GRUB searches for
29 * the header signature and uses the header to load it.
30 */
31
32 #define MB_INFO_FLAGS_OFFSET 0
33 #define MB_INFO_BOOT_DEVICE_OFFSET 12
34 #define MB_INFO_COMMAND_LINE_OFFSET 16
35 #define CMDLINE_SIZE 256
36
37 /*
38 * We want to execute at FREELDR_BASE (to be compatible with
39 * bootsector loading), but GRUB only allows loading of
40 * multiboot kernels above 1MB. So we let GRUB load us
41 * there and then relocate ourself to FREELDR_BASE.
42 */
43 #define INITIAL_BASE HEX(200000)
44
45 /* Align to 32 bits boundary */
46 .align 4
47
48 /* Multiboot header */
49 MultibootHeader:
50 /* magic */
51 .long MULTIBOOT_HEADER_MAGIC
52 /* flags */
53 .long MULTIBOOT_HEADER_FLAGS
54 /* checksum */
55 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
56 /* header_addr */
57 .long INITIAL_BASE + MultibootHeader - FREELDR_BASE
58 /* load_addr */
59 .long INITIAL_BASE
60 /* load_end_addr */
61 .long 0
62 /* bss_end_addr */
63 .long 0
64 /* entry_addr */
65 .long INITIAL_BASE + MultibootEntry - FREELDR_BASE
66
67 MultibootEntry:
68 cld
69
70 /* Save command line */
71 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
72 jz mb2
73 mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
74 mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
75 mov ecx, CMDLINE_SIZE - 1
76 mb1:
77 lodsb
78 stosb
79 test al, al
80 jz mb2
81 dec ecx
82 jnz mb1
83
84 mb2:
85 /* See if the boot device was passed in */
86 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_BOOT_DEVICE
87
88 /* If no boot device known, assume first partition of first harddisk */
89 mov dx, HEX(0180)
90 jz mb3
91
92 /* Load boot drive into DL, boot partition into DH */
93 mov edx, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
94 bswap edx
95 inc dh
96
97 mb3:
98 /* Relocate itself to lower address */
99 mov esi, INITIAL_BASE
100 mov edi, FREELDR_BASE
101 mov ecx, offset __bss_start__ - FREELDR_BASE
102 shr ecx, 2
103 rep movsd
104
105 /* Load segment registers for real-address mode */
106 lgdt gdtptr
107 mov ax, HEX(10)
108 mov ds, ax
109 mov es, ax
110 mov fs, ax
111 mov gs, ax
112 mov ss, ax
113
114 /* Jump to relocated code */
115 ljmp HEX(08), mb4
116
117 .code16
118 mb4:
119 /* Disable protected mode */
120 mov eax, cr0
121 and eax, CR0_PE_CLR
122 mov cr0, eax
123
124 /* Jump to real entry point */
125 ljmp16 0, FREELDR_BASE
126
127 /* Force 8-byte alignment */
128 .align 8
129 gdt:
130 /* 16-bit flat CS (!) */
131 .word HEX(FFFF)
132 .word HEX(0000)
133 .word HEX(9B00)
134 .word HEX(008F)
135
136 /* 16-bit real mode DS */
137 .word HEX(FFFF)
138 .word HEX(0000)
139 .word HEX(9300)
140 .word HEX(0000)
141
142 /* GDT pointer */
143 gdtptr:
144 .word HEX(17) /* Limit */
145 .long gdt - 8 /* Base Address */
146
147 PUBLIC cmdline
148 cmdline:
149 .space CMDLINE_SIZE
150
151 END