324 lines
8.0 KiB
C
324 lines
8.0 KiB
C
/*
|
|
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
|
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
|
* You may obtain a copy of Mulan PSL v1 at:
|
|
* http://license.coscl.org.cn/MulanPSL
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
* PURPOSE.
|
|
* See the Mulan PSL v1 for more details.
|
|
*/
|
|
|
|
#include <process/process.h>
|
|
#include <process/thread.h>
|
|
#include <common/list.h>
|
|
#include <common/util.h>
|
|
#include <common/bitops.h>
|
|
#include <common/kmalloc.h>
|
|
#include <mm/vmspace.h>
|
|
#include <common/printk.h>
|
|
#include <common/cpio.h>
|
|
|
|
/* tool functions */
|
|
bool is_valid_slot_id(struct slot_table * slot_table, int slot_id)
|
|
{
|
|
if (slot_id < 0 && slot_id >= slot_table->slots_size)
|
|
return false;
|
|
if (!get_bit(slot_id, slot_table->slots_bmp))
|
|
return false;
|
|
if (slot_table->slots[slot_id] == NULL)
|
|
BUG("slot NULL while bmp is not\n");
|
|
return true;
|
|
}
|
|
|
|
static int slot_table_init(struct slot_table *slot_table, unsigned int size)
|
|
{
|
|
int r;
|
|
|
|
size = DIV_ROUND_UP(size, BASE_OBJECT_NUM) * BASE_OBJECT_NUM;
|
|
slot_table->slots_size = size;
|
|
|
|
slot_table->slots = kzalloc(size * sizeof(*slot_table->slots));
|
|
if (!slot_table->slots) {
|
|
r = -ENOMEM;
|
|
goto out_fail;
|
|
}
|
|
|
|
slot_table->slots_bmp = kzalloc(BITS_TO_LONGS(size)
|
|
* sizeof(unsigned long));
|
|
if (!slot_table->slots_bmp) {
|
|
r = -ENOMEM;
|
|
goto out_free_slots;
|
|
}
|
|
|
|
slot_table->full_slots_bmp = kzalloc(BITS_TO_LONGS(BITS_TO_LONGS(size))
|
|
* sizeof(unsigned long));
|
|
if (!slot_table->full_slots_bmp) {
|
|
r = -ENOMEM;
|
|
goto out_free_slots_bmp;
|
|
}
|
|
|
|
return 0;
|
|
out_free_slots_bmp:
|
|
kfree(slot_table->slots_bmp);
|
|
out_free_slots:
|
|
kfree(slot_table->slots);
|
|
out_fail:
|
|
return r;
|
|
}
|
|
|
|
static int expand_slot_table(struct slot_table *slot_table)
|
|
{
|
|
unsigned int new_size, old_size;
|
|
struct slot_table new_slot_table;
|
|
int r;
|
|
|
|
old_size = slot_table->slots_size;
|
|
new_size = old_size + BASE_OBJECT_NUM;
|
|
r = slot_table_init(&new_slot_table, new_size);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
memcpy(new_slot_table.slots, slot_table->slots,
|
|
old_size * sizeof(*slot_table->slots));
|
|
memcpy(new_slot_table.slots_bmp, slot_table->slots_bmp,
|
|
BITS_TO_LONGS(old_size) * sizeof(unsigned long));
|
|
memcpy(new_slot_table.full_slots_bmp, slot_table->full_slots_bmp,
|
|
BITS_TO_LONGS(BITS_TO_LONGS(old_size)) * sizeof(unsigned long));
|
|
slot_table->slots_size = new_size;
|
|
slot_table->slots = new_slot_table.slots;
|
|
slot_table->slots_bmp = new_slot_table.slots_bmp;
|
|
slot_table->full_slots_bmp = new_slot_table.full_slots_bmp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int alloc_slot_id(struct process *process)
|
|
{
|
|
int empty_idx = 0, r;
|
|
struct slot_table *slot_table;
|
|
int bmp_size = 0, full_bmp_size = 0;
|
|
|
|
slot_table = &process->slot_table;
|
|
|
|
while (true) {
|
|
bmp_size = slot_table->slots_size;
|
|
full_bmp_size = BITS_TO_LONGS(bmp_size);
|
|
|
|
empty_idx = find_next_zero_bit(slot_table->full_slots_bmp,
|
|
full_bmp_size, 0);
|
|
if (empty_idx >= full_bmp_size)
|
|
goto expand;
|
|
|
|
empty_idx = find_next_zero_bit(slot_table->slots_bmp,
|
|
bmp_size,
|
|
empty_idx * BITS_PER_LONG);
|
|
if (empty_idx >= bmp_size)
|
|
goto expand;
|
|
else
|
|
break;
|
|
expand:
|
|
r = expand_slot_table(slot_table);
|
|
if (r < 0)
|
|
goto out_fail;
|
|
}
|
|
BUG_ON(empty_idx < 0 || empty_idx >= bmp_size);
|
|
|
|
set_bit(empty_idx, slot_table->slots_bmp);
|
|
if (slot_table->full_slots_bmp[empty_idx / BITS_PER_LONG]
|
|
== ~((unsigned long)0))
|
|
set_bit(empty_idx / BITS_PER_LONG, slot_table->full_slots_bmp);
|
|
|
|
return empty_idx;
|
|
out_fail:
|
|
return r;
|
|
}
|
|
|
|
static int process_init(struct process *process, unsigned int size)
|
|
{
|
|
struct slot_table *slot_table = &process->slot_table;
|
|
|
|
BUG_ON(slot_table_init(slot_table, size));
|
|
init_list_head(&process->thread_list);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct process *process_create(void)
|
|
{
|
|
struct process *process;
|
|
struct object *object;
|
|
struct object_slot *slot;
|
|
struct vmspace *vmspace;
|
|
int total_size, slot_id;
|
|
|
|
// init thread
|
|
total_size = sizeof(*object) + sizeof(*process);
|
|
if ((object = kmalloc(total_size)) == NULL)
|
|
goto out_fail;
|
|
object->type = TYPE_PROCESS;
|
|
object->size = sizeof(*process);
|
|
object->refcount = 1;
|
|
process = (struct process *)object->opaque;
|
|
process_init(process, BASE_OBJECT_NUM);
|
|
|
|
// put the cap of the process its self on the first slot
|
|
slot_id = alloc_slot_id(process);
|
|
BUG_ON(slot_id != PROCESS_OBJ_ID);
|
|
slot = kzalloc(sizeof(*slot));
|
|
if (!slot)
|
|
goto out_free_process;
|
|
slot->slot_id = slot_id;
|
|
slot->process = process;
|
|
slot->isvalid = true;
|
|
slot->object = object;
|
|
init_list_head(&slot->copies);
|
|
process->slot_table.slots[slot_id] = slot;
|
|
|
|
vmspace = obj_alloc(TYPE_VMSPACE, sizeof(*vmspace));
|
|
BUG_ON(!vmspace);
|
|
vmspace_init(vmspace);
|
|
slot_id = cap_alloc(process, vmspace, 0);
|
|
BUG_ON(slot_id != VMSPACE_OBJ_ID);
|
|
|
|
return process;
|
|
out_free_process:
|
|
kfree(process);
|
|
out_fail:
|
|
return NULL;
|
|
}
|
|
|
|
void process_exit(struct process *process)
|
|
{
|
|
struct process *process_get;
|
|
struct slot_table *slot_table;
|
|
int slot_id;
|
|
|
|
/* hold a reference and release all cap related to it */
|
|
process_get = obj_get(process, PROCESS_OBJ_ID, TYPE_PROCESS);
|
|
/* process is already freed by others */
|
|
if (!process_get)
|
|
return;
|
|
/* cap_revoke(process, process_OBJ_ID); */
|
|
|
|
slot_table = &process->slot_table;
|
|
|
|
for_each_set_bit(slot_id, slot_table->slots_bmp, slot_table->slots_size) {
|
|
cap_free(process, slot_id);
|
|
}
|
|
|
|
obj_put(process);
|
|
}
|
|
|
|
/*
|
|
* Tool Functions to read a binary program file from ramdisk
|
|
*/
|
|
extern const char binary_cpio_bin_start;
|
|
|
|
static void *cpio_cb_file(const void *start, size_t size, void *data)
|
|
{
|
|
char *buff = kmalloc(size);
|
|
if (buff <= 0)
|
|
return ERR_PTR(-ENOMEM);
|
|
memcpy(buff, start, size);
|
|
return buff;
|
|
}
|
|
|
|
static int ramdisk_read_file(char *path, char **buf)
|
|
{
|
|
BUG_ON(path == NULL);
|
|
|
|
int ret = 0;
|
|
*buf = cpio_extract_single(&binary_cpio_bin_start, path, cpio_cb_file,
|
|
NULL);
|
|
if (ret == 0)
|
|
return 0;
|
|
else
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/* process_create_root: create the root process */
|
|
void process_create_root(char *bin_name)
|
|
{
|
|
struct process *root_process;
|
|
int thread_cap;
|
|
struct thread *root_thread;
|
|
char *binary = NULL;
|
|
int ret;
|
|
|
|
// 从内存硬盘读取相关文件,使用 CPIO 格式
|
|
ret = ramdisk_read_file(bin_name, &binary);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(binary == NULL);
|
|
|
|
// 创建 PCB 并设置自身 Cap
|
|
root_process = process_create();
|
|
|
|
// 创建主线程与其 Cap
|
|
thread_cap = thread_create_main(root_process, ROOT_THREAD_STACK_BASE,
|
|
ROOT_THREAD_STACK_SIZE,
|
|
ROOT_THREAD_PRIO, TYPE_ROOT,
|
|
smp_get_cpu_id(), binary, bin_name);
|
|
|
|
// 将主线程 Cap 加入进程
|
|
root_thread = obj_get(root_process, thread_cap, TYPE_THREAD);
|
|
/* Enqueue: put init thread into the ready queue */
|
|
BUG_ON(sched_enqueue(root_thread));
|
|
obj_put(root_thread);
|
|
current_thread = root_thread;
|
|
}
|
|
|
|
/* syscalls */
|
|
int sys_create_process(void)
|
|
{
|
|
struct process *new_process;
|
|
struct vmspace *vmspace;
|
|
int cap, r;
|
|
|
|
/* cap current process */
|
|
new_process = obj_alloc(TYPE_PROCESS, sizeof(*new_process));
|
|
if (!new_process) {
|
|
r = -ENOMEM;
|
|
goto out_fail;
|
|
}
|
|
process_init(new_process, BASE_OBJECT_NUM);
|
|
cap = cap_alloc(current_process, new_process, 0);
|
|
if (cap < 0) {
|
|
r = cap;
|
|
goto out_free_obj_new_grp;
|
|
}
|
|
|
|
/* 1st cap is process */
|
|
if (cap_copy(current_thread->process, new_process, cap, 0, 0)
|
|
!= PROCESS_OBJ_ID) {
|
|
printk("init process cap[0] is not process\n");
|
|
r = -1;
|
|
goto out_free_cap_grp_current;
|
|
}
|
|
|
|
/* 2st cap is vmspace */
|
|
vmspace = obj_alloc(TYPE_VMSPACE, sizeof(*vmspace));
|
|
if (!vmspace) {
|
|
r = -ENOMEM;
|
|
goto out_free_obj_vmspace;
|
|
}
|
|
vmspace_init(vmspace);
|
|
r = cap_alloc(new_process, vmspace, 0);
|
|
if (r < 0)
|
|
goto out_free_obj_vmspace;
|
|
else if (r != VMSPACE_OBJ_ID)
|
|
BUG("init process cap[1] is not vmspace\n");
|
|
|
|
return cap;
|
|
out_free_obj_vmspace:
|
|
obj_free(vmspace);
|
|
out_free_cap_grp_current:
|
|
cap_free(current_process, cap);
|
|
new_process = NULL;
|
|
out_free_obj_new_grp:
|
|
obj_free(new_process);
|
|
out_fail:
|
|
return r;
|
|
}
|