手写操作系统 - 汇编实现进入保护模式

发布时间:2023年12月29日

前言

  1. 在了解段页门得基础上,理解如何从实时模式进入保护模式
  2. 如何引入C语言得开发与调试
    • 生成内核:汇编与C语言如何生成内核
    • 调试C语言
    • 汇编、C语言如何互调

手写64位操作系统内核规划图:

boot程序起始0扇区,共占1个扇区
setup程序起始1扇区,共占一个扇区2个扇区
x86内核起始 3扇区,共占一个扇区大于30个扇区

在这里插入图片描述

1、从实时模式进入保护模式

  1. 关中断

    cli:是一个汇编指令,用于清除(禁用)中断标志位(IF位)在eflags寄存器中。当IF位被清除时,处理器将不响应可屏蔽的硬件中断,这常用于临界区代码,以避免在执行关键任务时被中断。
    sti:用于设置(启用)中断标志位在eflags寄存器中。执行sti后,处理器将开始响应可屏蔽的硬件中断。这通常用于完成关键任务后重新启用中断。
    eflags.IF:一个寄存器,其中的IF(Interrupt Flag)是eflags中的一个位,用于控制处理器是否响应可屏蔽的硬件中断。cli和sti指令分别用于清除和设置这个标志位。
    
  2. 开A20总线

    考虑为什么要开A20?
    ; 开A20
    in    al,  92h
    or    al,  00000010b
    out   92h, al
    
  3. 设置段寄存器、加载gdt表

    内核态
    	代码段、数据段
    	2
    -----------------------------
    x64长模式
    	4
    
    tss
    	用户态切内核态
    
    8个
    ------------------------------
    调用门
    
  4. cr0寄存器,cr0.pe = 1

    cr0 :   pe位(进入保护模式)、pg(开启分页)
    cr1:
    cr2:	内存异常			4G     0x10000000    页机制
    cr3:	页表的基址
    
  5. 来一个练习:32位,0-4g,代码段
    在这里插入图片描述

    Base;0
    Limit::0xfffff
    G:1        ;为0时Segment Limit单位为字节 2^20*1Byte = 1M  为1时单位4K 2^20*4K =4G
    D/B:1
    AVL:0
    P:1
    DPL:0		
    S:1		;代码段
    TYPE:1000   ;Execule Only
    -------------------------------------
    高32位:0000 0000 1100 1111 1001 1000 0000 0000  ---> 0x00cf9800
    低32位:0000 0000 0000 0000 1111 1111 1111 1111  ---> 0x0000ffff
    

2、如何引入C语言得开发与调试

  1. 生成内核:汇编与C语言如何生成内核

    ${BUILD}/kernel.bin: ${BUILD}/boot/head.o ${BUILD}/init/main.o
    ld -m elf_i386 $^ -o $@ -Ttext 0x1200
    
    非常重要:-Ttext 0x1200,指定代码入口,调试时候需要用
    调试的时候,要选kenel.bin,因为这里面有调试符号,如果说你编译.o文件的时候,不带-g,那内核就是没办法调试
    
    ${BUILD}/system.bin: ${BUILD}/kernel.bin
    objcopy -O binary ${BUILD}/kernel.bin ${BUILD}/system.bin
    nm ${BUILD}/kernel.bin | sort > ${BUILD}/system.map(不是必须的)
    
  2. 调试C语言

    1、内核依赖的所有文件编译的时候应该要带-g,生成调试符号
    2、指定入口-Ttext 0x1200
    3、要用qemu调试模式运行
    		-s -S   socket  lo
    		127.0.0.1:1234
    
    		gdb kernel.bin
    		target remote:1234
    
  3. 汇编、C语言如何互调

    • 汇编如何调用C语言中的函数

      以汇编中掉调用C语言中c_test()函数,核心全局函数
      汇编代码中增加:
      	extern c_test
      	gq_ctest:
      		 call c_test
      
      C语言中:
      	void c_test(void) {
      	    int a = 0;
      	    char* video = (char*)0xb8000;
      	    *video = 'Z';
      	}
      
    • 汇编如何访问C语言中的全局变量

      
      
    • C语言如何调用汇编语言的函数

      C语言中调用gq_ctest()函数,核心是要将汇编中的void gq_ctest(void) 申明成全局函数
      

      在这里插入图片描述

    • C语言如何访问汇编中定义的变量:地址
      在这里插入图片描述

总结

代码地址

文章来源:https://blog.csdn.net/weixin_53492721/article/details/134730861
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。