summaryrefslogtreecommitdiff
path: root/kernel/process.s
blob: fd0462f6bbcd76d5e87cb53dce154b918f06e25f (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
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
.intel_syntax noprefix
.global copy_page_physical
.global loop_m
copy_page_physical:
   push ebx              
   pushf                 
                        
   cli                 
                      
   mov ebx, [esp+12] 
   mov ecx, [esp+16]

   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

   mov edx, cr0 
   or  edx, 0x80000000 
   mov cr0, edx       

   popf              
   pop ebx          
   ret


.extern current_task_TCB
.global TCB

.section .data

    .struct 0
TCB: 
TCB.ESP:
    .space 4
TCB.CR3:
    .space 4
TCB.ESP0:
    .space 4

.global switch_to_task
.global insert_eip_on_stack
.global internal_fork
.extern create_process

.section .text

internal_fork:
    push ebp
    mov ecx, esp
    mov ebp, esp

    mov eax, [ebp+8] # current_task

    lea edx, after_internal_fork
    push edx
    push ecx
    push eax
    call create_process
    add esp, 0xC
    cmp eax, 0
    jnz internal_fork_ret
    mov eax, 1
internal_fork_ret:
    pop ebp
    ret
after_internal_fork:
    pop ebp
    mov eax, 0
    ret

insert_eip_on_stack:
    push ebp
    mov ebp, esp
    mov eax, [ebp+8] # cr3
    mov ecx, [ebp+8+4] # address
    mov edx, [ebp+8+4+4] # value

    push ebx

    mov ebx, cr3
    mov cr3, eax

    mov [ecx], edx

    mov cr3, ebx

    pop ebx
    pop ebp
    ret

# C declaration:
#    void switch_to_task(thread_control_block *next_thread);
# 
# WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns

switch_to_task:
    # Save previous task's state
 
    # Notes:
    #   For cdecl; EAX, ECX, and EDX are already saved by the caller and don't need to be saved again
    #   EIP is already saved on the stack by the caller's "CALL" instruction
    #   The task isn't able to change CR3 so it doesn't need to be saved
    #   Segment registers are constants (while running kernel code) so they don't need to be saved
 
    push ebx
    push esi
    push edi
    push ebp
 
    mov edi,[current_task_TCB]    # edi = address of the previous task's "thread control block"
    mov [edi+TCB.ESP],esp         # Save ESP for previous task's kernel stack in the thread's TCB
 
    # Load next task's state
 
    mov esi,[esp+(4+1)*4]         # esi = address of the next task's "thread control block" (parameter passed on stack)
    mov [current_task_TCB],esi    # Current task's TCB is the next task TCB
 
    mov esp,[esi+TCB.ESP]         # Load ESP for next task's kernel stack from the thread's TCB
    mov eax,[esi+TCB.CR3]         # eax = address of page directory for next task
    mov ebx,[esi+TCB.ESP0]        # ebx = address for the top of the next task's kernel stack
#    mov [TSS.ESP0],ebx            # Adjust the ESP0 field in the TSS (used by CPU for for CPL=3 -> CPL=0 privilege level changes)
    mov ecx,cr3                   # ecx = previous task's virtual address space
 
    cmp eax,ecx                   # Does the virtual address space need to being changed?

    je .doneVAS                   #  no, virtual address space is the same, so don't reload it and cause TLB flushes
    mov cr3,eax                   #  yes, load the next task's virtual address space
.doneVAS:
 
    pop ebp
    pop edi
    pop esi
    pop ebx
 
    sti
    ret                           # Load next task's EIP from its kernel stack