2012年1月1日 星期日

x86: from ring0 to ring3, then enter to ring0

終於來到這裡了, 從 ring0 -> ring3 -> ring0, 藉由 call gate 的使用, 慢慢的將權限切換完成了。補上杨文博沒有的部份, 這段程式碼依照于渊的版本, 最後會切回 dos/real mode, 並回到 dos prompt。

學習心得, 有三步驟:
  1. 單純的使用 call gate ,
  2. 切換到 ring3,
  3. 使用步驟一的 call gate 切回到 ring0

後面的每一步都會使用前面的程式碼。若要切回 dos/real mode, 還需要使用 ldt, 這算是第零步驟吧!照例, 程式碼的解釋就請參考杨文博的電子書。

289 mov $(SELECT_TSS), %ax /* Load TSS to TR register */
290 ltr %ax

ltr 指令用來載入一個 segment selector (指到一個 TSS)。ring3 -> ring0 時, 需要用到這個資料結構。

cg_r3_to_r0.S
1 /*
2 ref: Orange'S:一个操作系统的实现
3 practice enter to ring3.
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 /*
16 * call gate: r3 -> r0
17 */
18
19 #include "pm.h"
20
21 #define video_addr_offset (video_addr-LABEL_DATA)
22
23 .code16
24 .text
25 jmp LABEL_BEGIN /* jump over the .data section. */
26
27 /* NOTE! Wenbo-20080512: Actually here we put the normal .data section into
28 the .code section. For application SW, it is not allowed. However, we are
29 writing an OS. That is OK. Because there is no OS to complain about
30 that behavior. :) */
31
32 /* Global Descriptor Table */
33 LABEL_GDT: Descriptor 0, 0, 0
34 LABEL_DESC_NORMAL: Descriptor 0, 0xffff, DA_DRW # Normal descriptor is for back to real mode.
35 LABEL_DESC_CODE32: Descriptor 0, (SegCode32Len - 1), (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_LDT: Descriptor 0, (LDT_LEN-1), DA_LDT
41 LABEL_DESC_VIDEO: Descriptor 0xB8000, 0xffff, (DA_DRW+DA_DPL3)
42 LABEL_DESC_CODECG: Descriptor 0, (SEG_CODE_CG_LEN - 1), (DA_C + DA_32)
43 LABEL_DESC_CODER3: Descriptor 0, (SEG_CODER3_LEN - 1), (DA_C + DA_32 + DA_DPL3)
44 LABEL_DESC_STACKR3: Descriptor 0, (TopOfStackR3 - 1), (DA_DRWA + DA_32 + DA_DPL3)
45 LABEL_DESC_TSS: Descriptor 0, (TSS_LEN - 1), DA_386TSS
46
47 # Gates Descriptor
48 #LABEL_CG_TEST: Gate SELECT_CODE_CG, 0, 0xffff, (DA_386CGate + DA_DPL0)
49 LABEL_CG_TEST: Gate SELECT_CODE_CG, 0, 0xffff, (DA_386CGate + DA_DPL3)
50
51 .set GdtLen, (. - LABEL_GDT) /* GDT Length */
52
53 GdtPtr: .2byte (GdtLen - 1) /* GDT Limit */
54 .4byte 0 /* GDT Base */
55
56 /* GDT Selector */
57 .set SelectorNormal, (LABEL_DESC_NORMAL - LABEL_GDT)
58 .set SelectorCode32, (LABEL_DESC_CODE32 - LABEL_GDT)
59 .set SelectorCode16, (LABEL_DESC_CODE16 - LABEL_GDT)
60 .set SelectorData, (LABEL_DESC_DATA - LABEL_GDT)
61 .set SelectorStack, (LABEL_DESC_STACK - LABEL_GDT)
62 .set SelectorTest, (LABEL_DESC_TEST - LABEL_GDT)
63 .set SelectorLDT, (LABEL_DESC_LDT - LABEL_GDT)
64 .set SelectorVideo, (LABEL_DESC_VIDEO - LABEL_GDT)
65 .set SELECT_CODE_CG, (LABEL_DESC_CODECG - LABEL_GDT)
66 .set SELECT_CODER3, (LABEL_DESC_CODER3 - LABEL_GDT + SA_RPL3)
67 .set SELECT_STACKR3, (LABEL_DESC_STACKR3 - LABEL_GDT + SA_RPL3)
68 .set SELECT_CG_TEST, (LABEL_CG_TEST - LABEL_GDT + SA_RPL3)
69 .set SELECT_TSS, (LABEL_DESC_TSS - LABEL_GDT)
70
71 # LDT
72
73 LABEL_LDT:
74 LABEL_LDT_DESC_CODEA: Descriptor 0, (CodeALen - 1), (DA_C + DA_32) # Code, 32 位
75 .set LDT_LEN, (. - LABEL_LDT) /* LDT Length */
76
77 /* LDT Selector (TI flag set)*/
78 .set SelectorLDTCodeA, (LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL)
79
80
81 /* Program starts here. */
82 LABEL_BEGIN:
83 mov %cs, %ax /* Move code segment address(CS) to data segment */
84 mov %ax, %ds /* register(DS), ES and SS. Because we have */
85 mov %ax, %es /* embedded .data section into .code section in */
86 mov %ax, %ss /* the start(mentioned in the NOTE above). */
87
88 movw $0x100, %sp
89 nop
90 movw %ax, (LABEL_GO_BACK_TO_REAL+3) # modify segment value, indexed memory mode, ref professional aeesmbly language p 102.
91 mov $(SPValueInRealMode), %sp
92
93 /* Initialize 16-bits code segment descriptor. */
94 xor %eax, %eax
95 mov %cs, %ax
96 shl $4, %eax
97 addl $(LABEL_SEG_CODE16), %eax
98 movw %ax, (LABEL_DESC_CODE16 + 2)
99 shr $16, %eax
100 movb %al, (LABEL_DESC_CODE16 + 4)
101 movb %ah, (LABEL_DESC_CODE16 + 7)
102
103 /* Initialize 32-bits code segment descriptor. */
104 xor %eax, %eax
105 mov %cs, %ax
106 shl $4, %eax
107 addl $(LABEL_SEG_CODE32), %eax
108 movw %ax, (LABEL_DESC_CODE32 + 2)
109 shr $16, %eax
110 movb %al, (LABEL_DESC_CODE32 + 4)
111 movb %ah, (LABEL_DESC_CODE32 + 7)
112
113
114 # Initialize CODER3 descriptor
115 xor %eax, %eax
116 mov %cs, %ax
117 shl $4, %eax
118 addl $(LABEL_SEG_CODER3), %eax
119 movw %ax, (LABEL_DESC_CODER3 + 2)
120 shr $16, %eax
121 movb %al, (LABEL_DESC_CODER3 + 4)
122 movb %ah, (LABEL_DESC_CODER3 + 7)
123
124 # Initialize STACK R3 descriptor
125 xor %eax, %eax
126 mov %cs, %ax
127 shl $4, %eax
128 addl $(LABEL_STACKR3), %eax
129 movw %ax, (LABEL_DESC_STACKR3 + 2)
130 shr $16, %eax
131 movb %al, (LABEL_DESC_STACKR3 + 4)
132 movb %ah, (LABEL_DESC_STACKR3 + 7)
133
134
135 /* Initialize call gate code segment descriptor. */
136 xor %eax, %eax
137 mov %cs, %ax
138 shl $4, %eax
139 addl $(LABEL_CODE_CG), %eax
140 movw %ax, (LABEL_DESC_CODECG + 2)
141 shr $16, %eax
142 movb %al, (LABEL_DESC_CODECG + 4)
143 movb %ah, (LABEL_DESC_CODECG + 7)
144
145 # initialize data segment descriptor
146 xor %eax, %eax
147 mov %ds, %ax
148 shl $4, %eax
149 addl $(LABEL_DATA), %eax
150 movw %ax, (LABEL_DESC_DATA + 2)
151 shr $16, %eax
152 movb %al, (LABEL_DESC_DATA + 4)
153 movb %ah, (LABEL_DESC_DATA + 7)
154
155 # initialize stack segment descriptor
156 xor %eax, %eax
157 mov %ds, %ax
158 shl $4, %eax
159 addl $(LABEL_STACK), %eax
160 movw %ax, (LABEL_DESC_STACK + 2)
161 shr $16, %eax
162 movb %al, (LABEL_DESC_STACK + 4)
163 movb %ah, (LABEL_DESC_STACK + 7)
164
165 /* Initialize TSS GDT. */
166 xor %eax, %eax
167 mov %ds, %ax
168 shl $4, %eax
169 addl $(LABEL_TSS), %eax
170 movw %ax, (LABEL_DESC_TSS + 2)
171 shr $16, %eax
172 movb %al, (LABEL_DESC_TSS + 4)
173 movb %ah, (LABEL_DESC_TSS + 7)
174
175 /* Initialize LDT descriptor in GDT. */
176 xor %eax, %eax
177 mov %ds, %ax
178 shl $4, %eax
179 addl $(LABEL_LDT), %eax
180 movw %ax, (LABEL_DESC_LDT + 2)
181 shr $16, %eax
182 movb %al, (LABEL_DESC_LDT + 4)
183 movb %ah, (LABEL_DESC_LDT + 7)
184
185 /* Initialize code A descriptor in LDT. */
186 xor %eax, %eax
187 mov %ds, %ax
188 shl $4, %eax
189 addl $(LABEL_CODE_A), %eax
190 movw %ax, (LABEL_LDT_DESC_CODEA + 2)
191 shr $16, %eax
192 movb %al, (LABEL_LDT_DESC_CODEA + 4)
193 movb %ah, (LABEL_LDT_DESC_CODEA + 7)
194
195
196 /* Prepared for loading GDTR */
197 xor %eax, %eax
198 mov %ds, %ax
199 shl $4, %eax
200 add $(LABEL_GDT), %eax /* eax <- gdt base*/
201 movl %eax, (GdtPtr + 2)
202
203 /* Load GDTR(Global Descriptor Table Register) */
204 lgdtw GdtPtr
205
206 /* Clear Interrupt Flags */
207 cli
208
209 /* Open A20 line. */
210 inb $0x92, %al
211 orb $0b00000010, %al
212 outb %al, $0x92
213
214 /* Enable protect mode, PE bit of CR0. */
215 movl %cr0, %eax
216 orl $1, %eax
217 movl %eax, %cr0
218
219 /* Mixed-Size Jump. */
220 ljmp $SelectorCode32, $0 /* Thanks to earthengine@gmail, I got */
221 /* this mixed-size jump insn of gas. */
222 /* this calls far jump (ptr 16:32) in intel manual) */
223
224 LABEL_REAL_ENTRY: # 從保護模式跳回到實模式就到了這裡
225 mov %cx, %ax
226 mov %ax, %ds
227 mov %ax, %es
228 mov %ax, %ss
229
230
231 in $0x92, %al
232 and $0b11111101, %al # close A20 line
233 out %al, $0x92
234
235 sti # 開中斷
236
237 mov $0x4c00, %ax
238 int $0x21 # 回到 DOS
239 # END of .code16
240
241 LABEL_SEG_CODE32:
242 .code32
243
244 mov $(SelectorData), %ax
245 mov %ax, %ds # 資料段選擇子
246 mov $(SelectorTest), %ax
247 mov %ax, %es # 測試段選擇子
248
249
250
251
252 mov $(SelectorVideo), %ax
253 mov %ax, %gs /* Video segment selector(dest) */
254
255 mov $(SelectorStack), %ax
256 mov %ax, %ss # 堆疊段選擇子
257
258 mov $(TopOfStack), %esp
259
260 /*
261 movl $((80 * 10 + 0) * 2), %edi
262 movb $0xC, %ah # 0000: Black Back 1100: Red Front
263 movb $'P', %al
264
265 mov %ax, %gs:(%edi)
266 */
267
268 # print string "In Protect Mode now. ^-^"
269 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
270 xor %esi, %esi
271 xor %edi, %edi
272 mov $(OffsetPMMessage), %esi # data string offset
273 movl $((80 * 10 + 0) * 2), %edi # 目的資料偏移。螢幕第 10 行, 第 0 列。
274 cld # Clear Direction Flag, ref: http://www.fermi.mn.it/linux/quarta/x86/cld.htm
275 # After CLD is executed, string operations will increment the index
276 # (SI and/or DI) that they use.
277 .1:
278 lodsb # For legacy mode, Load byte at address DS:(E)SI into AL.
279 # For 64-bit mode load byte at address (R)SI into AL.
280 # ref: http://siyobik.info/main/reference/instruction/LODS%2FLODSB%2FLODSW%2FLODSD%2FLODSQ
281 test %al, %al # result is 0, zf sets to 1.
282 jz .2 # zf = 1 jump
283 # mov [gs:edi], ax
284 mov %ax, %gs:(%edi)
285 add $2, %edi
286 jmp .1
287 .2: # 顯示完畢
288
289 mov $(SELECT_TSS), %ax /* Load TSS to TR register */
290 ltr %ax
291
292 pushl $(SELECT_STACKR3)
293 pushl $(TopOfStackR3)
294 pushl $(SELECT_CODER3)
295 pushl $0
296 lret
297
298 # call gate test
299 #lcall $(SELECT_CG_TEST), $0
300
301 # the call gate setting selector
302 #lcall $(SELECT_CODE_CG), $0
303
304 # mov $(SelectorLDT), %ax
305 # lldt %ax
306 # jmp $(SelectorLDTCodeA), $0
307
308
309 /*
310 movl $0, (video_addr_offset)
311 movb $0xb8, %al
312 call DispAL_m
313
314 movl $(80*(3-1)*2 + (2-1)*2), (video_addr_offset)
315 movb $0xc7, %al
316 call DispAL_m
317
318 #call DispReturn
319 movl $160, (video_addr_offset)
320 call DispReturn
321 movb $0xa9, %al
322 call DispAL
323 call DispReturn
324 movw $0xabcd, %ax
325 call DispAX
326 call DispReturn
327 movl (video_addr_offset), %ax
328 call DispAX
329 call DispReturn
330
331 addl $2, (video_addr_offset)
332 movl (video_addr_offset), %ax
333 call DispAX
334
335 call TestRead
336 call TestWrite
337 call TestRead
338 */
339
340 # ljmpl $SelectorCode16,$0
341 # jmpl $SelectorCode16,$0 # it works
342
343
344
345 # ------------------------------------------------------------------------
346 TestRead:
347 xor %esi, %esi
348 mov $8, %ecx
349 .loop:
350 mov %es:(%esi), %al
351 call DispAL
352 inc %esi
353 loop .loop
354 call DispReturn
355
356 ret
357 # TestRead 結束-----------------------------------------------------------
358
359
360 # ------------------------------------------------------------------------
361 TestWrite:
362 pushl %esi
363 pushl %edi
364 xor %esi, %esi
365 xor %edi, %edi
366 mov $(OffsetStrTest), %esi # data offset
367 cld # Clear Direction Flag, ref: http://www.fermi.mn.it/linux/quarta/x86/cld.htm
368 # After CLD is executed, string operations will increment the index
369 # (SI and/or DI) that they use.
370 .6:
371 lodsb # For legacy mode, Load byte at address DS:(E)SI into AL.
372 # For 64-bit mode load byte at address (R)SI into AL.
373 # ref: http://siyobik.info/main/reference/instruction/LODS%2FLODSB%2FLODSW%2FLODSD%2FLODSQ
374
375 test %al, %al
376 jz .5 # zf = 1 jump
377 # mov [es:edi], al
378 mov %al, %es:(%edi)
379 inc %edi
380 jmp .6
381 .5:
382
383 popl %edi
384 popl %esi
385 ret
386 # TestWrite 結束----------------------------------------------------------
387
388 DispAX:
389 pushl %ebx
390 pushl %ecx
391 pushl %edx
392
393 movw %ax, %dx
394 shr $8, %ax # ah -> al
395 movl $2, %ecx
396 .b:
397 call DispAL_m
398 movw %dx, %ax
399 addl $4, (video_addr_offset)
400 # call DispAL_m
401 # andw 0xff, %ax
402 loop .b
403
404 popl %edx
405 popl %ecx
406 popl %ebx
407
408 ret
409 # end DispAX
410
411 # ------------------------------------------------------------------------
412 # 顯示 AL 中的數字
413 # 默認地:
414 # 數字已經存在 AL 中
415 # edi 始終指向要顯示的下一個字元的位置
416 # 被改變的暫存器:
417 # ax, edi
418 # ------------------------------------------------------------------------
419 DispAL:
420 pushl %ecx
421 pushl %edx
422
423 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
424 movb %al, %dl
425 shr $4, %al
426 movl $2, %ecx
427 .begin:
428 andb $0x0f, %al
429 cmp $9, %al
430 ja .3 # cf=0, zf=0, above 9 (>9)
431 #addb $'0', %al
432 addb $0x30, %al
433 jmp .4
434 .3:
435 sub $0x0A, %al
436 #add $'A', %al
437 add $0x41, %al
438 .4:
439 #mov [gs:edi], ax
440 mov %ax, %gs:(%edi)
441 # mov %ax, %gs:(video_addr_offset)
442 #mov %ax, %gs:(0)
443 add $2, %edi
444
445 # addl $2, (video_addr_offset)
446
447 mov %dl, %al
448 loop .begin
449 add $2, %edi
450 #add $2, (video_addr_offset)
451
452 popl %edx
453 popl %ecx
454
455 ret
456 # DispAL 結束-------------------------------------------------------------
457
458 DispAL_m:
459 pushl %ebx
460 pushl %ecx
461 pushl %edx
462
463 movl (video_addr_offset), %ebx
464 movb $0x0c, %ah # 0000: 黑底 1100: 紅字
465 movb %al, %dl
466 shr $4, %al
467 movl $2, %ecx
468 .begin_1:
469 andb $0x0f, %al
470 cmp $9, %al
471 ja .31 # cf=0, zf=0, above 9 (>9)
472 #addb $'0', %al
473 addb $0x30, %al
474 jmp .41
475 .31:
476 sub $0x0A, %al
477 #add $'A', %al
478 add $0x41, %al
479 .41:
480 #mov [gs:edi], ax
481 #mov %ax, %gs:(%edi)
482 #if 0
483 movw (video_addr_offset), %ax
484 call DispReturn
485 call DispAX
486 #endif
487 movw %ax, %gs:(%ebx)
488 #mov %ax, %gs:(0)
489 add $2, %ebx
490
491 mov %dl, %al
492 loop .begin_1
493 addl $2, %ebx
494
495 popl %edx
496 popl %ecx
497 popl %ebx
498
499 ret
500 # DispAL_m 結束-------------------------------------------------------------
501
502
503 # ------------------------------------------------------------------------
504 DispReturn:
505 pushl %eax
506 pushl %ebx
507 mov %edi, %eax
508 movb $160, %bl
509 divb %bl # %eax/160, 商 al, 餘數 ah.
510 and $0x0FF, %eax
511 inc %eax # ++ %eax
512 mov $160, %bl
513 mul %bl
514 mov %eax, %edi
515 popl %ebx
516 popl %eax
517 ret
518 # DispReturn 結束---------------------------------------------------------
519
520 LABEL_STACKR3:
521 .space 512, 0
522 .set TopOfStackR3, . - LABEL_STACKR3
523
524 LABEL_TSS:
525 .4byte 0 /* Back Link */
526 .4byte TopOfStack /* ESP0 */
527 .4byte SelectorStack /* SS0 */
528 .4byte 0 /* ESP1 */
529 .4byte 0 /* SS1 */
530 .4byte 0 /* ESP2 */
531 .4byte 0 /* SS2 */
532 .4byte 0 /* CR3(PDBR) */
533 .4byte 0 /* EIP */
534 .4byte 0 /* EFLAGS */
535 .4byte 0 /* EAX */
536 .4byte 0 /* ECX */
537 .4byte 0 /* EDX */
538 .4byte 0 /* EBX */
539 .4byte 0 /* ESP */
540 .4byte 0 /* EBP */
541 .4byte 0 /* ESI */
542 .4byte 0 /* EDI */
543 .4byte 0 /* ES */
544 .4byte 0 /* CS */
545 .4byte 0 /* SS */
546 .4byte 0 /* DS */
547 .4byte 0 /* FS */
548 .4byte 0 /* GS */
549 .4byte 0 /* LDT Segment Selector */
550 .2byte 0 /* Trap Flag: 1-bit */
551 .2byte (. - LABEL_TSS + 2) /* I/O Map Base Address */
552 .byte 0xff /* End */
553 .set TSS_LEN, (. - LABEL_TSS)
554
555 # ring 3 code
556 LABEL_SEG_CODER3:
557 mov $(SelectorVideo), %ax
558 mov %ax, %gs
559 movl $((80*11+1) *2 ), %edi
560 movb $0xC, %ah
561 movb $'3', %al
562 mov %ax, %gs:(%edi)
563
564 # call gate test
565 lcall $(SELECT_CG_TEST), $0
566
567 jmp .
568 .set SEG_CODER3_LEN, . - LABEL_SEG_CODER3
569
570 # test call gate
571 LABEL_CODE_CG:
572 mov $(SelectorVideo), %ax
573 mov %ax, %gs
574 movl $((80*11+0) *2 ), %edi
575 movb $0xC, %ah
576 movb $'C', %al
577
578 mov %ax, %gs:(%edi)
579
580
581 mov $(SelectorLDT), %ax
582 lldt %ax
583 jmp $(SelectorLDTCodeA), $0
584
585 #lret # long return command
586 .set SEG_CODE_CG_LEN, . - LABEL_CODE_CG
587 LABEL_CODE_A:
588 #if 0
589 # intel syntax
590 mov ax, SelectorVideo
591 mov gs, ax ; 視頻段選擇子(目的)
592
593 mov edi, (80 * 12 + 0) * 2 ; 螢幕第 10 行, 第 0 列。
594 mov ah, 0Ch ; 0000: 黑底 1100: 紅字
595 mov al, 'L'
596 mov [gs:edi], ax
597 #else
598 # at&t syntax
599 #if 1
600 mov $(SelectorVideo), %ax
601 mov %ax, %gs
602 mov $((80 * 12 + 0) * 2), %edi
603 mov $0x0c, %ah
604 mov $'L', %al
605 mov %ax, %gs:(%edi)
606 #else
607 /* can call DispAL function */
608 movb $0xef, %al
609 call DispAL
610 #endif
611 /* jump to real mode code16 and return to dos. */
612 ljmpl $SelectorCode16,$0
613
614 #endif
615 .set CodeALen, (. - LABEL_CODE_A)
616
617 /*
618 kmain:
619 pushl %ebp
620 movl %esp, %ebp
621 popl %ebp
622 ret
623 .size kmain, .-kmain
624 .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
625 */
626 # .section .note.GNU-stack,"",@progbits
627
628
629 /* Get the length of 32-bit segment code. */
630 .set SegCode32Len, . - LABEL_SEG_CODE32
631
632 #[SECTION .data1] ; 資料段
633 #ALIGN 32
634 #[BITS 32]
635 LABEL_DATA:
636 SPValueInRealMode: .2byte 0x0
637 # string
638 PMMessage: .ascii "In Protect Mode now. ^-^\0" # 在保護模式中顯示
639 .set OffsetPMMessage, (PMMessage - LABEL_DATA)
640 #StrTest: .ascii "B\0"
641 StrTest: .ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0"
642 #OffsetStrTest equ StrTest - $$
643 .set OffsetStrTest , (StrTest - LABEL_DATA)
644 #DataLen equ $ - LABEL_DATA
645 video_addr: .int 0
646 .set DataLen, . - LABEL_DATA
647 /* 32-bit global stack segment. */
648 LABEL_STACK:
649 .space 512, 0
650 .set TopOfStack, (. - LABEL_STACK - 1)
651
652 # END of [SECTION .data1]
653
654
655 LABEL_SEG_CODE16:
656 .code16
657 #jmp .
658 # back to real mode
659 mov $SelectorNormal, %ax
660 mov %ax, %ds
661 mov %ax, %es
662 mov %ax, %fs
663 mov %ax, %gs
664 mov %ax, %ss
665
666 mov %cr0, %eax
667 and $0b11111110, %al
668 mov %eax, %cr0
669
670
671 LABEL_GO_BACK_TO_REAL:
672 #.2byte 0xea66
673 #.4byte 0x00000000
674 #.2byte LABEL_REAL_ENTRY
675 jmp $0, $LABEL_REAL_ENTRY # 段位址會在程序開始處被設置成正確的值
676
677
678 .set Code16Len, . - LABEL_SEG_CODE16
679
680

沒有留言:

張貼留言

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

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