📄 ext2.asm
字号:
; EXT2.ASM
; EXT2 Boot Sector
; Copyright (c) 2002, 2003 Brian Palmer
; [bp-0x04] Here we will store the number of sectors per track
; [bp-0x08] Here we will store the number of heads
; [bp-0x0c] Here we will store the size of the disk as the BIOS reports in CHS form
; [bp-0x10] Here we will store the number of LBA sectors read
SECTORS_PER_TRACK equ 0x04
NUMBER_OF_HEADS equ 0x08
BIOS_CHS_DRIVE_SIZE equ 0x0C
LBA_SECTORS_READ equ 0x10
EXT2_ROOT_INO equ 2
EXT2_S_IFMT equ 0f0h
EXT2_S_IFREG equ 080h
org 7c00h
segment .text
bits 16
start:
jmp short main
nop
BootDrive db 0x80
;BootPartition db 0 ; Moved to end of boot sector to have a standard format across all boot sectors
;SectorsPerTrack db 63 ; Moved to [bp-SECTORS_PER_TRACK]
;NumberOfHeads dw 16 ; Moved to [bp-NUMBER_OF_HEADS]
;BiosCHSDriveSize dd (1024 * 1024 * 63) ; Moved to [bp-BIOS_CHS_DRIVE_SIZE]
;LBASectorsRead dd 0 ; Moved to [bp-LBA_SECTORS_READ]
Ext2VolumeStartSector dd 263088 ; Start sector of the ext2 volume
Ext2BlockSize dd 2 ; Block size in sectors
Ext2BlockSizeInBytes dd 1024 ; Block size in bytes
Ext2PointersPerBlock dd 256 ; Number of block pointers that can be contained in one block
Ext2GroupDescPerBlock dd 32 ; Number of group descriptors per block
Ext2FirstDataBlock dd 1 ; First data block (1 for 1024-byte blocks, 0 for bigger sizes)
Ext2InodesPerGroup dd 2048 ; Number of inodes per group
Ext2InodesPerBlock dd 8 ; Number of inodes per block
Ext2ReadEntireFileLoadSegment:
dw 0
Ext2InodeIndirectPointer:
dd 0
Ext2InodeDoubleIndirectPointer:
dd 0
Ext2BlocksLeftToRead:
dd 0
main:
xor ax,ax ; Setup segment registers
mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct
mov ss,ax ; Make SS correct
mov bp,7c00h
mov sp,7b00h ; Setup a stack
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
jne GetDriveParameters
mov [BYTE bp+BootDrive],dl ; Save the boot drive
GetDriveParameters:
mov ah,08h
mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl
int 13h ; Request drive parameters from the bios
jnc CalcDriveSize ; If the call succeeded then calculate the drive size
; If we get here then the call to the BIOS failed
; so just set CHS equal to the maximum addressable
; size
mov cx,0ffffh
mov dh,cl
CalcDriveSize:
; Now that we have the drive geometry
; lets calculate the drive size
mov bl,ch ; Put the low 8-bits of the cylinder count into BL
mov bh,cl ; Put the high 2-bits in BH
shr bh,6 ; Shift them into position, now BX contains the cylinder count
and cl,3fh ; Mask off cylinder bits from sector count
; CL now contains sectors per track and DH contains head count
movzx eax,dh ; Move the heads into EAX
movzx ebx,bx ; Move the cylinders into EBX
movzx ecx,cl ; Move the sectors per track into ECX
inc eax ; Make it one based because the bios returns it zero based
mov [BYTE bp-NUMBER_OF_HEADS],eax ; Save number of heads
mov [BYTE bp-SECTORS_PER_TRACK],ecx ; Save number of sectors per track
inc ebx ; Make the cylinder count one based also
mul ecx ; Multiply heads with the sectors per track, result in edx:eax
mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already]
; We now have the total number of sectors as reported
; by the bios in eax, so store it in our variable
mov [BYTE bp-BIOS_CHS_DRIVE_SIZE],eax
LoadExtraBootCode:
; First we have to load our extra boot code at
; sector 1 into memory at [0000:7e00h]
;mov eax,01h
xor eax,eax
inc eax ; Read logical sector 1, EAX now = 1
mov cx,1 ; Read one sector
mov bx,7e00h ; Read sector to [0000:7e00h]
call ReadSectors
jmp LoadRootDirectory
; Reads ext2 group descriptor into [7000:8000]
; We read it to this arbitrary location so
; it will not cross a 64k boundary
; EAX has group descriptor number to read
Ext2ReadGroupDesc:
shl eax,5 ; Group = (Group * sizeof(GROUP_DESCRIPTOR) /* 32 */)
xor edx,edx
div DWORD [BYTE bp+Ext2GroupDescPerBlock] ; Group = (Group / Ext2GroupDescPerBlock)
add eax,DWORD [BYTE bp+Ext2FirstDataBlock] ; Group = Group + Ext2FirstDataBlock + 1
inc eax ; EAX now has the group descriptor block number
; EDX now has the group descriptor offset in the block
; Adjust the read offset so that the
; group descriptor is read to 7000:8000
mov ebx,78000h
sub ebx,edx
shr ebx,4
mov es,bx
xor bx,bx
; Everything is now setup to call Ext2ReadBlock
; Instead of using the call instruction we will
; just put Ext2ReadBlock right after this routine
; Reads ext2 block into [ES:BX]
; EAX has logical block number to read
Ext2ReadBlock:
mov ecx,DWORD [BYTE bp+Ext2BlockSize]
mul ecx
jmp ReadSectors
; Reads ext2 inode into [6000:8000]
; We read it to this arbitrary location so
; it will not cross a 64k boundary
; EAX has inode number to read
Ext2ReadInode:
dec eax ; Inode = Inode - 1
xor edx,edx
div DWORD [BYTE bp+Ext2InodesPerGroup] ; Inode = (Inode / Ext2InodesPerGroup)
mov ebx,eax ; EBX now has the inode group number
mov eax,edx
xor edx,edx
div DWORD [BYTE bp+Ext2InodesPerBlock] ; Inode = (Inode / Ext2InodesPerBlock)
shl edx,7 ; FIXME: InodeOffset *= 128 (make the array index a byte offset)
; EAX now has the inode offset block number from inode table
; EDX now has the inode offset in the block
; Save the inode values and put the group
; descriptor number in EAX and read it in
push edx
push eax
mov eax,ebx
call Ext2ReadGroupDesc
; Group descriptor has been read, now
; grab the inode table block number from it
push WORD 7000h
pop es
mov di,8008h
pop eax ; Restore inode offset block number from stack
add eax,DWORD [es:di] ; Add the inode table start block
; Adjust the read offset so that the
; inode we want is read to 6000:8000
pop edx ; Restore inode offset in the block from stack
mov ebx,68000h
sub ebx,edx
shr ebx,4
mov es,bx
xor bx,bx
call Ext2ReadBlock
ret
; Reads logical sectors into [ES:BX]
; EAX has logical sector number to read
; CX has number of sectors to read
ReadSectors:
add eax,DWORD [BYTE bp+Ext2VolumeStartSector] ; Add the start of the volume
cmp eax,DWORD [BYTE bp-BIOS_CHS_DRIVE_SIZE] ; Check if they are reading a sector outside CHS range
jae ReadSectorsLBA ; Yes - go to the LBA routine
; If at all possible we want to use LBA routines because
; They are optimized to read more than 1 sector per read
pushad ; Save logical sector number & sector count
CheckInt13hExtensions: ; Now check if this computer supports extended reads
mov ah,0x41 ; AH = 41h
mov bx,0x55aa ; BX = 55AAh
mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh)
int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK
jc ReadSectorsCHS ; CF set on error (extensions not supported)
cmp bx,0xaa55 ; BX = AA55h if installed
jne ReadSectorsCHS
test cl,1 ; CX = API subset support bitmap
jz ReadSectorsCHS ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
popad ; Restore sector count & logical sector number
ReadSectorsLBA:
pushad ; Save logical sector number & sector count
cmp cx,byte 64 ; Since the LBA calls only support 0x7F sectors at a time we will limit ourselves to 64
jbe ReadSectorsSetupDiskAddressPacket ; If we are reading less than 65 sectors then just do the read
mov cx,64 ; Otherwise read only 64 sectors on this loop iteration
ReadSectorsSetupDiskAddressPacket:
mov [BYTE bp-LBA_SECTORS_READ],cx
mov WORD [BYTE bp-LBA_SECTORS_READ+2],0
o32 push byte 0
push eax ; Put 64-bit logical block address on stack
push es ; Put transfer segment on stack
push bx ; Put transfer offset on stack
push cx ; Set transfer count
push byte 0x10 ; Set size of packet to 10h
mov si,sp ; Setup disk address packet on stack
mov dl,[BYTE bp+BootDrive] ; Drive number
mov ah,42h ; Int 13h, AH = 42h - Extended Read
int 13h ; Call BIOS
jc PrintDiskError ; If the read failed then abort
add sp,byte 0x10 ; Remove disk address packet from stack
popad ; Restore sector count & logical sector number
push bx
mov ebx,DWORD [BYTE bp-LBA_SECTORS_READ]
add eax,ebx ; Increment sector to read
shl ebx,5
mov dx,es
add dx,bx ; Setup read buffer for next sector
mov es,dx
pop bx
sub cx,[BYTE bp-LBA_SECTORS_READ]
jnz ReadSectorsLBA ; Read next sector
ret
; Reads logical sectors into [ES:BX]
; EAX has logical sector number to read
; CX has number of sectors to read
ReadSectorsCHS:
popad ; Get logical sector number & sector count off stack
ReadSectorsCHSLoop:
pushad
xor edx,edx
mov ecx,DWORD [BYTE bp-SECTORS_PER_TRACK]
div ecx ; Divide logical by SectorsPerTrack
inc dl ; Sectors numbering starts at 1 not 0
mov cl,dl ; Sector in CL
mov edx,eax
shr edx,16
div WORD [BYTE bp-NUMBER_OF_HEADS] ; Divide logical by number of heads
mov dh,dl ; Head in DH
mov dl,[BYTE bp+BootDrive] ; Drive number in DL
mov ch,al ; Cylinder in CX
ror ah,2 ; Low 8 bits of cylinder in CH, high 2 bits
; in CL shifted to bits 6 & 7
or cl,ah ; Or with sector number
mov ax,0201h
int 13h ; DISK - READ SECTORS INTO MEMORY
; AL = number of sectors to read, CH = track, CL = sector
; DH = head, DL = drive, ES:BX -> buffer to fill
; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read
jc PrintDiskError ; If the read failed then abort
popad
inc eax ; Increment Sector to Read
mov dx,es
add dx,byte 20h ; Increment read buffer for next sector
mov es,dx
loop ReadSectorsCHSLoop ; Read next sector
ret
; Displays a disk error message
; And reboots
PrintDiskError:
mov si,msgDiskError ; Bad boot disk message
call PutChars ; Display it
Reboot:
mov si,msgAnyKey ; Press any key message
call PutChars ; Display it
xor ax,ax
int 16h ; Wait for a keypress
int 19h ; Reboot
PutChars:
lodsb
or al,al
jz short Done
call PutCharsCallBios
jmp short PutChars
PutCharsCallBios:
mov ah,0eh
mov bx,07h
int 10h
retn
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -