Repository navigation
Expand file tree
/
Copy paththreads_low.asm
More file actions
executable file
·148 lines (116 loc) · 4.06 KB
/
Copy paththreads_low.asm
File metadata and controls
executable file
·148 lines (116 loc) · 4.06 KB
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
; File: threads_low.asm
;
; This code is a modified version of David Hovemeyer's GeekOS code.
; Low level interrupt/thread handling code for GeekOS.
; Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
; Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
; ----------------------------------------------------------------------
; threads_low_switch_to(Thread * _thread)
;
; If the calling entity is a thread, we save its context.
; Then we load the context of the new thread, and continue executing
; with the new thread.
;
; ----------------------------------------------------------------------
[BITS 32]
KERNEL_CS equ 1<<3 ; kernel code segment is GDT entry 1
KERNEL_DS equ 2<<3 ; kernel data segment is GDT entry 2
INTERRUPT_STATE_SIZE equ 68 ; size of exception frame on stack
; Save registers prior to calling a handler function.
; This must be kept up to date with:
; - REGS (register context) struct in machine.h
; - setup_thread_context() in threads.c
%macro save_registers 0
pushad
push ds
push es
push fs
push gs
%endmacro
; Restore registers and clean up the stack after calling a handler function
; (i.e., just before we return from the interrupt via an iret instruction).
%macro restore_registers 0
pop gs
pop fs
pop es
pop ds
popad
add esp, 8 ; skip int num and error code
%endmacro
extern _current_thread ; defined and initialized in threads.c
global _threads_low_switch_to
align 16
; this function is exported.
_threads_low_switch_to:
; Is this a full-blown context switch, or is this just the start-up
; thread giving control to the first real thread? If the latter, we
; don't need to do anything with setting up and saving the current
; context. We simply proceed to loading the new context.
cmp [_current_thread], dword 0
je .context_load_only
; Modify the stack to allow a later return via an iret instruction.
; We start with a stack that looks like this:
;
; thread_ptr
; esp --> return addr
;
; We change it to look like this:
;
; thread_ptr
; eflags
; cs
; esp --> return addr
push eax ; save eax
mov eax, [esp+4] ; get return address
mov [esp-4], eax ; move return addr down 8 bytes from orig loc
add esp, 8 ; move stack ptr up
pushfd ; put eflags where return address was
mov eax, [esp-4] ; restore saved value of eax
push dword KERNEL_CS ; push cs selector
sub esp, 4 ; point stack ptr at return address
; Push fake error code and interrupt number
push dword 0
push dword 0
; Save general purpose registers.
save_registers
; Save stack pointer in the thread context struct (at offset 0).
mov eax, [_current_thread]
mov [eax+0], esp
; Load the pointer to the new thread context into eax.
; We skip over the Interrupt_State struct on the stack to
; get the parameter.
mov eax, dword [esp+INTERRUPT_STATE_SIZE]
; Make the new thread current, and switch to its stack.
mov [_current_thread], eax
mov esp, [eax+0]
; Restore general purpose and segment registers, and clear interrupt
; number and error code.
restore_registers
; We'll return to the place where the thread was
; executing last.
iret
.context_load_only:
; We skipped the whole exception frame setup, and just need to
; store the thread pointer into eax.
mov eax, [esp+4]
; Make the new thread current, and switch to its stack.
mov [_current_thread], eax
mov esp, [eax+0]
; Restore general purpose and segment registers, and clear interrupt
; number and error code.
restore_registers
; We'll return to the place where the thread was
; executing last.
iret
; ----------------------------------------------------------------------
; get_EFLAGS()
;
; Returns value of the EFLAGS status register.
;
; ----------------------------------------------------------------------
global _get_EFLAGS
; this function is exported.
_get_EFLAGS:
pushfd ; push eflags
pop eax ; pop contents into eax
ret