1;------------------------------------------------------------------------------
2;*
3;*   Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
4;*   This program and the accompanying materials                          
5;*   are licensed and made available under the terms and conditions of the BSD License         
6;*   which accompanies this distribution.  The full text of the license may be found at        
7;*   http://opensource.org/licenses/bsd-license.php                                            
8;*                                                                                             
9;*   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
10;*   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
11;*   
12;*    bs16.asm
13;*  
14;*   Abstract:
15;*
16;------------------------------------------------------------------------------
17
18        .model  small
19        .stack
20        .486p
21        .code
22
23FAT_DIRECTORY_ENTRY_SIZE  EQU     020h
24FAT_DIRECTORY_ENTRY_SHIFT EQU     5
25BLOCK_SIZE                EQU     0200h
26BLOCK_MASK                EQU     01ffh
27BLOCK_SHIFT               EQU     9
28                                               ; "EFILDR_____"
29LOADER_FILENAME_PART1     EQU     04c494645h   ; "EFIL"
30LOADER_FILENAME_PART2     EQU     036315244h   ; "DR16"
31LOADER_FILENAME_PART3     EQU     020202036h   ; "6___"
32
33        org 0h
34Ia32Jump:
35  jmp   BootSectorEntryPoint  ; JMP inst                  - 3 bytes
36  nop
37
38OemId             db  "INTEL   "    ; OemId               - 8 bytes
39; BPB data below will be fixed by tool
40SectorSize        dw  0             ; Sector Size         - 16 bits
41SectorsPerCluster db  0             ; Sector Per Cluster  - 8 bits
42ReservedSectors   dw  0             ; Reserved Sectors    - 16 bits
43NoFats            db  0             ; Number of FATs      - 8 bits
44RootEntries       dw  0             ; Root Entries        - 16 bits
45Sectors           dw  0             ; Number of Sectors   - 16 bits
46Media             db  0             ; Media               - 8 bits  - ignored
47SectorsPerFat     dw  0             ; Sectors Per FAT     - 16 bits
48SectorsPerTrack   dw  0             ; Sectors Per Track   - 16 bits - ignored
49Heads             dw  0             ; Heads               - 16 bits - ignored
50HiddenSectors     dd  0             ; Hidden Sectors      - 32 bits - ignored
51LargeSectors      dd  0             ; Large Sectors       - 32 bits 
52PhysicalDrive     db  0             ; PhysicalDriveNumber - 8 bits  - ignored
53CurrentHead       db  0             ; Current Head        - 8 bits
54Signature         db  0             ; Signature           - 8 bits  - ignored
55Id                db  "    "        ; Id                  - 4 bytes
56FatLabel          db  "           " ; Label               - 11 bytes
57SystemId          db  "FAT16   "    ; SystemId            - 8 bytes
58
59BootSectorEntryPoint:
60        ASSUME  ds:@code
61        ASSUME  ss:@code
62
63; ****************************************************************************
64; Start Print
65; ****************************************************************************
66  lea  si, cs:[StartString]
67  call PrintString
68
69; ****************************************************************************
70; Print over
71; ****************************************************************************
72
73  mov   ax,cs         ; ax = 0
74  mov   ss,ax         ; ss = 0
75  add   ax,1000h
76  mov   ds,ax
77
78  mov   sp,07c00h     ; sp = 0x7c00
79  mov   bp,sp         ; bp = 0x7c00
80
81  mov   ah,8                                ; ah = 8 - Get Drive Parameters Function
82  mov   byte ptr [bp+PhysicalDrive],dl      ; BBS defines that BIOS would pass the booting driver number to the loader through DL
83  int   13h                                 ; Get Drive Parameters
84  xor   ax,ax                   ; ax = 0
85  mov   al,dh                   ; al = dh
86  inc   al                      ; MaxHead = al + 1
87  push  ax                      ; 0000:7bfe = MaxHead
88  mov   al,cl                   ; al = cl
89  and   al,03fh                 ; MaxSector = al & 0x3f
90  push  ax                      ; 0000:7bfc = MaxSector
91
92  cmp   word ptr [bp+SectorSignature],0aa55h  ; Verify Boot Sector Signature
93  jne   BadBootSector
94  mov   cx,word ptr [bp+RootEntries]      ; cx = RootEntries
95  shl   cx,FAT_DIRECTORY_ENTRY_SHIFT      ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
96  mov   bx,cx                             ; bx = size of the Root Directory in bytes
97  and   bx,BLOCK_MASK                     ; See if it is an even number of sectors long
98  jne   BadBootSector                     ; If is isn't, then the boot sector is bad.
99  mov   bx,cx                             ; bx = size of the Root Directory in bytes
100  shr   bx,BLOCK_SHIFT                    ; bx = size of Root Directory in sectors
101  mov   al,byte ptr [bp+NoFats]           ; al = NoFats
102  xor   ah,ah                             ; ah = 0  ==> ax = NoFats
103  mul   word ptr [bp+SectorsPerFat]       ; ax = NoFats * SectorsPerFat
104  add   ax,word ptr [bp+ReservedSectors]  ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
105  push  ds
106  pop   es
107  xor   di,di                             ; Store directory in es:di = 1000:0000
108  call  ReadBlocks                        ; Read entire Root Directory
109  add   ax,bx                             ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)
110  mov   word ptr [bp],ax                  ; Save FirstClusterLBA (FirstDataSector) for later use
111
112  ; dx - variable storage (initial value is 0)
113  ; bx - loader (initial value is 0)
114  xor   dx, dx
115  xor   bx, bx
116
117FindEFILDR:
118  cmp   dword ptr [di],LOADER_FILENAME_PART1         ; Compare to "EFIL"
119  jne   FindVARSTORE
120  cmp   dword ptr [di+4],LOADER_FILENAME_PART2
121  jne   FindVARSTORE
122  cmp   dword ptr [di+7],LOADER_FILENAME_PART3
123  jne   FindVARSTORE
124  mov   bx, word ptr [di+26]              ; bx = Start Cluster for EFILDR  <----------------------------------
125  test  dx, dx
126  je    FindNext                          ; Efivar.bin is not loaded
127  jmp   FoundAll
128
129FindVARSTORE:
130  ; if the file is not loader file, see if it's "EFIVAR  BIN"
131  cmp   dword ptr [di], 056494645h        ; Compare to "EFIV"
132  jne   FindNext
133  cmp   dword ptr [di+4], 020205241h      ; Compare to "AR  "
134  jne   FindNext
135  cmp   dword ptr [di+7], 04e494220h      ; Compare to " BIN"
136  jne   FindNext
137  mov   dx, di                            ; dx = Offset of Start Cluster for Efivar.bin <---------------------
138  add   dx, 26
139  test  bx, bx
140  je    FindNext                          ; Efildr is not loaded
141  jmp   FoundAll
142  
143FindNext:
144  ; go to next find
145  add   di,FAT_DIRECTORY_ENTRY_SIZE       ; Increment di
146  sub   cx,FAT_DIRECTORY_ENTRY_SIZE       ; Decrement cx
147  ; TODO: jump to FindVarStore if ...
148  jne   FindEFILDR
149  jmp   NotFoundAll
150
151FoundAll:
152FoundEFILDR:
153  mov     cx,bx                               ; cx = Start Cluster for EFILDR  <----------------------------------
154  mov     ax,cs                               ; Destination = 2000:0000
155  add     ax,2000h
156  mov     es,ax
157  xor     di,di
158ReadFirstClusterOfEFILDR:
159  mov     ax,cx                               ; ax = StartCluster
160  sub     ax,2                                ; ax = StartCluster - 2
161  xor     bh,bh                               
162  mov     bl,byte ptr [bp+SectorsPerCluster]  ; bx = SectorsPerCluster
163  push    dx
164  mul     bx
165  pop     dx                                  ; ax = (StartCluster - 2) * SectorsPerCluster
166  add     ax, word ptr [bp]                   ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
167  xor     bh,bh
168  mov     bl,byte ptr [bp+SectorsPerCluster]  ; bx = Number of Sectors in a cluster
169  push    es
170  call    ReadBlocks
171  pop     ax
172JumpIntoFirstSectorOfEFILDR:
173  mov     word ptr [bp+JumpSegment],ax
174JumpFarInstruction:
175  db      0eah
176JumpOffset:
177  dw      0000h
178JumpSegment:
179  dw      2000h
180
181
182PrintString:
183  mov  ax,0b800h
184  mov  es,ax
185  mov  ax, 07c0h
186  mov  ds, ax
187  mov  cx, 7
188  mov  di, 160
189  rep  movsw
190  ret
191; ****************************************************************************
192; ReadBlocks - Reads a set of blocks from a block device
193;
194; AX    = Start LBA
195; BX    = Number of Blocks to Read
196; ES:DI = Buffer to store sectors read from disk
197; ****************************************************************************
198
199; cx = Blocks
200; bx = NumberOfBlocks
201; si = StartLBA
202
203ReadBlocks:
204  pusha
205  add     eax,dword ptr [bp+LBAOffsetForBootSector]    ; Add LBAOffsetForBootSector to Start LBA
206  add     eax,dword ptr [bp+HiddenSectors]    ; Add HiddenSectors to Start LBA
207  mov     esi,eax                             ; esi = Start LBA
208  mov     cx,bx                               ; cx = Number of blocks to read
209ReadCylinderLoop:
210  mov     bp,07bfch                           ; bp = 0x7bfc
211  mov     eax,esi                             ; eax = Start LBA
212  xor     edx,edx                             ; edx = 0
213  movzx   ebx,word ptr [bp]                   ; bx = MaxSector
214  div     ebx                                 ; ax = StartLBA / MaxSector
215  inc     dx                                  ; dx = (StartLBA % MaxSector) + 1
216  sub     bx,dx                               ; bx = MaxSector - Sector
217  inc     bx                                  ; bx = MaxSector - Sector + 1
218  cmp     cx,bx                               ; Compare (Blocks) to (MaxSector - Sector + 1)
219  jg      LimitTransfer
220  mov     bx,cx                               ; bx = Blocks
221LimitTransfer:
222  push    cx
223  mov     cl,dl                               ; cl = (StartLBA % MaxSector) + 1 = Sector
224  xor     dx,dx                               ; dx = 0
225  div     word ptr [bp+2]                     ; ax = ax / (MaxHead + 1) = Cylinder  
226                                              ; dx = ax % (MaxHead + 1) = Head
227
228  push    bx                                  ; Save number of blocks to transfer
229  mov     dh,dl                               ; dh = Head
230  mov     bp,07c00h                           ; bp = 0x7c00
231  mov     dl,byte ptr [bp+PhysicalDrive]      ; dl = Drive Number
232  mov     ch,al                               ; ch = Cylinder
233  mov     al,bl                               ; al = Blocks
234  mov     ah,2                                ; ah = Function 2
235  mov     bx,di                               ; es:bx = Buffer address
236  int     013h
237  jc      DiskError
238  pop     bx
239  pop     cx
240  movzx   ebx,bx
241  add     esi,ebx                             ; StartLBA = StartLBA + NumberOfBlocks
242  sub     cx,bx                               ; Blocks = Blocks - NumberOfBlocks
243  mov     ax,es
244  shl     bx,(BLOCK_SHIFT-4)
245  add     ax,bx
246  mov     es,ax                               ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE
247  cmp     cx,0
248  jne     ReadCylinderLoop
249  popa
250  ret
251
252; ****************************************************************************
253; ERROR Condition:
254; ****************************************************************************
255NotFoundAll:
256  ; if we found EFILDR, continue
257  test bx,bx
258  jne  FoundEFILDR
259BadBootSector:
260DiskError:
261  lea  si, cs:[ErrorString]
262  call PrintString
263Halt:
264  jmp   Halt
265
266StartString:
267  db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch
268ErrorString:
269  db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch
270
271; ****************************************************************************
272; LBA Offset for BootSector, need patched by tool for HD boot.
273; ****************************************************************************
274
275  org 01fah
276LBAOffsetForBootSector:
277  dd        0h
278
279; ****************************************************************************
280; Sector Signature
281; ****************************************************************************
282
283  org 01feh
284SectorSignature:
285  dw        0aa55h      ; Boot Sector Signature
286
287  end 
288  
289