假設處理序 P 有子處理序 A。而 A 使用 exit(),那麼 MM 將會:
- 告訴 FS:A 退出,請作相應處理
- 釋放 A 佔用的記憶體
- 判斷 P 是否正在 WAITING
- 如果是
- 清除 P 的 WAITING 位
- 向 P 發送訊息以解除阻塞(到此 P 的 wait() 函數結束)
- 釋放 A 的處理序表項(到此 A 的 exit() 函數結束)
- 如果否
- 設定 A 的 HANGING 位
- 瀏覽 proc_table[],如果發現 A 有子處理序 B,那麼
- 將 Init 處理序設定為 B 的父處理序(換言之,將 B 過繼給 Init)
- 判斷是否滿足 Init 正在 WAITING 且 B 正在 HANGING
- 如果是
- 清除 Init 的 WAITING 位
- 向 Init 發送訊息以解除阻塞(到此 Init 的 wait() 函數結束)
- 釋放 B 的處理序表項(到此 B 的 exit() 函數結束)
- 如果否
- 如果 Init 正在 WAITING 但 B 並沒有 HANGING,那麼「握手」會在將來 B 使用 exit() 時發生
- 如果 B 正在 HANGING 但 Init 並沒有 WAITING,那麼「握手」會在將來 Init 使用 wait() 時發生
如果 P 使用 wait(),那麼 MM 將會:
- 瀏覽 proc_table[],如果發現 A 是 P 的子處理序,並且它正在 HANGING,那麼
- 向 P 發送訊息以解除阻塞(到此 P 的 wait() 函數結束)
- 釋放 A 的處理序表項(到此 A 的 exit() 函數結束)
- 如果 P 的子處理序沒有一個再 HANGING,則
- 設 P 的 WAITING 位
- 如果 P 壓根兒沒有子處理序,則
- 向 P 發送訊息,訊息攜帶一個表示出錯的返回值(到此 P 的 wait() 函數結束)
程式碼
kernel/main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* kernel_main
*****************************************************************************/
/**
* jmp from kernel.asm::_start.
*
*****************************************************************************/
PUBLIC int kernel_main()
{
disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
int i, j, eflags, prio;
u8 rpl;
u8 priv; /* privilege */
struct task * t;
struct proc * p = proc_table;
char * stk = task_stack + STACK_SIZE_TOTAL;
for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++,t++) {
if (i >= NR_TASKS + NR_NATIVE_PROCS) {
p->p_flags = FREE_SLOT;
continue;
}
if (i < NR_TASKS) { /* TASK */
t = task_table + i;
priv = PRIVILEGE_TASK;
rpl = RPL_TASK;
eflags = 0x1202;/* IF=1, IOPL=1, bit 2 is always 1 */
prio = 15;
}
else { /* USER PROC */
t = user_proc_table + (i - NR_TASKS);
priv = PRIVILEGE_USER;
rpl = RPL_USER;
eflags = 0x202; /* IF=1, bit 2 is always 1 */
prio = 5;
}
strcpy(p->name, t->name); /* name of the process */
p->p_parent = NO_TASK;
if (strcmp(t->name, "INIT") != 0) {
p->ldts[INDEX_LDT_C] = gdt[SELECTOR_KERNEL_CS >> 3];
p->ldts[INDEX_LDT_RW] = gdt[SELECTOR_KERNEL_DS >> 3];
/* change the DPLs */
p->ldts[INDEX_LDT_C].attr1 = DA_C | priv << 5;
p->ldts[INDEX_LDT_RW].attr1 = DA_DRW | priv << 5;
}
else { /* INIT process */
unsigned int k_base;
unsigned int k_limit;
int ret = get_kernel_map(&k_base, &k_limit);
assert(ret == 0);
init_desc(&p->ldts[INDEX_LDT_C],
0, /* bytes before the entry point
* are useless (wasted) for the
* INIT process, doesn't matter
*/
(k_base + k_limit) >> LIMIT_4K_SHIFT,
DA_32 | DA_LIMIT_4K | DA_C | priv << 5);
init_desc(&p->ldts[INDEX_LDT_RW],
0, /* bytes before the entry point
* are useless (wasted) for the
* INIT process, doesn't matter
*/
(k_base + k_limit) >> LIMIT_4K_SHIFT,
DA_32 | DA_LIMIT_4K | DA_DRW | priv << 5);
}
p->regs.cs = INDEX_LDT_C << 3 | SA_TIL | rpl;
p->regs.ds =
p->regs.es =
p->regs.fs =
p->regs.ss = INDEX_LDT_RW << 3 | SA_TIL | rpl;
p->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;
p->regs.eip = (u32)t->initial_eip;
p->regs.esp = (u32)stk;
p->regs.eflags = eflags;
p->ticks = p->priority = prio;
p->p_flags = 0;
p->p_msg = 0;
p->p_recvfrom = NO_TASK;
p->p_sendto = NO_TASK;
p->has_int_msg = 0;
p->q_sending = 0;
p->next_sending = 0;
for (j = 0; j < NR_FILES; j++)
p->filp[j] = 0;
stk -= t->stacksize;
}
k_reenter = 0;
ticks = 0;
p_proc_ready = proc_table;
init_clock();
init_keyboard();
restart();
while(1){}
}
/*****************************************************************************
* get_ticks
*****************************************************************************/
PUBLIC int get_ticks()
{
MESSAGE msg;
reset_msg(&msg);
msg.type = GET_TICKS;
send_recv(BOTH, TASK_SYS, &msg);
return msg.RETVAL;
}
/*****************************************************************************
* Init
*****************************************************************************/
/**
* The hen.
*
*****************************************************************************/
void Init()
{
int fd_stdin = open("/dev_tty0", O_RDWR);
assert(fd_stdin == 0);
int fd_stdout = open("/dev_tty0", O_RDWR);
assert(fd_stdout == 1);
printf("Init() is running ...\n");
int pid = fork();
if (pid != 0) { /* parent process */
printf("parent is running, child pid:%d\n", pid);
int s;
int child = wait(&s);
printf("child (%d) exited with status: %d.\n", child, s);
}
else { /* child process */
printf("child is running, pid:%d\n", getpid());
exit(123);
}
while (1) {
int s;
int child = wait(&s);
printf("child (%d) exited with status: %d.\n", child, s);
}
}
/*======================================================================*
TestA
*======================================================================*/
void TestA()
{
for(;;);
}
/*======================================================================*
TestB
*======================================================================*/
void TestB()
{
for(;;);
}
/*======================================================================*
TestB
*======================================================================*/
void TestC()
{
for(;;);
}
/*****************************************************************************
* panic
*****************************************************************************/
PUBLIC void panic(const char *fmt, ...)
{
int i;
char buf[256];
/* 4 is the size of fmt in the stack */
va_list arg = (va_list)((char*)&fmt + 4);
i = vsprintf(buf, fmt, arg);
printl("%c !!panic!! %s", MAG_CH_PANIC, buf);
/* should never arrive here */
__asm__ __volatile__("ud2");
}
mm/forkexit.c
/*************************************************************************//**
*****************************************************************************
* @file forkexit.c
* @brief
* @author Forrest Y. Yu
* @date Tue May 6 00:37:15 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
PRIVATE void cleanup(struct proc * proc);
/*****************************************************************************
* do_fork
*****************************************************************************/
/**
* Perform the fork() syscall.
*
* @return Zero if success, otherwise -1.
*****************************************************************************/
PUBLIC int do_fork()
{
/* find a free slot in proc_table */
struct proc* p = proc_table;
int i;
for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++)
if (p->p_flags == FREE_SLOT)
break;
int child_pid = i;
assert(p == &proc_table[child_pid]);
assert(child_pid >= NR_TASKS + NR_NATIVE_PROCS);
if (i == NR_TASKS + NR_PROCS) /* no free slot */
return -1;
assert(i < NR_TASKS + NR_PROCS);
/* duplicate the process table */
int pid = mm_msg.source;
u16 child_ldt_sel = p->ldt_sel;
*p = proc_table[pid];
p->ldt_sel = child_ldt_sel;
p->p_parent = pid;
sprintf(p->name, "%s_%d", proc_table[pid].name, child_pid);
/* duplicate the process: T, D & S */
struct descriptor * ppd;
/* Text segment */
ppd = &proc_table[pid].ldts[INDEX_LDT_C];
/* base of T-seg, in bytes */
int caller_T_base = reassembly(ppd->base_high, 24,
ppd->base_mid, 16,
ppd->base_low);
/* limit of T-seg, in 1 or 4096 bytes,
depending on the G bit of descriptor */
int caller_T_limit = reassembly(0, 0,
(ppd->limit_high_attr2 & 0xF), 16,
ppd->limit_low);
/* size of T-seg, in bytes */
int caller_T_size = ((caller_T_limit + 1) *
((ppd->limit_high_attr2 & (DA_LIMIT_4K >> 8)) ?
4096 : 1));
/* Data & Stack segments */
ppd = &proc_table[pid].ldts[INDEX_LDT_RW];
/* base of D&S-seg, in bytes */
int caller_D_S_base = reassembly(ppd->base_high, 24,
ppd->base_mid, 16,
ppd->base_low);
/* limit of D&S-seg, in 1 or 4096 bytes,
depending on the G bit of descriptor */
int caller_D_S_limit = reassembly((ppd->limit_high_attr2 & 0xF), 16,
0, 0,
ppd->limit_low);
/* size of D&S-seg, in bytes */
int caller_D_S_size = ((caller_T_limit + 1) *
((ppd->limit_high_attr2 & (DA_LIMIT_4K >> 8)) ?
4096 : 1));
/* we don't separate T, D & S segments, so we have: */
assert((caller_T_base == caller_D_S_base ) &&
(caller_T_limit == caller_D_S_limit) &&
(caller_T_size == caller_D_S_size ));
/* base of child proc, T, D & S segments share the same space,
so we allocate memory just once */
int child_base = alloc_mem(child_pid, caller_T_size);
/* int child_limit = caller_T_limit; */
printl("{MM} 0x%x <- 0x%x (0x%x bytes)\n",
child_base, caller_T_base, caller_T_size);
/* child is a copy of the parent */
phys_copy((void*)child_base, (void*)caller_T_base, caller_T_size);
/* child's LDT */
init_desc(&p->ldts[INDEX_LDT_C],
child_base,
(PROC_IMAGE_SIZE_DEFAULT - 1) >> LIMIT_4K_SHIFT,
DA_LIMIT_4K | DA_32 | DA_C | PRIVILEGE_USER << 5);
init_desc(&p->ldts[INDEX_LDT_RW],
child_base,
(PROC_IMAGE_SIZE_DEFAULT - 1) >> LIMIT_4K_SHIFT,
DA_LIMIT_4K | DA_32 | DA_DRW | PRIVILEGE_USER << 5);
/* tell FS, see fs_fork() */
MESSAGE msg2fs;
msg2fs.type = FORK;
msg2fs.PID = child_pid;
send_recv(BOTH, TASK_FS, &msg2fs);
/* child PID will be returned to the parent proc */
mm_msg.PID = child_pid;
/* birth of the child */
MESSAGE m;
m.type = SYSCALL_RET;
m.RETVAL = 0;
m.PID = 0;
send_recv(SEND, child_pid, &m);
return 0;
}
/*****************************************************************************
* do_exit
*****************************************************************************/
/**
* Perform the exit() syscall.
*
* If proc A calls exit(), then MM will do the following in this routine:
* <1> inform FS so that the fd-related things will be cleaned up
* <2> free A's memory
* <3> set A.exit_status, which is for the parent
* <4> depends on parent's status. if parent (say P) is:
* (1) WAITING
* - clean P's WAITING bit, and
* - send P a message to unblock it
* - release A's proc_table[] slot
* (2) not WAITING
* - set A's HANGING bit
* <5> iterate proc_table[], if proc B is found as A's child, then:
* (1) make INIT the new parent of B, and
* (2) if INIT is WAITING and B is HANGING, then:
* - clean INIT's WAITING bit, and
* - send INIT a message to unblock it
* - release B's proc_table[] slot
* else
* if INIT is WAITING but B is not HANGING, then
* - B will call exit()
* if B is HANGING but INIT is not WAITING, then
* - INIT will call wait()
*
* TERMs:
* - HANGING: everything except the proc_table entry has been cleaned up.
* - WAITING: a proc has at least one child, and it is waiting for the
* child(ren) to exit()
* - zombie: say P has a child A, A will become a zombie if
* - A exit(), and
* - P does not wait(), neither does it exit(). that is to say, P just
* keeps running without terminating itself or its child
*
* @param status Exiting status for parent.
*
*****************************************************************************/
PUBLIC void do_exit(int status)
{
int i;
int pid = mm_msg.source; /* PID of caller */
int parent_pid = proc_table[pid].p_parent;
struct proc * p = &proc_table[pid];
/* tell FS, see fs_exit() */
MESSAGE msg2fs;
msg2fs.type = EXIT;
msg2fs.PID = pid;
send_recv(BOTH, TASK_FS, &msg2fs);
free_mem(pid);
p->exit_status = status;
if (proc_table[parent_pid].p_flags & WAITING) { /* parent is waiting */
proc_table[parent_pid].p_flags &= ~WAITING;
cleanup(&proc_table[pid]);
}
else { /* parent is not waiting */
proc_table[pid].p_flags |= HANGING;
}
/* if the proc has any child, make INIT the new parent */
for (i = 0; i < NR_TASKS + NR_PROCS; i++) {
if (proc_table[i].p_parent == pid) { /* is a child */
proc_table[i].p_parent = INIT;
if ((proc_table[INIT].p_flags & WAITING) &&
(proc_table[i].p_flags & HANGING)) {
proc_table[INIT].p_flags &= ~WAITING;
cleanup(&proc_table[i]);
}
}
}
}
/*****************************************************************************
* cleanup
*****************************************************************************/
/**
* Do the last jobs to clean up a proc thoroughly:
* - Send proc's parent a message to unblock it, and
* - release proc's proc_table[] entry
*
* @param proc Process to clean up.
*****************************************************************************/
PRIVATE void cleanup(struct proc * proc)
{
MESSAGE msg2parent;
msg2parent.type = SYSCALL_RET;
msg2parent.PID = proc2pid(proc);
msg2parent.STATUS = proc->exit_status;
send_recv(SEND, proc->p_parent, &msg2parent);
proc->p_flags = FREE_SLOT;
}
/*****************************************************************************
* do_wait
*****************************************************************************/
/**
* Perform the wait() syscall.
*
* If proc P calls wait(), then MM will do the following in this routine:
* <1> iterate proc_table[],
* if proc A is found as P's child and it is HANGING
* - reply to P (cleanup() will send P a messageto unblock it)
* - release A's proc_table[] entry
* - return (MM will go on with the next message loop)
* <2> if no child of P is HANGING
* - set P's WAITING bit
* <3> if P has no child at all
* - reply to P with error
* <4> return (MM will go on with the next message loop)
*
*****************************************************************************/
PUBLIC void do_wait()
{
int pid = mm_msg.source;
int i;
int children = 0;
struct proc* p_proc = proc_table;
for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) {
if (p_proc->p_parent == pid) {
children++;
if (p_proc->p_flags & HANGING) {
cleanup(p_proc);
return;
}
}
}
if (children) {
/* has children, but no child is HANGING */
proc_table[pid].p_flags |= WAITING;
}
else {
/* no child at all */
MESSAGE msg;
msg.type = SYSCALL_RET;
msg.PID = NO_TASK;
send_recv(SEND, pid, &msg);
}
}
Makefile
######################### # Makefile for Orange'S # ######################### # Entry point of Orange'S # It must have the same value with 'KernelEntryPointPhyAddr' in load.inc! ENTRYPOINT = 0x1000 # Offset of entry point in kernel file # It depends on ENTRYPOINT ENTRYOFFSET = 0x400 # Programs, flags, etc. ASM = nasm DASM = objdump CC = gcc LD = ld ASMBFLAGS = -I boot/include/ ASMKFLAGS = -I include/ -I include/sys/ -f elf CFLAGS = -I include/ -I include/sys/ -m32 -c -fno-builtin -fno-stack-protector LDFLAGS = -s -melf_i386 -Ttext $(ENTRYPOINT) -Map krnl.map DASMFLAGS = -D # This Program ORANGESBOOT = boot/boot.bin boot/loader.bin ORANGESKERNEL = kernel.bin OBJS = kernel/kernel.o lib/syscall.o kernel/start.o kernel/main.o\ kernel/clock.o kernel/keyboard.o kernel/tty.o kernel/console.o\ kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\ kernel/systask.o kernel/hd.o\ lib/printf.o lib/vsprintf.o\ lib/kliba.o lib/klib.o lib/string.o lib/misc.o\ lib/open.o lib/read.o lib/write.o lib/close.o lib/unlink.o\ lib/getpid.o lib/syslog.o\ fs/main.o fs/open.o fs/misc.o fs/read_write.o\ lib/fork.o lib/exit.o lib/wait.o\ mm/main.o mm/forkexit.o\ fs/link.o\ fs/disklog.o DASMOUTPUT = kernel.bin.asm # All Phony Targets .PHONY : everything final image clean realclean disasm all buildimg # Default starting position nop : @echo "why not \`make image' huh? :)" everything : $(ORANGESBOOT) $(ORANGESKERNEL) all : realclean everything image : realclean everything clean buildimg clean : rm -f $(OBJS) realclean : rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL) disasm : $(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT) # We assume that "a.img" exists in current folder buildimg : mkdir tmp sleep 1 sudo mount -o loop a.img tmp sleep 1 sudo cp -fv boot/loader.bin tmp sudo cp -fv kernel.bin tmp sleep 1 sudo umount tmp sleep 1 rmdir tmp boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc $(ASM) $(ASMBFLAGS) -o $@ $< boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc $(ASM) $(ASMBFLAGS) -o $@ $< $(ORANGESKERNEL) : $(OBJS) $(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS) kernel/kernel.o : kernel/kernel.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/syscall.o : lib/syscall.asm $(ASM) $(ASMKFLAGS) -o $@ $< kernel/start.o: kernel/start.c $(CC) $(CFLAGS) -o $@ $< kernel/main.o: kernel/main.c $(CC) $(CFLAGS) -o $@ $< kernel/clock.o: kernel/clock.c $(CC) $(CFLAGS) -o $@ $< kernel/keyboard.o: kernel/keyboard.c $(CC) $(CFLAGS) -o $@ $< kernel/tty.o: kernel/tty.c $(CC) $(CFLAGS) -o $@ $< kernel/console.o: kernel/console.c $(CC) $(CFLAGS) -o $@ $< kernel/i8259.o: kernel/i8259.c $(CC) $(CFLAGS) -o $@ $< kernel/global.o: kernel/global.c $(CC) $(CFLAGS) -o $@ $< kernel/protect.o: kernel/protect.c $(CC) $(CFLAGS) -o $@ $< kernel/proc.o: kernel/proc.c $(CC) $(CFLAGS) -o $@ $< lib/printf.o: lib/printf.c $(CC) $(CFLAGS) -o $@ $< lib/vsprintf.o: lib/vsprintf.c $(CC) $(CFLAGS) -o $@ $< kernel/systask.o: kernel/systask.c $(CC) $(CFLAGS) -o $@ $< kernel/hd.o: kernel/hd.c $(CC) $(CFLAGS) -o $@ $< lib/klib.o: lib/klib.c $(CC) $(CFLAGS) -o $@ $< lib/misc.o: lib/misc.c $(CC) $(CFLAGS) -o $@ $< lib/kliba.o : lib/kliba.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/string.o : lib/string.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/open.o: lib/open.c $(CC) $(CFLAGS) -o $@ $< lib/read.o: lib/read.c $(CC) $(CFLAGS) -o $@ $< lib/write.o: lib/write.c $(CC) $(CFLAGS) -o $@ $< lib/close.o: lib/close.c $(CC) $(CFLAGS) -o $@ $< lib/unlink.o: lib/unlink.c $(CC) $(CFLAGS) -o $@ $< lib/getpid.o: lib/getpid.c $(CC) $(CFLAGS) -o $@ $< lib/syslog.o: lib/syslog.c $(CC) $(CFLAGS) -o $@ $< lib/fork.o: lib/fork.c $(CC) $(CFLAGS) -o $@ $< lib/exit.o: lib/exit.c $(CC) $(CFLAGS) -o $@ $< lib/wait.o: lib/wait.c $(CC) $(CFLAGS) -o $@ $< mm/main.o: mm/main.c $(CC) $(CFLAGS) -o $@ $< mm/forkexit.o: mm/forkexit.c $(CC) $(CFLAGS) -o $@ $< fs/main.o: fs/main.c $(CC) $(CFLAGS) -o $@ $< fs/open.o: fs/open.c $(CC) $(CFLAGS) -o $@ $< fs/read_write.o: fs/read_write.c $(CC) $(CFLAGS) -o $@ $< fs/link.o: fs/link.c $(CC) $(CFLAGS) -o $@ $< fs/disklog.o: fs/disklog.c $(CC) $(CFLAGS) -o $@ $<
![]() |
| 執行畫面 |

留言
張貼留言