• 嗣树
    置顶
    2021-06-03
    回答一下问题,GRUB 头中为什么需要 _entry 标号和 _start 标号的地址? 我们定义的 flags 值为: MBT_HDR_FLAGS EQU 0x00010003 根据 Multiboot Specification 定义的头结构 Offset Type Field Name Note 0 u32 magic required 4 u32 flags required 8 u32 checksum required 12 u32 header_addr if flags[16] is set 16 u32 load_addr if flags[16] is set 20 u32 load_end_addr if flags[16] is set 24 u32 bss_end_addr if flags[16] is set 28 u32 entry_addr if flags[16] is set 32 u32 mode_type if flags[2] is set 36 u32 width if flags[2] is set 40 u32 height if flags[2] is set 44 u32 depth if flags[2] is set flags[16] 解释如下: If bit 16 in the ‘flags’ word is set, then the fields at offsets 12-28 in the Multiboot header are valid, and the boot loader should use them instead of the fields in the actual executable header to calculate where to load the OS image. This information does not need to be provided if the kernel image is in ELF format, but it must be provided if the images is in a.out format or in some other format. Compliant boot loaders must be able to load images that either are in ELF format or contain the load address information embedded in the Multiboot header; they may also directly support other executable formats, such as particular a.out variants, but are not required to. 也就是如果我们用的是标准的 ELF 文件就不需要提供额外的地址信息,而我们用的是自己定义的格式就需要人家从哪里加载哪里运行,所以需要将 bit 16 使能,填充相应的字段。 再解释下两个字段的含义: load_addr Contains the physical address of the beginning of the text segment. The offset in the OS image file at which to start loading is defined by the offset at which the header was found, minus (header_addr - load_addr). load_addr must be less than or equal to header_addr. entry_addr The physical address to which the boot loader should jump in order to start running the operating system.
    展开

    作者回复: 嗯嗯 是的

    共 3 条评论
    4
  • neohope
    置顶
    2021-06-02
    大体上整理了一下: 1、grub启动后,选择对应的启动菜单项,grub会通过自带文件系统驱动,定位到对应的eki文件 2、grub会尝试加载eki文件【eki文件需要满足grub多协议引导头的格式要求】 这些是在imginithead.asm中实现的,所以要包括: A、grub文件头,包括魔数、grub1和grub2支持等 B、定位的_start符号等 3、grub校验成功后,会调用_start,然跳转到_entry A、_entry中:关闭中断 B、加载GDT C、然后进入_32bits_mode,清理寄存器,设置栈顶 D、调用inithead_entry【C】 4、inithead_entry.c A、从imginithead.asm进入后,首先进入函数调用inithead_entry B、初始化光标,清屏 C、从eki文件内部,找到initldrsve.bin文件,并分别拷贝到内存的指定物理地址 D、从eki文件内部,找到initldrkrl.bin文件,并分别拷贝到内存的指定物理地址 E、返回imginithead.asm 5、imginithead.asm中继续执行 jmp 0x200000 而这个位置,就是initldrkrl.bin在内存的位置ILDRKRL_PHYADR 所以后面要执行initldrkrl.bin的内容 6、这样就到了ldrkrl32.asm的_entry A、将GDT加载到GDTR寄存器【内存】 B、将IDT加载到IDTR寄存器【中断】 C、跳转到_32bits_mode 初始寄存器 初始化栈 调用ldrkrl_entry【C】 7、ldrkrlentry.c A、初始化光标,清屏 B、收集机器参数init_bstartparm【C】 8、bstartparm.c A、初始化machbstart_t B、各类初始化函数,填充machbstart_t的内容 C、返回 9、ldrkrlentry.c A、返回 10、ldrkrl32.asm A、跳转到0x2000000地址继续执行
    展开

    作者回复: 厉害了,总结 的好

    共 15 条评论
    83
  • springXu
    置顶
    2021-06-02
    真实进入实际写代码的课程了。 对于grub的头格式在的第二节写个HelloOS.bin就已经有了,这次头格式还是会有。理由是grub是一级引导器。 这节课的内容就是围绕着由一级转到二级引导器的过程展开了。 关于二级引导器的加载过程,简单点说就是把我们内核加载到指定内存的位置并执行,这个加载函数核心是m2mcopy函数,东哥留给我们自己分析了,但东哥强调分析了下为什么会有32位下的代码和16位汇编代码共存的现象。 其实是为了让BIOS提供的获取硬件信息的操作函数(也就是实模式下的BIOS中断号来获取的)做成了c语言环境下也可以调用的功能。这就像跨语言互相调用的技术。汇编调用c语言的方法,反过来c语言调用汇编方法。但更为复杂些,原因是保护模式到实模式再回到保护模式的切换过程。内核可以获取硬件信息就可以根据硬件环境参数,配置自身参数开始工作了。如何配置参数,那又是下节继续播讲。周五见。 关于思考题,这个是grub也是要把控制权交给我们二级引导器的入口地址。 至于为什么不光有一个_start就可以了,我猜测是为了做验证吧。_start的操作是jmp 地址。这个地址正好是_entry。有错误还请东哥指正。哈哈
    展开

    作者回复: 正确的

    共 3 条评论
    19
  • pedro
    2021-06-02
    早起看专栏! 先回答思考题,grub是multiboot规范,因此引导器头部数据必须得满足一定的规则才能被grub所加载,本文中的MBT_HDR_FLAGS为0x001003,第16位被置为1,因此load_addr和entry_addr都是有效的,而它们正好分别对应_start和_entry。 其中load_addr是引导器二进制文件text段的起始地址,即_start,grub解析头部数据后,拿到_start地址,并从该地址处开始执行二级引导器代码。 而entry_addr对应的是操作系统的入口点,也就是_entry。引导程序最后将跳转到这里,不过本文的实现并没有完全按照这种思路来,_start直接跳到_entry,然后由_entry负责二级引导工作。

    作者回复: 对啊 哈哈 铁汁好

    共 5 条评论
    15
  • Amerny
    2021-09-18
    感觉代码也看不懂,稀里糊涂的,是不是得需要把代码看懂了才能进行下一步呀,脑子不够用了

    作者回复: 需要多看几遍

    
    11
  • 晶
    2021-08-24
    对应grub2的代码定义结构: struct multiboot_header { multiboot_uint32_t magic; // 魔数 0xE85250D6 multiboot_uint32_t architecture; // 架构 0表示x86 multiboot_uint32_t header_length; // 表示mb header 长度 multiboot_uint32_t checksum; // 校验和 }; 在 之后是multiboot_header_tag, struct multiboot_header_tag_address { multiboot_uint16_t type; // 2 表示 multiboot_header_tag_address multiboot_uint16_t flags; // 0 multiboot_uint32_t size; // 24 multiboot_uint32_t header_addr; // mbhdr multiboot_uint32_t load_addr; // _start multiboot_uint32_t load_end_addr; // 0 表示数据段 和 代码段一样 占用整个空间 multiboot_uint32_t bss_end_addr; // 0 }; 再之后是 multiboot_header_tag_entry_address struct multiboot_header_tag_entry_address { multiboot_uint16_t type; // type = 3 表示 multiboot_header_tag_entry_address multiboot_uint16_t flags; multiboot_uint32_t size; multiboot_uint32_t entry_addr; }; mbhdr: DD 0xE85250D6 magic DD 0 architecture DD mhdrend - mbhdr header_length DD -(0xE85250D6 + 0 + (mhdrend - mbhdr)) checksum ;multiboot_header_tag DW 2, 0 ; type = 2 ;flag = 0; DD 24 ; size =24 DD mbhdr DD _start DD 0 DD 0 ;multiboot_header_tag_entry_address DW 3, 0 ;;type = 3 flag = 0 DD 12 DD _entry ; entry_addr = _entry ; DD 0 DW 0, 0 DD 8
    展开

    作者回复: 是的

    
    5
  • 沈畅
    2021-08-15
    如果我们不用grub作为引导程序,自己写一个引导程序,在实模式下,是不是就可以直接调用bois中断收集硬件信息,而不需要后面在保护模式下切换回实模式,再收集?

    作者回复: 是的 是的

    
    4
  • 熊光红
    2021-06-03
    请问老师,如何调试内核?怎么搭建调试环境

    作者回复: printf 走天下

    共 3 条评论
    4
  • Jayying
    2021-07-31
    不大会汇编语言,感觉看汇编还有些难度

    编辑回复: 到十三节课以后主要就是C啦,加油~

    
    2
  • 🎋 🎋 🎋
    2021-07-27
    老师 lmoskrlimg:未找到命令 是为什么呀

    作者回复: 没到时候 继续往后看

    
    2