1;------------------------------------------------------------------------------
2;*
3;*   Copyright (c) 2006 - 2012, 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;*    bs32.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     030325244h   ; "DR20"
31LOADER_FILENAME_PART3     EQU     020202030h   ; "0___"
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
52
53;******************************************************************************
54;
55;The structure for FAT32 starting at offset 36 of the boot sector. (At this point,
56;the BPB/boot sector for FAT12 and FAT16 differs from the BPB/boot sector for FAT32.)
57;
58;******************************************************************************
59
60SectorsPerFat32   dd  0             ; Sectors Per FAT for FAT32       - 4 bytes
61ExtFlags          dw  0             ; Mirror Flag                     - 2 bytes
62FSVersion         dw  0             ; File System Version             - 2 bytes
63RootCluster       dd  0             ; 1st Cluster Number of Root Dir  - 4 bytes
64FSInfo            dw  0             ; Sector Number of FSINFO         - 2 bytes
65BkBootSector      dw  0             ; Sector Number of Bk BootSector  - 2 bytes
66Reserved          db  12 dup(0)     ; Reserved Field                  - 12 bytes
67PhysicalDrive     db  0             ; Physical Drive Number           - 1 byte
68Reserved1         db  0             ; Reserved Field                  - 1 byte
69Signature         db  0             ; Extended Boot Signature         - 1 byte
70VolId             db  "    "        ; Volume Serial Number            - 4 bytes
71FatLabel          db  "           " ; Volume Label                    - 11 bytes
72FileSystemType    db  "FAT32   "    ; File System Type                - 8 bytes
73
74BootSectorEntryPoint:
75        ASSUME  ds:@code
76        ASSUME  ss:@code
77
78; ****************************************************************************
79; Start Print
80; ****************************************************************************
81  mov  si, offset StartString
82  call PrintString
83
84; ****************************************************************************
85; Print over
86; ****************************************************************************
87
88  mov   ax,cs         ; ax = 0
89  mov   ss,ax         ; ss = 0
90  add   ax,1000h
91  mov   ds,ax
92
93  mov   sp,07c00h     ; sp = 0x7c00
94  mov   bp,sp         ; bp = 0x7c00
95
96  mov   ah,8                                ; ah = 8 - Get Drive Parameters Function
97  mov   byte ptr [bp+PhysicalDrive],dl      ; BBS defines that BIOS would pass the booting driver number to the loader through DL
98  int   13h                                 ; Get Drive Parameters
99  xor   ax,ax                   ; ax = 0
100  mov   al,dh                   ; al = dh
101  inc   al                      ; MaxHead = al + 1
102  push  ax                      ; 0000:7bfe = MaxHead
103  mov   al,cl                   ; al = cl
104  and   al,03fh                 ; MaxSector = al & 0x3f
105  push  ax                      ; 0000:7bfc = MaxSector
106
107  cmp   word ptr [bp+SectorSignature],0aa55h  ; Verify Boot Sector Signature
108  jne   BadBootSector
109  mov   cx,word ptr [bp+RootEntries]      ; cx = RootEntries
110  shl   cx,FAT_DIRECTORY_ENTRY_SHIFT      ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
111  mov   bx,cx                             ; bx = size of the Root Directory in bytes
112  and   bx,BLOCK_MASK                     ; See if it is an even number of sectors long
113  jne   BadBootSector                     ; If is isn't, then the boot sector is bad.
114  mov   bx,cx                             ; bx = size of the Root Directory in bytes
115  shr   bx,BLOCK_SHIFT                    ; bx = size of Root Directory in sectors
116  mov   al,byte ptr [bp+NoFats]           ; al = NoFats
117  xor   ah,ah                             ; ah = 0  ==> ax = NoFats
118  mul   word ptr [bp+SectorsPerFat32]     ; ax = NoFats * SectorsPerFat
119  add   ax,word ptr [bp+ReservedSectors]  ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
120  add   ax,bx                             ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA
121  mov   word ptr [bp],ax                  ; Save FirstClusterLBA for later use
122
123  mov   ax,word ptr [bp+RootCluster]      ; ax = StartCluster of Root Directory
124  sub   ax,2                              ; ax = StartCluster - 2
125  xor   bh,bh
126  mov   bl,byte ptr [bp+SectorsPerCluster]; bx = SectorsPerCluster
127  mul   bx                                ; ax = (StartCluster - 2) * SectorsPerCluster
128  add   ax, word ptr [bp]                 ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
129  push  ds
130  pop   es
131  xor   di,di                             ; Store directory in es:di = 1000:0000
132  call  ReadBlocks                        ; Read StartCluster of Root Directory
133
134  ; dx - variable storage (initial value is 0)
135  ; bx - loader (initial value is 0)
136  xor   dx, dx
137  xor   bx, bx
138
139FindEFILDR:
140  cmp   dword ptr [di],LOADER_FILENAME_PART1         ; Compare to "EFIL"
141  jne   FindVARSTORE
142  cmp   dword ptr [di+4],LOADER_FILENAME_PART2
143  jne   FindVARSTORE
144  cmp   dword ptr [di+7],LOADER_FILENAME_PART3
145  jne   FindVARSTORE
146  mov   bx, word ptr [di+26]              ; bx = Start Cluster for EFILDR  <----------------------------------
147  test  dx, dx
148  je    FindNext                          ; Efivar.bin is not loaded
149  jmp   FoundAll
150
151FindVARSTORE:
152  ; if the file is not loader file, see if it's "EFIVAR  BIN"
153  cmp   dword ptr [di], 056494645h        ; Compare to "EFIV"
154  jne   FindNext
155  cmp   dword ptr [di+4], 020205241h      ; Compare to "AR  "
156  jne   FindNext
157  cmp   dword ptr [di+7], 04e494220h      ; Compare to " BIN"
158  jne   FindNext
159  mov   dx, di                            ; dx = Offset of Start Cluster for Efivar.bin <---------------------
160  add   dx, 26
161  test  bx, bx
162  je    FindNext                          ; Efildr is not loaded
163  jmp   FoundAll
164
165FindNext:
166  ; go to next find
167  add   di,FAT_DIRECTORY_ENTRY_SIZE       ; Increment di
168  sub   cx,FAT_DIRECTORY_ENTRY_SIZE       ; Decrement cx
169  ; TODO: jump to FindVarStore if ...
170  jne   FindEFILDR
171  jmp   NotFoundAll
172
173FoundAll:
174FoundEFILDR:
175  mov     cx,bx                               ; cx = Start Cluster for EFILDR  <----------------------------------
176  mov     ax,cs                               ; Destination = 2000:0000
177  add     ax,2000h
178  mov     es,ax
179  xor     di,di
180ReadFirstClusterOfEFILDR:
181  mov     ax,cx                               ; ax = StartCluster
182  sub     ax,2                                ; ax = StartCluster - 2
183  xor     bh,bh
184  mov     bl,byte ptr [bp+SectorsPerCluster]  ; bx = SectorsPerCluster
185  push    dx
186  mul     bx
187  pop     dx                                  ; ax = (StartCluster - 2) * SectorsPerCluster
188  add     ax, word ptr [bp]                   ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
189  xor     bh,bh
190  mov     bl,byte ptr [bp+SectorsPerCluster]  ; bx = Number of Sectors in a cluster
191  push    es
192  call    ReadBlocks
193  pop     ax
194JumpIntoFirstSectorOfEFILDR:
195  mov     word ptr [bp+JumpSegment],ax
196JumpFarInstruction:
197  db      0eah
198JumpOffset:
199  dw      0000h
200JumpSegment:
201  dw      2000h
202
203
204PrintString:
205  mov  ax,0b800h
206  mov  es,ax
207  mov  ax, 07c0h
208  mov  ds, ax
209  mov  cx, 6
210  mov  di, 160
211  rep  movsw
212  ret
213; ****************************************************************************
214; ReadBlocks - Reads a set of blocks from a block device
215;
216; AX    = Start LBA
217; BX    = Number of Blocks to Read
218; ES:DI = Buffer to store sectors read from disk
219; ****************************************************************************
220
221; cx = Blocks
222; bx = NumberOfBlocks
223; si = StartLBA
224
225ReadBlocks:
226  pusha
227  add     eax,dword ptr [bp+LBAOffsetForBootSector]    ; Add LBAOffsetForBootSector to Start LBA
228  add     eax,dword ptr [bp+HiddenSectors]    ; Add HiddenSectors to Start LBA
229  mov     esi,eax                             ; esi = Start LBA
230  mov     cx,bx                               ; cx = Number of blocks to read
231ReadCylinderLoop:
232  mov     bp,07bfch                           ; bp = 0x7bfc
233  mov     eax,esi                             ; eax = Start LBA
234  xor     edx,edx                             ; edx = 0
235  movzx   ebx,word ptr [bp]                   ; bx = MaxSector
236  div     ebx                                 ; ax = StartLBA / MaxSector
237  inc     dx                                  ; dx = (StartLBA % MaxSector) + 1
238  sub     bx,dx                               ; bx = MaxSector - Sector
239  inc     bx                                  ; bx = MaxSector - Sector + 1
240  cmp     cx,bx                               ; Compare (Blocks) to (MaxSector - Sector + 1)
241  jg      LimitTransfer
242  mov     bx,cx                               ; bx = Blocks
243LimitTransfer:
244  push    cx
245  mov     cl,dl                               ; cl = (StartLBA % MaxSector) + 1 = Sector
246  xor     dx,dx                               ; dx = 0
247  div     word ptr [bp+2]                     ; ax = ax / (MaxHead + 1) = Cylinder
248                                              ; dx = ax % (MaxHead + 1) = Head
249
250  push    bx                                  ; Save number of blocks to transfer
251  mov     dh,dl                               ; dh = Head
252  mov     bp,07c00h                           ; bp = 0x7c00
253  mov     dl,byte ptr [bp+PhysicalDrive]      ; dl = Drive Number
254  mov     ch,al                               ; ch = Cylinder
255  mov     al,bl                               ; al = Blocks
256  mov     ah,2                                ; ah = Function 2
257  mov     bx,di                               ; es:bx = Buffer address
258  int     013h
259  jc      DiskError
260  pop     bx
261  pop     cx
262  movzx   ebx,bx
263  add     esi,ebx                             ; StartLBA = StartLBA + NumberOfBlocks
264  sub     cx,bx                               ; Blocks = Blocks - NumberOfBlocks
265  mov     ax,es
266  shl     bx,(BLOCK_SHIFT-4)
267  add     ax,bx
268  mov     es,ax                               ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE
269  cmp     cx,0
270  jne     ReadCylinderLoop
271  popa
272  ret
273
274; ****************************************************************************
275; ERROR Condition:
276; ****************************************************************************
277NotFoundAll:
278  ; if we found EFILDR, continue
279  test bx,bx
280  jne  FoundEFILDR
281BadBootSector:
282DiskError:
283  mov  si, offset ErrorString
284  call PrintString
285Halt:
286  jmp   Halt
287
288StartString:
289  db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch
290ErrorString:
291  db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch
292
293; ****************************************************************************
294; LBA Offset for BootSector, need patched by tool for HD boot.
295; ****************************************************************************
296
297  org 01fah
298LBAOffsetForBootSector:
299  dd        0h
300
301; ****************************************************************************
302; Sector Signature
303; ****************************************************************************
304
305  org 01feh
306SectorSignature:
307  dw        0aa55h      ; Boot Sector Signature
308
309  end
310
311