~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/kern/i386/pc/startup.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
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 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
 */
 
18
 
 
19
 
 
20
/*
 
21
 * Note: These functions defined in this file may be called from C.
 
22
 *       Be careful of that you must not modify some registers. Quote
 
23
 *       from gcc-2.95.2/gcc/config/i386/i386.h:
 
24
 
 
25
   1 for registers not available across function calls.
 
26
   These must include the FIXED_REGISTERS and also any
 
27
   registers that can be used without being saved.
 
28
   The latter must include the registers where values are returned
 
29
   and the register where structure-value addresses are passed.
 
30
   Aside from that, you can include as many other registers as you like.
 
31
 
 
32
  ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
 
33
{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1 }
 
34
 */
 
35
 
 
36
/*
 
37
 * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
 
38
 *       So the first three arguments are passed in %eax, %edx, and %ecx,
 
39
 *       respectively, and if a function has a fixed number of arguments
 
40
 *       and the number is greater than three, the function must return
 
41
 *       with "ret $N" where N is ((the number of arguments) - 3) * 4.
 
42
 */
 
43
 
 
44
#include <config.h>
 
45
#include <grub/symbol.h>
 
46
#include <grub/boot.h>
 
47
#include <grub/machine/boot.h>
 
48
#include <grub/machine/memory.h>
 
49
#include <grub/machine/console.h>
 
50
#include <grub/cpu/linux.h>
 
51
#include <grub/machine/kernel.h>
 
52
#include <grub/term.h>
 
53
#include <multiboot.h>
 
54
#include <multiboot2.h>
 
55
 
 
56
#define ABS(x)  ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
 
57
 
 
58
        .file   "startup.S"
 
59
 
 
60
        .text
 
61
 
 
62
        /* Tell GAS to generate 16-bit instructions so that this code works
 
63
           in real mode. */
 
64
        .code16
 
65
 
 
66
        .globl  start, _start
 
67
start:
 
68
_start:
 
69
LOCAL (base):
 
70
        /*
 
71
         *  Guarantee that "main" is loaded at 0x0:0x8200.
 
72
         */
 
73
#ifdef __APPLE__
 
74
        ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
 
75
#else
 
76
        ljmp $0, $ABS(LOCAL (codestart))
 
77
#endif
 
78
        /*
 
79
         *  Compatibility version number
 
80
         *
 
81
         *  These MUST be at byte offset 6 and 7 of the executable
 
82
         *  DO NOT MOVE !!!
 
83
         */
 
84
        . = _start + 0x6
 
85
        .byte   GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
 
86
 
 
87
        /*
 
88
         *  This is a special data area 8 bytes from the beginning.
 
89
         */
 
90
 
 
91
        . = _start + 0x8
 
92
 
 
93
VARIABLE(grub_total_module_size)
 
94
        .long   0
 
95
VARIABLE(grub_kernel_image_size)
 
96
        .long   0
 
97
VARIABLE(grub_compressed_size)
 
98
        .long   0
 
99
VARIABLE(grub_install_dos_part)
 
100
        .long   0xFFFFFFFF
 
101
VARIABLE(grub_install_bsd_part)
 
102
        .long   0xFFFFFFFF
 
103
reed_solomon_redundancy:
 
104
        .long   0
 
105
 
 
106
#ifdef APPLE_CC
 
107
bss_start:
 
108
        .long 0
 
109
bss_end:
 
110
        .long 0
 
111
#endif
 
112
/*
 
113
 *  This is the area for all of the special variables.
 
114
 */
 
115
 
 
116
VARIABLE(grub_boot_drive)
 
117
        .byte   0
 
118
 
 
119
/* the real mode code continues... */
 
120
LOCAL (codestart):
 
121
        cli             /* we're not safe here! */
 
122
 
 
123
        /* set up %ds, %ss, and %es */
 
124
        xorw    %ax, %ax
 
125
        movw    %ax, %ds
 
126
        movw    %ax, %ss
 
127
        movw    %ax, %es
 
128
 
 
129
        /* set up the real mode/BIOS stack */
 
130
        movl    $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
 
131
        movl    %ebp, %esp
 
132
 
 
133
        sti             /* we're safe again */
 
134
 
 
135
        /* save the boot drive */
 
136
        ADDR32  movb    %dl, EXT_C(grub_boot_drive)
 
137
 
 
138
        /* reset disk system (%ah = 0) */
 
139
        int     $0x13
 
140
 
 
141
        /* transition to protected mode */
 
142
        DATA32  call real_to_prot
 
143
 
 
144
        /* The ".code32" directive takes GAS out of 16-bit mode. */
 
145
        .code32
 
146
 
 
147
        incl    %eax
 
148
        call    grub_gate_a20
 
149
 
 
150
        movl    EXT_C(grub_compressed_size), %edx
 
151
        addl    $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx
 
152
        movl    reed_solomon_redundancy, %ecx
 
153
        leal    _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax
 
154
        testl   %edx, %edx
 
155
        jz post_reed_solomon
 
156
        call    EXT_C (grub_reed_solomon_recover)
 
157
        jmp post_reed_solomon
 
158
 
 
159
#include <rs_decoder.S>
 
160
 
 
161
        .text
 
162
 
 
163
        . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART
 
164
/*
 
165
 * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
 
166
 * This uses the a.out kludge to load raw binary to the area starting at 1MB,
 
167
 * and relocates itself after loaded.
 
168
 */
 
169
        .p2align        2       /* force 4-byte alignment */
 
170
multiboot_header:
 
171
        /* magic */
 
172
        .long   0x1BADB002
 
173
        /* flags */
 
174
        .long   (1 << 16)
 
175
        /* checksum */
 
176
        .long   -0x1BADB002 - (1 << 16)
 
177
        /* header addr */
 
178
        .long   multiboot_header - _start + 0x100000 + 0x200
 
179
        /* load addr */
 
180
        .long   0x100000
 
181
        /* load end addr */
 
182
        .long   0
 
183
        /* bss end addr */
 
184
        .long   0
 
185
        /* entry addr */
 
186
        .long   multiboot_entry - _start + 0x100000 + 0x200
 
187
 
 
188
multiboot_entry:
 
189
        .code32
 
190
        /* obtain the boot device */
 
191
        movl    12(%ebx), %edx
 
192
 
 
193
        movl    $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
 
194
        movl    %ebp, %esp
 
195
 
 
196
        /* relocate the code */
 
197
        movl    $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
 
198
        addl    EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
 
199
        movl    $0x100000, %esi
 
200
        movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
 
201
        cld
 
202
        rep
 
203
        movsb
 
204
        /* jump to the real address */
 
205
        movl    $multiboot_trampoline, %eax
 
206
        jmp     *%eax
 
207
 
 
208
multiboot_trampoline:
 
209
        /* fill the boot information */
 
210
        movl    %edx, %eax
 
211
        shrl    $8, %eax
 
212
        xorl    %ebx, %ebx
 
213
        cmpb    $0xFF, %ah
 
214
        je      1f
 
215
        movb    %ah, %bl
 
216
        movl    %ebx, EXT_C(grub_install_dos_part)
 
217
1:
 
218
        cmpb    $0xFF, %al
 
219
        je      2f
 
220
        movb    %al, %bl
 
221
        movl    %ebx, EXT_C(grub_install_bsd_part)
 
222
2:
 
223
        shrl    $24, %edx
 
224
        movb    $0xFF, %dh
 
225
        /* enter the usual booting */
 
226
        call    prot_to_real
 
227
        jmp     LOCAL (codestart)
 
228
 
 
229
post_reed_solomon:
 
230
 
 
231
#ifdef ENABLE_LZMA
 
232
        movl    $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
 
233
        movl    $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
 
234
        pushl   %edi
 
235
        pushl   %esi
 
236
        movl    EXT_C(grub_kernel_image_size), %ecx
 
237
        addl    EXT_C(grub_total_module_size), %ecx
 
238
        subl    $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
 
239
        pushl   %ecx
 
240
        leal    (%edi, %ecx), %ebx
 
241
        call    _LzmaDecodeA
 
242
        /* _LzmaDecodeA clears DF, so no need to run cld */
 
243
        popl    %ecx
 
244
        popl    %edi
 
245
        popl    %esi
 
246
#endif
 
247
 
 
248
        /* copy back the decompressed part (except the modules) */
 
249
        subl    EXT_C(grub_total_module_size), %ecx
 
250
        rep
 
251
        movsb
 
252
 
 
253
#if 0
 
254
        /* copy modules before cleaning out the bss */
 
255
        movl    EXT_C(grub_total_module_size), %ecx
 
256
        movl    EXT_C(grub_kernel_image_size), %esi
 
257
        addl    %ecx, %esi
 
258
        addl    $_start, %esi
 
259
        decl    %esi
 
260
        movl    $END_SYMBOL, %edi
 
261
        addl    %ecx, %edi
 
262
        decl    %edi
 
263
        std
 
264
        rep
 
265
        movsb
 
266
#endif
 
267
 
 
268
#ifdef APPLE_CC
 
269
        /* clean out the bss */
 
270
        bss_start_abs = ABS (bss_start)
 
271
        bss_end_abs = ABS (bss_end)
 
272
 
 
273
        movl    bss_start_abs, %edi
 
274
 
 
275
        /* compute the bss length */
 
276
        movl    bss_end_abs, %ecx
 
277
        subl    %edi, %ecx
 
278
#else
 
279
        /* clean out the bss */
 
280
        movl    $BSS_START_SYMBOL, %edi
 
281
 
 
282
        /* compute the bss length */
 
283
        movl    $END_SYMBOL, %ecx
 
284
        subl    %edi, %ecx
 
285
#endif
 
286
 
 
287
        /* clean out */
 
288
        xorl    %eax, %eax
 
289
        cld
 
290
        rep
 
291
        stosb
 
292
 
 
293
        /*
 
294
         *  Call the start of main body of C code.
 
295
         */
 
296
        call EXT_C(grub_main)
 
297
 
 
298
#include "../realmode.S"
 
299
 
 
300
/*
 
301
 * grub_gate_a20(int on)
 
302
 *
 
303
 * Gate address-line 20 for high memory.
 
304
 *
 
305
 * This routine is probably overconservative in what it does, but so what?
 
306
 *
 
307
 * It also eats any keystrokes in the keyboard buffer.  :-(
 
308
 */
 
309
 
 
310
grub_gate_a20:  
 
311
        movl    %eax, %edx
 
312
 
 
313
gate_a20_test_current_state:
 
314
        /* first of all, test if already in a good state */
 
315
        call    gate_a20_check_state
 
316
        cmpb    %al, %dl
 
317
        jnz     gate_a20_try_bios
 
318
        ret
 
319
 
 
320
gate_a20_try_bios:
 
321
        /* second, try a BIOS call */
 
322
        pushl   %ebp
 
323
        call    prot_to_real
 
324
 
 
325
        .code16
 
326
        movw    $0x2400, %ax
 
327
        testb   %dl, %dl
 
328
        jz      1f
 
329
        incw    %ax
 
330
1:      int     $0x15
 
331
 
 
332
        DATA32  call    real_to_prot
 
333
        .code32
 
334
 
 
335
        popl    %ebp
 
336
        call    gate_a20_check_state
 
337
        cmpb    %al, %dl
 
338
        jnz     gate_a20_try_system_control_port_a
 
339
        ret
 
340
 
 
341
gate_a20_try_system_control_port_a:
 
342
        /*
 
343
         * In macbook, the keyboard test would hang the machine, so we move
 
344
         * this forward.
 
345
         */
 
346
        /* fourth, try the system control port A */
 
347
        inb     $0x92
 
348
        andb    $(~0x03), %al
 
349
        testb   %dl, %dl
 
350
        jz      6f
 
351
        orb     $0x02, %al
 
352
6:      outb    $0x92
 
353
 
 
354
        /* When turning off Gate A20, do not check the state strictly,
 
355
           because a failure is not fatal usually, and Gate A20 is always
 
356
           on some modern machines.  */
 
357
        testb   %dl, %dl
 
358
        jz      7f
 
359
        call    gate_a20_check_state
 
360
        cmpb    %al, %dl
 
361
        jnz     gate_a20_try_keyboard_controller
 
362
7:      ret
 
363
 
 
364
gate_a20_flush_keyboard_buffer:
 
365
        inb     $0x64
 
366
        andb    $0x02, %al
 
367
        jnz     gate_a20_flush_keyboard_buffer
 
368
2:
 
369
        inb     $0x64
 
370
        andb    $0x01, %al
 
371
        jz      3f
 
372
        inb     $0x60
 
373
        jmp     2b
 
374
3:
 
375
        ret
 
376
 
 
377
gate_a20_try_keyboard_controller:
 
378
        /* third, try the keyboard controller */
 
379
        call    gate_a20_flush_keyboard_buffer
 
380
 
 
381
        movb    $0xd1, %al
 
382
        outb    $0x64
 
383
4:
 
384
        inb     $0x64
 
385
        andb    $0x02, %al
 
386
        jnz     4b
 
387
 
 
388
        movb    $0xdd, %al
 
389
        testb   %dl, %dl
 
390
        jz      5f
 
391
        orb     $0x02, %al
 
392
5:      outb    $0x60
 
393
        call    gate_a20_flush_keyboard_buffer
 
394
 
 
395
        /* output a dummy command (USB keyboard hack) */
 
396
        movb    $0xff, %al
 
397
        outb    $0x64
 
398
        call    gate_a20_flush_keyboard_buffer
 
399
 
 
400
        call    gate_a20_check_state
 
401
        cmpb    %al, %dl
 
402
        /* everything failed, so restart from the beginning */
 
403
        jnz     gate_a20_try_bios
 
404
        ret
 
405
 
 
406
gate_a20_check_state:
 
407
        /* iterate the checking for a while */
 
408
        movl    $100, %ecx
 
409
1:
 
410
        call    3f
 
411
        cmpb    %al, %dl
 
412
        jz      2f
 
413
        loop    1b
 
414
2:
 
415
        ret
 
416
3:
 
417
        pushl   %ebx
 
418
        pushl   %ecx
 
419
        xorl    %eax, %eax
 
420
        /* compare the byte at 0x8000 with that at 0x108000 */
 
421
        movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
 
422
        pushl   %ebx
 
423
        /* save the original byte in CL */
 
424
        movb    (%ebx), %cl
 
425
        /* store the value at 0x108000 in AL */
 
426
        addl    $0x100000, %ebx
 
427
        movb    (%ebx), %al
 
428
        /* try to set one less value at 0x8000 */
 
429
        popl    %ebx
 
430
        movb    %al, %ch
 
431
        decb    %ch
 
432
        movb    %ch, (%ebx)
 
433
        /* serialize */
 
434
        outb    %al, $0x80
 
435
        outb    %al, $0x80
 
436
        /* obtain the value at 0x108000 in CH */
 
437
        pushl   %ebx
 
438
        addl    $0x100000, %ebx
 
439
        movb    (%ebx), %ch
 
440
        /* this result is 1 if A20 is on or 0 if it is off */
 
441
        subb    %ch, %al
 
442
        xorb    $1, %al
 
443
        /* restore the original */
 
444
        popl    %ebx
 
445
        movb    %cl, (%ebx)
 
446
        popl    %ecx
 
447
        popl    %ebx
 
448
        ret
 
449
 
 
450
#ifdef ENABLE_LZMA
 
451
#include "lzma_decode.S"
 
452
#endif
 
453
 
 
454
/*
 
455
 * The code beyond this point is compressed.  Assert that the uncompressed
 
456
 * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
 
457
 */
 
458
        . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
 
459
 
 
460
        . = _start + GRUB_KERNEL_MACHINE_PREFIX
 
461
VARIABLE(grub_prefix)
 
462
        /* to be filled by grub-mkimage */
 
463
 
 
464
        /*
 
465
         *  Leave some breathing room for the prefix.
 
466
         */
 
467
        . = _start + GRUB_KERNEL_MACHINE_PREFIX_END
 
468
 
 
469
 
 
470
 
 
471
/*
 
472
 * grub_exit()
 
473
 *
 
474
 * Exit the system.
 
475
 */
 
476
FUNCTION(grub_exit)
 
477
        call    prot_to_real
 
478
        .code16
 
479
        /* Tell the BIOS a boot failure. If this does not work, reboot.  */
 
480
        int     $0x18
 
481
        jmp     cold_reboot
 
482
        .code32
 
483
 
 
484
/*
 
485
 *  void grub_chainloader_real_boot (int drive, void *part_addr)
 
486
 *
 
487
 *  This starts another boot loader.
 
488
 */
 
489
 
 
490
FUNCTION(grub_chainloader_real_boot)
 
491
        pushl   %edx
 
492
        pushl   %eax
 
493
 
 
494
        /* Turn off Gate A20 */
 
495
        xorl    %eax, %eax
 
496
        call    grub_gate_a20
 
497
 
 
498
        /* set up to pass boot drive */
 
499
        popl    %edx
 
500
 
 
501
        /* ESI must point to a partition table entry */
 
502
        popl    %esi
 
503
 
 
504
        call    prot_to_real
 
505
        .code16
 
506
        ljmp    $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
 
507
        .code32
 
508
 
 
509
/*
 
510
 * void grub_console_putchar (int c)
 
511
 *
 
512
 * Put the character C on the console. Because GRUB wants to write a
 
513
 * character with an attribute, this implementation is a bit tricky.
 
514
 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
 
515
 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
 
516
 * save the current position, restore the original position, write the
 
517
 * character and the attribute, and restore the current position.
 
518
 *
 
519
 * The reason why this is so complicated is that there is no easy way to
 
520
 * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
 
521
 * support setting a background attribute.
 
522
 */
 
523
FUNCTION(grub_console_putchar)
 
524
        /* Retrieve the base character.  */
 
525
        movl    0(%edx), %edx
 
526
        pusha
 
527
        movb    EXT_C(grub_console_cur_color), %bl
 
528
 
 
529
        call    prot_to_real
 
530
        .code16
 
531
        movb    %dl, %al
 
532
        xorb    %bh, %bh
 
533
 
 
534
        /* use teletype output if control character */
 
535
        cmpb    $0x7, %al
 
536
        je      1f
 
537
        cmpb    $0x8, %al
 
538
        je      1f
 
539
        cmpb    $0xa, %al
 
540
        je      1f
 
541
        cmpb    $0xd, %al
 
542
        je      1f
 
543
 
 
544
        /* save the character and the attribute on the stack */
 
545
        pushw   %ax
 
546
        pushw   %bx
 
547
 
 
548
        /* get the current position */
 
549
        movb    $0x3, %ah
 
550
        int     $0x10
 
551
 
 
552
        /* check the column with the width */
 
553
        cmpb    $79, %dl
 
554
        jl      2f
 
555
 
 
556
        /* print CR and LF, if next write will exceed the width */
 
557
        movw    $0x0e0d, %ax
 
558
        int     $0x10
 
559
        movb    $0x0a, %al
 
560
        int     $0x10
 
561
 
 
562
        /* get the current position */
 
563
        movb    $0x3, %ah
 
564
        int     $0x10
 
565
 
 
566
2:
 
567
        /* restore the character and the attribute */
 
568
        popw    %bx
 
569
        popw    %ax
 
570
 
 
571
        /* write the character with the attribute */
 
572
        movb    $0x9, %ah
 
573
        movw    $1, %cx
 
574
        int     $0x10
 
575
 
 
576
        /* move the cursor forward */
 
577
        incb    %dl
 
578
        movb    $0x2, %ah
 
579
        int     $0x10
 
580
 
 
581
        jmp     3f
 
582
 
 
583
1:      movw    $1, %bx
 
584
        movb    $0xe, %ah
 
585
        int     $0x10
 
586
 
 
587
3:      DATA32  call    real_to_prot
 
588
        .code32
 
589
 
 
590
        popa
 
591
        ret
 
592
 
 
593
 
 
594
LOCAL(bypass_table):
 
595
        .word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
 
596
        .word 0x1c00 | '\n'
 
597
LOCAL(bypass_table_end):
 
598
 
 
599
/*
 
600
 * int grub_console_getkey (void)
 
601
 *      if there is a character pending, return it; otherwise return -1
 
602
 * BIOS call "INT 16H Function 01H" to check whether a character is pending
 
603
 *      Call with       %ah = 0x1
 
604
 *      Return:
 
605
 *              If key waiting to be input:
 
606
 *                      %ah = keyboard scan code
 
607
 *                      %al = ASCII character
 
608
 *                      Zero flag = clear
 
609
 *              else
 
610
 *                      Zero flag = set
 
611
 * BIOS call "INT 16H Function 00H" to read character from keyboard
 
612
 *      Call with       %ah = 0x0
 
613
 *      Return:         %ah = keyboard scan code
 
614
 *                      %al = ASCII character
 
615
 */
 
616
 
 
617
FUNCTION(grub_console_getkey)
 
618
        pushl   %ebp
 
619
        pushl   %edi
 
620
 
 
621
        call    prot_to_real
 
622
        .code16
 
623
 
 
624
        /*
 
625
         * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
 
626
         * cause the machine to hang at the second keystroke. However, we can
 
627
         * work around this problem by ensuring the presence of keystroke with
 
628
         * INT 16/AH = 1 before calling INT 16/AH = 0.
 
629
         */
 
630
 
 
631
        movb    $1, %ah
 
632
        int     $0x16
 
633
        jz      notpending
 
634
 
 
635
        movb    $0, %ah
 
636
        int     $0x16
 
637
 
 
638
        xorl    %edx, %edx
 
639
        movw    %ax, %dx                /* real_to_prot uses %eax */
 
640
 
 
641
        DATA32  call    real_to_prot
 
642
        .code32
 
643
 
 
644
        movl    $0xff, %eax
 
645
        testl   %eax, %edx
 
646
        jz      1f
 
647
 
 
648
        andl    %edx, %eax
 
649
        cmpl    $0x20, %eax
 
650
        jae     2f
 
651
        movl    %edx, %eax
 
652
        leal    LOCAL(bypass_table), %edi
 
653
        movl    $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx
 
654
        repne scasw 
 
655
        jz      3f
 
656
 
 
657
        andl    $0xff, %eax
 
658
        addl    $(('a' - 1) | GRUB_TERM_CTRL), %eax
 
659
        jmp     2f
 
660
3:
 
661
        andl    $0xff, %eax
 
662
        jmp 2f
 
663
 
 
664
1:      movl    %edx, %eax
 
665
        shrl    $8, %eax
 
666
        orl     $GRUB_TERM_EXTENDED, %eax
 
667
2:
 
668
        popl    %edi
 
669
        popl    %ebp
 
670
        ret
 
671
 
 
672
notpending:     
 
673
        .code16
 
674
        DATA32  call    real_to_prot
 
675
        .code32
 
676
#if GRUB_TERM_NO_KEY != 0
 
677
#error Fix this asm code
 
678
#endif
 
679
        jmp 2b
 
680
 
 
681
 
 
682
/*
 
683
 * grub_uint16_t grub_console_getxy (void)
 
684
 * BIOS call "INT 10H Function 03h" to get cursor position
 
685
 *      Call with       %ah = 0x03
 
686
 *                      %bh = page
 
687
 *      Returns         %ch = starting scan line
 
688
 *                      %cl = ending scan line
 
689
 *                      %dh = row (0 is top)
 
690
 *                      %dl = column (0 is left)
 
691
 */
 
692
 
 
693
 
 
694
FUNCTION(grub_console_getxy)
 
695
        pushl   %ebp
 
696
        pushl   %ebx                    /* save EBX */
 
697
 
 
698
        call    prot_to_real
 
699
        .code16
 
700
 
 
701
        xorb    %bh, %bh                /* set page to 0 */
 
702
        movb    $0x3, %ah
 
703
        int     $0x10                   /* get cursor position */
 
704
 
 
705
        DATA32  call    real_to_prot
 
706
        .code32
 
707
 
 
708
        movb    %dl, %ah
 
709
        movb    %dh, %al
 
710
 
 
711
        popl    %ebx
 
712
        popl    %ebp
 
713
        ret
 
714
 
 
715
 
 
716
/*
 
717
 * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
 
718
 * BIOS call "INT 10H Function 02h" to set cursor position
 
719
 *      Call with       %ah = 0x02
 
720
 *                      %bh = page
 
721
 *                      %dh = row (0 is top)
 
722
 *                      %dl = column (0 is left)
 
723
 */
 
724
 
 
725
 
 
726
FUNCTION(grub_console_gotoxy)
 
727
        pushl   %ebp
 
728
        pushl   %ebx                    /* save EBX */
 
729
 
 
730
        movb    %cl, %dh        /* %dh = y */
 
731
        /* %dl = x */
 
732
 
 
733
        call    prot_to_real
 
734
        .code16
 
735
 
 
736
        xorb    %bh, %bh                /* set page to 0 */
 
737
        movb    $0x2, %ah
 
738
        int     $0x10                   /* set cursor position */
 
739
 
 
740
        DATA32  call    real_to_prot
 
741
        .code32
 
742
 
 
743
        popl    %ebx
 
744
        popl    %ebp
 
745
        ret
 
746
 
 
747
 
 
748
/*
 
749
 * void grub_console_cls (void)
 
750
 * BIOS call "INT 10H Function 09h" to write character and attribute
 
751
 *      Call with       %ah = 0x09
 
752
 *                      %al = (character)
 
753
 *                      %bh = (page number)
 
754
 *                      %bl = (attribute)
 
755
 *                      %cx = (number of times)
 
756
 */
 
757
 
 
758
FUNCTION(grub_console_cls)
 
759
        pushl   %ebp
 
760
        pushl   %ebx                    /* save EBX */
 
761
 
 
762
        call    prot_to_real
 
763
        .code16
 
764
 
 
765
        /* move the cursor to the beginning */
 
766
        movb    $0x02, %ah
 
767
        xorb    %bh, %bh
 
768
        xorw    %dx, %dx
 
769
        int     $0x10
 
770
 
 
771
        /* write spaces to the entire screen */
 
772
        movw    $0x0920, %ax
 
773
        movw    $0x07, %bx
 
774
        movw    $(80 * 25), %cx
 
775
        int     $0x10
 
776
 
 
777
        /* move back the cursor */
 
778
        movb    $0x02, %ah
 
779
        int     $0x10
 
780
 
 
781
        DATA32  call    real_to_prot
 
782
        .code32
 
783
 
 
784
        popl    %ebx
 
785
        popl    %ebp
 
786
        ret
 
787
 
 
788
 
 
789
/*
 
790
 * void grub_console_setcursor (int on)
 
791
 * BIOS call "INT 10H Function 01h" to set cursor type
 
792
 *      Call with       %ah = 0x01
 
793
 *                      %ch = cursor starting scanline
 
794
 *                      %cl = cursor ending scanline
 
795
 */
 
796
 
 
797
console_cursor_state:
 
798
        .byte   1
 
799
console_cursor_shape:
 
800
        .word   0
 
801
 
 
802
FUNCTION(grub_console_setcursor)
 
803
        pushl   %ebp
 
804
        pushl   %ebx
 
805
 
 
806
        /* push ON */
 
807
        pushl   %edx
 
808
 
 
809
        /* check if the standard cursor shape has already been saved */
 
810
        movw    console_cursor_shape, %ax
 
811
        testw   %ax, %ax
 
812
        jne     1f
 
813
 
 
814
        call    prot_to_real
 
815
        .code16
 
816
 
 
817
        movb    $0x03, %ah
 
818
        xorb    %bh, %bh
 
819
        int     $0x10
 
820
 
 
821
        DATA32  call    real_to_prot
 
822
        .code32
 
823
 
 
824
        cmp     %cl, %ch
 
825
        jb      3f
 
826
        movw    $0x0d0e, %cx
 
827
3:      
 
828
        movw    %cx, console_cursor_shape
 
829
1:
 
830
        /* set %cx to the designated cursor shape */
 
831
        movw    $0x2000, %cx
 
832
        popl    %eax
 
833
        testl   %eax, %eax
 
834
        jz      2f
 
835
        movw    console_cursor_shape, %cx
 
836
2:
 
837
        call    prot_to_real
 
838
        .code16
 
839
 
 
840
        movb    $0x1, %ah
 
841
        int     $0x10
 
842
 
 
843
        DATA32  call    real_to_prot
 
844
        .code32
 
845
 
 
846
        popl    %ebx
 
847
        popl    %ebp
 
848
        ret
 
849
 
 
850
/*
 
851
 * grub_get_rtc()
 
852
 *      return the real time in ticks, of which there are about
 
853
 *      18-20 per second
 
854
 */
 
855
FUNCTION(grub_get_rtc)
 
856
        pushl   %ebp
 
857
 
 
858
        call    prot_to_real    /* enter real mode */
 
859
        .code16
 
860
 
 
861
        /* %ax is already zero */
 
862
        int     $0x1a
 
863
 
 
864
        DATA32  call    real_to_prot
 
865
        .code32
 
866
 
 
867
        movl    %ecx, %eax
 
868
        shll    $16, %eax
 
869
        movw    %dx, %ax
 
870
 
 
871
        popl    %ebp
 
872
        ret
 
873
 
 
874
/*
 
875
 * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
 
876
 */
 
877
FUNCTION(grub_pxe_call)
 
878
        pushl   %ebp
 
879
        movl    %esp, %ebp
 
880
        pushl   %esi
 
881
        pushl   %edi
 
882
        pushl   %ebx
 
883
 
 
884
        movl    %ecx, %ebx
 
885
        movl    %eax, %ecx
 
886
        movl    %edx, %eax
 
887
        andl    $0xF, %eax
 
888
        shrl    $4, %edx
 
889
        shll    $16, %edx
 
890
        addl    %eax, %edx
 
891
 
 
892
        call    prot_to_real
 
893
        .code16
 
894
 
 
895
        pushl   %ebx
 
896
        pushl   %edx
 
897
        pushw   %cx
 
898
        movw    %sp, %bx
 
899
        lcall   *%ss:6(%bx)
 
900
        cld
 
901
        addw    $10, %sp
 
902
        movw    %ax, %cx
 
903
 
 
904
        DATA32  call    real_to_prot
 
905
        .code32
 
906
 
 
907
        movzwl  %cx, %eax
 
908
 
 
909
        popl    %ebx
 
910
        popl    %edi
 
911
        popl    %esi
 
912
        popl    %ebp
 
913
        ret
 
914
 
 
915
FUNCTION(grub_bios_interrupt)
 
916
        pushl    %ebp
 
917
        pushl    %ecx
 
918
        pushl    %eax
 
919
        pushl    %ebx
 
920
        pushl    %esi
 
921
        pushl    %edi   
 
922
        pushl    %edx
 
923
        
 
924
        movb     %al, intno
 
925
        movl     (%edx), %eax
 
926
        movl     %eax, LOCAL(bios_register_eax)
 
927
        movw     4(%edx), %ax
 
928
        movw     %ax, LOCAL(bios_register_es)
 
929
        movw     6(%edx), %ax
 
930
        movw     %ax, LOCAL(bios_register_ds)
 
931
        movw     8(%edx), %ax
 
932
        movw     %ax, LOCAL(bios_register_flags)
 
933
 
 
934
        movl    12(%edx), %ebx
 
935
        movl    16(%edx), %ecx
 
936
        movl    20(%edx), %edi
 
937
        movl    24(%edx), %esi
 
938
        movl    28(%edx), %edx
 
939
 
 
940
        call    prot_to_real
 
941
        .code16
 
942
 
 
943
        mov     %ds, %ax
 
944
        push    %ax
 
945
 
 
946
        /* movw imm16, %ax*/
 
947
        .byte   0xb8
 
948
LOCAL(bios_register_es):
 
949
        .short  0
 
950
        movw    %ax, %es
 
951
        /* movw imm16, %ax*/
 
952
        .byte   0xb8
 
953
LOCAL(bios_register_ds):
 
954
        .short  0
 
955
        movw    %ax, %ds
 
956
 
 
957
        /* movw imm16, %ax*/
 
958
        .byte   0xb8
 
959
LOCAL(bios_register_flags):
 
960
        .short  0
 
961
        push    %ax
 
962
        popf
 
963
 
 
964
        /* movl imm32, %eax*/
 
965
        .byte   0x66, 0xb8
 
966
LOCAL(bios_register_eax):
 
967
        .long   0
 
968
        
 
969
        /* int imm8.  */
 
970
        .byte   0xcd
 
971
intno:  
 
972
        .byte   0
 
973
 
 
974
        movl    %eax, %cs:LOCAL(bios_register_eax)
 
975
        movw    %ds, %ax
 
976
        movw    %ax, %cs:LOCAL(bios_register_ds)
 
977
        pop     %ax
 
978
        mov     %ax, %ds
 
979
        pushf
 
980
        pop     %ax
 
981
        movw    %ax, LOCAL(bios_register_flags)
 
982
        mov     %es, %ax
 
983
        movw    %ax, LOCAL(bios_register_es)
 
984
 
 
985
        DATA32  call    real_to_prot
 
986
        .code32
 
987
 
 
988
        popl    %eax
 
989
 
 
990
        movl    %ebx, 12(%eax)
 
991
        movl    %ecx, 16(%eax)
 
992
        movl    %edi, 20(%eax)
 
993
        movl    %esi, 24(%eax)
 
994
        movl    %edx, 28(%eax)
 
995
 
 
996
        movl     %eax, %edx
 
997
 
 
998
        movl     LOCAL(bios_register_eax), %eax
 
999
        movl     %eax, (%edx)
 
1000
        movw     LOCAL(bios_register_es), %ax
 
1001
        movw     %ax, 4(%edx)
 
1002
        movw     LOCAL(bios_register_ds), %ax
 
1003
        movw     %ax, 6(%edx)
 
1004
        movw     LOCAL(bios_register_flags), %ax
 
1005
        movw     %ax, 8(%edx)
 
1006
 
 
1007
        popl    %edi
 
1008
        popl    %esi
 
1009
        popl    %ebx
 
1010
        popl    %eax
 
1011
        popl    %ecx
 
1012
        popl    %ebp
 
1013
        ret