1 #include "syscall.h" 2 #include <common/errno.h> 3 #include <common/fcntl.h> 4 #include <common/kthread.h> 5 #include <common/string.h> 6 #include <driver/disk/ahci/ahci.h> 7 #include <exception/gate.h> 8 #include <exception/irq.h> 9 #include <filesystem/vfs/VFS.h> 10 #include <mm/slab.h> 11 #include <process/process.h> 12 #include <time/sleep.h> 13 // 导出系统调用入口函数,定义在entry.S中 14 extern void syscall_int(void); 15 16 extern uint64_t sys_clock(struct pt_regs *regs); 17 extern uint64_t sys_mstat(struct pt_regs *regs); 18 extern uint64_t sys_open(struct pt_regs *regs); 19 extern uint64_t sys_unlink_at(struct pt_regs *regs); 20 extern uint64_t sys_kill(struct pt_regs *regs); 21 extern uint64_t sys_sigaction(struct pt_regs *regs); 22 extern uint64_t sys_rt_sigreturn(struct pt_regs *regs); 23 extern uint64_t sys_getpid(struct pt_regs *regs); 24 extern uint64_t sys_sched(struct pt_regs *regs); 25 26 /** 27 * @brief 关闭文件系统调用 28 * 29 * @param fd_num 文件描述符号 30 * 31 * @param regs 32 * @return uint64_t 33 */ 34 extern uint64_t sys_close(struct pt_regs *regs); 35 36 /** 37 * @brief 从文件中读取数据 38 * 39 * @param fd_num regs->r8 文件描述符号 40 * @param buf regs->r9 输出缓冲区 41 * @param count regs->r10 要读取的字节数 42 * 43 * @return uint64_t 44 */ 45 extern uint64_t sys_read(struct pt_regs *regs); 46 47 /** 48 * @brief 向文件写入数据 49 * 50 * @param fd_num regs->r8 文件描述符号 51 * @param buf regs->r9 输入缓冲区 52 * @param count regs->r10 要写入的字节数 53 * 54 * @return uint64_t 55 */ 56 extern uint64_t sys_write(struct pt_regs *regs); 57 58 /** 59 * @brief 调整文件的访问位置 60 * 61 * @param fd_num 文件描述符号 62 * @param offset 偏移量 63 * @param whence 调整模式 64 * @return uint64_t 调整结束后的文件访问位置 65 */ 66 extern uint64_t sys_lseek(struct pt_regs *regs); 67 68 /** 69 * @brief 导出系统调用处理函数的符号 70 * 71 */ 72 73 /** 74 * @brief 系统调用不存在时的处理函数 75 * 76 * @param regs 进程3特权级下的寄存器 77 * @return ul 78 */ 79 ul system_call_not_exists(struct pt_regs *regs) 80 { 81 kerror("System call [ ID #%d ] not exists.", regs->rax); 82 return ESYSCALL_NOT_EXISTS; 83 } // 取消前述宏定义 84 85 /** 86 * @brief 重新定义为:把系统调用函数加入系统调用表 87 * @param syscall_num 系统调用号 88 * @param symbol 系统调用处理函数 89 */ 90 #define SYSCALL_COMMON(syscall_num, symbol) [syscall_num] = symbol, 91 92 /** 93 * @brief 初始化系统调用模块 94 * 95 */ 96 void syscall_init() 97 { 98 kinfo("Initializing syscall..."); 99 100 set_system_trap_gate(0x80, 0, syscall_int); // 系统调用门 101 } 102 103 /** 104 * @brief 通过中断进入系统调用 105 * 106 * @param syscall_id 107 * @param arg0 108 * @param arg1 109 * @param arg2 110 * @param arg3 111 * @param arg4 112 * @param arg5 113 * @param arg6 114 * @param arg7 115 * @return long 116 */ 117 118 long enter_syscall_int(ul syscall_id, ul arg0, ul arg1, ul arg2, ul arg3, ul arg4, ul arg5, ul arg6, ul arg7) 119 { 120 long err_code; 121 __asm__ __volatile__("movq %2, %%r8 \n\t" 122 "movq %3, %%r9 \n\t" 123 "movq %4, %%r10 \n\t" 124 "movq %5, %%r11 \n\t" 125 "movq %6, %%r12 \n\t" 126 "movq %7, %%r13 \n\t" 127 "movq %8, %%r14 \n\t" 128 "movq %9, %%r15 \n\t" 129 "int $0x80 \n\t" 130 : "=a"(err_code) 131 : "a"(syscall_id), "m"(arg0), "m"(arg1), "m"(arg2), "m"(arg3), "m"(arg4), "m"(arg5), "m"(arg6), 132 "m"(arg7) 133 : "memory", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "rcx", "rdx"); 134 135 return err_code; 136 } 137 138 /** 139 * @brief 打印字符串的系统调用 140 * 141 * 当arg1和arg2均为0时,打印黑底白字,否则按照指定的前景色和背景色来打印 142 * 143 * @param regs 寄存器 144 * @param arg0 要打印的字符串 145 * @param arg1 前景色 146 * @param arg2 背景色 147 * @return ul 返回值 148 */ 149 ul sys_put_string(struct pt_regs *regs) 150 { 151 152 printk_color(regs->r9, regs->r10, (char *)regs->r8); 153 // printk_color(BLACK, WHITE, (char *)regs->r8); 154 155 return 0; 156 } 157 158 uint64_t sys_fork(struct pt_regs *regs) 159 { 160 return do_fork(regs, 0, regs->rsp, 0); 161 } 162 uint64_t sys_vfork(struct pt_regs *regs) 163 { 164 return do_fork(regs, CLONE_VM | CLONE_FS | CLONE_SIGNAL, regs->rsp, 0); 165 } 166 167 /** 168 * @brief 将堆内存调整为arg0 169 * 170 * @param arg0 新的堆区域的结束地址 171 * arg0=-1 ===> 返回堆区域的起始地址 172 * arg0=-2 ===> 返回堆区域的结束地址 173 * @return uint64_t 错误码 174 * 175 */ 176 uint64_t sys_brk(struct pt_regs *regs) 177 { 178 uint64_t new_brk = PAGE_2M_ALIGN(regs->r8); 179 180 // kdebug("sys_brk input= %#010lx , new_brk= %#010lx bytes current_pcb->mm->brk_start=%#018lx 181 // current->end_brk=%#018lx", regs->r8, new_brk, current_pcb->mm->brk_start, current_pcb->mm->brk_end); 182 183 if ((int64_t)regs->r8 == -1) 184 { 185 // kdebug("get brk_start=%#018lx", current_pcb->mm->brk_start); 186 return current_pcb->mm->brk_start; 187 } 188 if ((int64_t)regs->r8 == -2) 189 { 190 // kdebug("get brk_end=%#018lx", current_pcb->mm->brk_end); 191 return current_pcb->mm->brk_end; 192 } 193 if (new_brk > current_pcb->addr_limit) // 堆地址空间超过限制 194 return -ENOMEM; 195 196 int64_t offset; 197 if (new_brk >= current_pcb->mm->brk_end) 198 offset = (int64_t)(new_brk - current_pcb->mm->brk_end); 199 else 200 offset = -(int64_t)(current_pcb->mm->brk_end - new_brk); 201 202 new_brk = mm_do_brk(current_pcb->mm->brk_end, offset); // 扩展堆内存空间 203 204 current_pcb->mm->brk_end = new_brk; 205 return 0; 206 } 207 208 /** 209 * @brief 将堆内存空间加上offset(注意,该系统调用只应在普通进程中调用,而不能是内核线程) 210 * 211 * @param arg0 offset偏移量 212 * @return uint64_t the previous program break 213 */ 214 uint64_t sys_sbrk(struct pt_regs *regs) 215 { 216 uint64_t retval = current_pcb->mm->brk_end; 217 if ((int64_t)regs->r8 > 0) 218 { 219 220 uint64_t new_brk = PAGE_2M_ALIGN(retval + regs->r8); 221 if (new_brk > current_pcb->addr_limit) // 堆地址空间超过限制 222 { 223 kdebug("exceed mem limit, new_brk = %#018lx", new_brk); 224 return -ENOMEM; 225 } 226 } 227 else 228 { 229 if ((__int128_t)current_pcb->mm->brk_end + (__int128_t)regs->r8 < current_pcb->mm->brk_start) 230 return retval; 231 } 232 // kdebug("do brk"); 233 uint64_t new_brk = mm_do_brk(current_pcb->mm->brk_end, (int64_t)regs->r8); // 调整堆内存空间 234 // kdebug("do brk done, new_brk = %#018lx", new_brk); 235 current_pcb->mm->brk_end = new_brk; 236 return retval; 237 } 238 239 /** 240 * @brief 重启计算机 241 * 242 * @return 243 */ 244 uint64_t sys_reboot(struct pt_regs *regs) 245 { 246 // 重启计算机 247 io_out8(0x64, 0xfe); 248 249 return 0; 250 } 251 252 /** 253 * @brief 切换工作目录 254 * 255 * @param dest_path 目标路径 256 * @return 257 +--------------+------------------------+ 258 | 返回码 | 描述 | 259 +--------------+------------------------+ 260 | 0 | 成功 | 261 | EACCESS | 权限不足 | 262 | ELOOP | 解析path时遇到路径循环 | 263 | ENAMETOOLONG | 路径名过长 | 264 | ENOENT | 目标文件或目录不存在 | 265 | ENODIR | 检索期间发现非目录项 | 266 | ENOMEM | 系统内存不足 | 267 | EFAULT | 错误的地址 | 268 | ENAMETOOLONG | 路径过长 | 269 +--------------+------------------------+ 270 */ 271 extern uint64_t sys_chdir(struct pt_regs *regs); 272 273 /** 274 * @brief 获取目录中的数据 275 * 276 * @param fd 文件描述符号 277 * @return uint64_t dirent的总大小 278 */ 279 extern uint64_t sys_getdents(struct pt_regs *regs); 280 281 /** 282 * @brief 执行新的程序 283 * 284 * @param user_path(r8寄存器) 文件路径 285 * @param argv(r9寄存器) 参数列表 286 * @return uint64_t 287 */ 288 uint64_t sys_execve(struct pt_regs *regs) 289 { 290 291 char *user_path = (char *)regs->r8; 292 char **argv = (char **)regs->r9; 293 294 int path_len = strnlen_user(user_path, PAGE_4K_SIZE); 295 296 if (path_len >= PAGE_4K_SIZE) 297 return -ENAMETOOLONG; 298 else if (path_len <= 0) 299 return -EFAULT; 300 301 char *path = (char *)kmalloc(path_len + 1, 0); 302 if (path == NULL) 303 return -ENOMEM; 304 305 memset(path, 0, path_len + 1); 306 307 // 拷贝文件路径 308 strncpy_from_user(path, user_path, path_len); 309 path[path_len] = '\0'; 310 311 // 执行新的程序 312 uint64_t retval = do_execve(regs, path, argv, NULL); 313 314 kfree(path); 315 return retval; 316 } 317 318 /** 319 * @brief 等待进程退出 320 * 321 * @param pid 目标进程id 322 * @param status 返回的状态信息 323 * @param options 等待选项 324 * @param rusage 325 * @return uint64_t 326 */ 327 uint64_t sys_wait4(struct pt_regs *regs) 328 { 329 uint64_t pid = regs->r8; 330 int *status = (int *)regs->r9; 331 int options = regs->r10; 332 void *rusage = (void *)regs->r11; 333 334 struct process_control_block *proc = NULL; 335 struct process_control_block *child_proc = NULL; 336 337 // 查找pid为指定值的进程 338 // ps: 这里判断子进程的方法没有按照posix 2008来写。 339 // todo: 根据进程树判断是否为当前进程的子进程 340 // todo: 当进程管理模块拥有pcblist_lock之后,调用之前,应当对其加锁 341 child_proc = process_find_pcb_by_pid(pid); 342 343 if (child_proc == NULL) 344 return -ECHILD; 345 346 // 暂时不支持options选项,该值目前必须为0 347 if (options != 0) 348 return -EINVAL; 349 350 // 如果子进程没有退出,则等待其退出 351 // BUG: 这里存在问题,由于未对进程管理模块加锁,因此可能会出现子进程退出后,父进程还在等待的情况 352 // (子进程退出后,process_exit_notify消息丢失) 353 while (child_proc->state != PROC_ZOMBIE) 354 wait_queue_sleep_on_interriptible(¤t_pcb->wait_child_proc_exit); 355 356 // 拷贝子进程的返回码 357 if (likely(status != NULL)) 358 *status = child_proc->exit_code; 359 // copy_to_user(status, (void*)child_proc->exit_code, sizeof(int)); 360 361 process_release_pcb(child_proc); 362 return 0; 363 } 364 365 /** 366 * @brief 进程退出 367 * 368 * @param exit_code 退出返回码 369 * @return uint64_t 370 */ 371 uint64_t sys_exit(struct pt_regs *regs) 372 { 373 return process_do_exit(regs->r8); 374 } 375 376 uint64_t sys_nanosleep(struct pt_regs *regs) 377 { 378 const struct timespec *rqtp = (const struct timespec *)regs->r8; 379 struct timespec *rmtp = (struct timespec *)regs->r9; 380 381 return rs_nanosleep(rqtp, rmtp); 382 } 383 384 ul sys_ahci_end_req(struct pt_regs *regs) 385 { 386 // ahci_end_request(); 387 return 0; 388 } 389 390 // 系统调用的内核入口程序 391 void do_syscall_int(struct pt_regs *regs, unsigned long error_code) 392 { 393 ul ret = system_call_table[regs->rax](regs); 394 regs->rax = ret; // 返回码 395 } 396 uint64_t sys_pipe(struct pt_regs *regs) 397 { 398 return -ENOTSUP; 399 } 400 401 extern uint64_t sys_mkdir(struct pt_regs *regs); 402 403 extern int sys_dup(int oldfd); 404 extern int sys_dup2(int oldfd, int newfd); 405 406 system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = { 407 [0] = system_call_not_exists, 408 [1] = sys_put_string, 409 [2] = sys_open, 410 [3] = sys_close, 411 [4] = sys_read, 412 [5] = sys_write, 413 [6] = sys_lseek, 414 [7] = sys_fork, 415 [8] = sys_vfork, 416 [9] = sys_brk, 417 [10] = sys_sbrk, 418 [11] = sys_reboot, 419 [12] = sys_chdir, 420 [13] = sys_getdents, 421 [14] = sys_execve, 422 [15] = sys_wait4, 423 [16] = sys_exit, 424 [17] = sys_mkdir, 425 [18] = sys_nanosleep, 426 [19] = sys_clock, 427 [20] = sys_pipe, 428 [21] = sys_mstat, 429 [22] = sys_unlink_at, 430 [23] = sys_kill, 431 [24] = sys_sigaction, 432 [25] = sys_rt_sigreturn, 433 [26] = sys_getpid, 434 [27] = sys_sched, 435 [28] = sys_dup, 436 [29] = sys_dup2, 437 [30 ... 255] = system_call_not_exists, 438 }; 439