gptmbr.S revision 1.2 1 1.1 jakllsch /* -----------------------------------------------------------------------
2 1.1 jakllsch *
3 1.1 jakllsch * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
4 1.1 jakllsch * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5 1.1 jakllsch *
6 1.1 jakllsch * Permission is hereby granted, free of charge, to any person
7 1.1 jakllsch * obtaining a copy of this software and associated documentation
8 1.1 jakllsch * files (the "Software"), to deal in the Software without
9 1.1 jakllsch * restriction, including without limitation the rights to use,
10 1.1 jakllsch * copy, modify, merge, publish, distribute, sublicense, and/or
11 1.1 jakllsch * sell copies of the Software, and to permit persons to whom
12 1.1 jakllsch * the Software is furnished to do so, subject to the following
13 1.1 jakllsch * conditions:
14 1.1 jakllsch *
15 1.1 jakllsch * The above copyright notice and this permission notice shall
16 1.1 jakllsch * be included in all copies or substantial portions of the Software.
17 1.1 jakllsch *
18 1.1 jakllsch * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 1.1 jakllsch * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 1.1 jakllsch * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 1.1 jakllsch * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 1.1 jakllsch * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 1.1 jakllsch * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 1.1 jakllsch * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 1.1 jakllsch * OTHER DEALINGS IN THE SOFTWARE.
26 1.1 jakllsch *
27 1.1 jakllsch * ----------------------------------------------------------------------- */
28 1.1 jakllsch
29 1.1 jakllsch #include <machine/asm.h>
30 1.1 jakllsch #include <sys/bootblock.h>
31 1.1 jakllsch
32 1.1 jakllsch #ifdef CTRL_80
33 1.1 jakllsch .macro ADJUST_DRIVE
34 1.1 jakllsch testb $0x04, BIOS_kbdflags
35 1.1 jakllsch jz 1f
36 1.1 jakllsch movb $0x80, %dl
37 1.1 jakllsch 1:
38 1.1 jakllsch .endm
39 1.1 jakllsch #elif defined(FORCE_80)
40 1.1 jakllsch .macro ADJUST_DRIVE
41 1.1 jakllsch movb $0x80, %dl
42 1.1 jakllsch .endm
43 1.1 jakllsch #else
44 1.1 jakllsch .macro ADJUST_DRIVE
45 1.1 jakllsch .endm
46 1.1 jakllsch #endif
47 1.1 jakllsch
48 1.1 jakllsch .code16
49 1.1 jakllsch .text
50 1.1 jakllsch
51 1.1 jakllsch .globl bootsec
52 1.1 jakllsch stack = 0x7c00
53 1.1 jakllsch
54 1.1 jakllsch /* Partition table header here */
55 1.1 jakllsch phdr = stack /* Above the stack, overwritten by bootsect */
56 1.1 jakllsch /* Partition table sector here */
57 1.1 jakllsch /* To handle > 32K we need to play segment tricks... */
58 1.1 jakllsch psec = _phdr + 512
59 1.1 jakllsch
60 1.1 jakllsch /* Where we put DS:SI */
61 1.1 jakllsch dssi_out = start + 0x1be
62 1.1 jakllsch
63 1.1 jakllsch BIOS_kbdflags = 0x417
64 1.1 jakllsch BIOS_page = 0x462
65 1.1 jakllsch
66 1.1 jakllsch /* gas/ld has issues with doing this as absolute addresses... */
67 1.1 jakllsch .section ".bootsec", "a", @nobits
68 1.1 jakllsch .globl bootsec
69 1.1 jakllsch bootsec:
70 1.1 jakllsch .space 512
71 1.1 jakllsch
72 1.1 jakllsch .text
73 1.1 jakllsch .globl start
74 1.1 jakllsch start:
75 1.1 jakllsch cli
76 1.1 jakllsch xorw %ax, %ax
77 1.1 jakllsch movw %ax, %ds
78 1.1 jakllsch movw %ax, %ss
79 1.1 jakllsch movw $stack, %sp
80 1.1 jakllsch movw %sp, %si
81 1.1 jakllsch pushw %es /* 4(%bp) es:di -> $PnP header */
82 1.1 jakllsch pushw %di /* 2(%bp) */
83 1.1 jakllsch movw %ax, %es
84 1.1 jakllsch sti
85 1.1 jakllsch cld
86 1.1 jakllsch
87 1.1 jakllsch /* Copy down to 0:0x600 */
88 1.1 jakllsch movw $start, %di
89 1.1 jakllsch movw $(512/2), %cx
90 1.1 jakllsch rep; movsw
91 1.1 jakllsch
92 1.1 jakllsch ljmpw $0, $next
93 1.1 jakllsch next:
94 1.1 jakllsch
95 1.1 jakllsch ADJUST_DRIVE
96 1.1 jakllsch pushw %dx /* 0(%bp) = %dl -> drive number */
97 1.1 jakllsch
98 1.1 jakllsch /* Check to see if we have EBIOS */
99 1.1 jakllsch pushw %dx /* drive number */
100 1.1 jakllsch movb $0x41, %ah /* %al == 0 already */
101 1.1 jakllsch movw $0x55aa, %bx
102 1.1 jakllsch xorw %cx, %cx
103 1.1 jakllsch xorb %dh, %dh
104 1.1 jakllsch stc
105 1.1 jakllsch int $0x13
106 1.1 jakllsch jc 1f
107 1.1 jakllsch cmpw $0xaa55, %bx
108 1.1 jakllsch jne 1f
109 1.1 jakllsch shrw %cx /* Bit 0 = fixed disk subset */
110 1.1 jakllsch jnc 1f
111 1.1 jakllsch
112 1.1 jakllsch /* We have EBIOS; patch in the following code at
113 1.1 jakllsch read_sector_cbios: movb $0x42, %ah ; jmp read_common */
114 1.1 jakllsch movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
115 1.1 jakllsch (read_sector_cbios)
116 1.1 jakllsch
117 1.1 jakllsch 1:
118 1.1 jakllsch popw %dx
119 1.1 jakllsch
120 1.1 jakllsch /* Get (C)HS geometry */
121 1.1 jakllsch movb $0x08, %ah
122 1.1 jakllsch int $0x13
123 1.1 jakllsch andw $0x3f, %cx /* Sector count */
124 1.1 jakllsch movw %sp, %bp /* %bp -> frame pointer: LEAVE UNCHANGED */
125 1.1 jakllsch pushw %cx /* -2(%bp) Save sectors on the stack */
126 1.1 jakllsch movzbw %dh, %ax /* dh = max head */
127 1.1 jakllsch incw %ax /* From 0-based max to count */
128 1.1 jakllsch mulw %cx /* Heads*sectors -> sectors per cylinder */
129 1.1 jakllsch
130 1.1 jakllsch /* Save sectors/cylinder on the stack */
131 1.1 jakllsch pushw %dx /* -4(%bp) High word */
132 1.1 jakllsch pushw %ax /* -6(%bp) Low word */
133 1.1 jakllsch
134 1.1 jakllsch /* Load partition table header */
135 1.1 jakllsch xorl %eax,%eax
136 1.1 jakllsch cltd
137 1.1 jakllsch incw %ax /* %edx:%eax = 1 */
138 1.1 jakllsch movw $phdr, %bx
139 1.1 jakllsch pushw %bx /* -8(%bp) phdr == bootsect */
140 1.1 jakllsch call read_sector
141 1.1 jakllsch
142 1.1 jakllsch /* Number of partition sectors */
143 1.1 jakllsch /* We assume the partition table is 32K or less, and that
144 1.1 jakllsch the sector size is 512. */
145 1.1 jakllsch /* Note: phdr == 6(%bp) */
146 1.1 jakllsch movw (80+6)(%bp),%cx /* NumberOfPartitionEntries */
147 1.1 jakllsch movw (84+6)(%bp),%ax /* SizeOfPartitionEntry */
148 1.1 jakllsch pushw %ax
149 1.1 jakllsch pushw %cx
150 1.1 jakllsch mulw %cx
151 1.1 jakllsch shrw $9,%ax
152 1.1 jakllsch xchgw %ax,%cx
153 1.1 jakllsch incw %cx
154 1.1 jakllsch
155 1.1 jakllsch /* Starting LBA of partition array */
156 1.1 jakllsch movl (72+6)(%bp),%eax
157 1.1 jakllsch movl (76+6)(%bp),%edx
158 1.1 jakllsch
159 1.1 jakllsch pushw %bx
160 1.1 jakllsch get_ptab:
161 1.1 jakllsch call read_sector
162 1.1 jakllsch call inc64
163 1.2 joerg loop get_ptab
164 1.1 jakllsch
165 1.1 jakllsch /* Find the boot partition */
166 1.1 jakllsch xorw %si,%si /* Nothing found yet */
167 1.1 jakllsch popw %di /* Partition table in memory */
168 1.1 jakllsch popw %cx /* NumberOfPartitionEntries */
169 1.1 jakllsch popw %ax /* SizeOfPartitionEntry */
170 1.1 jakllsch
171 1.1 jakllsch find_part:
172 1.1 jakllsch /* If the PartitionTypeGUID is all zero, it's an empty slot */
173 1.1 jakllsch movl (%di),%edx
174 1.1 jakllsch orl 4(%di),%edx
175 1.1 jakllsch orl 8(%di),%edx
176 1.1 jakllsch orl 12(%di),%edx
177 1.1 jakllsch jz not_this
178 1.1 jakllsch testb $0x04,48(%di)
179 1.1 jakllsch jz not_this
180 1.1 jakllsch andw %si,%si
181 1.1 jakllsch jnz found_multiple
182 1.1 jakllsch movw %di,%si
183 1.1 jakllsch not_this:
184 1.1 jakllsch addw %ax,%di
185 1.2 joerg loop find_part
186 1.1 jakllsch
187 1.1 jakllsch andw %si,%si
188 1.1 jakllsch jnz found_part
189 1.1 jakllsch
190 1.1 jakllsch missing_os:
191 1.1 jakllsch call error
192 1.1 jakllsch .ascii "Missing OS\r\n"
193 1.1 jakllsch
194 1.1 jakllsch found_multiple:
195 1.1 jakllsch call error
196 1.1 jakllsch .ascii "Multiple active partitions\r\n"
197 1.1 jakllsch
198 1.1 jakllsch found_part:
199 1.1 jakllsch xchgw %ax,%cx /* Set up %cx for rep movsb further down */
200 1.1 jakllsch
201 1.1 jakllsch movw $dssi_out,%di
202 1.1 jakllsch pushw %di
203 1.1 jakllsch
204 1.1 jakllsch /* 80 00 00 00 ee 00 00 00
205 1.1 jakllsch - bootable partition, type EFI (EE), no CHS information */
206 1.1 jakllsch xorl %eax,%eax
207 1.1 jakllsch movb $0x80,%al
208 1.1 jakllsch stosl
209 1.1 jakllsch movb $0xed,%al
210 1.1 jakllsch stosl
211 1.1 jakllsch movl 32(%si),%eax
212 1.1 jakllsch movl 36(%si),%edx
213 1.1 jakllsch call saturate_stosl /* Partition start */
214 1.1 jakllsch
215 1.1 jakllsch movl 40(%si),%eax
216 1.1 jakllsch movl 44(%si),%edx
217 1.1 jakllsch subl 32(%si),%eax
218 1.1 jakllsch sbbl 36(%si),%edx
219 1.1 jakllsch call inc64
220 1.1 jakllsch call saturate_stosl /* Partition length */
221 1.1 jakllsch
222 1.1 jakllsch movzwl %cx,%eax /* Length of GPT entry */
223 1.1 jakllsch stosl
224 1.1 jakllsch
225 1.1 jakllsch rep; movsb /* GPT entry follows MBR entry */
226 1.1 jakllsch popw %si
227 1.1 jakllsch
228 1.1 jakllsch /*
229 1.1 jakllsch * boot: invoke the actual bootstrap. %ds:%si points to the
230 1.1 jakllsch * partition information in memory. The top word on the stack
231 1.1 jakllsch * is phdr == 0x7c00 == the address of the boot sector.
232 1.1 jakllsch */
233 1.1 jakllsch boot:
234 1.1 jakllsch movl (32+20)(%si),%eax
235 1.1 jakllsch movl (36+20)(%si),%edx
236 1.1 jakllsch popw %bx
237 1.1 jakllsch call read_sector
238 1.1 jakllsch cmpw $0xaa55, -2(%bx)
239 1.1 jakllsch jne missing_os /* Not a valid boot sector */
240 1.1 jakllsch movw %bp, %sp /* driveno == bootsec-6 */
241 1.1 jakllsch popw %dx /* dl -> drive number */
242 1.1 jakllsch popw %di /* es:di -> $PnP vector */
243 1.1 jakllsch popw %es
244 1.1 jakllsch movl $0x54504721,%eax /* !GPT magic number */
245 1.1 jakllsch cli
246 1.1 jakllsch jmpw *%sp /* %sp == bootsec */
247 1.1 jakllsch
248 1.1 jakllsch /*
249 1.1 jakllsch * Store the value in %eax to %di iff %edx == 0, otherwise store -1.
250 1.1 jakllsch * Returns the value that was actually written in %eax.
251 1.1 jakllsch */
252 1.1 jakllsch saturate_stosl:
253 1.1 jakllsch andl %edx,%edx
254 1.1 jakllsch jz 1f
255 1.1 jakllsch orl $-1,%eax
256 1.1 jakllsch 1: stosl
257 1.1 jakllsch ret
258 1.1 jakllsch
259 1.1 jakllsch /*
260 1.1 jakllsch * Increment %edx:%eax
261 1.1 jakllsch */
262 1.1 jakllsch inc64:
263 1.1 jakllsch addl $1,%eax
264 1.1 jakllsch adcl $0,%edx
265 1.1 jakllsch ret
266 1.1 jakllsch
267 1.1 jakllsch /*
268 1.1 jakllsch * read_sector: read a single sector pointed to by %edx:%eax to
269 1.1 jakllsch * %es:%bx. CF is set on error. All registers saved.
270 1.1 jakllsch */
271 1.1 jakllsch read_sector:
272 1.1 jakllsch pushal
273 1.1 jakllsch pushl %edx /* MSW of LBA */
274 1.1 jakllsch pushl %eax /* LSW of LBA */
275 1.1 jakllsch pushw %es /* Buffer segment */
276 1.1 jakllsch pushw %bx /* Buffer offset */
277 1.1 jakllsch pushw $1 /* Sector count */
278 1.1 jakllsch pushw $16 /* Size of packet */
279 1.1 jakllsch movw %sp, %si
280 1.1 jakllsch
281 1.1 jakllsch /* This chunk is skipped if we have ebios */
282 1.1 jakllsch /* Do not clobber %es:%bx or %edx:%eax before this chunk! */
283 1.1 jakllsch read_sector_cbios:
284 1.1 jakllsch divl -6(%bp) /* secpercyl */
285 1.1 jakllsch shlb $6, %ah
286 1.1 jakllsch movb %ah, %cl
287 1.1 jakllsch movb %al, %ch
288 1.1 jakllsch xchgw %dx, %ax
289 1.1 jakllsch divb -2(%bp) /* sectors */
290 1.1 jakllsch movb %al, %dh
291 1.1 jakllsch orb %ah, %cl
292 1.1 jakllsch incw %cx /* Sectors are 1-based */
293 1.1 jakllsch movw $0x0201, %ax
294 1.1 jakllsch
295 1.1 jakllsch read_common:
296 1.1 jakllsch movb (%bp), %dl /* driveno */
297 1.1 jakllsch int $0x13
298 1.1 jakllsch leaw 16(%si), %sp /* Drop DAPA */
299 1.1 jakllsch popal
300 1.1 jakllsch jc disk_error
301 1.1 jakllsch addb $2, %bh /* bx += 512: point to the next buffer */
302 1.1 jakllsch ret
303 1.1 jakllsch
304 1.1 jakllsch disk_error:
305 1.1 jakllsch call error
306 1.1 jakllsch .ascii "Disk error on boot\r\n"
307 1.1 jakllsch
308 1.1 jakllsch /*
309 1.1 jakllsch * Print error messages. This is invoked with "call", with the
310 1.1 jakllsch * error message at the return address.
311 1.1 jakllsch */
312 1.1 jakllsch error:
313 1.1 jakllsch popw %si
314 1.1 jakllsch 2:
315 1.1 jakllsch lodsb
316 1.1 jakllsch movb $0x0e, %ah
317 1.1 jakllsch movb (BIOS_page), %bh
318 1.1 jakllsch movb $0x07, %bl
319 1.1 jakllsch int $0x10 /* May destroy %bp */
320 1.1 jakllsch cmpb $10, %al /* Newline? */
321 1.1 jakllsch jne 2b
322 1.1 jakllsch
323 1.1 jakllsch int $0x18 /* Boot failure */
324 1.1 jakllsch die:
325 1.1 jakllsch hlt
326 1.1 jakllsch jmp die
327 1.1 jakllsch
328 1.1 jakllsch mbr_space = end - .
329 1.1 jakllsch . = MBR_DSN_OFFSET
330 1.1 jakllsch end:
331