-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocess.asm
163 lines (130 loc) · 3.26 KB
/
process.asm
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
extern process_stack_start
extern fork
extern on_task_returned
extern process_main
extern screen_put_char
extern screen_print_hex
extern next_task
extern next_directory
extern next_task_dir_phys_addr
extern next_task_esp
extern current_task
extern current_directory
extern kernel_idle_task
global copy_frame
copy_frame:
push ebx
pushf ; save eflags
cli ; don't get interrupted
mov ebx, [esp+12] ; src
mov ecx, [esp+16] ; dst
; disable paging
mov edx, cr0
and edx, 0x7fffffff
mov cr0, edx
mov edx, 1024
.loop:
mov eax, [ebx]
mov [ecx], eax
add ebx, 4
add ecx, 4
dec edx
jnz .loop
; enable paging
mov edx, cr0
or edx, 0x80000000
mov cr0, edx
popf
pop ebx
ret
global read_eip
read_eip:
pop eax
jmp eax
global start_process
start_process:
push ebx
mov ebx, esp ; ebx = kernel stack
mov esp, [process_stack_start] ; moved stack to user pages
call fork
cmp eax, 0
je .start_of_process
; kernel
; after kernel forks to first process all that is left is to respond to ISRs
; and even if there is something, it can be called from kernel_idle_task
call kernel_idle_task
; kernel_idle_task should never return
; we can't really get back to original kernel stack and code
; I leave this here only for reference
; original kernel stack is probably overwritten by ISRs
mov esp, ebx ; restore kernel stack
pop ebx
ret
.start_of_process:
; user
; we want to jump to user start function
; but return from it to on_task_returned
push on_task_returned
jmp process_main
global switch_task_dispatched_to_user
switch_task_dispatched_to_user:
; (page_dir_phys_addr, registers)
add esp, 4 ; take off return address
; we can switch dir because we are on kernel stack, and it is mapped to all dirs
pop eax ; take off page dir phys addr
mov cr3, eax ; page dir switched
pop eax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
pop edi
pop esi
pop ebp
add esp, 4 ;pop esp
pop ebx
pop edx
pop ecx
pop eax
add esp, 8 ; intno + errcode
iret
global switch_task_dispatched_kernel
switch_task_dispatched_kernel:
; (page_dir_phys_addr, registers_ptr)
mov eax, [esp + 4] ; take off page dir phys addr
mov cr3, eax ; page dir switched
mov eax, [esp + 8] ; eax points to registers, which should be in kernel memory, mapped to all dirs
; ds should be the same, we're not switching priviledge level
; mov ecx, [eax] ; take first field of registers - ds
; mov ds, cx
; mov es, cx
; mov fs, cx
; mov gs, cx
mov edi, [eax + 4]
mov esi, [eax + 8]
mov ebp, [eax + 12]
mov esp, [eax + 56] ; prev_esp
mov ebx, [eax + 20]
mov edx, [eax + 24]
mov ecx, [eax + 28]
push dword [eax + 44] ; push return address to new stack
push dword [eax + 52] ; push eflags
mov eax, [eax + 32] ; finally restore eax
popf ; pop eflags from new stack
ret ; pop return address and continue with task
global switch_to_user_mode
switch_to_user_mode:
cli
mov ax, 0x23 ; user data segment 0x20 | 0x3 - ring 3
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ecx, [esp + 4] ; save return address that is passed as parameter
mov eax, esp ; save stack pointer
push dword 0x23 ; stack segment selector = data segment
push eax ; restore stack after iret
push dword 0x202 ; eflags: I + reserved 1
push dword 0x1B ; user code segment 0x18 | 0x3 ring 3
push ecx ; push return address
iret