2012年1月3日 星期二

x86 page table test (1)

侯捷老師說的「發表是最好的回憶」, 我很贊同, 所以我要精確把努力的過程紀錄下來。

這個程式讀寫物理位址: 0x801000, 0x800000, 並使用分頁轉換將線性位址從
0x800000 轉到 0x800000
以及
0x800000 轉到 0x801000

x86 page table test (0) 只做一對一轉換, 純粹練習 paging 用的, 實際上沒享受到分頁的好處。

由於會使用 call 指令, 所以還是事先設定好 stack 比較好 (沒設定好像也沒事)。

182 mov $(SelectorStack), %ax
183 mov %ax, %ss # 堆疊段選擇子
184 mov $(TopOfStack), %esp


程式先寫入 0xe8 到 0x801000,

189
mov $(SELECTOR_FREE_MEM_AREA), %ax
190 mov %ax, %es
191 movb $0xe8, %es:(0x1000)

再來設定好兩組 page table:
(PAGE_DIR_BASE/PAGE_TBL_BASE)
(PAGE_DIR_BASE_1/PAGE_TBL_BASE_1)

200
call SetupPaging /* set up paging before 32-bit code */
201 call SetupPaging_1 /* set up paging before 32-bit code */

然後使用 switch_page_dir 將 (PAGE_DIR_BASE/PAGE_TBL_BASE) 的設定寫入 cr3。

203 call switch_page_dir


程式寫入 0xf9 到位址 0x800000,

208 mov $(SELECTOR_FREE_MEM_AREA), %ax
209 mov %ax, %es
210 movb $0xf9, %es:(0)
211 movb %es:(0), %al
212 call DispAL
213
214 mov $(SelectorVideo), %ax
215 mov %ax, %gs /* Video segment selector(dest) */
216 mov $20, %edi
217 mov $(SELECTOR_FREE_MEM_AREA), %ax
218 mov %ax, %es
219 # movb $0xf9, %es:(0)
220 movb %es:(0), %al
221 call DispAL

然後再由 0x800000 複製到 al, 兩次的動作藉由 DispAL 將值印出來, 確認寫入的位址無誤。

再來使用 switch_page_dir_1 將 (PAGE_DIR_BASE_1/PAGE_TBL_BASE_1) 的設定寫入 cr3。

225 call switch_page_dir_1


程式先寫入 0xe3 到位址 0x800000 (但其物理位址已經被轉到是 0x801000)

229 mov $(SELECTOR_FREE_MEM_AREA), %ax
230 mov %ax, %es
231 movb $0xe3, %es:(0)


寫入的線性位址是一樣的, %es:(0), 但是經過 page maping 之後, 這是對應到 0x801000, 而不是 0x800000。

將原本的 page table 切回來之後,

236 call switch_page_dir
237
238 mov $(SelectorVideo), %ax
239 mov %ax, %gs /* Video segment selector(dest) */
240 mov $40, %edi
241 mov $(SELECTOR_FREE_MEM_AREA), %ax
242 mov %ax, %es
243 # movb $0xf9, %es:(0)
244 movb %es:(0), %al
245 call DispAL

0x800000 印出 F9


246

247 movb %es:(0x1000), %al
248 mov $50, %edi
249 call DispAL

0x801000 印出 E3

為什麼用 0x801000, 0x800000 這兩個位址來測試呢?這是特別設計過的, 我首先想要做的事情:

  1. 讓線性位址 0x800000 在分頁轉換後對應到 0x800000;
  2. 另一個分頁轉換則是, 讓線性位址 0x800000 在分頁轉換後對應到 0x801000;

0x800000 二進位 0000 0000 1000 0000 0000 0000 0000 0000
分成三部份:

0000 0000 10 = 2(十進位) 表示 page directory 要選第二個 entry, 這個 entry 的內容我填入第二個 page table 的位址。所以分頁轉換會去找第二個 page table。

所以修改第二個 page table:

382 # setup the 2nd page
383 mov $(SELECTOR_PAGE_TBL_1), %ax
384 mov %ax, %es
385 mov $(TEST_OFFSET|PG_P | PG_USU | PG_RWW), %eax
386 #mov %eax, %es:(0x3000)
387 mov %eax, %es:(0x2000)

再來的 00 0000 0000 就是第零個 page table item,
所以
387 mov %eax, %es:(0x2000)

就是寫入第二個 page table 的第零個 page table item (第二個 page table 的第一個 page table item 位址是: %es:(0x2000 + 0x1000)), 讓他變成 0x00801000

.set TEST_OFFSET, 0x00801000 # const for 0x00801000

這是為了讓 0x800000 在分頁轉換後變成了 0x801000。

線性位址 0x800000 表示去查第二個 page table 的第零個 page table item 的值, 目前是 0x00801000, 而 or 上 0x800000000 變是 0x00801000 (0x00801 | 000), 這是經過分頁轉換物理位址。

這程式會在切回 dos/real mode 時當掉,
outb %al, $0x92
死在這裡, 不知道為什麼, 有空再來查了。

想要進一步測試可以把

mov %eax, %es:(0x2000) 換成 mov %eax, %es:(0x3000)

由於寫到不正確的分頁表, 所以 0x800000 並不會轉換成 0x00801000。所以最後還是看到 E8。並沒有在第二次的分頁轉換後被改成 E3。而由於這樣是一對一轉換, 所以實際上修改的是 0x800000 的物理位址, 所以 fail 那張圖本來 F9 的地方被改成 E3。

杨文博/于渊的版本用的是 function call 的方法, 我覺得有點複雜, 所以自己亂想出這個測試程式, 果然藉由程式的實作, 比教科書上來的有印象多了, 560 行在 dos 下執行的程式, 就可以了解什麼是分頁記憶體管理, 比硬背好多了。寫的不夠完整, 要全盤了解這段 code, 可能需要把杨文博/于渊的書籍 (保護模式那章) 讀一遍。

214 mov $(SelectorVideo), %ax
215 mov %ax, %gs /* Video segment selector(dest) */
216 mov $20, %edi

216 的 edi 設定是 video address, 表示要把 AL 的內容顯示在哪一行哪一列。

pt_2.S
1 /*
2 ref: Orange'S:一个操作系统的实现
3 do the 5M memory r/w
4 */
5 /* chapter3/1/loader.S
6
7 Author: Wenbo Yang <solrex@gmail.com> <http://solrex.cn>
8
9 This file is part of the source code of book "Write Your Own OS with Free
10 and Open Source Software"
. Homepage @ <http://share.solrex.cn/WriteOS/>.
11
12 This file is licensed under the GNU General Public License; either
13 version 3 of the License, or (at your option) any later version. */
14 /*
15 * describe by descent:
16 *
17 * copy from 5M_mem_rw.S and modify for page table test.
18 */
19
20 #include "pm.h"
21
22 .set PAGE_DIR_BASE, 0x100000 /* 1MB, base address of page directory */
23 .set PAGE_TBL_BASE, 0x101000 /* 1MB+4KB, base address of page table */
24
25 .set PAGE_DIR_BASE_1, 0x200000 /* 2MB, base address of page directory */
26 .set PAGE_TBL_BASE_1, 0x201000 /* 2MB+4KB, base address of page table */
27
28 .set FREE_MEM_AREA, 0x800000 # 8 MB address, use to a free memroy for rw
29 .set TEST_OFFSET, 0x00801000 # const for 0x00801000
30
31 .code16
32 .text
33 jmp LABEL_BEGIN /* jump over the .data section. */
34
35 /* NOTE! Wenbo-20080512: Actually here we put the normal .data section into
36 the .code section. For application SW, it is not allowed. However, we are
37 writing an OS. That is OK. Because there is no OS to complain about
38 that behavior. :) */
39
40 /* Global Descriptor Table */
41 LABEL_GDT: Descriptor 0, 0, 0
42 LABEL_DESC_NORMAL: Descriptor 0, 0xffff, DA_DRW # Normal descriptor is for back to real mode.
43 LABEL_DESC_CODE32: Descriptor 0, (SegCode32Len - 1), (DA_C + DA_32)
44 LABEL_DESC_CODE16: Descriptor 0, 0xffff, DA_C # 非一致程式碼段, 16
45 LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW # Data
46 LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32 # Stack, 32 位
47 LABEL_DESC_TEST: Descriptor 0x500000, 0xffff, DA_DRW
48 LABEL_DESC_VIDEO: Descriptor 0xB8000, 0xffff, DA_DRW
49
50 LABEL_DES_PAGE_DIR: Descriptor PAGE_DIR_BASE, 4096, DA_DRW
51 LABEL_DES_PAGE_TBL: Descriptor PAGE_TBL_BASE, 1023, (DA_DRW | DA_LIMIT_4K)
52
53 LABEL_DES_PAGE_DIR_1: Descriptor PAGE_DIR_BASE_1, 4096, DA_DRW
54 LABEL_DES_PAGE_TBL_1: Descriptor PAGE_TBL_BASE_1, 1023, (DA_DRW | DA_LIMIT_4K)
55
56 LABEL_DES_FREE_MEM_AREA: Descriptor FREE_MEM_AREA, 0xfffff, (DA_DRW | DA_LIMIT_4K)
57
58 .set GdtLen, (. - LABEL_GDT) /* GDT Length */
59
60 GdtPtr: .2byte (GdtLen - 1) /* GDT Limit */
61 .4byte 0 /* GDT Base */
62
63 /* GDT Selector */
64 .set SelectorNormal, (LABEL_DESC_NORMAL - LABEL_GDT)
65 .set SelectorCode32, (LABEL_DESC_CODE32 - LABEL_GDT)
66 .set SelectorCode16, (LABEL_DESC_CODE16 - LABEL_GDT)
67 .set SelectorData, (LABEL_DESC_DATA - LABEL_GDT)
68 .set SelectorStack, (LABEL_DESC_STACK - LABEL_GDT)
69 .set SelectorTest, (LABEL_DESC_TEST - LABEL_GDT)
70 .set SelectorVideo, (LABEL_DESC_VIDEO - LABEL_GDT)
71 .set SELECTOR_PAGE_DIR, (LABEL_DES_PAGE_DIR - LABEL_GDT)
72 .set SELECTOR_PAGE_TBL, (LABEL_DES_PAGE_TBL - LABEL_GDT)
73 .set SELECTOR_PAGE_DIR_1, (LABEL_DES_PAGE_DIR_1 - LABEL_GDT)
74 .set SELECTOR_PAGE_TBL_1, (LABEL_DES_PAGE_TBL_1 - LABEL_GDT)
75 .set SELECTOR_FREE_MEM_AREA, (LABEL_DES_FREE_MEM_AREA - LABEL_GDT)
76
77
78 /* Program starts here. */
79 LABEL_BEGIN:
80 mov %cs, %ax /* Move code segment address(CS) to data segment */
81 mov %ax, %ds /* register(DS), ES and SS. Because we have */
82 mov %ax, %es /* embedded .data section into .code section in */
83 mov %ax, %ss /* the start(mentioned in the NOTE above). */
84
85 movw $0x100, %sp
86 nop
87 movw %ax, (LABEL_GO_BACK_TO_REAL+3) # modify segment value, indexed memory mode, ref professional aeesmbly language p 102.
88 movw %sp, (SPValueInRealMode)
89
90
91 /* Initialize 16-bits code segment descriptor. */
92 xor %eax, %eax
93 mov %cs, %ax
94 shl $4, %eax
95 addl $(LABEL_SEG_CODE16), %eax
96 movw %ax, (LABEL_DESC_CODE16 + 2)
97 shr $16, %eax
98 movb %al, (LABEL_DESC_CODE16 + 4)
99 movb %ah, (LABEL_DESC_CODE16 + 7)
100
101 /* Initialize 32-bits code segment descriptor. */
102 xor %eax, %eax
103 mov %cs, %ax
104 shl $4, %eax
105 addl $(LABEL_SEG_CODE32), %eax
106 movw %ax, (LABEL_DESC_CODE32 + 2)
107 shr $16, %eax
108 movb %al, (LABEL_DESC_CODE32 + 4)
109 movb %ah, (LABEL_DESC_CODE32 + 7)
110
111 # initialize data segment descriptor
112 xor %eax, %eax
113 mov %ds, %ax
114 shl $4, %eax
115 addl $(LABEL_DATA), %eax
116 movw %ax, (LABEL_DESC_DATA + 2)
117 shr $16, %eax
118 movb %al, (LABEL_DESC_DATA + 4)
119 movb %ah, (LABEL_DESC_DATA + 7)
120
121 # initialize stack segment descriptor
122 xor %eax, %eax
123 mov %ds, %ax
124 shl $4, %eax
125 addl $(LABEL_STACK), %eax
126 movw %ax, (LABEL_DESC_STACK + 2)
127 shr $16, %eax
128 movb %al, (LABEL_DESC_STACK + 4)
129 movb %ah, (LABEL_DESC_STACK + 7)
130
131 /* Prepared for loading GDTR */
132 xor %eax, %eax
133 mov %ds, %ax
134 shl $4, %eax
135 add $(LABEL_GDT), %eax /* eax <- gdt base*/
136 movl %eax, (GdtPtr + 2)
137
138 /* Load GDTR(Global Descriptor Table Register) */
139 lgdtw GdtPtr
140
141 /* Clear Interrupt Flags */
142 cli
143
144 /* Open A20 line. */
145 inb $0x92, %al
146 orb $0b00000010, %al
147 outb %al, $0x92
148
149 /* Enable protect mode, PE bit of CR0. */
150 movl %cr0, %eax
151 orl $1, %eax
152 movl %eax, %cr0
153
154 /* Mixed-Size Jump. */
155 ljmp $SelectorCode32, $0 /* Thanks to earthengine@gmail, I got */
156 /* this mixed-size jump insn of gas. */
157 /* this calls far jump (ptr 16:32) in intel manual) */
158
159 LABEL_REAL_ENTRY: # 從保護模式跳回到實模式就到了這裡
160 mov %cx, %ax
161 mov %ax, %ds
162 mov %ax, %es
163 mov %ax, %ss
164
165 # mov sp, [SPValueInRealMode]
166 movw (SPValueInRealMode), %sp
167
168 jmp .
169
170 inb $0x92, %al
171 andb $0b11111101, %al # close A20 line
172 outb %al, $0x92
173
174 sti # 開中斷
175
176 mov $0x4c00, %ax
177 int $0x21 # 回到 DOS
178 # END of .code16
179
180 LABEL_SEG_CODE32:
181 .code32
182 mov $(SelectorStack), %ax
183 mov %ax, %ss # 堆疊段選擇子
184 mov $(TopOfStack), %esp
185
186 mov $(SelectorVideo), %ax
187 mov %ax, %gs /* Video segment selector(dest) */
188 mov $0, %edi
189 mov $(SELECTOR_FREE_MEM_AREA), %ax
190 mov %ax, %es
191 movb $0xe8, %es:(0x1000)
192 movb %es:(0x1000), %al
193 call DispAL
194
195 # movb $0x76, %es:(0x1000)
196 # movb %es:(0x1000), %al
197 # mov $90, %edi
198 # call DispAL
199
200 call SetupPaging /* set up paging before 32-bit code */
201 call SetupPaging_1 /* set up paging before 32-bit code */
202
203 call switch_page_dir
204
205 mov $(SelectorVideo), %ax
206 mov %ax, %gs /* Video segment selector(dest) */
207 mov $10, %edi
208 mov $(SELECTOR_FREE_MEM_AREA), %ax
209 mov %ax, %es
210 movb $0xf9, %es:(0)
211 movb %es:(0), %al
212 call DispAL
213
214 mov $(SelectorVideo), %ax
215 mov %ax, %gs /* Video segment selector(dest) */
216 mov $20, %edi
217 mov $(SELECTOR_FREE_MEM_AREA), %ax
218 mov %ax, %es
219 # movb $0xf9, %es:(0)
220 movb %es:(0), %al
221 call DispAL
222
223
224 #if 1
225 call switch_page_dir_1
226 mov $(SelectorVideo), %ax
227 mov %ax, %gs /* Video segment selector(dest) */
228 mov $30, %edi
229 mov $(SELECTOR_FREE_MEM_AREA), %ax
230 mov %ax, %es
231 movb $0xe3, %es:(0)
232 # movb %es:(0), %al
233 # call DispAL
234 #endif
235
236 call switch_page_dir
237
238 mov $(SelectorVideo), %ax
239 mov %ax, %gs /* Video segment selector(dest) */
240 mov $40, %edi
241 mov $(SELECTOR_FREE_MEM_AREA), %ax
242 mov %ax, %es
243 # movb $0xf9, %es:(0)
244 movb %es:(0), %al
245 call DispAL
246
247 movb %es:(0x1000), %al
248 mov $50, %edi
249 call DispAL
250
251
252
253 mov $(SelectorData), %ax
254 mov %ax, %ds # 資料段選擇子
255 mov $(SelectorTest), %ax
256 mov %ax, %es # 測試段選擇子
257
258
259
260
261 mov $(SelectorVideo), %ax
262 mov %ax, %gs /* Video segment selector(dest) */
263
264 mov $(SelectorStack), %ax
265 mov %ax, %ss # 堆疊段選擇子
266
267 mov $(TopOfStack), %esp
268
269
270
271 /*
272 movl $((80 * 10 + 0) * 2), %edi
273 movb $0xC, %ah # 0000: Black Back 1100: Red Front
274 movb $'P', %al
275
276 mov %ax, %gs:(%edi)
277 */
278
279 # print string "In Protect Mode now. ^-^"
280 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
281 xor %esi, %esi
282 xor %edi, %edi
283 mov $(OffsetPMMessage), %esi # data string offset
284 movl $((80 * 10 + 0) * 2), %edi # 目的資料偏移。螢幕第 10 行, 第 0 列。
285 cld # Clear Direction Flag, ref: http://www.fermi.mn.it/linux/quarta/x86/cld.htm
286 # After CLD is executed, string operations will increment the index
287 # (SI and/or DI) that they use.
288 .1:
289 lodsb # For legacy mode, Load byte at address DS:(E)SI into AL.
290 # For 64-bit mode load byte at address (R)SI into AL.
291 # ref: http://siyobik.info/main/reference/instruction/LODS%2FLODSB%2FLODSW%2FLODSD%2FLODSQ
292 test %al, %al # result is 0, zf sets to 1.
293 jz .2 # zf = 1 jump
294 # mov [gs:edi], ax
295 mov %ax, %gs:(%edi)
296 add $2, %edi
297 jmp .1
298 .2: # 顯示完畢
299
300 #push %eax # Multiboot magic number
301 # push %ebx # Multiboot data structure
302
303 # call kmain
304 call DispReturn
305 #movb $0xa9, %al
306 #call DispAL
307
308 call TestRead
309 call TestWrite
310 call TestRead
311
312
313 ljmpl $SelectorCode16,$0
314 # jmpl $SelectorCode16,$0 # it works
315
316 # ------------------------------------------------------------------------
317 SetupPaging:
318 /* Directly map linear addresses to physical addresses for simplification */
319 /* Init page directory, %ecx entries. */
320 mov $(SELECTOR_PAGE_DIR), %ax
321 mov %ax, %es
322 mov $1024, %ecx /* Loop counter, num of page tables: 1024 */
323 xor %edi, %edi
324 xor %eax, %eax
325 /* Set PDE attributes(flags): P: 1, U/S: 1, R/W: 1. */
326 mov $(PAGE_TBL_BASE | PG_P | PG_USU | PG_RWW), %eax
327 SP.1:
328 stosl /* Store %eax to %es:%edi consecutively. */
329 add $4096, %eax /* Page tables are in sequential format. */
330 loop SP.1 /* %ecx loops. */
331
332 /* Init page tables, %ecx pages. */
333 mov $(SELECTOR_PAGE_TBL), %ax
334 mov %ax, %es
335 mov $(30*1024), %ecx /* Loop counter, num of pages: 1024^2. */
336 xor %edi, %edi
337 /* Set PTE attributes(flags): P:1, U/S: 1, R/W: 1. */
338 mov $(PG_P | PG_USU | PG_RWW), %eax
339 SP.2:
340 stosl /* Store %eax to %es:%edi consecutively. */
341 add $4096, %eax /* Pages are in sequential format. */
342 loop SP.2 /* %ecx loops. */
343
344 ret
345 # end SetupPaging:
346
347 switch_page_dir:
348 mov $(PAGE_DIR_BASE), %eax
349 mov %eax, %cr3 /* Store base address of page table dir to %cr3. */
350 mov %cr0, %eax
351 or $0x80000000, %eax
352 mov %eax, %cr0 /* Enable paging bit in %cr0. */
353 ret
354
355 SetupPaging_1:
356 /* Directly map linear addresses to physical addresses for simplification */
357 /* Init page directory, %ecx entries. */
358 mov $(SELECTOR_PAGE_DIR_1), %ax
359 mov %ax, %es
360 mov $1024, %ecx /* Loop counter, num of page tables: 1024 */
361 xor %edi, %edi
362 xor %eax, %eax
363 /* Set PDE attributes(flags): P: 1, U/S: 1, R/W: 1. */
364 mov $(PAGE_TBL_BASE_1 | PG_P | PG_USU | PG_RWW), %eax
365 SP2.1:
366 stosl /* Store %eax to %es:%edi consecutively. */
367 add $4096, %eax /* Page tables are in sequential format. */
368 loop SP2.1 /* %ecx loops. */
369
370 /* Init page tables, %ecx pages. */
371 mov $(SELECTOR_PAGE_TBL_1), %ax
372 mov %ax, %es
373 mov $(30*1024), %ecx /* Loop counter, num of pages: 1024^2. */
374 xor %edi, %edi
375 /* Set PTE attributes(flags): P:1, U/S: 1, R/W: 1. */
376 mov $(PG_P | PG_USU | PG_RWW), %eax
377 SP2.2:
378 stosl /* Store %eax to %es:%edi consecutively. */
379 add $4096, %eax /* Pages are in sequential format. */
380 loop SP2.2 /* %ecx loops. */
381
382 # setup the 2nd page
383 mov $(SELECTOR_PAGE_TBL_1), %ax
384 mov %ax, %es
385 mov $(TEST_OFFSET|PG_P | PG_USU | PG_RWW), %eax
386 #mov %eax, %es:(0x3000)
387 mov %eax, %es:(0x2000)
388
389 ret
390 # end SetupPaging_1
391
392 switch_page_dir_1:
393 mov $(PAGE_DIR_BASE_1), %eax
394 mov %eax, %cr3 /* Store base address of page table dir to %cr3. */
395 mov %cr0, %eax
396 or $0x80000000, %eax
397 mov %eax, %cr0 /* Enable paging bit in %cr0. */
398 ret
399
400 TestRead:
401 xor %esi, %esi
402 mov $8, %ecx
403 .loop:
404 mov %es:(%esi), %al
405 call DispAL
406 inc %esi
407 loop .loop
408 call DispReturn
409
410 ret
411 # TestRead 結束-----------------------------------------------------------
412
413
414 # ------------------------------------------------------------------------
415 TestWrite:
416 pushl %esi
417 pushl %edi
418 xor %esi, %esi
419 xor %edi, %edi
420 mov $(OffsetStrTest), %esi # data offset
421 cld # Clear Direction Flag, ref: http://www.fermi.mn.it/linux/quarta/x86/cld.htm
422 # After CLD is executed, string operations will increment the index
423 # (SI and/or DI) that they use.
424 .6:
425 lodsb # For legacy mode, Load byte at address DS:(E)SI into AL.
426 # For 64-bit mode load byte at address (R)SI into AL.
427 # ref: http://siyobik.info/main/reference/instruction/LODS%2FLODSB%2FLODSW%2FLODSD%2FLODSQ
428
429 test %al, %al
430 jz .5 # zf = 1 jump
431 # mov [es:edi], al
432 mov %al, %es:(%edi)
433 inc %edi
434 jmp .6
435 .5:
436
437 popl %edi
438 popl %esi
439 ret
440 # TestWrite 結束----------------------------------------------------------
441
442
443 # ------------------------------------------------------------------------
444 # 顯示 AL 中的數字
445 # 默認地:
446 # 數字已經存在 AL 中
447 # edi 始終指向要顯示的下一個字元的位置
448 # 被改變的暫存器:
449 # ax, edi
450 # ------------------------------------------------------------------------
451 DispAL:
452 pushl %ecx
453 pushl %edx
454
455 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
456 movb %al, %dl
457 shr $4, %al
458 movl $2, %ecx
459 .begin:
460 andb $0x0f, %al
461 cmp $9, %al
462 ja .3 # cf=0, zf=0, above 9 (>9)
463 #addb $'0', %al
464 addb $0x30, %al
465 jmp .4
466 .3:
467 sub $0x0A, %al
468 #add $'A', %al
469 add $0x41, %al
470 .4:
471 #mov [gs:edi], ax
472 mov %ax, %gs:(%edi)
473 add $2, %edi
474
475 mov %dl, %al
476 loop .begin
477 add $2, %edi
478
479 popl %edx
480 popl %ecx
481
482 ret
483 # DispAL 結束-------------------------------------------------------------
484
485
486 # ------------------------------------------------------------------------
487 DispReturn:
488 pushl %eax
489 pushl %ebx
490 mov %edi, %eax
491 movb $160, %bl
492 divb %bl # %eax/160, 商 al, 餘數 ah.
493 and $0x0FF, %eax
494 inc %eax # ++ %eax
495 mov $160, %bl
496 mul %bl
497 mov %eax, %edi
498 popl %ebx
499 popl %eax
500 ret
501 # DispReturn 結束---------------------------------------------------------
502
503 /*
504 kmain:
505 pushl %ebp
506 movl %esp, %ebp
507 popl %ebp
508 ret
509 .size kmain, .-kmain
510 .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
511 */
512 # .section .note.GNU-stack,"",@progbits
513
514
515 /* Get the length of 32-bit segment code. */
516 .set SegCode32Len, . - LABEL_SEG_CODE32
517
518 #[SECTION .data1] ; 資料段
519 #ALIGN 32
520 #[BITS 32]
521 LABEL_DATA:
522 SPValueInRealMode: .2byte 0x0
523 # string
524 PMMessage: .ascii "In Protect Mode now. ^-^\0" # 在保護模式中顯示
525 .set OffsetPMMessage, (PMMessage - LABEL_DATA)
526 #StrTest: .ascii "B\0"
527 StrTest: .ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0"
528 #OffsetStrTest equ StrTest - $$
529 .set OffsetStrTest , (StrTest - LABEL_DATA)
530 #DataLen equ $ - LABEL_DATA
531 .set DataLen, . - LABEL_DATA
532 /* 32-bit global stack segment. */
533 LABEL_STACK:
534 .space 512, 0
535 .set TopOfStack, (. - LABEL_STACK - 1)
536
537 # END of [SECTION .data1]
538
539
540 LABEL_SEG_CODE16:
541 .code16
542 #jmp .
543 # back to real mode
544 mov $SelectorNormal, %ax
545 mov %ax, %ds
546 mov %ax, %es
547 mov %ax, %fs
548 mov %ax, %gs
549 mov %ax, %ss
550
551 mov %cr0, %eax
552 and $0b11111110, %al
553 mov %eax, %cr0
554
555
556 LABEL_GO_BACK_TO_REAL:
557 #.2byte 0xea66
558 #.4byte 0x00000000
559 #.2byte LABEL_REAL_ENTRY
560 jmp $0, $LABEL_REAL_ENTRY # 段位址會在程序開始處被設置成正確的值
561
562
563 .set Code16Len, . - LABEL_SEG_CODE16
564
565
566



E8, F9, F9, F9, E3 的物理位址分別是 0x801000, 0x800000, 0x800000, 0x800000, 0x801000。

* paging ok


E8, F9, F9, E3, E8 的物理位址分別是 0x801000, 0x800000, 0x800000, 0x800000, 0x801000。


* paging fail

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。