[CONTROL] Use the new header with SPDX license identifier.
[reactos.git] / reactos / boot / freeldr / bootsect / ext2.asm
1 ; EXT2.ASM
2 ; EXT2 Boot Sector
3 ; Copyright (c) 2002, 2003 Brian Palmer
4
5 ; [bp-0x04] Here we will store the number of sectors per track
6 ; [bp-0x08] Here we will store the number of heads
7 ; [bp-0x0c] Here we will store the size of the disk as the BIOS reports in CHS form
8 ; [bp-0x10] Here we will store the number of LBA sectors read
9
10 SECTORS_PER_TRACK equ 0x04
11 NUMBER_OF_HEADS equ 0x08
12 BIOS_CHS_DRIVE_SIZE equ 0x0C
13 LBA_SECTORS_READ equ 0x10
14
15
16 EXT2_ROOT_INO equ 2
17 EXT2_S_IFMT equ 0f0h
18 EXT2_S_IFREG equ 080h
19
20
21 org 7c00h
22
23 segment .text
24
25 bits 16
26
27 start:
28 jmp short main
29 nop
30
31 BootDrive db 0x80
32 ;BootPartition db 0 ; Moved to end of boot sector to have a standard format across all boot sectors
33 ;SectorsPerTrack db 63 ; Moved to [bp-SECTORS_PER_TRACK]
34 ;NumberOfHeads dw 16 ; Moved to [bp-NUMBER_OF_HEADS]
35 ;BiosCHSDriveSize dd (1024 * 1024 * 63) ; Moved to [bp-BIOS_CHS_DRIVE_SIZE]
36 ;LBASectorsRead dd 0 ; Moved to [bp-LBA_SECTORS_READ]
37
38 Ext2VolumeStartSector dd 263088 ; Start sector of the ext2 volume
39 Ext2BlockSize dd 2 ; Block size in sectors
40 Ext2BlockSizeInBytes dd 1024 ; Block size in bytes
41 Ext2PointersPerBlock dd 256 ; Number of block pointers that can be contained in one block
42 Ext2GroupDescPerBlock dd 32 ; Number of group descriptors per block
43 Ext2FirstDataBlock dd 1 ; First data block (1 for 1024-byte blocks, 0 for bigger sizes)
44 Ext2InodesPerGroup dd 2048 ; Number of inodes per group
45 Ext2InodesPerBlock dd 8 ; Number of inodes per block
46
47 Ext2ReadEntireFileLoadSegment:
48 dw 0
49 Ext2InodeIndirectPointer:
50 dd 0
51 Ext2InodeDoubleIndirectPointer:
52 dd 0
53 Ext2BlocksLeftToRead:
54 dd 0
55
56 main:
57 xor ax,ax ; Setup segment registers
58 mov ds,ax ; Make DS correct
59 mov es,ax ; Make ES correct
60 mov ss,ax ; Make SS correct
61 mov bp,7c00h
62 mov sp,7b00h ; Setup a stack
63
64
65 cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
66 jne GetDriveParameters
67
68 mov [BYTE bp+BootDrive],dl ; Save the boot drive
69
70
71 GetDriveParameters:
72 mov ah,08h
73 mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl
74 int 13h ; Request drive parameters from the bios
75 jnc CalcDriveSize ; If the call succeeded then calculate the drive size
76
77 ; If we get here then the call to the BIOS failed
78 ; so just set CHS equal to the maximum addressable
79 ; size
80 mov cx,0ffffh
81 mov dh,cl
82
83 CalcDriveSize:
84 ; Now that we have the drive geometry
85 ; lets calculate the drive size
86 mov bl,ch ; Put the low 8-bits of the cylinder count into BL
87 mov bh,cl ; Put the high 2-bits in BH
88 shr bh,6 ; Shift them into position, now BX contains the cylinder count
89 and cl,3fh ; Mask off cylinder bits from sector count
90 ; CL now contains sectors per track and DH contains head count
91 movzx eax,dh ; Move the heads into EAX
92 movzx ebx,bx ; Move the cylinders into EBX
93 movzx ecx,cl ; Move the sectors per track into ECX
94 inc eax ; Make it one based because the bios returns it zero based
95 mov [BYTE bp-NUMBER_OF_HEADS],eax ; Save number of heads
96 mov [BYTE bp-SECTORS_PER_TRACK],ecx ; Save number of sectors per track
97 inc ebx ; Make the cylinder count one based also
98 mul ecx ; Multiply heads with the sectors per track, result in edx:eax
99 mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already]
100
101 ; We now have the total number of sectors as reported
102 ; by the bios in eax, so store it in our variable
103 mov [BYTE bp-BIOS_CHS_DRIVE_SIZE],eax
104
105
106 LoadExtraBootCode:
107 ; First we have to load our extra boot code at
108 ; sector 1 into memory at [0000:7e00h]
109 ;mov eax,01h
110 xor eax,eax
111 inc eax ; Read logical sector 1, EAX now = 1
112 mov cx,1 ; Read one sector
113 mov bx,7e00h ; Read sector to [0000:7e00h]
114 call ReadSectors
115
116 jmp LoadRootDirectory
117
118
119
120 ; Reads ext2 group descriptor into [7000:8000]
121 ; We read it to this arbitrary location so
122 ; it will not cross a 64k boundary
123 ; EAX has group descriptor number to read
124 Ext2ReadGroupDesc:
125 shl eax,5 ; Group = (Group * sizeof(GROUP_DESCRIPTOR) /* 32 */)
126 xor edx,edx
127 div DWORD [BYTE bp+Ext2GroupDescPerBlock] ; Group = (Group / Ext2GroupDescPerBlock)
128 add eax,DWORD [BYTE bp+Ext2FirstDataBlock] ; Group = Group + Ext2FirstDataBlock + 1
129 inc eax ; EAX now has the group descriptor block number
130 ; EDX now has the group descriptor offset in the block
131
132 ; Adjust the read offset so that the
133 ; group descriptor is read to 7000:8000
134 mov ebx,78000h
135 sub ebx,edx
136 shr ebx,4
137 mov es,bx
138 xor bx,bx
139
140
141 ; Everything is now setup to call Ext2ReadBlock
142 ; Instead of using the call instruction we will
143 ; just put Ext2ReadBlock right after this routine
144
145 ; Reads ext2 block into [ES:BX]
146 ; EAX has logical block number to read
147 Ext2ReadBlock:
148 mov ecx,DWORD [BYTE bp+Ext2BlockSize]
149 mul ecx
150 jmp ReadSectors
151
152 ; Reads ext2 inode into [6000:8000]
153 ; We read it to this arbitrary location so
154 ; it will not cross a 64k boundary
155 ; EAX has inode number to read
156 Ext2ReadInode:
157 dec eax ; Inode = Inode - 1
158 xor edx,edx
159 div DWORD [BYTE bp+Ext2InodesPerGroup] ; Inode = (Inode / Ext2InodesPerGroup)
160 mov ebx,eax ; EBX now has the inode group number
161 mov eax,edx
162 xor edx,edx
163 div DWORD [BYTE bp+Ext2InodesPerBlock] ; Inode = (Inode / Ext2InodesPerBlock)
164 shl edx,7 ; FIXME: InodeOffset *= 128 (make the array index a byte offset)
165 ; EAX now has the inode offset block number from inode table
166 ; EDX now has the inode offset in the block
167
168 ; Save the inode values and put the group
169 ; descriptor number in EAX and read it in
170 push edx
171 push eax
172 mov eax,ebx
173 call Ext2ReadGroupDesc
174
175 ; Group descriptor has been read, now
176 ; grab the inode table block number from it
177 push WORD 7000h
178 pop es
179 mov di,8008h
180 pop eax ; Restore inode offset block number from stack
181 add eax,DWORD [es:di] ; Add the inode table start block
182
183 ; Adjust the read offset so that the
184 ; inode we want is read to 6000:8000
185 pop edx ; Restore inode offset in the block from stack
186 mov ebx,68000h
187 sub ebx,edx
188 shr ebx,4
189 mov es,bx
190 xor bx,bx
191
192 call Ext2ReadBlock
193 ret
194
195
196 ; Reads logical sectors into [ES:BX]
197 ; EAX has logical sector number to read
198 ; CX has number of sectors to read
199 ReadSectors:
200 add eax,DWORD [BYTE bp+Ext2VolumeStartSector] ; Add the start of the volume
201 cmp eax,DWORD [BYTE bp-BIOS_CHS_DRIVE_SIZE] ; Check if they are reading a sector outside CHS range
202 jae ReadSectorsLBA ; Yes - go to the LBA routine
203 ; If at all possible we want to use LBA routines because
204 ; They are optimized to read more than 1 sector per read
205
206 pushad ; Save logical sector number & sector count
207
208 CheckInt13hExtensions: ; Now check if this computer supports extended reads
209 mov ah,0x41 ; AH = 41h
210 mov bx,0x55aa ; BX = 55AAh
211 mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh)
212 int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK
213 jc ReadSectorsCHS ; CF set on error (extensions not supported)
214 cmp bx,0xaa55 ; BX = AA55h if installed
215 jne ReadSectorsCHS
216 test cl,1 ; CX = API subset support bitmap
217 jz ReadSectorsCHS ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
218
219 popad ; Restore sector count & logical sector number
220
221 ReadSectorsLBA:
222 pushad ; Save logical sector number & sector count
223
224 cmp cx,byte 64 ; Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64
225 jbe ReadSectorsSetupDiskAddressPacket ; If we are reading less than 65 sectors then just do the read
226 mov cx,64 ; Otherwise read only 64 sectors on this loop iteration
227
228 ReadSectorsSetupDiskAddressPacket:
229 mov [BYTE bp-LBA_SECTORS_READ],cx
230 mov WORD [BYTE bp-LBA_SECTORS_READ+2],0
231 o32 push byte 0
232 push eax ; Put 64-bit logical block address on stack
233 push es ; Put transfer segment on stack
234 push bx ; Put transfer offset on stack
235 push cx ; Set transfer count
236 push byte 0x10 ; Set size of packet to 10h
237 mov si,sp ; Setup disk address packet on stack
238
239
240 mov dl,[BYTE bp+BootDrive] ; Drive number
241 mov ah,42h ; Int 13h, AH = 42h - Extended Read
242 int 13h ; Call BIOS
243 jc PrintDiskError ; If the read failed then abort
244
245 add sp,byte 0x10 ; Remove disk address packet from stack
246
247 popad ; Restore sector count & logical sector number
248
249 push bx
250 mov ebx,DWORD [BYTE bp-LBA_SECTORS_READ]
251 add eax,ebx ; Increment sector to read
252 shl ebx,5
253 mov dx,es
254 add dx,bx ; Setup read buffer for next sector
255 mov es,dx
256 pop bx
257
258 sub cx,[BYTE bp-LBA_SECTORS_READ]
259 jnz ReadSectorsLBA ; Read next sector
260
261 ret
262
263
264 ; Reads logical sectors into [ES:BX]
265 ; EAX has logical sector number to read
266 ; CX has number of sectors to read
267 ReadSectorsCHS:
268 popad ; Get logical sector number & sector count off stack
269
270 ReadSectorsCHSLoop:
271 pushad
272 xor edx,edx
273 mov ecx,DWORD [BYTE bp-SECTORS_PER_TRACK]
274 div ecx ; Divide logical by SectorsPerTrack
275 inc dl ; Sectors numbering starts at 1 not 0
276 mov cl,dl ; Sector in CL
277 mov edx,eax
278 shr edx,16
279 div WORD [BYTE bp-NUMBER_OF_HEADS] ; Divide logical by number of heads
280 mov dh,dl ; Head in DH
281 mov dl,[BYTE bp+BootDrive] ; Drive number in DL
282 mov ch,al ; Cylinder in CX
283 ror ah,2 ; Low 8 bits of cylinder in CH, high 2 bits
284 ; in CL shifted to bits 6 & 7
285 or cl,ah ; Or with sector number
286 mov ax,0201h
287 int 13h ; DISK - READ SECTORS INTO MEMORY
288 ; AL = number of sectors to read, CH = track, CL = sector
289 ; DH = head, DL = drive, ES:BX -> buffer to fill
290 ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
291
292 jc PrintDiskError ; If the read failed then abort
293
294 popad
295
296 inc eax ; Increment Sector to Read
297
298 mov dx,es
299 add dx,byte 20h ; Increment read buffer for next sector
300 mov es,dx
301
302 loop ReadSectorsCHSLoop ; Read next sector
303
304 ret
305
306
307
308
309 ; Displays a disk error message
310 ; And reboots
311 PrintDiskError:
312 mov si,msgDiskError ; Bad boot disk message
313 call PutChars ; Display it
314
315 Reboot:
316 mov si,msgAnyKey ; Press any key message
317 call PutChars ; Display it
318 xor ax,ax
319 int 16h ; Wait for a keypress
320 int 19h ; Reboot
321
322 PutChars:
323 lodsb
324 or al,al
325 jz short Done
326 call PutCharsCallBios
327 jmp short PutChars
328 PutCharsCallBios:
329 mov ah,0eh
330 mov bx,07h
331 int 10h
332 retn
333 Done:
334 mov al,0dh
335 call PutCharsCallBios
336 mov al,0ah
337 call PutCharsCallBios
338 retn
339
340
341
342 msgDiskError db 'Disk error',0
343 ; Sorry, need the space...
344 ;msgAnyKey db 'Press any key to restart',0
345 msgAnyKey db 'Press any key',0
346
347 times 509-($-$$) db 0 ; Pad to 509 bytes
348
349 BootPartition db 0
350
351 dw 0aa55h ; BootSector signature
352
353
354 ; End of bootsector
355 ;
356 ; Now starts the extra boot code that we will store
357 ; at sector 1 on a EXT2 volume
358
359
360
361 LoadRootDirectory:
362
363 mov eax,EXT2_ROOT_INO ; Put the root directory inode number in EAX
364 call Ext2ReadInode ; Read in the inode
365
366 ; Point ES:DI to the inode structure at 6000:8000
367 push WORD 6000h
368 pop es
369 mov di,8000h
370 push di
371 push es ; Save these for later
372
373 ; Get root directory size from inode structure
374 mov eax,DWORD [es:di+4]
375 push eax
376
377 ; Now that the inode has been read in load
378 ; the root directory file data to 0000:8000
379 call Ext2ReadEntireFile
380
381 ; Since the root directory was loaded to 0000:8000
382 ; then add 8000h to the root directory's size
383 pop eax
384 mov edx,8000h ; Set EDX to the current offset in the root directory
385 add eax,edx ; Initially add 8000h to the size of the root directory
386
387 SearchRootDirectory:
388 push edx ; Save current offset in root directory
389 push eax ; Save the size of the root directory
390
391 ; Now we have to convert the current offset
392 ; in the root directory to a SEGMENT:OFFSET pair
393 mov eax,edx
394 xor edx,edx
395 mov ecx,16
396 div ecx ; Now AX:DX has segment & offset
397 mov es,ax
398 mov di,dx
399 push di ; Save the start of the directory entry
400 add di,byte 8 ; Add the offset to the filename
401 mov si,filename
402 mov cl,11
403 rep cmpsb ; Compare the file names
404 pop di
405 pop eax
406 pop edx
407 jz FoundFile
408
409 ; Nope, didn't find it in this entry, keep looking
410 movzx ecx,WORD [es:di+4]
411 add edx,ecx
412
413 ; Check to see if we have reached the
414 ; end of the root directory
415 cmp edx,eax
416 jb SearchRootDirectory
417 jmp PrintFileNotFound
418
419 FoundFile:
420 mov eax,[es:di] ; Get inode number from directory entry
421 call Ext2ReadInode ; Read in the inode
422
423 ; Point ES:DI to the inode structure at 6000:8000
424 pop es
425 pop di ; These were saved earlier
426
427 mov cx,[es:di] ; Get the file mode so we can make sure it's a regular file
428 and ch,EXT2_S_IFMT ; Mask off everything but the file type
429 cmp ch,EXT2_S_IFREG ; Make sure it's a regular file
430 je LoadFreeLoader
431 jmp PrintRegFileError
432
433 LoadFreeLoader:
434 mov si,msgLoading ; "Loading FreeLoader..." message
435 call PutChars ; Display it
436
437 call Ext2ReadEntireFile ; Read freeldr.sys to 0000:8000
438
439 mov dl,[BYTE bp+BootDrive]
440 mov dh,[BYTE bp+BootPartition]
441 push 0 ; push segment (0x0000)
442 mov eax, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
443 add eax, 0x8000 ; RVA -> VA
444 push ax ; push offset
445 retf ; Transfer control to FreeLoader
446
447
448
449
450
451 ; Reads ext2 file data into [0000:8000]
452 ; This function assumes that the file's
453 ; inode has been read in to 6000:8000 *and*
454 ; ES:DI points to 6000:8000
455 ; This will load all the blocks up to
456 ; and including the double-indirect pointers.
457 ; This should be sufficient because it
458 ; allows for ~64MB which is much bigger
459 ; than we need for a boot loader.
460 Ext2ReadEntireFile:
461
462 ; Reset the load segment
463 mov WORD [BYTE bp+Ext2ReadEntireFileLoadSegment],800h
464
465 ; Now we must calculate how
466 ; many blocks to read in
467 ; We will do this by rounding the
468 ; file size up to the next block
469 ; size and then dividing by the block size
470 mov eax,DWORD [BYTE bp+Ext2BlockSizeInBytes] ; Get the block size in bytes
471 push eax
472 dec eax ; Ext2BlockSizeInBytes -= 1
473 add eax,DWORD [es:di+4] ; Add the file size
474 xor edx,edx
475 pop ecx ; Divide by the block size in bytes
476 div ecx ; EAX now contains the number of blocks to load
477 push eax
478
479 ; Make sure the file size isn't zero
480 cmp eax,byte 0
481 jnz Ext2ReadEntireFile2
482 jmp PrintFileSizeError
483
484 Ext2ReadEntireFile2:
485 ; Save the indirect & double indirect pointers
486 mov edx,DWORD [es:di+0x58] ; Get indirect pointer
487 mov [BYTE bp+Ext2InodeIndirectPointer],edx ; Save indirect pointer
488 mov edx,DWORD [es:di+0x5c] ; Get double indirect pointer
489 mov [BYTE bp+Ext2InodeDoubleIndirectPointer],edx ; Save double indirect pointer
490
491 ; Now copy the direct pointers to 7000:0000
492 ; so that we can call Ext2ReadDirectBlocks
493 push ds ; Save DS
494 push es
495 push WORD 7000h
496 pop es
497 pop ds
498 mov si,8028h
499 xor di,di ; DS:SI = 6000:8028 ES:DI = 7000:0000
500 mov cx,24 ; Moving 24 words of data
501 rep movsw
502 pop ds ; Restore DS
503
504 ; Now we have all the block pointers in the
505 ; right location so read them in
506 pop eax ; Restore the total number of blocks in this file
507 xor ecx,ecx ; Set the max count of blocks to read to 12
508 mov cl,12 ; which is the number of direct block pointers in the inode
509 call Ext2ReadDirectBlockList
510
511 ; Check to see if we actually have
512 ; blocks left to read
513 cmp eax,byte 0
514 jz Ext2ReadEntireFileDone
515
516 ; Now we have read all the direct blocks in
517 ; the inode. So now we have to read the indirect
518 ; block and read all it's direct blocks
519 push eax ; Save the total block count
520 mov eax,DWORD [BYTE bp+Ext2InodeIndirectPointer] ; Get the indirect block pointer
521 push WORD 7000h
522 pop es
523 xor bx,bx ; Set the load address to 7000:0000
524 call Ext2ReadBlock ; Read the block
525
526 ; Now we have all the block pointers from the
527 ; indirect block in the right location so read them in
528 pop eax ; Restore the total block count
529 mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] ; Get the number of block pointers that one block contains
530 call Ext2ReadDirectBlockList
531
532 ; Check to see if we actually have
533 ; blocks left to read
534 cmp eax,byte 0
535 jz Ext2ReadEntireFileDone
536
537 ; Now we have read all the direct blocks from
538 ; the inode's indirect block pointer. So now
539 ; we have to read the double indirect block
540 ; and read all it's indirect blocks
541 ; (whew, it's a good thing I don't support triple indirect blocks)
542 mov [BYTE bp+Ext2BlocksLeftToRead],eax ; Save the total block count
543 mov eax,DWORD [BYTE bp+Ext2InodeDoubleIndirectPointer] ; Get the double indirect block pointer
544 push WORD 7800h
545 pop es
546 push es ; Save an extra copy of this value on the stack
547 xor bx,bx ; Set the load address to 7000:8000
548 call Ext2ReadBlock ; Read the block
549
550 pop es ; Put 7800h into ES (saved on the stack already)
551 xor di,di
552
553 Ext2ReadIndirectBlock:
554 mov eax,DWORD [es:di] ; Get indirect block pointer
555 add di,BYTE 4 ; Update DI for next array index
556 push es
557 push di
558
559 push WORD 7000h
560 pop es
561 xor bx,bx ; Set the load address to 7000:0000
562 call Ext2ReadBlock ; Read the indirect block
563
564 ; Now we have all the block pointers from the
565 ; indirect block in the right location so read them in
566 mov eax,DWORD [BYTE bp+Ext2BlocksLeftToRead] ; Restore the total block count
567 mov ecx,DWORD [BYTE bp+Ext2PointersPerBlock] ; Get the number of block pointers that one block contains
568 call Ext2ReadDirectBlockList
569 mov [BYTE bp+Ext2BlocksLeftToRead],eax ; Save the total block count
570 pop di
571 pop es
572
573 ; Check to see if we actually have
574 ; blocks left to read
575 cmp eax,byte 0
576 jnz Ext2ReadIndirectBlock
577
578 Ext2ReadEntireFileDone:
579 ret
580
581 ; Reads a maximum number of blocks
582 ; from an array at 7000:0000
583 ; and updates the total count
584 ; ECX contains the max number of blocks to read
585 ; EAX contains the number of blocks left to read
586 ; On return:
587 ; EAX contains the new number of blocks left to read
588 Ext2ReadDirectBlockList:
589 cmp eax,ecx ; Compare it to the maximum number of blocks to read
590 ja CallExt2ReadDirectBlocks ; If it will take more blocks then just read all of the blocks
591 mov cx,ax ; Otherwise adjust the block count accordingly
592
593 CallExt2ReadDirectBlocks:
594 sub eax,ecx ; Subtract the number of blocks being read from the total count
595 push eax ; Save the new total count
596 call Ext2ReadDirectBlocks
597 pop eax ; Restore the total count
598 ret
599
600
601 ; Reads a specified number of blocks
602 ; from an array at 7000:0000
603 ; CX contains the number of blocks to read
604 Ext2ReadDirectBlocks:
605
606 push WORD 7000h
607 pop es
608 xor di,di ; Set ES:DI = 7000:0000
609
610 Ext2ReadDirectBlocksLoop:
611 mov eax,[es:di] ; Get direct block pointer from array
612 add di,BYTE 4 ; Update DI for next array index
613
614 push cx ; Save number of direct blocks left
615 push es ; Save array segment
616 push di ; Save array offset
617 mov es,[BYTE bp+Ext2ReadEntireFileLoadSegment]
618 xor bx,bx ; Setup load address for next read
619
620 call Ext2ReadBlock ; Read the block (this updates ES for the next read)
621
622 mov [BYTE bp+Ext2ReadEntireFileLoadSegment],es ; Save updated ES
623
624 pop di ; Restore the array offset
625 pop es ; Restore the array segment
626 pop cx ; Restore the number of blocks left
627
628 loop Ext2ReadDirectBlocksLoop
629
630 ; At this point all the direct blocks should
631 ; be loaded and ES (Ext2ReadEntireFileLoadSegment)
632 ; should be ready for the next read.
633 ret
634
635
636
637 ; Displays a file not found error message
638 ; And reboots
639 PrintFileNotFound:
640 mov si,msgFreeLdr ; FreeLdr not found message
641 jmp short DisplayItAndReboot
642
643 ; Displays a file size is 0 error
644 ; And reboots
645 PrintFileSizeError:
646 mov si,msgFileSize ; Error message
647 jmp short DisplayItAndReboot
648
649 ; Displays a file is not a regular file error
650 ; And reboots
651 PrintRegFileError:
652 mov si,msgRegFile ; Error message
653 DisplayItAndReboot:
654 call PutChars ; Display it
655 jmp Reboot
656
657 msgFreeLdr db 'freeldr.sys not found',0
658 msgFileSize db 'File size is 0',0
659 msgRegFile db 'freeldr.sys isnt a regular file',0
660 filename db 'freeldr.sys'
661 msgLoading db 'Loading FreeLoader...',0
662
663 times 1022-($-$$) db 0 ; Pad to 1022 bytes
664
665 dw 0aa55h ; BootSector signature