当前位置: 首页 > news >正文

深入自制操作系统(一、Bootloader的实现)

我们的操作系统启动流程:

boot.asm -> loader.asm -> kernel.asm -> shell.asm

直接上代码

Boot.asm

; Plain Kernel
; boot.asmorg 0x07C00
StackBase             equ 0x07C00 ; 栈基址
LoaderBase            equ 0x09000 ; Loader基址
OffsetLoader          equ 0x0100  ; Loader偏移
RootDirSectors        equ 14      ; 根目录大小
SectorNoRootDirectory equ 19      ; 根目录起始扇区
SectorNoFAT1          equ 1       ; 第一个FAT表开始扇区
DeltaSectorNo         equ 17 jmp short startnop; 下面的...咱也不知道,咱也不敢问,厂家说啥就是啥BS_OEMName     db 'Plain   '    ; 8个字节BPB_BytsPerSec dw 512           ; 每扇区512个字节BPB_SecPerClus db 1             ; 每簇固定1个扇区BPB_RsvdSecCnt dw 1             ; MBR固定占用1个扇区BPB_NumFATs    db 2             ; FAT12文件系统固定2个FAT表BPB_RootEntCnt dw 224           ; FAT12文件系统中根目录最大224个文件BPB_TotSec16   dw 2880          ; 1.44MB磁盘固定2880个扇区BPB_Media      db 0xF0          ; 介质描述符,固定为0xF0BPB_FATSz16    dw 9             ; 一个FAT表所占的扇区数FAT12文件系统固定为9个扇区BPB_SecPerTrk  dw 18            ; 每磁道扇区数,固定为18BPB_NumHeads   dw 2             ; 磁头数BPB_HiddSec    dd 0             ; 隐藏扇区数,没有BPB_TotSec32   dd 0             ; 直接置0即可BS_DrvNum      db 0             ; int 13h 调用时所读取的驱动器号,由于只有一个软盘所以是0 BS_Reserved1   db 0             ; 未使用,预留BS_BootSig     db 0x29          ; 扩展引导标记,固定为0x29BS_VolID       dd 0             ; 卷序列号,由于只挂载一个软盘所以为0BS_VolLab      db 'Plain - OS ' ; 卷标,11个字节BS_FileSysType db 'FAT12   '    ; 由于是 FAT12 文件系统,所以写入 FAT12 后补齐8个字节start:mov ax, 0x0600mov bx, 0x0700mov cx, 0mov dx, 0x184Fint 0x10mov ah, 0x02xor bh, bhmov dh, 0mov dl, 0int 0x10xor ax, ax ; 相当于 mov ax, 0mov ds, axmov es, axmov ss, axmov sp, StackBasemov dh, 0mov si, msgcall print_stringread_main:mov word [wSectorNo], SectorNoRootDirectorycmp word [wRootDirLoopSize], 0jz no_loaderdec word [wRootDirLoopSize] ; 减一个扇区mov ax, StackBasemov es, axmov bx, OffsetLoadermov ax, [wSectorNo] ; nowmov cl, 1call read_sectormov si, LoaderFileNamemov di, OffsetLoadercldmov dx, 0x10loader_search:cmp dx, 0jz next_sectordec dxmov cx, 11cmp_name:cmp cx, 0jz loader_founddec cxlodsbcmp al, byte [es:di]jz next_strjmp differentnext_str:inc dijmp cmp_namedifferent:and di, 0xFFE0add di, 0x20mov si, LoaderFileNamejmp loader_searchnext_sector:add word [wSectorNo], 1jmp read_mainno_loader:mov si, Message2call print_stringjmp $loader_found:mov ax, RootDirSectorsand di, 0xFFE0add di, 0x1Amov cx, word [es:di]push cxadd cx,axadd cx, DeltaSectorNomov ax, LoaderBasemov es, axmov bx, OffsetLoadermov ax, cxload_file:mov cl, 1call read_sectorpop axcall FAT_entrycmp ax, 0x0FFFjz loader_filepush axmov dx, RootDirSectorsadd ax, dxadd ax, DeltaSectorNoadd bx, [BPB_BytsPerSec]jmp load_fileloader_file:mov dh, 1mov si, Message1call print_stringjmp LoaderBase:OffsetLoader ; Loader!print_string:lodsbor al, al ; 检查是否为0jz .donemov ah, 0x0Emov bx, 0x0007int 0x10jmp print_string.done:retread_sector:push bpmov bp, spsub esp, 2mov byte [bp-2], clpush bxmov bl, [BPB_SecPerTrk]div blinc ahmov cl, ahmov dh, alshr al, 1mov ch, aland dh, 1 ; 磁头pop bxmov dl, [BS_DrvNum].read_start:mov ah, 2mov al, byte [bp-2]int 0x13jc .read_startadd esp, 2pop bpretFAT_entry:push espush bxpush axmov ax, LoaderBasesub ax, 0x0100mov es, ax ; 缓冲区的基址pop axmov byte [bOdd], 0mov bx, 3mul bxmov bx, 2div bxcmp dx, 0jz FAT_nextmov byte [bOdd], 1FAT_next:xor dx, dxmov bx, [BPB_BytsPerSec]div bxpush dxxor bx, bxadd ax, SectorNoFAT1mov cl, 2call read_sectorpop dxadd bx, dxmov ax, [es:bx]cmp byte [bOdd], 1jnz FAT_next2shr ax, 4FAT_next2:and ax, 0x0FFFall_OK:pop bxpop esretmsg              db "Loading Loader...", 0wRootDirLoopSize dw RootDirSectors
wSectorNo        dw 0              ; 当前扇区数
bOdd             db 0              LoaderFileName   db "LOADER  BIN", 0 ; loader的文件名Message1         db "OK!", 0x0A, 0x0D, 0
Message2         db "Loader Not Find", 0times 510-($-$$) db 0
db 0x55, 0xAA

Loader.asm

org 0100h
BaseOfStack equ 0100hjmp LABEL_START%include "load.inc"LABEL_GDT:          Descriptor 0, 0, 0
LABEL_DESC_FLAT_C:  Descriptor 0, 0fffffh, DA_C|DA_32|DA_LIMIT_4K
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW|DA_32|DA_LIMIT_4K
LABEL_DESC_VIDEO:   Descriptor 0B8000h, 0ffffh, DA_DRW|DA_DPL3GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1dd BaseOfLoaderPhyAddr + LABEL_GDTSelectorFlatC  equ LABEL_DESC_FLAT_C - LABEL_GDT
SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT
SelectorVideo  equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3LABEL_START:mov ax, csmov ds, axmov es, axmov ss, axmov sp, BaseOfStackmov si, msgcall print_stringmov word [wSectorNo], SectorNoOfRootDirectoryxor ah, ahxor dl, dlint 13hSearchRootDir:cmp word [wRootDirSizeForLoop], 0jz NoKernelFounddec word [wRootDirSizeForLoop]mov ax, BaseOfKernelFilemov es, axmov bx, OffsetOfKernelFilemov ax, [wSectorNo]mov cl, 1call ReadSectormov si, KernelFileNamemov di, OffsetOfKernelFilecldmov dx, 10hSearchFile:cmp dx, 0jz NextSectordec dxmov cx, 11
CmpFilename:cmp cx, 0jz FileFounddec cxlodsbcmp al, byte [es:di]jz NextCharjmp DifferentFile
NextChar:inc dijmp CmpFilenameDifferentFile:and di, 0FFE0hadd di, 20hmov si, KernelFileNamejmp SearchFileNextSector:add word [wSectorNo], 1jmp SearchRootDirNoKernelFound:mov si, Message2call print_stringjmp $FileFound:mov ax, RootDirSectorsand di, 0FFF0hpush eaxmov eax, [es:di + 01Ch]mov dword [dwKernelSize], eaxpop eaxadd di, 01Ahmov cx, word [es:di]push cxadd cx, axadd cx, DeltaSectorNomov ax, BaseOfKernelFilemov es, axmov bx, OffsetOfKernelFilemov ax, cxLoadFile:mov cl, 1call ReadSectorpop axcall GetFATEntrycmp ax, 0FFFhjz FileLoadedpush axmov dx, RootDirSectorsadd ax, dxadd ax, DeltaSectorNoadd bx, [BPB_BytsPerSec]jmp LoadFileFileLoaded:call KillMotormov si, Message1call print_stringlgdt [GdtPtr]cliin al, 92hor al, 00000010bout 92h, almov eax, cr0or eax, 1mov cr0, eaxjmp dword SelectorFlatC:(BaseOfLoaderPhyAddr+LABEL_PM_START)print_string:lodsbor al, aljz .donemov ah, 0x0Emov bx, 0x0007int 0x10jmp print_string.done:retReadSector:push bpmov bp, spsub esp, 2mov byte [bp-2], clpush bxmov bl, [BPB_SecPerTrk]div blinc ahmov cl, ahmov dh, alshr al, 1mov ch, aland dh, 1pop bxmov dl, [BS_DrvNum]
ReadLoop:mov ah, 2mov al, byte [bp-2]int 13hjc ReadLoopadd esp, 2pop bpretGetFATEntry:push espush bxpush axmov ax, BaseOfKernelFilesub ax, 0100hmov es, axpop axmov byte [bOdd], 0mov bx, 3mul bxmov bx, 2div bxcmp dx, 0jz EvenEntrymov byte [bOdd], 1
EvenEntry:xor dx, dxmov bx, [BPB_BytsPerSec]div bxpush dxmov bx, 0add ax, SectorNoOfFAT1mov cl, 2call ReadSectorpop dxadd bx, dxmov ax, [es:bx]cmp byte [bOdd], 1jnz EvenEntry2shr ax, 4
EvenEntry2:and ax, 0FFFhpop bxpop esretKillMotor:push dxmov dx, 03F2hmov al, 0out dx, alpop dxret[section .s32]
align 32
[bits 32]
LABEL_PM_START:mov ax, SelectorVideomov gs, axmov ax, SelectorFlatRWmov ds, axmov es, axmov fs, axmov ss, axmov esp, TopOfStackcall InitKerneljmp SelectorFlatC:KernelEntryPointPhyAddrMemCpy:push ebpmov ebp, esppush esipush edipush ecxmov edi, [ebp + 8]mov esi, [ebp + 12]mov ecx, [ebp + 16]
CopyLoop:cmp ecx, 0jz CopyDonemov al, [ds:esi]inc esimov byte [es:edi], alinc edidec ecxjmp CopyLoop
CopyDone:mov eax, [ebp + 8]pop ecxpop edipop esimov esp, ebppop ebpretInitKernel:xor esi, esimov cx, word [BaseOfKernelFilePhyAddr + 2Ch]movzx ecx, cxmov esi, [BaseOfKernelFilePhyAddr + 1Ch]add esi, BaseOfKernelFilePhyAddr
ProcessHeader:mov eax, [esi]cmp eax, 0jz NextHeaderpush dword [esi + 010h]mov eax, [esi + 04h]add eax, BaseOfKernelFilePhyAddrpush eaxpush dword [esi + 08h]call MemCpyadd esp, 12NextHeader:add esi, 020hdec ecxjnz ProcessHeaderret[section .data1]
StackSpace: times 1024 db 0
TopOfStack equ $ - StackSpacedwKernelSize        dd 0
wRootDirSizeForLoop dw RootDirSectors
wSectorNo           dw 0
bOdd                db 0
KernelFileName      db "KERNEL  BIN", 0
msg                 db "Loading Kernel...", 0
Message1            db "OK!", 0x0A, 0x0D, 0
Message2            db "Kernel Not Find", 0

loader.asm

BS_OEMName     db 'Plain   '    ; 8个字节BPB_BytsPerSec dw 512           ; 每扇区512个字节BPB_SecPerClus db 1             ; 每簇固定1个扇区BPB_RsvdSecCnt dw 1             ; MBR固定占用1个扇区BPB_NumFATs    db 2             ; FAT12文件系统固定2个FAT表BPB_RootEntCnt dw 224           ; FAT12文件系统中根目录最大224个文件BPB_TotSec16   dw 2880          ; 1.44MB磁盘固定2880个扇区BPB_Media      db 0xF0          ; 介质描述符,固定为0xF0BPB_FATSz16    dw 9             ; 一个FAT表所占的扇区数FAT12文件系统固定为9个扇区BPB_SecPerTrk  dw 18            ; 每磁道扇区数,固定为18BPB_NumHeads   dw 2             ; 磁头数BPB_HiddSec    dd 0             ; 隐藏扇区数,没有BPB_TotSec32   dd 0             ; 直接置0即可BS_DrvNum      db 0             ; int 13h 调用时所读取的驱动器号,由于只有一个软盘所以是0 BS_Reserved1   db 0             ; 未使用,预留BS_BootSig     db 0x29          ; 扩展引导标记,固定为0x29BS_VolID       dd 0             ; 卷序列号,由于只挂载一个软盘所以为0BS_VolLab      db 'Plain - OS ' ; 卷标,11个字节BS_FileSysType db 'FAT12   '    ; 由于是 FAT12 文件系统,所以写入 FAT12 后补齐8个字节FATSz                   equ 9      ; BPB_FATSz16
RootDirSectors          equ 14     ; 根目录大小
SectorNoOfRootDirectory equ 19     ; 根目录起始扇区
SectorNoOfFAT1          equ 1 ; 第一个FAT表的开始扇区
DeltaSectorNo           equ 17 ; 由于第一个簇不用,所以RootDirSectors要-2再加上根目录区首扇区和偏移才能得到真正的地址,故把RootDirSectors-2封装成一个常量(17)DA_32       equ 0x4000
DA_LIMIT_4K equ 0x8000DA_DPL0     equ 0x00
DA_DPL1     equ 0x20
DA_DPL2     equ 0x40
DA_DPL3     equ 0x60DA_DR       equ 0x90
DA_DRW      equ 0x92
DA_DRWA     equ 0x93
DA_C        equ 0x98
DA_CR       equ 0x9A
DA_CCO      equ 0x9C
DA_CCOR     equ 0x9EDA_LDT      equ 0x82
DA_TaskGate equ 0x85
DA_386TSS   equ 0x89
DA_386CGate equ 0x8C
DA_386IGate equ 0x8E
DA_386TGate equ 0x8FSA_RPL0     equ 0
SA_RPL1     equ 1
SA_RPL2     equ 2
SA_RPL3     equ 3SA_TIG      equ 0
SA_TIL      equ 4PG_P        equ 1
PG_RWR      equ 0
PG_RWW      equ 2
PG_USS      equ 0
PG_USU      equ 4%macro Descriptor 3dw %2 & 0xFFFFdw %1 & 0xFFFFdb (%1 >> 16) & 0xFFdw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF)db (%1 >> 24) & 0xFF
%endmacro%macro Gate 4dw (%2 & 0xFFFF)dw %1dw (%3 & 0x1F) | ((%4 << 8) & 0xFF00)dw ((%2 >> 16) & 0xFFFF)
%endmacroBaseOfLoader            equ 09000h ; Loader的基址
OffsetOfLoader          equ 0100h  ; Loader的偏移BaseOfLoaderPhyAddr     equ BaseOfLoader * 10h ; Loader被装载到的物理地址BaseOfKernelFile            equ 08000h ; Kernel的基址
OffsetOfKernelFile          equ 0h  ; Kernel的偏移BaseOfKernelFilePhyAddr     equ BaseOfKernelFile * 10h ; Kernel被装载到的物理地址
KernelEntryPointPhyAddr     equ 0x100000 ; Kernel入口点,一定要与编译命令一致!!!

Makefile

all:make binmake imgmake runbin:nasm boot.asm -o boot.binnasm loader.asm -o loader.bin#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o monitor.o monitor.c#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o common.o common.c#gcc -c -O0 -fno-builtin -m32 -fno-stack-protector -o main.o main.c#nasm -f elf -o kernel.o kernel.asm#nasm -f elf -o io.o io.asm#i686-elf-ld -s -Ttext 0x100000 -o kernel.bin kernel.o io.oimg : boot.bin loader.bin kernel.bin#dd if=boot.bin of=a.img bs=512 count=1#dd if=loader.bin of=a.img bs=512 seek=1 conv=notrunc#python img.pyedimg   imgin:1.img \wbinimg src:boot.bin len:512 from:0 to:0 \copy from:loader.bin to:@: \#copy from:kernel.bin to:@: \imgout:a.imgrun : a.imgqemu-system-i386 -fda a.img

一个make直接编译运行

显示 Kernel Not Found 即成功

至于1.img

这是ztools工具链edimg必须的,具体可以参考30day里的

为什么要有这种恶心的东西不要问我,问edimg作者

文件内容如图

依赖:

mtools (用于编译)

edimg (30day的写盘工具)

qemu  (虚拟机)

i686-elf-mtools (后面用来链接)

http://www.xdnf.cn/news/242389.html

相关文章:

  • 微软与Meta大幅增加人工智能基础设施投入
  • AI大模型基础设施:NVIDIA的用于AI大语言模型训练和推理的几款主流显卡
  • Arduino程序函数从入门到精通
  • 中国发布Web3计划:区块链列为核心基础技术,不排除发展加密资产应用!
  • 2025五一杯B题超详细解题思路
  • Qwen3 发布:优化编码与代理能力,强化 MCP 支持引领 AI 新潮流
  • 在阿里云 Ubuntu 24.04 上部署 RabbitMQ:一篇实战指南
  • 24.Linux中RTC的驱动实验_csdn
  • MATLAB R2024a安装教程
  • Spring MVC 与 FreeMarker 整合
  • Sigmoid函数导数推导详解
  • CSS学习笔记14——移动端相关知识(rem,媒体查询,less)
  • 奇偶ASCII值判断
  • 对计网考研中的信道、传输时延、传播时延的理解
  • python2反编译部分
  • POI从入门到上手(三)-轻松完成EasyExcel使用,完成Excel导入导出.
  • 第 11 届蓝桥杯 C++ 青少组中 / 高级组省赛 2020 年真题,选择题详细解释
  • WPF使用SQLSugar和Nlog
  • 精品推荐-湖仓一体电商数据分析平台实践教程合集(视频教程+设计文档+完整项目代码)
  • OpenHarmony全局资源调度管控子系统之内存管理部件
  • 【STM32单片机】#12 SPI通信(软件读写)
  • IRF2.0IRF3.1
  • 小白dockerfile
  • Linux安全清理删除目录bash脚本
  • 使用scipy求解优化问题
  • Three.js在vue中的使用(一)-基础
  • 报错:函数或变量 ‘calcmie‘ 无法识别。
  • 【网络服务器】——回声服务器(echo)
  • 【C++】类和对象【中下】
  • 【中间件】bthread_基础_TaskControl