2012年1月2日 星期一

x86 page table test (0)

這是用來測試 x86 的分頁程式, 進入保護模式後, 設定 page directory, page table (231 SetupPaging:), 印出訊息後, 切回 dos/real mode, 並回到 dos prompt。

別小看只有 400 行的組合語言程式, 這可要花不少腦力才能完全了解。每一行的功能都是自己寫的, 沒有呼叫 bios。

pt_1.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, 0x200000 /* 2MB, base address of page directory */
23 .set PAGE_TBL_BASE, 0x201000 /* 2MB+4KB, base address of page table */
24
25 .code16
26 .text
27 jmp LABEL_BEGIN /* jump over the .data section. */
28
29 /* NOTE! Wenbo-20080512: Actually here we put the normal .data section into
30 the .code section. For application SW, it is not allowed. However, we are
31 writing an OS. That is OK. Because there is no OS to complain about
32 that behavior. :) */
33
34 /* Global Descriptor Table */
35 LABEL_GDT: Descriptor 0, 0, 0
36 LABEL_DESC_NORMAL: Descriptor 0, 0xffff, DA_DRW # Normal descriptor is for back to real mode.
37 LABEL_DESC_CODE32: Descriptor 0, (SegCode32Len - 1), (DA_C + DA_32)
38 LABEL_DESC_CODE16: Descriptor 0, 0xffff, DA_C # 非一致程式碼段, 16
39 LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW # Data
40 LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32 # Stack, 32 位
41 LABEL_DESC_TEST: Descriptor 0x500000, 0xffff, DA_DRW
42 LABEL_DESC_VIDEO: Descriptor 0xB8000, 0xffff, DA_DRW
43
44 LABEL_DES_PAGE_DIR: Descriptor PAGE_DIR_BASE, 4096, DA_DRW
45 LABEL_DES_PAGE_TBL: Descriptor PAGE_TBL_BASE, 1023, (DA_DRW | DA_LIMIT_4K)
46
47 .set GdtLen, (. - LABEL_GDT) /* GDT Length */
48
49 GdtPtr: .2byte (GdtLen - 1) /* GDT Limit */
50 .4byte 0 /* GDT Base */
51
52 /* GDT Selector */
53 .set SelectorNormal, (LABEL_DESC_NORMAL - LABEL_GDT)
54 .set SelectorCode32, (LABEL_DESC_CODE32 - LABEL_GDT)
55 .set SelectorCode16, (LABEL_DESC_CODE16 - LABEL_GDT)
56 .set SelectorData, (LABEL_DESC_DATA - LABEL_GDT)
57 .set SelectorStack, (LABEL_DESC_STACK - LABEL_GDT)
58 .set SelectorTest, (LABEL_DESC_TEST - LABEL_GDT)
59 .set SelectorVideo, (LABEL_DESC_VIDEO - LABEL_GDT)
60 .set SELECTOR_PAGE_DIR, (LABEL_DES_PAGE_DIR - LABEL_GDT)
61 .set SELECTOR_PAGE_TBL, (LABEL_DES_PAGE_TBL - LABEL_GDT)
62
63
64 /* Program starts here. */
65 LABEL_BEGIN:
66 mov %cs, %ax /* Move code segment address(CS) to data segment */
67 mov %ax, %ds /* register(DS), ES and SS. Because we have */
68 mov %ax, %es /* embedded .data section into .code section in */
69 mov %ax, %ss /* the start(mentioned in the NOTE above). */
70
71 movw $0x100, %sp
72 nop
73 movw %ax, (LABEL_GO_BACK_TO_REAL+3) # modify segment value, indexed memory mode, ref professional aeesmbly language p 102.
74 movw %sp, (SPValueInRealMode)
75
76
77 /* Initialize 16-bits code segment descriptor. */
78 xor %eax, %eax
79 mov %cs, %ax
80 shl $4, %eax
81 addl $(LABEL_SEG_CODE16), %eax
82 movw %ax, (LABEL_DESC_CODE16 + 2)
83 shr $16, %eax
84 movb %al, (LABEL_DESC_CODE16 + 4)
85 movb %ah, (LABEL_DESC_CODE16 + 7)
86
87 /* Initialize 32-bits code segment descriptor. */
88 xor %eax, %eax
89 mov %cs, %ax
90 shl $4, %eax
91 addl $(LABEL_SEG_CODE32), %eax
92 movw %ax, (LABEL_DESC_CODE32 + 2)
93 shr $16, %eax
94 movb %al, (LABEL_DESC_CODE32 + 4)
95 movb %ah, (LABEL_DESC_CODE32 + 7)
96
97 # initialize data segment descriptor
98 xor %eax, %eax
99 mov %ds, %ax
100 shl $4, %eax
101 addl $(LABEL_DATA), %eax
102 movw %ax, (LABEL_DESC_DATA + 2)
103 shr $16, %eax
104 movb %al, (LABEL_DESC_DATA + 4)
105 movb %ah, (LABEL_DESC_DATA + 7)
106
107 # initialize stack segment descriptor
108 xor %eax, %eax
109 mov %ds, %ax
110 shl $4, %eax
111 addl $(LABEL_STACK), %eax
112 movw %ax, (LABEL_DESC_STACK + 2)
113 shr $16, %eax
114 movb %al, (LABEL_DESC_STACK + 4)
115 movb %ah, (LABEL_DESC_STACK + 7)
116
117 /* Prepared for loading GDTR */
118 xor %eax, %eax
119 mov %ds, %ax
120 shl $4, %eax
121 add $(LABEL_GDT), %eax /* eax <- gdt base*/
122 movl %eax, (GdtPtr + 2)
123
124 /* Load GDTR(Global Descriptor Table Register) */
125 lgdtw GdtPtr
126
127 /* Clear Interrupt Flags */
128 cli
129
130 /* Open A20 line. */
131 inb $0x92, %al
132 orb $0b00000010, %al
133 outb %al, $0x92
134
135 /* Enable protect mode, PE bit of CR0. */
136 movl %cr0, %eax
137 orl $1, %eax
138 movl %eax, %cr0
139
140 /* Mixed-Size Jump. */
141 ljmp $SelectorCode32, $0 /* Thanks to earthengine@gmail, I got */
142 /* this mixed-size jump insn of gas. */
143 /* this calls far jump (ptr 16:32) in intel manual) */
144
145 LABEL_REAL_ENTRY: # 從保護模式跳回到實模式就到了這裡
146 mov %cx, %ax
147 mov %ax, %ds
148 mov %ax, %es
149 mov %ax, %ss
150
151 # mov sp, [SPValueInRealMode]
152 movw (SPValueInRealMode), %sp
153
154
155 in $0x92, %al
156 and $0b11111101, %al # close A20 line
157 out %al, $0x92
158
159 sti # 開中斷
160
161 mov $0x4c00, %ax
162 int $0x21 # 回到 DOS
163 # END of .code16
164
165 LABEL_SEG_CODE32:
166 .code32
167 call SetupPaging /* set up paging before 32-bit code */
168
169 mov $(SelectorData), %ax
170 mov %ax, %ds # 資料段選擇子
171 mov $(SelectorTest), %ax
172 mov %ax, %es # 測試段選擇子
173
174
175
176
177 mov $(SelectorVideo), %ax
178 mov %ax, %gs /* Video segment selector(dest) */
179
180 mov $(SelectorStack), %ax
181 mov %ax, %ss # 堆疊段選擇子
182
183 mov $(TopOfStack), %esp
184
185 /*
186 movl $((80 * 10 + 0) * 2), %edi
187 movb $0xC, %ah # 0000: Black Back 1100: Red Front
188 movb $'P', %al
189
190 mov %ax, %gs:(%edi)
191 */
192
193 # print string "In Protect Mode now. ^-^"
194 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
195 xor %esi, %esi
196 xor %edi, %edi
197 mov $(OffsetPMMessage), %esi # data string offset
198 movl $((80 * 10 + 0) * 2), %edi # 目的資料偏移。螢幕第 10 行, 第 0 列。
199 cld # Clear Direction Flag, ref: http://www.fermi.mn.it/linux/quarta/x86/cld.htm
200 # After CLD is executed, string operations will increment the index
201 # (SI and/or DI) that they use.
202 .1:
203 lodsb # For legacy mode, Load byte at address DS:(E)SI into AL.
204 # For 64-bit mode load byte at address (R)SI into AL.
205 # ref: http://siyobik.info/main/reference/instruction/LODS%2FLODSB%2FLODSW%2FLODSD%2FLODSQ
206 test %al, %al # result is 0, zf sets to 1.
207 jz .2 # zf = 1 jump
208 # mov [gs:edi], ax
209 mov %ax, %gs:(%edi)
210 add $2, %edi
211 jmp .1
212 .2: # 顯示完畢
213
214 #push %eax # Multiboot magic number
215 # push %ebx # Multiboot data structure
216
217 # call kmain
218 call DispReturn
219 #movb $0xa9, %al
220 #call DispAL
221
222 call TestRead
223 call TestWrite
224 call TestRead
225
226
227 ljmpl $SelectorCode16,$0
228 # jmpl $SelectorCode16,$0 # it works
229
230 # ------------------------------------------------------------------------
231 SetupPaging:
232 /* Directly map linear addresses to physical addresses for simplification */
233 /* Init page directory, %ecx entries. */
234 mov $(SELECTOR_PAGE_DIR), %ax
235 mov %ax, %es
236 mov $1024, %ecx /* Loop counter, num of page tables: 1024 */
237 xor %edi, %edi
238 xor %eax, %eax
239 /* Set PDE attributes(flags): P: 1, U/S: 1, R/W: 1. */
240 mov $(PAGE_TBL_BASE | PG_P | PG_USU | PG_RWW), %eax
241 SP.1:
242 stosl /* Store %eax to %es:%edi consecutively. */
243 add $4096, %eax /* Page tables are in sequential format. */
244 loop SP.1 /* %ecx loops. */
245
246 /* Init page tables, %ecx pages. */
247 mov $(SELECTOR_PAGE_TBL), %ax
248 mov %ax, %es
249 mov $(1024*1024), %ecx /* Loop counter, num of pages: 1024^2. */
250 xor %edi, %edi
251 /* Set PTE attributes(flags): P:1, U/S: 1, R/W: 1. */
252 mov $(PG_P | PG_USU | PG_RWW), %eax
253 SP.2:
254 stosl /* Store %eax to %es:%edi consecutively. */
255 add $4096, %eax /* Pages are in sequential format. */
256 loop SP.2 /* %ecx loops. */
257
258 mov $(PAGE_DIR_BASE), %eax
259 mov %eax, %cr3 /* Store base address of page table dir to %cr3. */
260 mov %cr0, %eax
261 or $0x80000000, %eax
262 mov %eax, %cr0 /* Enable paging bit in %cr0. */
263 ret
264 # end SetupPaging:
265
266 TestRead:
267 xor %esi, %esi
268 mov $8, %ecx
269 .loop:
270 mov %es:(%esi), %al
271 call DispAL
272 inc %esi
273 loop .loop
274 call DispReturn
275
276 ret
277 # TestRead 結束-----------------------------------------------------------
278
279
280 # ------------------------------------------------------------------------
281 TestWrite:
282 pushl %esi
283 pushl %edi
284 xor %esi, %esi
285 xor %edi, %edi
286 mov $(OffsetStrTest), %esi # data offset
287 cld # Clear Direction Flag, ref: http://www.fermi.mn.it/linux/quarta/x86/cld.htm
288 # After CLD is executed, string operations will increment the index
289 # (SI and/or DI) that they use.
290 .6:
291 lodsb # For legacy mode, Load byte at address DS:(E)SI into AL.
292 # For 64-bit mode load byte at address (R)SI into AL.
293 # ref: http://siyobik.info/main/reference/instruction/LODS%2FLODSB%2FLODSW%2FLODSD%2FLODSQ
294
295 test %al, %al
296 jz .5 # zf = 1 jump
297 # mov [es:edi], al
298 mov %al, %es:(%edi)
299 inc %edi
300 jmp .6
301 .5:
302
303 popl %edi
304 popl %esi
305 ret
306 # TestWrite 結束----------------------------------------------------------
307
308
309 # ------------------------------------------------------------------------
310 # 顯示 AL 中的數字
311 # 默認地:
312 # 數字已經存在 AL 中
313 # edi 始終指向要顯示的下一個字元的位置
314 # 被改變的暫存器:
315 # ax, edi
316 # ------------------------------------------------------------------------
317 DispAL:
318 pushl %ecx
319 pushl %edx
320
321 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
322 movb %al, %dl
323 shr $4, %al
324 movl $2, %ecx
325 .begin:
326 andb $0x0f, %al
327 cmp $9, %al
328 ja .3 # cf=0, zf=0, above 9 (>9)
329 #addb $'0', %al
330 addb $0x30, %al
331 jmp .4
332 .3:
333 sub $0x0A, %al
334 #add $'A', %al
335 add $0x41, %al
336 .4:
337 #mov [gs:edi], ax
338 mov %ax, %gs:(%edi)
339 add $2, %edi
340
341 mov %dl, %al
342 loop .begin
343 add $2, %edi
344
345 popl %edx
346 popl %ecx
347
348 ret
349 # DispAL 結束-------------------------------------------------------------
350
351
352 # ------------------------------------------------------------------------
353 DispReturn:
354 pushl %eax
355 pushl %ebx
356 mov %edi, %eax
357 movb $160, %bl
358 divb %bl # %eax/160, 商 al, 餘數 ah.
359 and $0x0FF, %eax
360 inc %eax # ++ %eax
361 mov $160, %bl
362 mul %bl
363 mov %eax, %edi
364 popl %ebx
365 popl %eax
366 ret
367 # DispReturn 結束---------------------------------------------------------
368
369 /*
370 kmain:
371 pushl %ebp
372 movl %esp, %ebp
373 popl %ebp
374 ret
375 .size kmain, .-kmain
376 .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
377 */
378 # .section .note.GNU-stack,"",@progbits
379
380
381 /* Get the length of 32-bit segment code. */
382 .set SegCode32Len, . - LABEL_SEG_CODE32
383
384 #[SECTION .data1] ; 資料段
385 #ALIGN 32
386 #[BITS 32]
387 LABEL_DATA:
388 SPValueInRealMode: .2byte 0x0
389 # string
390 PMMessage: .ascii "In Protect Mode now. ^-^\0" # 在保護模式中顯示
391 .set OffsetPMMessage, (PMMessage - LABEL_DATA)
392 #StrTest: .ascii "B\0"
393 StrTest: .ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0"
394 #OffsetStrTest equ StrTest - $$
395 .set OffsetStrTest , (StrTest - LABEL_DATA)
396 #DataLen equ $ - LABEL_DATA
397 .set DataLen, . - LABEL_DATA
398 /* 32-bit global stack segment. */
399 LABEL_STACK:
400 .space 512, 0
401 .set TopOfStack, (. - LABEL_STACK - 1)
402
403 # END of [SECTION .data1]
404
405
406 LABEL_SEG_CODE16:
407 .code16
408 #jmp .
409 # back to real mode
410 mov $SelectorNormal, %ax
411 mov %ax, %ds
412 mov %ax, %es
413 mov %ax, %fs
414 mov %ax, %gs
415 mov %ax, %ss
416
417 mov %cr0, %eax
418 and $0b11111110, %al
419 mov %eax, %cr0
420
421
422 LABEL_GO_BACK_TO_REAL:
423 #.2byte 0xea66
424 #.4byte 0x00000000
425 #.2byte LABEL_REAL_ENTRY
426 jmp $0, $LABEL_REAL_ENTRY # 段位址會在程序開始處被設置成正確的值
427
428
429 .set Code16Len, . - LABEL_SEG_CODE16
430
431
432

沒有留言:

張貼留言

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

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