ReactOS 源码分析
前言
ReactOS是一个开源的免费的操作系统,它致力于兼容现在最流行的操作系统windows,打破微软垄断的局面,这里我们为那些默默无闻的开发者致敬,他们开发reactos没有工资,没有补贴,没有…只有默默的写代码…这是一种精神..
代码分析
那我们就在最初引导阶段开始分析.首先我们假设我们的机器是i386机型. 引导磁盘是fat32格式.我的Reactos代码在D:/ReactOS/ReactOS_src/下,代码版本0.39
1. 系统开始启动
首先机器加电自检,然后检查启动盘,是从光盘还是硬盘启动呢?可能大家都知道,这是在BIOS里面设置的,这里我们是研究已经安装好的系统启动过程,就磁盘启动啦,首先找到启动磁盘,BIOS会检查磁盘的0面0磁道,1扇区,如果发现其为55aa结尾而且小于512字节就认为他就是一个合法的引导扇扇区(BootSector),然后把这个引导代码加载到0000:7c000处,然后跳转到这个地方执行,现在就把所有的控制权交给引导代码了,BIOS里的启动代码是固定在ROM里的,所以系统启动的代码就是那段引导程序代码,前面我们也假设了我们是fat32格式的磁盘.所以我们就从fat32.asm开始吧.
2 f at32.asm
代码位置: D:/ReactOS/ReactOS_src/boot/freeldr/bootsect/fat32.asm
代码如下:
;看了吧,这里就是把他加载到了0000:7c000
org 7c00h
segment .text
bits 16 ;16位程序
start:
jmp short main
nop
/*这里是什么?用winhex打开磁盘,选在结构fat32的样式打开就可以看待这些数据了,
数据结构如下
typedef struct _FAT_BOOTSECTOR
{
UCHAR JumpBoot[3]; // Jump instruction to boot code
CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes
USHORT BytesPerSector; // Bytes per sector
UCHAR SectorsPerCluster; // Number of sectors in a cluster
USHORT ReservedSectors; // Reserved sectors,usually 1 (the bootsector)
UCHAR NumberOfFats; // Number of FAT tables
USHORT RootDirEntries; // Number of root directory entries (fat12/16)
USHORT TotalSectors; // Number of total sectors on the drive,16-bit
UCHAR MediaDescriptor; // Media descriptor byte
USHORT SectorsPerFat; // Sectors per FAT table (fat12/16)
USHORT SectorsPerTrack; // Number of sectors in a track
USHORT NumberOfHeads; // Number of heads on the disk
ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table)
ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume
UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80)
UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
ULONG VolumeSerialNumber; // Volume serial number
CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory
CHAR FileSystemType[8]; // One of the strings "FAT12 ","FAT16 ",or "FAT "
UCHAR BootCodeAndData[448]; // The remainder of the boot sector
USHORT BootSectorMagic; // 0xAA55
} FAT_BOOTSECTOR,*PFAT_BOOTSECTOR;*/
OEMName db 'FrLdr1.0'
BytesPerSector dw 512
SectsPerCluster db 0
ReservedSectors dw 32
….略
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,7c00h ; Setup a stack
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
jne CheckSectorsPerFat
mov [BYTE bp+BootDrive],dl ; Save the boot drive
;下面检查参数是否正确
CheckSectorsPerFat:
cmp WORD [BYTE bp+SectorsPerFat],byte 0x00 ; Check the old 16-bit value of SectorsPerFat
jnz CheckFailed ; If it is non-zero then exit with an error
CheckTotalSectors: ; Check the old 16-bit value of TotalSectors & MaxRootEntries
cmp DWORD [BYTE bp+MaxRootEntries],byte 0x00; by comparing the DWORD at offset MaxRootEntries to zero
jnz CheckFailed ; If it is non-zero then exit with an error
CheckFileSystemVersion:
cmp WORD [BYTE bp+FSVersion],byte 0x00 ; Check the file system version word
jna GetDriveParameters ; It is zero,so continue
CheckFailed:
jmp PrintFileSystemError ; If it is not zero then exit with an error
GetDriveParameters:
….省略
CalcDriveSize:
…省略
;计算出来放在BiosCHSDriveSize里面
LoadExtraBootCode:
; First we have to load our extra boot code at
; sector 14 into memory at [0000:7e00h]
…略
call ReadSectors
jmp StartSearch
;==========================================================
; Reads logical sectors into [ES:BX]
; EAX has logical sector number to read
; CX has number of sectors to read
ReadSectors:
…略
;这里进行的工作是检查是否为LBA模式如果是进行LBA模式读取
; End of bootsector
;
; Now starts the extra boot code that we will store
; at sector 14 on a FAT32 volume
;
; To remain multi-boot compatible with other operating
; systems we must not overwrite anything other than
; the bootsector which means we will have to use
; a different sector like 14 to store our extra boot code
;========================================================
;下面的代码是进行查找freeldr.sys,然后进行加载,加载到0000:8000处
StartSearch:
; Now we must get the first cluster of the root directory
mov eax,DWORD [BYTE bp+RootDirStartCluster]
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
jb ContinueSearch ; If not continue,if so then we didn't find freeldr.sys
jmp PrintFileNotFound
ContinueSearch:
mov bx,2000h
mov es,bx ; Read cluster to [2000:0000h]
call ReadCluster ; Read the cluster
; Now we have to find our way through the root directory to
; The OSLOADER.SYS file
xor bx,bx
mov bl,[BYTE bp+SectsPerCluster]
shl bx,4 ; BX = BX * 512 / 32
mov ax,2000h ; We loaded at 2000:0000
mov es,ax
xor di,di
mov si,filename
mov cx,11
rep cmpsb ; Compare filenames
jz FoundFile ; If same we found it
dec bx
jnz FindFile
jmp PrintFileNotFound
FindFile:
mov ax,es ; We didn't find it in the prevIoUs dir entry
add ax,2 ; So lets move to the next one
mov es,ax ; And search again
xor di,filename
mov cx,11
rep cmpsb ; Compare filenames
jz FoundFile ; If same we found it
dec bx ; Keep searching till we run out of dir entries
jnz FindFile ; Last entry?
; Get the next root dir cluster and try again until we run out of clusters
mov eax,DWORD [BYTE bp+RootDirStartCluster]
call GetFatEntry
mov [BYTE bp+RootDirStartCluster],eax
jmp StartSearch
FoundFile:
; Display "Loading FreeLoader..." message
mov si,msgLoading ; Loading message
call PutChars ; Display it
xor di,di ; ES:DI has dir entry
xor dx,dx
mov ax,WORD [es:di+14h] ; Get start cluster high word
shl eax,16
mov ax,WORD [es:di+1ah] ; Get start cluster low word
CheckStartCluster:
cmp eax,2 ; Check and see if the start cluster starts at cluster 2 or above
jnb CheckEndCluster ; If so then continue
jmp PrintFileSystemError ; If not exit with error
CheckEndCluster:
cmp eax,0ffffff8h ; Check and see if the start cluster is and end of cluster chain indicator
jb InitializeLoadSegment ; If not then continue
jmp PrintFileSystemError ; If so exit with error
InitializeLoadSegment:
mov bx,800h
mov es,bx
LoadFile:
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
jae LoadFileDone ; If so continue,if not then read the next one
push eax
xor bx,bx ; Load ROSLDR starting at 0000:8000h
push es
call ReadCluster
pop es
xor bx,5 ; BX = BX * 512 / 16
mov ax,es ; Increment the load address by
add ax,bx ; The size of a cluster
mov es,ax
pop eax
push es
call GetFatEntry ; Get the next entry
pop es
jmp LoadFile ; Load the next cluster (if any)
LoadFileDone:
mov dl,[BYTE bp+BootDrive] ; Load boot drive into DL
mov dh,[BootPartition] ; Load boot partition into DH
;看这里是把freeldr加载到0000:8000位置然后跳转到此处
xor ax,ax
push ax ; We loaded at 0000:8000
push WORD 8000h ; We will do a far return to 0000:8000h
retf ; Transfer control to ROSLDR
;下面是fat格式磁盘的解析函数,可以玩下
; Returns the FAT entry for a given cluster number
; On entry EAX has cluster number
; On return EAX has FAT entry for that cluster
GetFatEntry:
shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes)
mov ecx,eax ; Save this for later in ECX
xor edx,edx
movzx ebx,WORD [BYTE bp+BytesPerSector]
push ebx
div ebx ; FAT Sector Number = EAX / BytesPerSector
movzx ebx,WORD [BYTE bp+ReservedSectors]
add eax,ebx ; FAT Sector Number += ReservedSectors
mov ebx,DWORD [BYTE bp+HiddenSectors]
add eax,ebx ; FAT Sector Number += HiddenSectors
pop ebx
dec ebx
and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector
; EAX holds logical FAT sector number
; ECX holds FAT entry offset
; Now we have to check the extended flags
; to see which FAT is the active one
; and use it,or if they are mirrored then
; no worries
movzx ebx,WORD [BYTE bp+ExtendedFlags] ; Get extended flags and put into ebx
and bx,0x0f ; Mask off upper 8 bits,now we have active fat in bl
jz LoadFatSector ; If fat is mirrored then skip fat calcs
cmp bl,[BYTE bp+NumberOfFats] ; Compare bl to number of fats
jb GetActiveFatOffset
jmp PrintFileSystemError ; If bl is bigger than numfats exit with error
GetActiveFatOffset:
push eax ; Save logical FAT sector number
mov eax,[BYTE bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax
mul ebx ; Multiplied by the active FAT index we have in ebx
pop edx ; Get logical FAT sector number
add eax,edx ; Add the current FAT sector offset
LoadFatSector:
push ecx
; EAX holds logical FAT sector number
; Check if we have already loaded it
cmp eax,DWORD [FatSectorInCache]
je LoadFatSectorAlreadyLoaded
mov DWORD [FatSectorInCache],eax
mov bx,7000h
mov es,bx
xor bx,bx ; We will load it to [7000:0000h]
mov cx,1
call ReadSectors
LoadFatSectorAlreadyLoaded:
mov bx,bx
pop ecx
mov eax,DWORD [es:ecx] ; Get FAT entry
and eax,0fffffffh ; Mask off reserved bits
ret
FatSectorInCache: ; This variable tells us which sector we currently have in memory
dd 0ffffffffh ; There is no need to re-read the same sector if we don't have to
; Reads cluster number in EAX into [ES:0000]
ReadCluster:
; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
….略
; Displays a file not found error message
; And reboots
PrintFileNotFound:
mov si,msgFreeLdr ; FreeLdr not found message
call PutChars ; Display it
mov si,msgAnyKey ; Press any key message
call PutChars ; Display it
jmp Reboot
msgFreeLdr db 'freeldr.sys not found',0dh,0ah,0
filename db 'FREELDR SYS'
msgLoading db 'Loading FreeLoader...',0
times 1022-($-$$) db 0 ; Pad to 1022 bytes
dw 0aa55h ; BootSector signature
好,看完代码也有单晕晕乎乎了,我们来总结下fat32.asm。首先加载到0000:7c00处,接下来就是那个结构体,而上面跳转到main函数那了.开始当然是对一些寄存器的初始化,接着就是检查BootSector的参数是否正确,接着计算整个磁盘的存储量,为什么要计算这个呢?为了检查磁盘是否支持LBA模式。再下面的工作就是查找freeldr.sys.并将其加载到内存0000:8000处,
其中又有fat文件格式的操作….
需要的知识点:
1,汇编是必要的.
2,bootsector.
3,fat32文件系统解析
4,怎么检查是否支持LBA模式
5,int 10,int 13 貌似都会吧..
6,得会使用nasm编译呀!!
对了freeldr目录下有个note.txt里面有内存分配表如下,大家好好看看:
Memory layout:
0000:0000 - 0000:0FFF: Interrupt vector table & BIOS data
0000:1000 - 0000:6FFF: Real mode stack area
0000:7000 - 0000:7FFF: Cmdline (multiboot)
0000:8000 - xxxx:xxxx: FreeLoader program & data area
xxxx:xxxx - 7000:7FFF: Random memory allocation heap
7000:8000 - 7000:FFFF: Protected mode stack area
8000:0000 - 8000:FFFF: File system read buffer
9000:0000 - 9000:FFFF: Disk read buffer for BIOS Int 13h
A000:0000 - FFFF:FFFF: reserved