     1                                  ;
     2                                  ; File:
     3                                  ;                          oemboot.asm
     4                                  ;                      2004, Kenneth J. Davis
     5                                  ;                Copyright (c) 200?, <add name here>
     6                                  ; Description:
     7                                  ; OEM boot sector for FreeDOS compatible with IBM's (R) PC-DOS,
     8                                  ; and Microsoft's (R) MS-DOS.  It may work with older OpenDOS/DR-DOS,
     9                                  ; although the standard FreeDOS boot sector is needed with ver 7+
    10                                  ; releases.  May work with other versions of DOS that use
    11                                  ; IBMBIO.COM/IBMDOS.COM pair.  This boot sector loads only up
    12                                  ; to 58 sectors (29KB) of the kernel (IBMBIO.COM) to 0x70:0 then
    13                                  ; jumps to it.  As best I can tell, PC-DOS (and MS-DOS up to version
    14                                  ; 6.xx behaves similar) expects on entry for:
    15                                  ; ch = media id byte in the boot sector
    16                                  ; dl = BIOS drive booted from (0x00=A:, 0x80=C:, ...)
    17                                  ; ax:bx = the starting (LBA) sector of cluster 2 (ie the 1st
    18                                  ; data sector, which is 0x0000:0021 for FAT12)
    19                                  ; ?note? IBMBIO.COM/IO.SYS may use ax:bx and cluster # stored
    20                                  ; elsewhere (perhaps dir entry still at 0x50:0) to determine
    21                                  ; starting sector for full loading of kernel file.
    22                                  ; it also expects the boot sector (in particular the BPB)
    23                                  ; to still be at 0x0:7C00, the directory entry for IBMBIO.COM
    24                                  ; (generally first entry of first sector of the root directory)
    25                                  ; at 0x50:0 (DOS Data Area).  The original boot sector may update
    26                                  ; the floppy disk parameter table (int 1Eh), but we don't so
    27                                  ; may fail for any systems where the changes (???) are needed.
    28                                  ; If the above conditions are not met, then IBMBIO.COM will
    29                                  ; print the not a bootable disk error message.
    30                                  ;
    31                                  ; For MS-DOS >= 7 (ie Win9x DOS) the following conditions
    32                                  ; must be met:
    33                                  ; bp = 0x7C00, ie offset boot sector loaded at
    34                                  ; [bp-4] = the starting (LBA) sector of cluster 2 (ie the 1st
    35                                  ; data sector [this is the same as ax:bx for earlier versions
    36                                  ; and dx:ax in Win9x boot sector]
    37                                  ; The starting cluster of the kernel file is stored in
    38                                  ; di for FAT 12/16 (where si is a don't care) and si:di
    39                                  ; for FAT 32.
    40                                  ; The values for ax,bx,cx,dx,ds and the stack do not
    41                                  ; seem to be important (used by IO.SYS) and so may be any value
    42                                  ; (though dx:ax=[data_start], cx=0, bx=0x0f00 on FAT12 or
    43                                  ; 0x0700 on FAT32, ds=0, ss:sp=0:7b??)
    44                                  
    45                                  ; the boot time stack may store the original int1E floppy
    46                                  ; parameter table, otherwise nothing else important seems
    47                                  ; stored there and I am unsure if even this value is used
    48                                  ; beyond boot sector code.
    49                                  
    50                                  ;
    51                                  ; This boot sector only supports FAT12/FAT16 as PC-DOS
    52                                  ; does not support FAT32 and newer FAT32 capable DOSes
    53                                  ; probably have different boot requirements; also do NOT
    54                                  ; use it to boot the FreeDOS kernel as it expects to be
    55                                  ; fully loaded by boot sector (> 29KB & usually to 0x60:0).
    56                                  ;
    57                                  ; WARNING: PC-DOS has additional requirements, in particular,
    58                                  ; it may expect that IBMBIO.COM and IBMDOS.COM be the 1st
    59                                  ; two entries in the root directory (even before the label)
    60                                  ; and that they occupy the 1st consecutive data sectors.
    61                                  ; Newer releases may support other positions, but still
    62                                  ; generally should occupy consecutive sectors. These conditions
    63                                  ; can usually be met by running sys on a freshly formatted
    64                                  ; and un-label'd disk.
    65                                  ;
    66                                  ;
    67                                  ; Derived From:
    68                                  ;                            boot.asm
    69                                  ;                           DOS-C boot
    70                                  ;
    71                                  ;                   Copyright (c) 1997, 2000-2004
    72                                  ;               Svante Frey, Jim Hall, Jim Tabor, Bart Oldeman,
    73                                  ;             Tom Ehlert, Eric Auer, Luchezar Georgiev, Jon Gentle
    74                                  ;             and Michal H. Tyc (DR-DOS adaptation, boot26dr.asm)
    75                                  ;                      All Rights Reserved
    76                                  ;
    77                                  ; This file is part of FreeDOS.
    78                                  ;
    79                                  ; DOS-C is free software; you can redistribute it and/or
    80                                  ; modify it under the terms of the GNU General Public License
    81                                  ; as published by the Free Software Foundation; either version
    82                                  ; 2, or (at your option) any later version.
    83                                  ;
    84                                  ; DOS-C is distributed in the hope that it will be useful, but
    85                                  ; WITHOUT ANY WARRANTY; without even the implied warranty of
    86                                  ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
    87                                  ; the GNU General Public License for more details.
    88                                  ;
    89                                  ; You should have received a copy of the GNU General Public
    90                                  ; License along with DOS-C; see the file COPYING.  If not,
    91                                  ; write to the Free Software Foundation, 675 Mass Ave,
    92                                  ; Cambridge, MA 02139, USA.
    93                                  ;
    94                                  ;
    95                                  ;	+--------+
    96                                  ;	| CLUSTER|
    97                                  ;	|  LIST  |
    98                                  ;	|--------| 0000:7F00
    99                                  ;	|LBA PKT |
   100                                  ;	|--------| 0000:7E00  (0:BP+200)
   101                                  ;	|BOOT SEC| contains BPB
   102                                  ;	|ORIGIN  | 
   103                                  ;	|--------| 0000:7C00  (0:BP)
   104                                  ;	|VARS    | only known is 1st data sector (start of cluster 2)
   105                                  ;	|--------| 0000:7BFC  (DS:[BP-4])
   106                                  ;	|STACK   | minimal 256 bytes (1/2 sector)
   107                                  ;	|- - - - |
   108                                  ;	|KERNEL  | kernel loaded here (max 58 sectors, 29KB)
   109                                  ;	|LOADED  | also used as FAT buffer
   110                                  ;	|--------| 0070:0000 (0:0700)
   111                                  ;	|DOS DA/ | DOS Data Area,
   112                                  ;	|ROOT DIR| during boot contains directory entries
   113                                  ;	|--------| 0000:0500
   114                                  ;	|BDA     | BIOS Data Area
   115                                  ;	+--------+ 0000:0400
   116                                  ;	|IVT     | Interrupt Vector Table
   117                                  ;	+--------+ 0000:0000
   118                                  
   119                                  CPU 8086  ; enable assembler warnings to limit instruction set
   120                                  
   121                                  ;%define ISFAT12         1              ; only 1 of these should be set,
   122                                  ;%define ISFAT16         1              ; defines which FAT is supported
   123                                  
   124                                  %define TRYLBAREAD       1              ; undefine to use only CHS int 13h
   125                                  %define SETROOTDIR       1              ; if defined dir entry copied to 0:500
   126                                  %define LOOPONERR        1              ; if defined on error simply loop forever
   127                                  ;%define RETRYALWAYS     1              ; if defined retries read forever
   128                                  ;%define WINBOOT         1              ; use win9x kernel calling conventions (name & jmp addr)
   129                                  ;%define MSCOMPAT        1              ; sets default filename to MSDOS IO.SYS
   130                                  
   131                                  %ifdef WINBOOT                          ; if set also change from PC-DOS to 
   132                                  %ifndef MSCOMPAT                        ; kernel name to MS-DOS kernel name
   133                                  %define MSCOMPAT
   134                                  %endif
   135                                  %endif
   136                                  
   137                                  segment	.text
   138                                  
   139                                  %define BASE            0x7c00          ; boot sector originally at 0x0:BASE
   140                                  %define LOADSEG         0x0070          ; segment to load kernel at LOADSEG:0
   141                                  %define LOADEND         0x07b0          ; limit reads to below this segment
   142                                                                          ; LOADSEG+29KB, else data overwritten
   143                                  
   144                                  %define FATBUF          bp-0x7500       ; offset of temporary buffer for FAT
   145                                                                          ; chain 0:FATBUF = 0:0700 = LOADSEG:0
   146                                  %define ROOTDIR         0x7C00-0x7700   ; offset to buffer for root directory
   147                                                                          ; entry of kernel 0:ROOTDIR
   148                                  %define CLUSTLIST       bp+0x0300       ; zero terminated list of clusters
   149                                                                          ; that the kernel occupies
   150                                  
   151                                  ;       Some extra variables
   152                                  ; using bp-Entry+variable_name generates smaller code than using just
   153                                  ; variable_name, where bp is initialized to Entry, so bp-Entry equals 0
   154                                  
   155                                  %define LBA_PACKET      bp+0x0200            ; immediately after boot sector
   156                                  %define LBA_SIZE        word [LBA_PACKET]    ; size of packet, should be 10h
   157                                  %define LBA_SECNUM      word [LBA_PACKET+2]  ; number of sectors to read
   158                                  %define LBA_OFF         LBA_PACKET+4         ; buffer to read/write to
   159                                  %define LBA_SEG         LBA_PACKET+6
   160                                  %define LBA_SECTOR_0    word [LBA_PACKET+8 ] ; LBA starting sector #
   161                                  %define LBA_SECTOR_16   word [LBA_PACKET+10]
   162                                  %define LBA_SECTOR_32   word [LBA_PACKET+12]
   163                                  %define LBA_SECTOR_48   word [LBA_PACKET+14]
   164                                  
   165                                  %define PARAMS LBA_PACKET+0x10
   166                                  ;%define RootDirSecs      PARAMS+0x0        ; # of sectors root dir uses
   167                                  %define fat_start        PARAMS+0x2         ; first FAT sector
   168                                  ;%define root_dir_start   PARAMS+0x6        ; first root directory sector
   169                                  %define first_cluster    PARAMS+0x0a        ; starting cluster of kernel file
   170                                  %define data_start       bp-4               ; first data sector (win9x expects here)
   171                                  
   172                                  ;-----------------------------------------------------------------------
   173                                  
   174                                  
   175                                                  org     BASE
   176                                  
   177 00000000 EB3C                    Entry:          jmp     short real_start
   178 00000002 90                                      nop
   179                                  
   180                                  ;       bp is initialized to 7c00h
   181                                  %define bsOemName       bp+0x03      ; OEM label
   182                                  %define bsBytesPerSec   bp+0x0b      ; bytes/sector
   183                                  %define bsSecPerClust   bp+0x0d      ; sectors/allocation unit
   184                                  %define bsResSectors    bp+0x0e      ; # reserved sectors
   185                                  %define bsFATs          bp+0x10      ; # of fats
   186                                  %define bsRootDirEnts   bp+0x11      ; # of root dir entries
   187                                  %define bsSectors       bp+0x13      ; # sectors total in image
   188                                  %define bsMedia         bp+0x15      ; media descrip: fd=2side9sec, etc...
   189                                  %define sectPerFat      bp+0x16      ; # sectors in a fat
   190                                  %define sectPerTrack    bp+0x18      ; # sectors/track
   191                                  %define nHeads          bp+0x1a      ; # heads
   192                                  %define nHidden         bp+0x1c      ; # hidden sectors
   193                                  %define nSectorHuge     bp+0x20      ; # sectors if > 65536
   194                                  %define drive           bp+0x24      ; drive number
   195                                  %define extBoot         bp+0x26      ; extended boot signature
   196                                  %define volid           bp+0x27
   197                                  %define vollabel        bp+0x2b
   198                                  %define filesys         bp+0x36
   199                                  
   200                                  
   201                                  ;-----------------------------------------------------------------------
   202                                  
   203                                  ;               times   0x3E-$+$$ db 0
   204                                  ;
   205                                  ;       Instead of zero-fill,
   206                                  ;       initialize BPB with values suitable for a 1440 K floppy
   207                                  ;
   208 00000003 49424D2020352E30                        db 'IBM  5.0'   ; OEM label
   209 0000000B 0002                                    dw 512          ; bytes per sector
   210 0000000D 01                                      db 1            ; sectors per cluster
   211 0000000E 0100                                    dw 1            ; reserved sectors
   212 00000010 02                                      db 2            ; number of FATs
   213 00000011 E000                                    dw 224          ; root directory entries
   214 00000013 400B                                    dw 80 * 36      ; total sectors on disk
   215 00000015 F0                                      db 0xF0         ; media descriptor
   216 00000016 0900                                    dw 9            ; sectors per 1 FAT copy
   217 00000018 1200                                    dw 18           ; sectors per track
   218 0000001A 0200                                    dw 2            ; number of heads
   219 0000001C 00000000                                dd 0            ; hidden sectors
   220 00000020 00000000                                dd 0            ; big total sectors
   221 00000024 00                                      db 0            ; boot unit
   222 00000025 00                                      db 0            ; reserved
   223 00000026 29                                      db 0x29         ; extended boot record id
   224 00000027 78563412                                dd 0x12345678   ; volume serial number
   225 0000002B 4E4F204E414D452020-                     db 'NO NAME    '; volume label
   225 00000034 2020               
   226                                                  times   36h - ($ - $$) db 0
   227                                                  ; The filesystem ID is used by lDOS's instsect (by ecm)
   228                                                  ;  by default to validate that the filesystem matches.
   229                                  %ifdef ISFAT12
   230                                                  db "FAT12"     ; filesystem id
   231                                   %ifdef ISFAT16
   232                                   %error Must select one FS
   233                                   %endif
   234                                  %elifdef ISFAT16
   235 00000036 4641543136                              db "FAT16"
   236                                  %else
   237                                   %error Must select one FS
   238                                  %endif
   239 0000003B 20<rep 3h>                              times   3Eh - ($ - $$) db 32
   240                                  
   241                                  ;-----------------------------------------------------------------------
   242                                  ;   ENTRY
   243                                  ;-----------------------------------------------------------------------
   244                                  
   245                                  real_start:
   246 0000003E FA                                      cli             ; disable interrupts until stack ready
   247 0000003F FC                                      cld             ; all string operations increment
   248 00000040 31C0                                    xor     ax, ax  ; ensure our segment registers ready
   249 00000042 8ED8                                    mov     ds, ax  ; cs=ds=es=ss=0x0000
   250 00000044 8EC0                                    mov     es, ax
   251 00000046 8ED0                                    mov     ss, ax
   252 00000048 BD007C                                  mov     bp, BASE
   253 0000004B 8D66FC                                  lea     sp, [bp-4] ; for DOS <7 this may be [bp]
   254                                  
   255                                  ;       For compatibility, diskette parameter vector updated.
   256                                  ;               lea     di  [bp+0x3E] ; use 7c3e([bp+3e]) for PC-DOS,
   257                                  ;               ;lea     di  [bp]     ; but 7c00([bp]) for DR-DOS 7 bug
   258                                  ;               mov     bx, 4 * 1eh   ; stored at int 1E's vector
   259                                  ;               lds     si, [bx]      ; fetch current int 1eh pointer
   260                                  ;               push    ds            ; store original 1eh pointer at stack top
   261                                  ;               push    si            ; so can restore later if needed
   262                                  ;
   263                                  ;       Copy table to new location
   264                                  ;               mov     cl, 11        ; the parameter table is 11 bytes
   265                                  ;               rep     movsb         ; and copy the parameter block
   266                                  ;               mov     ds, ax        ; restore DS
   267                                  ;
   268                                  ;       Note: make desired changes to table here
   269                                  ;
   270                                  ;       Update int1E to new location
   271                                  ;               mov     [bx+2], 0     ; set to 0:bp or 0:bp+3e as appropriate
   272                                  ;               mov     word [bx], 0x7c3e ; (use 0x7c00 for DR-DOS)
   273                                  
   274 0000004E FB                                      sti             ; enable interrupts
   275                                  
   276                                  ;       If updated floppy parameter table then must notify BIOS
   277                                  ;       Otherwise a reset should not be needed here.
   278                                  ;               int     0x13    ; reset drive (AX=0)
   279                                  
   280                                  ;
   281                                  ; Note: some BIOS implementations may not correctly pass drive number
   282                                  ; in DL, however we work around this in SYS.COM by NOP'ing out the use of DL
   283                                  ; (formerly we checked for [drive]==0xff; update sys.c if code moves)
   284                                  ;
   285 0000004F 885624                                  mov     [drive], dl        ; rely on BIOS drive number in DL
   286                                  
   287                                  
   288                                  ;       GETDRIVEPARMS:  Calculate start of some disk areas.
   289                                  ;
   290 00000052 8B761C                                  mov     si, word [nHidden]
   291 00000055 8B7E1E                                  mov     di, word [nHidden+2]
   292 00000058 03760E                                  add     si, word [bsResSectors]
   293 0000005B 83D700                                  adc     di, byte 0              ; DI:SI = first FAT sector
   294                                  
   295 0000005E 89B61202                                mov     word [fat_start], si
   296 00000062 89BE1402                                mov     word [fat_start+2], di
   297                                  
   298 00000066 8A4610                                  mov     al, [bsFATs]
   299 00000069 98                                      cbw
   300 0000006A F76616                                  mul     word [sectPerFat]       ; DX:AX = total number of FAT sectors
   301                                  
   302 0000006D 01C6                                    add     si, ax
   303 0000006F 11D7                                    adc     di, dx                  ; DI:SI = first root directory sector
   304 00000071 57                                      push di                         ; mov word [root_dir_start+2], di
   305 00000072 56                                      push si                         ; mov word [root_dir_start], si
   306                                  
   307                                                  ; Calculate how many sectors the root directory occupies.
   308 00000073 8B5E0B                                  mov     bx, [bsBytesPerSec]
   309 00000076 B105                                    mov     cl, 5                   ; divide BX by 32
   310 00000078 D3EB                                    shr     bx, cl                  ; BX = directory entries per sector
   311                                  
   312 0000007A 8B4611                                  mov     ax, [bsRootDirEnts]
   313 0000007D 31D2                                    xor     dx, dx
   314 0000007F F7F3                                    div     bx                      ; set AX = sectors per root directory
   315 00000081 50                                      push    ax                      ; mov word [RootDirSecs], ax
   316                                  
   317 00000082 01C6                                    add     si, ax
   318 00000084 83D700                                  adc     di, byte 0              ; DI:SI = first data sector
   319                                  
   320 00000087 8976FC                                  mov     [data_start], si
   321 0000008A 897EFE                                  mov     [data_start+2], di
   322                                  
   323                                  
   324                                  ;       FINDFILE: Searches for the file in the root directory.
   325                                  ;
   326                                  ;       Returns:
   327                                  ;                               AX = first cluster of file
   328                                  
   329                                                  ; First, read the root directory into buffer.
   330                                                  ; into the temporary buffer. (max 29KB or overruns stuff)
   331                                  
   332 0000008D 5F                                      pop     di              ; mov di, word [RootDirSecs]
   333 0000008E 58                                      pop     ax              ; mov ax, word [root_dir_start]
   334 0000008F 5A                                      pop     dx              ; mov dx, word [root_dir_start+2]
   335 00000090 BB0005                                  mov     bx, ROOTDIR     ; es:bx = 0:0500
   336 00000093 06                                      push    es              ; save pointer to ROOTDIR
   337 00000094 E8B100                                  call    readDisk
   338 00000097 07                                      pop     es              ; restore pointer to ROOTDIR
   339 00000098 BE0005                                  mov     si, ROOTDIR     ; ds:si = 0:0500
   340                                  
   341                                  
   342                                  		; Search for kernel file name, and find start cluster.
   343                                  
   344 0000009B B90B00                  next_entry:     mov     cx, 11
   345 0000009E BF[F101]                                mov     di, filename
   346 000000A1 56                                      push    si
   347 000000A2 F3A6                                    repe    cmpsb
   348 000000A4 5E                                      pop     si
   349 000000A5 8B441A                                  mov     ax, [si+0x1A]; get cluster number from directory entry
   350 000000A8 740C                                    je      ffDone
   351                                  
   352 000000AA 83C620                                  add     si, byte 0x20   ; go to next directory entry
   353 000000AD 726D                                    jc      boot_error      ; fail if not found and si wraps
   354 000000AF 803C00                                  cmp     byte [si], 0    ; if the first byte of the name is 0,
   355 000000B2 75E7                                    jnz     next_entry      ; there are no more files in the directory
   356 000000B4 EB66                                    jmp     boot_error
   357                                  
   358                                  ffDone:
   359 000000B6 89861A02                                mov [first_cluster], ax ; store first cluster number
   360                                  
   361                                  %ifdef SETROOTDIR
   362                                                  ; copy over this portion of root dir to 0x0:500 for PC-DOS
   363                                                  ; (this may allow IBMBIO.COM to start in any directory entry)
   364 000000BA BF0005                                  mov     di, ROOTDIR     ; es:di = 0:0500
   365 000000BD B92000                                  mov     cx, 32          ; limit to this 1 entry (rest don't matter)
   366 000000C0 F3A5                                    rep     movsw
   367                                  %endif
   368                                  
   369                                  ;       GETFATCHAIN:
   370                                  ;
   371                                  ;       Reads the FAT chain and stores it in a temporary buffer in the first
   372                                  ;       64 kb.  The FAT chain is stored an array of 16-bit cluster numbers,
   373                                  ;       ending with 0.
   374                                  ;
   375                                  ;       The file must fit in conventional memory, so it can't be larger than
   376                                  ;       640 kb. The sector size must be at least 512 bytes, so the FAT chain
   377                                  ;       can't be larger than 2.5 KB (655360 / 512 * 2 = 2560).
   378                                  ;
   379                                  ;       Call with:      AX = first cluster in chain
   380                                  
   381                                                  ; Load the complete FAT into memory. The FAT can't be larger
   382                                                  ; than 128 kb
   383 000000C2 8D9E008B                                lea     bx, [FATBUF]            ; es:bx = 0:0700
   384 000000C6 8B7E16                                  mov     di, [sectPerFat]
   385 000000C9 8B861202                                mov     ax, word [fat_start]
   386 000000CD 8B961402                                mov     dx, word [fat_start+2]
   387 000000D1 E87400                                  call    readDisk
   388                                  
   389                                                  ; Set ES:DI to the temporary storage for the FAT chain.
   390 000000D4 1E                                      push    ds
   391 000000D5 07                                      pop     es
   392 000000D6 8DBE0003                                lea     di, [CLUSTLIST]
   393                                                  ; Set DS:0 to FAT data we loaded
   394 000000DA B87000                                  mov     ax, LOADSEG
   395 000000DD 8ED8                                    mov     ds, ax                  ; ds:0 = 0x70:0 = 0:FATBUF
   396                                  
   397 000000DF 8B861A02                                mov ax, [first_cluster]         ; restore first cluster number
   398 000000E3 1E                                      push    ds                      ; store LOADSEG
   399                                  
   400 000000E4 AB                      next_clust:     stosw                           ; store cluster number
   401 000000E5 89C6                                    mov     si, ax                  ; SI = cluster number
   402                                  
   403                                  %ifdef ISFAT12
   404                                                  ; This is a FAT-12 disk.
   405                                  
   406                                  fat_12:         add     si, si          ; multiply cluster number by 3...
   407                                                  add     si, ax
   408                                                  shr     si, 1           ; ...and divide by 2
   409                                                  lodsw
   410                                  
   411                                                  ; If the cluster number was even, the cluster value is now in
   412                                                  ; bits 0-11 of AX. If the cluster number was odd, the cluster
   413                                                  ; value is in bits 4-15, and must be shifted right 4 bits. If
   414                                                  ; the number was odd, CF was set in the last shift instruction.
   415                                  
   416                                                  mov     cl, 4           ; always initialise shift counter
   417                                                  jc      fat_odd         ; is odd, only shift down -->
   418                                                  shl     ax, cl          ; shift up (effectively masks off
   419                                                                          ;  the highest 4 bits)
   420                                  fat_odd:
   421                                                  shr     ax, cl
   422                                                  cmp     ax, 0x0ff8      ; check for EOF
   423                                                  jb      next_clust      ; continue if not EOF
   424                                  
   425                                  %endif
   426                                  %ifdef ISFAT16
   427                                                  ; This is a FAT-16 disk. The maximal size of a 16-bit FAT
   428                                                  ; is 128 kb, so it may not fit within a single 64 kb segment.
   429                                  
   430 000000E7 BA7000                  fat_16:         mov     dx, LOADSEG
   431 000000EA 01F6                                    add     si, si          ; multiply cluster number by two
   432 000000EC 7303                                    jnc     first_half      ; if overflow...
   433 000000EE 80C610                                  add     dh, 0x10        ; ...add 64 kb to segment value
   434                                  
   435 000000F1 8EDA                    first_half:     mov     ds, dx          ; DS:SI = pointer to next cluster
   436 000000F3 AD                                      lodsw                   ; AX = next cluster
   437                                  
   438 000000F4 83F8F8                                  cmp     ax, 0xfff8      ; >= FFF8 = 16-bit EOF
   439 000000F7 72EB                                    jb      next_clust      ; continue if not EOF
   440                                  %endif
   441                                  
   442                                  finished:       ; Mark end of FAT chain with 0, so we have a single
   443                                                  ; EOF marker for both FAT-12 and FAT-16 systems.
   444                                  
   445 000000F9 31C0                                    xor     ax, ax
   446 000000FB AB                                      stosw
   447                                  
   448 000000FC 0E                                      push    cs
   449 000000FD 1F                                      pop     ds
   450                                  
   451                                  
   452                                  ;       loadFile: Loads the file into memory, one cluster at a time.
   453                                  
   454 000000FE 07                                      pop     es              ; set ES:BX to load address 70:0
   455 000000FF 31DB                                    xor     bx, bx
   456                                  
   457 00000101 8DB60003                                lea     si, [CLUSTLIST] ; set DS:SI to the FAT chain
   458                                  
   459 00000105 AD                      cluster_next:   lodsw                   ; AX = next cluster to read
   460 00000106 09C0                                    or      ax, ax          ; EOF?
   461 00000108 751A                                    jne     load_next       ; no, continue
   462                                  
   463                                                                          ; dl set to drive by readDisk
   464 0000010A 8A6E15                                  mov ch, [bsMedia]       ; ch set to media id
   465 0000010D 8B46FE                                  mov ax, [data_start+2]  ; ax:bx set to 1st data sector
   466 00000110 8B5EFC                                  mov bx, [data_start]    ;
   467 00000113 8BBE1A02                                mov di, [first_cluster] ; set di (si:di on FAT32) to starting cluster #
   468                                  %ifdef WINBOOT
   469                                                  jmp     LOADSEG:0x0200  ; yes, pass control to kernel
   470                                  %else                
   471 00000117 EA00007000                              jmp     LOADSEG:0000    ; yes, pass control to kernel
   472                                  %endif
   473                                  
   474                                  
   475                                  ; failed to boot
   476                                  boot_error:     
   477 0000011C E82100                  call            show
   478                                  ;               db      "Error! Hit a key to reboot.",0
   479 0000011F 293A00                                  db      "):",0
   480                                  %ifdef LOOPONERR
   481 00000122 EBFE                    jmp $
   482                                  %else
   483                                  
   484                                                  ; Note: should restore floppy paramater table address at int 0x1E
   485                                                  xor     ah,ah
   486                                                  int     0x13                    ; reset floppy
   487                                                  int     0x16                    ; wait for a key
   488                                                  int     0x19                    ; reboot the machine
   489                                  %endif
   490                                  
   491                                  
   492 00000124 48                      load_next:      dec     ax                      ; cluster numbers start with 2
   493 00000125 48                                      dec     ax
   494                                  
   495 00000126 8B7E0D                                  mov     di, word [bsSecPerClust]
   496 00000129 4F                                      dec     di                      ; minus one if 256 spc
   497 0000012A 81E7FF00                                and     di, 0xff                ; DI = sectors per cluster - 1
   498 0000012E 47                                      inc     di                      ; = spc
   499 0000012F F7E7                                    mul     di
   500 00000131 0346FC                                  add     ax, [data_start]
   501 00000134 1356FE                                  adc     dx, [data_start+2]      ; DX:AX = first sector to read
   502 00000137 E80E00                                  call    readDisk
   503 0000013A EBC9                                    jmp     short cluster_next
   504                                  
   505                                  
   506                                  ; shows text after the call to this function.
   507                                  
   508                                  show.do_show:
   509 0000013C B40E                                    mov     ah, 0Eh                 ; show character
   510 0000013E CD10                                    int     10h                     ; via "TTY" mode
   511 00000140 5E                      show:           pop     si
   512 00000141 AC                                      lodsb                           ; get character
   513 00000142 56                                      push    si                      ; stack up potential return address
   514 00000143 3C00                                    cmp     al, 0                   ; end of string?
   515 00000145 75F5                                    jne     .do_show                ; until done
   516 00000147 C3                                      ret
   517                                  
   518                                  
   519                                  ;       readDisk:       Reads a number of sectors into memory.
   520                                  ;
   521                                  ;       Call with:      DX:AX = 32-bit DOS sector number
   522                                  ;                       DI = number of sectors to read
   523                                  ;                       ES:BX = destination buffer
   524                                  ;
   525                                  ;       Returns:        CF set on error
   526                                  ;                       ES:BX points one byte after the last byte read.
   527                                  ;                       Exits early if LBA_SEG == LOADEND.
   528                                  
   529 00000148 56                      readDisk:       push    si                      ; preserve cluster #
   530                                  
   531 00000149 89860802                                mov     LBA_SECTOR_0,ax
   532 0000014D 89960A02                                mov     LBA_SECTOR_16,dx
   533 00000151 8C860602                                mov     word [LBA_SEG], es
   534 00000155 899E0402                                mov     word [LBA_OFF], bx
   535                                  
   536 00000159 E8E4FF                                  call    show
   537 0000015C 2E00                                    db      ".",0
   538                                  read_next:
   539                                  
   540                                  ; initialize constants
   541 0000015E C78600021000                            mov     LBA_SIZE, 10h           ; LBA packet is 16 bytes
   542 00000164 C78602020100                            mov     LBA_SECNUM,1            ; reset LBA count if error
   543                                  
   544                                  ; limit kernel loading to 29KB, preventing stack & boot sector being overwritten
   545 0000016A 81BE0602B007                            cmp     word [LBA_SEG], LOADEND ; skip reading if past the end
   546 00000170 7476                                    je      read_skip               ; of kernel file buffer
   547                                  
   548                                  ;******************** LBA_READ *******************************
   549                                  
   550                                  						; check for LBA support
   551                                  										
   552                                  %ifdef TRYLBAREAD
   553 00000172 B441                                    mov     ah,041h                 ;
   554 00000174 BBAA55                                  mov     bx,055aah               ;
   555 00000177 8A5624                                  mov     dl, [drive]             ; BIOS drive, 0=A:, 80=C:
   556 0000017A 84D2                                    test    dl,dl                   ; don't use LBA addressing on A:
   557 0000017C 741C                                    jz      read_normal_BIOS        ; might be a (buggy)
   558                                                                                  ; CDROM-BOOT floppy emulation
   559 0000017E CD13                                    int     0x13
   560 00000180 7218                                    jc	read_normal_BIOS
   561                                  
   562 00000182 D1E9                                    shr     cx,1                    ; CX must have 1 bit set
   563                                  
   564 00000184 81DB54AA                                sbb     bx,0aa55h - 1           ; tests for carry (from shr) too!
   565 00000188 7510                                    jne     read_normal_BIOS
   566                                                                                  ; OK, drive seems to support LBA addressing
   567 0000018A 8DB60002                                lea     si,[LBA_PACKET]
   568                                                                                  ; setup LBA disk block
   569 0000018E 899E0C02                                mov     LBA_SECTOR_32,bx        ; bx is 0 if extended 13h mode supported
   570 00000192 899E0E02                                mov     LBA_SECTOR_48,bx
   571                                  	
   572                                  
   573 00000196 B442                                    mov     ah,042h
   574 00000198 EB29                                    jmp short    do_int13_read
   575                                  %endif
   576                                  
   577                                  							
   578                                  
   579                                  read_normal_BIOS:      
   580                                  
   581                                  ;******************** END OF LBA_READ ************************
   582 0000019A 8B8E0802                                mov     cx, LBA_SECTOR_0
   583 0000019E 8B960A02                                mov     dx, LBA_SECTOR_16
   584                                  
   585                                                  ;
   586                                                  ; translate sector number to BIOS parameters
   587                                                  ;
   588                                                  ;
   589                                                  ; abs = sector                          offset in track
   590                                                  ;     + head * sectPerTrack             offset in cylinder
   591                                                  ;     + track * sectPerTrack * nHeads   offset in platter
   592                                                  ;
   593 000001A2 8A4618                                  mov     al, [sectPerTrack]
   594 000001A5 F6661A                                  mul     byte [nHeads]
   595 000001A8 91                                      xchg    ax, cx
   596                                                  ; cx = nHeads * sectPerTrack <= 255*63
   597                                                  ; dx:ax = abs
   598 000001A9 F7F1                                    div     cx
   599                                                  ; ax = track, dx = sector + head * sectPertrack
   600 000001AB 92                                      xchg    ax, dx
   601                                                  ; dx = track, ax = sector + head * sectPertrack
   602 000001AC F67618                                  div     byte [sectPerTrack]
   603                                                  ; dx =  track, al = head, ah = sector
   604 000001AF 89D1                                    mov     cx, dx
   605                                                  ; cx =  track, al = head, ah = sector
   606                                  
   607                                                  ; the following manipulations are necessary in order to
   608                                                  ; properly place parameters into registers.
   609                                                  ; ch = cylinder number low 8 bits
   610                                                  ; cl = 7-6: cylinder high two bits
   611                                                  ;      5-0: sector
   612 000001B1 88C6                                    mov     dh, al                  ; save head into dh for bios
   613 000001B3 86E9                                    xchg    ch, cl                  ; set cyl no low 8 bits
   614 000001B5 D0C9                                    ror     cl, 1                   ; move track high bits into
   615 000001B7 D0C9                                    ror     cl, 1                   ; bits 7-6 (assumes top = 0)
   616 000001B9 08E1                                    or      cl, ah                  ; merge sector into cylinder
   617 000001BB 41                                      inc     cx                      ; make sector 1-based (1-63)
   618                                  
   619 000001BC C49E0402                                les     bx,[LBA_OFF]
   620 000001C0 B80102                                  mov     ax, 0x0201
   621                                  do_int13_read:                
   622 000001C3 8A5624                                  mov     dl, [drive]
   623 000001C6 CD13                                    int     0x13
   624                                  
   625                                  read_finished:
   626                                  %ifdef RETRYALWAYS
   627                                                  jnc     read_ok                 ; jump if no error
   628                                                  xor     ah, ah                  ; else, reset floppy
   629                                                  int     0x13
   630                                  read_next_chained:
   631                                                  jmp     short read_next         ; read the same sector again
   632                                  %else
   633 000001C8 7303E94FFF                              jc      boot_error              ; exit on error
   634                                  %endif
   635                                  
   636                                  read_ok:
   637 000001CD 8B460B                                  mov     ax, word [bsBytesPerSec]  
   638 000001D0 B104                                    mov     cl, 4                   ; adjust segment pointer by increasing
   639 000001D2 D3E8                                    shr     ax, cl
   640 000001D4 01860602                                add     word [LBA_SEG], ax      ; by paragraphs read in (per sector)
   641                                  
   642 000001D8 8386080201                              add     LBA_SECTOR_0,  byte 1
   643 000001DD 83960A0200                              adc     LBA_SECTOR_16, byte 0   ; DX:AX = next sector to read
   644 000001E2 4F                                      dec     di                      ; if there is anything left to read,
   645                                  %ifdef RETRYALWAYS
   646                                                  jnz     read_next_chained       ; continue
   647                                  %else
   648 000001E3 7403E976FF                              jnz     read_next               ; continue
   649                                  %endif
   650                                  
   651                                  read_skip:
   652 000001E8 8E860602                                mov     es, word [LBA_SEG]      ; load adjusted segment value
   653                                                  ; clear carry: unnecessary since adc clears it
   654 000001EC 5E                                      pop     si
   655 000001ED C3                                      ret
   656                                  
   657 000001EE 00<rep 3h>                     times   0x01f1-$+$$ db 0
   658                                  %ifdef MSCOMPAT
   659                                  filename        db      "IO      SYS"
   660                                  %else
   661 000001F1 49424D42494F202043-     filename        db      "IBMBIO  COM"
   661 000001FA 4F4D               
   662                                  %endif
   663 000001FC 0000                                    db      0,0
   664                                  
   665 000001FE 55AA                    sign            dw      0xAA55
   666                                  
