Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / boot / i386 / pc / diskboot.S
blobd030a14c9163953dd49f105f40363ac676b55f93
1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 1999,2000,2001,2002,2006,2007,2009,2010   Free Software Foundation, Inc.
4  *
5  *  GRUB 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 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  GRUB 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
16  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
17  */
19 #include <grub/symbol.h>
20 #include <grub/machine/boot.h>
23  *  defines for the code go here
24  */
26 #define MSG(x)  movw $x, %si; call LOCAL(message)
28         .file   "diskboot.S"
30         .text
32         /* Tell GAS to generate 16-bit instructions so that this code works
33            in real mode. */
34         .code16
36         .globl  start, _start
37 start:
38 _start:
39         /*
40          * _start is loaded at 0x2000 and is jumped to with
41          * CS:IP 0:0x2000 in kernel.
42          */
44         /*
45          * we continue to use the stack for boot.img and assume that
46          * some registers are set to correct values. See boot.S
47          * for more information.
48          */
50         /* save drive reference first thing! */
51         pushw   %dx
53         /* print a notification message on the screen */
54         pushw   %si
55         MSG(notification_string)
56         popw    %si
58         /* this sets up for the first run through "bootloop" */
59         movw    $LOCAL(firstlist), %di
61         /* save the sector number of the second sector in %ebp */
62         movl    (%di), %ebp
64         /* this is the loop for reading the rest of the kernel in */
65 LOCAL(bootloop):
67         /* check the number of sectors to read */
68         cmpw    $0, 8(%di)
70         /* if zero, go to the start function */
71         je      LOCAL(bootit)
73 LOCAL(setup_sectors):
74         /* check if we use LBA or CHS */
75         cmpb    $0, -1(%si)
77         /* use CHS if zero, LBA otherwise */
78         je      LOCAL(chs_mode)
80         /* load logical sector start */
81         movl    (%di), %ebx
82         movl    4(%di), %ecx
84         /* the maximum is limited to 0x7f because of Phoenix EDD */
85         xorl    %eax, %eax
86         movb    $0x7f, %al
88         /* how many do we really want to read? */
89         cmpw    %ax, 8(%di)     /* compare against total number of sectors */
91         /* which is greater? */
92         jg      1f
94         /* if less than, set to total */
95         movw    8(%di), %ax
98         /* subtract from total */
99         subw    %ax, 8(%di)
101         /* add into logical sector start */
102         addl    %eax, (%di)
103         adcl    $0, 4(%di)
105         /* set up disk address packet */
107         /* the size and the reserved byte */
108         movw    $0x0010, (%si)
110         /* the number of sectors */
111         movw    %ax, 2(%si)
113         /* the absolute address */
114         movl    %ebx, 8(%si)
115         movl    %ecx, 12(%si)
117         /* the segment of buffer address */
118         movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
120         /* save %ax from destruction! */
121         pushw   %ax
123         /* the offset of buffer address */
124         movw    $0, 4(%si)
127  * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
128  *      Call with       %ah = 0x42
129  *                      %dl = drive number
130  *                      %ds:%si = segment:offset of disk address packet
131  *      Return:
132  *                      %al = 0x0 on success; err code on failure
133  */
135         movb    $0x42, %ah
136         int     $0x13
138         jc      LOCAL(read_error)
140         movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
141         jmp     LOCAL(copy_buffer)
143 LOCAL(chs_mode):
144         /* load logical sector start (top half) */
145         movl    4(%di), %eax
146         orl     %eax, %eax
147         jnz     LOCAL(geometry_error)
149         /* load logical sector start (bottom half) */
150         movl    (%di), %eax
152         /* zero %edx */
153         xorl    %edx, %edx
155         /* divide by number of sectors */
156         divl    (%si)
158         /* save sector start */
159         movb    %dl, 10(%si)
161         xorl    %edx, %edx      /* zero %edx */
162         divl    4(%si)          /* divide by number of heads */
164         /* save head start */
165         movb    %dl, 11(%si)
167         /* save cylinder start */
168         movw    %ax, 12(%si)
170         /* do we need too many cylinders? */
171         cmpw    8(%si), %ax
172         jge     LOCAL(geometry_error)
174         /* determine the maximum sector length of this read */
175         movw    (%si), %ax      /* get number of sectors per track/head */
177         /* subtract sector start */
178         subb    10(%si), %al
180         /* how many do we really want to read? */
181         cmpw    %ax, 8(%di)     /* compare against total number of sectors */
184         /* which is greater? */
185         jg      2f
187         /* if less than, set to total */
188         movw    8(%di), %ax
191         /* subtract from total */
192         subw    %ax, 8(%di)
194         /* add into logical sector start */
195         addl    %eax, (%di)
196         adcl    $0, 4(%di)
199  *  This is the loop for taking care of BIOS geometry translation (ugh!)
200  */
202         /* get high bits of cylinder */
203         movb    13(%si), %dl
205         shlb    $6, %dl         /* shift left by 6 bits */
206         movb    10(%si), %cl    /* get sector */
208         incb    %cl             /* normalize sector (sectors go
209                                         from 1-N, not 0-(N-1) ) */
210         orb     %dl, %cl        /* composite together */
211         movb    12(%si), %ch    /* sector+hcyl in cl, cylinder in ch */
213         /* restore %dx */
214         popw    %dx
215         pushw   %dx
217         /* head number */
218         movb    11(%si), %dh
220         pushw   %ax     /* save %ax from destruction! */
223  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
224  *      Call with       %ah = 0x2
225  *                      %al = number of sectors
226  *                      %ch = cylinder
227  *                      %cl = sector (bits 6-7 are high bits of "cylinder")
228  *                      %dh = head
229  *                      %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
230  *                      %es:%bx = segment:offset of buffer
231  *      Return:
232  *                      %al = 0x0 on success; err code on failure
233  */
235         movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
236         movw    %bx, %es        /* load %es segment with disk buffer */
238         xorw    %bx, %bx        /* %bx = 0, put it at 0 in the segment */
239         movb    $0x2, %ah       /* function 2 */
240         int     $0x13
242         jc      LOCAL(read_error)
244         /* save source segment */
245         movw    %es, %bx
247 LOCAL(copy_buffer):
249         /* load addresses for copy from disk buffer to destination */
250         movw    10(%di), %es    /* load destination segment */
252         /* restore %ax */
253         popw    %ax
255         /* determine the next possible destination address (presuming
256                 512 byte sectors!) */
257         shlw    $5, %ax         /* shift %ax five bits to the left */
258         addw    %ax, 10(%di)    /* add the corrected value to the destination
259                                    address for next time */
261         /* save addressing regs */
262         pusha
263         pushw   %ds
265         /* get the copy length */
266         shlw    $3, %ax
267         movw    %ax, %cx
269         xorw    %di, %di        /* zero offset of destination addresses */
270         xorw    %si, %si        /* zero offset of source addresses */
271         movw    %bx, %ds        /* restore the source segment */
273         cld             /* sets the copy direction to forward */
275         /* perform copy */
276         rep             /* sets a repeat */
277         movsw           /* this runs the actual copy */
279         /* restore addressing regs and print a dot with correct DS
280            (MSG modifies SI, which is saved, and unused AX and BX) */
281         popw    %ds
282         MSG(notification_step)
283         popa
285         /* check if finished with this dataset */
286         cmpw    $0, 8(%di)
287         jne     LOCAL(setup_sectors)
289         /* update position to load from */
290         subw    $GRUB_BOOT_MACHINE_LIST_SIZE, %di
292         /* jump to bootloop */
293         jmp     LOCAL(bootloop)
295 /* END OF MAIN LOOP */
297 LOCAL(bootit):
298         /* print a newline */
299         MSG(notification_done)
300         popw    %dx     /* this makes sure %dl is our "boot" drive */
301         ljmp    $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
305  * BIOS Geometry translation error (past the end of the disk geometry!).
306  */
307 LOCAL(geometry_error):
308         MSG(geometry_error_string)
309         jmp     LOCAL(general_error)
312  * Read error on the disk.
313  */
314 LOCAL(read_error):
315         MSG(read_error_string)
317 LOCAL(general_error):
318         MSG(general_error_string)
320 /* go here when you need to stop the machine hard after an error condition */
321 LOCAL(stop):    jmp     LOCAL(stop)
323 notification_string:    .asciz "loading"
325 notification_step:      .asciz "."
326 notification_done:      .asciz "\r\n"
328 geometry_error_string:  .asciz "Geom"
329 read_error_string:      .asciz "Read"
330 general_error_string:   .asciz " Error"
333  * message: write the string pointed to by %si
335  *   WARNING: trashes %si, %ax, and %bx
336  */
338         /*
339          * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
340          *      %ah = 0xe       %al = character
341          *      %bh = page      %bl = foreground color (graphics modes)
342          */
344         movw    $0x0001, %bx
345         movb    $0xe, %ah
346         int     $0x10           /* display a byte */
348         incw    %si
349 LOCAL(message):
350         movb    (%si), %al
351         cmpb    $0, %al
352         jne     1b      /* if not end of string, jmp to display */
353         ret
356  *  This area is an empty space between the main body of code below which
357  *  grows up (fixed after compilation, but between releases it may change
358  *  in size easily), and the lists of sectors to read, which grows down
359  *  from a fixed top location.
360  */
362         .word 0
363         .word 0
365         . = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE
366 LOCAL(firstlist):       /* this label has to be before the first list entry!!! */
367         /* fill the first data listing with the default */
368 blocklist_default_start:
369         /* this is the sector start parameter, in logical sectors from
370            the start of the disk, sector 0 */
371         .long 2, 0
372 blocklist_default_len:
373         /* this is the number of sectors to read.  grub-mkimage
374            will fill this up */
375         .word 0
376 blocklist_default_seg:
377         /* this is the segment of the starting address to load the data into */
378         .word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20)