2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
21 #include <memkernel.h>
32 #include <interrupt.h>
35 * Initializes process management
36 * @return -1=Success; 0=Failure
39 proc_all
= llist_create();
40 proc_running
= llist_create();
41 proc_sleeping
= llist_create();
44 if (syscall_create(SYSCALL_PROC_GETPID
,proc_getpid
,0)==-1) return -1;
45 if (syscall_create(SYSCALL_PROC_GETUID
,proc_getuid
,1)==-1) return -1;
46 if (syscall_create(SYSCALL_PROC_GETGID
,proc_getgid
,1)==-1) return -1;
47 if (syscall_create(SYSCALL_PROC_SETUID
,proc_setuid
,2)==-1) return -1;
48 if (syscall_create(SYSCALL_PROC_SETGID
,proc_setgid
,2)==-1) return -1;
49 if (syscall_create(SYSCALL_PROC_GETPARENT
,proc_getparent
,1)==-1) return -1;
50 if (syscall_create(SYSCALL_PROC_GETNAME
,proc_getname
,3)==-1) return -1;
51 if (syscall_create(SYSCALL_PROC_GETPIDBYNAME
,proc_getpidbyname
,1)==-1) return -1;
52 if (syscall_create(SYSCALL_PROC_GETVAR
,proc_getvar
,0)==-1) return -1;
53 if (syscall_create(SYSCALL_PROC_EXIT
,proc_exit
,1)==-1) return -1;
54 if (syscall_create(SYSCALL_PROC_ABORT
,proc_abort
,0)==-1) return -1;
55 if (syscall_create(SYSCALL_PROC_STOP
,proc_stop
,0)==-1) return -1;
60 * Creates a new process
61 * @param name Process name
64 proc_t
*proc_create(char *name
,uid_t uid
,gid_t gid
,proc_t
*parent
,int running
) {
65 proc_t
*new = malloc(sizeof(proc_t
));
67 new->pid
= proc_nextpid
++;
74 new->name
= strdup(name
);
76 if (parent
!=NULL
) llist_push(parent
->children
,new);
77 new->children
= llist_create();
78 memset(&(new->registers
),0,sizeof(new->registers
));
79 new->registers
.efl
= 0x202;
80 new->registers
.cs
= IDX2SEL(3,PRIV_USER
);
81 new->registers
.ds
= IDX2SEL(4,PRIV_USER
);
82 new->registers
.es
= IDX2SEL(4,PRIV_USER
);
83 new->registers
.fs
= IDX2SEL(4,PRIV_USER
);
84 new->registers
.gs
= IDX2SEL(4,PRIV_USER
);
85 new->registers
.ss
= IDX2SEL(4,PRIV_USER
);
86 new->addrspace
= memuser_create_addrspace(new);
87 new->registers
.esp
= (uint32_t)memuser_create_stack(new->addrspace
);
88 //memset(&(new->irq_handler),0,sizeof(new->irq_handler));
89 new->time_handler
= llist_create();
91 new->ticks_rem
= NICE2TICKS(new->nice
);
92 //new->ipc_objects = llist_create();
95 new->is_sleeping
= !running
;
99 llist_push(proc_all
,new);
100 llist_push(running
?proc_running
:proc_sleeping
,new);
106 * @param proc Process
109 int proc_destroy(proc_t
*proc
) {
113 while ((child
= llist_pop(proc
->children
))) child
->parent
= proc
->parent
;
114 llist_destroy(proc
->children
);
115 if (proc
->parent
!=NULL
) llist_remove(proc
->parent
->children
,llist_find(proc
->parent
->children
,proc
));
116 if (proc
->addrspace
!=NULL
) memuser_destroy_addrspace(proc
->addrspace
);
117 llist_destroy(proc
->time_handler
);
119 llist_remove(proc_all
,llist_find(proc_all
,proc
));
120 if (llist_remove(proc_running
,llist_find(proc_running
,proc
))!=proc
) llist_remove(proc_sleeping
,llist_find(proc_sleeping
,proc
));
126 * Finds a process by PID
130 proc_t
*proc_find(pid_t pid
) {
133 if (proc_current
->pid
==pid
) return proc_current
;
134 for (i
=0;(proc
= llist_get(proc_all
,i
));i
++) {
135 if (proc
->pid
==pid
) return proc
;
141 * Sends a process sleeping
142 * @param proc Process
143 * @param sleep Reference to sleep variable
146 int proc_sleep(proc_t
*proc
) {
147 if (!proc
->is_sleeping
) {
148 llist_remove(proc_running
,llist_find(proc_running
,proc
));
149 llist_push(proc_sleeping
,proc
);
150 proc
->is_sleeping
= 1;
151 if (proc
==proc_current
) proc_shedule();
158 * @param proc Process
161 int proc_wake(proc_t
*proc
) {
162 if (proc
->is_sleeping
) {
163 llist_remove(proc_sleeping
,llist_find(proc_sleeping
,proc
));
164 llist_push(proc_running
,proc
);
165 proc
->is_sleeping
= 0;
171 * Save registers of process
172 * @param proc Process
175 int proc_regs_save(proc_t
*proc
) {
176 proc
->registers
.eax
= *interrupt_curregs
.eax
;
177 proc
->registers
.ebx
= *interrupt_curregs
.ebx
;
178 proc
->registers
.ecx
= *interrupt_curregs
.ecx
;
179 proc
->registers
.edx
= *interrupt_curregs
.edx
;
180 proc
->registers
.esi
= *interrupt_curregs
.esi
;
181 proc
->registers
.edi
= *interrupt_curregs
.edi
;
182 proc
->registers
.ebp
= *interrupt_curregs
.ebp
;
183 proc
->registers
.esp
= *interrupt_curregs
.esp
;
184 proc
->registers
.eip
= *interrupt_curregs
.eip
;
185 proc
->registers
.efl
= *interrupt_curregs
.efl
;
186 proc
->registers
.cs
= *interrupt_curregs
.cs
;
187 proc
->registers
.ds
= *interrupt_curregs
.ds
;
188 proc
->registers
.es
= *interrupt_curregs
.es
;
189 proc
->registers
.fs
= *interrupt_curregs
.fs
;
190 proc
->registers
.gs
= *interrupt_curregs
.gs
;
191 proc
->registers
.ss
= *interrupt_curregs
.ss
;
192 if (proc
->is_vm86
) vm86_save_segregs(proc
);
197 * Load registers of process
198 * @param proc Process
201 int proc_regs_load(proc_t
*proc
) {
202 *interrupt_curregs
.eax
= proc
->registers
.eax
;
203 *interrupt_curregs
.ebx
= proc
->registers
.ebx
;
204 *interrupt_curregs
.ecx
= proc
->registers
.ecx
;
205 *interrupt_curregs
.edx
= proc
->registers
.edx
;
206 *interrupt_curregs
.esi
= proc
->registers
.esi
;
207 *interrupt_curregs
.edi
= proc
->registers
.edi
;
208 *interrupt_curregs
.ebp
= proc
->registers
.ebp
;
209 *interrupt_curregs
.esp
= proc
->registers
.esp
;
210 *interrupt_curregs
.eip
= proc
->registers
.eip
;
211 *interrupt_curregs
.efl
= proc
->registers
.efl
;
212 *interrupt_curregs
.cs
= proc
->registers
.cs
;
213 *interrupt_curregs
.ds
= proc
->registers
.ds
;
214 *interrupt_curregs
.es
= proc
->registers
.es
;
215 *interrupt_curregs
.fs
= proc
->registers
.fs
;
216 *interrupt_curregs
.gs
= proc
->registers
.gs
;
217 *interrupt_curregs
.ss
= proc
->registers
.ss
;
218 if (proc
->is_vm86
) vm86_load_segregs(proc
);
223 * Loads next process for execution
225 void proc_shedule() {
228 proc_t
*proc_old
= proc_current
;
230 // if no processes running hold machine (until next interrupt)
231 if (llist_empty(proc_running
)) {
232 // if no processes at all, shutdown
233 if (llist_empty(proc_sleeping
)) cpu_shutdown();
235 /// @todo maybe put these 2 lines in proc_idle
236 proc_regs_save(proc_current
);
242 // Process finished its time slice
243 if (proc_current
!=NULL
) {
244 proc_current
->ticks_rem
--;
248 // Search for process that still has time
249 for (i
=0;(proc
= llist_get(proc_running
,i
));i
++) {
250 if (proc
->ticks_rem
>0) proc_current
= proc
;
253 // If no processes with time, fill time slices
254 if (proc_current
==NULL
) {
255 //kprintf("Refilling time slices\n");
256 for (i
=0;(proc
= llist_get(proc_running
,i
));i
++) proc
->ticks_rem
= NICE2TICKS(proc
->nice
);
257 proc_current
= llist_get(proc_running
,0);
260 // Set context and load address space
261 if (proc_old
!=proc_current
) {
262 if (proc_old
!=NULL
) proc_regs_save(proc_old
);
263 proc_regs_load(proc_current
);
264 memuser_load_addrspace(proc_current
->addrspace
);
272 pid_t
proc_getpid() {
273 return proc_current
->pid
;
277 * Gets Parent PID (Syscall)
278 * @param pid Process to get parent's PID of
279 * @return Parent's PID
281 pid_t
proc_getparent(pid_t pid
) {
282 proc_t
*proc
= proc_find(pid
);
284 if (proc
->parent
!=NULL
) return proc
->parent
->pid
;
291 * @param idmask Which ID to return
294 uid_t
proc_getuid(int idmask
) {
295 if ((idmask
&1)) return proc_current
->uid
;
296 else if ((idmask
&2)) return proc_current
->euid
;
297 else if ((idmask
&4)) return proc_current
->suid
;
303 * @param idmask Which ID to set
305 * @todo Check permissions
307 void proc_setuid(int idmask
,uid_t uid
) {
308 if ((idmask
&1)) proc_current
->uid
= uid
;
309 else if ((idmask
&2)) proc_current
->euid
= uid
;
310 else if ((idmask
&4)) proc_current
->suid
= uid
;
315 * @param idmask Which ID to return
318 gid_t
proc_getgid(int idmask
) {
319 if ((idmask
&1)) return proc_current
->gid
;
320 else if ((idmask
&2)) return proc_current
->egid
;
321 else if ((idmask
&4)) return proc_current
->sgid
;
327 * @param idmask Which ID to set
329 * @todo Check permissions
331 void proc_setgid(int idmask
,gid_t gid
) {
332 if ((idmask
&1)) proc_current
->gid
= gid
;
333 else if ((idmask
&2)) proc_current
->egid
= gid
;
334 else if ((idmask
&4)) proc_current
->sgid
= gid
;
338 * Gets process name (Syscall)
340 * @param buf Buffer for name
341 * @param maxlen Maximal length of name
342 * @return Success? (if buf==NULL length of name is returned)
344 ssize_t
proc_getname(pid_t pid
,char *buf
,size_t maxlen
) {
345 proc_t
*proc
= proc_find(pid
);
348 strncpy(buf
,proc
->name
,maxlen
);
351 else return strlen(proc
->name
)+1;
357 * Gets PID by process name
358 * @param name Process name
359 * @return PID of process
361 pid_t
proc_getpidbyname(const char *name
) {
364 for (i
=0;(proc
= llist_get(proc_all
,i
));i
++) {
365 if (strcmp(proc
->name
,name
)==0) return proc
->pid
;
371 * Gets private variable
372 * @return private variable
375 return proc_current
->var
;
379 * Exits process (Syscall)
380 * @param ret Return value
382 void proc_exit(int ret
) {
383 proc_current
->ret
= ret
;
384 proc_current
->defunc
= 1;
385 llist_remove(proc_running
,llist_find(proc_running
,proc_current
));
386 //memuser_destroy_addrspace(proc_current->addrspace);
387 //proc_current->addrspace = NULL;
393 * Aborts process (Syscall)
396 kprintf("Program aborted: %s #%d\n",proc_current
->name
,proc_current
->pid
);
401 * Stops process (Syscall)
404 proc_sleep(proc_current
);
408 * Calls a function in process
409 * @param proc Process
410 * @param func Function
411 * @param numparams Number of parameters
412 * @param ... Parameters
414 void proc_call(proc_t
*proc
,void *func
,size_t numparams
,...) {
418 int *params
= malloc(numparams
*sizeof(int));
419 uint32_t *eip
= proc_current
==proc
?interrupt_curregs
.eip
:&proc
->registers
.eip
;
421 va_start(args
,numparams
);
422 for (i
=0;i
<numparams
;i
++) params
[numparams
-(i
+1)] = va_arg(args
,int);
425 memuser_load_addrspace(proc
->addrspace
);
426 for (i
=0;i
<numparams
;i
++) proc_push(proc
,params
[i
]);
427 proc_push(proc
,*eip
);
428 if (proc_current
!=NULL
) {
429 memuser_load_addrspace(proc_current
->addrspace
);
431 *eip
= (uint32_t)func
;
438 * Push an element on user stack
439 * @param proc Process
442 void proc_push(proc_t
*proc
,int val
) {
443 uint32_t *esp
= proc_current
==proc
?interrupt_curregs
.esp
:&proc
->registers
.esp
;
445 //memuser_load_addrspace(proc->addrspace);
446 *((int*)(*esp
)) = val
;
447 //memuser_load_addrspace(proc_current->addrspace);
451 * Pops an element from user stack
452 * @param proc Process
455 int proc_pop(proc_t
*proc
) {
456 int val
= *((int*)proc
->registers
.esp
);
457 proc
->registers
.esp
+= sizeof(int);
462 * Idles until next schedule
465 asm("mov %0,%%esp"::"r"(cpu_this
->tss
->esp0
)); // reload ESP0 in TSS "by hand"
471 * Forks a process (share virtual memory)
472 * @param proc Process to be forked
473 * @return New process
475 proc_t
*proc_vfork(proc_t
*proc
) {
476 proc_t
*new = malloc(sizeof(proc_t
));
477 memcpy(new,proc
,sizeof(proc_t
));
478 new->pid
= proc_nextpid
++;
480 new->name
= strdup(proc
->name
);
481 llist_push(proc
->children
,new);
482 new->time_handler
= llist_copy(proc
->time_handler
);
483 new->ticks_rem
= NICE2TICKS(new->nice
);
484 llist_push(proc_all
,new);
485 llist_push(proc_running
,new);
491 * @param proc Process to be forked
492 * @return New process
494 proc_t
*proc_fork(proc_t
*proc
) {
495 proc_t
*new = proc_vfork(proc
);
496 new->addrspace
= memuser_clone_addrspace(new,proc
->addrspace
);