linux fat get entry,操作系统--主引导程序控制权的转移

本文详细介绍了嵌入式系统中BootLoader的内存布局和作用,以及在ARM7TDMI核心系统中如何从BootLoader跳转到Loader。通过FAT表加载文件内容,并展示了汇编代码实现过程,包括主引导程序、Loader的地址、功能及跳转逻辑。同时,讨论了代码优化,如减少栈空间使用,以适应内存限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.主引导程序控制权的转移

首先需要了解的是BootLoader内存布局,在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。

a089cb34a348ab1aa62b6ae477c3db61.png

0x7c00主引导程序的起始地址,之前为栈空间,主要是函数调用。,最终主引导程序是从boot程序跳转到0x9000loader,中间部分为Fat表,占用4个字节

1.通过FAT表加载文件内容--流程图

4fba81587cd3f0e8582712288b050855.png

实验步骤

1.在虚拟软盘中创建体积较大的文本文件(Loader)

2.将Loader的内容加载到BaseOfLoader地址处

3.打印Loader中的文本(判断加载是否完全)

org 0x7c00

jmp short start

nop

define:

BaseOfStack equ 0x7c00

BaseOfLoader equ 0x9000

RootEntryOffset equ 19

RootEntryLength equ 14

EntryItemLength equ 32

FatEntryOffset equ 1

FatEntryLength equ 9

header:

BS_OEMName db "D.T.Soft"

BPB_BytsPerSec dw 512

BPB_SecPerClus db 1

BPB_RsvdSecCnt dw 1

BPB_NumFATs db 2

BPB_RootEntCnt dw 224

BPB_TotSec16 dw 2880

BPB_Media db 0xF0

BPB_FATSz16 dw 9

BPB_SecPerTrk dw 18

BPB_NumHeads dw 2

BPB_HiddSec dd 0

BPB_TotSec32 dd 0

BS_DrvNum db 0

BS_Reserved1 db 0

BS_BootSig db 0x29

BS_VolID dd 0

BS_VolLab db "D.T.OS-0.01"

BS_FileSysType db "FAT12 "

start:

mov ax, cs

mov ss, ax

mov ds, ax

mov es, ax

mov sp, BaseOfStack

mov ax, RootEntryOffset

mov cx, RootEntryLength

mov bx, Buf

call ReadSector

mov si, Target

mov cx, TarLen

mov dx, 0

call FindEntry

cmp dx, 0

jz output

mov si, bx

mov di, EntryItem

mov cx, EntryItemLength

call MemCpy

mov ax, FatEntryLength

mov cx, [BPB_BytsPerSec]

mul cx

mov bx, BaseOfLoader

sub bx, ax

mov ax, FatEntryOffset

mov cx, FatEntryLength

call ReadSector

mov cx, [EntryItem + 0x1A]

mov si, BaseOfLoader

loading:

mov ax, dx

add ax, 31

mov cx, 1

push dx

push bx

mov bx, si

call ReadSector

pop bx

pop cx

call FatVec

cmp dx, 0xFF7

jnb BaseOfLoader

add si, 512

jmp loading

output:

mov bp, MsgStr

mov cx, MsgLen

call Print

last:

hlt

jmp last

; cx --> index

; bx --> fat table address

;

; return:

; dx --> fat[index]

FatVec:

mov ax, cx

mov cl, 2

div cl

push ax

mov ah, 0

mov cx, 3

mul cx

mov cx, ax

pop ax

cmp ah, 0

jz even

jmp odd

even: ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];

mov dx, cx

add dx, 1

add dx, bx

mov bp, dx

mov dl, byte [bp]

and dl, 0x0F

shl dx, 8

add cx, bx

mov bp, cx

or dl, byte [bp]

jmp return

odd: ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );

mov dx, cx

add dx, 2

add dx, bx

mov bp, dx

mov dl, byte [bp]

mov dh, 0

shl dx, 4

add cx, 1

add cx, bx

mov bp, cx

mov cl, byte [bp]

shr cl, 4

and cl, 0x0F

mov ch, 0

or dx, cx

return:

ret

; ds:si --> source

; es:di --> destination

; cx --> length

MemCpy:

push si

push di

push cx

push ax

cmp si, di

ja btoe

add si, cx

add di, cx

dec si

dec di

jmp etob

btoe:

cmp cx, 0

jz done

mov al, [si]

mov byte [di], al

inc si

inc di

dec cx

jmp btoe

etob:

cmp cx, 0

jz done

mov al, [si]

mov byte [di], al

dec si

dec di

dec cx

jmp etob

done:

pop ax

pop cx

pop di

pop si

ret

; es:bx --> root entry offset address

; ds:si --> target string

; cx --> target length

;

; return:

; (dx !=0 ) ? exist : noexist

; exist --> bx is the target entry

FindEntry:

push di

push bp

push cx

mov dx, [BPB_RootEntCnt]

mov bp, sp

find:

cmp dx, 0

jz noexist

mov di, bx

mov cx, [bp]

call MemCmp

cmp cx, 0

jz exist

add bx, 32

dec dx

jmp find

exist:

noexist:

pop cx

pop bp

pop di

ret

; ds:si --> source

; es:di --> destination

; cx --> length

;

; return:

; (cx == 0) ? equal : noequal

MemCmp:

push si

push di

push ax

compare:

cmp cx, 0

jz equal

mov al, [si]

cmp al, byte [di]

jz goon

jmp noequal

goon:

inc si

inc di

dec cx

jmp compare

equal:

noequal:

pop ax

pop di

pop si

ret

; es:bp --> string address

; cx --> string length

Print:

mov dx, 0

mov ax, 0x1301

mov bx, 0x0007

int 0x10

ret

; no parameter

ResetFloppy:

push ax

push dx

mov ah, 0x00

mov dl, [BS_DrvNum]

int 0x13

pop dx

pop ax

ret

; ax --> logic sector number

; cx --> number of sector

; es:bx --> target address

ReadSector:

push bx

push cx

push dx

push ax

call ResetFloppy

push bx

push cx

mov bl, [BPB_SecPerTrk]

div bl

mov cl, ah

add cl, 1

mov ch, al

shr ch, 1

mov dh, al

and dh, 1

mov dl, [BS_DrvNum]

pop ax

pop bx

mov ah, 0x02

read:

int 0x13

jc read

pop ax

pop dx

pop cx

pop bx

ret

MsgStr db "No LOADER ..."

MsgLen equ ($-MsgStr)

Target db "LOADER "

TarLen equ ($-Target)

EntryItem times EntryItemLength db 0x00

Buf:

times 510-($-$$) db 0x00

db 0x55, 0xaa

对此进行make的结果

013dca5a1d9024efac08ec363d9bffb4.png

从该结果可以看出,TIME的值为负数了,说明主引导程序的大小大于了512,我们需要将其减小,将之前不重要的入栈与出栈的操作进行删除,以免占用空间,那么我们之前为何要这样做呢?是为了遵守汇编代码的约定,有操作相关寄存器的值就要进行入栈出栈操作。那么我们这块内存已经不够,因此没必要进行这个操作了。我们将下面的入栈出栈操作进行删除,但是要在 FindEntry 这个函数保留 cx 寄存器的入栈出栈的操作,原因是下面不停在改变 cx 寄存器的值。我们在 find 操作中,call MemCmp 操作前后有必要再加上 si 寄存器的入栈出栈操作

将其改正后的make以及在bochs上实现的结果为会打印loader中的字符串内容

f6ae5bb317a49cc6bdc0370b7c56418d.png

B.第一个loader程序

1.起始地址0x9000

2.通过int0x10在屏幕上打印字符串

b038d9a6e79357f7753e46abc69ff83b.png

a.零标志位--判断运算的结果是否为0,当运算结果为0时,ZF位的值为1

b.同时jxx代表了一个指令族,功能是根据标志位进行调整

jo当OF为1则跳转,jc当CF为1则跳转,jns当SF不为1则跳转,jz当ZF为1则跳转,je比较结果为相等则跳转

loader.asm代码实现

org 0x9000

begin:

mov si, msg

print:

mov al, [si]

add si, 1

cmp al, 0x00

je end

mov ah, 0x0E

mov bx, 0x0F

int 0x10

jmp print

end:

hlt

jmp end

msg:

db 0x0a, 0x0a

db "Hello, D.T.OS!"

db 0x0a, 0x0a

db 0x00

将loader.asm进行反编译得出的结果

2275aaea7be2210476f7cc6351ccaded.png

可以看到在这里的jz对应的是loader.asm中的je命令

接下来将loader拷贝到软盘中去,然后从Boot跳转到loader进行执行,我们将虚拟软盘先在linux中进行挂载,然后进行拷贝,最后进行运行

cdf22ef2f9faceb74ca92834630dbe82.png

e4af78b75c8fb9ba32905c90e8213ef9.png

从打印的结果可以看出,控制权从boot已经转移到loader程序了

将其打印结果进行修改看在bochs上的实现结果是否也修改了

d8f9ea4a16637c5ee8219c557af7fd8c.png

38b0ab1ed20b0a00fc189f17e7ba15e6.png

在这里我们需要将makefile文件进行修改保证后期的运行简便

.PHONY : all clean rebuild

BOOT_SRC := boot.asm

BOOT_OUT := boot

LOADER_SRC := loader.asm

LOADER_OUT := loader

IMG := data.img

IMG_PATH := /mnt/hgfs

RM := rm -fr

all : $(IMG) $(BOOT_OUT) $(LOADER_OUT)

@echo "Build Success ==> D.T.OS!"

$(IMG) :

bximage $@ -q -fd -size=1.44

$(BOOT_OUT) : $(BOOT_SRC)

nasm $^ -o $@

dd if=$@ of=$(IMG) bs=512 count=1 conv=notrunc

$(LOADER_OUT) : $(LOADER_SRC)

nasm $^ -o $@

sudo mount -o loop $(IMG) $(IMG_PATH)

sudo cp $@ $(IMG_PATH)/$@

sudo umount $(IMG_PATH)

clean :

$(RM) $(IMG) $(BOOT_OUT) $(LOADER_OUT)

rebuild :

@$(MAKE) clean

@$(MAKE) all

最后将data.img在window下实现

7c0d36ce18c3768a976c77b518057a52.png

小结

1.Boot需要进行重构保证在512字节内完成功能

2.在汇编程序中尽量确保函数调用前后通用寄存器的状态不变

3.Boot成功加载Loader后将控制权转移

4.Loader程序没有代码体积上的限制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值