已完成实验
简介
实验 20. 实现系统调用
总结
-
进程结构体新增 pid 成员变量
-
pid 采用静态全局变量,锁控制+1,确保唯一
-
进程初始化是就分配好 pid
-
添加 getpid,本质调用 syscall,参数入栈,再执行 int 0x80
-
添加 0x80 中断,根据参数 0 调用系统调用函数表的函数
-
初始化系统调用函数表,表项 0 就是获取 pid
主要代码
thread.h
thread.c
syscall.c
// 文件: syscall.c
// 时间: 2024-08-01
// 来自: ccj
// 描述: 用户系统调用,压入0x80和参数,执行int 0x80
#include "syscall.h"
/// 无参数的系统调用
// 1. push ${NUMBER}
// 2. int 0x80
// 3. pop ${NUMBER}
// 4. eax的值给到retval
#define _syscall0(NUMBER) \
({ \
int retval; \
asm volatile("pushl %[number]; int $0x80; addl $4, %%esp" \
: "=a"(retval) \
: [number] "i"(NUMBER) \
: "memory"); \
retval; \
})
// 一个参数的系统调用
#define _syscall1(NUMBER, ARG0) \
({ \
int retval; \
asm volatile("pushl %[arg0]; pushl %[number]; int $0x80; addl $8, %%esp" \
: "=a"(retval) \
: [number] "i"(NUMBER), [arg0] "g"(ARG0) \
: "memory"); \
retval; \
})
// 两个参数的系统调用
#define _syscall2(NUMBER, ARG0, ARG1) \
({ \
int retval; \
asm volatile( \
"pushl %[arg1]; pushl %[arg0]; " \
"pushl %[number]; int $0x80; addl $12, %%esp" \
: "=a"(retval) \
: [number] "i"(NUMBER), [arg0] "g"(ARG0), [arg1] "g"(ARG1) \
: "memory"); \
retval; \
})
// 三个参数的系统调用
#define _syscall3(NUMBER, ARG0, ARG1, ARG2) \
({ \
int retval; \
asm volatile( \
"pushl %[arg2]; pushl %[arg1]; pushl %[arg0]; " \
"pushl %[number]; int $0x80; addl $16, %%esp" \
: "=a"(retval) \
: [number] "i"(NUMBER), [arg0] "g"(ARG0), [arg1] "g"(ARG1), [arg2] "g"(ARG2) \
: "memory"); \
retval; \
})
/// @brief 返回当前任务pid
/// @return
uint32_t getpid() { return _syscall0(SYS_GETPID); }
kernel.s
syscall-init.c
// 文件: syscall-init.c
// 时间: 2024-08-01
// 来自: ccj
// 描述: 初始化系统调用函数表,0x80中断根据参数执行表的函数
#include "syscall-init.h"
#include "syscall.h"
#include "stdint.h"
#include "print.h"
#include "thread.h"
#define syscall_nr 32
typedef void* syscall;
// 系统调用处理数组
syscall syscall_table[syscall_nr];
/// @brief 返回当前任务的pid
/// @param
/// @return
uint32_t sys_getpid(void) { return running_thread()->pid; }
/// @brief 初始化系统调用
/// @param
void syscall_init(void) {
put_str("[syscall] syscall_init start\n");
syscall_table[SYS_GETPID] = sys_getpid;
put_str("[syscall] syscall_init done\n");
}
init.c
main.c
// 文件: main.c
// 时间: 2024-07-19
// 来自: ccj
// 描述: 内核从此处开始
#include "print.h"
#include "init.h"
#include "thread.h"
#include "interrupt.h"
#include "console.h"
#include "process.h"
#include "syscall.h"
#include "syscall-init.h"
// 两个内核线程
void k_thread_a(void*);
void k_thread_b(void*);
// 两个用户进程
void u_prog_a(void);
void u_prog_b(void);
int prog_a_pid = 0, prog_b_pid = 0;
int main(void) {
put_str("I am kernel\n");
init_all();
process_execute(u_prog_a, "user_prog_a");
process_execute(u_prog_b, "user_prog_b");
console_put_str("main_pid:0x");
console_put_int(sys_getpid());
console_put_char('\n');
thread_start("k_thread_a", 31, k_thread_a, "argA ");
thread_start("k_thread_b", 31, k_thread_b, "argB ");
intr_enable(); // 打开中断,使时钟中断起作用
while (1) {};
return 0;
}
// 内核线程函数
void k_thread_a(void* arg) {
console_put_str("thread_a_pid:0x");
console_put_int(sys_getpid());
console_put_char('\n');
console_put_str("prog_a_pid:0x");
console_put_int(prog_a_pid);
console_put_char('\n');
while (1) {}
}
void k_thread_b(void* arg) {
console_put_str("thread_b_pid:0x");
console_put_int(sys_getpid());
console_put_char('\n');
console_put_str("prog_b_pid:0x");
console_put_int(prog_b_pid);
console_put_char('\n');
while (1) {}
}
// 测试用户进程
void u_prog_a(void) {
prog_a_pid = getpid();
while (1) {}
}
void u_prog_b(void) {
prog_b_pid = getpid();
while (1) {}
}