2013年3月15日 星期五

x86 process switch implementation (1) - save %ax

前面那一個版本只差了一些小地方:

49 .global proc_a
50 proc_a:
51 1:
52   mov $0x1, %ax
53   int $0x30
54   jmp 1b
55 
56 .global proc_b
57 proc_b:
58 1:
59   mov $0x2, %al
60   int $0x30
61   jmp 1b

proc_a, proc_b 會同時使用 %ax, 所以在切換這兩個 process 時, %ax 需要 save/restore, 總不能切回 proc_a 時, %ax 變成 2, 這就不對了。要怎麼做呢?process switch 的重點也在於此。

87 stack_frame_a:
88   .word 0x9# ax
89   .word 0x0# eip
90   .word 0x1# cs
91   .word 0x2# flag
92 
93 stack_frame_b:
94   .word 0x9# ax
95   .word 0x0# eip
96   .word 0x1# cs
97   .word 0x2# flag

在 stack frame 上用一個欄位來保存 %ax, 在 int 0x30 切換 process 時, 保存和回復這個 %ax 即可。聽起來很簡單, 但一開始我可是花了一星期才搞懂 (希望大家不要像我一樣, 花這麼多的時間)。L65, L75 就是用來做這件事情。

這一樣要使用 bochs 內建 debugger 來跑過一次才能有所體會, 並且將相關暫存器, 記憶體內容 dump 出來, 程式體驗有時候甚至比理解觀念還重要。我只能解釋到這裡, 其他就得靠讀者們自己跑程式碼。不過還是希望不要讓大家誤會 process switch 是如此簡單, 一樣是省略很多不太容易說明的細節 (ex: stack 的保存與回復) 才想到的解釋方式。會 save/restore %ax 之後, 當然其他的 register 應該也沒問題, 依樣畫葫蘆即可。

這系列的目的不是說明 process switch 的實作, 只是希望能幫助有興趣的同好在看相關的程式碼時, 能容易看些。

simple_proc.S
 1 #define STACK_FRAME_OFFSET 6
 2 .code16
 3 .text
 4 .global begin
 5 begin:
 6   xchg %bx, %bx #bochs magic break point
 7   cli
 8 
 9   xor     %eax, %eax
10   mov     %cs,%ax
11   mov     %ax,%ds
12 
13 ## reset 0x30 interrupt
14   movw    $0x0, %bx
15   movw    %bx, %es
16   movw $switch_proc, %es:0xc0 # isr offset
17   movw %ax, %es:0xc2 #isr seg
18 
19 
20   movw    $0xb800, %ax
21   movw    %ax, %gs
22 
23 ## set stack frame eip
24   movw $proc_a, stack_frame_a+2
25   movw $proc_b, stack_frame_b+2
26 
27 ## set stack frame cs
28   movw %cs, %ax
29   movw %ax, stack_frame_a+4
30   movw %ax, stack_frame_b+4
31 
32 ## set stack frame flag
33   # get flag
34   pushf
35   movw (%esp), %ax
36   popf
37   movw %ax, stack_frame_a+6
38   movw %ax, stack_frame_b+6
39 
40   movw $stack_frame_a, cur_proc
41   movw cur_proc, %sp
42   popw %ax
43   iret
44 
45   mov $0x4c00, %ax
46   int $0x21           
47 
48 
49 .global proc_a
50 proc_a:
51 1:
52   mov $0x1, %ax
53   int $0x30
54   jmp 1b
55 
56 .global proc_b
57 proc_b:
58 1:
59   mov $0x2, %al
60   int $0x30
61   jmp 1b
62 
63 .global switch_proc
64 switch_proc:
65   pushw %ax
66   movw cur_proc, %dx
67   cmp $stack_frame_a, %dx
68   je 1f
69   movw $stack_frame_a, cur_proc
70   jmp 2f
71 1:
72   movw $stack_frame_b, cur_proc
73 2:
74   movw cur_proc, %sp
75   popw %ax
76   iret
77 
78 
79 cur_proc:
80   .word 0x0
81 
82   .space  256, 0
83 proc_stack_top_a:
84   .space  256, 0
85 proc_stack_top_b:
86 
87 stack_frame_a:
88   .word 0x9# ax
89   .word 0x0# eip
90   .word 0x1# cs
91   .word 0x2# flag
92 
93 stack_frame_b:
94   .word 0x9# ax
95   .word 0x0# eip
96   .word 0x1# cs
97   .word 0x2# flag
98 

該來的還是跑不掉, 我本來不想提及保護模式, 這得加上不少程式碼, 違反了我提到的簡單原則, 我只想將重點擺在 process switch, 不過最後的說明還是得用到, x86 process switch implementation (2) 要談談恐怖的保護模式。

沒有留言:

張貼留言

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

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