-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmpos-app.h
241 lines (208 loc) · 7.33 KB
/
mpos-app.h
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#ifndef WEENSYOS_MPOS_APP_H
#define WEENSYOS_MPOS_APP_H
#include "mpos.h"
#include "lib.h"
/*****************************************************************************
* mpos-app.h
*
* This header file defines the C versions of the 5 mpos system calls.
* Each system call is defined by assembly code that implements a protected
* control transfer to the kernel, using the 'int' machine instruction.
* Any arguments to the system call are passed in registers, which have
* names like %eax and %ebx. You'll see how below.
* The kernel returns any results in a register, %eax.
* You'll also see how we tell the compiler to put the value of %eax
* into a C variable.
*
*****************************************************************************/
/*****************************************************************************
* sys_getpid
*
* Returns the current process's process ID.
*
*****************************************************************************/
static inline pid_t
sys_getpid(void)
{
// We call a system call using the 'int' instruction. This causes a
// software interrupt, which is sometimes called a "trap".
// In weensyos, the type of system call is indicated by the interrupt
// number -- here, INT_SYS_GETPID.
// The sys_getpid() call returns a value in the %eax register.
// The C compiler lets us execute arbitrary assembly instructions
// with an "asm" statement, like the one below.
// The arguments to the "asm" statement define which instruction to
// run, and how to put values from registers into C variables.
// Here, '"=a" (pid)' tells the C compiler that, after executing the
// 'int' instruction, it should store the value of the %eax register
// into the 'pid' variable.
// That means that after the "asm" instruction (which causes the
// interrupt), the system call's return value is in the 'pid'
// variable, and we can just return that value!
pid_t pid;
asm volatile("int %1\n"
: "=a" (pid)
: "i" (INT_SYS_GETPID)
: "cc", "memory");
return pid;
}
/*****************************************************************************
* sys_fork
*
* Create a new process by copying the current process's state.
* (In MiniprocOS, this is just the current process's stack; in a real OS
* there would be much more.)
* In the child's context, this system call returns 0.
* In the parent's context, it returns the child's process ID.
* Returns -1 if the system call failed.
*
*****************************************************************************/
static inline pid_t
sys_fork(void)
{
// This system call follows the same pattern as sys_getpid().
pid_t result;
asm volatile("int %1\n"
: "=a" (result)
: "i" (INT_SYS_FORK)
: "cc", "memory");
return result;
}
/*****************************************************************************
* sys_yield
*
* Yield control of the CPU to the kernel, which will pick another
* process to run. (It might run this process again, depending on the
* scheduling policy.)
*
*****************************************************************************/
static inline void
sys_yield(void)
{
// This system call has no return values, so there's no '=a' clause.
asm volatile("int %0\n"
:
: "i" (INT_SYS_YIELD)
: "cc", "memory");
}
/*****************************************************************************
* sys_exit(status)
*
* Exit the current process with exit status 'status'.
* This system call never returns.
*
*****************************************************************************/
static inline void sys_exit(int status) __attribute__ ((noreturn));
static inline void
sys_exit(int status)
{
// This system call uses another feature: the application passes a
// PARAMETER to the kernel, namely the "status" variable.
// It passes that parameter by storing it in the %eax register
// before causing the interrupt.
// Then the kernel can look up the parameter by checking the value
// of that register.
// The '"a" (start_function)' clause, below, tells the C compiler
// to load the value of "start_function" into %eax before executing
// the 'int' instruction.
// You can load other registers with similar syntax; specifically:
// "a" = %eax, "b" = %ebx, "c" = %ecx, "d" = %edx,
// "S" = %esi, "D" = %edi.
asm volatile("int %0\n"
:
: "i" (INT_SYS_EXIT),
"a" (status)
: "cc", "memory");
loop: goto loop; /* will not be reached */
}
/*****************************************************************************
* sys_wait(pid)
*
* Wait until the process with ID 'pid' exits, then return that
* process's exit status.
* sys_wait(pid) will only return successfully *once* for a given process
* 'pid'. If two processes call sys_wait(pid) for the same pid, only one
* of them will return the actual exit status.
* After that point the process ID might be reused.
*
* Returns -1 if 'pid' does not exist, or equals the current process's ID.
* Returns WAIT_TRYAGAIN == -2 if 'pid' has not yet exited.
*
*****************************************************************************/
static inline int
sys_wait(pid_t pid)
{
int retval;
asm volatile("int %1\n"
: "=a" (retval)
: "i" (INT_SYS_WAIT),
"a" (pid)
: "cc", "memory");
return retval;
}
/*****************************************************************************
* sys_kill(pid)
*
* Kill another process
* Returns -1 if 'pid' does not exist, or equals the current process's ID.
*
*
*****************************************************************************/
static inline int
sys_kill(pid_t pid)
{
int retval;
asm volatile("int %1\n"
: "=a" (retval)
: "i" (INT_SYS_KILL),
"a" (pid)
: "cc", "memory");
return retval;
}
//XIA: sys_newthread
/*****************************************************************************
* sys_newthread(void (*start_function)(void));
*
* Creat another another thread to excute start_function
* Returns -1 if it did not succeed
* Returns pid of the new process to parent process
* Returns 0 to the new thread
*****************************************************************************/
static inline pid_t
sys_newthread(void (*start_function)(void))
{
pid_t pid;
asm volatile("int %1\n"
: "=a" (pid)
: "i" (INT_SYS_NEWTHREAD),
"a" (start_function)
: "cc", "memory");
return pid;
}
/*****************************************************************************
* app_printf(format, ...)
*
* Calls console_printf() (see lib.h).
* The cursor position is read from 'cursorpos', a shared variable defined
* by the kernel, and written back into that variable.
* The initial color is based on the current process ID.
*
*****************************************************************************/
static void app_printf(const char *format, ...) __attribute__((noinline));
static void
app_printf(const char *format, ...)
{
// set default color based on currently running process
int color = sys_getpid();
if (color < 0)
color = 0x0700;
else {
static const uint8_t col[] = { 0x0E, 0x0F, 0x0C, 0x0A, 0x09 };
color = col[color % sizeof(col)] << 8;
}
va_list val;
va_start(val, format);
cursorpos = console_vprintf(cursorpos, color, format, val);
va_end(val);
}
#endif