[心得] 在 x86 真实模式加载大于 1M 的 kernel

楼主: descent (“雄辩是银,沉默是金”)   2014-04-27 11:46:34
这篇是讨论如何在 x86 真实模式下存取超过 1M ram。
有什么问题还请大家指证。
这问题还真有点困难, 因为在 x86 真实模式下, 只能存取 1M 内存位址,
但实际上比 1M 还少, 还记得 dos 的 640K 限制吗?扣掉
bios/接口卡所使用的内存空间, 大概只有 0x0000:0x0500 ~ 0x9000:0xFFFF 这范围的
内存可用。
大约是: 0xa0000 - 0x500 = 654080 byte 。
参考这张内存配置图:http://goo.gl/ujPPFw (
http://descent-incoming.blogspot.tw/2012/11/elf.html )
simple os kernel + romfs ramdisk 就必须小于 654080 byte。
kernel 要超过很不容易, 但是 ramdisk 随便塞个档案就容易超过了, 所以该是来解决这
问题了。
有两个方法:
自己处理磁盘加载的程式码, 也就是自己刻 floppy disk, ide/sata driver, 不使用
bios 0x13 call, 这样就可以在保护模式下驱动磁盘机。
使用 big real mode。
柿子挑软的吃, 方案一实在太困难, usb floppy 要搞定的东西可不少, 不像以前使用单
纯的软碟接口, 光是处理 usb 可就不轻松。我决定使用 big real mode。
big real mode 也称为 unreal mode, flat real mode 简单说就是在 real mode 下, 但
是可以存取 4g 的内存空间, 怎么做到?大概是这样:
切入保护模式, 设定存取 4g 的 gdt/selector, 设定这个 selector 到某个 segment
register (ex: %fs), 切回真实模式, 使用 %fs 来寻址。
big real mode:
http://blog.csdn.net/lightseed/article/details/4312834 ( http://goo.gl/BY3JQ2
)
http://www.mouseos.com/arch/unreal.html ( http://goo.gl/rgRcnK )
http://en.wikipedia.org/wiki/Unreal_mode ( http://goo.gl/NPFJac )
big real mode 可以调用呼叫真实模式下的 bios call, 所以我就可以使用 int 0x13 来
读取磁盘上的档案, 每次读取一个 sector, 然后复制到 1MB 以外的位址 (我是复制到
0x300000), 这样就可以在真实模式下加载一个超过 1MB 的 kernel。
我使用 %fs:0x300000 这样的方式将 kernel 复制到这个位址 (in big real mode)。
%fs 是 0x28 (base = 0, limit = 4G), 在我的认知, 我认为绝对位址应该是
0x300000, 也就是我复制 kernel 到物理位址 0x300000。而切换到保护模式后 (同一份
gdt), 读取 0x300000 也应该可以读到 kernel。
一开始我在 qemu/bochs 测试, 如我所愿, 我也使用 bochs 内建 debugger 观看
0x300000 的位址, 的确是 kernel 的内容。
本来以为已经搞定, 模拟器 qemu/bochs 都没问题, 开心的不得了, 在真实机器测试应该
也可顺利通过, but ... 在真实机器下却不是这样, 程式完全不正常, 没什么比这还令人
沮丧了。无法在真实机器执行, 这程式就没意义了, 对我来说, 这就是错误的程式, 我不
希望这程式只能活在虚拟机环境。
真实机器可没有那么好的 debug 环境, 透过冥想 + debug code, 勉强在真实机器上完成
了。
在真实机器上, %fs:0x300000 并不是存取到 0x300000, 而是 0x300000+0x28x16。我如
何得知?因为我写程式去 dump 0x300000 的内容, 并不是我预期的 kernel, 而
0x300000+0x28x16 才是 kernel 的内容。我猜测在真实机器上 %fs:0x300000 存取的不
是 0x300000 而是 0x300000+0x28x16, 因为 %fs 是 0x28 的关系。
我疑惑的是 qemu/bochs 的结果和真实机器不同, 是我搞错什么了? 在 eeepc 901 和
amd 的机器上测试, %fs:0x300000 都是得到 0x300000+0x28x16, 而不是我预期的
0x300000。
其实我有用 %fs:0xb8000 来显示 char (in big real mode), 并不是在第0行, 第0列的
位址, 才让我想到有可能差了 0x28X16。下图的蓝色字串便是使用 %fs:0xb8000 来印到
萤幕。
( http://goo.gl/wuQNrD )
寄件者 write_os ( http://goo.gl/jDT3LC )
在 eeepc 901 上测试, 这个 kernel size: 672596 超过 654080, 证明突破 640K 真实
模式下的限制。
( http://goo.gl/OV48TT )
上图是 simple os 执行画面, 那么问题出在哪里呢?
selector 0x28 in %fs, 这是我在 big real mode 设定的 gdt/selector。
LABEL_DESC_4G_RW: Descriptor 0, 0xfffff, DA_DRW | DA_32 | DA_LIMIT_4K
0x28 这个 selector 定义的 segment 如上:
base:0
limit: 0xffffffff
整个 4G 空间。
在 qemu/bochs 保护模式下, 使用 %fs:0x300000 时, 是指到绝对位址 0x300000, 3M 的
位址上。但在我的 eeepc 901 真实机器上则是 0x300000 + 0x28*16 = 0x300280
#ifdef REAL_PC
u32 buff = LOAD_KERNEL_ADDR + (0x28*16);
#else
u32 buff = LOAD_KERNEL_ADDR;
#endif
所以我的程式多了这个 REAL_PC macro。
下面的图是另外一台 nb, amd 的 cpu, 也可正常开到 simple os 画面, 让我对程式的正
确性信心大增。
( http://goo.gl/HoqnWf )
前面说勉强可用是因为若插入 debug function, insert p_dump_u8(buff, 32); in
copy_elf_code(), kernel 还是无法正常加载, dump_u8() 是 debug function, 所以又
得靠冥想来解决这问题了。
好累, 没处理掉这问题, 休假期间都睡不安稳阿!
附上一起和我 debug 的 ibm usb floppy disk, 辛苦啦, 喀喀喀的读取声, 缓慢的读取
速度, 还真怀念。
( http://goo.gl/s4fCWU )
寄件者 write_os ( http://goo.gl/jDT3LC )
使用 usb storage 测试 1M 的 kernel (1314148 bytes), 也能顺利加载。也许你会有个
疑问, 为什么不用软碟测试?
软碟要读很久, 我等著等著会睡着, 要是失败了, 很浪费时间。
软驱资料很容易出错, 有错的话, 我不知道是程式错了还是软盘片本身资料就是错的。
( http://goo.gl/r6A9Cr )
到这里都还在真实模式下 (正确来说是 big real mode), 按下空白键后就会切到保护模
式, 再来便会跳到 kernel 的 code, 执行 kernel。
usb storage 的速度比软盘片快多了, 画面的 '.' 代表读入一个 sector (512 byte),
所以 kernel 档案愈大看到的 '.' 就愈多, 看着画面上满满的 '.' 还蛮有成就感的。
https://github.com/descent/simple_os ( http://goo.gl/XDC9Iq )
git commit: 1ebf4fc42c484e0d2d2d0e9027ec4e9654ccb341
ref: x86/x64体系探索及程 by 志
// 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字 http://goo.gl/TZ4E17 //
blog 图文版本
http://descent-incoming.blogspot.tw/2013/02/x86-1m-kernel.html
作者: WolfLord (呆呆小狼￾ ￾ N￾ ￾ )   2014-04-27 14:31:00
nice info,but cannot using in 188 186 ●︿●
作者: alibuda174 (阿哩不达)   2014-04-27 14:33:00
very good info
作者: wgst88w (清楚明“熙”)   2014-04-27 15:36:00
冥想 XDDDD
作者: kikiqqp (喵食罐头)   2014-04-29 20:38:00
有用
作者: KanoLoa (卡)   2014-06-01 23:53:00
好厉害的冥想,你快迈入传奇了吧

Links booklink

Contact Us: admin [ a t ] ucptt.com