Skip to content

Commit

Permalink
✨ 070 系统调用 fork
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenBaby committed Jul 7, 2022
1 parent 1c6a4cb commit 54fe61a
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 4 deletions.
8 changes: 8 additions & 0 deletions docs/08 系统调用/070 系统调用 fork.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 系统调用 fork

```c++
pid_t fork(void); // 创建子进程
```
- 子进程返回值为 0
- 父进程返回值为子进程 id
4 changes: 4 additions & 0 deletions src/include/onix/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
typedef enum syscall_t
{
SYS_NR_TEST,
SYS_NR_FORK = 2,
SYS_NR_WRITE = 4,
SYS_NR_GETPID = 20,
SYS_NR_BRK = 45,
Expand All @@ -15,6 +16,9 @@ typedef enum syscall_t
} syscall_t;

u32 test();

pid_t fork();

void yield();
void sleep(u32 ms);

Expand Down
2 changes: 2 additions & 0 deletions src/include/onix/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ typedef struct intr_frame_t
task_t *running_task();
void schedule();

pid_t task_fork();

void task_yield();
void task_block(task_t *task, list_t *blist, task_state_t state);
void task_unblock(task_t *task);
Expand Down
2 changes: 2 additions & 0 deletions src/kernel/gate.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ void syscall_init()
}

syscall_table[SYS_NR_TEST] = sys_test;
syscall_table[SYS_NR_FORK] = task_fork;

syscall_table[SYS_NR_SLEEP] = task_sleep;
syscall_table[SYS_NR_YIELD] = task_yield;

Expand Down
72 changes: 72 additions & 0 deletions src/kernel/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,17 +422,63 @@ void unlink_page(u32 vaddr)
flush_tlb(vaddr);
}

// 拷贝一页,返回拷贝后的物理地址
static u32 copy_page(void *page)
{
u32 paddr = get_page();

page_entry_t *entry = get_pte(0, false);
entry_init(entry, IDX(paddr));
memcpy((void *)0, (void *)page, PAGE_SIZE);

entry->present = false;
return paddr;
}

// 拷贝当前页目录
page_entry_t *copy_pde()
{
task_t *task = running_task();

page_entry_t *pde = (page_entry_t *)alloc_kpage(1); // todo free
memcpy(pde, (void *)task->pde, PAGE_SIZE);

// 将最后一个页表指向页目录自己,方便修改
page_entry_t *entry = &pde[1023];
entry_init(entry, IDX(pde));

page_entry_t *dentry;

for (size_t didx = 2; didx < 1023; didx++)
{
dentry = &pde[didx];
if (!dentry->present)
continue;

page_entry_t *pte = (page_entry_t *)(PDE_MASK | (didx << 12));

for (size_t tidx = 0; tidx < 1024; tidx++)
{
entry = &pte[tidx];
if (!entry->present)
continue;

// 对应物理内存引用大于 0
assert(memory_map[entry->index] > 0);
// 置为只读
entry->write = false;
// 对应物理页引用加 1
memory_map[entry->index]++;

assert(memory_map[entry->index] < 255);
}

u32 paddr = copy_page(pte);
dentry->index = IDX(paddr);
}

set_cr3(task->pde);

return pde;
}

Expand Down Expand Up @@ -496,6 +542,32 @@ void page_fault(

assert(KERNEL_MEMORY_SIZE <= vaddr < USER_STACK_TOP);

if (code->present)
{
assert(code->write);

page_entry_t *pte = get_pte(vaddr, false);
page_entry_t *entry = &pte[TIDX(vaddr)];

assert(entry->present);
assert(memory_map[entry->index] > 0);
if (memory_map[entry->index] == 1)
{
entry->write = true;
LOGK("WRITE page for 0x%p\n", vaddr);
}
else
{
void *page = (void *)PAGE(IDX(vaddr));
u32 paddr = copy_page(page);
memory_map[entry->index]--;
entry_init(entry, IDX(paddr));
flush_tlb(vaddr);
LOGK("COPY page for 0x%p\n", vaddr);
}
return;
}

if (!code->present && (vaddr < task->brk || vaddr >= USER_STACK_BOTTOM))
{
u32 page = PAGE(IDX(vaddr));
Expand Down
59 changes: 59 additions & 0 deletions src/kernel/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,65 @@ void task_to_user_mode(target_t target)
"jmp interrupt_exit\n" ::"m"(iframe));
}

extern void interrupt_exit();

static void task_build_stack(task_t *task)
{
u32 addr = (u32)task + PAGE_SIZE;
addr -= sizeof(intr_frame_t);
intr_frame_t *iframe = (intr_frame_t *)addr;
iframe->eax = 0;

addr -= sizeof(task_frame_t);
task_frame_t *frame = (task_frame_t *)addr;

frame->ebp = 0xaa55aa55;
frame->ebx = 0xaa55aa55;
frame->edi = 0xaa55aa55;
frame->esi = 0xaa55aa55;

frame->eip = interrupt_exit;

task->stack = (u32 *)frame;
}

pid_t task_fork()
{
// LOGK("fork is called\n");
task_t *task = running_task();

// 当前进程没有阻塞,且正在执行
assert(task->node.next == NULL && task->node.prev == NULL && task->state == TASK_RUNNING);

// 拷贝内核栈 和 PCB
task_t *child = get_free_task();
pid_t pid = child->pid;
memcpy(child, task, PAGE_SIZE);

child->pid = pid;
child->ppid = task->pid;
child->ticks = child->priority;
child->state = TASK_READY;

// 拷贝用户进程虚拟内存位图
child->vmap = kmalloc(sizeof(bitmap_t)); // todo kfree
memcpy(child->vmap, task->vmap, sizeof(bitmap_t));

// 拷贝虚拟位图缓存
void *buf = (void *)alloc_kpage(1); // todo free_kpage
memcpy(buf, task->vmap->bits, PAGE_SIZE);
child->vmap->bits = buf;

// 拷贝页目录
child->pde = (u32)copy_pde();

// 构造 child 内核栈
task_build_stack(child); // ROP
// schedule();

return child->pid;
}

static void task_setup()
{
task_t *task = running_task();
Expand Down
17 changes: 13 additions & 4 deletions src/kernel/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,23 @@ static void user_init_thread()
{
u32 counter = 0;

char ch;
while (true)
{
// test();
printf("init thread %d %d %d...\n", getpid(), getppid(), counter++);
// printf("init thread %d %d %d...\n", getpid(), getppid(), counter++);
// printf("task is in user mode %d\n", counter++);
sleep(1000);
pid_t pid = fork();

if (pid)
{
printf("fork after parent %d, %d, %d\n", pid, getpid(), getppid());
}
else
{
printf("fork after child %d, %d, %d\n", pid, getpid(), getppid());
}
hang();
sleep(100);
}
}

Expand All @@ -53,7 +63,6 @@ void test_thread()

while (true)
{
printf("test thread %d %d %d...\n", getpid(), getppid(), counter++);
// LOGK("test task %d....\n", counter++);
// BMB;
sleep(2000);
Expand Down
5 changes: 5 additions & 0 deletions src/lib/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ u32 test()
return _syscall0(SYS_NR_TEST);
}

pid_t fork()
{
return _syscall0(SYS_NR_FORK);
}

void yield()
{
_syscall0(SYS_NR_YIELD);
Expand Down

0 comments on commit 54fe61a

Please sign in to comment.