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

« back to all changes in this revision

Viewing changes to boot/i386/pc/boot.S

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

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