source: grub-pc/trunk/fuentes/debian/grub-extras/ntldr-img/grldrstart.S @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 128.5 KB
Line 
1/*
2 *  grldrstart.S -- Startup code for GRLDR
3 *  Copyright (C) 2004-2007  Tinybit(tinybit@tom.com)
4 *  Copyright (C) 2007  Bean(bean@windrv.net)
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/*
22 * This program is used to generate the GRLDR file.
23 *
24 * Use the following shell command to generate the GRLDR file:
25 *
26 *      cat grldrstart pre_stage2 > grldr
27 *
28 */
29
30#ifndef STAGE1_5
31//#include <stage2_size.h>
32#else
33#error cannot compile with STAGE1_5
34#endif
35
36#ifdef GRLDR_MBR
37        .file   "mbrstart.S"
38#elif defined(GRLDR_INSTALL)
39        .file   "bootlacestart.S"
40#else
41        .file   "grldrstart.S"
42#endif
43
44#ifdef GRLDR_INSTALL
45        //.data
46#else
47        .text
48
49        .globl  start, _start
50
51start:
52_start:
53#endif
54
55_start1:
56
57        /* Tell GAS to generate 16-bit real mode instructions */
58
59        .code16
60
61        . = _start1 + 0x00
62
63        /* 1 byte at offset 0x00 will be overwritten for the EBIOS indicator
64         * later. This is safe because the jmp instruction only get executed
65         * once. The write happens after the jmp instruction have got
66         * executed.
67         *
68         * The value written would be 0x42 for EBIOS present(LBA) and 0x02
69         * for non-present(CHS).
70         *
71         */
72
73        /* No cli, we use stack! BIOS or caller usually sets SS:SP=0000:0400 */
74
75        jmp     1f      /* FAT32/NTFS routine comes to offset 0 */
76
77        . = _start1 + 0x02
78
79        .byte   0x80    /* bit0=1: disable GRLDR search on floppy */
80                        /* bit1=1: disable the boot of the previous MBR with
81                         *         invalid partition table */
82                        /* bit2=1: disable the feature of unconditional
83                         *         entrance to the command-line */
84                        /* bit7=1: disable the boot of the previous MBR prior
85                                   to the search for GRLDR */
86
87        /* GRLDR.MBR uses offset 0x03 to indicate a timer counter. */
88
89        /* 0xff indicates waiting forever,
90         * other value specifies the time in seconds to wait */
91
92        . = _start1 + 0x03
93
94        .byte   5
95
96        /* a key press to wait. if AX returned from int16 equals this word,
97         * the desired action will occur. */
98
99        . = _start1 + 0x04
100
101        .word   0x3920          /* the space bar */
102
103        . = _start1 + 0x06
104
105        .byte   0xff    /* preferred boot drive number, 0xff for no-drive(i.e., drive not defined) */
106        .byte   0xff    /* preferred partition number, 0xff for whole drive(a floppy that has no partition table) */
107
108        . = _start1 + 8
109
110#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
111
112        /* filled in by mkisofs using the -boot-info-table option */
113
114#;bi_pvd:       .long 0xDEADBEEF        /* LBA of primary volume descript */
115#;bi_file:      .long 0xDEADBEEF        /* LBA of boot file */
116#;bi_length:    .long 0xDEADBEEF        /* Length of boot file */
117#;bi_csum:      .long 0xDEADBEEF        /* Checksum of boot file */
118#;bi_reserved:  .space (10*4)           /* Reserved */
119
120        . = _start1 + 0x40
121
122#else
123
124        /* filled in with BPB in case the drive(typically USB) is treated as floppy by buggy BIOSes */
125
126        . = _start1 + 0x60
127
128#endif  /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
129
1301:
131        call    1f
132
133#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
134
135        . = _start1 + 0x43
136
137#else
138
139        . = _start1 + 0x63
140
141#endif  /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
142
1431:
144        popw    %bx                     /* Instruction Pointer of 1b */
145
146#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
147
148        subw    $(1b - _start1), %bx    /* CS:BX=_start1 */
149
150#else
151
152        subw    $(1b - _start1), %bx    /* CS:BX=_start1 */
153
154#endif  /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
155
156        shrw    $4, %bx
157        movw    %cs, %ax
158        addw    %ax, %bx                /* BX:0000=_start1 */
159
160#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
161
162        /* we are booted from BOOT.INI, or whole GRLDR image already loaded */
163
164        pushw   %bx                     /* BX:0000=_start1 */
165        addw    $((grldr_signature - _start1 + 4 + STAGE2_SIZE - 4) >> 4), %bx
166        movw    %bx, %ds
167
168        cmpl    $0xCE1A02B0, ((STAGE2_SIZE - 4) & 0x0F)
169        popw    %ds                     /* DS:0000=_start1 */
170        je      grldr_real_start        /* whole image loaded. boot it! */
171
172        /* bad! we might be loaded by a buggy BIOS with a no-emulation-mode
173         * bootable CD. The buggy BIOS might load only 1 CD-ROM sector(2048
174         * bytes) of our grldr image. So we need this check.
175         */
176
177        /* Our cdrom_check code begins at 0x1BE and overlaps the partition
178         * table. Just in case someone replace it with a partition table and
179         * use this sector as an MBR, we do this additional test for safety.
180         */
181
182        /* We should avoid using opcode 0x00 and 0x80 at cdrom_check. */
183
184        /* Note that if cdrom_check code is present, then we are booting from
185         * no-emulation mode cdrom.
186         */
187
188        testb   $0x7F, cdrom_check - _start1    /* is it 0x00 or 0x80? */
189        jz      1f                      /* yes, cdrom_check not found */
190        call    cdrom_check             /* no, cdrom_check is present */
1911:
192        /* DS:0000=_start1 */
193
194        /* Let CS:0000=_start1 */
195        pushw   %ds
196
197        #;pushw $(1f - _start1)
198        .byte   0x6A, (1f - _start1)
199
200        lret
201        . = . - (. - _start1) / 0x80
2021:
203#else
204        /* BX:0000=_start1 */
205
206        movw    %bx, %ds
207
208        /* Let CS:0000=_start1 */
209        pushw   %bx
210
211        #;pushw $(1f - _start1)
212        .byte   0x6A, (1f - _start1)
213
214        lret
215        . = . - (. - _start1) / 0x80
2161:
217        testb   $0x04, 0x02
218        jz      1f
219
220        /* set the DUCE indicator */
221        xorw    %ax, %ax
222        movw    %ax, %es
223        movw    $0x5FC, %di
224        movl    $0x45435544, %eax
225        stosl
2261:
227#endif
228
229        /* CS:0000=DS:0000=_start1 */
230
231        /* we are loaded by BIOS or another boot loader */
232
233#define GRLDR_CS 0x2000         /* grldr code segment */
234                                /* hope this segment never be used by all */
235                                /*      subsequent partition boot records */
236#if 0
237        /* for single sector boot record */
238#define MONITOR 0x7e10
239#else
240        /* for 4-sector NTFS boot record */
241#define MONITOR 0x8410
242#endif
243
244//      cli
245        pushw   $GRLDR_CS
246        popw    %ss
247        movw    $0x9000, %sp    /* SS:SP=0x9d000, keep away from EBDA data */
248//      sti
249
250        /* Extended BIOS Data Area should not take up space below 0x9d000 */
251
252        /*
253         * 0x07c00-0x07dff      This sector. Another boot loader load us here
254         * 0x0d000-0x14dff      partition/floppy boot track(bootsector,etc)
255         * 0x94000-0x9bdff      master boot track(MBR,etc,usually 63 sectors)
256         * 0x9be00-0x9c3ff      3 sectors for temp extended partition entries
257         * 0x9c400-0x9cfff      6 sectors for stack
258         */
259
260#define FS_BOOT 0xd00           /* segment of partition boot track */
261
262        xorw    %cx, %cx
263        pushw   %cx             /* CX=0 */
264        movw    $0x0080, %dx
265        pushw   %dx
266        movb    $8, %ah         /* read drive parameters changes DX,ES,DI */
267        stc
268        int     $0x13
269        popw    %dx
270        popw    %ax             /* AX=0 */
271
272        pushw   %ss             /* SS=0x9400 */
273        popw    %es             /* ES=0x9400 */
274
275        jc      Error1
276
277        andb    $63, %cl        /* AL=sectors per track, CF cleared */
278
279        stc
280        jz      Error1
281
282        xchgw   %ax, %cx        /* this moves CL to AL, and CX=0 */
283        movb    $0x02, %ah
284        movw    %ax, %bp        /* save AX to BP: read 1 track */
285        xorw    %bx, %bx        /* ES already has a known value of 0x9400 */
286        incw    %cx
287        pushw   %dx
288        stc
289        int     $0x13           /* read master boot track to ES:0000 */
290        popw    %dx
291        jc      Error1
292        negb    %ah             /* set CF=1 if non-zero */
293Error1:
294        pushw   %cs             /* DS=0 */
295        popw    %ds             /* DS=CS */
296        pushfw                  /* CF=1 on error */
297
298        /* CS=DS=old segment. ES=SS=new segment. */
299
300        /* Move the code and error messages from DS:0000 to 9400:0000, do not
301         * touch the partition table
302         */
303        xorw    %si, %si
304        xorw    %di, %di
305        movw    $223, %cx       /* 223 words = 446 bytes = 0x1be bytes */
306        cld
307        repz movsw              /* SI=DI=0x1be, CX=0 */
308
309        movw    $(grldr_signature - _start1), %bx
310
311        /* if the boot loader has loaded more than one sector, we use them */
312        movl    $0xAA555247, %eax       /* "GR" 0x55 0xAA */
313//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
314        cmpl    %eax, (%bx)             /* DS=old segment! */
315        jne     1f
316
317        /* The MOVE_HELPER code is in the old segment! */
318
319        call    move_helper     /* SI=0x1be, CX=0 */
3201:
321//#endif
322
323        /* Jump to new segment! */
324#if 1
325        ljmp    $GRLDR_CS, $(1f - _start1)
326#else
327        pushw   %ss             /* 0x9400 */
328
329        //pushw $(1f - _start1)
330        .byte   0x6A, (1f - _start1)
331
332        lret
333        . = . - (. - _start1) / 0x80
334#endif
3351:
336
337        /* We are at the new segment. CS=ES=SS=new segment. */
338
339        /* But DS is still old segment. */
340
341        pushw   %ss
342        popw    %ds
343
344        /* CS=DS=ES=SS=new segment. */
345
346        //movw  $0x01be, %si
347
348        /* check the existence of helper */
349        cmpl    %eax, (%bx)
350
351#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
352
353        jne     Error_or_prev_MBR       /* Missing helper */
354
355#else
356
357        je      1f
358
359        /* try to load helper from floppy */
360
361        pushal
362
363        movw    0x18, %ax       /* BPB sectors per track at offset 0x18 */
364
365        cmpw    $0x3F, %ax
366        ja      3f
367
368        cmpb    $((pre_stage2_start - _start1) >> 9), %al
369        jb      3f
370
371        decw    %ax             /* skip the first sector already loaded */
372
373        movw    $3, %di         /* retry 3 times on read failure */
3742:
375        movb    $2, %ah         /* BIOS disk read */
376        cwd                     /* DX=0 for floppy head 0 */
377        movw    $0x200, %bx     /* ES:BX immediately follow this sector */
378        movw    $2, %cx         /* skip the first sector already loaded */
379
380        pushaw
381        int     $0x13
382        popaw
383
384        jnc     3f
385
386        pushaw
387        xorw    %ax, %ax
388        int     $0x13
389        popaw
390
391        decw    %di
392        jnz     2b
3933:
394        popal
395        cmpl    %eax, (%bx)             /* helper loaded? */
396
397        jne     Error_or_prev_MBR       /* Missing helper */
398
3991:
400#endif
401
402        popfw                   /* CF=1 on error */
403        jc      try_floppy      /* harddisk (hd0) failed, try floppy (fd0) */
4041:
405        pushw   %cs
406        popw    %ds
407        lodsw
408        movb    %ah, %dh        /* head number */
409        lodsw
410        movw    %ax, %cx        /* sector and cylinder number */
411        andb    $63, %al
412        //stc
413        jz      helper_call_c
414
415        /* use BP to calculate the sectors to read within 1 track */
416        subw    %bp, %ax
417        decw    %ax             /* decb %al */
418        negb    %al             /* AL=sectors upto the end of the track */
4197:
420        movw    $3, %di         /* retry 3 times on read failure */
4212:
422        movb    $2, %ah
423        pushw   $FS_BOOT
424        popw    %es             /* ES=FS_BOOT */
425        xorw    %bx, %bx
426
427        pushaw
428        int     $0x13           /* read partition boot track to FS_BOOT:0000 */
429        popaw
430
431        jnc     helper_call
432
433        pushaw
434        xorw    %ax, %ax
435        int     $0x13
436        popaw
437
438        decw    %di
439        jnz     2b
440
441helper_call_c:
442
443        stc
444
445helper_call:
446        /* find GRLDR in this partition
447         * before the call:
448         *      CF=1            : indicates an invalid or corrupt entry
449         *      CF=0            : indicates a valid entry
450         *
451         * on return:
452         *      CF=1            : means "below", try next entry
453         *      CF=0,ZF=1       : means "equal", helper did nothing, so we need
454         *                        a further try to boot via NT bootsector
455         *      CF=0,ZF=0       : means "above", helper succeeded, boot it now
456         */
457        call    helper_start    /* change to jmp 6f if helper not present */
458        ja      filesystem_boot /* helper succeeded, directly boot it */
4596:
460
461add_sub_si:
462
463        /* extended partition check routine will adjust this to
464         *
465         *      0x83, 0xEE, 0x04 for "subw $4, %si"
466         *
467         *                       or
468         *
469         *      0x83, 0xC6, 0xFC for "addw $-4, %si"
470         *
471         * so that SI keeps the value 0x1fe.
472         */
473        addw    $12, %si        /* 0x83, 0xC6, 0x0C */
474
475        . = add_sub_si + 3
476
477        /* extended partition check routine will adjust the word 0x1fe at
478         * (add_sub_si + 5). The value 0x1ff or greater indicates there are
479         * entries need to be treated. The value 0x1fe indicates no entries
480         * left, and the floppy should be checked.
481         */
482
483        cmpw    $0x01fe, %si    /* 0x81, 0xFE, 0xfe, 0x01 */
484                                /* All entries checked done? */
485        jb      1b              /* No, check the next entry */
486        ja      5f              /* floppy already checked. Fail and hang */
487
488try_floppy:
489
490        movw    $0x31b2, %si    /* a value big enough */
491        movb    $0x08, %ah      /* read drive parameters changes DX,ES,DI */
492        cwd                     /* DL=0 for floppy */
493        pushw   %dx             /* DX=0 */
494        int     $0x13
495        popw    %ax             /* AX=0 */
496        jc      5f              /* floppy failure, issue "Error" and hang */
497        cwd                     /* DX=0 */
498        xchgw   %ax, %cx        /* this moves CL to AL, and CX=0 */
499        andb    $63, %al        /* AL=sectors per track */
500        jz      5f              /* invalid value. floppy failure. hangs */
501        //movw  $1, %cx
502        incw    %cx
503        jmp     7b
504
5055:
506Error_or_prev_MBR:
507
508        /* GRLDR not found, print "Error" or launch previous MBR */
509        movw    $(message_string - _start1), %si
510Error2:
511        call    print_message   /* CS:SI points to message string */
5123:      jmp     3b
513
514#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
515filesystem_boot:
516        /* The partition boot record successfully modified, just boot it */
517
518        /*
519         * The boot might fail, but we want to take back the control.
520         * So we save the registers now.
521         */
522        pushw   %ds
523        pushw   %es
524        pushal
525
526        /* DS=CS=GRLDR_CS, ES=FS_BOOT */
527
528        /* save GRLDR_CS */
529
530        movw    %es, %bx        # save old ES to BX
531
532        cli
533        lgdt    gdt - _start1
534        movl    %cr0, %eax
535        orb     $1, %al
536        movl    %eax, %cr0
537
538        movw    $8, %si
539        movw    %si, %es
540
541        xorl    %esi, %esi
542        xorl    %edi, %edi
543        movl    $(0x9000 / 4), %ecx
544
545        cld
546        repz movsl
547
548        movw    $16, %si
549        movw    %si, %es
550
551        andb    $0xfe, %al
552        movl    %eax, %cr0
553
554        movw    %bx, %es        # restore ES from BX
555
556        /* move FS_BOOT:0000 to 0:7c00 */
557#if 0
558        /* for single sector boot record */
559        movw    $0x0200, %cx    /* move 2 sectors, the old FS_BOOT:0000 will
560                                 * keep untouched.  */
561#else
562        /* for 4-sector NTFS boot record */
563        movw    $0x0400, %cx    /* move 4 sectors, the old FS_BOOT:0000 will
564                                 * keep untouched.  */
565#endif
566        xorw    %si, %si
567        pushw   %si     /* SI=0, for the segment of 0000:7c00 */
568        movw    $0x7c00, %di
569        pushw   %di     /* DI=0x7c00, for the offset of 0000:7c00 */
570        pushw   %es     /* ES=FS_BOOT */
571        popw    %ds     /* DS=FS_BOOT */
572        pushw   %si     /* SI=0 */
573        popw    %es     /* ES=0 */
574        cld
575        repz movsw
576
577        movw    $MONITOR, %di
578        movw    $(restore_GRLDR_CS - _start1), %si
579        movw    $((gdt_end - restore_GRLDR_CS) / 4), %cx
580        cld
581        repz cs movsl           /* CS segment override prefix(=0x2E) */
582
583        pushw   %es     /* ES=0 */
584        popw    %ds     /* DS=0 */
585        sti
586        lret    //ljmp  $0, $0x7c00
587#endif
588
589try_next_partition:
590
591        cli
592        movw    $GRLDR_CS, %ax
593        movw    %ax, %ss
594        movw    $(0x9000-36), %sp
595        sti
596
597        /* restore the registers and continue */
598        popal
599        popw    %es
600        popw    %ds
601        jmp     add_sub_si
602
603        /* prints string CS:SI (modifies AX BX SI) */
6043:
605        //xorw  %bx, %bx        /* video page 0 */
606        movb    $0x0e, %ah      /* print char in AL */
607        int     $0x10           /* via TTY mode */
608
609print_message:
610
611        lodsb   %cs:(%si), %al  /* get token */
612        cmpb    $0, %al         /* end of string? */
613        jne     3b
614        ret
615
616message_string:
617
618#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
619        .ascii  "\r\nMissing helper.\0"
620#else
621        .ascii  "\r\nMissing MBR-helper.\0"
622#endif
623
624#;buggy_bios_string:
625#;
626#;      .ascii  "\r\nBuggy BIOS!\0"
627
628        /* Make sure the above code does not occupy the partition table */
629
630#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
631        /* offset value here must be less than or equal to 0x1be */
632        . = . - ((. - _start1) / 0x1bf)
633#else
634        /* offset value here must be less than or equal to 0x1b8 */
635        . = . - ((. - _start1) / 0x1b9)
636#endif
637
638        /* The following code may occupy the same area as the partition table */
639
640#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
641
642        /* we are not booted from MBR. So we can reuse the area of partition
643         * table for our code.
644         */
645
646        . = _start1 + 0x1be
647
648cdrom_check:
649
650        /* DS points to the sector start, but CS does not. */
651
652        /* BX segment points to near the end of GRLDR image. */
653
654        popw    %ax     /* old return IP */
655
656        /* set BX as the new safe stack. */
657        movw    %bx, %ss
658        movw    $0xFFF0, %sp
659
660        pushw   %ax     /* old return IP */
661
662        /* check if DL is no-emulation-mode bootable CDROM. */
663        pushw   %ds
664
665        cmpb    $0x80, %dl
666        jb      1f      /* not a valid no-emulation-mode cdrom drive number */
667
668        cmpw    $0xAA55, 0x7FE          /* 2048 bytes loaded? */
669        jne     1f
670
671//      cmpw    $0xAA55, 0x5FE          /* 2048 bytes loaded? */
672//      jne     1f
673
674        movw    $0x0180, %si
675        movw    $0x4B01, %ax
676        pushw   $0x0040
677        //.byte 0x6A, 0x40
678        popw    %ds
679        pushw   %ds
680        popw    %es
681        movb    $0x13, (%si)
682        int     $0x13
683
684        /* ignore CF */
685#;      jc      2f      /* not in emulation mode */
686        xorl    %eax, %eax
687        xorw    %bp, %bp
688        testb   $0x0F, 1(%si)   /* boot media type is No Emulation? */
689        jnz     2f      /* no, it simulates floppy or hard disk. */
690        cmpb    %dl, 2(%si)     /* drive number */
691        jnz     2f      /* invalid drive */
692
693        /* OK! it is no-emulation-mode cdrom drive. */
694        movl    4(%si), %eax    /* LBA of GRLDR */
695        incw    %bp
696
6972:
698        jmp     cdrom_helper
6991:
700        popw    %ds
701        ret
702
703
704#endif  /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
705
706        . = _start1 + 0x1fe     /* boot signature */
707
708/* partition entries in the extended partitions will overwrite code here upto
709 * 0x3fd.
710 *
711 * the extended partition entries will occupy a temp area at 0x9be00-0x9c3ff
712 */
713
714#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
715        .word   0xaa55
716#endif
717
718        . = _start1 + 0x200
719
720/* if it is in the Master Boot Track, the second sector can be used to backup
721 * the previously working MBR, typically, the MS MBR. if the backup copy of
722 * the MBR cannot boot(because, e.g., it depends on another sector of code
723 * that does not exist for now), then please do not set the ending signature
724 * to 0xAA55, that is to say, if the signature is already 0xAA55, you should
725 * change it to another value(for example, 0x0000).
726 */
727
728#if (! defined(GRLDR_INSTALL))
729#if 0
730print_cl:
731        pushaw
732
733        movw    %cx, %ax
734        movb    $16, %cl
735        divb    %cl             # quo=AL, rem=AH
736        orw     $0x3030, %ax
737
738        cmpb    $0x39, %ah
739        jbe     1f
740        addb    $7, %ah
7411:
742        cmpb    $0x39, %al
743        jbe     1f
744        addb    $7, %al
7451:
746        movb    %ah, %cl
747
748        xorw    %bx, %bx
749
750        movb    $0x0e, %ah
751        int     $0x10
752
753        movb    $0x0e, %ah
754        movb    %cl, %al
755        int     $0x10
756
757        movw    $0x0e20, %ax
758        int     $0x10
759
760        popaw
761        ret
762#else
763#if 0
764        .word   5, 0x47, 0x52, 0x4c, 0x44, 0x52, 4, 0x24
765        .word   0x49, 0x33, 0x30, 0xe000, 0, 0x3000, 0, 0
766#else
767        .byte   0x90, 0x90
768        .byte   0x90, 0x90
769        .byte   0x90, 0x90
770        .byte   0x90, 0x90
771        .byte   0x90, 0x90
772        .byte   0x90, 0x90
773        .byte   0x90, 0x90
774        .byte   0x90, 0x90
775
776        .byte   0x90, 0x90
777        .byte   0x90, 0x90
778        .byte   0x90, 0x90
779        .byte   0x90, 0x90
780        .byte   0x90, 0x90
781        .byte   0x90, 0x90
782        .byte   0x90, 0x90
783        .byte   0x90, 0x90
784#endif
785        .byte   0x90, 0x90
786        .byte   0x90, 0x90
787        .byte   0x90, 0x90
788        .byte   0x90, 0x90
789        .byte   0x90, 0x90
790        .byte   0x90, 0x90
791        .byte   0x90, 0x90
792        .byte   0x90, 0x90
793
794        .byte   0x90, 0x90
795        .byte   0x90, 0x90
796        .byte   0x90, 0x90
797        .byte   0x90, 0x90
798        .byte   0x90, 0x90
799        .byte   0x90, 0x90
800        .byte   0x90, 0x90
801        .byte   0x90, 0x90
802
803        .byte   0x90, 0x90
804        .byte   0x90, 0x90
805        .byte   0x90, 0x90
806        .byte   0x90, 0x90
807        .byte   0x90, 0x90
808        .byte   0x90, 0x90
809        .byte   0x90, 0x90
810        .byte   0x90, 0x90
811
812        .byte   0x90, 0x90
813        .byte   0x90, 0x90
814        .byte   0x90, 0x90
815#endif
816        . = _start1 + 0x256     /* cmdcons comes here */
817
818#if 0
819        jmp     1f
820#else
821        .byte   0x90, 0x90
822#endif
823
824        . = _start1 + 0x258
825
826        .byte   0x90, 0x90
827
828        . = _start1 + 0x25a
829
830        .byte   0x90, 0x90
831        .byte   0x90, 0x90
832        .byte   0x90, 0x90
833        .byte   0x90, 0x90
834        .byte   0x90, 0x90
835        .byte   0x90, 0x90
836        .byte   0x90, 0x90
837        .byte   0x90, 0x90
838
839        . = _start1 + 0x26a
8401:
841        //movw  %cs, %ax
842        //movw  %ax, %ds
843        //jmp   single_boot_sector
844
845        /* a value < 0x80 here means we are not booted from no-emulation-mode
846         * bootable CD.
847         */
848        movb    $0x7F, %dl
849        jmp     _start1
850
851#endif  /* (! defined(GRLDR_INSTALL)) */
852
853#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
854cdrom_helper:
855
856        /* IP and old_DS is on the stack. */
857
858        /* DS=ES=40h */
859
860        /* Stack is high and safe. */
861
862        /* EAX is LBA. if EAX==0, LBA is unknown. */
863
864        /* check if the first sector is the same as the current one */
865
866        /* load the first sector onto the sector immediately follows */
8671:
868        popw    %bx             /* BX = old_DS = load_segment */
869        pushw   %bx
870        movw    %bx, %es
871        addw    $0x0080, %bx    /* buffer segment */
872        call    load_cd_sector
873
874        /* compare the two sectors */
875        movw    $0x200, %cx
876        movw    %bx, %ds
877        xorw    %si, %si
878        xorw    %di, %di
879        cld
880        repz cmpsl
881        je      load_the_rest   /* 1st sector is ok, continue */
882not_grldr:
883        testw   %bp, %bp
884        jz      2f
885        xorw    %bp, %bp
886        xorl    %eax, %eax
8872:
888        incl    %eax
889        jnz     1b              /* try next */
890
891cd_no_grldr:
892
893        popw    %ds             /* DS=load_segment */
894
895        # Here we use error message and routine in FAT32 boot sector
896        # which is also inside the 2048-byte CD sector.
897
898        movw    $(msg_BootError_32 - _start1), %si
899        jmp     boot_error_32
900
901load_cd_sector:
902        /* input:       EAX     LBA
903         *              BX      buffer segment(buffer offset=0)
904         *              DS      0x40 (or another safe one)
905         */
906
907        movw    $0x1A0, %si
908
909        /* disk address packet */
910        movl    $0x00010010, (%si)      /* load 1 sector each time. */
911        movw    $0, 4(%si)              /* buffer offset=0 */
912        movw    %bx, 6(%si)             /* buffer segment */
913        movl    %eax, 8(%si)            /* LBA lo 32 bits */
914        movl    $0, 12(%si)             /* LBA hi 32 bits */
915
916        pushal
917        movb    $0x42, %ah
918        int     $0x13
919        popal
920        ret
921
922load_the_rest:
923
924        /* load all sectors (except the first one) */
925
926        /* EAX = first sector(LBA) of GRLDR */
927
928        popw    %bx             /* BX = old_DS = load_segment */
929        pushw   %bx
930        movw    %bx, %es
931        /* 6144 = 0x1800 = 3 sectors > 4KB, this is for the additional 4KB-preset-menu at the end of grldr */
932        movw    $((grldr_signature - _start1 + 4 + STAGE2_SIZE - 1 + 6144) / 2048), %cx /* sectors to load */
9331:
934        incl    %eax            /* next sector */
935        addw    $0x0080, %bx    /* buffer segment */
936
937        call    load_cd_sector
938
939        loop    1b
940
941        /* loading is completed. BX=segment of the last sector. */
942
943        subw    $0x0181, %bx    /* decw %bx */
944        movw    %bx, %ds
945
946        /* check the ending signature */
947        cmpl    $0xCE1A02B0, ((grldr_signature - _start1 + 4 + STAGE2_SIZE - 1) % 2048) + 13
948        jne     not_grldr
949#;      je      grldr_real_start        /* yes. boot it! */
950
951#;      /* it is not our grldr image, return and use MBR-helper. */
952#;
953#;4:
954#;      //jmp   grldr_real_start
955#;      popw    %ds
956#;      ret
957
958grldr_real_start:
959
960        #; FAT_12_16 no longer be used. So comment out.
961        #;je    1f      /* jc   1f */
962        #;//ZF=0        /* CF cleared, so we are coming from FAT_12_16 */
963        #;popw  %dx             /* discard the cluster number */
964        #;popw  %dx             /* this is our boot_drive/boot_partition */
965        #;1:
966
967        #; The partition number for no-emulation-mode bootable CDROM will be
968        #; set to 0xFF later(in common.c). So comment out.
969        #;cli
970        #;movw  %cs, %ax
971        #;cmpw  $0x1000, %ax
972        #;jne   1f
973        #;
974        #;/* CS=0x1000, may be booted from ext2 or no-emulation-mode CDROM */
975        #;
976        #;cmpw  $0x1000, %di
977        #;jne   2f
978        #;cmpw  $0x7c00, %bp
979        #;jne   2f
980        #;movw  %es, %ax
981        #;cmpw  $0x1000, %ax
982        #;jbe   2f
983        #;cmpw  $0x7c00, %si
984        #;jbe   2f
985        #;movl  %edx, %eax
986        #;shrl  $16, %eax
987        #;jnz   2f
988        #;jecxz 1f              // booted from ext2 partition
989        #;2:
990        #;// booted from no-emulation-mode bootable CDROM
991        #;movb  $0xff, %dh      // partition 0xff means whole drive(for CDROM)
992        #;                      #; if needed, 0xfe can be used as an indicator
993        #;                      #; here for the bootable CDROM and changed to
994        #;                      #; 0xff later.
995        #;1:
996        #;
997        #;//if not booted from CDROM, don't touch the boot partition number(dh)
998
999        cli
1000        xorw    %ax, %ax
1001        movw    %ax, %ss
1002        movw    $0x0400, %sp    /* tmp use real-mode IDT as stack */
1003        movw    %cs, %bp        /* save CS to BP */
1004        call    1f
10051:
1006        popw    %bx             /* BX=Instruction Pointer of 1b */
1007        subw    $(1b - _start1), %bx
1008        movw    %bx, %cx
1009        shrw    $4, %bx
1010        addw    %bp, %bx
1011        pushw   %bx             /* new CS */
1012        andw    $0x000f, %cx
1013        addw    $(1f - _start1), %cx
1014        pushw   %cx             /* new IP */
1015        lret
10161:
1017        pushw   %cs
1018        popw    %ds
1019
1020        /* CS=DS=BX, CS:0000 = _start1 */
1021
1022        addw    $((pre_stage2_start - _start1) >> 4), %bx
1023
1024        /* BX:0000 = pre_stage2_start */
1025
1026        cmpw    $0x820, %bx
1027        jb      2f
1028
1029        movw    $((0x8200 - (pre_stage2_start - _start1) - 0x400) >> 4), %cx
1030
1031        /* Now CS(=DS) >= CX+0x40 */
1032
1033        movw    %cx, %es
1034        xorw    %di, %di
1035        xorw    %si, %si
1036
1037        /////////////////////////////////////////////////////////////
1038        //
1039        //                    CS
1040        //                    DS          0x820     BX
1041        //                    _start1---------------pre_stage2_start
1042        //          CX+0x40---------------0x820
1043        //   CX
1044        //   ES
1045        //
1046        /////////////////////////////////////////////////////////////
1047
1048        movw    $0x200, %cx     /* move 2 sectors */
1049        cld
1050        repz movsw
1051
1052        pushw   %es             /* ES:0000 = _start */
1053        pushw   $(1f - _start)
1054        lret                    /* CS=ES, CS:0000 = _start1 */
10551:
1056
1057        /* move BX:0000 to 0820:0000 upward since BX >= 0x820 */
1058
1059        cld
1060
1061        movw    %bx, %ds
1062        movw    $0x820, %bx
1063        movw    %bx, %es
1064
1065        xorw    %si, %si
1066        xorw    %di, %di
1067
1068        movw    $6, %bx         /* 64K pages: 0x20000 - 0x7ffff */
10691:
1070        movw    $0x8000, %cx
1071        repz movsw
1072        movw    %ds, %ax
1073        addw    $0x1000, %ax
1074        movw    %ax, %ds
1075        movw    %es, %ax
1076        addw    $0x1000, %ax
1077        movw    %ax, %es
1078        decw    %bx
1079        jnz     1b
1080
1081        jmp     3f
10822:
1083
1084        /* move BX:0000 to 0820:0000 downward since BX < 0x820 */
1085
1086        std
1087
1088        addw    $0x7000, %bx
1089        movw    %bx, %ds
1090        movw    $0x7820, %bx
1091        movw    %bx, %es
1092
1093        movw    $0xfffe, %si
1094        movw    %si, %di
1095
1096        movw    $8, %bx         /* 64K pages: 0x08200 - 0x881ff */
10971:
1098        movw    $0x8000, %cx
1099        repz movsw
1100        movw    %ds, %ax
1101        subw    $0x1000, %ax
1102        movw    %ax, %ds
1103        movw    %es, %ax
1104        subw    $0x1000, %ax
1105        movw    %ax, %es
1106        decw    %bx
1107        jnz     1b
1108
1109        cld
1110
11113:
1112
1113        /* put the config file name */
1114        xorw    %ax, %ax
1115        movw    %ax, %es
1116        movw    %ax, %ds
1117
1118        xorl    %ebp, %ebp
1119
1120        movb    %dh, 0x820A     /* this is the boot partition number */
1121
1122        #; clear saved_entryno so that force_cdrom_as_boot_device be cleared
1123        #; later in common.c
1124
1125        movl    %ebp, 0x820C    /* EBP=0, clear saved_entryno */
1126
1127        movw    $0x0010, %cx    /* set max length of grub version string */
1128        movw    $0x8212, %di    /* version string */
1129        cld
1130        /* AL is already 0. Locate the end of version string */
1131        repnz scasb     /* find the location of the default config file name */
1132
1133        jcxz    1f      /* failed, will not use the default config file name */
1134
1135        movw    $0x4e, %cx      /* max length of config file name */
1136
1137        movw    %cs, %si        /* CS:0000 = _start1 */
1138        shlw    $4, %si         /* 0000:SI = _start1 */
1139
1140        addw    $(default_config_file - _start1), %si
1141
1142        //movw  $(default_config_file + 0x8200 - pre_stage2_start), %si
1143        cld
1144        repz movsb      /* move file name to the config-file field of stage2 */
11451:
1146
1147        movw    $0x0003, %ax    /* set display mode: 80*25 color text */
1148        int     $0x10
1149
1150        xorw    %bx, %bx
1151        movw    $(launch_pre_stage2 - _start1), %si
1152        call    print_message   /* CS:SI points to message string */
1153
1154        xorw    %ax, %ax
1155        movw    %ax, %ss
1156        movw    $0x2000, %sp
1157
1158        sti
1159
1160        ljmp    $0, $0x8200
1161
1162launch_pre_stage2:
1163        .ascii  "\r\n\r\nBooting GRLDR...\r\n"
1164
1165        .byte   0               /* mark the end of ascii zero string */
1166
1167default_config_file:
1168//#ifndef PRESET_MENU_STRING
1169        .ascii  "/menu.lst"
1170//#else
1171//      .ascii  "[default menu is disabled]"
1172//#endif
1173
1174        .byte   0               /* mark the end of ascii zero string */
1175#endif  /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
1176
1177        . = _start1 + 0x400
1178
1179#define ALTERNATIVE_KERNEL
1180
1181
1182/*
1183 * The following is based on FreeDOS, modified heavily by Tinybit in Feb, 2004
1184 *
1185 * Merges LBA and CHS boot sectors to ONE FAT32 boot sector!
1186 *
1187 * Memory layout for GRLDR FAT32 single stage boot process:
1188 *
1189 *      ...
1190 *      |-------| 1FE0:7E00
1191 *      |BOOTSEC| (GRUB does not use this relocation area)
1192 *      |RELOC. | (overwritten by kernel loaded)
1193 *      |-------| 1FE0:7C00
1194 *      ...
1195 *      |-------|
1196 *      |KERNEL | (overwrites bootsec reloc.)
1197 *      |LOADED | (holds 1 sector directory buffer before kernel load)
1198 *      |-------| 2000:0000
1199 *      ...
1200 *      |-------| 0000:7E00
1201 *      |BOOTSEC| GRUB always run inside this sector,
1202 *      |ORIGIN | no relocation.
1203 *      |-------| 0000:7C00
1204 *      ...
1205 *      |-------| 0060:0200
1206 *      |  FAT  | (only 1 sector buffered)
1207 *      |-------| 0060:0000
1208 *      ...
1209 *
1210 */
1211
1212/*
1213; This is an LBA-enabled FreeDOS FAT32 boot sector (single sector!).
1214; You can use and copy source code and binaries under the terms of the
1215; GNU Public License (GPL), version 2 or newer. See www.gnu.org for more.
1216
1217; Based on earlier work by FreeDOS kernel hackers, modified heavily by
1218; Eric Auer and Jon Gentle in 7 / 2003.
1219;
1220; Features: Uses LBA and calculates all variables from BPB/EBPB data,
1221; thus making partition move / resize / image-restore easier. FreeDOS
1222; can boot from FAT32 partitions which start > 8 GB boundary with this
1223; boot sector. Disk geometry knowledge is not needed for booting.
1224;
1225; Windows uses 2-3 sectors for booting (sector stage, statistics sector,
1226; filesystem stage). Only using 1 sector for FreeDOS makes multi-booting
1227; of FreeDOS and Windows on the same filesystem easier.
1228;
1229; Requirements: LBA BIOS and 386 or better CPU. Use the older CHS-only
1230; boot sector if you want FAT32 on really old PCs (problems: you cannot
1231; boot from > 8 GB boundary, cannot move / resize / ... without applying
1232; SYS again if you use the CHS-only FAT32 boot sector).
1233;
1234; FAT12 / FAT16 hints: Use the older CHS-only boot sector unless you
1235; have to boot from > 8 GB. The LBA-and-CHS FAT12 / FAT16 boot sector
1236; needs applying SYS again after move / resize / ... a variant of that
1237; boot sector without CHS support but with better move / resize / ...
1238; support would be good for use on LBA harddisks.
1239
1240
1241; Memory layout for the FreeDOS FAT32 single stage boot process:
1242
1243;       ...
1244;       |-------| 1FE0:7E00
1245;       |BOOTSEC|
1246;       |RELOC. |
1247;       |-------| 1FE0:7C00
1248;       ...
1249;       |-------| 2000:0200
1250;       |  FAT  | (only 1 sector buffered)
1251;       |-------| 2000:0000
1252;       ...
1253;       |-------| 0000:7E00
1254;       |BOOTSEC| overwritten by the kernel, so the
1255;       |ORIGIN | bootsector relocates itself up...
1256;       |-------| 0000:7C00
1257;       ...
1258;       |-------|
1259;       |KERNEL | maximum size 134k (overwrites bootsec origin)
1260;       |LOADED | (holds 1 sector directory buffer before kernel load)
1261;       |-------| 0060:0000
1262;       ...
1263*/
1264
1265#define BOOTGRUB        /* undef this if compiled for loading FreeDOS */
1266//#undef BOOTGRUB
1267
1268#ifdef  BOOTGRUB
1269#define LOADSEG         0x2000
1270#define FATSEG          0x0060
1271#else
1272#define LOADSEG         0x0060
1273#define FATSEG          0x2000
1274#endif
1275
1276Entry_32:
1277        jmp     1f
1278
1279        . = Entry_32 + 0x02
1280
1281        /* The default mode is CHS. This is for maximum compatiblity with
1282         * small-sized disks, e.g., floppies.
1283         *
1284         * Valid values are 0x90 for CHS mode, or 0x0e for LBA mode.
1285         *
1286         * If the BIOS int13 supports LBA, this byte can be safely set to 0x0e.
1287         *
1288         * Some USB BIOSes might have bugs when using CHS mode, so the format
1289         * program should set this byte to 0x0e. It seems that (generally) all
1290         * USB BIOSes have LBA support.
1291         *
1292         * If the format program does not know whether the BIOS has LBA
1293         * support, it may operate this way:
1294         *
1295         * if (partition_start + total_sectors_in_partition) exceeds the CHS
1296         * addressing ability(especially when it is greater than 1024*256*63),
1297         * the caller should set this byte to 0x0e, otherwise, set to 0x90.
1298         */
1299
1300        .byte   0x90    /* for CHS. Another possible value is 0x0e for LBA */
1301
1302
1303        . = Entry_32 + 0x03
1304
1305#ifdef  BOOTGRUB
1306        .ascii  "GRLDR   "      /* OEM name string (of OS which formatted the disk). */
1307#endif
1308
1309        . = Entry_32 + 0x0b
1310
1311        .word   0x200           /* bytes per sector. Must be 512 */
1312
1313        . = Entry_32 + 0x0d
1314
1315        /* Sectors per cluster. Valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
1316         * But a cluster size larger than 32K should not occur.
1317         */
1318
1319        .byte   1               /* sectors per cluster */
1320
1321        . = Entry_32 + 0x0e
1322
1323        /* Reserved sectors(number of sectors before the first FAT,
1324         * including the boot sector), usually 1.
1325         */
1326
1327        .word   1               /* reserved sectors */
1328
1329        . = Entry_32 + 0x10
1330
1331        /* Number of FATs(nearly always 2). */
1332
1333        .byte   2               /* number of FATs */
1334
1335        . = Entry_32 + 0x11
1336
1337        /* (Maximum number of root directory entries)Must be 0. */
1338
1339        .word   0               /* Max dir entries for FAT12/FAT16 */
1340
1341        . = Entry_32 + 0x13
1342
1343        /* (Total number of sectors for small disks only)Must be 0. */
1344
1345        .word   0               /* total sectors for FAT12/FAT16 */
1346
1347        . = Entry_32 + 0x15
1348
1349        /* Media descriptor byte, pretty meaningless now. */
1350
1351        .byte   0xf8            /* media descriptor */
1352
1353        . = Entry_32 + 0x16
1354
1355        /* (Sectors per FAT)Must be 0. */
1356
1357        .word   0               /* sectors per FAT for FAT12/FAT16 */
1358
1359        . = Entry_32 + 0x18
1360
1361        .word   18              /* sectors per track */
1362
1363        . = Entry_32 + 0x1a
1364
1365        .word   2               /* number of heads */
1366
1367        . = Entry_32 + 0x1c
1368
1369        /* Number of hidden sectors (those preceding the boot sector).
1370         * Also referred to as the starting sector of the partition.
1371         * For floppies, it should be 0.
1372         */
1373
1374        .long   0               /* hidden sectors */
1375
1376        . = Entry_32 + 0x20
1377
1378        /* Total number of sectors in the filesystem. */
1379
1380        .long   0               /* total sectors for FAT32 */
1381
1382        . = Entry_32 + 0x24
1383
1384        /* FAT32 sectors per FAT. */
1385
1386        .long   0
1387
1388        . = Entry_32 + 0x28
1389
1390        /* If bit 7 is clear then all FATs are updated, otherwise bits 0-3
1391         * give the current active FAT, all other bits are reserved.
1392         * This word is not used by grldr boot code.
1393         */
1394
1395        .word   0
1396
1397        . = Entry_32 + 0x2a
1398
1399        /* High byte is major revision number, low byte is minor revision
1400         * number, currently both are 0.
1401         * This word is not used by grldr boot code.
1402         */
1403
1404        .word   0
1405
1406        . = Entry_32 + 0x2c
1407
1408        /* Root directory starting cluster. */
1409
1410        .long   0
1411
1412        . = Entry_32 + 0x30
1413
1414        /* File system information sector number.
1415         * This word is not used by grldr boot code.
1416         */
1417
1418        .word   0
1419
1420        . = Entry_32 + 0x32
1421
1422        /* If non-zero this gives the sector which holds a copy of the
1423         * boot record, usually 6.
1424         * This word is not used by grldr boot code.
1425         */
1426
1427        .word   6
1428
1429        . = Entry_32 + 0x34
1430
1431        /* Reserved, 12 bytes, set to 0. */
1432
1433        .long   0
1434        .long   0
1435        .long   0
1436
1437        . = Entry_32 + 0x40
1438
1439        /* drive number of the boot device.
1440         * This byte is ignored for read. The program will write DL onto
1441         * this byte. The caller should set drive number in DL.
1442         * We assume all BIOSes pass correct drive number in DL.
1443         * That is to say, buggy BIOSes are not supported!!
1444         */
1445
1446        .byte   0
1447
1448        . = Entry_32 + 0x41
1449
1450        /* partition number of this filesystem in the boot drive.
1451         * This byte is ignored for read. The boot code will write partition
1452         * number onto this byte. See Entry + 0x5d below.
1453         */
1454
1455        .byte   0
1456
1457        . = Entry_32 + 0x42
1458
1459        /* Signature (must be 28h or 29h to be recognised by NT). */
1460
1461        .byte   0x29            /* extended boot signature for FAT12/FAT16 */
1462
1463        . = Entry_32 + 0x43
1464
1465        .long   0x0AC4AF63      /* volume serial number */
1466
1467        . = Entry_32 + 0x47
1468
1469        .ascii  "NO NAME    "   /* volume label, 11 bytes. */
1470
1471        . = Entry_32 + 0x52
1472
1473        .ascii  "FAT32   "      /* filesystem ID, 8 bytes. */
1474
1475/*
1476;       bp is initialized to 7c00h
1477; %define bsOemName     bp+0x03 ; OEM label (8)
1478%define bsBytesPerSec   bp+0x0b ; bytes/sector (dw)
1479%define bsSecPerClust   bp+0x0d ; sectors/allocation unit (db)
1480%define bsResSectors    bp+0x0e ; # reserved sectors (dw)
1481%define bsFATs          bp+0x10 ; # of fats (db)
1482; %define bsRootDirEnts bp+0x11 ; # of root dir entries (dw, 0 for FAT32)
1483                        ; (FAT32 has root dir in a cluster chain)
1484; %define bsSectors     bp+0x13 ; # sectors total in image (dw, 0 for FAT32)
1485                        ; (if 0 use nSectorHuge even if FAT16)
1486; %define bsMedia       bp+0x15 ; media descriptor: fd=2side9sec, etc... (db)
1487; %define sectPerFat    bp+0x16 ; # sectors in a fat (dw, 0 for FAT32)
1488                        ; (FAT32 always uses xsectPerFat)
1489%define sectPerTrack    bp+0x18 ; # sectors/track
1490; %define nHeads        bp+0x1a ; # heads (dw)
1491%define nHidden         bp+0x1c ; # hidden sectors (dd)
1492; %define nSectorHuge   bp+0x20 ; # sectors if > 65536 (dd)
1493%define xsectPerFat     bp+0x24 ; Sectors/Fat (dd)
1494                        ; +0x28 dw flags (for fat mirroring)
1495                        ; +0x2a dw filesystem version (usually 0)
1496%define xrootClst       bp+0x2c ; Starting cluster of root directory (dd)
1497                        ; +0x30 dw -1 or sector number of fs.-info sector
1498                        ; +0x32 dw -1 or sector number of boot sector backup
1499                        ; (+0x34 .. +0x3f reserved)
1500%define drive           bp+0x40 ; Drive number
1501                        bp+0x41 ; partition number for GRLDR
1502
1503%define fat_sector      bp+0x44         ; last accessed FAT sector (dd)
1504                                        ; (overwriting unused bytes)
1505%define fat_start       bp+0x48         ; first FAT sector (dd)
1506                                        ; (overwriting unused bytes)
1507%define data_start      bp+0x4c         ; first data sector (dd)
1508                                        ; (overwriting unused bytes)
1509
1510*/
1511                /* not used: [0x42] = byte 0x29 (ext boot param flag)
1512                 * [0x43] = dword serial
1513                 * [0x47] = label (padded with 00, 11 bytes)
1514                 * [0x52] = "FAT32",32,32,32 (not used by Windows)
1515                 * ([0x5a] is where FreeDOS parts start)
1516                 */
1517
1518        . = Entry_32 + 0x5a
15191:
1520        cli
1521        cld
1522
1523#ifdef  BOOTGRUB
1524
1525        . = Entry_32 + 0x5c
1526
1527        /* the byte at offset 0x5d stores the real partition number for read.
1528         * the format program or the caller should set it to a correct value.
1529         * For floppies, it should be 0xff, which stands for whole drive.
1530         */
1531
1532        movb    $0xff, %dh      /* boot partition number */
1533
1534        cmpb    $0xff, %dh      /* is floppy? */
1535        jne     1f
1536        movb    $0, %dl         /* yes, let drive number = 0 */
15371:
1538#endif
1539
1540        xorw    %ax, %ax
1541        movw    %ax, %ds
1542        movw    $0x7c00, %bp
1543
1544#ifdef  BOOTGRUB
1545        movw    %ax, %es
1546#else
1547        movw    $0x1fe0, %ax
1548        movw    %ax, %es
1549        movw    %bp, %si        /* move from 0000:7c00 */
1550        movw    %bp, %di        /* move to 1fe0:7c00 */
1551        movw    $0x0100, %cx    /* one sector to move */
1552        repz movsw
1553        ljmp    $0x1fe0, $(1f - Entry_32 + 0x7c00)
15541:
1555        movw    %ax, %ds
1556#endif
1557        movw    %ax, %ss        /* stack and BP-relative moves up, too */
1558        leaw    -0x20(%bp), %sp
1559        sti
1560        movw    %dx, 0x40(%bp)  /* BIOS passes drive number in DL */
1561
1562        movb    $0x41, %ah
1563        movw    $0x55AA, %bx
1564        int     $0x13
1565        jc      1f              /* No EBIOS */
1566        cmpw    $0xAA55, %bx
1567        jne     1f              /* No EBIOS */
1568        testb   $1, %cl
1569        jz      1f              /* No EBIOS */
1570        /* EBIOS supported */
1571        movb    $0x42, (ebios_32 - 1 - Entry_32 + 0x7c00)
15721:
1573
1574/* figure out where FAT and DATA area starts
1575 * (modifies EAX EDX, sets fat_start and data_start variables)
1576 */
1577        xorl    %eax, %eax
1578        movl    %eax, 0x44(%bp) /* init buffer status */
1579
1580        /* first, find fat_start */
1581        movw    0x0e(%bp), %ax  /* reserved sectors */
1582        addl    0x1c(%bp), %eax /* hidden sectors */
1583        movl    %eax, 0x48(%bp) /* first FAT sector */
1584        movl    %eax, 0x4c(%bp) /* first data sector, initial value */
1585
1586        /* next, find data_start */
1587        movl    0x10(%bp), %eax /* number of fats, no movzbl needed: the
1588                                   2 words after 0x10(%bp) are 0 for fat32 */
1589        mull    0x24(%bp)       /* sectors per fat (EDX=0) */
1590        addl    %eax, 0x4c(%bp) /* first DATA sector */
1591
1592/* Searches for the file in the root directory.
1593 * Returns:     EAX = first cluster of file
1594 */
1595
1596        movl    0x2c(%bp), %eax /* root dir cluster */
1597
15981:
1599        pushl   %eax            /* save cluster */
1600        call    cluster_to_lba_32
1601                /* EDX is sectors per cluster, EAX is sector number */
1602        movw    $(msg_BootError_32 - Entry_32 + 0x7c00), %si
1603        jc      boot_error_32   /* EOC encountered */
1604
16052:
1606        lesw    (loadseg_off_32 - Entry_32)(%bp), %bx   /* load to loadseg:0 */
1607        call    readDisk_32
1608
1609        xorw    %di, %di
1610
1611        /* Search for kernel file name, and find start cluster */
16123:
1613        movw    $11, %cx
1614        movw    $(filename_32 - Entry_32 + 0x7c00), %si
1615        repz cmpsb
1616        jz      1f      /* note that di now is at dirent+11 */
1617
1618        addw    $0x20, %di
1619        andw    $-0x20, %di     /* 0xffe0 */
1620        cmp     0x0b(%bp), %di  /* bytes per sector */
1621        jnz     3b              /* next directory entry */
1622
1623        decw    %dx     /* initially DX holds sectors per cluster */
1624        jnz     2b      /* loop over sectors in cluster */
1625
1626        popl    %eax            /* restore current cluster */
1627        call    next_cluster_32
1628        jmp     1b              /* read next cluster */
1629
1630#ifndef ALTERNATIVE_KERNEL
1631loadseg_off_32:
1632        .word   0
1633        .word   LOADSEG
1634#endif
1635
16361:
1637        /* kernel directory entry is found */
1638        pushw   %es:(0x14-11)(%di)      /* get cluster number HI */
1639        pushw   %es:(0x1a-11)(%di)      /* get cluster number LO */
1640        popl    %eax                    /* convert to 32bit */
1641
1642        xorw    %bx, %bx        /* read kernel at ES:BX=LOADSEG:0 */
1643
1644/* read kernel */
1645
16462:
1647        pushl   %eax
1648        call    cluster_to_lba_32
1649                /* EDX is sectors per cluster, EAX is sector number */
1650        jnc     1f
1651
1652        /* EOC encountered - done */
1653#ifdef  BOOTGRUB
1654        movw    0x40(%bp), %dx  /* boot_drive and boot_partition */
1655#else
1656        movb    0x40(%bp), %bl  /* FreeDOS kernel uses BL, not DL, for drive */
1657#endif
1658        ljmp    *(loadseg_off_32 - Entry_32)(%bp)
1659
16601:
1661        call    readDisk_32
1662        decw    %dx     /* initially DX holds sectors per cluster */
1663        jnz     1b      /* loop over sectors in cluster */
1664
1665        popl    %eax
1666        call    next_cluster_32
1667        jmp     2b
1668
1669/* given a cluster number, find the number of the next cluster in
1670 * the FAT chain. Needs fat_start.
1671 * input:       EAX - cluster
1672 *              EDX = 0
1673 * output:      EAX - next cluster
1674 *              EDX = undefined
1675 */
1676
1677next_cluster_32:
1678        pushw   %es
1679        /* pushw        %di */
1680        pushw   %bx             /* hi word of EBX never used */
1681
1682#if 1
1683        /* xorl %edx, %edx */
1684        shll    $2, %eax        /* 32bit FAT */
1685        movzwl  0x0b(%bp), %ebx /* bytes per sector */
1686        divl    %ebx            /* residue is in EDX */
1687        /* movw %dx, %di */
1688#else
1689        shll    $2, %eax        /* 32bit FAT */
1690        ;xchgw  %ax, %di        /* movw %ax, %di */
1691        movw    %ax, %di
1692        ;shlw   $2, %di         /* 32bit FAT */
1693
1694        pushw   %cx
1695        movw    0x0b(%bp), %bx  /* bytes per sector */
1696        bsfw    %bx, %cx
1697        ;decw   %cx
1698        ;decw   %cx
1699        decw    %bx
1700        andw    %bx, %di        /* mask to sector size */
1701        shrl    %cl, %eax
1702        popw    %cx
1703#endif
1704        addl    0x48(%bp), %eax /* add the first FAT sector number.
1705                                   EAX is absolute sector number now */
1706        movw    $FATSEG, %bx
1707        movw    %bx, %es
1708        xorw    %bx, %bx
1709
1710        cmpl    0x44(%bp), %eax /* is it the last accessed and already buffered
1711                                   FAT sector? */
1712        jz      1f
1713        movl    %eax, 0x44(%bp) /* mark sector EAX as buffered */
1714        call    readDisk_32     /* read sector EAX to buffer */
17151:
1716#if 1
1717        //.byte 0x67, 0x26, 0x80, 0x62, 0x03, 0x0f
1718        addr32 andb     $0x0f, %es:3(%edx)      /* mask out top 4 bits */
1719
1720        //.byte 0x67, 0x66, 0x26, 0x8b, 0x02
1721        addr32 movl     %es:(%edx), %eax        /* read next cluster number */
1722#else
1723        andb    $0x0f, %es:3(%di)       /* mask out top 4 bits */
1724        movl    %es:(%di), %eax /* read next cluster number */
1725#endif
1726        popw    %bx
1727        /* popw %di */
1728        popw    %es
1729        ret
1730
1731/* Convert cluster number to the absolute sector number
1732 * ... or return carry if EndOfChain! Needs data_start.
1733 * input:       EAX - target cluster
1734 * output:      EAX - absolute sector
1735 *              EDX - [bsSectPerClust] (byte)
1736 *              carry clear
1737 *              (if carry set, EAX/EDX unchanged, end of chain)
1738 */
1739
1740cluster_to_lba_32:
1741        cmpl    $0x0ffffff8, %eax       /* check End Of Chain */
1742        cmc
1743        jb      1f                      /* carry is stored if EOC */
1744
1745        /* sector = (cluster-2) * clustersize + data_start */
1746        decl    %eax
1747        decl    %eax
1748
1749        movzbl  0x0d(%bp), %edx         /* sectors per cluster */
1750        pushw   %dx                     /* only DX would change */
1751        mull    %edx                    /* EDX = 0 */
1752        popw    %dx
1753        addl    0x4c(%bp), %eax         /* data_start */
1754        /* here, carry is cleared (unless parameters are wrong) */
17551:
1756        ret
1757
1758/* Read a sector from disk, using LBA or CHS
1759 * input:       EAX - 32-bit DOS sector number
1760 *              ES:BX - destination buffer
1761 *              (will be filled with 1 sector of data)
1762 * output:      ES:BX points one byte after the last byte read.
1763 *              EAX - next sector
1764 */
1765
1766readDisk_32:
1767        pushal
1768        xorl    %edx, %edx      /* EDX:EAX = LBA */
1769        pushl   %edx            /* hi 32bit of sector number */
1770        pushl   %eax            /* lo 32bit of sector number */
1771        pushw   %es             /* buffer segment */
1772        pushw   %bx             /* buffer offset */
1773        pushw   $1              /* 1 sector to read */
1774        pushw   $16             /* size of this parameter block */
1775
1776        xorl    %ecx, %ecx
1777        pushl   0x18(%bp)       /* lo:sectors per track, hi:number of heads */
1778        popw    %cx             /* ECX = sectors per track */
1779        divl    %ecx            /* residue is in EDX */
1780                                /* quotient is in EAX */
1781        incw    %dx             /* sector number in DL */
1782        popw    %cx             /* ECX = number of heads */
1783        pushw   %dx             /* push sector number into stack */
1784        xorw    %dx, %dx        /* EDX:EAX = cylinder * TotalHeads + head */
1785        divl    %ecx            /* residue is in EDX, head number */
1786                                /* quotient is in EAX, cylinder number */
1787        xchgb   %dl, %dh        /* head number should be in DH */
1788                                /* DL = 0 */
1789        popw    %cx             /* pop sector number from stack */
1790        xchgb   %al, %ch        /* lo 8bit cylinder should be in CH */
1791                                /* AL = 0 */
1792        shlb    $6, %ah         /* hi 2bit cylinder ... */
1793        orb     %ah, %cl        /* ... should be in CL */
1794
1795        movw    $0x201, %ax     /* read 1 sector */
1796ebios_32: /* ebios_32 - 1 points to 0x02 that can be changed to 0x42 */
1797
1798//      cmpb    $0x0e, 2(%bp)   /* force LBA? */
1799//      jnz     1f              /* no, continue */
1800//      movb    $0x42, %ah      /* yes, use extended disk read */
1801//1:
1802        movw    %sp, %si        /* DS:SI points to disk address packet */
1803        movb    0x40(%bp), %dl  /* hard disk drive number */
1804        int     $0x13
1805        popaw                   /* remove parameter block from stack */
1806        popal
1807        jc      disk_error_32   /* disk read error, jc 1f if caller handles */
1808        incl    %eax            /* next sector */
1809        addw    0x0b(%bp), %bx  /* bytes per sector */
1810        jnc     1f              /* 64K bound check */
1811        pushw   %dx
1812        movw    %es, %dx
1813        addb    $0x10, %dh      /* add 1000h to ES */
1814                                /* here, carry is cleared */
1815        movw    %dx, %es
1816        popw    %dx
18171:
1818        /* carry stored on disk read error */
1819        ret
1820
1821        . = . - (. - readDisk_32)/91
1822
1823msg_DiskReadError_32:
1824
1825        .ascii  "disk error\0"
1826
1827msg_BootError_32:
1828
1829        .ascii  "No "
1830
1831filename_32:
1832
1833#ifdef  BOOTGRUB2
1834        .ascii  "G2LDR      \0"
1835#elif defined (BOOTGRUB)
1836        .ascii  "GRLDR      \0"
1837#else
1838        .ascii  "KERNEL  SYS\0"
1839#endif
1840
1841#ifdef ALTERNATIVE_KERNEL
1842filename_end_32:
1843
1844        . = Entry_32 + 0x1e8
1845
1846loadseg_off_32:
1847        .word   0
1848        .word   LOADSEG
1849
1850        . = Entry_32 + 0x1ec
1851
1852boot_image_ofs_32:
1853
1854        .word (filename_32 - Entry_32)+(filename_end_32 - filename_32 - 1)*2048
1855#endif
1856
1857        . = Entry_32 + 0x1ee
1858
1859disk_error_32:
1860
1861        movw    $(msg_DiskReadError_32 - Entry_32 + 0x7c00), %si
1862
1863boot_error_32:
1864
1865/* prints string DS:SI (modifies AX BX SI) */
1866
1867//print_32:
18681:
1869        lodsb   (%si), %al      /* get token */
1870        //xorw  %bx, %bx        /* video page 0 */
1871        movb    $0x0e, %ah      /* print it */
1872        int     $0x10           /* via TTY mode */
1873        cmpb    $0, %al         /* end of string? */
1874        jne     1b              /* until done */
1875
1876        /* The caller will change this to
1877         *      ljmp    $0x9400, $(try_next_partition - _start1)
1878         */
1879
18801:      jmp     1b
1881
1882        . = Entry_32 + 0x1fc
1883
1884        .word   0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
1885
1886        . = Entry_32 + 0x200
1887
1888        . = _start1 + 0x600
1889
1890        //.arch i8086, nojumps
1891        .arch   i186, nojumps
1892/*
1893 * The following is based on FreeDOS, modified heavily by Tinybit in Feb, 2004
1894 *
1895 * Merges FAT12 and FAT16 boot sectors to ONE FAT boot sector!
1896 *
1897 * Memory layout for GRLDR FAT single stage boot process:
1898 *
1899 *      +--------+
1900 *      |        |
1901 *      |GRLDR   | also used as max 128k FAT buffer
1902 *      |LOADED  | before GRLDR loading starts
1903 *      |--------| 2000:0000
1904 *      |        |
1905 *      |--------| 0000:7E00
1906 *      |BOOTSECT|
1907 *      |ORIGIN  |
1908 *      |--------| 0000:7C00
1909 *      |        |
1910 *      |--------| 0000:3000
1911 *      |CLUSTER |
1912 *      |LIST    |
1913 *      |--------| 0000:2000
1914 *      |        |
1915 *      +--------+
1916 */
1917
1918/*
1919;
1920; File:
1921;                            boot.asm
1922; Description:
1923;                           DOS-C boot
1924;
1925;                       Copyright (c) 1997;
1926;                           Svante Frey
1927;                       All Rights Reserved
1928;
1929; This file is part of DOS-C.
1930;
1931; DOS-C is free software; you can redistribute it and/or
1932; modify it under the terms of the GNU General Public License
1933; as published by the Free Software Foundation; either version
1934; 2, or (at your option) any later version.
1935;
1936; DOS-C is distributed in the hope that it will be useful, but
1937; WITHOUT ANY WARRANTY; without even the implied warranty of
1938; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1939; the GNU General Public License for more details.
1940;
1941; You should have received a copy of the GNU General Public
1942; License along with DOS-C; see the file COPYING.  If not,
1943; write to the Free Software Foundation, 675 Mass Ave,
1944; Cambridge, MA 02139, USA.
1945;
1946;
1947;       +--------+ 1FE0:7E00
1948;       |BOOT SEC|
1949;       |RELOCATE|
1950;       |--------| 1FE0:7C00
1951;       |        |
1952;       |--------| 1FE0:3000
1953;       | CLUSTER|
1954;       |  LIST  |
1955;       |--------| 1FE0:2000
1956;       |        |
1957;       |--------| 0000:7E00
1958;       |BOOT SEC| overwritten by max 128k FAT buffer
1959;       |ORIGIN  | and later by max 134k loaded kernel
1960;       |--------| 0000:7C00
1961;       |        |
1962;       |--------|
1963;       |KERNEL  | also used as max 128k FAT buffer
1964;       |LOADED  | before kernel loading starts
1965;       |--------| 0060:0000
1966;       |        |
1967;       +--------+
1968*/
1969
1970#ifdef  BOOTGRUB
1971#define LOADSEG_12_16   0x2000
1972#define FATBUF          0x2000        /* offset of temp buffer for FAT chain */
1973#else
1974#define LOADSEG_12_16   0x0060
1975#define FATBUF          0x2000        /* offset of temp buffer for FAT chain */
1976#endif
1977
1978Entry_12_16:
1979        jmp     1f
1980
1981        . = Entry_12_16 + 0x02
1982
1983        /* The default mode is CHS. This is for maximum compatiblity with
1984         * small-sized disks, e.g., floppies.
1985         *
1986         * Valid values are 0x90 for CHS mode, or 0x0e for LBA mode.
1987         *
1988         * If the BIOS int13 supports LBA, this byte can be safely set to 0x0e.
1989         *
1990         * Some USB BIOSes might have bugs when using CHS mode, so the format
1991         * program should set this byte to 0x0e. It seems that (generally) all
1992         * USB BIOSes have LBA support.
1993         *
1994         * If the format program does not know whether the BIOS has LBA
1995         * support, it may operate this way:
1996         *
1997         * if (partition_start + total_sectors_in_partition) exceeds the CHS
1998         * addressing ability(especially when it is greater than 1024*256*63),
1999         * the caller should set this byte to 0x0e, otherwise, set to 0x90.
2000         */
2001
2002        .byte   0x90    /* for CHS. Another possible value is 0x0e for LBA */
2003
2004
2005        . = Entry_12_16 + 0x03
2006
2007#ifdef  BOOTGRUB
2008        .ascii  "GRLDR   "
2009#endif
2010
2011        . = Entry_12_16 + 0x0b
2012
2013        .word   0x200           /* bytes per sector */
2014
2015        . = Entry_12_16 + 0x0d
2016
2017        .byte   1               /* sectors per cluster */
2018
2019        . = Entry_12_16 + 0x0e
2020
2021        .word   1               /* reserved sectors */
2022
2023        . = Entry_12_16 + 0x10
2024
2025        .byte   2               /* number of FATs */
2026
2027        . = Entry_12_16 + 0x11
2028
2029        .word   224             /* Max dir entries */
2030
2031        . = Entry_12_16 + 0x13
2032
2033        .word   2880            /* total sectors in the filesystem */
2034
2035        . = Entry_12_16 + 0x15
2036
2037        .byte   0xf0            /* media descriptor */
2038
2039        . = Entry_12_16 + 0x16
2040
2041        .word   9               /* sectors per FAT */
2042
2043        . = Entry_12_16 + 0x18
2044
2045        .word   18              /* sectors per track */
2046
2047        . = Entry_12_16 + 0x1a
2048
2049        .word   2               /* number of heads */
2050
2051        . = Entry_12_16 + 0x1c
2052
2053        .long   0               /* hidden sectors */
2054
2055        . = Entry_12_16 + 0x20
2056
2057        .long   0               /* total sectors for large partitions */
2058
2059        . = Entry_12_16 + 0x24
2060
2061        /* drive number of the boot device.
2062         * This byte is ignored for read. The program will write DL onto
2063         * this byte. The caller should set drive number in DL.
2064         * We assume all BIOSes pass correct drive number in DL.
2065         * That is to say, buggy BIOSes are not supported!!
2066         */
2067
2068        .byte   0
2069
2070        . = Entry_12_16 + 0x25
2071
2072        /* partition number of this filesystem in the boot drive.
2073         * This byte is ignored for read. The boot code will write partition
2074         * number onto this byte. See Entry_12_16 + 0x41 below.
2075         */
2076
2077        .byte   0
2078
2079        . = Entry_12_16 + 0x26
2080
2081        .byte   0x29            /* extended boot signature */
2082
2083        . = Entry_12_16 + 0x27
2084
2085        .long   0x0AC4AF63      /* volume serial number */
2086
2087        . = Entry_12_16 + 0x2b
2088
2089        .ascii  "NO NAME    "   /* volume label */
2090
2091        . = Entry_12_16 + 0x36
2092
2093        .ascii  "FAT12   "      /* filesystem ID */
2094
2095/*
2096;       bp is initialized to 7c00h
2097%define bsOemName       bp+0x03      ; OEM label
2098%define bsBytesPerSec   bp+0x0b      ; bytes/sector
2099%define bsSecPerClust   bp+0x0d      ; sectors/allocation unit
2100%define bsResSectors    bp+0x0e      ; # reserved sectors
2101%define bsFATs          bp+0x10      ; # of fats
2102%define bsRootDirEnts   bp+0x11      ; # of root dir entries
2103%define bsSectors       bp+0x13      ; # sectors total in image
2104%define bsMedia         bp+0x15      ; media descrip: fd=2side9sec, etc...
2105%define sectPerFat      bp+0x16      ; # sectors in a fat
2106%define sectPerTrack    bp+0x18      ; # sectors/track
2107%define nHeads          bp+0x1a      ; # heads
2108%define nHidden         bp+0x1c      ; # hidden sectors
2109%define nSectorHuge     bp+0x20      ; # sectors if > 65536
2110%define drive           bp+0x24      ; drive number
2111                        bp+0x25      ; partition number for GRLDR
2112%define extBoot         bp+0x26      ; extended boot signature
2113%define volid           bp+0x27
2114%define vollabel        bp+0x2b
2115%define filesys         bp+0x36
2116
2117%define RootDirSecs     bp+0x26         ; # of sectors root dir uses
2118                                        ; (overwriting unused bytes)
2119%define fat_start       bp+0x28         ; first FAT sector
2120                                        ; (overwriting unused bytes)
2121%define root_dir_start  bp+0x2c         ; first root directory sector
2122                                        ; (overwriting unused bytes)
2123%define data_start      bp+0x30         ; first data sector
2124                                        ; (overwriting unused bytes)
2125%define data_clusters   bp+0x34         ; # of clusters in data area
2126                                        ; (overwriting unused bytes)
2127                        bp+0x36         ; bytes per FAT( > 0x1800 means FAT16)
2128                                        ; (overwriting unused bytes)
2129*/
2130                /* not used: [0x26] = byte 0x29 (ext boot param flag)
2131                 * [0x27] = dword serial
2132                 * [0x2b] = label (padded with 00, 11 bytes)
2133                 * [0x36] = "FAT12" or "FAT16",32,32,32 (not used by Windows)
2134                 * ([0x3e] is where FreeDOS parts start)
2135                 */
2136
2137        . = Entry_12_16 + 0x3e
21381:
2139        cli
2140        cld
2141
2142#ifdef  BOOTGRUB
2143
2144        . = Entry_12_16 + 0x40
2145
2146        /* the byte at offset 0x41 stores the real partition number for read.
2147         * the format program or the caller should set it to a correct value.
2148         * For floppies, it should be 0xff, which stands for whole drive.
2149         */
2150
2151        movb    $0xff, %dh      /* boot partition number */
2152
2153        cmpb    $0xff, %dh      /* is floppy? */
2154        jne     1f
2155        movb    $0, %dl         /* yes, let drive number = 0 */
21561:
2157#endif
2158
2159        xorw    %ax, %ax
2160        movw    %ax, %ds
2161        movw    $0x7c00, %bp
2162
2163#ifdef  BOOTGRUB
2164        movw    %ax, %es
2165        movw    %ax, %ss        /* stack and BP-relative moves up, too */
2166        leaw    -0x20(%bp), %sp
2167        sti
2168        movw    %dx, 0x24(%bp)  /* BIOS passes drive number in DL */
2169                                /* AX=0 */
2170//      xchgw   %ax, %dx        /* let DX = 0 */
2171//      xorw    %cx, %cx        /* CX = 0 */
2172#else
2173        movw    %bp, %si        /* move from 0000:7c00 */
2174        movw    %bp, %di        /* move to 1fe0:7c00 */
2175        movb    %dl, 0x24(%si)  /* BIOS passes drive number in DL */
2176//      xchgw   %ax, %dx        /* let DX = 0 */
2177        movw    $0x1fe0, %ax
2178        movw    %ax, %es
2179        movw    $0x0100, %cx    /* one sector to move */
2180        repz movsw
2181                                /* CX = 0 */
2182        ljmp    $0x1fe0, $(1f - Entry_12_16 + 0x7c00)
21831:
2184        movw    %ax, %ds
2185        movw    %ax, %ss        /* stack and BP-relative moves up, too */
2186        leaw    -0x20(%bp), %sp
2187        sti
2188                                /* AX=0x1fe0 */
2189#endif
2190
2191        movb    $0x41, %ah
2192        movw    $0x55AA, %bx
2193        int     $0x13
2194        jc      1f              /* No EBIOS */
2195        cmpw    $0xAA55, %bx
2196        jne     1f              /* No EBIOS */
2197        testb   $1, %cl
2198        jz      1f              /* No EBIOS */
2199        /* EBIOS supported */
2200        movb    $0x42, (ebios_12_16 - 1 - Entry_12_16 + 0x7c00)
22011:
2202//      xorw    %cx, %cx
2203        xorw    %ax, %ax
2204
2205        /* GET DRIVE PARMS: Calculate start of some disk areas */
2206
2207        movw    0x1c(%bp), %si  /* number of hidden sectors(lo) */
2208        movw    0x1e(%bp), %di  /* number of hidden sectors(hi) */
2209        addw    0x0e(%bp), %si  /* number of reserved sectors */
2210        adcw    %ax, %di        /* DI:SI = first FAT sector */
2211                                /* AX = 0 */
2212
2213        movw    %si, 0x28(%bp)  /* FAT start sector(lo) */
2214        movw    %di, 0x2a(%bp)  /* FAT start sector(hi) */
2215
2216        //xchgw %ax, %dx        /* let AX = 0 */
2217        movb    0x10(%bp), %al  /* number of FATs */
2218        /* cbw */
2219        mulw    0x16(%bp)       /* sectors per FAT */
2220                                /* DX:AX = total number of FAT sectors */
2221                                /* DX = 0 since no too many FAT sectors */
2222        addw    %ax, %si
2223        adcw    %dx, %di        /* DI:SI = root directory start sector */
2224        movw    %si, 0x2c(%bp)  /* root directory starting sector(lo) */
2225        movw    %di, 0x2e(%bp)  /* root directory starting sector(hi) */
2226
2227        /* Calculate how many sectors the root directory occupies */
2228
2229        movw    0x0b(%bp), %bx  /* bytes per sector */
2230        movb    $5, %cl         /* divide BX by 32 */
2231        shrw    %cl, %bx        /* BX = directory entries per sector */
2232
2233        movw    0x11(%bp), %ax  /* max number of root dir entries */
2234        /* xorw %dx, %dx */     /* assuming DX = 0 */
2235        divw    %bx             /* AX = sectors per root directory */
2236                                /* DX = 0 since normally no residue */
2237
2238        movw    %ax, 0x26(%bp)  /* number of sectors the root dir occupies */
2239
2240        addw    %ax, %si        /* DI:SI = first data sector */
2241        adcw    %dx, %di        /* assuming DX = 0 */
2242
2243        movw    %si, 0x30(%bp)  /* data starting sector(lo) */
2244        movw    %di, 0x32(%bp)  /* data starting sector(hi) */
2245#ifdef USE_TOTAL_CLUSTERS
2246        movw    0x13(%bp), %cx  /* total sectors(small) */
2247        jcxz    1f
2248        movw    %cx, 0x20(%bp)  /* total sectors(large)(lo) */
2249        movw    %dx, 0x22(%bp)  /* total sectors(large)(hi), assuming DX = 0 */
22501:
2251        movw    0x20(%bp), %ax  /* total sectors(large) */
2252        movw    0x22(%bp), %bx
2253        addw    0x1c(%bp), %ax  /* number of hidden sectors */
2254        adcw    0x1e(%bp), %bx
2255        subw    %si, %ax        /* data starting sector */
2256        sbbw    %di, %bx        /* BX:AX = total sectors in the data area */
2257        movb    0x0d(%bp), %dl  /* sectors per cluster(DH=0) */
2258        xchgw   %bx, %dx        /* DX:AX = total sectors in the data area */
2259                                /* BX = sectors per cluster */
2260        divw    %bx             /* AX = total clusters in the data area */
2261        movw    %ax, 0x34(%bp)  /* total clusters in the data area */
2262#else
2263        movw    $0xffff, 0x36(%bp)
2264        movw    0x16(%bp), %ax  /* sectors per FAT */
2265        mulw    0x0b(%bp)       /* bytes per sector */
2266        jc      1f
2267        movw    %ax, 0x36(%bp)
22681:
2269#endif
2270        /* Searches for the file in the root directory
2271         *
2272         * Returns:
2273         *      AX = first cluster of file
2274         */
2275
2276        /* First, read the whole root directory into the temporary buffer */
2277
2278        movw    0x2c(%bp), %ax  /* root directory starting sector(lo) */
2279        movw    0x2e(%bp), %dx  /* root directory starting sector(hi) */
2280        movw    0x26(%bp), %di  /* number of sectors the root dir occupies */
2281        lesw    (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
2282                                /* ES:BX = loadseg:0 */
2283        call    readDisk_12_16
2284
2285        lesw    (loadseg_off_12_16 - Entry_12_16)(%bp), %di
2286                                /* ES:DI = loadseg:0 */
2287
2288
2289        /* Search for kernel file name, and find start cluster */
2290
22911:
2292        movw    $11, %cx
2293        movw    $(filename_12_16 - Entry_12_16 + 0x7c00), %si
2294        pushw   %di
2295        repz cmpsb
2296        popw    %di
2297        movw    %es:0x1a(%di), %ax      /* get cluster number from dir entry */
2298        jz      1f
2299
2300        addw    $0x20, %di      /* go to next directory entry */
2301        cmpb    %ch, %es:(%di)  /* if the first byte of the name is 0,     */
2302                                /* there is no more files in the directory */
2303                                /* assuming CH = 0 */
2304        jnz     1b
2305        movw    $(msg_BootError_12_16 - Entry_12_16 + 0x7c00), %si
2306        jmp     boot_error_12_16        /* fail if not found */
2307
2308#ifndef ALTERNATIVE_KERNEL
2309loadseg_off_12_16:      .word   0
2310loadseg_seg_12_16:      .word   LOADSEG_12_16
2311#endif
2312
23131:
2314        pushw   %ax             /* store first cluster number */
2315                                /* CX = 0 */
2316
2317
2318        /* Reads the FAT chain and stores it in a temporary buffer in the first
2319         * 64KB.  The FAT chain is stored an array of 16-bit cluster numbers,
2320         * ending with 0.
2321         *
2322         * The file must fit in conventional memory, so it can't be larger than
2323         * 640KB. The sector size must be at least 512 bytes, so the FAT chain
2324         * can't be larger than around 3KB.
2325         *
2326         * Call with:   AX = first cluster in chain
2327         */
2328
2329        /* Load the complete FAT into memory. The FAT can't be larger
2330         * than 128 kb, so it should fit in the temporary buffer.
2331         */
2332
2333        lesw    (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
2334                                /* ES:BX = loadseg:0 */
2335        movw    0x16(%bp), %di  /* sectors per FAT */
2336        movw    0x28(%bp), %ax  /* FAT start sector(lo) */
2337        movw    0x2a(%bp), %dx  /* FAT start sector(hi) */
2338        call    readDisk_12_16
2339        popw    %ax             /* restore first cluster number */
2340
2341        /* Set ES:DI to the temporary storage for the FAT chain */
2342        pushw   %ds
2343        popw    %es
2344        movw    (loadseg_seg_12_16 - Entry_12_16)(%bp), %ds
2345        movw    $FATBUF, %di
2346
23472:
2348        stosw                   /* store cluster number */
2349        movw    %ax, %si        /* SI = cluster number */
2350        addw    %si, %si        /* multiply cluster number by two */
2351        movw    (loadseg_seg_12_16 - Entry_12_16)(%bp), %dx
2352                                /* segment for FAT16 */
2353        jnc     1f
2354        addb    $0x10, %dh      /* overflow. Add 0x1000 to segment value */
23551:
2356
2357#ifdef USE_TOTAL_CLUSTERS
2358        cmpw    $0x0ff7, 0x34(%bp)      /* total clusters in the data area */
2359#else
2360        cmpw    $0x1801, 0x36(%bp)      /* bytes per FAT */
2361#endif
2362        jnb     3f
2363
2364        /* This is a FAT12 disk */
2365
2366        addw    %ax, %si        /* multiply cluster number by 3 ... */
2367        shrw    $1, %si         /* ... and divide by 2 */
2368        lodsw
2369
2370        /* If the cluster number was even, the cluster value is now in
2371         * bits 0-11 of AX. If the cluster number was odd, the cluster
2372         * value is in bits 4-15, and must be shifted right 4 bits. If
2373         * the number was odd, CF was set in the last shift instruction.
2374         */
2375
2376        jnc     1f
2377        movb    $4, %cl
2378        shrw    %cl, %ax
23791:
2380        andb    $0x0f, %ah      /* mask off the highest 4 bits */
2381        cmpw    $0x0ff7, %ax    /* check for EOF */
2382        jmp     4f
2383
23843:
2385        /* This is a FAT16 disk. The maximal size of a 16bit FAT
2386         * is 128KB, so it may not fit within a single 64KB segment
2387         */
2388
2389        movw    %dx, %ds        /* DS:SI points to next cluster */
2390        lodsw                   /* AX = next cluster */
2391
2392        cmpw    $0xfff7, %ax    /* check for EOF */
23934:
2394        jbe     2b              /* continue if not EOF */
2395
2396        /* Mark end of FAT chain with 0, so we have a single
2397         * EOF marker for both FAT12 and FAT16 systems.
2398         */
2399
2400        xorw    %ax, %ax
2401        stosw
2402
2403        pushw   %cs
2404        popw    %ds
2405
2406        /* Loads the file into memory, one cluster at a time */
2407
2408        lesw    (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
2409                                /* ES:BX = loadseg:0 */
2410        movw    $FATBUF, %si    /* set DS:SI to the FAT chain */
2411
24122:
2413        lodsw                   /* AX = next cluster to read */
2414        orw     %ax, %ax
2415        jnz     1f
2416
2417        /* EOC encountered - done */
2418#ifdef  BOOTGRUB
2419        movw    0x24(%bp), %dx  /* boot_drive and boot_partition */
2420#else
2421        movb    0x24(%bp), %bl  /* FreeDOS kernel uses BL, not DL, for drive */
2422#endif
2423        ljmp    *(loadseg_off_12_16 - Entry_12_16)(%bp) /* boot it! */
2424
24251:
2426        decw    %ax             /* cluster numbers start with 2 */
2427        decw    %ax
2428
2429        movw    0x0d(%bp), %di  /* sectors per cluster */
2430        andw    $0xff, %di      /* DI = sectors per cluster */
2431        mulw    %di
2432        addw    0x30(%bp), %ax  /* data starting sector(lo) */
2433        adcw    0x32(%bp), %dx  /* data starting sector(hi) */
2434                                /* DX:AX = first sector to read */
2435        call    readDisk_12_16
2436        jmp     2b              /* read next cluster */
2437
2438/* Reads a number of sectors into memory.
2439 *
2440 * Call with:   DX:AX = 32-bit DOS sector number
2441 *                 DI = number of sectors to read
2442 *              ES:BX = destination buffer
2443 *
2444 * Returns:     CF set on error
2445 *              ES:BX points one byte after the last byte read.
2446 *              DX:AX = next sector number after read
2447 */
2448
2449readDisk_12_16:
24502:
2451        pushaw
2452        xorw    %cx, %cx
2453        pushw   %cx
2454        pushw   %cx
2455        pushw   %dx
2456        pushw   %ax
2457        pushw   %es             /* buffer segment */
2458        pushw   %bx             /* buffer offset */
2459        incw    %cx
2460        pushw   %cx             /* 1 sector to read */
2461        movb    $16, %cl
2462        pushw   %cx             /* size of this parameter block */
2463
2464        xchgw   %ax, %cx        /* save AX to CX */
2465
2466        /*
2467         * translate sector number to BIOS parameters
2468         *
2469         * LBA = sector-1                       offset in track
2470         *     + head * sectPerTrack            offset in cylinder
2471         *     + cyl * sectPerTrack * nHeads    offset in platter
2472         *
2473         */
2474        pushw   %bx
2475        movw    0x18(%bp), %ax  /* sectors per track */
2476        movw    %ax, %bx
2477        mulb    0x1a(%bp)       /* nHeads, but maybe a word value 0x100 */
2478        jnz     1f
2479        movb    %bl, %ah        /* nHeads=0x100, so AX=sectPerTrack*0x100 */
24801:
2481        xchgw   %ax, %cx        /* restore AX from CX, and save AX to CX */
2482                /* DX:AX = LBA, CX = nHeads * sectPerTrack <= 256*63 */
2483        divw    %cx      /* AX = cyl, DX = sector-1 + head * sectPerTrack */
2484        xchgw   %ax, %dx /* DX = cyl, AX = sector-1 + head * sectPerTrack */
2485        divb    %bl     /* sectors per track */
2486                         /* DX = cyl, AL = head, AH = sector-1 */
2487#if 1
2488        xchgb   %al, %ah /* DX = cyl, AH = head, AL = sector-1 */
2489        incw    %ax      /* DX = cyl, AH = head, AL = sector */
2490        xchgw   %ax, %dx /* AX = cyl, DH = head, DL = sector */
2491        xchgw   %ax, %cx /* CX = cyl, DH = head, DL = sector */
2492        xchgb   %cl, %ch        /* set cyl number low 8 bits in CH */
2493        rorb    $1, %cl         /* move cyl high bits into bits 7-6 */
2494        rorb    $1, %cl         /*      (assumes top = 0)             */
2495        orb     %dl, %cl        /* merge sector into cylinder */
2496#else
2497        movw    %dx, %cx /* CX = cyl, AL = head, AH = sector-1 */
2498
2499        /*
2500         * the following manipulations are necessary in order to properly place
2501         * parameters into registers.
2502         * CH = cylinder number low 8 bits
2503         * CL<7-6> = cylinder high two bits
2504         * CL<5-0> = sector
2505         */
2506        movb    %al, %dh        /* save head into DH for BIOS */
2507        xchgb   %cl, %ch        /* set cyl number low 8 bits in CH */
2508        rorb    $1, %cl         /* move cyl high bits into bits 7-6 */
2509        rorb    $1, %cl         /*      (assumes top = 0)             */
2510        incb    %ah             /* AH = sector number */
2511        orb     %ah, %cl        /* merge sector into cylinder */
2512#endif
2513        popw    %bx
2514
2515        movw    $0x0201, %ax    /* read 1 sector */
2516ebios_12_16: /* ebios_12_16 - 1 points to 0x02 that can be changed to 0x42 */
2517
2518//      cmpb    $0x0e, 2(%bp)   /* force LBA? */
2519//      jnz     1f              /* no, continue */
2520//      movb    $0x42, %ah      /* yes, use extended disk read */
2521//1:
2522        movw    %sp, %si        /* DS:SI points to disk address packet */
2523        movb    0x24(%bp), %dl  /* drive number */
2524        int     $0x13
2525//      stc                     #; only for testing the buggy Virtual PC
2526        popaw                   /* remove parameter block from stack */
2527        popaw
2528        jc      disk_error_12_16        /* disk read error, jc 1f if caller handles */
2529        incw    %ax             /* next sector */
2530        jnz     1f
2531        incw    %dx
25321:
2533        addw    0x0b(%bp), %bx  /* bytes per sector */
2534        jnc     1f              /* 64K bound check */
2535        pushw   %dx
2536        movw    %es, %dx
2537        addb    $0x10, %dh      /* add 1000h to ES */
2538                                /* here, carry is cleared */
2539        movw    %dx, %es
2540        popw    %dx
25411:
2542        decw    %di
2543        jnz     2b
2544
2545        /* carry stored on disk read error */
2546        ret
2547
2548        . = . - (. - readDisk_12_16)/99
2549
2550msg_DiskReadError_12_16:
2551
2552        .ascii  "disk error\0"
2553
2554msg_BootError_12_16:
2555
2556        .ascii  "No "
2557
2558filename_12_16:
2559
2560#ifdef  BOOTGRUB2
2561        .ascii  "G2LDR      \0"
2562#elif defined (BOOTGRUB)
2563        .ascii  "GRLDR      \0"
2564#else
2565        .ascii  "KERNEL  SYS\0"
2566#endif
2567
2568#ifdef ALTERNATIVE_KERNEL
2569filename_end_12_16:
2570
2571        . = Entry_12_16 + 0x1e8
2572
2573loadseg_off_12_16:      .word   0
2574loadseg_seg_12_16:      .word   LOADSEG_12_16
2575
2576        . = Entry_12_16 + 0x1ec
2577
2578boot_image_ofs_12_16:
2579
2580        .word (filename_12_16 - Entry_12_16)+(filename_end_12_16 - filename_12_16 - 1)*2048
2581#endif
2582
2583        . = Entry_12_16 + 0x1ee
2584
2585disk_error_12_16:
2586
2587        movw    $(msg_DiskReadError_12_16 - Entry_12_16 + 0x7c00), %si
2588
2589boot_error_12_16:
2590
2591/* prints string DS:SI (modifies AX BX SI) */
2592
2593//print_12_16:
25941:
2595        lodsb   (%si), %al      /* get token */
2596        //xorw  %bx, %bx        /* video page 0 */
2597        movb    $0x0e, %ah      /* print it */
2598        int     $0x10           /* via TTY mode */
2599        cmpb    $0, %al         /* end of string? */
2600        jne     1b              /* until done */
2601
2602        /* The caller will change this to
2603         *      ljmp    $0x9400, $(try_next_partition - _start1)
2604         */
2605
26061:      jmp     1b
2607
2608        . = Entry_12_16 + 0x1fc
2609
2610        .word   0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
2611
2612        . = Entry_12_16 + 0x200
2613
2614        . = _start1 + 0x800
2615
2616
2617
2618
2619        .arch   i486, nojumps
2620
2621/*
2622 #; Ext2 boot sector for GRLDR
2623 */
2624
2625
2626#define DEBUG   call    debug_print
2627#undef DEBUG
2628
2629        //. = _start1 + 0x800
2630
2631Entry_ext2:
2632
2633        jmp     1f
2634
2635        . = Entry_ext2 + 0x02
2636
2637        /* The default mode is CHS. This is for maximum compatiblity with
2638         * small-sized disks, e.g., floppies.
2639         *
2640         * Valid values are 0x02 for CHS mode, or 0x42 for LBA mode.
2641         *
2642         * If the BIOS int13 supports LBA, this byte can be safely set to 0x42.
2643         *
2644         * Some USB BIOSes might have bugs when using CHS mode, so the format
2645         * program should set this byte to 0x42. It seems that (generally) all
2646         * USB BIOSes have LBA support.
2647         *
2648         * If the format program does not know whether the BIOS has LBA
2649         * support, it may operate this way:
2650         *
2651         * if (partition_start + total_sectors_in_partition) exceeds the CHS
2652         * addressing ability(especially when it is greater than 1024*256*63),
2653         * the caller should set this byte to 0x42, otherwise, set to 0x02.
2654         */
2655
2656        .byte   0x02    /* for CHS. Another possible value is 0x42 for LBA */
2657
2658        . = Entry_ext2 + 0x03
2659
2660#if 0
2661
2662        .ascii  "ext2 grldr"
2663
2664#else
2665
2666msg_DiskReadError_ext2:
2667
2668        .ascii  "I/O error\0"
2669
2670#endif
2671
2672        . = Entry_ext2 + 0x0d
2673
2674        /* sectors per block. Valid values are 2, 4, 8, 16, 32.  */
2675
2676        .byte   2
2677
2678        . = Entry_ext2 + 0x0e
2679
2680        /* bytes per block.
2681         * Valid values are 0x400, 0x800, 0x1000, 0x2000, 0x4000.
2682         */
2683
2684        .word   1024            /* bytes per block, at most 16K */
2685
2686        . = Entry_ext2 + 0x10
2687
2688        /* pointers in pointers-per-block blocks, that is, number of blocks
2689         * covered by a double-indirect block.
2690         * Valid values are 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000.
2691         */
2692
2693        .long   0x10000 /* number of blocks covered by double-indirect block */
2694                        /* low word=0 */
2695
2696        . = Entry_ext2 + 0x14
2697
2698        /* pointers per block, that is, number of blocks covered by an indirect
2699         * block. Valid values are 0x100, 0x200, 0x400, 0x800, 0x1000.
2700         */
2701
2702        .long   0x100           /* high word=0, low byte=0 */
2703
2704        . = Entry_ext2 + 0x18
2705
2706        /* this is default for 1.44M floppy, the caller should set it to
2707         * a correct value */
2708
2709        .word   18      /* sectors per track */
2710
2711        . = Entry_ext2 + 0x1a
2712
2713        /* this is default for 1.44M floppy, the caller should set it to
2714         * a correct value */
2715
2716        .word   2       /* number of heads */
2717
2718        . = Entry_ext2 + 0x1c
2719
2720        /* this is default for 1.44M floppy, the caller should set it to
2721         * a correct value */
2722
2723        .long   0               /* hidden sectors */
2724
2725        . = Entry_ext2 + 0x20
2726
2727        /* total sectors in the filesystem(or in the partition).
2728         * This value is informative. The code does not use it.
2729         */
2730
2731        /* this is default for 1.44M floppy, the caller should set it to
2732         * a correct value */
2733
2734        .long   2880
2735
2736        . = Entry_ext2 + 0x24
2737
2738        /* This byte is ignored for read. The program will write DL onto
2739         * this byte. The caller should set drive number in DL.
2740         * We assume all BIOSes pass correct drive number in DL.
2741         * That is to say, buggy BIOSes are not supported!!
2742         */
2743
2744        .byte   0               /* drive number */
2745
2746        . = Entry_ext2 + 0x25
2747
2748        /* this is default for floppies, the caller should set it to
2749         * a correct value for hard-drive partitions */
2750
2751        .byte   0xff            /* partition number, 0xff for whole drive */
2752
2753        . = Entry_ext2 + 0x26
2754
2755        .word   0x80            /* inode size */
2756
2757        . = Entry_ext2 + 0x28
2758
2759        /* this is default for 1.44M floppy, the caller should set it to
2760         * a correct value */
2761
2762        .long   2048            /* s_inodes_per_group */
2763
2764        . = Entry_ext2 + 0x2c
2765
2766        /* block number for group descriptors = s_first_data_block + 1.
2767         * Valid values are 2 for 1024-byte blocks, and 1 for otherwise.
2768         */
2769
2770        /* this is default for 1.44M floppy, the caller should set it to
2771         * a correct value */
2772
2773        .long   2               /* block number for group descriptors */
2774
2775        . = Entry_ext2 + 0x30
27761:
2777        cld                     /* 0xFC */
2778
2779        xorw    %ax, %ax        /* 0x31, 0xC0; CF=0, ZF=1 */
2780
2781        /* this byte `nop' will be changed to `cwd' by bootlace for floppy */
2782        nop                     /* 0x90=nop, 0x99=cwd */
2783                                /* cwd will set DL=0 forcibly for floppy A: */
2784
2785        movw    %ax, %ss        /* constant SS=0 */
2786        movw    $0x7c00, %sp
2787
2788        movw    %sp, %bp        /* constant BP=0x7c00 */
2789        movw    %ax, %ds        /* constant DS=0 */
2790
2791        pushw   %ax             /* 0x0000 at 0000:7bfe */
2792        movw    $0x1000, %bx
2793        pushw   %bx             /* 0x1000 at 0000:7bfc */
2794        pushw   %ax             /* 0x0000 at 0000:7bfa */
2795                                /* SP=0x7bfa */
2796
2797        /* the 6 bytes in the stack are used by read_block():
2798         *      0000    ----    -2(%bp)
2799         *      1000    ----    -4(%bp)
2800         *      0000    ----    -6(%bp)
2801         * Don't touch them!
2802         */
2803
2804        movb    %dl, 0x24(%bp)  /* BIOS passes drive number in DL */
2805
2806        movb    $0x41, %ah
2807        movw    $0x55AA, %bx
2808        int     $0x13
2809#if 0
2810        jnc     1f
2811        /* No EBIOS */
2812        movb    $0x02, (ebios_ext2 - 1 - Entry_ext2 + 0x7c00)
2813#else
2814        jc      1f              #; No EBIOS
2815
2816        //testb $1, %cl
2817        //jz    1f              #; No EBIOS
2818#if 0
2819        /* gcc-4.0.1 does not generate 2-byte code. */
2820        rcrb    $1, %cl         #; also can be rorb $1, %cl
2821#else
2822        .byte   0xD0, 0xD9      #; ror cl: D0 C9
2823#endif
2824        jnc     1f              #; No EBIOS
2825
2826        movb    $0x42, (ebios_ext2 - 1 - Entry_ext2 + 0x7c00)
2827#endif
28281:
2829        xorl    %eax, %eax      /* CF=0, ZF=1 */
2830
2831#if 0
2832        /* the INC touches ZF flag, so use MOV instead */
2833
2834        incw    %ax
2835        incw    %ax             /* EAX=2=inode number for root dir */
2836#else
2837
2838        /* MOV keeps all flags untouched, so it is better than INC */
2839
2840        movb    $2, %al         /* EAX=2=inode number for root dir */
2841#endif
2842
2843        /* CF=0, ZF=1 because MOV and PUSH do not touch Flags */
2844
2845        /* read root dir to 0000:1000, and grldr to 1000:0000 */
2846
28474:
2848        /* EAX holds the inode number: for root dir or grldr */
2849
2850        /* These 3 PUSHes is intended to place 1000:0000 onto the stack for
2851         * grldr. For root dir, the stack is not used since CF is cleared.
2852         * Although there is no corresponding POPs, this is safe enough
2853         * because the program comes here only twice: the first is for
2854         * the root dir, and the second is for grldr.
2855         *
2856         * For root dir, CF=0 and ZF=1. For grldr, CF=1.
2857         */
2858
2859        pushw   %di             /* 0x1000, see "jz 4b" below. */
2860        pushw   %ss             /* 0x0000 */
2861        pushfw
2862
2863        /* SP=0x7bf4 for root dir, or 0x7bee for grldr */
2864
2865        decl    %eax            /* EAX=(inode - 1) */
2866
2867        /* inode numbers are far less than 0x7fffffff, so it is safe to
2868         * initialise EDX with CDQ */
2869
2870        cdq                     /* let EDX=0 */
2871
2872        divl    0x28(%bp)       /* s_inodes_per_group */
2873                                /* EAX=group number */
2874        pushl   %edx            /* EDX=inode number in the group */
2875
2876        /* group numbers are far less than 0x7fffffff, so it is safe to
2877         * initialise EDX with CDQ */
2878
2879        cdq                     /* let EDX=0 */
2880        shll    $5, %eax        /* EAX=relative displacement of the group descriptor */
2881        divl    0x0e(%bp)       /* bytes per block */
2882                                /* EAX=relative block number for the group descriptor */
2883                                /* DX=displacement in the block */
2884                                /* EDX high=0 */
2885
2886        pushw   %dx             /* we don't care about EDX high word, because it is 0 */
2887
2888        addl    0x2c(%bp), %eax /* EAX=absolute block number for the group descriptor */
2889                                /* CF=0, ZF=0 */
2890
2891        call    read_block      /* 0000:1000 points to the block data containing the group descriptor */
2892                                /* ES changed and > 0, BX=0x1000 */
2893                                /* ECX=EDX=0 */
2894                                /* CF=0, ZF=0 */
2895
2896        popw    %si             /* DS:[BX+SI] points to the group descriptor */
2897                                /* DS:[BX+SI+8] points to the starting block number of the group inode table */
2898
2899        popl    %eax            /* inode number in the group */
2900//      shll    $7, %eax        /* inode struct size = 0x80 */
2901//                              /* EAX=relative displacement of the inode struct */
2902//                              /* EDX=0 */
2903        movw    0x26(%bp), %dx  /* EDX=inode size */
2904        mull    %edx            /* EDX:EAX=relative displacement of the inode struct */
2905
2906        divl    0x0e(%bp)       /* bytes per block */
2907                                /* EAX=relative block number for the inode struct */
2908        pushw   %dx             /* DX=displacement of the inode struct in the block */
2909                                /* EDX high=0 */
2910
2911        addl    8(%bx, %si), %eax       /* EAX=absolute block number for the inode struct */
2912                                        /* CF=0, ZF=0 */
2913
2914        call    read_block      /* 0000:1000 points to the block data containing the inode struct */
2915                                /* ES changed and > 0, BX=0x1000 */
2916                                /* ECX=EDX=0 */
2917                                /* CF=0, ZF=0 */
2918
2919        popw    %si             /* DS:[BX+SI] points to the inode struct */
2920
2921        addw    %bx, %si        /* DS:SI points to the inode struct */
2922
2923        /* Move the inode struct to a known safe area(0000:0fa8 - 0000:0fff),
2924         * that is, 0x58 bytes immediately before 0000:1000. We care about only
2925         * the beginning 0x58 bytes of the 0x80-byte inode struct, the last
2926         * 0x28 bytes are ignored. The area from 0xfa8+0x28 to 0xfa8+0x57
2927         * stores 12 direct block pointers.
2928         *
2929         *
2930         * At address   Initial value               Stores what?
2931         * ==========   =============   ======================================
2932         * 0xfa8+0x04      (const)           the size of the file in bytes
2933         *
2934         * 0xfa8+0x08    total blocks           blocks left to read
2935         *
2936         * 0xfa8+0x0c         0           serial number of the block to read
2937         *
2938         */
2939
2940        pushw   %ss
2941        popw    %es                             /* ES=0 */
2942
2943        leaw    -0x58(%bx), %di                 /* BX=0x1000, so DI=0x0fa8 */
2944        //movw  $0x0fa8, %di
2945        movb    $0x2c, %cl                      /* 0x2c words = 0x58 bytes */
2946
2947        repz movsw                              /* now ECX=0, BX=0x1000=DI */
2948
2949        movl    %ecx, (0x0c - 0x58)(%di)        /* block serial number of the file */
2950                                                /* ECX=0 means first block */
2951                                                /* DI=0x1000 */
2952
2953        movl    (0x04 - 0x58)(%di), %eax        /* i_size, the file size */
2954        decl    %eax
2955
2956        divl    0x0e(%bp)                       /* bytes per block */
2957                                                /* EDX=various */
2958        incl    %eax
2959        movl    %eax, (0x08 - 0x58)(%di)        /* total blocks for file data */
2960
2961        /*
2962         * 0000:1000    trebly indirect block
2963         * 0000:8000    indirect block
2964         * 0000:c000    double indirect block
2965         * 1000:0000    the file data
2966         */
2967
2968        /* now DS:SI points to indirect block number */
2969
2970        lodsl                                   /* indirect block number */
2971        testl   %eax, %eax
2972        jz      1f
2973
2974        //pushw %ss
2975        //popw  %es                             /* ES=0 */
2976        movb    $0x80, %bh                      /* ES:BX=0000:8000 */
2977#if 0
2978        stc
2979        call    read_block
2980#else
2981        call    read_block_c
2982#endif
2983                                                /* ES changed and > 0, BX=0x8000 */
2984                                                /* ECX=EDX=0 */
2985                                                /* ZF=0, CF=0 */
2986
2987        /* now DS:SI points to double indirect block number */
2988
2989        lodsl                                   /* double indirect block number */
2990        testl   %eax, %eax
2991        jz      1f
2992
2993#if 0
2994        pushw   %ss
2995        popw    %es                             /* ES=0 */
2996        movb    $0xc0, %bh                      /* ES:BX=0000:c000 */
2997        stc
2998        call    read_block
2999#else
3000        movb    $0xc0, %bh                      /* ES:BX=0000:c000 */
3001        call    read_block_c
3002#endif
3003                                                /* ES changed and > 0, BX=0xc000 */
3004                                                /* ECX=EDX=0 */
3005                                                /* ZF=0, CF=0 */
3006
3007        /* now DS:SI points to trebly indirect block number */
3008
3009        lodsl                                   /* trebly indirect block number */
3010        testl   %eax, %eax                      /* CF=0, TEST always clears CF */
3011        jz      1f
3012                                                /* ZF=0 */
3013        //pushw %ss
3014        //popw  %es                             /* ES=0 */
3015        //movb  $0x10, %bh                      /* ES:BX=0000:1000 */
3016        //stc
3017        call    read_block                      /* 0000:1000 points to the block data */
3018                                                /* ES changed and > 0, BX=0x1000 */
3019                                                /* ECX=EDX=0 */
3020                                                /* ZF=0, CF=0 */
3021
3022        /* the block at 0000:1000, which contains the indirect block numbers,
3023         * is just overwritten by the trebly indirect block */
3024
30251:
3026        /* get absolute block number by block serial number */
3027
3028        movl    (0x0c - 0x58)(%di), %ebx        /* block serial number of the file */
3029        subl    $12, %ebx
3030        jc      3f                              /* direct block: block serial number < 12 */
3031
3032        pushw   %bx
3033        subl    0x14(%bp), %ebx
3034        popw    %ax
3035        jnc     2f
3036
3037        /* indirect block: 12 <= block serial number < 12 + 0x14(%bp) */
3038
3039        //addw  0x14(%bp), %bx
3040        addb    $(0x70 / 4), %ah
3041        //xchgw %ax, %bx
3042        jmp     8f
3043
30442:
3045        pushl   %ebx
3046        subl    0x10(%bp), %ebx
3047        jc      7f              /* EBX on the stack is < 0x10(%bp). double indirect block:
3048                                 * 12 + 0x14(%bp) <= block serial number < 12 + 0x14(%bp) + 0x10(%bp)
3049                                 */
3050
3051        /* trebly indirect block: block serial number >= 12 + 0x14(%bp) + 0x10(%bp) */
3052
3053        popl    %eax            /* discard the stack */
3054        xchgl   %eax, %ebx      /* move EBX to EAX */
3055                                /* EDX=0 */
3056        divl    0x10(%bp)
3057                                /* EAX=indirect block number, < 0x14(%bp) */
3058                                /* EDX=block number, < 0x10(%bp) */
3059
3060        pushl   %edx            /* EDX < 0x10(%bp) */
3061        testl   %edx, %edx
3062        jnz     7f
3063
3064        /* EDX=0, so we need to load the double indirect block */
3065
3066        shlw    $2, %ax
3067        xchgw   %ax, %bx
3068
3069        /* get the double indirect block number from the trebly indirect
3070         * block data */
3071
3072        movl    (%bx, %di), %eax
3073
3074//6:
3075        movw    $0xc000, %bx                    /* ES:BX=0000:c000 */
3076
3077        //pushw %ss
3078        //popw  %es                             /* ES=0 */
3079        //stc
3080        call    read_block_c    /* 0000:c000 points to the block data */
3081                                /* ES changed and > 0, BX=0xc000 */
3082                                /* ECX=EDX=0 */
3083                                /* CF=0, ZF=0 */
30847:
3085        popl    %eax            /* EAX < 0x10(%bp) */
3086        cdq                     /* let EDX=0 (notice the above jc 7f and jnz 7f) */
3087        divl    0x14(%bp)
3088                                /* EAX=indirect block number, < 0x14(%bp) */
3089                                /* EDX=block number, < 0x14(%bp) */
3090
3091        pushw   %dx             /* EDX < 0x14(%bp) */
3092        testw   %dx, %dx
3093        jnz     7f
3094
3095        /* if DX=0, we need to load the indirect block */
3096
3097        //addb  $(0xb0 / 4), %ah
3098        shlw    $2, %ax
3099        xchgw   %ax, %bx
3100
3101        /* get the indirect block number from the double indirect block data */
3102
3103        movl    0xb000(%bx, %di), %eax
3104        //movl  (%bx, %di), %eax
3105//5:
3106        movw    $0x8000, %bx                    /* ES:BX=0000:8000 */
3107
3108        //pushw %ss
3109        //popw  %es                             /* ES=0 */
3110        //stc
3111        call    read_block_c    /* 0000:8000 points to the block data */
3112                                /* ES changed and > 0, BX=0x8000 */
3113                                /* ECX=EDX=0 */
3114                                /* CF=0, ZF=0 */
31157:
3116        popw    %ax             /* AX < 0x14(%bp) */
31178:
3118        xchgw   %ax, %bx
31193:
3120        shlw    $2, %bx
3121        movl    (%bx, %di), %eax
3122
3123        /* got it! EAX=absolute block number */
3124
3125        /* read block data to 1000:0000. For root dir, read each block to
3126         * 1000:0000(overwrite the previous read). For grldr, read blocks
3127         * one by one to the area starting at 1000:0000.
3128         */
3129
3130        popfw
3131        popw    %bx
3132        popw    %es
3133        pushfw
3134
3135        /* CF=0 and ZF=1 for reading root dir, CF=1 for reading grldr */
3136
3137        call    read_block      /* 1000:0000 points to the block data */
3138                                /* ES changed and > 0x1000, BX=0 */
3139                                /* ECX=EDX=0 */
3140                                /* CF=0, ZF=0 */
3141
3142        popfw
3143        pushw   %es
3144        pushw   %bx
3145        pushfw
3146
3147        jc      3f              /* CF=1, we are reading grldr */
3148
3149        /* We have just read a block of the root dir to 1000:0000.
3150         * So we check all dir entries in the block to see if anyone
3151         * matches grldr.
3152         */
3153
3154        xorw    %si, %si
3155        pushw   %ss
3156        popw    %es             /* ES=0 */
3157
31582:
3159        pushw   %ds             /* DS=0 */
3160        movw    %di, %ds        /* DS=0x1000 */
3161        movw    $(filename_ext2 - Entry_ext2 + 0x7c00), %di
3162
3163        pushw   %si
3164        lodsl                   /* This is possible inode number for grldr */
3165        pushl   %eax            /* This is possible inode number for grldr */
3166        lodsw
3167        xchgw   %ax, %dx        /* rec_len */
3168        lodsw                   /* AL=name_len, should be 5 for grldr */
3169                                /* AH=file_type(1 for regular file) */
3170#if 0
3171        cmpw    $0x0105, %ax
3172        jnz     5f
3173        movb    %al, %cl        /* CH is already 0 */
3174        repz cmpsb
3175#else
3176        decb    %ah
3177        //jnz   5f
3178        xchgw   %ax, %cx        /* CX=name_len */
3179        repz cmpsb
3180        jnz     5f
3181        xchgw   %ax, %cx        /* movb $0, %al */
3182        scasb
3183#endif
31845:
3185        popl    %eax            /* This is possible inode number for grldr */
3186        popw    %si
3187
3188        /* DS=0x1000, EAX=inode number */
3189
3190        movw    %ds, %di        /* DI=0x1000 */
3191        popw    %ds             /* DS=0 */
3192
3193        stc                     /* indicates the new inode is for grldr */
3194
3195        jz      4b              /* grldr is found with EAX=inode number */
3196
3197        addw    %dx, %si
3198        cmpw    0x0e(%bp), %si  /* bytes per block */
3199        jb      2b
3200
3201        /* file not found in this block, continue */
3202
3203        /* We are lucky that CF=0, which indicates we are dealing with
3204         * the root dir.
3205         */
3206
32073:
3208
3209        /* CF=1 for grldr, CF=0 for root dir. */
3210
3211        incl    (0x0c - 0x58)(%di)
3212        decl    (0x08 - 0x58)(%di)
3213        jnz     1b
3214
3215#if 0
3216        /* The above 2 instructions INC and DEC do not touch CF, so we
3217         * can omit this POP-PUSH pair.
3218         */
3219
3220        popfw
3221        pushfw
3222#endif
3223
3224        movw    $(msg_No_grldr_ext2 - Entry_ext2 + 0x7c00), %si
3225
3226        jnc     boot_error_ext2         /* grldr not found in the root dir */
3227
3228        /* All grldr blocks have been loaded to memory starting at 1000:0000,
3229         * Before the boot, we pass boot_drive and boot_partition to grldr.
3230         */
3231
3232        /* ES>0x1000, BX=0, ECX=EDX=0, DI=0x1000, SS=0, SI>0x7c00, DS=0
3233         * BP=0x7c00, SP<=0x7c00
3234         */
3235
3236        movw    0x24(%bp), %dx
3237
3238        /* boot it now! */
3239
3240        pushw   %di             /* 0x1000 */
3241        pushw   %ss             /* 0x0000 */
3242        lret
3243
3244read_block_c:
3245
3246        pushw   %ss
3247        popw    %es                             /* ES=0 */
3248        stc
3249
3250/* read_block - read a block
3251 * input:       CF        - indicator for overlap or consecution
3252 *              EAX       = block number
3253 *              ES:BX     - buffer
3254 *
3255 * output:      if CF is cleared on input, ES:BX is initialized to 0000:1000
3256 *              ES:BX     - buffer filled with data
3257 *              ES, EAX   - Changed
3258 *              ECX       = 0
3259 *              EDX       = 0
3260 *              ZF    = 0
3261 *              CF    = 0
3262 */
3263
3264read_block:
3265
3266        jc      1f
3267
3268        .byte   0xC4, 0x5E, 0xFC        /* lesw -4(%bp), %bx */
3269                                        /* ES:BX=0000:1000 */
3270        jnz     1f
3271
3272        //at this time, the gcc cannot generate 3 byte code
3273        .byte   0xC4, 0x5E, 0xFA        /* lesw -6(%bp), %bx */
3274                                        /* ES:BX=1000:0000 */
3275        //. = . - (. - read_block) / 6
32761:
3277        movzbl  0x0d(%bp), %ecx /* CX=sectors per block */
3278                                /* ECX high=0 */
3279        . = . - (. - 1b) / 6
3280        mull    %ecx            /* EAX=relative sector number */
3281                                /* EDX=0 */
3282        . = . - (. - 1b) / 9
3283        addl    0x1c(%bp), %eax /* EAX=absolute sector number */
3284
3285#if 1
3286        /* pass through, saving 4 bytes(call and ret) */
3287#else
3288        call    readDisk_ext2
3289        ret
3290#endif
3291
3292/* Read sectors from disk, using LBA or CHS
3293 * input:       EAX   = 32-bit LBA sector number
3294 *              CX    = number of sectors to read
3295 *              ECX high word  = 0
3296 *              ES:BX = destination buffer
3297 *
3298 * output:      No return on error
3299 *              BX not changed
3300 *              ES    = ES + 0x20 * CX
3301 *              EAX   = EAX + CX
3302 *              ZF    = 0
3303 *              CF    = 0
3304 */
3305
3306readDisk_ext2:
33072:
3308        pushal
3309        //xorl  %edx, %edx      /* EDX:EAX = LBA */
3310        pushl   %edx            /* hi 32bit of sector number */
3311        pushl   %eax            /* lo 32bit of sector number */
3312        pushw   %es             /* buffer segment */
3313        pushw   %bx             /* buffer offset */
3314        pushw   $1              /* 1 sector to read */
3315        pushw   $16             /* size of this parameter block */
3316
3317        //xorl  %ecx, %ecx
3318        pushl   0x18(%bp)       /* lo:sectors per track, hi:number of heads */
3319        popw    %cx             /* ECX = sectors per track */
3320        divl    %ecx            /* residue is in EDX */
3321                                /* quotient is in EAX */
3322                                /* EDX high=0, DH=0 */
3323        incw    %dx             /* DL=sector number */
3324        popw    %cx             /* ECX = number of heads */
3325        pushw   %dx             /* push sector number into stack */
3326        xorw    %dx, %dx        /* EDX:EAX = cylinder * TotalHeads + head */
3327        divl    %ecx            /* residue is in EDX, head number */
3328                                /* quotient is in EAX, cylinder number */
3329                                /* EDX high=0, EAX high=0 */
3330
3331
3332        xchgb   %dl, %dh        /* head number should be in DH */
3333                                /* DL = 0 */
3334        popw    %cx             /* pop sector number from stack */
3335        xchgb   %al, %ch        /* lo 8bit cylinder should be in CH */
3336                                /* AL = 0 */
3337        shlb    $6, %ah         /* hi 2bit cylinder ... */
3338        orb     %ah, %cl        /* ... should be in CL */
3339
3340        incw    %ax             /* AL=1, read 1 sector */
3341
3342        /* Instead of 0x0e, the LBA indicator at 2(%bp) is
3343         *
3344         *      0x42 for LBA
3345         *
3346         * and
3347         *
3348         *      0x02 for CHS
3349         */
3350#if 0
3351        movb    $0x42, %ah
3352        /* ebios_ext2 - 1 points to 0x42 that can be changed to 0x02 */
3353#else
3354        movb    $0x02, %ah
3355        /* ebios_ext2 - 1 points to 0x02 that can be changed to 0x42 */
3356#endif
3357ebios_ext2:
3358
3359        //andb  2(%bp), %ah
3360
3361        movw    %sp, %si        /* DS:SI points to disk address packet */
3362        movb    0x24(%bp), %dl  /* drive number */
3363        int     $0x13
3364        jc      disk_error_ext2
3365        movw    %es, %ax
3366        addw    $0x20, %ax      /* here, carry is cleared */
3367        movw    %ax, %es
3368        popaw                   /* remove parameter block from stack */
3369        popal
3370        incl    %eax            /* next sector, here ZF=0 */
3371        loop    2b
3372        ret
3373
3374        //. = . - (. - readDisk_ext2)/74
3375
3376//msg_DiskReadError_ext2:
3377//
3378//      .ascii  "disk error\0"
3379
3380msg_No_grldr_ext2:
3381
3382        .ascii  "No "
3383
3384filename_ext2:
3385#ifdef  BOOTGRUB2
3386        .ascii  "g2ldr\0"
3387#else
3388        .ascii  "grldr\0"
3389#endif
3390        . = Entry_ext2 + 0x1ee
3391
3392filename_end_ext2:
3393
3394        .word (filename_ext2 - Entry_ext2)+(filename_end_ext2 - filename_ext2 - 1)*2048
3395
3396        . = Entry_ext2 + 0x1f0
3397
3398disk_error_ext2:
3399
3400        movw    $(msg_DiskReadError_ext2 - Entry_ext2 + 0x7c00), %si
3401
3402boot_error_ext2:
3403
3404/* prints string DS:SI (modifies AX BX SI) */
3405
3406//print_ext2:
34071:
3408        lodsb   (%si), %al      /* get token */
3409        //xorw  %bx, %bx        /* video page 0 */
3410        movb    $0x0e, %ah      /* print it */
3411        int     $0x10           /* via TTY mode */
3412        cmpb    $0, %al         /* end of string? */
3413        jne     1b              /* until done */
3414#if 1
3415
3416        /* The caller will change this to
3417         *      ljmp    $0x9400, $(try_next_partition - _start1)
3418         */
3419
34201:      jmp     1b
3421
3422#else
3423        /* boot failed, try to hand over the control to supervisor */
3424        ldsw    (1f + 3 - Entry_ext2)(%bp), %si
3425        lodsl
3426        cmpl    $0x9400b8fa, %eax
34271:      jnz     1b      /* no supervisor, hang up. */
3428        ljmp    $0x9400, $(try_next_partition - _start1)
3429
3430        //. = . - (. - disk_error_ext2) / 30
3431#endif
3432
3433        . = Entry_ext2 + 0x1fe
3434
3435        .word   0xAA55
3436
3437        . = _start1 + 0xA00
3438
3439#define INSIDE_GRLDR
3440
3441#include "ntfsbs.S"
3442
3443        . = _start1 + 0x1200
3444
3445        .arch   i586, jumps
3446
3447#ifdef DEBUG
3448
3449        . = Entry_ext2 + 0x201
3450
3451debug_print:
3452
3453        pushfl
3454        pushal
3455        movl    %eax, %ebp
3456        call    2f
3457#if 0
3458        popal
3459        pushal
3460        movl    %ebx, %ebp
3461        call    2f
3462        popal
3463        pushal
3464        movl    %ecx, %ebp
3465        call    2f
3466        popal
3467        pushal
3468        movl    %edx, %ebp
3469        call    2f
3470        popal
3471        pushal
3472        movl    %esi, %ebp
3473        call    2f
3474        popal
3475        pushal
3476        movl    %edi, %ebp
3477        call    2f
3478        popal
3479        popfl
3480        pushfl
3481        pushal
3482        pushfl
3483        popl    %ebp            /* flags */
3484        call    2f
3485        movw    %ds, %bp
3486        shll    $16, %ebp
3487        movw    %es, %bp
3488        call    2f
3489        movw    $0x0e0d, %ax    /* print CR */
3490        int     $0x10           /* via TTY mode */
3491        movw    $0x0e0a, %ax    /* print LF */
3492        int     $0x10           /* via TTY mode */
3493#endif
3494        popal
3495        popfl
3496        ret
34972:
3498        movw    $7, %cx
34991:
3500        xorw    %bx, %bx        /* video page 0 */
3501        movl    %ebp, %eax
3502        shrl    %cl, %eax
3503        shrl    %cl, %eax
3504        shrl    %cl, %eax
3505        shrl    %cl, %eax
3506        andb    $0x0f, %al
3507        addb    $0x30, %al
3508        movb    $0x0e, %ah      /* print char in AL */
3509        int     $0x10           /* via TTY mode */
3510
3511        decw    %cx
3512        testw   %cx, %cx
3513        jns     1b
3514
3515        movw    $0x0e20, %ax    /* print space */
3516        int     $0x10           /* via TTY mode */
3517        ret
3518#endif
3519
3520#if 1
3521        /* restore GRLDR_CS */
3522
3523        /* this code is executed at 0000:MONITOR, which must be a 16-byte
3524         * aligned address. The address 0000:MONITOR should be designed in
3525         * a way that could avoid memory confliction with volume boot records
3526         * (currently FAT12/16/32/NTFS/EXT2/3 are built in).
3527         */
3528
3529        /* CS=code */
3530
3531        .align 16
3532
3533restore_GRLDR_CS:
35342:
3535        call    1f
35361:
3537        popw    %bx             # instruction pointer of 1b
3538        movw    %cs, %ax
3539        shrw    $4, %bx
3540        addw    %ax, %bx        # BX=segment value of this code
3541        pushw   %bx
3542        pushw   $(1f - 2b)
3543        lret
35441:
3545        /* modify gdt base */
3546        xorl    %eax, %eax
3547        movw    %bx, %ax
3548        shll    $4, %eax
3549        addl    $(gdt -2b), %eax
3550        movl    %eax, %cs:(gdt - 2b + 2)
3551
3552        movw    $GRLDR_CS, %bx
3553        movw    %bx, %es
3554        movw    %ds, %bx        # save old DS to BX
3555
3556        cli
3557        lgdt    %cs:(gdt - 2b)
3558        movl    %cr0, %eax
3559        orb     $1, %al
3560        movl    %eax, %cr0
3561
3562        movw    $8, %si
3563        movw    %si, %ds
3564
3565        xorl    %esi, %esi
3566        xorl    %edi, %edi
3567        movl    $(0x9000 / 4), %ecx
3568
3569        cld
3570        repz movsl
3571
3572        movw    $16, %si
3573        movw    %si, %ds
3574
3575        andb    $0xfe, %al
3576        movl    %eax, %cr0
3577
3578        movw    %bx, %ds        # restore DS from BX
3579
3580        ljmp    $GRLDR_CS, $(try_next_partition - _start1)
3581
3582#endif
3583
3584# Descriptor tables
3585#
3586# NOTE: The intel manual says gdt should be sixteen bytes aligned for
3587# efficiency reasons.  However, there are machines which are known not
3588# to boot with misaligned GDTs, so alter this at your peril!  If you alter
3589# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
3590# empty GDT entries (one for NULL and one reserved).
3591#
3592# NOTE: On some CPUs, the GDT must be 8 byte aligned.  This is
3593# true for the Voyager Quad CPU card which will not boot without
3594# This directive.  16 byte aligment is recommended by intel.
3595#
3596        .align 16
3597gdt:
3598        /* this is the default null entry in GDT */
3599        .word   gdt_end - gdt - 1               # gdt limit
3600        .long   (GRLDR_CS * 16 + gdt - _start1) # linear address of gdt
3601        .word   0                               # pad 2 bytes
3602
3603        /* real mode data segment base=0x200000 */
3604        .word   0xFFFF, 0
3605        .byte   0x20, 0x92, 0, 0
3606
3607        /* real mode data segment base=0 */
3608        .word   0xFFFF, 0
3609        .byte   0, 0x92, 0, 0
3610
3611gdt_end:
3612
3613helper_start:
3614
3615        /* helper function begins here
3616         * before the call:
3617         *      CF=1            : indicates an invalid or corrupt entry
3618         *      CF=0            : indicates a valid entry
3619         *
3620         * on return:
3621         *      CF=1            : means "below", try next entry
3622         *      CF=0,ZF=1       : means "equal", helper did nothing, so we need
3623         *                        a further try to boot via NT bootsector
3624         *      CF=0,ZF=0       : means "above", helper succeeded, boot it now
3625         */
3626
3627        sti
3628
3629        /* DS=SS=0x9400 */
3630        pushw   %cs
3631        popw    %ds
3632
3633        pushw   $FS_BOOT
3634        popw    %es
3635
3636        /* ES=FS_BOOT */
3637
3638        /* Format of partition information blocks.
3639         *
3640         * Offset   Length in bytes     Field
3641         *  00h         1               Set to 80h if this partition is active.
3642         *  01h         1               Partition's starting head.
3643         *  02h         2               Partition's starting sector and track.
3644         *  04h(SI)     1               Partition's ID number.
3645         *  05h         1               Partition's ending head.
3646         *  06h         2               Partition's ending sector and track.
3647         *  08h         4               Starting LBA.
3648         *  0Ch         4               Partition's length in sectors.
3649         */
3650
3651        pushw   %ds             /* DS=0x9400 */
3652        pushw   %es             /* ES=FS_BOOT */
3653        pushal
3654        pushfw
3655
3656        //pushw %si
3657        //stc
3658        //jc    invalid_or_null         /* invalid or null entry */
3659#if 0
3660        /* backup 63 sectors at FS_BOOT:0 to 63 sectors at FS_BOOT:8000
3661         * this piece of code is no longer useful.
3662         */
3663        pushw   %es
3664        popw    %ds
3665        xorw    %si, %si
3666        movw    $0x8000, %di
3667        movw    $0x3f00, %cx
3668        cld
3669        repz movsw
3670#endif
3671
3672#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
3673        testb   $0x80, %cs:0x02 /* boot previous MBR first? */
3674        jnz     2f              /* no, continue to find GRLDR */
3675
3676        /* yes, call the routine for booting the previous MBR.
3677         * it will not return on success.
3678         * on failure, it will return here
3679         */
3680
3681        /* before we call the routine, we will check if the user want to
3682         * skip this step and continue to find the GRLDR
3683         */
3684#if 0
3685        movw    $(press_space_bar_string - _start1), %si
3686        cmpw    $0x3920, %cs:0x04
3687        je      1f
3688        movw    $(press_hot_key_string - _start1), %si
36891:
3690        /* if timeout==0, don't display the message */
3691
3692        cmpb    $0, %cs:0x03
3693        je      1f
3694        call    print_message   /* CS:SI points to message string */
3695        movw    $(press_any_key_string - _start1), %si
3696        call    print_message   /* CS:SI points to message string */
3697#else
3698        cmpb    $0, %cs:0x03
3699        je      1f
3700        movw    $(press_hot_key_pre - _start1), %si
3701        call    print_message
3702        movw    $(press_hot_key_name - _start1), %si
3703        call    print_message
3704        movw    $(press_hot_key_sub - _start1), %si
3705        call    print_message
3706#endif
37071:
3708        call    sleep_5_seconds
3709        jc      1f              /* desired hot-key pressed */
3710        call    boot_prev_mbr   //Error_modify
37111:
3712        orb     $0x80, %cs:0x02
37132:
3714#endif
3715        popfw
3716        popal
3717        popw    %es
3718        popw    %ds
3719
3720        pushw   %ds             /* DS=0x9400 */
3721        pushw   %es             /* ES=FS_BOOT */
3722        pushal
3723        pushfw
3724
3725        //cmpb  $0x0e, 0x00     /* EBIOS previously checked OK? */
3726        //jbe   1f              /* yes, skip the check */
3727        movb    $0x02, 0x00     /* initialise this byte to 0x02 */
3728        movb    $0x41, %ah      /* EBIOS check existence */
3729        movw    $0x55aa, %bx
3730        int     $0x13
3731        jc      1f              /* No EBIOS */
3732        cmpw    $0xaa55, %bx
3733        jnz     1f              /* No EBIOS */
3734        testb   $1, %cl
3735        jz      1f              /* No EBIOS */
3736        movb    $0x42, 0x00     /* LBA supported, save 0x42 to 9400:0000 */
37371:
3738        popfw
3739        popal
3740        popw    %es
3741        popw    %ds
3742
3743        pushw   %ds             /* DS=0x9400 */
3744        pushw   %es             /* ES=FS_BOOT */
3745        pushal
3746        pushfw
3747
3748        pushaw
3749        cmpw    $0x1c2, %si
3750        jne     1f
3751        /* initialize partition number and partition entries end */
3752        movw    $0xffff, 0x1bc          /* hd partition number */
3753        movw    $0x01fe, 0x1ba          /* partition entries end */
37541:
3755        pushw   %dx
3756        testb   %dl, %dl
3757        jns     1f                      /* floppy, use normal CHS mode */
3758        cmpw    $0x1f2, %si             /* is it a primary partition? */
3759        ja      2f                      /* no, it is an extended partition */
3760        movl    4(%si), %eax
3761        movl    %eax, 8(%si)            /* parent part_start saved here */
3762        xorl    %eax, %eax
3763        movl    %eax, 4(%si)            /* current part_start(0) saved here */
37642:
3765        //movl  -4(%si), %eax
3766        //cmpl  $0xfffffe00, %eax       /* check the starting CHS */
3767        //jb    1f                      /* use normal CHS mode */
3768
3769        /* get CHS total number of sectors */
3770        pushw   %es
3771        pushw   %ds
3772        movb    $8, %ah         /* read drive parameters changes DX,ES,DI */
3773        //movb  $0x80, %dl      /* BIOS drive number is in DL */
3774        int     $0x13
3775        popw    %ds
3776        popw    %es
3777        jc      3f
3778        testb   $63, %cl
3779        jnz     2f
37803:
3781        /* failed to get drive parameters, use maximum value */
3782#if 0
3783        popw    %dx
3784        pushw   %dx
3785        cmpb    $0x80, %dl
3786        jne     3f
3787        pushw   %ds
3788        xorw    %ax, %ax
3789        movw    %ax, %ds
3790        cmpb    $0, 0x475
3791        popw    %ds
3792        je      3f
3793
37943:
3795#endif
3796        movw    $0xffff, %cx
3797        movw    %cx, %dx
37982:
3799        //xorl  %eax, %eax
3800        movzbl  %dh, %eax
3801        incw    %ax
3802        movzbl  %cl, %edx
3803        andb    $63, %dl
3804        mulw    %dx             /* DX=0, AX=product */
3805        shrb    $6, %cl
3806        xchgb   %cl, %dh
3807        xchgb   %ch, %dl
3808        incw    %dx             /* DX=total cylinders */
3809        mull    %edx            /* EDX=0, EAX=product */
3810
3811        /* check the partition's starting LBA */
3812        movl    4(%si), %ebx
3813        addl    8(%si), %ebx    /* EBX=start_LBA */
3814
3815        testl   %ebx, %ebx
3816        je      1f
3817
3818        ///* we always use LBA mode */
3819        ////cmpl        %eax, %ebx
3820        ////jb  1f              /* use normal CHS mode */
3821        cmpb    $0x42, 0x00     /* EBIOS present? */
3822        jne     1f              /* no, skip the LBA mode int13 call */
3823
3824        /* load partition boot track to FS_BOOT using LBA mode */
3825        popw    %ax             /* AX=orig DX which holds drive number DL */
3826        pushw   %ax
3827        pushl   %edx            /* EDX=0, higher 4 bytes of starting LBA */
3828        pushl   %ebx            /* lower 4 bytes of starting LBA */
3829        pushw   %es             /* ES=FS_BOOT */
3830        pushw   %dx             /* DX=0, ES:0 is the buffer */
3831        //pushl $0x003f0010     /* transfer 63 sectors */
3832        pushw   $0x3f           /* transfer 63 sectors */
3833        pushw   $0x10           /* size of disk address packet */
3834        xchgw   %ax, %dx        /* restore drive number DL from AL */
3835        movb    $0x42, %ah      /* extended read */
3836        movw    %sp, %si        /* DS:SI points to disk address packet */
3837        int     $0x13           /* ignore the read failure */
3838        popaw                   /* adjust the stack */
3839        jc      1f
3840        popw    %dx
3841        popaw
3842
3843        //popw  %ax             /* discard flags in the stack */
3844        popfw
3845        clc
3846
3847        pushfw                  /* push new flags with CF=0 */
3848        pushaw
3849        pushw   %dx
38501:
3851        popw    %dx
3852        popaw
3853
3854        popfw
3855        popal
3856        popw    %es
3857        popw    %ds
3858
3859        pushw   %ds             /* DS=0x9400 */
3860        pushw   %es             /* ES=FS_BOOT */
3861        pushal
3862        pushfw
3863
3864        pushw   %si
3865
3866        pushfw
3867        pushw   %es
3868//---------------------------------------------------------
3869        /* print "Try (hd0,n): " or "Try (fd0): "*/
3870        pushw   %ds
3871        popw    %es             /* ES=DS=CS=0x9400 */
3872
3873        cld                     /* for stosb */
3874        xorw    %ax, %ax
3875        testb   %dl, %dl
3876        jns     1f              /* floppy */
3877        /* hard drive */
3878#if 0
3879        movw    %si, %ax
3880        subw    $0x1c2, %ax
3881        shrw    $4, %ax
3882        cmpw    $0x1fe, %si     /* is in MBR? */
3883        jb      1f              /* yes */
3884        /* no, it is an entry in an extended partition */
3885        movb    $0xFC, (add_sub_si + 2 - _start1)       /* addw $-4, %si */
3886        incw    0x1bc           /* logical partition number */
3887        movb    0x1bc, %al
3888#else
3889        incw    0x1bc           /* logical partition number */
3890        movw    0x1bc, %ax
3891        cmpb    $4, %al
3892        jb      1f
3893        movb    $0xFC, (add_sub_si + 2 - _start1)       /* addw $-4, %si */
3894#endif
38951:
3896        /* AL=partition number, AH=0 */
3897        pushw   %ax
3898
3899        movw    $(partition_message - _start1 + 7), %di /* drive type */
3900        movb    %dl, %al
3901        shrb    $7, %al         /* drive type: floppy=0, harddrive=1 */
3902        shlb    $1, %al
3903        addw    $0x6466, %ax    /* "fd" or "hd" */
3904        stosw
3905        movb    %dl, %al
3906        andb    $0x7f, %al      /* drive number */
3907        aam             /* convert binary to decimal, AH=high, AL=low */
3908        testb   %ah, %ah
3909        jz      1f
3910        addb    $0x30, %ah
3911        movb    %ah, (%di)
3912        incw    %di
39131:
3914        addb    $0x30, %al
3915        stosb
3916
3917        popw    %ax
3918
3919        testb   %dl, %dl
3920        jns     2f              /* floppy */
3921        /* this is a hard drive, the partition number is in AL */
3922        movb    $0x2c, (%di)    /* "," */
3923        incw    %di
3924        aam             /* convert binary to decimal, AH=high, AL=low */
3925        testb   %ah, %ah
3926        jz      1f
3927        addb    $0x30, %ah
3928        movb    %ah, (%di)
3929        incw    %di
39301:
3931        addb    $0x30, %al
3932        stosb
39332:
3934        movl    $0x00203a29, (%di)      /* "): \0" */
3935
3936        movw    $(partition_message - _start1), %si
3937        call    print_message   /* CS:SI points to message string */
3938//---------------------------------------------------------
3939        popw    %es
3940        popfw
3941        //stc
3942        jc      invalid_or_null         /* invalid or null entry */
3943
3944        xorw    %si, %si
3945        pushw   %es
3946        popw    %ds
3947
3948        /* DS=ES=FS_BOOT */
3949
3950        /* First, check for ext2 filesystem */
3951
3952        cmpw    $0xEF53, 0x438          /* Magic signature */
3953        jnz     1f
3954        xorl    %eax, %eax
3955        cmpl    %eax, 0x400             /* s_inodes_count */
3956        jz      1f
3957        cmpl    %eax, 0x404             /* s_blocks_count */
3958        jz      1f
3959//      cmpw    %ax, 0x458              /* s_inode_size, usually 0x80 */
3960//      jz      1f
3961        cmpl    %eax, 0x420             /* s_blocks_per_group */
3962        jz      1f
3963        cmpl    %eax, 0x428             /* s_inodes_per_group */
3964        jz      1f
3965        movl    0x414, %eax             /* s_first_data_block */
3966        movw    %ax, %bx                /* BX=1 for 1K block, 0 otherwise */
3967        shrl    $1, %eax                /* must be 0 */
3968        jnz     1f
3969        movl    0x418, %ecx             /* s_log_block_size */
3970        cmpl    $4, %ecx                /* max size of block is 16K */
3971        ja      1f
3972        negw    %cx                     /* CF=0 for 1K block, CF=1 otherwise */
3973        adcw    %ax, %bx                /* EAX=0 */
3974        decw    %bx
3975        jnz     1f
3976
3977        /* BX = 0 */
3978        /* EAX= 0 */
3979
3980        movw    $0x80, %ax              /* EXT2_GOOD_OLD_INODE_SIZE */
3981        movw    %ax, %cs:0x826          /* inode size */
3982        movl    0x44C, %ecx             /* ECX=s_rev_level */
3983        jecxz   3f                      /* EXT2_GOOD_OLD_REV */
3984        movw    0x458, %ax              /* AX=s_inode_size */
3985        testw   %ax, %ax
3986        jz      1f                      /* invalid inode size */
3987        pushw   %ax
3988        pushw   %dx
3989        movb    0x418, %cl              /* s_log_block_size */
3990        addb    $10, %cl
3991        xorw    %dx, %dx                /* DX=0 */
3992        incw    %dx                     /* DX=1 */
3993        shlw    %cl, %dx                /* DX=block size in bytes */
3994        xchgw   %ax, %cx                /* CX=s_inode_size */
3995        xchgw   %ax, %dx                /* AX=block size in bytes */
3996        xorw    %dx, %dx                /* DX:AX=block size in bytes */
3997        divw    %cx                     /* quo=AX, rem=DX */
3998        testw   %dx, %dx
3999        popw    %dx
4000        popw    %ax
4001        jnz     1f                      /* invalid inode size */
4002        movw    %ax, %cs:0x826          /* inode size */
40033:
4004        /* BX = 0 */
4005
4006        /* super block is sane */
4007
4008        //pushw %cs
4009        //popw  %ds
4010        ///* DS=SS=0x9400 */
4011        ///* ES=FS_BOOT */
4012        cld
4013        movw    $0x800, %si
4014        xorw    %di, %di
4015        movw    $0x0200, %cx    /* yes, we need 2 sectors if enable debug */
4016
4017        repz cs movsw           /* CS segment override prefix(=0x2E) */
4018
4019        /* modify the boot partition number */
4020
4021        /* the boot partition number is at offset 0x25 for ext2 */
4022
4023        testb   %dl, %dl
4024        jns     3f                      /* no modification for floppy */
4025        movw    $0x25, %di
4026        movw    %cs:0x1bc, %ax          /* partition number */
4027        stosb
40283:
4029        /* fix for ext2 partition: hidden_sectors, offset 0x1c */
4030        popw    %si                     /* DI points to old entry in MBR */
4031        pushw   %si
4032        xorl    %eax, %eax              /* let hidden_sectors=0 for floppy */
4033        testb   %dl, %dl
4034        jns     3f                      /* floppy */
4035        movl    %cs:4(%si), %eax
4036        addl    %cs:8(%si), %eax
40373:
4038        /* BX = 0 */
4039
4040        movl    %eax, %es:0x1c(%bx)     /* adjust hidden_sectors for EXT2 */
4041
4042        /* fix for ext2 partition: EBIOS indicator, offset 0x02 */
4043
4044        movb    %cs:0x00(%bx), %al
4045        movb    %al, %es:0x02(%bx)
4046
4047        /* fix for ext2 partition: sectors per block, offset 0x0d */
4048        /* fix for ext2 partition: bytes per block, offset 0x0e */
4049        /* fix for ext2 partition: dwords per block(dpb), offset 0x14 */
4050        /* fix for ext2 partition: square of dpb, offset 0x10 */
4051
4052        movb    %es:0x418, %cl          /* s_log_block_size */
4053        //incw  %cx
4054        movl    $2, %eax
4055        shlw    %cl, %ax
4056        movb    %al, %es:0x0d(%bx)
4057        shlw    $9, %ax                 /* block size is word wide */
4058        movw    %ax, %es:0x0e(%bx)
4059        shrw    $2, %ax
4060        movl    %eax, %es:0x14(%bx)
4061        addb    $8, %cl
4062        shll    %cl, %eax
4063        movl    %eax, %es:0x10(%bx)
4064
4065
4066        /* fix for ext2 partition: sectors per track, offset 0x18 */
4067        /* fix for ext2 partition: number of heads, offset 0x1a */
4068#if 1
4069        pushw   %ds
4070        pushw   %es
4071        pushw   %bx
4072        pushw   %dx
4073        movb    $8, %ah         /* read drive parameters changes DX,ES,DI,BX */
4074        movb    $0x80, %dl      /* BIOS drive number is in DL */
4075        int     $0x13
4076        movw    %dx, %ax
4077        popw    %dx
4078        popw    %bx
4079        popw    %es
4080        popw    %ds
4081        jc      3f
4082        andb    $63, %cl
4083        jz      3f
4084        movb    %cl, %es:0x18(%bx)
4085        shrw    $8, %ax
4086        incw    %ax
4087        movw    %ax, %es:0x1a(%bx)
40883:
4089#else
4090        testb   %dl, %dl
4091        jns     3f                      /* floppy */
4092        popw    %di                     /* DI points to old entry in MBR */
4093        pushw   %di
4094        movw    %cs:1(%di), %ax
4095        andb    $63, %ah
4096        movb    %ah, %es:0x18
4097        xorb    %ah, %ah
4098        incw    %ax
4099        movw    %ax, %es:0x1a
41003:
4101#endif
4102
4103        /* fix for ext2 partition: s_inodes_per_group, offset 0x28 */
4104        movl    %es:0x428, %eax         /* s_inodes_per_group */
4105        movl    %eax, %es:0x28(%bx)
4106
4107        /* fix for ext2 partition: block number for group descriptors, offset 0x2c */
4108        /* At which block the group descriptors begin? */
4109        movl    %es:0x414, %eax         /* s_first_data_block */
4110        incw    %ax
4111        movl    %eax, %es:0x2c(%bx)
4112
4113        /* fix for ext2 partition: on error go back to supervisor, offset 0x01fc */
4114        movw    $0x01fc, %si
4115        movw    %si, %di
4116        lodsw
4117        cmpw    $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
4118        jnz     3f
4119        decw    %ax             /* AL=0xEA, ljmp */
4120        stosb
4121        //movw  $(try_next_partition - _start1), %ax
4122        movw    $MONITOR, %ax
4123        stosw
4124        //movw  %cs, %ax        /* AX=0x9400 */
4125        xorw    %ax, %ax
4126        stosw                   /* the last byte 0x00 is in the next sector! */
4127//      addw    $0x0f, %di
4128//      movw    $(restore_GRLDR_CS - _start1), %si
4129//      movw    $((gdt_end - restore_GRLDR_CS) / 4), %cx
4130//      .byte   0x2e            /* %cs: prefix */
4131//      repz movsl
41323:
4133
4134        movw    $(EXT2_message - _start1), %si
4135        call    print_message   /* CS:SI points to message string */
4136
4137        clc
4138        jmp     move_entries_and_return
4139
41401:
4141        #; It is not EXT2. Check for FAT12/16/32/NTFS.
4142
4143        /* DS=ES=FS_BOOT */
4144
4145        cmpw    $0x200, 0x0b(%si)       /* bytes per sector */
4146        jne     1f                      /* not a normal BPB */
4147        movb    0x0d(%si), %al          /* sectors per cluster */
4148        testb   %al, %al
4149        jz      1f                      /* invalid if = 0 */
4150        movb    %al, %cl
4151        movw    $128, %ax
4152        divb    %cl                     /* quo=AL, rem=AH */
4153        testb   %ah, %ah
4154        jnz     1f                      /* invalid if not 2^n */
4155        movw    0x18(%si), %ax          /* sectors per track */
4156        testw   %ax, %ax
4157        jz      1f                      /* invalid if = 0 */
4158        cmpw    $63, %ax
4159        ja      1f                      /* invalid if > 63 */
4160        movw    0x1a(%si), %ax          /* number of heads */
4161        decw    %ax                     /* Max head number, should be a byte */
4162        testb   %ah, %ah                /* should be 0 */
4163        jnz     1f                      /* invalid if number of heads > 256 */
4164        cmpb    $0xf0, 0x15(%si)        /* media descriptor */
4165        jb      1f
4166
4167        cmpb    $0x42, %cs:0x00         /* EBIOS present? */
4168        jne     3f
4169        //movb  $0x41, %ah              /* EBIOS check existence */
4170        //movw  $0x55aa, %bx
4171        //int   $0x13
4172        //jc    3f                      /* No EBIOS */
4173        //cmpw  $0xaa55, %bx
4174        //jnz   3f                      /* No EBIOS */
4175        //testb $1, %cl
4176        //jz    3f                      /* No EBIOS */
4177        movb    $0x0e, 0x02(%si)        /* force LBA */
41783:
4179        cld
4180        movw    $0x0600, %bx            /* FAT12/FAT16 */
4181        movw    $0x003c, %cx            /* FAT12/FAT16 */
4182
4183        movb    0x10(%si), %al          /* number of FATs(NTFS:0, FAT:1,2) */
4184        cmpb    $2, %al
4185        ja      1f                      /* abnormal FAT */
4186        movw    0x11(%si), %ax          /* max root entries */
4187        testw   %ax, %ax
4188        jnz     2f                      /* FAT12/FAT16 */
4189
4190        /* FAT32 or NTFS */
4191        movw    0x13(%si), %ax          /* total sectors(small) */
4192        testw   %ax, %ax
4193        jnz     1f                      /* invalid FAT32 BPB */
4194        movw    0x16(%si), %ax          /* sectors per FAT(small) */
4195        testw   %ax, %ax
4196        jnz     1f                      /* invalid FAT32 BPB */
4197        movb    0x10(%si), %al          /* number of FATs(NTFS:0, FAT:1,2) */
4198        testb   %al, %al
4199        jz      8f
4200
4201        /* FAT32 */
4202        movl    0x20(%si), %eax         /* FAT32 total sectors */
4203        testl   %eax, %eax
4204        jz      1f
4205        movl    0x24(%si), %eax         /* FAT32 sectors per FAT */
4206        testl   %eax, %eax
4207        jz      1f
4208        movw    $0x0400, %bx            /* FAT32 */
4209        movw    $0x0058, %cx            /* FAT32 */
4210        movw    $(FAT32_message - _start1), %si
4211        jmp     7f
42128:
4213        /* NTFS */
4214        movl    0x20(%si), %eax         /* FAT32 total sectors */
4215        testl   %eax, %eax
4216        jnz     1f
4217        //movw  0x11(%si), %ax          /* max root entries */
4218        //testw %ax, %ax
4219        //jnz   1f
4220        movw    0x0e(%si), %ax          /* reserved sectors */
4221        testw   %ax, %ax
4222        jnz     1f
4223
4224        /* BUG fix for extended NTFS partition */
4225        popw    %si                     /* SI points to old entry in MBR */
4226        pushw   %si
4227        xorl    %eax, %eax              /* let hidden_sectors=0 for floppy */
4228        testb   %dl, %dl
4229        jns     3f                      /* floppy */
4230        movl    %cs:4(%si), %eax
4231        addl    %cs:8(%si), %eax
42323:
4233        movl    %eax, 0x1c              /* adjust hidden_sectors for NTFS */
4234
4235        movb    %dl, 0x24               /* adjust drive number for NTFS */
4236
4237#if 1
4238        // Load NTFS using internal boot sector at 0xA00
4239
4240        movw    $(NTFS5_message - _start1), %si
4241        call    print_message   /* CS:SI points to message string */
4242
4243        movw    $0xA00, %bx
4244        movw    $0x52, %cx
4245
4246        pushw   %cs
4247        popw    %ds
4248
4249        /* DS=SS=0x9400 */
4250        /* ES=FS_BOOT */
4251
4252        movw    %bx, %si
4253        xorw    %di, %di
4254        lodsw
4255        stosw
4256        addw    %cx, %si
4257        addw    %cx, %di
4258        movw    $0x800, %cx
4259        subw    %di, %cx
4260
4261        repz movsb
4262
4263        /* modify the boot partition number */
4264        movb    %es:1, %al
4265        addb    $5, %al                 /* AL is less than 0x80 */
4266        cbw                             /* AH=0 */
4267        xchgw   %ax, %di                /* move AX to DI */
4268        movb    $0xff, %al              /* partition=whole drive for floppy */
4269        testb   %dl, %dl
4270        jns     3f                      /* no modification for floppy */
4271        movb    0x1bc, %al              /* partition number */
42723:
4273        stosb
4274
4275        /* fix for NTFS partition: on error go back to supervisor, offset 0x01fa */
4276
4277        movw    $0x01fa, %di
4278        movw    %es:(%di), %ax
4279        cmpw    $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
4280        jnz     3f
4281        decw    %ax             /* AL=0xEA, ljmp */
4282        stosb
4283        //movw  $(try_next_partition - _start1), %ax
4284        movw    $MONITOR, %ax
4285        stosw
4286
4287        //movw  %cs, %ax        /* AX=0x9400 */
4288        xorw    %ax, %ax
4289        stosw                   /* DI=0x01ff */
42903:
4291        clc
4292        jmp     move_entries_and_return
4293
4294#else
4295
4296        /* modify the boot partition number */
4297        movb    $0xB6, %al              /* 0xB6="MOV DH,imm8" */
4298        movb    %cs:0x1bc, %ah
4299        testb   %dl, %dl
4300        js      3f
4301        movb    $0xff, %ah /* partition number for floppy is whole drive */
43023:
4303        /* before the call:
4304         *              AH= partition number
4305         *              AL= 0xB6        ; 0xB6 is opcode of "MOV DH,imm8"
4306         *              DL= drive number
4307         *
4308         * on return:   CF=0 if there is NTFS boot record;
4309         *              CF=1 otherwise.
4310         *              CF of flags_orig on the stack will set if CF=1
4311         */
4312
4313        call    modify_NTFS_boot_record
4314        //jnc   move_entries_and_return
4315        //movw  $(NTFS5_message - _start1), %si
4316        ////jmp 4f
4317        //call  print_message   /* CS:SI points to message string */
4318        //stc
4319        jmp     move_entries_and_return
4320
4321#endif
4322
43232:
4324        /* FAT12/FAT16 */
4325        movb    0x10(%si), %al          /* number of FATs(NTFS:0, FAT:1,2) */
4326        testb   %al, %al
4327        jz      1f
4328        movw    0x16(%si), %ax          /* sectors per FAT(small) */
4329        testw   %ax, %ax
4330        jz      1f
4331        movw    $(FAT16_message - _start1), %si
4332        cmpw    $12, %ax
4333        ja      7f
4334        movw    $(FAT12_message - _start1), %si
43357:
4336        /* BUG fix for extended FAT12/16/32 partition */
4337        popw    %di                     /* DI points to old entry in MBR */
4338        pushw   %di
4339        xorl    %eax, %eax              /* let hidden_sectors=0 for floppy */
4340        testb   %dl, %dl
4341        jns     3f                      /* floppy */
4342        movl    %cs:4(%di), %eax
4343        addl    %cs:8(%di), %eax
43443:
4345        movl    %eax, 0x1c              /* adjust hidden_sectors for FAT */
4346
4347        call    print_message   /* CS:SI points to message string */
4348        pushw   %cs
4349        popw    %ds
4350        /* DS=SS=0x9400 */
4351        /* ES=FS_BOOT */
4352        movw    %bx, %si
4353        xorw    %di, %di
4354        lodsw
4355        stosw
4356        addw    %cx, %si
4357        addw    %cx, %di
4358        movw    $0x0200, %cx
4359        subw    %di, %cx
4360        repz movsb
4361        /* modify the boot partition number */
4362        movb    %es:1, %al
4363        addb    $5, %al                 /* AL is less than 0x80 */
4364        cbw                             /* AH=0 */
4365        xchgw   %ax, %di                /* move AX to DI */
4366        movb    $0xff, %al              /* partition=whole drive for floppy */
4367        testb   %dl, %dl
4368        jns     3f                      /* no modification for floppy */
4369        movb    0x1bc, %al              /* partition number */
43703:
4371        stosb
4372
4373        /* fix for FAT12/16/32 partition: on error go back to supervisor, offset 0x01fa */
4374        //pushw %es
4375        //popw  %ds
4376        movw    $0x01fa, %di
4377        //movw  %di, %si
4378        //lodsw
4379        movw    %es:(%di), %ax
4380        cmpw    $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
4381        jnz     3f
4382        decw    %ax             /* AL=0xEA, ljmp */
4383        stosb
4384        //movw  $(try_next_partition - _start1), %ax
4385        movw    $MONITOR, %ax
4386        stosw
4387        //movw  %cs, %ax        /* AX=0x9400 */
4388        xorw    %ax, %ax
4389        stosw                   /* DI=0x01ff */
43903:
4391
4392        clc
4393        jmp     move_entries_and_return
43941:
4395        #; It is not FAT12/16/32/NTFS. Check for extended partition.
4396
4397        /* DS=ES=FS_BOOT */
4398
4399        pushw   %cs
4400        popw    %es
4401
4402        /* ES=SS=0x9400 */
4403        /* DS=FS_BOOT */
4404
4405        popw    %si
4406        pushw   %si
4407        cmpb    $0x05, %es:(%si)        /* extended */
4408        je      1f
4409        cmpb    $0x0f, %es:(%si)        /* Win95 extended (LBA) */
4410        je      1f
4411        cmpb    $0x15, %es:(%si)        /* hidden extended */
4412        je      1f
4413        cmpb    $0x1f, %es:(%si)        /* hidden win95 extended (LBA) */
4414        je      1f
4415        cmpb    $0x85, %es:(%si)        /* Linux extended */
4416        je      1f
4417        movw    $(non_MS_message - _start1), %si
44184:
4419        call    print_message   /* CS:SI points to message string */
4420        stc
4421        jmp     move_entries_and_return
44221:
4423        /* extended partition entry */
4424        cmpw    $0x1fe, %si
4425        jb      1f
4426        decw    %es:0x1bc       /* count the partitions in extended zone */
44271:
4428        movw    $(extended_message - _start1), %si
4429        call    print_message   /* CS:SI points to message string */
4430        movw    $0x1be, %si
4431        movw    $4, %cx
44325:
4433        //xorl  %eax, %eax
4434        //cmpl  %eax, (%si)
4435        //jnz   2f
4436        movl    (%si), %eax
4437        cmpw    2(%si), %ax     /* Is EAX high word equal to AX? */
4438        jnz     2f
4439        cmpb    %al, %ah        /* Is AL=AH? */
4440        jnz     2f
4441
4442        /* now all 4 bytes in EAX are equal to each other. */
4443        cmpl    %eax, 4(%si)
4444        jnz     2f
4445        cmpl    %eax, 8(%si)
4446        jnz     2f
4447        cmpl    %eax, 12(%si)
4448        jz      3f      /* entry with 16 dups of a byte means empty entry */
44492:
4450        movb    (%si), %al
4451        shlb    $1, %al
4452        jnz     1f
4453        //jnz   3f              /* invalid entry is treated as empty entry */
4454        movb    2(%si), %al
4455        and     $63, %al        /* starting sector number */
4456        jz      1f
4457        //jz    3f              /* invalid entry is treated as empty entry */
4458        movb    6(%si), %al
4459        and     $63, %al        /* ending sector number */
4460        jz      1f
4461        //jz    3f              /* invalid entry is treated as empty entry */
4462        movl    8(%si), %eax    /* starting LBA */
4463        testl   %eax, %eax
4464        jz      1f
4465        //jz    3f              /* invalid entry is treated as empty entry */
4466        movl    12(%si), %eax   /* total number of sectors in partition */
4467        testl   %eax, %eax
4468        jz      1f
44693:
4470        addw    $16, %si
4471        loop    5b
4472        cmpw    $0xaa55, (%si)
4473        jnz     1f
4474
4475        movw    $0x1be, %si
4476        movw    $4, %cx
4477        popw    %bx     /* the old SI points to extended partition ID in MBR */
4478        pushw   %bx
44795:
4480#if 1
4481        //xorl  %eax, %eax
4482        //cmpl  %eax, (%si)
4483        //jnz   2f
4484        movl    (%si), %eax
4485        cmpw    2(%si), %ax     /* Is EAX high word equal to AX? */
4486        jnz     2f
4487        cmpb    %al, %ah        /* Is AL=AH? */
4488        jnz     2f
4489
4490        /* now all 4 bytes in EAX are equal to each other. */
4491        cmpl    %eax, 4(%si)
4492        jnz     2f
4493        cmpl    %eax, 8(%si)
4494        jnz     2f
4495        cmpl    %eax, 12(%si)
4496        jz      3f      /* entry with 16 dups of a byte means empty entry */
44972:
4498        /* now it is an acceptable entry */
4499        movw    %es:0x1ba, %di  /* partition entries end */
4500        /* ensure our stack not to be overwritten by the partition entries */
4501        cmpw    $0x83f0, %di
4502        ja      3f              /* try next */
4503        /* ensure our code not to be overwritten by the partition entries */
4504        cmpw    $0x3fe, %di
4505        jne     6f
4506        /* more entries stores at 0x9be00-0x9c3ff */
4507        movw    $0x7e00, %di
4508        movw    %di, %es:0x1ba
45096:
4510        addw    $16, %es:0x1ba  /* increment partition entries end */
4511
4512        lodsl
4513        stosl
4514        lodsl
4515        stosl
4516
4517        xchgw   %ax, %dx        /* save AL(the partition ID)to DL */
4518
4519        lodsl
4520        xchgl   %eax, %edx      /* restore AL from DL(the partition ID)
4521                                 * and save EAX to EDX */
4522        cmpb    $0x05, %al
4523        je      6f
4524        cmpb    $0x0f, %al
4525        je      6f
4526        cmpb    $0x15, %al
4527        je      6f
4528        cmpb    $0x1f, %al
4529        je      6f
4530        cmpb    $0x85, %al
4531        je      6f
4532        /* normal partition, copied to 0x941fe-0x943fb */
4533        addl    %es:4(%bx), %edx        /* current partition start */
45346:
4535        /* extended partition, copied to 0x941fe-0x943fb */
4536        xchgl   %eax, %edx      /* restore or update EAX from EDX */
4537        stosl
4538        lodsl                           /* adjust SI only */
4539        movl    %es:8(%bx), %eax        /* parent partition start ... */
4540        stosl                           /* ... stored here */
4541        jmp     2f
45423:
4543        addw    $16, %si
4544#endif
4545        //. = 5b + 0x7c
45462:
4547        loop    5b
4548
4549        /* extended partition is not a normal one, so set carry to try next */
4550        stc
4551        jmp     move_entries_and_return
4552
4553invalid_or_null:
45541:
4555        movw    $(invalid_message - _start1), %si
4556        call    print_message   /* CS:SI points to message string */
4557        stc
4558
4559move_entries_and_return:
4560        popw    %si
4561        pushfw
4562        pushw   %cs
4563        popw    %ds
4564        pushw   %cs
4565        popw    %es
4566        pushw   %si
4567        cmpw    $0x202, %si
4568        jne     1f
4569        /* move entries backward 1 entry */
4570        movw    $0x1fe, %di
4571        movw    $0x20e, %si
4572        movw    $0xf8, %cx              /* 0x1f0 bytes = 0xf8 words */
4573        cld                             /* move upward */
4574        repz movsw
4575        movw    $0x3ee, %di
4576        movw    $0x7e00, %si
4577        movw    $0x8, %cx               /* 0x10 bytes = 0x8 words */
4578        cld                             /* move upward */
4579        repz movsw
4580        movw    $0x7e00, %di
4581        movw    $0x7e10, %si
4582        movw    $0x2f8, %cx             /* 0x5f0 bytes = 0x2f8 words */
4583        cld                             /* move upward */
4584        repz movsw
4585        cmpw    $0x7e10, 0x1ba
4586        jne     2f
4587        movw    $0x40e, 0x1ba
45882:
4589        subw    $0x10, 0x1ba
4590
45911:
4592        popw    %si
4593        movw    $0x1ff, (add_sub_si + 5 - _start1)
4594        cmpw    $0x1fe, 0x1ba
4595        jne     1f
4596        decw    (add_sub_si + 5 - _start1)
4597        cmpw    $0x31b2, %si            /* floppy? */
4598        je      1f                      /* yes */
4599        cmpw    $0x1f2, %si
4600        ja      2f                      /* logical partition */
4601        jb      1f                      /* primary partition 0, 1, 2 */
4602        /* primary partition 3 */
4603        cmpw    $0x0003, 0x1bc          /* are there any logical partitions? */
4604        ja      1f                      /* yes */
46052:
4606inc_hard_drive:
4607
4608        /* all partitions on the drive have been checked, try next drive.
4609         *
4610         * the current stack is:
4611         *
4612         * SP + 38      : DS
4613         * SP + 36      : ES
4614         * SP + 32      : EAX
4615         * SP + 28      : ECX
4616         * SP + 24      : EDX
4617         * SP + 20      : EBX
4618         * SP + 16      : ESP_temp
4619         * SP + 12      : EBP
4620         * SP +  8      : ESI
4621         * SP +  4      : EDI
4622         * SP +  2      : flags_orig
4623         * SP           : flags
4624         *
4625         */
4626
4627        /* get total hard drives */
4628        xorw    %ax, %ax
4629        movw    %ax, %ds
4630        movb    0x475, %dh
4631        pushw   %cs
4632        popw    %ds
4633//      cmpb    $16, %dh
4634//      jnb     2f
4635//      movb    $16, %dh
4636//2:
4637        orb     $0x80, %dh      /* CF=0, DH=Max harddrive number + 1 */
4638        //xchgw %ax, %cx        /* CL=Max harddrive number + 1, CH=0 */
4639        movw    %sp, %bp
4640        movb    24(%bp), %dl    /* BIOS drive number is in DL */
46412:
4642        jnc     3f
4643        call    print_message   /* CS:SI points to message string */
4644        movw    $(drive_number_string - _start1), %si
4645        movb    %dl, %al
4646        andb    $0x7f, %al
4647        aam                     /* AH=high decimal, AL=low decimal */
4648        addw    $0x3030, %ax
4649        xchgb   %al, %ah
4650        movw    %ax, 9(%si)
4651        call    print_message   /* CS:SI points to message string */
46523:
4653        incw    %dx
4654        cmpb    %dh, %dl
4655        jnb     2f              /* all drives checked, try floppy finally */
4656
4657        pushw   %bx
4658        pushw   %dx
4659        pushw   %es
4660        movb    $8, %ah         /* read drive parameters changes DX, ES, DI */
4661        int     $0x13
4662        popw    %es
4663        jc      3f              /* try next hard drive */
4664        //xchgw %ax, %cx        /* this moves CL to AL */
4665        andb    $63, %cl        /* CL=sectors per track, CF cleared */
4666        stc
4667        jz      3f              /* try next hard drive */
4668        popw    %dx             /* get DL */
4669        popw    %bx
4670        movb    %dl, %ch        /* DL saved at BP high byte in the stack */
4671        pushw   %cx             /* push new BX onto stack */
4672        pushw   %dx
4673        //movb  $0x02, %ah
4674        //movw  %ax, %si        /* save AX to SI: read 1 track */
4675        movw    $0x201, %ax     /* read 1 sector */
4676        movw    $0x7e00, %bx    /* read MBR to 9400:7e00 */
4677        movw    $1, %cx
4678        //popw  %dx
4679        //pushw %dx
4680        xorb    %dh, %dh
4681        stc
4682        int     $0x13
4683        sti
46843:
4685        popw    %dx
4686        popw    %bx             /* BL=sectors per track, BH=DL */
4687
4688        //movw  %si, %bx        /* BL=sectors per track */
4689
4690        movw    $(Error_while_reading_string - _start1), %si
4691        jc      2b              /* read failure, try next hard drive */
4692
4693        /* on seccessful return, should be: ah=0 for OK, al=1 for 1 sector */
4694        //decw  %ax             /* some BIOSes return incorrect AL */
4695        testb   %ah, %ah
4696        stc
4697        jnz     2b
4698
4699        /* The new partition table might be empty or invalid.
4700         * Move the new partition table onto the old one while checking
4701         */
4702
4703        //movb  %dl, %bh        /* DL saved at BP high byte in the stack */
4704
4705        movw    $0x7fbe, %si
4706        movw    $0x01be, %di
4707
47083:
4709        cmpw    $0x1fe, %di
4710        jnb     3f
4711
4712        xorl    %ecx, %ecx
4713
4714        lodsl
4715        stosl
4716        orl     %eax, %ecx
4717        lodsl
4718        stosl
4719        orl     %eax, %ecx
4720        lodsl
4721        stosl
4722        orl     %eax, %ecx
4723        lodsl
4724        stosl
4725        orl     %eax, %ecx
4726        jecxz   3b              /* null entry, check next */
4727
4728        //lodsw
4729        //stosw
4730        movb    -16(%si), %al
4731        shlb    $1, %al
4732        stc
4733        xchgw   %ax, %si        /* save SI to AX */
4734        movw    $(partition_boot_indicator_string - _start1), %si
4735        jnz     2b
4736        xchgw   %ax, %si        /* restore SI from AX */
4737        //lodsw
4738        //stosw
4739        movb    -14(%si), %al
4740        andb    $63, %al
4741        stc
4742        xchgw   %ax, %si        /* save SI to AX */
4743        movw    $(partition_sectors_per_track_string - _start1), %si
4744        jz      2b
4745        xchgw   %ax, %si        /* restore SI from AX */
4746        //lodsw
4747        //stosw
4748        //lodsw
4749        //stosw
4750        movb    -10(%si), %al
4751        andb    $63, %al
4752        stc
4753        xchgw   %ax, %si        /* save SI to AX */
4754        movw    $(partition_sectors_per_track_string - _start1), %si
4755        jz      2b
4756        xchgw   %ax, %si        /* restore SI from AX */
4757        //lodsl
4758        //stosl
4759        movl    -8(%si), %eax
4760        testl   %eax, %eax
4761        stc
4762        xchgw   %ax, %si        /* save SI to AX */
4763        movw    $(partition_start_sector_string - _start1), %si
4764        jz      2b
4765        xchgw   %ax, %si        /* restore SI from AX */
4766
4767        //lodsl
4768        //stosl
4769        movl    -4(%si), %eax
4770        testl   %eax, %eax
4771        stc
4772        xchgw   %ax, %si        /* save SI to AX */
4773        movw    $(partition_end_sector_string - _start1), %si
4774        jz      2b
4775        xchgw   %ax, %si        /* restore SI from AX */
4776
4777        jmp     3b
47783:
4779        cmpw    $0xAA55, (%si)
4780        stc
4781        xchgw   %ax, %si        /* save SI to AX */
4782        movw    $(no_boot_signature_string - _start1), %si
4783        jnz     2b
4784        xchgw   %ax, %si        /* restore SI from AX */
4785        //lodsw
4786        //stosw                 /* store boot signature */
4787
4788        /* Now the partition table is OK */
4789
4790        movw    %bx, 12(%bp)    /* adjust BP in the stack */
4791
4792        movw    $0x1b2, 8(%bp)  /* adjust SI in the stack */
4793
4794        /* temp change the code:        call    self_modify_once
4795         *
4796         * "call self_modify_once" at add_sub_si is:
4797         *
4798         *      .byte   0xE8
4799         *      .word   (self_modify_once - add_sub_si - 3)
4800         *
4801         */
4802        movb    $0xE8, (add_sub_si - _start1)
4803        movw    $(self_modify_once - add_sub_si - 3), (add_sub_si + 1 - _start1)
4804
4805        /* initialize partition number and partition entries end */
4806        movw    $0xffff, 0x1bc          /* hd partition number */
4807        movw    $0x01fe, 0x1ba          /* partition entries end */
4808
4809        jmp     1f
48102:
4811        /* get here if all drives have been checked */
4812#if 0
4813        movw    $0x202, 8(%bp)  /* adjust SI in the stack */
4814
4815        /* restore the original code:   addw    $-4, %si */
4816        movw    $0xC683, (add_sub_si  - _start1)        /* 0x83, 0xC6 */
4817        movb    $0xFC, (add_sub_si + 2 - _start1)       /* 0xFC */
4818#endif
4819        //--------------------------------------------------------------------
4820        /* change the code:     jmp     Error_modify
4821         *
4822         * "jmp Error_modify" at Error_or_prev_MBR:
4823         *
4824         *      .byte   0xE9
4825         *      .word   (Error_modify - Error_or_prev_MBR - 3)
4826         *
4827         */
4828        movb    $0xE9, (Error_or_prev_MBR - _start1)
4829        movw    $(Error_modify - Error_or_prev_MBR - 3), (Error_or_prev_MBR + 1 - _start1)
4830        //--------------------------------------------------------------------
4831
4832        //--------------------------------------------------------------------
4833        /* floppy search disabled ? */
4834#if 0
4835        testb   $1, 0x02                /* test bit0 of the third byte */
4836        jz      1f                      /* zero means floppy search enabled */
4837        /* 0x1fd or below means disable floppy search */
4838        decw    (add_sub_si + 5 - _start1)
4839#else
4840        movb    0x02, %al
4841        andb    $0x01, %al
4842        subb    %al, (add_sub_si + 5 - _start1)
4843#endif
4844        //--------------------------------------------------------------------
4845
48461:
4847#if 0
4848        popfw
4849        lahf                    /* Load Flags into AH Register. */
4850                                /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
4851                                /* CF will be moved to ZF */
4852        movb    %ah, %al
4853        andb    $1, %al         /* CF=0 */
4854        shlb    $6, %al         /* move CF to ZF */
4855        popfw
4856        lahf                    /* Load Flags into AH Register. */
4857                                /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
4858        andb    $0xbf, %ah      /* 0xbf= binary 1011 1111. It clears ZF */
4859        orb     %al, %ah
4860#else
4861        popw    %ax             /* AX=Flags */
4862        popfw                   /* Flags_orig */
4863        lahf                    /* Load Flags_orig into AH Register. */
4864                                /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
4865        shlb    $2, %ah
4866        rorw    $2, %ax         /* move CF of Flags to ZF of Flags_orig */
4867#endif
4868
4869        sahf                    /* update flags */
4870                                /* current CF is the CF of Flags_orig */
4871                                /* current ZF is the CF of Flags */
4872        jc      1f              /* CF=1 means failed in loading bootsector */
4873        popal                   /* get drive number DL */
4874        pushal
4875        pushfw
4876        cmpb    $0xff, %cs:0x06
4877        jz      2f
4878        movb    %cs:0x1bc, %dh
4879        testb   %dl, %dl
4880        js      3f
4881        movb    $0xff, %dh      /* partition # for floppy is "whole drive" */
48823:
4883        cmpw    %cs:0x06, %dx
4884        jz      2f
4885        popfw
4886        stc
4887        pushfw
48882:
4889        popfw
48901:
4891        popal
4892        popw    %es
4893        popw    %ds
4894        ret
4895
4896self_modify_once:
4897        /* when we get here, SI should be 0x1b2, and BP high holds DL */
4898        addw    $12, %si        /* 0x83, 0xC6, 0x0C */
4899        movw    %bp, %ax
4900        movb    %ah, %dl
4901
4902        /* note: DS=0x9400 */
4903
4904        /* restore the original code:   addw    $12, %si */
4905        movw    $0xC683, (add_sub_si  - _start1)        /* 0x83, 0xC6 */
4906        movb    $0x0C, (add_sub_si + 2 - _start1)       /* 0x0C */
4907        ret
4908
4909Error_modify:
4910        cmpb    $0xff, %cs:0x06 /* preferred drive? */
4911        jz      1f              /* not active. Turn to the final step. */
4912
4913        /* preferred drive is already handled, so de-activate it now. */
4914        movb    $0xff, %cs:0x06
4915
4916        /* we will do the second pass, from drive 0x80. */
4917        movb    $0x7f, %dl      /* this will become 0x80 after inc. */
4918
4919        /* pass "error" to PUSHF, simulating a load failure, in order
4920         * to try the first entry after return from the helper function.
4921         */
4922
4923        stc
4924
4925        pushw   $(helper_call + 3 - _start1)    /* return address */
4926        pushw   %cs             /* 0x9400, it is for DS. */
4927        pushw   $FS_BOOT        /* 0x0d00, it is for ES. */
4928        pushal
4929        //pushl %eax
4930        //pushl %ecx
4931        //pushl %edx
4932        //pushl %ebx
4933        //pushl %esp
4934        //pushl %ebp
4935        //pushl %esi
4936        //pushl %edi
4937        pushfw                  /* CF=1 */
4938        pushfw
4939
4940        pushw   %cs
4941        popw    %es             /* ES=0x9400 */
4942
4943        /* redo from start: DL will be 0x80 after inc. */
4944        jmp     inc_hard_drive
49451:
4946boot_prev_mbr:
4947
4948        /* prepare to boot the previous MBR */
4949
4950        /* at this moment DS=0x9400, ES=$FS_BOOT or ES=0x9400 */
4951        xorw    %ax, %ax
4952        //pushw %ax     /* AX=0, for the segment of 0000:7c00 */
4953        movw    %ax, %es        /* ES=0x0000 */
4954        movw    %ax, %ds        /* DS=0x0000 */
4955        pushw   %ds
4956        pushw   %es
4957        movw    $0x0202, %ax    /* read 2 sectors ... */
4958        movw    $0x7A00, %bx    /* ... to 0000:7A00 */
4959        //pushw %bx     /* BX=0x7c00, for the offset of 0000:7c00 */
4960        movw    $0x0001, %cx    /* from the first sector ... */
4961        movw    $0x0080, %dx    /* ... of the first hard drive */
4962        stc
4963        int     $0x13
4964        sti
4965        popw    %es
4966        popw    %ds
4967        jc      1f
4968        testb   %ah, %ah
4969        jnz     1f
4970        cmpw    $0xAA55, 0x7dfe
4971        jne     1f
4972        cmpw    $0xAA55, 0x7bfe
4973        jne     1f
4974
4975        /* has a valid partition table ? */
4976        movw    $0x7dbe, %si
49773:
4978        cmpw    $0x7dfe, %si
4979        jnb     3f              /* partition table is OK */
4980        movw    $4, %cx
4981
4982        movw    %si, %di
49832:
4984        lodsl
4985        negl    %eax
4986        jc      2f
4987        loop    2b
4988        /* empty entry, check next */
4989        jmp     3b
49902:
4991        /* non-empty entry */
4992        movw    %di, %si
4993
4994        lodsw
4995        shlb    $1, %al
4996        jnz     2f
4997        lodsw
4998        andb    $63, %al
4999        jz      2f
5000        lodsw
5001        lodsw
5002        andb    $63, %al
5003        jz      2f
5004        lodsl
5005        negl    %eax
5006        jnc     2f
5007        lodsl
5008        negl    %eax
5009        jc      3b
50102:
5011        stc             /* invalid partition table */
50123:
5013        pushfw
5014
5015        /* disable the boot of non-MBR bootsector ? */
5016        testb   $2, %cs:0x02            /* test bit1 of the third byte */
5017        jz      2f                      /* zero means non-MBR enabled */
5018        popfw
5019        jc      1f      /* invalid partition table, print "Error" */
5020
5021        /* the partition table is valid */
5022        pushfw
5023
50242:
5025        /* the check passed, and the boot is permitted */
5026        popfw
5027
5028        jc      2f      /* invalid partition table */
5029
5030        /* use partition table in MBR instead */
5031
5032        /* copy 72 bytes at 0000:7bb8 to 0000:7db8 */
5033
5034        movw    $0x7bb8, %si
5035        movw    $0x7db8, %di
5036        movw    $36, %cx
5037        cld
5038        repz movsw
5039
50402:
5041        testb   $0x80, %cs:0x02         /* test bit 7 of the third byte */
5042        jz      2f                      /* zero means boot prev-MBR first */
5043
5044        movw    $(Cannot_find_GRLDR_string - _start1), %si
5045        call    print_message   /* CS:SI points to message string */
5046//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
5047        movw    $(press_space_bar_string - _start1), %si
5048        cmpw    $0x3920, %cs:0x04
5049        je      3f
5050        movw    $0x3920, %cs:0x04
5051        #;movw  $(press_hot_key_string - _start1), %si
50523:
5053        call    print_message   /* CS:SI points to message string */
5054        movw    $(prev_MBR_string - _start1), %si
5055        call    print_message   /* CS:SI points to message string */
5056//#else
5057//      movw    $(press_hot_key_pre - _start1), %si
5058//      call    print_message
5059//      movw    $(press_hot_key_name - _start1), %si
5060//      call    print_message
5061//      movw    $(press_hot_key_sub - _start1), %si
5062//      call    print_message
5063//#endif
50643:
5065        call    sleep_5_seconds
5066        /* if hot-key is pressed, wait forever until another key is pressed. */
5067        movb    $0xff, %cs:0x03
5068        jc      3b              /* desired hot-key is pressed */
50692:
5070        /* boot the previous MBR */
5071
5072        /* clear the DUCE indicator */
5073        movl    $0, 0x5FC       /* DS=ES=0 */
5074
5075        //movb  $0x80, %dl
5076        ljmp    $0, $0x7c00
50771:
5078        /* no previous MBR, print "Error" */
5079        ///* Note the 0000:7C00 is on the stack */
5080        //popw  %ax     /* AX=0x0000 */
5081        //popw  %ax     /* AX=0x7C00 */
5082
5083        testb   $0x80, %cs:0x02 /* are we called prior to the GRLDR search? */
5084        jnz     1f              /* no, it is a failure at last */
5085        /* yes, so return to the caller */
5086        movw    $(continue_string - _start1), %si
5087        call    print_message   /* CS:SI points to message string */
5088        call    sleep_5_seconds
5089        ret
50901:
5091        movw    $(message_string_helper - _start1), %si
5092        call    print_message   /* CS:SI points to message string */
50931:      jmp     1b      /* hang */
5094
5095sleep_5_seconds:
5096        /* sleep 5 seconds */
5097
5098        /* sleep forever if %cs:0x03 is 0xff */
5099
5100        /* calculate the timeout ticks */
5101
5102        pushw   %ds
5103        pushl   %esi
5104        pushl   %edx
5105
5106        movl    $0xffffffff, %edx
5107        movzbl  %cs:0x03, %eax
5108        cmpb    $0xff, %al
5109        je      1f
5110        movl    $18, %edx       /* 18.2 ticks per second. We simply use 18. */
5111        mulw    %dx             /* EDX=0, EAX=ticks */
5112        xchgw   %ax, %dx        /* EAX=0, EDX=ticks */
51131:
5114        xorw    %ax, %ax
5115        movw    %ax, %ds
5116        movl    0x46c, %eax     /* initial tick */
5117        movl    %eax, %ecx      /* ECX=initial tick */
5118        testl   %edx, %edx
5119        js      1f
5120        addl    %edx, %eax      /* EAX=timeout tick */
5121        pushl   %eax
5122
5123        movzbl  %cs:0x03, %eax
5124        orl     %eax, %eax
5125        jz      3f
5126
5127        movw    $(hot_key_timeout_pre - _start1), %si
5128        pushl   %eax
5129        call    print_message
5130        popl    %eax
5131
5132        movw    $(hot_key_timeout_num - _start1), %si
5133        call    print_decimal
51343:
5135        movl    %ecx, %esi
5136        addl    $18, %esi
5137
5138        popl    %eax
5139        jmp     3f
51401:
5141        movl    %edx, %eax      /* EAX=0xffffffff */
5142        movl    %edx, %esi
51433:
5144        movl    0x46c, %ebx     /* EBX=current tick */
5145        cmpl    %ecx, %ebx
5146        jnb     2f
5147
5148        /* current tick is less than initial tick, this means the ticks have
5149         * overflowed to the next day, and EBX is rather small. */
5150        xorl    %ecx, %ecx
5151        movl    %edx, %eax
5152        movl    $18, %esi
51532:
5154        /* check if there is any key press. */
5155        pushl   %eax
5156        movb    $1, %ah
5157        int     $0x16
5158        pushw   %ax
5159        pushfw
5160
5161        movb    $0x11, %ah
5162        int     $0x16
5163        jnz     1f
5164        popfw
5165        jnz     2f
5166
5167        /* no, there is no key press. */
5168
5169        popw    %ax
5170        popl    %eax
5171
5172        cmpl    %esi, %ebx
5173        jb      4f
5174        pushl   %esi
5175        pushl   %eax
5176        pushl   %edx
5177
5178
5179        subl    %esi, %eax
5180        xorl    %edx, %edx
5181        movl    $18, %esi
5182        divl    %esi
5183
5184        movw    $(hot_key_timeout_num - _start1), %si
5185        pushl   %ebx
5186        call    print_decimal
5187        popl    %ebx
5188
5189        popl    %edx
5190        popl    %eax
5191        popl    %esi
5192        addl    $18, %esi
51934:
5194        cmpl    %eax, %ebx      /* timeout? */
5195        jbe     3b              /* no, continue to wait */
5196
5197        /* timeout reached, CF=0, no key pressed. */
5198        popl    %edx
5199        popl    %esi
5200        popw    %ds
5201        ret
52021:
5203        popfw
52042:
5205        /* yes, there is a key press. */
5206#if 0
5207        /* clear the keyboard buffer */
5208        movb    $1, %ah
5209        int     $0x16
5210        jz      1f      /* no keys, end */
5211        movb    $0, %ah
5212        int     $0x16   /* discard the key */
5213        jmp     1b
52141:
5215#endif
5216
5217        /* check if it is the desired key. */
5218
5219        xorw    %cs:0x04, %ax   /* CF=0 */
5220        popw    %ax
5221        je      1f
5222        xorw    %cs:0x04, %ax   /* CF=0 */
5223        jne     2f              /* not desired, return CF=0 */
5224
5225        /* remove the desired key from the keyboard buffer. */
5226
5227        movb    $0, %ah
5228        int     $0x16   /* discard the key */
5229        jmp     3f
52301:
5231        /* remove the desired key from the keyboard buffer. */
5232
5233        movb    $0x10, %ah
5234        int     $0x16   /* discard the key */
52353:
5236        stc     /* CF=1, the desired key pressed */
52372:
5238        popl    %eax
5239        popl    %edx
5240        popl    %esi
5241        popw    %ds
5242        ret
5243
5244out_decimal:
5245        /*
5246         * input: EAX = number, CS:SI = buffer
5247         */
5248
5249        pushl   %edx
5250        pushl   %ecx
5251        pushw   %bx
5252
5253        movl    $10, %ecx
5254        movw    %si, %bx
5255
52561:
5257        xorl    %edx, %edx
5258        divl    %ecx
5259        addb    $'0', %dl
5260        movb    %dl, %cs:(%si)
5261        incw    %si
5262        orl     %eax, %eax
5263        jnz     1b
5264
5265        pushw   %si
5266
52671:
5268        decw    %si
5269        cmpw    %bx, %si
5270        jbe     1f
5271        movb    %cs:(%si), %al
5272        xchgb   %al, %cs:(%bx)
5273        movb    %al, %cs:(%si)
5274        incw    %bx
5275        jmp     1b
52761:
5277
5278        popw    %si
5279
5280        popw    %bx
5281        popl    %ecx
5282        popl    %edx
5283        ret
5284
5285print_decimal:
5286        pushw   %si
5287        call    out_decimal
5288
52891:
5290        cmpb    $'\b', %cs:(%si)
5291        jz      2f
5292        movb    $' ', %cs:(%si)
5293        incw    %si
5294        jmp     1b
52952:
5296        popw    %si
5297        call    print_message
5298        ret
5299
5300#if 0
5301modify_NTFS_boot_record:
5302
5303        /* before the call:
5304         *              AH= partition number
5305         *              AL= 0xB6        ; 0xB6 is opcode of "MOV DH,imm8"
5306         *              DL= drive number
5307         *
5308         * on return:   CF=0 if there is NTFS boot record;
5309         *              CF=1 otherwise.
5310         *              CF of flags_orig on the stack will set if CF=1
5311         */
5312
5313        /*
5314         *
5315         * the current stack is:
5316         *
5317         * SP + 40      : DS
5318         * SP + 38      : ES
5319         * SP + 34      : EAX
5320         * SP + 30      : ECX
5321         * SP + 26      : EDX
5322         * SP + 22      : EBX
5323         * SP + 18      : ESP_temp
5324         * SP + 14      : EBP
5325         * SP + 10      : ESI
5326         * SP +  6      : EDI
5327         * SP +  4      : flags_orig
5328         * SP +  2      : SI            ; SI points to old entry in MBR
5329         * SP           : return_IP
5330         *
5331         */
5332
5333        /* DS=ES=FS_BOOT */
5334
5335        /* change NTLDR to GRLDR */
5336
5337        /* check GR or NT or anything else */
5338
5339        pushw   %ax
5340
5341        movw    $0x200, %si
5342        lodsw
5343        cmpw    $5, %ax
5344        jne     1f              /* failure */
5345        lodsw
5346        testb   %ah, %ah        /* high byte of unicode ASCII should be 0 */
5347        jne     1f              /* failure */
5348
5349        /* 'N' should be a capital letter */
5350
5351        cmpb    $0x41, %al      /* Less than 'A' */
5352        jb      1f              /* failure */
5353        cmpb    $0x5A, %al      /* Greater than 'Z'*/
5354        ja      1f              /* failure */
5355
5356        xchgw   %ax, %cx        /* save AX to CX. CL='N' */
5357
5358        lodsw
5359        testb   %ah, %ah        /* high byte of unicode ASCII should be 0 */
5360        jne     1f              /* failure */
5361
5362        /* 'T' should be a capital letter */
5363
5364        cmpb    $0x41, %al      /* Less than 'A' */
5365        jb      1f              /* failure */
5366        cmpb    $0x5A, %al      /* Greater than 'Z'*/
5367        ja      1f              /* failure */
5368
5369        movb    %al, %ch        /* save AL to CH. CH='T' */
5370
5371        lodsw
5372        cmpw    $0x4C, %ax      /* 'L' */
5373        jne     1f              /* failure */
5374        lodsw
5375        cmpw    $0x44, %ax      /* 'D' */
5376        jne     1f              /* failure */
5377        lodsw
5378        cmpw    $0x52, %ax      /* 'R' */
5379        jne     1f              /* failure */
5380        lodsw
5381        cmpw    $0x04, %ax      /* length of "$I30" */
5382        jne     1f              /* failure */
5383        lodsw
5384        cmpw    $0x24, %ax      /* '$' */
5385        jne     1f              /* failure */
5386        lodsw
5387        cmpw    $0x49, %ax      /* 'I' */
5388        jne     1f              /* failure */
5389        lodsw
5390        cmpw    $0x33, %ax      /* '3' */
5391        jne     1f              /* failure */
5392        lodsw
5393        cmpw    $0x30, %ax      /* '0' */
5394        jne     1f              /* failure */
5395
5396
5397        /* assume it is NT bootsector. first, find "NTLDR". CX holds "NT" */
5398        movw    $0x0100, %di
5399        movb    %cl, %al        /* AL="N" */
5400        movb    $1, %ah         /* AH=Carry for SAHF below */
5401        movl    $0x52444c00, %ebx       /* "LDR" */
5402        movb    %ch, %bl                /* 'T' */
5403        movw    $0x00fa, %cx
5404
5405        /* now AL holds 'N' and BL holds 'T' */
5406
5407        //cld                   /* already upward */
54083:
5409        repnz scasb             /* find "N" */
5410        jcxz    4f              /* gets the end, exit */
5411        cmpl    %ebx, (%di)     /* is it "NTLDR"? */
5412        jnz     3b              /* no, continue to find */
5413
5414        /* "NTLDR" is found, so we believe it is NT boot sector. */
5415
5416        movw    $0x5247, -1(%di)        /* change "NT" to "GR" */
5417
5418        /* CF=0 for now */
5419
5420        lahf                    /* Load Flags into AH */
5421                                /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
5422                                /* AH = binary xxxxxxx0 */
5423        jmp     3b
54244:
5425        sahf            /* Store AH into flags SF ZF xx AF xx PF xx CF */
5426
5427        /* CF=0 means "NTLDR" is found, CF=1 means "NTLDR" is not found. */
5428
5429        jc      1f              /* failure */
5430
5431        movl    $0x00520047, 0x202      /* change to "G R L D R" */
5432
5433        /* check NT 4.0 */
5434
5435        movw    $0x406, %si
5436        movl    (%si), %ebx             /* NT 4.0 */
5437        cmpl    $0x03E8B800, %ebx       /* MOV AX, 03E8 */
5438        jnz     3f
5439
5440        movl    0x84, %ebx
5441        cmpl    $0x680007E8, %ebx       /* call 008e; push (0D00) */
5442        jnz     3f
5443
5444//      movw    0x154, %bx              /* CR LF at end of "A disk read error occurred." */
5445//      cmpw    $0x0A0D, %bx            /* CR LF */
5446//      jnz     3f
5447//      movw    0x180, %bx              /* CR LF at end of "A kernel file is missing from the disk." */
5448//      cmpw    $0x0A0D, %bx            /* CR LF */
5449//      jnz     3f
5450//      movw    0x1A8, %bx              /* CR LF at end of "A kernel file is too discontiguous." */
5451//      cmpw    $0x0A0D, %bx            /* CR LF */
5452//      jnz     3f
5453//      movw    0x1F8, %bx              /* CR LF at end of "NTLDR is compressed." */
5454//      cmpw    $0x0A0D, %bx            /* CR LF */
5455//      jnz     3f
5456
5457        movl    0xE8, %ebx
5458        cmpl    $0x13CD80B2, %ebx       /* "B2 80"="mov DL, 80", "CD 13"="int 13" */
5459        jnz     3f
5460
5461        popw    %ax
5462        movw    %ax, 4(%si)
5463
5464        movl    $0x68909090, %ebx       /* nop;nop;nop;push (0D00) */
5465        movl    %ebx, 0x84
5466
5467//      /* change CRLF in NTFS error messages to spaces */
5468//      movw    $0x2020, %bx            /* change CRLF to 2 spaces */
5469//      movw    %bx, 0x154
5470//      movw    %bx, 0x180
5471//      movw    %bx, 0x1A8
5472//      movw    %bx, 0x1F8
5473
5474        movb    %dl, 0xE9               /* modify drive number */
5475
5476        /* modify NTFS boot record */
5477        movb    $0xea, %al      /* ljmp, hand over the control to supervisor */
5478        movb    %al, 0x122
5479        //movw  $(try_next_partition - _start1), %ax    /* offset for ljmp */
5480        movw    $MONITOR, %ax   /* offset for ljmp */
5481        movw    %ax, 0x123
5482        //movw  %cs, %ax        /* AX=0x9400, segment for ljmp */
5483        xorw    %ax, %ax
5484        movw    %ax, 0x125
5485
5486        movw    $(NTFS4_message - _start1), %si
5487        call    print_message   /* CS:SI points to message string */
5488        clc
5489        ret
54903:
5491        /* check NT 5.0 */
5492
5493        movw    $0x44b, %si
5494        movl    (%si), %ebx             /* NT 5.0 */
5495        cmpl    $0x03E8B800, %ebx       /* MOV AX, 03E8 */
5496        jz      2f
5497
5498        movw    $0x479, %si
5499        movl    (%si), %ebx             /* NT 5.1 SP2 */
5500        cmpl    $0x03E8B800, %ebx       /* MOV AX, 03E8 */
5501        jnz     1f
55022:
5503        movl    0x71, %ebx
5504        cmpl    $0x680053E8, %ebx       /* call 00C7; push (0D00) */
5505        jnz     1f
5506
5507        //movw  0x183, %bx              /* CR LF at begin of "A disk read error occurred." */
5508        movb    0x1F8, %bl
5509        movb    $1, %bh
5510        movw    (%bx), %bx
5511        cmpw    $0x0A0D, %bx            /* CR LF */
5512        jnz     1f
5513        //movw  0x1A0, %bx              /* CR LF at begin of "NTLDR is missing." */
5514        movb    0x1F9, %bl
5515        movb    $1, %bh
5516        movw    (%bx), %bx
5517        cmpw    $0x0A0D, %bx            /* CR LF */
5518        jnz     1f
5519        //movw  0x1B3, %bx              /* CR LF at begin of "NTLDR is compressed." */
5520        movb    0x1FA, %bl
5521        movb    $1, %bh
5522        movw    (%bx), %bx
5523        cmpw    $0x0A0D, %bx            /* CR LF */
5524        jnz     1f
5525
5526        popw    %ax
5527        movw    %ax, 4(%si)
5528
5529        movl    $0x68909090, %ebx       /* nop;nop;nop;push (0D00) */
5530        movl    %ebx, 0x71
5531
5532        /* change CRLF in NTFS error messages to spaces */
5533        movw    $0x2020, %ax
5534        movb    0x1F8, %bl
5535        movb    $1, %bh
5536        movw    %ax, (%bx)      // 0x183
5537        movb    0x1F9, %bl
5538        movb    $1, %bh
5539        movw    %ax, (%bx)      // 0x1A0
5540        movb    0x1FA, %bl
5541        movb    $1, %bh
5542        movw    %ax, (%bx)      // 0x1B3
5543
5544        /* modify NTFS boot record */
5545        movb    $0xEA, %al      /* ljmp, hand over the control to supervisor */
5546        movb    %al, 0x167
5547        //movw  $(try_next_partition - _start1), %ax    /* offset for ljmp */
5548        movw    $MONITOR, %ax   /* offset for ljmp */
5549        movw    %ax, 0x168
5550        //movw  %cs, %ax        /* AX=0x9400, segment for ljmp */
5551        xorw    %ax, %ax
5552        movw    %ax, 0x16A
5553
5554        cmpw    $0x44b, %si
5555        jne     2f
5556        movw    $(NTFS5_message - _start1), %si
5557        jmp     3f
55582:
5559        movw    $(NTFS5p_message - _start1), %si
55603:
5561        call    print_message   /* CS:SI points to message string */
5562        clc
5563        ret
55641:
5565        /* NTFS boot record not found. */
5566
5567        movw    $(NTFS_no_boot_record_message - _start1), %si
5568        call    print_message   /* CS:SI points to message string */
5569
5570        popw    %ax
5571        popl    %eax                    /* return_IP and SI */
5572        popfw
5573        stc
5574        pushfw
5575        pushl   %eax                    /* return_IP and SI */
5576        ret
5577#endif
5578
5579//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
5580move_helper:
5581
5582        /* called only once and only when the boot loader loaded this code */
5583        pushw   %si
5584        pushw   %bx
5585        pushl   %eax
5586
5587        movw    $0x0003, %ax    /* set display mode: 80*25 color text */
5588        int     $0x10
5589
5590        movw    $0x200, %si
5591        movw    %si, %di
5592        movw    $0xf00, %cx
5593        cld
5594        repz movsw
5595
5596        popl    %eax
5597        popw    %bx
5598        popw    %si
5599        ret
5600//#endif
5601
5602#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
5603filesystem_boot:
5604        /* The partition boot record successfully modified, just boot it */
5605
5606        /*
5607         * The boot might fail, but we want to take back the control.
5608         * So we save the registers now.
5609         */
5610        pushw   %ds
5611        pushw   %es
5612        pushal
5613
5614        /* DS=CS=GRLDR_CS, ES=FS_BOOT */
5615
5616        /* save GRLDR_CS */
5617
5618        movw    %es, %bx        # save old ES to BX
5619
5620        cli
5621        lgdt    gdt - _start1
5622        movl    %cr0, %eax
5623        orb     $1, %al
5624        movl    %eax, %cr0
5625
5626        movw    $8, %si
5627        movw    %si, %es
5628
5629        xorl    %esi, %esi
5630        xorl    %edi, %edi
5631        movl    $(0x9000 / 4), %ecx
5632
5633        cld
5634        repz movsl
5635
5636        movw    $16, %si
5637        movw    %si, %es
5638
5639        andb    $0xfe, %al
5640        movl    %eax, %cr0
5641
5642        movw    %bx, %es        # restore ES from BX
5643
5644        /* move FS_BOOT:0000 to 0:7c00 */
5645#if 0
5646        /* for single sector boot record */
5647        movw    $0x0200, %cx    /* move 2 sectors, the old FS_BOOT:0000 will
5648                                 * keep untouched.  */
5649#else
5650        /* for 4-sector NTFS boot record */
5651        movw    $0x0400, %cx    /* move 4 sectors, the old FS_BOOT:0000 will
5652                                 * keep untouched.  */
5653#endif
5654        xorw    %si, %si
5655        pushw   %si     /* SI=0, for the segment of 0000:7c00 */
5656        movw    $0x7c00, %di
5657        pushw   %di     /* DI=0x7c00, for the offset of 0000:7c00 */
5658        pushw   %es     /* ES=FS_BOOT */
5659        popw    %ds     /* DS=FS_BOOT */
5660        pushw   %si     /* SI=0 */
5661        popw    %es     /* ES=0 */
5662        cld
5663        repz movsw
5664
5665        movw    $MONITOR, %di
5666        movw    $(restore_GRLDR_CS - _start1), %si
5667        movw    $((gdt_end - restore_GRLDR_CS) / 4), %cx
5668        cld
5669        repz cs movsl           /* CS segment override prefix(=0x2E) */
5670
5671        pushw   %es     /* ES=0 */
5672        popw    %ds     /* DS=0 */
5673        sti
5674        lret    //ljmp  $0, $0x7c00
5675#endif
5676
5677press_space_bar_string:
5678        .ascii  "\r\nPress space bar\0"
5679
5680press_hot_key_pre:
5681        .ascii "\r\nPress \0"
5682
5683press_hot_key_sub:
5684        .ascii  " to start GRUB, any other key to boot previous MBR ...\0"
5685
5686hot_key_timeout_pre:
5687        .ascii "\r\nTimeout : \0"
5688
5689hot_key_timeout_num:
5690        .ascii "   \b\b\b\0"
5691
5692continue_string:
5693        .ascii  "\r\nInvalid previous MBR. Press any key to start GRUB ...\0"
5694
5695Cannot_find_GRLDR_string:
5696        .ascii  "\r\nCannot find GRLDR.\0"
5697
5698prev_MBR_string:
5699        .ascii  " to hold the screen, any other key to boot previous MBR ...\0"
5700
5701Error_while_reading_string:
5702        .ascii  "\r\nError while reading MBR of \0"
5703
5704drive_number_string:
5705        .ascii  "drive (hd0 ) \0"
5706
5707partition_boot_indicator_string:
5708        .ascii  "\r\nInvalid boot indicator in partition table of \0"
5709
5710partition_sectors_per_track_string:
5711        .ascii  "\r\nInvalid sectors_per_track in partition table of \0"
5712
5713partition_start_sector_string:
5714        .ascii  "\r\nInvalid start_sector in partition table of \0"
5715
5716partition_end_sector_string:
5717        .ascii  "\r\nInvalid end_sector in partition table of \0"
5718
5719no_boot_signature_string:
5720        .ascii  "\r\nNo boot signature in partition table of \0"
5721
5722message_string_helper:
5723        .ascii  "\r\nError: Cannot find GRLDR in all devices. Press Ctrl+Alt+Del to restart.\0"
5724
5725partition_message:
5726        .ascii  "\r\nTry (hd0,0 ) : \0"
5727
5728EXT2_message:
5729        .ascii  "EXT2: \0"
5730NTFS4_message:
5731        .ascii  "NTFS4: \0"
5732NTFS5_message:
5733        .ascii  "NTFS5: \0"
5734NTFS5p_message:
5735        .ascii  "NTFS5p: \0"
5736FAT32_message:
5737        .ascii  "FAT32: \0"
5738FAT16_message:
5739        .ascii  "FAT16: \0"
5740FAT12_message:
5741        .ascii  "FAT12: \0"
5742non_MS_message:
5743        .ascii  "non-MS: skip \0"
5744extended_message:
5745        .ascii  "Extended: \0"
5746invalid_message:
5747        .ascii  "invalid or null \0"
5748#if 0
5749NTFS_no_boot_record_message:
5750        .ascii  "This partition is NTFS but with unknown boot record. Please\r\ninstall Microsoft NTFS boot sectors to this partition correctly, or create an\r\nFAT12/16/32 partition and place the same copy of GRLDR and MENU.LST there.\0"
5751#endif
5752
5753#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
5754        . = _start1 + 0x1ffa
5755#else
5756        . = . + (0x3ec - ((. - _start1) % 0x200)) % 0x200
5757
5758press_hot_key_name:
5759
5760        /* hot key name, the address is (grldr_signature - 16) */
5761
5762        .ascii  "hot-key\0"
5763
5764        . = press_hot_key_name + 14
5765
5766        //. = . + (0x3fa - ((. - _start1) % 0x200)) % 0x200
5767#endif
5768
5769        /* version word of grldr.mbr, the address is (grldr_signature - 2) */
5770
5771        .word   2
5772
5773grldr_signature:
5774        .byte   0x47, 0x52, 0x55, 0xaa  /* signature for helper */
5775
5776        .align  0x200
5777
5778#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
5779
5780        /* pre_stage2 start at 0x2000 for grldr */
5781
5782        . = _start1 + 0x2000
5783
5784#endif
5785
5786#if defined(GRLDR_MBR)
5787        /* if the size is less than 8192, let it be 8192 */
5788        . = . + (0x2000 - (. - _start1)) * (0x4000 / (. - _start1 + 0x2001))
5789#endif
5790
5791pre_stage2_start:
5792
5793
Note: See TracBrowser for help on using the repository browser.