ReactOS 源码分析 (一) by:ProgrammeBoy
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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |