summaryrefslogtreecommitdiff
path: root/kernel/asm.s
blob: 655dcfc7553613b0211542f678f463b91049c461 (plain)
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
98
99
100
101
102
103
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]
  jne .skip
  pop ebx
  pop ebp
  ret
.skip:
  ; 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]
  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]
  shl ebx, 3
  add ebx, 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]
  shl ebx, 3
  add ebx, gdt+40
  mov byte [ebx+5], 0
  pop ebx
  pop ebp
  ret