看板 ASM 關於我們 聯絡資訊
這篇是討論如何在 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://www.ptt.cc/bbs/ASM/M.1398570410.A.6E2.html
WolfLord:nice info,but cannot using in 188 186 ●︿● 04/27 14:31
alibuda174:very good info 04/27 14:33
wgst88w:冥想 XDDDD 04/27 15:36
damody: 04/28 15:58
kikiqqp:有用 04/29 20:38
KanoLoa:好厲害的冥想,你快邁入傳奇了吧 06/01 23:53