-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
大佬,关于内核我有些问题 #17
Comments
;boot.asm ;本文件主要是将主引导和内核读取到内存中 [BITS 16]
;FAT12信息 echo16: ;输出字符串 startDash:
firstRead:
Read: ReadMain: next:
readCore: readNext:
success: ;突然想加function(e){console.log(e)}
fail: msg_reading:
|
;loader.asm ;本文件主要加载GDT表IDT表,保存bios的信息,移动内核,切换保护模式和跳转到内核 ;0x7c00 boot %include "/home/lovelive/desktop/os/os/boot/pm.asm" ;引入oranges的常量表
;gdt表 gdtLenght equ $-gdt ;gdt选择子 start:
scr1024x768:
scr320x200: getKey: writeGDT: ;写gdt表
|
显示模式切换我是参考的《30天》,所以和大佬你现在的有些不同,大佬开始好像也是看的《30天》,然后loader我是对齐到了第二个扇区,这样我就直接把第二个扇区加到指定位置上,比较方便我操作 |
还有大佬,代码段中限长为0xfffff-1好像不够管理4G空间吧。。。 |
或者大佬,这么说吧。。。我之前在实模式下将内核加载到了0x10000开头的位置,我认为保护模式下GDT的起点是0x0000,那么我是不是将基指向gdt的data段然后跳转到0x10000就行,如果是那么ELF我需要如何执行?是直接将其装载到0X10000他就会被系统识别并通过找入口直接跳转到入口开始执行么? |
Hello,我已经好几年没有继续研究 kernel 了,而且现在也没有从事相关的工作, |
好的大佬 |
你的理解大致没错,在 OS67 里,boot/bootsect.asm 会在实模式下把内核加载到 0x8000,开启保护模式并进入 32 位模式后之后跳转到 loader.asm 在这里是内核的一部分,和内核本体的 c 代码被编译成一个 binary,因此符号也是共享的,入口位置通过 |
大佬。。。[extern osmain] 不是引用一个外部定义了的函数么。。 |
Orz 好吧,看来我的理解有偏差,你要 ELF 入口点难道不是想找到内核代码开始的地方么?在没有 crt0 的情况下(其实我不知道有没有……),入口点不就是 main 函数么地址么? 对 OS67 来说并不存在什么 ELF 入口点,script/link.ld#L8 把内核的 .text 段安排在文件的最开始,生成一个 elf 格式的 kernel,然后 Makefile#L54 会把 elf 给 strip 成 binary,所以其实加载到内核的只是一个普通的 binary,它的 0x0 处就是 kernstart。 |
你用 bochs 看过 GDT 表了么?建议用 bochsdbg 在 JMP 前加个 INT 3 断下来单步跟跟看。 😂 你贴的代码感觉我现在已经看不懂了,你列举的四个可能的问题,都可以通过 bochsdbg 来解决,当然由于 GDT 设置错误的问题可能调起来不是很直观。 |
记得 DA_LIMIT_4K 也就是 Gr 位被置位的段的粒度是 4K 吧。 |
当然不「会被系统识别」,你就是系统,并没有一个第三者来帮你识别 elf 文件,除非你用更先进的 bootloader(比如基于 UEFI 的)。 如我刚才所说,OS67 的内核并不是一个 elf 文件,而是一个普通的 binary,因此与你现在的实现有出入,从汇编跳转到 C 代码这一段可能缺少参考价值。 对于 elf 来说,你直接跳转到 0x10000 也就是 elf 的 0x0 处当然是不行的,于渊的 Orange's 的做法是在汇编里解析 ELF 的 header,你可以参考看看,当年我看得很累于是采用了现在的做法…… |
那如果我采用打成一个elf或者其他文件然后加入镜像,并且不使用elf的格式,只相当于把内核打包成一个整体的文件,然后通过打包之后的地址进行访问不知道能不能成功,访问地址可以通过hexdump找到 |
应该可以,只要你保证总是能找到「入口点」,是什么格式都没所谓其实。 注意在跑 C 代码前先把其他的各种段基址设置好 kern/loader.asm#L21。 |
我现在是学校有个编程活动,我想参加,之前抄了一遍30天的代码,但是那位大佬的编译器什么什么的全是他自带了。。。感觉抄一遍代码交了学到的东西不多,参加活动的诚意也不足,然后看了os67和neuos,都是类unix,没有图形化,然后我现在卡住了。。一个打包的问题,因为现在的格式是FAT12,需要按照文件系统格式保存,我现在是在centos下创建img然后挂载之后往里面存东西来打img的,然后现在又卡在了c编译成内核,我想的是c编译成bin然后c里面加个头来引用其他所有的内容 |
谢谢大佬指点,我再去试试 |
我先试着保留boot.asm和loader.asm然后对齐两个文件到7c00和0x7e00然后将核心文件转成bin然后移动到0x10000处然后通过loader跳转到10000处试试 |
看 30 天只能看到有趣的东西,重要的细节通通被作者藏起来了,这也是我放弃抄 SilverRainZ/OSASK 的原因。 我对这本书的看法:https://www.cnblogs.com/lastavengers/p/4115612.html
neuos 是 @VOID001 那个么 😂 么?世界真小。
等你跨过保护模式和 C 语言的坎,开始做驱动,内存和进程部分的工作时,你会发现图形化实在算不得内核的一部分,尽管它也应该很有趣。
这是科学的做法。
可以参考下 loader.asm 是怎么做的,如果你不介意内核不是 elf 的话。 |
0.主要是第一次写,后面肯定会更加深入去了解 |
现在确实把指令加载到内存中了,我不再使用FAT12文件系统了 |
那应该就是GDT的问题,我现在加载到指定位置了但是没有跳转,我打算去掉保护模式进行一次实模式的跳转来验证正确性 |
成功 |
看到被 LA at 了,我就出来了 > < |
大师球 |
|
还有大佬你们。。。貌似都不喜欢用QQ和微信。。。 |
大佬们。。睡了么。。没睡要不咱来讨论个问题? @SilverRainZ @VOID001 |
我把代码整理一下贴在ubuntu pause吧,,, |
这个是loader.asm |
其中我将lgdt注释掉了,现在这样的gdt最后加载了的话gdt表好像全是0 |
建议你用 Bochs 断点调试,看 gdtr 的地址是多少,并且用 bochs 打印出那个地址的 data 确认是否有误,GDT Table 和 GDT Descriptor 的 format 可以看 Intel 手册得知 |
大佬,原因我查出来了,我看了一下gdtr的地址,是0x00a2,突然想到可能是因为加载到了内存的原因,因为他是在编译的时候确定的,所以我在开头加上了org 0x7e00这样他的地址就变成了0x7ea2,就可以正常读取到GDTR了 |
感觉是数据段的属性没设置对,触发某硬件中断然后 reset 了? |
大佬,这里的数据段是指elf数据段还是GDT表数据段呢。。 |
我试着向0x20000处写入但是还是reset了 |
GDT,你 ds 的值对得上么? |
ds是0x0000,能对上 |
0x0000 咋就对得上呢…… 保护模式下段寄存器不是段选择子的值么。 |
大佬我懂了,我ds应该设置gdt表中的段号,谢谢两位大佬的帮助 @SilverRainZ @VOID001 |
我刚才发现了。。。。好丢脸啊、、、 |
现在的情况就比如说,i是在0到15的范围变动的,5是包括在其中的,我把前面的font固定成图一的65,让i自行变动,如果成功那应该是至少有一行是有两个点的,但是。。完全没有。。。我是懵逼的。。代码没错但是结果就是出不来。。 |
箭头指向的上下都测试过了,都是正确的,就是指向的这行的两个空有问题。。。 |
测试的话无法输出数值,我是用二进制绘制变量自己的二进制码去读取变量数值的,看了是正确的 |
话说二维数组大小限制应该不会小到256*16吧。。我之前认为可能只加载10个柱面有数据没被加载进来,因为光ascii的点阵字库就12.0 KB,但是我加了读取的扇区,。。还是不行。。。 |
大佬。。过了。。我把字符数组的最后几排去掉就过了。。。?????一脸懵逼 |
1.我现在理解的内核加载是:bootloader把软盘里的内容加载到内存,然后跳转到ELF文件找到入口执行内核程序,但是不太清楚这里elf是自行进入脚本ld文件设置的入口还是需要我们给定入口位置
2.我现在是把bootloader分为boot和loader来写,boot主要把程序加载到内存,loader主要改显示模式,加载GDT表,开A20和切换保护模式等,我现在内存中的结构大概如此:
;0x7c00 boot
;0x7e00 loader
;0x8200 bios信息
;0x10000 内核
而GDT表现在是这样:
;gdt表
gdt: ;基地址 大小限制 这段的属性
gdt_null: Descriptor 0, 0, 0 ;空记录(基)
gdt_code: Descriptor 0, 0xfffff-1, DA_C+DA_32+DA_LIMIT_4K ;代码段
gdt_data: Descriptor 0, 0xfffff-1, DA_DRW+DA_32+DA_LIMIT_4K ;数据段
gdtLenght equ $-gdt
gdtLimit dw gdtLenght-1
gdtAddress dd gdt
;gdt选择子
selgdt_code equ gdt_code-gdt_null
selgdt_data equ gdt_data-gdt_null
然后我现在lgdt [gdtLimit] 后打算跳到内核执行
jmp dword selgdt_code:0x10000
但是貌似bochs又跳回了boot未启动的部分,也就是说重新加载了一遍程序,我想问一下大佬这里跳转部分我应该怎么做。bochs的GDT表好像和设置的不太一样,我现在总结出可能出现的问题:
1.我GDT设置有问题,基地址跳错位置了
2.我GDT表没设置上去
3.我跳转有问题
4.我从软盘加载到内存时候有问题
而其中内核加载到的内存地址我是boot中通过先将loader加载到0x7e00后将剩余部分全部加载到0x1000:0开始的位置
我下面会把boot和loader放上来,希望大佬给指点指点
The text was updated successfully, but these errors were encountered: