Chinaunix首页 | 论坛 | 博客

net

  • 博客访问: 136733
  • 博文数量: 4
  • 博客积分: 1995
  • 博客等级: 上尉
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-06 15:30
文章分类

全部博文(4)

文章存档

2008年(4)

我的朋友
最近访客

分类: LINUX

2008-04-28 17:22:32

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


stage1.S被放在0面0道的第1扇区,start.S被放在0面0道的第2扇区,而与boot分区相关的文件系统的xxfs_stage1_5被放在0面0道第3扇区开始的扇区里,其占据的扇区数目与该stage1_5文件的大小有关。


代码:

+------------+ | stage1 | <-- 0面0道第1扇区
+------------+ | start | <-- 0面0道第2扇区
+------------+ | stage1_5 | <-- 0面0道第3扇区
| ... | +------------+



阅读(2159) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~