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