作者descent (「雄辩是银,沉默是金」)
看板ASM
标题[心得] 在 x86 真实模式载入大於 1M 的 kernel
时间Sun Apr 27 11:46:34 2014
这篇是讨论如何在 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
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 58.114.140.73
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/ASM/M.1398570410.A.6E2.html
1F:推 WolfLord:nice info,but cannot using in 188 186 ●︿● 04/27 14:31
2F:推 alibuda174:very good info 04/27 14:33
3F:推 wgst88w:冥想 XDDDD 04/27 15:36
4F:推 damody: 04/28 15:58
5F:推 kikiqqp:有用 04/29 20:38
6F:推 KanoLoa:好厉害的冥想,你快迈入传奇了吧 06/01 23:53