2011年11月3日 星期四

c run time environment in x86 protected mode (2)

不知道要怎麼命名, 總之是一個 function 呼叫問題。

void p_t(u8 *ch)

傳入一個 pointer, 將第一個 char 改成 'X'。 然後用 write_mem8 印到螢幕上。

預期的結果應該是 ch[0]=X, 在螢幕上印出 X, 不過在一開始測試的時候印出的卻是 ch 的初使值 a。哪裡搞錯了呢?




k.c
1 typedef char byte;
2 typedef unsigned char u8;
3 typedef unsigned short int u16;
4 typedef unsigned int u32;
5
6 void write_mem8(u32 addr, u8 data); // assembly function.
7
8 #define BASE 160*6
9
10 #define TEST_FUNC
11
12 static const u8 str[]="I am c function";
13
14 void p_t(u8 *ch)
15 {
16 ch[0]='X';
17 }
18
19 void kmain(void)
20 {
21
22 // normal test
23 #if 0
24 int i=0;
25
26 for (i=0 ; str[i]!=0 ; ++i)
27 write_mem8(BASE+i*2, str[i]);
28 #endif
29
30 #ifdef TEST_FUNC
31 u8 ch[2]={'a','b'}; // 97, 98
32
33 //hex2char(0x9c, ch);
34 p_t(ch);
35 //write_mem8(BASE, ch[1]);
36 write_mem8(BASE+2, ch[0]);
37
38 #endif
39
40 #ifdef C_ACCESS_POINTER
41 u8 *vaddr=(u8 *)(0xb8000+160);
42
43 *vaddr='E';
44 #endif
45 }

k.s 是用 gcc -Wall -Wextra -Werror -nostdlib -nostartfiles -nodefaultlibs -c k.c 產生的。注意 19.5 和 19 行。19.5 的 %ss: 是我加上的, 強制使用 %ss 當 segment register, 預設應該是使用 %ds 來當作 segment register。由於 k.c 31 行的 ch[2] 是在 stack 建立, 並不是在 %ds 指到的那塊記憶體 segment (我讓 %ds 指到的記憶體 segment 和 %ss 指到的記憶體 segment 不是同一塊)。所以加上 %ss: 強迫程式使用 %ss 來定址。這樣就沒問題了。



k.s
1 .file "k.c"
2 .section .rodata
3 .type str, @object
4 .size str, 16
5 str:
6 .string "I am c function"
7 .text
8 .globl p_t
9 .type p_t, @function
10 p_t:
11 .LFB0:
12 .cfi_startproc
13 pushl %ebp
14 .cfi_def_cfa_offset 8
15 .cfi_offset 5, -8
16 movl %esp, %ebp
17 .cfi_def_cfa_register 5
18 movl 8(%ebp), %eax
19 movb $88, (%eax)
19.5 movb $88, %ss:(%eax)
20 popl %ebp
21 .cfi_def_cfa 4, 4
22 .cfi_restore 5
23 ret
24 .cfi_endproc
25 .LFE0:
26 .size p_t, .-p_t
27 .globl kmain
28 .type kmain, @function
29 kmain:
30 .LFB1:
31 .cfi_startproc
32 pushl %ebp
33 .cfi_def_cfa_offset 8
34 .cfi_offset 5, -8
35 movl %esp, %ebp
36 .cfi_def_cfa_register 5
37 subl $40, %esp
38 movb $97, -10(%ebp)
39 movb $98, -9(%ebp)
40 leal -10(%ebp), %eax
41 movl %eax, (%esp)
42 call p_t
43 movzbl -10(%ebp), %eax
44 movzbl %al, %eax
45 movl %eax, 4(%esp)
46 movl $962, (%esp)
47 call write_mem8
48 leave
49 .cfi_restore 5
50 .cfi_def_cfa 4, 4
51 ret
52 .cfi_endproc
53 .LFE1:
54 .size kmain, .-kmain
55 .ident "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
56 .section .note.GNU-stack,"",@progbits
57


那有沒辦法不要修改 k.s 就能得到相同結果呢?

5M_mem_rw_mix_c.S 第 18 行的 macro 會決定 %ss 和 %ds 是不是要指到相同的 segment, 若指到相同的 segment, 那上面的 C 程式就會印出正確的結果。

設定 c runtime 環境沒想像中那麼簡單吧!

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

沒有留言:

張貼留言

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

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