Reactos
1/*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: EXTFS volume boot sector
5 * COPYRIGHT: Copyright 2002-2003 Brian Palmer <brianp@sginet.com>
6 * Copyright 2024-2025 Daniel Victor <ilauncherdeveloper@gmail.com>
7 */
8
9#include <asm.inc>
10#include <freeldr/include/arch/pc/x86common.h>
11
12// Boot sector constants
13#define BOOTSECTOR_BASE_ADDRESS HEX(7C00)
14#define EXTLDR_BOOTSECTOR_SIZE 1024
15#define EXT_POINTER_SIZE 4
16#define EXT_EXTENT_SIZE 12
17
18// Maximum extent values
19#define EXT_EXTENT_MAX_LEVEL 5
20#define EXT_EXTENT_MAX_LENGTH 32768
21
22// Group descriptor offsets
23#define EXT_GROUP_DESC_INODE_TABLE_OFFSET 8
24
25// Extent offsets
26#define EXT_EXTENT_HEADER_ENTRIES_OFFSET 2
27#define EXT_EXTENT_HEADER_DEPTH_OFFSET 6
28#define EXT_EXTENT_INDEX_LEAF_OFFSET 4
29#define EXT_EXTENT_LENGTH_OFFSET 4
30#define EXT_EXTENT_START_OFFSET 8
31
32// Inode offsets
33#define EXT_INODE_SIZE_OFFSET 4
34#define EXT_INODE_FLAGS_OFFSET 32
35#define EXT_INODE_BLOCK_POINTER_OFFSET 40
36
37// Directory entry offsets
38#define EXT_DIRECTORY_ENTRY_SIZE_OFFSET 4
39#define EXT_DIRECTORY_ENTRY_NAME_LENGTH_OFFSET 6
40#define EXT_DIRECTORY_ENTRY_NAME_OFFSET 8
41
42// Inode flags
43#define EXT_INODE_FLAG_EXTENTS HEX(80000)
44
45// Inode blocks constants
46#define EXT_INODE_BLOCKS 12
47#define EXT_INODE_INDIRECT_BLOCKS 3
48
49// Root Inode
50#define EXT_ROOT_INODE 2
51
52// Inode address
53#define EXT_INODE_ADDRESS HEX(9000)
54
55// Data block addresses
56#define EXT_BLOCK_ADDRESS HEX(1000)
57#define EXT_BLOCK2_ADDRESS HEX(2000)
58#define EXT_BLOCK3_ADDRESS HEX(3000)
59#define EXT_BLOCK4_ADDRESS HEX(4000)
60#define EXT_BLOCK5_ADDRESS HEX(5000)
61#define EXT_BLOCK6_ADDRESS HEX(6000)
62#define EXT_BLOCK7_ADDRESS HEX(A000)
63
64// Inode types
65#define EXT_INODE_TYPE_MASK HEX(F000)
66#define EXT_INODE_TYPE_REGULAR HEX(8000)
67
68// File size limit
69#define EXT_INODE_DATA_SIZE_LIMIT HEX(F000)
70
71// Offset of functions addresses that will be used by the extldr.sys 3rd-stage bootsector
72#define ExtReadBlockOffset 2
73#define ExtReadInodeOffset 4
74#define DisplayItAndRebootOffset 6
75#define PutCharsOffset 8
76
77// Boot sector stack constants
78#define BOOTSECTOR_STACK_TEMP_VARIABLES 2
79#define BOOTSECTOR_STACK_TEMP_VARIABLES_SIZE (4 * BOOTSECTOR_STACK_TEMP_VARIABLES)
80#define BOOTSECTOR_STACK_OFFSET (8 + BOOTSECTOR_STACK_TEMP_VARIABLES_SIZE)
81#define BOOTSECTOR_STACK_BASE (BOOTSECTOR_BASE_ADDRESS - BOOTSECTOR_STACK_OFFSET)
82#define BP_REL(x) ss:[bp + (x - BOOTSECTOR_BASE_ADDRESS)]
83
84// Temporary variables
85#define ExtFileSizeState ((BOOTSECTOR_STACK_BASE + BOOTSECTOR_STACK_TEMP_VARIABLES_SIZE) - 4)
86#define LBASectorsRead (ExtFileSizeState - 4)
87
88.code16
89
90#ifndef INCLUDED_ASM
91
92start:
93 jmp short main
94 nop
95
96// Fields that will be changed by the installer
97BootDrive:
98 .byte HEX(FF)
99ExtVolumeStartSector:
100 .long 263088 // Start sector of the ext2 volume
101ExtBlockSize:
102 .long 2 // Block size in sectors
103ExtBlockSizeInBytes:
104 .long 1024 // Block size in bytes
105ExtPointersPerBlock:
106 .long 256 // Number of block pointers that can be contained in one block
107ExtGroupDescSize:
108 .long 32 // Size of Group Descriptor
109ExtFirstDataBlock:
110 .long 2 // First data block (2 for 1024-byte blocks, 1 for bigger sizes)
111ExtInodeSize:
112 .long 128 // Size of Inode
113ExtInodesPerGroup:
114 .long 2048 // Number of inodes per group
115
116// File variables
117ExtFileSize:
118 .long 0 // File size in bytes
119ExtFileAddress:
120 .long FREELDR_BASE // File address
121ExtFileAddressOld:
122 .long FREELDR_BASE // Old file address
123
124// Inode variables
125ExtReadInodeGroup:
126 .long 0
127ExtReadInodeIndex:
128 .long 0
129ExtReadInodeGroupBlock:
130 .long 0
131ExtReadInodeIndexBlock:
132 .long 0
133ExtReadInodeGroupOffset:
134 .word 0
135ExtReadInodeIndexOffset:
136 .word 0
137
138main:
139 xor ax, ax // Setup segment registers
140 mov ds, ax // Make DS correct
141 mov es, ax // Make ES correct
142 mov ss, ax // Make SS correct
143 mov bp, BOOTSECTOR_BASE_ADDRESS
144 mov sp, bp // Setup a stack
145 sub sp, BOOTSECTOR_STACK_OFFSET
146
147 // Save the function addresses so the helper code knows where to call them
148 mov word ptr ss:[bp-ExtReadBlockOffset], offset ExtReadBlock
149 mov word ptr ss:[bp-ExtReadInodeOffset], offset ExtReadInode
150 mov word ptr ss:[bp-DisplayItAndRebootOffset], offset DisplayItAndReboot
151 mov word ptr ss:[bp-PutCharsOffset], offset PutChars
152
153 mov si, offset BootDrive
154 cmp byte ptr [si], HEX(0ff) // If they have specified a boot drive then use it
155 jne CheckInt13hExtensions
156
157 mov byte ptr [si], dl // Save the boot drive
158
159// Now check if this computer supports extended reads. This boot sector will not work without it.
160CheckInt13hExtensions:
161 mov ah, HEX(41) // AH = 41h
162 mov bx, HEX(55aa) // BX = 55AAh
163 int HEX(13) // IBM/MS INT 13 Extensions - INSTALLATION CHECK
164 jc PrintDiskError // CF set on error (extensions not supported)
165 cmp bx, HEX(aa55) // BX = AA55h if installed
166 jne PrintDiskError
167 test cl, 1 // si = API subset support bitmap
168 jz PrintDiskError // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
169
170LoadExtraBootCode:
171 // First we have to load our extra boot code at
172 // sector 1 into memory at [0000:7e00h]
173 xor eax, eax
174 inc eax
175 mov cx, 1
176 xor bx, bx
177 mov es, bx // Read sector to [0000:7e00h]
178 mov bx, HEX(7e00)
179 call ReadSectors
180
181 jmp LoadRootDirectory
182
183// Reads logical sectors into ES:[BX]
184// EAX has logical sector number to read
185// CX has number of sectors to read
186ReadSectors:
187 push es
188 add eax, dword ptr BP_REL(ExtVolumeStartSector) // Add the start of the volume
189 // If at all possible we want to use LBA routines because
190 // they are optimized to read more than 1 sector per read
191
192ReadSectorsLBA:
193 pushad // Save logical sector number & sector count
194
195 cmp cx, 64 // Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64
196 jbe ReadSectorsSetupDiskAddressPacket // If we are reading less than 65 sectors then just do the read
197 mov cx, 64 // Otherwise read only 64 sectors on this loop iteration
198
199ReadSectorsSetupDiskAddressPacket:
200 movzx ecx, cx
201 mov dword ptr BP_REL(LBASectorsRead), ecx
202 data32 push 0
203 push eax // Put 64-bit logical block address on stack
204 push es // Put transfer segment on stack
205 push bx // Put transfer offset on stack
206 push cx // Set transfer count
207 push 16 // Set size of packet to 10h
208 mov si, sp // Setup disk address packet on stack
209
210 mov dl, byte ptr BP_REL(BootDrive) // Drive number
211 mov ah, HEX(42) // Int 13h, AH = 42h - Extended Read
212 int HEX(13) // Call BIOS
213 jc PrintDiskError // If the read failed then abort
214
215 add sp, 16 // Remove disk address packet from stack
216
217 popad // Restore sector count & logical sector number
218
219 push bx
220 mov ebx, dword ptr BP_REL(LBASectorsRead)
221 add eax, ebx // Increment sector to read
222 shl ebx, 5
223 mov dx, es
224 add dx, bx // Setup read buffer for next sector
225 mov es, dx
226 pop bx
227
228 sub cx, word ptr BP_REL(LBASectorsRead)
229 jnz ReadSectorsLBA // Read next sector
230
231 pop es
232 ret
233
234// Displays a disk error message
235// And reboots
236PrintDiskError:
237 mov si, offset msgDiskError // Bad boot disk message
238 call PutChars // Display it
239
240Reboot:
241 mov si, offset msgAnyKey // Press any key message
242 call PutChars // Display it
243 xor ax, ax
244 int HEX(16) // Wait for a keypress
245 int HEX(19) // Reboot
246
247.PutCharsLoop:
248 mov ah, HEX(0E)
249 mov bx, 7
250 int HEX(10)
251PutChars:
252 lodsb
253 or al, al
254 jnz .PutCharsLoop
255 ret
256
257SwapESWithDS:
258 // Swap ES and DS
259 push es
260 push ds
261 pop es
262 pop ds
263 ret
264
265ExtReadGroupDescriptor:
266 mov eax, dword ptr BP_REL(ExtReadInodeGroupBlock) // Get Inode group block
267 add eax, dword ptr BP_REL(ExtFirstDataBlock) // Add the Group Descriptor offset
268 call ExtSetInodeSegment
269
270ExtReadBlock:
271 xor edx, edx
272 mov ecx, dword ptr BP_REL(ExtBlockSize)
273 mul ecx
274 jmp ReadSectors
275
276// EAX
277ExtCalculateBlock:
278 xor edx, edx // Clear EDX before division
279 div dword ptr BP_REL(ExtBlockSizeInBytes) // Inode /= ExtBlockSizeInBytes
280 mov dword ptr ds:[bp + si], eax // Store the Inode block
281 ret
282
283// SI, DI
284ExtCalculateOffset:
285 add bx, bp // Sum BX with BP for absolute address
286 xor edx, edx // Clear EDX before multiplication
287 mov eax, dword ptr ds:[bp + si] // Get the Inode block
288 mul dword ptr BP_REL(ExtBlockSizeInBytes) // Inode *= ExtBlockSizeInBytes
289 mov ecx, dword ptr ds:[bx] // Get the Inode
290 sub ecx, eax // Subtract the original Inode with rounded down Inode
291 mov word ptr ds:[bp + di], cx // Store the rounded down Inode
292 ret
293
294ExtSetOldFileSegment:
295 mov ebx, dword ptr BP_REL(ExtFileAddressOld) // Get the EXT old file address
296 jmp .ExtSegSkip
297ExtSetFileSegment:
298 mov ebx, dword ptr BP_REL(ExtFileAddress) // Get the EXT file address
299.ExtSegSkip:
300 shr ebx, 4 // Shift four bits to the right to get segment
301 jmp .ExtSkip
302ExtSetInodeSegment:
303 mov bx, EXT_INODE_ADDRESS / 16 // Get the EXT inode address
304.ExtSkip:
305 mov es, bx // Set ES
306 xor bx, bx // Clear BX
307 ret
308
309// Read the Inode in EAX register
310ExtReadInode:
311 xor edx, edx // Clear EDX before division
312 dec eax // Inode--
313 div dword ptr BP_REL(ExtInodesPerGroup) // Inode /= ExtInodesPerGroup
314 mov dword ptr BP_REL(ExtReadInodeGroup), eax // Store the Inode group
315 mov dword ptr BP_REL(ExtReadInodeIndex), edx // Store the Inode index
316
317 xor edx, edx // Clear EDX before multiplication
318 mul dword ptr BP_REL(ExtGroupDescSize) // Inode group *= ExtGroupDescSize
319 mov dword ptr BP_REL(ExtReadInodeGroup), eax // Store the precalculated Inode group
320
321 xor edx, edx // Clear EDX before multiplication
322 mov eax, dword ptr BP_REL(ExtReadInodeIndex) // Get the read Inode index
323 mul dword ptr BP_REL(ExtInodeSize) // Inode group *= ExtInodeSize
324 mov dword ptr BP_REL(ExtReadInodeIndex), eax // Store the Inode index
325
326 // Calculate the Inode index block
327 mov si, offset ExtReadInodeIndexBlock - start
328 call ExtCalculateBlock
329
330 // Calculate the Inode group block
331 mov eax, dword ptr BP_REL(ExtReadInodeGroup)
332 mov si, offset ExtReadInodeGroupBlock - start
333 call ExtCalculateBlock
334
335 // Calculate the Inode group offset
336 mov bx, offset ExtReadInodeGroup - start
337 mov si, offset ExtReadInodeGroupBlock - start
338 mov di, offset ExtReadInodeGroupOffset - start
339 call ExtCalculateOffset
340
341 // Calculate the Inode index offset
342 mov bx, offset ExtReadInodeIndex - start
343 mov si, offset ExtReadInodeIndexBlock - start
344 mov di, offset ExtReadInodeIndexOffset - start
345 call ExtCalculateOffset
346
347 // Read group descriptor
348 call ExtReadGroupDescriptor
349
350 // Set the offset address
351 mov si, word ptr BP_REL(ExtReadInodeGroupOffset)
352
353 // Get InodeTable field from the ExtGroupDescriptor structure
354 mov eax, dword ptr es:[si + EXT_GROUP_DESC_INODE_TABLE_OFFSET]
355
356 // Sum EAX with Inode index block
357 add eax, dword ptr BP_REL(ExtReadInodeIndexBlock)
358
359 jmp ExtReadBlock
360
361msgDiskError:
362 .ascii "Disk error", CR, LF, NUL
363msgAnyKey:
364 .ascii "Press any key", CR, LF, NUL
365
366.org 509
367
368BootPartition:
369 .byte 0
370
371.word HEX(AA55) // BootSector signature
372
373// End of bootsector
374//
375// Now starts the extra boot code that we will store
376// at sector 1 on a EXT volume
377
378LoadRootDirectory:
379 mov al, EXT_ROOT_INODE // Put the root directory inode number in AL
380 movzx eax, al // Convert AL to EAX
381
382 call ExtReadInode // Read the inode
383 call BasicReadFile // Load the directory entries using basic function
384 call SearchFile // Find the extended loader and run it
385
386 jmp ExtLdrPrintFileNotFound // If the extended loader wasn't found, display an error
387
388ExtInodeDetectExtentsFlag:
389 mov eax, es:[si + EXT_INODE_FLAGS_OFFSET]
390 test eax, EXT_INODE_FLAG_EXTENTS
391 ret
392
393ExtUpdateFileSize:
394 mov eax, dword ptr BP_REL(ExtBlockSizeInBytes)
395
396ExtAdjustFileSize:
397 // Update the file size
398 sub dword ptr BP_REL(ExtFileSizeState), eax
399 add dword ptr BP_REL(ExtFileAddress), eax
400 ret
401
402ExtReadFileDone:
403 push eax
404 mov eax, dword ptr BP_REL(ExtFileSizeState)
405 cmp eax, dword ptr BP_REL(ExtBlockSizeInBytes)
406 pop eax
407 ret
408
409ExtFileReadBlocks:
410 push es
411.FRLoop:
412 // Check if there is no more blocks to read
413 call ExtReadFileDone
414 jb .FRDone
415
416 // If the block count is zero then do nothing
417 test bx, bx
418 jz .FRDone
419
420 // Read the block
421 pushad
422 call ExtSetFileSegment
423 call ExtReadBlock
424 popad
425
426 // Update the file size
427 call ExtUpdateFileSize
428
429 // Go to the next block and decrement the block count
430 inc eax
431 dec bx
432
433 // Loop until all blocks are read
434 jmp .FRLoop
435.FRDone:
436 pop es
437 ret
438
439BasicReadFileExtents:
440 // Add block pointer offset
441 add si, EXT_INODE_BLOCK_POINTER_OFFSET
442
443.DepthExtentsLoop:
444 // Load extent header depth
445 mov dx, word ptr es:[si + EXT_EXTENT_HEADER_DEPTH_OFFSET]
446
447 // Check if depth is zero
448 test dx, dx
449 jz .DepthExtentsDone
450
451 // Go to next extent
452 add si, EXT_EXTENT_SIZE
453
454 // Push all registers
455 pushad
456
457 // Read the extent block
458 mov eax, dword ptr es:[si + EXT_EXTENT_INDEX_LEAF_OFFSET]
459 call ExtSetInodeSegment
460 call ExtReadBlock
461
462 // Pop all registers
463 popad
464
465 // Reset SI
466 xor si, si
467
468 jmp .DepthExtentsLoop
469.DepthExtentsDone:
470 // Load extent header entries
471 mov cx, word ptr es:[si + EXT_EXTENT_HEADER_ENTRIES_OFFSET]
472
473.FinalExtentsLoop:
474 // Check if there is no more blocks to read
475 call ExtReadFileDone
476 jb .FinalExtentsDone
477
478 // Go to next extent
479 add si, EXT_EXTENT_SIZE
480
481 // Load extent length
482 mov bx, word ptr es:[si + EXT_EXTENT_LENGTH_OFFSET]
483 and ebx, HEX(FFFF)
484
485 // Check if extent is sparse
486 cmp bx, EXT_EXTENT_MAX_LENGTH
487 jbe .NotSparse
488
489 // Adjust sparse extent length
490 sub bx, EXT_EXTENT_MAX_LENGTH
491
492 // Adjust extent length to byte count
493 // by multiplying extent length to block size
494 xor edx, edx
495 mov eax, dword ptr BP_REL(ExtBlockSizeInBytes)
496 mul ebx
497
498 // Adjust file size for sparse extent
499 call ExtAdjustFileSize
500
501 jmp .FinalExtentsSkip
502
503.NotSparse:
504 // Read blocks from extent start
505 mov eax, dword ptr es:[si + EXT_EXTENT_START_OFFSET]
506 call ExtFileReadBlocks
507
508.FinalExtentsSkip:
509 // Loop to process next extent
510 loop .FinalExtentsLoop
511
512.FinalExtentsDone:
513 ret
514
515BasicReadFile:
516 push es
517 pushad
518 call ExtSetInodeSegment
519
520 // Set the correct Inode offset
521 mov si, word ptr BP_REL(ExtReadInodeIndexOffset)
522
523 // Set the old file address
524 mov eax, dword ptr BP_REL(ExtFileAddress)
525 mov dword ptr BP_REL(ExtFileAddressOld), eax
526
527 // Set the file size limit
528 mov eax, EXT_INODE_DATA_SIZE_LIMIT
529
530 // Load file size from Inode
531 mov ebx, dword ptr es:[si + EXT_INODE_SIZE_OFFSET]
532
533 // Compare and limit file size
534 cmp ebx, eax
535 jbe .BelowOrEqualSize
536 mov ebx, eax
537.BelowOrEqualSize:
538 // Store the file size in the ExtFileSize variable
539 mov dword ptr BP_REL(ExtFileSize), ebx
540
541 // Set rounded up file size
542 add ebx, dword ptr BP_REL(ExtBlockSizeInBytes)
543 dec ebx
544 mov dword ptr BP_REL(ExtFileSizeState), ebx
545
546 // Don't use the extents method if theres no extents flag
547 call ExtInodeDetectExtentsFlag
548 jz .NoExtents
549
550 // If this Inode use Extents mapping then use the extents method and skip the entire classic method
551 call BasicReadFileExtents
552 jmp .LDone
553
554.NoExtents:
555 // Set up for reading direct block addresses
556 xor ecx, ecx
557 mov cl, EXT_INODE_BLOCKS
558 add si, EXT_INODE_BLOCK_POINTER_OFFSET
559.LLoop:
560 call ExtSetInodeSegment
561
562 call ExtReadFileDone
563 jb .LDone
564
565 // Get the block address
566 mov eax, dword ptr es:[si]
567
568 // If the block address is zero, skip the block
569 test eax, eax
570 jz .LSkipBlock
571
572 // Set the file segment
573 call ExtSetFileSegment
574
575 // Read the block
576 call ExtReadBlock
577.LSkipBlock:
578 call ExtUpdateFileSize
579
580 // Increment block
581 add si, EXT_POINTER_SIZE
582
583 // Loop until all blocks are loaded
584 loop .LLoop
585.LDone:
586 popad
587 pop es
588 ret
589
590SearchFile:
591 call ExtSetOldFileSegment
592 call SwapESWithDS
593
594 xor si, si
595 mov dx, word ptr BP_REL(ExtFileSize)
596.FLoop:
597 mov eax, dword ptr ds:[si] // Load directory Inode
598
599 cmp si, dx // End of buffer reached?
600 jae .Done // Abort the search if yes
601
602 // Save SI
603 push si
604
605 test eax, eax // Check if Inode is zero
606 jz .Skip // Skip this entry if yes
607
608 mov di, offset ExtLdrFileName // Load target filename address
609 mov cx, offset ExtLdrFileNameEnd - ExtLdrFileName // Length of filename to compare
610 cmp byte ptr ds:[si + EXT_DIRECTORY_ENTRY_NAME_LENGTH_OFFSET], cl // Compare if both names have the same length
611 jnz .Skip // Skip this entry if not
612 add si, EXT_DIRECTORY_ENTRY_NAME_OFFSET // Move to filename in entry
613 repe cmpsb // Compare filenames
614 pop si // Restore SI
615 jz LoadExtLdr // Found matching file
616 push si // Save SI
617
618.Skip:
619 // Restore SI
620 pop si
621
622 // Move to next directory entry and continue looping
623 add si, word ptr ds:[si + EXT_DIRECTORY_ENTRY_SIZE_OFFSET]
624 jmp .FLoop
625.Done:
626 ret
627
628LoadExtLdr:
629 // Swap ES and DS
630 call SwapESWithDS
631
632 push si // Save SI
633 mov si, offset msgLoadingExtLdr // Point SI to a loading message
634 call PutChars // Show the message
635 pop si // Restore SI
636
637 mov eax, dword ptr es:[si] // Load directory Inode
638 call ExtReadInode // Read the inode
639 mov si, word ptr BP_REL(ExtReadInodeIndexOffset) // Set the correct offset
640
641 // Get Inode type
642 mov ax, word ptr es:[si]
643 and ax, EXT_INODE_TYPE_MASK
644
645 cmp ax, EXT_INODE_TYPE_REGULAR // Check if regular file
646 jnz ExtLdrPrintRegFileError // If not, handle error
647
648 call BasicReadFile // Load the file using basic function
649 call ExtSetOldFileSegment // Set old file segment
650 call SwapESWithDS // Swap ES with DS before copy
651
652 // Copy the loaded file to 1KB ahead of this bootsector
653 xor si, si
654 mov di, offset ExtLdrEntryPoint
655 mov cx, EXTLDR_BOOTSECTOR_SIZE
656 rep movsb
657
658 ljmp16 0, ExtLdrEntryPoint
659
660ExtLdrPrintFileNotFound:
661 // Make DS correct, display it and reboot
662 call SwapESWithDS
663 mov si, offset msgExtLdr
664 jmp DisplayItAndReboot
665
666ExtLdrPrintRegFileError:
667 mov si, offset msgExtLdrNotRegularFile // ExtLdr not found message
668DisplayItAndReboot:
669 call PutChars // Display it
670 jmp Reboot
671
672ExtLdrFileName:
673 .ascii "extldr.sys"
674ExtLdrFileNameEnd:
675
676msgExtLdr:
677 .ascii "extldr.sys not found", CR, LF, NUL
678msgExtLdrNotRegularFile:
679 .ascii "extldr.sys is not a regular file", CR, LF, NUL
680msgLoadingExtLdr:
681 .ascii "Loading ExtLoader...", CR, LF, NUL
682
683.org 1022
684
685.word HEX(AA55) // BootSector signature
686
687ExtLdrEntryPoint:
688// ExtLdr is loaded here
689
690.endcode16
691
692END
693
694#else
695
696#define start BOOTSECTOR_BASE_ADDRESS
697
698#define BootDrive (start + 3)
699#define ExtVolumeStartSector (BootDrive + 1)
700#define ExtBlockSize (ExtVolumeStartSector + 4)
701#define ExtBlockSizeInBytes (ExtBlockSize + 4)
702#define ExtPointersPerBlock (ExtBlockSizeInBytes + 4)
703#define ExtGroupDescSize (ExtPointersPerBlock + 4)
704#define ExtFirstDataBlock (ExtGroupDescSize + 4)
705#define ExtInodeSize (ExtFirstDataBlock + 4)
706#define ExtInodesPerGroup (ExtInodeSize + 4)
707
708#define ExtFileSize (ExtInodesPerGroup + 4)
709#define ExtFileAddress (ExtFileSize + 4)
710#define ExtFileAddressOld (ExtFileAddress + 4)
711
712#define ExtReadInodeGroup (ExtFileAddressOld + 4)
713#define ExtReadInodeIndex (ExtReadInodeGroup + 4)
714#define ExtReadInodeGroupBlock (ExtReadInodeIndex + 4)
715#define ExtReadInodeIndexBlock (ExtReadInodeGroupBlock + 4)
716#define ExtReadInodeGroupOffset (ExtReadInodeIndexBlock + 4)
717#define ExtReadInodeIndexOffset (ExtReadInodeGroupOffset + 2)
718
719#define BootPartition (BootDrive + 506)
720
721#define ExtReadBlock word ptr ss:[bp-ExtReadBlockOffset]
722#define ExtReadInode word ptr ss:[bp-ExtReadInodeOffset]
723#define DisplayItAndReboot word ptr ss:[bp-DisplayItAndRebootOffset]
724#define PutChars word ptr ss:[bp-PutCharsOffset]
725
726#endif