~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to grub-core/boot/i386/pc/boot.S

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*-Asm-*- */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 1999,2000,2001,2002,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/symbol.h>
 
21
#include <grub/boot.h>
 
22
#include <grub/machine/boot.h>
 
23
 
 
24
/*
 
25
 *  defines for the code go here
 
26
 */
 
27
 
 
28
        /* Print message string */
 
29
#define MSG(x)  movw $x, %si; call LOCAL(message)
 
30
#define ERR(x)  movw $x, %si; jmp LOCAL(error_message)
 
31
 
 
32
        .file   "boot.S"
 
33
 
 
34
        .text
 
35
 
 
36
        /* Tell GAS to generate 16-bit instructions so that this code works
 
37
           in real mode. */
 
38
        .code16
 
39
 
 
40
.globl _start, start;
 
41
_start:
 
42
start:
 
43
        /*
 
44
         * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
 
45
         */
 
46
 
 
47
        /*
 
48
         * Beginning of the sector is compatible with the FAT/HPFS BIOS
 
49
         * parameter block.
 
50
         */
 
51
 
 
52
        jmp     LOCAL(after_BPB)
 
53
        nop     /* do I care about this ??? */
 
54
 
 
55
        /*
 
56
         * This space is for the BIOS parameter block!!!!  Don't change
 
57
         * the first jump, nor start the code anywhere but right after
 
58
         * this area.
 
59
         */
 
60
 
 
61
        . = _start + GRUB_BOOT_MACHINE_BPB_START
 
62
        . = _start + 4
 
63
 
 
64
        /* scratch space */
 
65
mode:
 
66
        .byte   0
 
67
disk_address_packet:
 
68
sectors:
 
69
        .long   0
 
70
heads:
 
71
        .long   0
 
72
cylinders:
 
73
        .word   0
 
74
sector_start:
 
75
        .byte   0
 
76
head_start:
 
77
        .byte   0
 
78
cylinder_start:
 
79
        .word   0
 
80
        /* more space... */
 
81
 
 
82
        . = _start + GRUB_BOOT_MACHINE_BPB_END
 
83
 
 
84
        /*
 
85
         * End of BIOS parameter block.
 
86
         */
 
87
 
 
88
kernel_address:
 
89
        .word   GRUB_BOOT_MACHINE_KERNEL_ADDR
 
90
 
 
91
        . = _start + GRUB_BOOT_MACHINE_KERNEL_SECTOR
 
92
kernel_sector:
 
93
        .long   1, 0
 
94
 
 
95
        . = _start + GRUB_BOOT_MACHINE_BOOT_DRIVE
 
96
boot_drive:
 
97
        .byte 0xff      /* the disk to load kernel from */
 
98
                        /* 0xff means use the boot drive */
 
99
 
 
100
LOCAL(after_BPB):
 
101
 
 
102
/* general setup */
 
103
        cli             /* we're not safe here! */
 
104
 
 
105
        /*
 
106
         * This is a workaround for buggy BIOSes which don't pass boot
 
107
         * drive correctly. If GRUB is installed into a HDD, check if
 
108
         * DL is masked correctly. If not, assume that the BIOS passed
 
109
         * a bogus value and set DL to 0x80, since this is the only
 
110
         * possible boot drive. If GRUB is installed into a floppy,
 
111
         * this does nothing (only jump).
 
112
         */
 
113
        . = _start + GRUB_BOOT_MACHINE_DRIVE_CHECK
 
114
boot_drive_check:
 
115
        jmp     3f      /* grub-setup may overwrite this jump */
 
116
        testb   $0x80, %dl
 
117
        jz      2f
 
118
3:
 
119
        /* Ignore %dl different from 0-0x0f and 0x80-0x8f.  */
 
120
        testb   $0x70, %dl
 
121
        jz      1f
 
122
2:      
 
123
        movb    $0x80, %dl
 
124
1:
 
125
        /*
 
126
         * ljmp to the next instruction because some bogus BIOSes
 
127
         * jump to 07C0:0000 instead of 0000:7C00.
 
128
         */
 
129
        ljmp    $0, $real_start
 
130
 
 
131
real_start:
 
132
 
 
133
        /* set up %ds and %ss as offset from 0 */
 
134
        xorw    %ax, %ax
 
135
        movw    %ax, %ds
 
136
        movw    %ax, %ss
 
137
 
 
138
        /* set up the REAL stack */
 
139
        movw    $GRUB_BOOT_MACHINE_STACK_SEG, %sp
 
140
 
 
141
        sti             /* we're safe again */
 
142
 
 
143
        /*
 
144
         *  Check if we have a forced disk reference here
 
145
         */
 
146
        movb   boot_drive, %al
 
147
        cmpb    $0xff, %al
 
148
        je      1f
 
149
        movb    %al, %dl
 
150
1:
 
151
        /* save drive reference first thing! */
 
152
        pushw   %dx
 
153
 
 
154
        /* print a notification message on the screen */
 
155
        MSG(notification_string)
 
156
 
 
157
        /* set %si to the disk address packet */
 
158
        movw    $disk_address_packet, %si
 
159
 
 
160
        /* check if LBA is supported */
 
161
        movb    $0x41, %ah
 
162
        movw    $0x55aa, %bx
 
163
        int     $0x13
 
164
 
 
165
        /*
 
166
         *  %dl may have been clobbered by INT 13, AH=41H.
 
167
         *  This happens, for example, with AST BIOS 1.04.
 
168
         */
 
169
        popw    %dx
 
170
        pushw   %dx
 
171
 
 
172
        /* use CHS if fails */
 
173
        jc      LOCAL(chs_mode)
 
174
        cmpw    $0xaa55, %bx
 
175
        jne     LOCAL(chs_mode)
 
176
 
 
177
        andw    $1, %cx
 
178
        jz      LOCAL(chs_mode)
 
179
 
 
180
lba_mode:
 
181
        xorw    %ax, %ax
 
182
        movw    %ax, 4(%si)
 
183
 
 
184
        incw    %ax
 
185
        /* set the mode to non-zero */
 
186
        movb    %al, -1(%si)
 
187
 
 
188
        /* the blocks */
 
189
        movw    %ax, 2(%si)
 
190
 
 
191
        /* the size and the reserved byte */
 
192
        movw    $0x0010, (%si)
 
193
 
 
194
        /* the absolute address */
 
195
        movl    kernel_sector, %ebx
 
196
        movl    %ebx, 8(%si)
 
197
        movl    kernel_sector + 4, %ebx
 
198
        movl    %ebx, 12(%si)
 
199
 
 
200
        /* the segment of buffer address */
 
201
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
 
202
 
 
203
/*
 
204
 * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
 
205
 *      Call with       %ah = 0x42
 
206
 *                      %dl = drive number
 
207
 *                      %ds:%si = segment:offset of disk address packet
 
208
 *      Return:
 
209
 *                      %al = 0x0 on success; err code on failure
 
210
 */
 
211
 
 
212
        movb    $0x42, %ah
 
213
        int     $0x13
 
214
 
 
215
        /* LBA read is not supported, so fallback to CHS.  */
 
216
        jc      LOCAL(chs_mode)
 
217
 
 
218
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
 
219
        jmp     LOCAL(copy_buffer)
 
220
 
 
221
LOCAL(chs_mode):
 
222
        /*
 
223
         *  Determine the hard disk geometry from the BIOS!
 
224
         *  We do this first, so that LS-120 IDE floppies work correctly.
 
225
         */
 
226
        movb    $8, %ah
 
227
        int     $0x13
 
228
        jnc     LOCAL(final_init)
 
229
 
 
230
        /*
 
231
         *  The call failed, so maybe use the floppy probe instead.
 
232
         */
 
233
        testb   $GRUB_BOOT_MACHINE_BIOS_HD_FLAG, %dl
 
234
        jz      LOCAL(floppy_probe)
 
235
 
 
236
        /* Nope, we definitely have a hard disk, and we're screwed. */
 
237
        ERR(hd_probe_error_string)
 
238
 
 
239
LOCAL(final_init):
 
240
        /* set the mode to zero */
 
241
        movzbl  %dh, %eax
 
242
        movb    %ah, -1(%si)
 
243
 
 
244
        /* save number of heads */
 
245
        incw    %ax
 
246
        movl    %eax, 4(%si)
 
247
 
 
248
        movzbw  %cl, %dx
 
249
        shlw    $2, %dx
 
250
        movb    %ch, %al
 
251
        movb    %dh, %ah
 
252
 
 
253
        /* save number of cylinders */
 
254
        incw    %ax
 
255
        movw    %ax, 8(%si)
 
256
 
 
257
        movzbw  %dl, %ax
 
258
        shrb    $2, %al
 
259
 
 
260
        /* save number of sectors */
 
261
        movl    %eax, (%si)
 
262
 
 
263
setup_sectors:
 
264
        /* load logical sector start (top half) */
 
265
        movl    kernel_sector + 4, %eax
 
266
 
 
267
        orl     %eax, %eax
 
268
        jnz     LOCAL(geometry_error)
 
269
 
 
270
        /* load logical sector start (bottom half) */
 
271
        movl    kernel_sector, %eax
 
272
 
 
273
        /* zero %edx */
 
274
        xorl    %edx, %edx
 
275
 
 
276
        /* divide by number of sectors */
 
277
        divl    (%si)
 
278
 
 
279
        /* save sector start */
 
280
        movb    %dl, %cl
 
281
 
 
282
        xorw    %dx, %dx        /* zero %edx */
 
283
        divl    4(%si)          /* divide by number of heads */
 
284
 
 
285
        /* do we need too many cylinders? */
 
286
        cmpw    8(%si), %ax
 
287
        jge     LOCAL(geometry_error)
 
288
 
 
289
        /* normalize sector start (1-based) */
 
290
        incb    %cl
 
291
 
 
292
        /* low bits of cylinder start */
 
293
        movb    %al, %ch
 
294
 
 
295
        /* high bits of cylinder start */
 
296
        xorb    %al, %al
 
297
        shrw    $2, %ax
 
298
        orb     %al, %cl
 
299
 
 
300
        /* save head start */
 
301
        movb    %dl, %al
 
302
 
 
303
        /* restore %dl */
 
304
        popw    %dx
 
305
 
 
306
        /* head start */
 
307
        movb    %al, %dh
 
308
 
 
309
/*
 
310
 * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
 
311
 *      Call with       %ah = 0x2
 
312
 *                      %al = number of sectors
 
313
 *                      %ch = cylinder
 
314
 *                      %cl = sector (bits 6-7 are high bits of "cylinder")
 
315
 *                      %dh = head
 
316
 *                      %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
 
317
 *                      %es:%bx = segment:offset of buffer
 
318
 *      Return:
 
319
 *                      %al = 0x0 on success; err code on failure
 
320
 */
 
321
 
 
322
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
 
323
        movw    %bx, %es        /* load %es segment with disk buffer */
 
324
 
 
325
        xorw    %bx, %bx        /* %bx = 0, put it at 0 in the segment */
 
326
        movw    $0x0201, %ax    /* function 2 */
 
327
        int     $0x13
 
328
 
 
329
        jc      LOCAL(read_error)
 
330
 
 
331
        movw    %es, %bx
 
332
 
 
333
LOCAL(copy_buffer):
 
334
        /*
 
335
         * We need to save %cx and %si because the startup code in
 
336
         * kernel uses them without initializing them.
 
337
         */
 
338
        pusha
 
339
        pushw   %ds
 
340
 
 
341
        movw    $0x100, %cx
 
342
        movw    %bx, %ds
 
343
        xorw    %si, %si
 
344
        movw    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
 
345
        movw    %si, %es
 
346
 
 
347
        cld
 
348
 
 
349
        rep
 
350
        movsw
 
351
 
 
352
        popw    %ds
 
353
        popa
 
354
 
 
355
        /* boot kernel */
 
356
        jmp     *(kernel_address)
 
357
 
 
358
/* END OF MAIN LOOP */
 
359
 
 
360
/*
 
361
 * BIOS Geometry translation error (past the end of the disk geometry!).
 
362
 */
 
363
LOCAL(geometry_error):
 
364
        ERR(geometry_error_string)
 
365
 
 
366
/*
 
367
 * Read error on the disk.
 
368
 */
 
369
LOCAL(read_error):
 
370
        movw    $read_error_string, %si
 
371
LOCAL(error_message):
 
372
        call    LOCAL(message)
 
373
LOCAL(general_error):
 
374
        MSG(general_error_string)
 
375
 
 
376
/* go here when you need to stop the machine hard after an error condition */
 
377
        /* tell the BIOS a boot failure, which may result in no effect */
 
378
        int     $0x18
 
379
LOCAL(stop):
 
380
        jmp     LOCAL(stop)
 
381
 
 
382
notification_string:    .asciz "GRUB "
 
383
geometry_error_string:  .asciz "Geom"
 
384
hd_probe_error_string:  .asciz "Hard Disk"
 
385
read_error_string:      .asciz "Read"
 
386
general_error_string:   .asciz " Error\r\n"
 
387
 
 
388
/*
 
389
 * message: write the string pointed to by %si
 
390
 *
 
391
 *   WARNING: trashes %si, %ax, and %bx
 
392
 */
 
393
 
 
394
        /*
 
395
         * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
 
396
         *      %ah = 0xe       %al = character
 
397
         *      %bh = page      %bl = foreground color (graphics modes)
 
398
         */
 
399
1:
 
400
        movw    $0x0001, %bx
 
401
        movb    $0xe, %ah
 
402
        int     $0x10           /* display a byte */
 
403
LOCAL(message):
 
404
        lodsb
 
405
        cmpb    $0, %al
 
406
        jne     1b      /* if not end of string, jmp to display */
 
407
        ret
 
408
 
 
409
        /*
 
410
         *  Windows NT breaks compatibility by embedding a magic
 
411
         *  number here.
 
412
         */
 
413
 
 
414
        . = _start + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
 
415
nt_magic:
 
416
        .long 0
 
417
        .word 0
 
418
 
 
419
        /*
 
420
         *  This is where an MBR would go if on a hard disk.  The code
 
421
         *  here isn't even referenced unless we're on a floppy.  Kinda
 
422
         *  sneaky, huh?
 
423
         */
 
424
 
 
425
        . = _start + GRUB_BOOT_MACHINE_PART_START
 
426
part_start:
 
427
 
 
428
probe_values:
 
429
        .byte   36, 18, 15, 9, 0
 
430
 
 
431
LOCAL(floppy_probe):
 
432
/*
 
433
 *  Perform floppy probe.
 
434
 */
 
435
 
 
436
        movw    $probe_values - 1, %si
 
437
 
 
438
LOCAL(probe_loop):
 
439
        /* reset floppy controller INT 13h AH=0 */
 
440
        xorw    %ax, %ax
 
441
        int     $0x13
 
442
 
 
443
        incw    %si
 
444
        movb    (%si), %cl
 
445
 
 
446
        /* if number of sectors is 0, display error and die */
 
447
        cmpb    $0, %cl
 
448
        jne     1f
 
449
 
 
450
/*
 
451
 * Floppy disk probe failure.
 
452
 */
 
453
        MSG(fd_probe_error_string)
 
454
        jmp     LOCAL(general_error)
 
455
 
 
456
/* "Floppy" */
 
457
fd_probe_error_string:  .asciz "Floppy"
 
458
 
 
459
1:
 
460
        /* perform read */
 
461
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
 
462
        movw    $0x201, %ax
 
463
        movb    $0, %ch
 
464
        movb    $0, %dh
 
465
        int     $0x13
 
466
 
 
467
        /* if error, jump to "LOCAL(probe_loop)" */
 
468
        jc      LOCAL(probe_loop)
 
469
 
 
470
        /* %cl is already the correct value! */
 
471
        movb    $1, %dh
 
472
        movb    $79, %ch
 
473
 
 
474
        jmp     LOCAL(final_init)
 
475
 
 
476
        . = _start + GRUB_BOOT_MACHINE_PART_END
 
477
 
 
478
/* the last 2 bytes in the sector 0 contain the signature */
 
479
        .word   GRUB_BOOT_MACHINE_SIGNATURE