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        .code16
22
23.equ                      FAT_DIRECTORY_ENTRY_SIZE, 0x020
24.equ                      FAT_DIRECTORY_ENTRY_SHIFT, 5
25.equ                      BLOCK_SIZE, 0x0200
26.equ                      BLOCK_MASK, 0x01ff
27.equ                      BLOCK_SHIFT, 9
28                                               # "EFILDR_____"
29.equ                      LOADER_FILENAME_PART1, 0x04c494645    # "EFIL"
30.equ                      LOADER_FILENAME_PART2, 0x036315244    # "DR16"
31.equ                      LOADER_FILENAME_PART3, 0x020202036    # "6___"
32
33        .org 0x0
34.global _start
35_start:
36Ia32Jump:
37  jmp   BootSectorEntryPoint  # JMP inst                  - 3 bytes
38  nop
39
40OemId:              .ascii   "INTEL   "       # OemId               - 8 bytes
41# BPB data below will be fixed by tool
42SectorSize:         .word  0                  # Sector Size         - 16 bits
43SectorsPerCluster:  .byte  0                  # Sector Per Cluster  - 8 bits
44ReservedSectors:    .word  0                  # Reserved Sectors    - 16 bits
45NoFats:             .byte  0                  # Number of FATs      - 8 bits
46RootEntries:        .word  0                  # Root Entries        - 16 bits
47Sectors:            .word  0                  # Number of Sectors   - 16 bits
48Media:              .byte  0                  # Media               - 8 bits  - ignored
49SectorsPerFat:      .word  0                  # Sectors Per FAT     - 16 bits
50SectorsPerTrack:    .word  0                  # Sectors Per Track   - 16 bits - ignored
51Heads:              .word  0                  # Heads               - 16 bits - ignored
52HiddenSectors:      .long  0                  # Hidden Sectors      - 32 bits - ignored
53LargeSectors:       .long  0                  # Large Sectors       - 32 bits
54PhysicalDrive:      .byte  0                  # PhysicalDriveNumber - 8 bits  - ignored
55CurrentHead:        .byte  0                  # Current Head        - 8 bits
56Signature:          .byte  0                  # Signature           - 8 bits  - ignored
57VolId:              .ascii "    "             # Volume Serial Number- 4 bytes
58FatLabel:           .ascii "           "      # Label               - 11 bytes
59SystemId:           .ascii "FAT12   "         # SystemId            - 8 bytes
60
61BootSectorEntryPoint:
62        #ASSUME ds:@code
63        #ASSUME ss:@code
64
65# ****************************************************************************
66# Start Print
67# ****************************************************************************
68  movw $StartString, %si
69  call PrintString
70
71# ****************************************************************************
72# Print over
73# ****************************************************************************
74
75  movw  %cs, %ax      # ax = 0
76  movw  %ax, %ss      # ss = 0
77  addw  $0x1000, %ax
78  movw  %ax, %ds
79
80  movw  $0x7c00, %sp  # sp = 0x7c00
81  movw  %sp, %bp      # bp = 0x7c00
82
83  movb  $8, %ah                             # ah = 8 - Get Drive Parameters Function
84  movb  %dl, PhysicalDrive(%bp)             # BBS defines that BIOS would pass the booting driver number to the loader through DL
85  int   $0x13                               # Get Drive Parameters
86  xorw  %ax, %ax                # ax = 0
87  movb  %dh, %al                # al = dh
88  incb  %al                     # MaxHead = al + 1
89  pushw %ax                     # 0000:7bfe = MaxHead
90  movb  %cl, %al                # al = cl
91  andb  $0x3f, %al              # MaxSector = al & 0x3f
92  pushw %ax                     # 0000:7bfc = MaxSector
93
94  cmpw  $0xaa55, SectorSignature(%bp)         # Verify Boot Sector Signature
95  jne   BadBootSector
96  movw  RootEntries(%bp), %cx             # cx = RootEntries
97  shlw  $FAT_DIRECTORY_ENTRY_SHIFT, %cx   # cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
98  movw  %cx, %bx                          # bx = size of the Root Directory in bytes
99  andw  $BLOCK_MASK, %bx                  # See if it is an even number of sectors long
100  jne   BadBootSector                     # If is isn't, then the boot sector is bad.
101  movw  %cx, %bx                          # bx = size of the Root Directory in bytes
102  shrw  $BLOCK_SHIFT, %bx                 # bx = size of Root Directory in sectors
103  movb  NoFats(%bp), %al                  # al = NoFats
104  xorb  %ah, %ah                          # ah = 0  ==> ax = NoFats
105  mulw  SectorsPerFat(%bp)                # ax = NoFats * SectorsPerFat
106  addw  ReservedSectors(%bp), %ax         # ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
107  pushw %ds
108  popw  %es
109  xorw  %di, %di                          # Store directory in es:di = 1000:0000
110  call  ReadBlocks                        # Read entire Root Directory
111  addw  %bx, %ax                          # ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)
112  movw  %ax, (%bp)                        # Save FirstClusterLBA (FirstDataSector) for later use
113
114  # dx - variable storage (initial value is 0)
115  # bx - loader (initial value is 0)
116  xorw  %dx, %dx
117  xorw  %bx, %bx
118
119FindEFILDR:
120  cmpl   $LOADER_FILENAME_PART1, (%di)        # Compare to "EFIL"
121  jne   FindVARSTORE
122  cmpl   $LOADER_FILENAME_PART2, 4(%di)
123  jne   FindVARSTORE
124  cmpl   $LOADER_FILENAME_PART3, 7(%di)
125  jne   FindVARSTORE
126  movw  26(%di), %bx                      # bx = Start Cluster for EFILDR  <----------------------------------
127  testw %dx, %dx
128  je    FindNext                          # Efivar.bin is not loaded
129  jmp   FoundAll
130
131FindVARSTORE:
132  ##if the file is not loader file, see if it's "EFIVAR  BIN"
133  cmpl  $0x56494645, (%di)                # Compare to "EFIV"
134  jne   FindNext
135  cmpl  $0x20205241, 4(%di)               # Compare to "AR  "
136  jne   FindNext
137  cmpl  $0x4e494220, 7(%di)               # Compare to " BIN"
138  jne   FindNext
139  movw  %di, %dx                          # dx = Offset of Start Cluster for Efivar.bin <---------------------
140  addw  $26, %dx
141  testw %bx, %bx
142  je    FindNext                          # Efildr is not loaded
143  jmp   FoundAll
144
145FindNext:
146  # go to next find
147  addw  $FAT_DIRECTORY_ENTRY_SIZE, %di    # Increment di
148  subw  $FAT_DIRECTORY_ENTRY_SIZE, %cx    # Decrement cx
149  # TODO: jump to FindVarStore if ...
150  jne   FindEFILDR
151  jmp   NotFoundAll
152
153FoundAll:
154FoundEFILDR:
155  movw    %bx, %cx                            # cx = Start Cluster for EFILDR  <----------------------------------
156  movw    %cs, %ax                            # Destination = 2000:0000
157  addw    $0x2000, %ax
158  movw    %ax, %es
159  xorw    %di, %di
160ReadFirstClusterOfEFILDR:
161  movw    %cx, %ax                            # ax = StartCluster
162  subw    $2, %ax                             # ax = StartCluster - 2
163  xorb    %bh, %bh
164  movb    SectorsPerCluster(%bp), %bl         # bx = SectorsPerCluster
165  pushw   %dx
166  mulw    %bx
167  popw    %dx                                 # ax = (StartCluster - 2) * SectorsPerCluster
168  addw    (%bp), %ax                          # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
169  xorb    %bh, %bh
170  movb    SectorsPerCluster(%bp), %bl         # bx = Number of Sectors in a cluster
171  pushw   %es
172  call    ReadBlocks
173  popw    %ax
174JumpIntoFirstSectorOfEFILDR:
175  movw    %ax, JumpSegment(%bp)
176JumpFarInstruction:
177  .byte   0xea
178JumpOffset:
179  .word   0x000
180JumpSegment:
181  .word   0x2000
182
183
184PrintString:
185  movw $0xb800, %ax
186  movw %ax, %es
187  movw $0x7c0, %ax
188  movw %ax, %ds
189  movw $7, %cx
190  movw $160, %di
191  rep
192  movsw
193  ret
194# ****************************************************************************
195# ReadBlocks - Reads a set of blocks from a block device
196#
197# AX    = Start LBA
198# BX    = Number of Blocks to Read
199# ES:DI = Buffer to store sectors read from disk
200# ****************************************************************************
201
202# cx = Blocks
203# bx = NumberOfBlocks
204# si = StartLBA
205
206ReadBlocks:
207  pusha
208  addl    LBAOffsetForBootSector(%bp), %eax            # Add LBAOffsetForBootSector to Start LBA
209  addl    HiddenSectors(%bp), %eax            # Add HiddenSectors to Start LBA
210  movl    %eax, %esi                          # esi = Start LBA
211  movw    %bx, %cx                            # cx = Number of blocks to read
212ReadCylinderLoop:
213  movw    $0x7bfc, %bp                        # bp = 0x7bfc
214  movl    %esi, %eax                          # eax = Start LBA
215  xorl    %edx, %edx                          # edx = 0
216  movzwl  (%bp), %ebx                         # bx = MaxSector
217  divl    %ebx                                # ax = StartLBA / MaxSector
218  incw    %dx                                 # dx = (StartLBA % MaxSector) + 1
219  subw    %dx, %bx                            # bx = MaxSector - Sector
220  incw    %bx                                 # bx = MaxSector - Sector + 1
221  cmpw    %bx, %cx                            # Compare (Blocks) to (MaxSector - Sector + 1)
222  jg      LimitTransfer
223  movw    %cx, %bx                            # bx = Blocks
224LimitTransfer:
225  pushw   %cx
226  movb    %dl, %cl                            # cl = (StartLBA % MaxSector) + 1 = Sector
227  xorw    %dx, %dx                            # dx = 0
228  divw    2(%bp)                              # ax = ax / (MaxHead + 1) = Cylinder
229                                              # dx = ax % (MaxHead + 1) = Head
230
231  pushw   %bx                                 # Save number of blocks to transfer
232  movb    %dl, %dh                            # dh = Head
233  movw    $0x7c00, %bp                        # bp = 0x7c00
234  movb    PhysicalDrive(%bp), %dl             # dl = Drive Number
235  movb    %al, %ch                            # ch = Cylinder
236  movb    %bl, %al                            # al = Blocks
237  movb    $2, %ah                             # ah = Function 2
238  movw    %di, %bx                            # es:bx = Buffer address
239  int     $0x13
240  jc      DiskError
241  popw    %bx
242  popw    %cx
243  movzwl  %bx, %ebx
244  addl    %ebx, %esi                          # StartLBA = StartLBA + NumberOfBlocks
245  subw    %bx, %cx                            # Blocks = Blocks - NumberOfBlocks
246  movw    %es, %ax
247  shlw    $(BLOCK_SHIFT-4),%bx
248  addw    %bx, %ax
249  movw    %ax, %es                            # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
250  cmpw    $0, %cx
251  jne     ReadCylinderLoop
252  popa
253  ret
254
255# ****************************************************************************
256# ERROR Condition:
257# ****************************************************************************
258NotFoundAll:
259  ## if we found EFILDR, continue
260  testw %bx, %bx
261  jne  FoundEFILDR
262BadBootSector:
263DiskError:
264  movw $ErrorString, %si
265  call PrintString
266Halt:
267  jmp   Halt
268
269StartString:
270  .byte  'B', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c
271ErrorString:
272  .byte  'B', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c
273
274# ****************************************************************************
275# LBA Offset for BootSector, need patched by tool for HD boot.
276# ****************************************************************************
277
278  .org 0x01fa
279LBAOffsetForBootSector:
280  .long     0x0
281
282# ****************************************************************************
283# Sector Signature
284# ****************************************************************************
285
286  .org 0x01fe
287SectorSignature:
288  .word     0xaa55      # Boot Sector Signature
289
290
291
292