1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
global clear_tss
global invlpg
global set_tss
global switch_to
extern ctask
extern ctaskn
extern gdt
extern save_state
; void switch_to(int n, struct task_struct *task)
switch_to:
push ebp
mov ebp, esp
push ebx
; abort if we're switching to the current task
mov ebx, [ctask]
cmp ebx, [ebp+12]
je .end
; update ctask and ctaskn
mov ebx, [ebp+12]
mov [ctask], ebx
mov ebx, [ebp+8]
mov [ctaskn], ebx
; calculate the task segment index and jump to it
mov ebx, [ebp+8]
add ebx, 5
shl ebx, 3
mov [.tmp+4], bx
jmp far [.tmp]
.end:
pop ebx
pop ebp
ret
.tmp:
dq 0
; void invlpg(void *page)
invlpg:
push ebp
mov ebp, esp
; test if we're running on a i386 and abort if so (only i486+ have caches)
pushf
pop eax
and eax, 0xFFFBFFFF
push eax
popf
pushf
pop eax
test eax, 0x40000
jnz .skip
pushf
pop eax
or eax, 0x40000
push eax
popf
pushf
pop eax
test eax, 0x40000
jz .skip
mov eax, [ebp+8]
invlpg [eax]
.skip:
pop ebp
ret
; void set_tss(unsigned int n, void *tss)
set_tss:
push ebp
mov ebp, esp
push ebx
mov eax, [ebp+12]
mov ebx, [ebp+8]
lea ebx, [ebx*8+gdt+40]
mov [ebx+2], ax
shr eax, 16
mov [ebx+4], al
mov [ebx+7], ah
mov eax, 103 ; limit - 1
mov [ebx], ax
shr eax, 16
and al, 0x0F
mov [ebx+6], al
mov byte [ebx+5], 0x89
pop ebx
pop ebp
ret
; void clear_tss(unsigned int n)
clear_tss:
push ebp
mov ebp, esp
push ebx
mov ebx, [ebp+8]
mov byte [ebx*8+gdt+40+5], 0
pop ebx
pop ebp
ret
|