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

从零开始制作 MyOS(四)

从零开始制作 MyOS(四)—— 跳转到 C 语言编写的小型内核

目标

在引导加载器准备好后,用 C 语言编写一个小型内核并实现从引导加载器跳转到内核执行。

代码

引导程序文件

org 0x7C00
bits 16start:; 初始化段寄存器xor ax, axmov ds, axmov es, axmov ss, axmov sp, 0x7C00; 显示启动信息mov si, msg_loadingcall print_string; 加载内核到 0x10000mov ax, 0x1000mov es, axxor bx, bxmov ah, 0x02    ; 读扇区mov al, 4       ; 4个扇区mov ch, 0       ; 柱面0mov cl, 2       ; 扇区2mov dh, 0       ; 磁头0mov dl, 0x80    ; 驱动器int 0x13jc disk_error; 切换到保护模式clilgdt [gdt_descriptor]; 启用A20in al, 0x92or al, 2out 0x92, almov eax, cr0or eax, 1mov cr0, eaxjmp CODE_SEG:init_pmdisk_error:mov si, msg_errorcall print_stringjmp $print_string:lodsbtest al, aljz .donemov ah, 0x0Eint 0x10jmp print_string
.done:retbits 32
init_pm:mov ax, DATA_SEGmov ds, axmov es, axmov ss, axmov esp, 0x90000; 跳转到内核jmp 0x10000; 数据区
msg_loading db "Booting...", 0xD, 0xA, 0
msg_error db "Disk error!", 0; GDT
gdt_start:dq 0
gdt_code:dw 0xFFFFdw 0db 0db 10011010bdb 11001111bdb 0
gdt_data:dw 0xFFFFdw 0db 0db 10010010bdb 11001111bdb 0
gdt_end:gdt_descriptor:dw gdt_end - gdt_start - 1dd gdt_startCODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_starttimes 510-($-$$) db 0
dw 0xAA55

内核入口文件

section .text
global _start_start:mov esp, 0x90000  ; 设置栈指针extern kernel_maincall kernel_main   ; 调用C内核hlt

小型内核文件

void kernel_main(void) {char *vga = (char*)0xB8000;// 清屏for (int i = 0; i < 80 * 25 * 2; i += 2) {vga[i] = ' ';vga[i + 1] = 0x07;}// 显示字符串char *msg = "Hello from C Kernel!";for (int i = 0; msg[i]; i++) {vga[i * 2] = msg[i];vga[i * 2 + 1] = 0x07;}while(1) asm("hlt");
}

链接器

ENTRY(_start)SECTIONS
{. = 0x10000;.text : { *(.text) }.data : { *(.data) }.bss : { *(.bss) }
}

Makefile

CC = gcc
LD = ld
ASM = nasmCFLAGS = -m32 -ffreestanding -nostdlib -c
ASFLAGS = -f elf32
LDFLAGS = -m elf_i386 -T linker.ld -nostdliball: os.imgos.img: boot.bin kernel.bindd if=/dev/zero of=os.img bs=512 count=2880dd if=boot.bin of=os.img conv=notruncdd if=kernel.bin of=os.img bs=512 seek=1 conv=notruncboot.bin: boot.asm$(ASM) -f bin boot.asm -o boot.binkernel.bin: kernel.elfobjcopy -O binary kernel.elf kernel.binkernel.elf: entry.o kernel.o$(LD) $(LDFLAGS) -o kernel.elf entry.o kernel.okernel.o: kernel.c$(CC) $(CFLAGS) kernel.c -o kernel.oentry.o: entry.asm$(ASM) $(ASFLAGS) entry.asm -o entry.oclean:rm -f *.o *.bin *.elf os.imgrun: os.imgqemu-system-x86_64 -drive format=raw,file=os.img.PHONY: all clean run

编译运行

# ubuntu 中,VGA 显示
make clean && make run

运行结果

当终端打印出来“Hello from C Kernel!”,就表示运行成功了

跳转 C 内核成功

问题

本节遇到最大的问题是内核跳转不过来,目前只找到以下一些可能:

磁盘问题

  1. 段寄存器设置顺序错误

    • 先设置ES再操作磁盘
  2. 缺少错误重试机制​
    +

  3. 扇区数不足

A20地址线启用问题

  1. and al, 0xFE会错误清除bit 0(可能影响系统重启)

  2. 缺少状态检查​:未验证A20是否真正启用成功

保护模式跳转问题

  1. 无效跳转指令,jmp 0x10000未使用段选择子,在保护模式下会崩溃
  2. 缺少段寄存器初始化​:未正确设置DS/ES/SS等数据段寄存器

内核入口对齐问题

  1. 未声明全局符号​:_start未在entry.asm中声明为global
  2. ​栈未对齐​:x86要求栈指针按16字节对齐

编译链接问题

  1. 缺少内核地址指定​:链接脚本未强制指定内核加载地址为0x10000
  2. 未处理BSS段​:未清零未初始化数据段
http://www.jsqmd.com/news/26301/

相关文章:

  • 2025年10月压力监测厂家对比榜:五强评测与选型参考
  • 2025年质量好的洗菜盆厨房水槽优质厂家推荐榜单
  • 基于VC++和ObjectARX开发的AutoCAD曲线交点打断功能实现代码
  • 12个单词
  • 不是,斜二倍增是啥啊
  • 2025年评价高的滚珠丝杆升降机用户好评厂家排行
  • 2025 年消防培训学校最新推荐榜,技术实力与市场口碑深度解析
  • 2025年知名的GXN-CMS型碳分子筛实力源头
  • 2025年10月中国离婚财产分割律师榜单:官方资质与用户口碑综合排名
  • 2025 年上海留学服务机构最新推荐榜,聚焦机构综合服务实力与留学申请口碑深度解析
  • 用Fiddler修改网页title的步骤
  • K3s x RustFS,边缘场景下的云原生存储解决之道
  • 2025年10月进度管理工具推荐:信创适配进度系统排名榜
  • 2025-10-29 ZR-J 模拟赛 赛后总结【ZR】
  • 2025年热门的上海行星式搅拌机设备行业内口碑厂家排行榜
  • 阿里云 OSS postObject V4 使用
  • 2025年10月武汉离婚律师推荐榜:五强对比评测与选择指南
  • 用筛选过滤器修改京东界面名字
  • 2025年靠谱的精冲工艺座椅齿板厂家最新TOP排行榜
  • 修改京东商城官网title为百度商城
  • springboot+vue图书借阅管理专业的系统设计(源码+文档+调试+基础修改+答疑)
  • 2025 年散热器厂家最新推荐榜,聚焦企业技术实力与市场口碑深度解析及多领域适配能力储能液冷/锂电/铜管串铝翅片散热器公司推荐
  • 图纸安全外发策略,保障企业知识产权与市场竞争力
  • 101超酷!用Python写回文音乐,3步搞定你的MIDI创作处女作
  • 体素化
  • 2025年口碑好的四方立绒厂家推荐及选择指南
  • 吃数篇 酉鸡
  • 2025年十大哈尔滨工伤纠纷律师事务所哪家强
  • Web信息的物联网设备指纹如何生成
  • 跨网文件传输是什么?主要有哪几种应用场景?