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 <filesystem/fat32/fat32.h> 11 #include <mm/slab.h> 12 #include <process/process.h> 13 #include <time/sleep.h> 14 // 导出系统调用入口函数,定义在entry.S中 15 extern void system_call(void); 16 extern void syscall_int(void); 17 18 extern uint64_t sys_clock(struct pt_regs *regs); 19 extern uint64_t sys_mstat(struct pt_regs *regs); 20 extern uint64_t sys_open(struct pt_regs *regs); 21 extern uint64_t sys_unlink_at(struct pt_regs *regs); 22 extern uint64_t sys_kill(struct pt_regs *regs); 23 extern uint64_t sys_sigaction(struct pt_regs * regs); 24 extern uint64_t sys_rt_sigreturn(struct pt_regs * regs); 25 extern uint64_t sys_getpid(struct pt_regs * regs); 26 27 /** 28 * @brief 导出系统调用处理函数的符号 29 * 30 */ 31 32 /** 33 * @brief 系统调用不存在时的处理函数 34 * 35 * @param regs 进程3特权级下的寄存器 36 * @return ul 37 */ 38 ul system_call_not_exists(struct pt_regs *regs) 39 { 40 kerror("System call [ ID #%d ] not exists.", regs->rax); 41 return ESYSCALL_NOT_EXISTS; 42 } // 取消前述宏定义 43 44 /** 45 * @brief 重新定义为:把系统调用函数加入系统调用表 46 * @param syscall_num 系统调用号 47 * @param symbol 系统调用处理函数 48 */ 49 #define SYSCALL_COMMON(syscall_num, symbol) [syscall_num] = symbol, 50 51 /** 52 * @brief sysenter的系统调用函数,从entry.S中跳转到这里 53 * 54 * @param regs 3特权级下的寄存器值,rax存储系统调用号 55 * @return ul 对应的系统调用函数的地址 56 */ 57 ul system_call_function(struct pt_regs *regs) 58 { 59 return system_call_table[regs->rax](regs); 60 } 61 62 /** 63 * @brief 初始化系统调用模块 64 * 65 */ 66 void syscall_init() 67 { 68 kinfo("Initializing syscall..."); 69 70 set_system_trap_gate(0x80, 0, syscall_int); // 系统调用门 71 } 72 73 /** 74 * @brief 通过中断进入系统调用 75 * 76 * @param syscall_id 77 * @param arg0 78 * @param arg1 79 * @param arg2 80 * @param arg3 81 * @param arg4 82 * @param arg5 83 * @param arg6 84 * @param arg7 85 * @return long 86 */ 87 88 long enter_syscall_int(ul syscall_id, ul arg0, ul arg1, ul arg2, ul arg3, ul arg4, ul arg5, ul arg6, ul arg7) 89 { 90 long err_code; 91 __asm__ __volatile__("movq %2, %%r8 \n\t" 92 "movq %3, %%r9 \n\t" 93 "movq %4, %%r10 \n\t" 94 "movq %5, %%r11 \n\t" 95 "movq %6, %%r12 \n\t" 96 "movq %7, %%r13 \n\t" 97 "movq %8, %%r14 \n\t" 98 "movq %9, %%r15 \n\t" 99 "int $0x80 \n\t" 100 : "=a"(err_code) 101 : "a"(syscall_id), "m"(arg0), "m"(arg1), "m"(arg2), "m"(arg3), "m"(arg4), "m"(arg5), "m"(arg6), 102 "m"(arg7) 103 : "memory", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "rcx", "rdx"); 104 105 return err_code; 106 } 107 108 /** 109 * @brief 打印字符串的系统调用 110 * 111 * 当arg1和arg2均为0时,打印黑底白字,否则按照指定的前景色和背景色来打印 112 * 113 * @param regs 寄存器 114 * @param arg0 要打印的字符串 115 * @param arg1 前景色 116 * @param arg2 背景色 117 * @return ul 返回值 118 */ 119 ul sys_put_string(struct pt_regs *regs) 120 { 121 122 printk_color(regs->r9, regs->r10, (char *)regs->r8); 123 // printk_color(BLACK, WHITE, (char *)regs->r8); 124 125 return 0; 126 } 127 128 /** 129 * @brief 关闭文件系统调用 130 * 131 * @param fd_num 文件描述符号 132 * 133 * @param regs 134 * @return uint64_t 135 */ 136 uint64_t sys_close(struct pt_regs *regs) 137 { 138 int fd_num = (int)regs->r8; 139 140 // kdebug("sys close: fd=%d", fd_num); 141 return vfs_close(fd_num); 142 } 143 144 /** 145 * @brief 从文件中读取数据 146 * 147 * @param fd_num regs->r8 文件描述符号 148 * @param buf regs->r9 输出缓冲区 149 * @param count regs->r10 要读取的字节数 150 * 151 * @return uint64_t 152 */ 153 uint64_t sys_read(struct pt_regs *regs) 154 { 155 int fd_num = (int)regs->r8; 156 void *buf = (void *)regs->r9; 157 int64_t count = (int64_t)regs->r10; 158 159 // 校验buf的空间范围 160 if (SYSCALL_FROM_USER(regs) && (!verify_area((uint64_t)buf, count))) 161 return -EPERM; 162 163 // kdebug("sys read: fd=%d", fd_num); 164 165 // 校验文件描述符范围 166 if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) 167 return -EBADF; 168 169 // 文件描述符不存在 170 if (current_pcb->fds[fd_num] == NULL) 171 return -EBADF; 172 173 if (count < 0) 174 return -EINVAL; 175 176 struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; 177 uint64_t ret = 0; 178 if (file_ptr->file_ops && file_ptr->file_ops->read) 179 ret = file_ptr->file_ops->read(file_ptr, (char *)buf, count, &(file_ptr->position)); 180 181 return ret; 182 } 183 184 /** 185 * @brief 向文件写入数据 186 * 187 * @param fd_num regs->r8 文件描述符号 188 * @param buf regs->r9 输入缓冲区 189 * @param count regs->r10 要写入的字节数 190 * 191 * @return uint64_t 192 */ 193 uint64_t sys_write(struct pt_regs *regs) 194 { 195 int fd_num = (int)regs->r8; 196 void *buf = (void *)regs->r9; 197 int64_t count = (int64_t)regs->r10; 198 199 // 校验buf的空间范围 200 if (SYSCALL_FROM_USER(regs) && (!verify_area((uint64_t)buf, count))) 201 return -EPERM; 202 kdebug("sys write: fd=%d", fd_num); 203 204 // 校验文件描述符范围 205 if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) 206 return -EBADF; 207 208 // 文件描述符不存在 209 if (current_pcb->fds[fd_num] == NULL) 210 return -EBADF; 211 212 if (count < 0) 213 return -EINVAL; 214 215 struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; 216 uint64_t ret = 0; 217 if (file_ptr->file_ops && file_ptr->file_ops->write) 218 ret = file_ptr->file_ops->write(file_ptr, (char *)buf, count, &(file_ptr->position)); 219 220 return ret; 221 } 222 223 /** 224 * @brief 调整文件的访问位置 225 * 226 * @param fd_num 文件描述符号 227 * @param offset 偏移量 228 * @param whence 调整模式 229 * @return uint64_t 调整结束后的文件访问位置 230 */ 231 uint64_t sys_lseek(struct pt_regs *regs) 232 { 233 int fd_num = (int)regs->r8; 234 long offset = (long)regs->r9; 235 int whence = (int)regs->r10; 236 237 // kdebug("sys_lseek: fd=%d", fd_num); 238 uint64_t retval = 0; 239 240 // 校验文件描述符范围 241 if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) 242 return -EBADF; 243 244 // 文件描述符不存在 245 if (current_pcb->fds[fd_num] == NULL) 246 return -EBADF; 247 248 struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; 249 if (file_ptr->file_ops && file_ptr->file_ops->lseek) 250 retval = file_ptr->file_ops->lseek(file_ptr, offset, whence); 251 252 return retval; 253 } 254 255 uint64_t sys_fork(struct pt_regs *regs) 256 { 257 return do_fork(regs, 0, regs->rsp, 0); 258 } 259 uint64_t sys_vfork(struct pt_regs *regs) 260 { 261 return do_fork(regs, CLONE_VM | CLONE_FS | CLONE_SIGNAL, regs->rsp, 0); 262 } 263 264 /** 265 * @brief 将堆内存调整为arg0 266 * 267 * @param arg0 新的堆区域的结束地址 268 * arg0=-1 ===> 返回堆区域的起始地址 269 * arg0=-2 ===> 返回堆区域的结束地址 270 * @return uint64_t 错误码 271 * 272 */ 273 uint64_t sys_brk(struct pt_regs *regs) 274 { 275 uint64_t new_brk = PAGE_2M_ALIGN(regs->r8); 276 277 // kdebug("sys_brk input= %#010lx , new_brk= %#010lx bytes current_pcb->mm->brk_start=%#018lx 278 // current->end_brk=%#018lx", regs->r8, new_brk, current_pcb->mm->brk_start, current_pcb->mm->brk_end); 279 280 if ((int64_t)regs->r8 == -1) 281 { 282 // kdebug("get brk_start=%#018lx", current_pcb->mm->brk_start); 283 return current_pcb->mm->brk_start; 284 } 285 if ((int64_t)regs->r8 == -2) 286 { 287 // kdebug("get brk_end=%#018lx", current_pcb->mm->brk_end); 288 return current_pcb->mm->brk_end; 289 } 290 if (new_brk > current_pcb->addr_limit) // 堆地址空间超过限制 291 return -ENOMEM; 292 293 int64_t offset; 294 if (new_brk >= current_pcb->mm->brk_end) 295 offset = (int64_t)(new_brk - current_pcb->mm->brk_end); 296 else 297 offset = -(int64_t)(current_pcb->mm->brk_end - new_brk); 298 299 new_brk = mm_do_brk(current_pcb->mm->brk_end, offset); // 扩展堆内存空间 300 301 current_pcb->mm->brk_end = new_brk; 302 return 0; 303 } 304 305 /** 306 * @brief 将堆内存空间加上offset(注意,该系统调用只应在普通进程中调用,而不能是内核线程) 307 * 308 * @param arg0 offset偏移量 309 * @return uint64_t the previous program break 310 */ 311 uint64_t sys_sbrk(struct pt_regs *regs) 312 { 313 uint64_t retval = current_pcb->mm->brk_end; 314 if ((int64_t)regs->r8 > 0) 315 { 316 317 uint64_t new_brk = PAGE_2M_ALIGN(retval + regs->r8); 318 if (new_brk > current_pcb->addr_limit) // 堆地址空间超过限制 319 { 320 kdebug("exceed mem limit, new_brk = %#018lx", new_brk); 321 return -ENOMEM; 322 } 323 } 324 else 325 { 326 if ((__int128_t)current_pcb->mm->brk_end + (__int128_t)regs->r8 < current_pcb->mm->brk_start) 327 return retval; 328 } 329 // kdebug("do brk"); 330 uint64_t new_brk = mm_do_brk(current_pcb->mm->brk_end, (int64_t)regs->r8); // 调整堆内存空间 331 // kdebug("do brk done, new_brk = %#018lx", new_brk); 332 current_pcb->mm->brk_end = new_brk; 333 return retval; 334 } 335 336 /** 337 * @brief 重启计算机 338 * 339 * @return 340 */ 341 uint64_t sys_reboot(struct pt_regs *regs) 342 { 343 // 重启计算机 344 io_out8(0x64, 0xfe); 345 346 return 0; 347 } 348 349 /** 350 * @brief 切换工作目录 351 * 352 * @param dest_path 目标路径 353 * @return 354 +--------------+------------------------+ 355 | 返回码 | 描述 | 356 +--------------+------------------------+ 357 | 0 | 成功 | 358 | EACCESS | 权限不足 | 359 | ELOOP | 解析path时遇到路径循环 | 360 | ENAMETOOLONG | 路径名过长 | 361 | ENOENT | 目标文件或目录不存在 | 362 | ENODIR | 检索期间发现非目录项 | 363 | ENOMEM | 系统内存不足 | 364 | EFAULT | 错误的地址 | 365 | ENAMETOOLONG | 路径过长 | 366 +--------------+------------------------+ 367 */ 368 uint64_t sys_chdir(struct pt_regs *regs) 369 { 370 char *dest_path = (char *)regs->r8; 371 // kdebug("dest_path=%s", dest_path); 372 // 检查目标路径是否为NULL 373 if (dest_path == NULL) 374 return -EFAULT; 375 376 // 计算输入的路径长度 377 int dest_path_len; 378 if (user_mode(regs)) 379 { 380 dest_path_len = strnlen_user(dest_path, PAGE_4K_SIZE); 381 } 382 else 383 dest_path_len = strnlen(dest_path, PAGE_4K_SIZE); 384 385 // 长度小于等于0 386 if (dest_path_len <= 0) 387 return -EFAULT; 388 else if (dest_path_len >= PAGE_4K_SIZE) 389 return -ENAMETOOLONG; 390 391 // 为路径字符串申请空间 392 char *path = kmalloc(dest_path_len + 1, 0); 393 // 系统内存不足 394 if (path == NULL) 395 return -ENOMEM; 396 397 memset(path, 0, dest_path_len + 1); 398 if (regs->cs & USER_CS) 399 { 400 // 将字符串从用户空间拷贝进来, +1是为了拷贝结尾的\0 401 strncpy_from_user(path, dest_path, dest_path_len + 1); 402 } 403 else 404 strncpy(path, dest_path, dest_path_len + 1); 405 // kdebug("chdir: path = %s", path); 406 struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0); 407 408 kfree(path); 409 410 if (dentry == NULL) 411 return -ENOENT; 412 // kdebug("dentry->name=%s, namelen=%d", dentry->name, dentry->name_length); 413 // 目标不是目录 414 if (dentry->dir_inode->attribute != VFS_IF_DIR) 415 return -ENOTDIR; 416 417 return 0; 418 } 419 420 /** 421 * @brief 获取目录中的数据 422 * 423 * @param fd 文件描述符号 424 * @return uint64_t dirent的总大小 425 */ 426 uint64_t sys_getdents(struct pt_regs *regs) 427 { 428 int fd = (int)regs->r8; 429 void *dirent = (void *)regs->r9; 430 long count = (long)regs->r10; 431 432 if (fd < 0 || fd > PROC_MAX_FD_NUM) 433 return -EBADF; 434 435 if (count < 0) 436 return -EINVAL; 437 438 struct vfs_file_t *filp = current_pcb->fds[fd]; 439 if (filp == NULL) 440 return -EBADF; 441 442 uint64_t retval = 0; 443 if (filp->file_ops && filp->file_ops->readdir) 444 retval = filp->file_ops->readdir(filp, dirent, &vfs_fill_dirent); 445 446 return retval; 447 } 448 449 /** 450 * @brief 执行新的程序 451 * 452 * @param user_path(r8寄存器) 文件路径 453 * @param argv(r9寄存器) 参数列表 454 * @return uint64_t 455 */ 456 uint64_t sys_execve(struct pt_regs *regs) 457 { 458 // kdebug("sys_execve"); 459 char *user_path = (char *)regs->r8; 460 char **argv = (char **)regs->r9; 461 462 int path_len = strnlen_user(user_path, PAGE_4K_SIZE); 463 464 // kdebug("path_len=%d", path_len); 465 if (path_len >= PAGE_4K_SIZE) 466 return -ENAMETOOLONG; 467 else if (path_len <= 0) 468 return -EFAULT; 469 470 char *path = (char *)kmalloc(path_len + 1, 0); 471 if (path == NULL) 472 return -ENOMEM; 473 474 memset(path, 0, path_len + 1); 475 476 // kdebug("before copy file path from user"); 477 // 拷贝文件路径 478 strncpy_from_user(path, user_path, path_len); 479 path[path_len] = '\0'; 480 481 // kdebug("before do_execve, path = %s", path); 482 // 执行新的程序 483 uint64_t retval = do_execve(regs, path, argv, NULL); 484 485 kfree(path); 486 return retval; 487 } 488 489 /** 490 * @brief 等待进程退出 491 * 492 * @param pid 目标进程id 493 * @param status 返回的状态信息 494 * @param options 等待选项 495 * @param rusage 496 * @return uint64_t 497 */ 498 uint64_t sys_wait4(struct pt_regs *regs) 499 { 500 uint64_t pid = regs->r8; 501 int *status = (int *)regs->r9; 502 int options = regs->r10; 503 void *rusage = (void *)regs->r11; 504 505 struct process_control_block *proc = NULL; 506 struct process_control_block *child_proc = NULL; 507 508 // 查找pid为指定值的进程 509 // ps: 这里判断子进程的方法没有按照posix 2008来写。 510 // todo: 根据进程树判断是否为当前进程的子进程 511 // todo: 当进程管理模块拥有pcblist_lock之后,调用之前,应当对其加锁 512 child_proc = process_find_pcb_by_pid(pid); 513 514 if (child_proc == NULL) 515 return -ECHILD; 516 517 // 暂时不支持options选项,该值目前必须为0 518 if (options != 0) 519 return -EINVAL; 520 521 // 如果子进程没有退出,则等待其退出 522 while (child_proc->state != PROC_ZOMBIE) 523 wait_queue_sleep_on_interriptible(¤t_pcb->wait_child_proc_exit); 524 525 // 拷贝子进程的返回码 526 if (likely(status != NULL)) 527 *status = child_proc->exit_code; 528 // copy_to_user(status, (void*)child_proc->exit_code, sizeof(int)); 529 530 process_release_pcb(child_proc); 531 return 0; 532 } 533 534 /** 535 * @brief 进程退出 536 * 537 * @param exit_code 退出返回码 538 * @return uint64_t 539 */ 540 uint64_t sys_exit(struct pt_regs *regs) 541 { 542 return process_do_exit(regs->r8); 543 } 544 545 uint64_t sys_nanosleep(struct pt_regs *regs) 546 { 547 const struct timespec *rqtp = (const struct timespec *)regs->r8; 548 struct timespec *rmtp = (struct timespec *)regs->r9; 549 550 return nanosleep(rqtp, rmtp); 551 } 552 553 ul sys_ahci_end_req(struct pt_regs *regs) 554 { 555 ahci_end_request(); 556 return 0; 557 } 558 559 // 系统调用的内核入口程序 560 void do_syscall_int(struct pt_regs *regs, unsigned long error_code) 561 { 562 563 ul ret = system_call_table[regs->rax](regs); 564 regs->rax = ret; // 返回码 565 } 566 567 system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = { 568 [0] = system_call_not_exists, 569 [1] = sys_put_string, 570 [2] = sys_open, 571 [3] = sys_close, 572 [4] = sys_read, 573 [5] = sys_write, 574 [6] = sys_lseek, 575 [7] = sys_fork, 576 [8] = sys_vfork, 577 [9] = sys_brk, 578 [10] = sys_sbrk, 579 [11] = sys_reboot, 580 [12] = sys_chdir, 581 [13] = sys_getdents, 582 [14] = sys_execve, 583 [15] = sys_wait4, 584 [16] = sys_exit, 585 [17] = sys_mkdir, 586 [18] = sys_nanosleep, 587 [19] = sys_clock, 588 [20] = sys_pipe, 589 [21] = sys_mstat, 590 [22] = sys_unlink_at, 591 [23] = sys_kill, 592 [24] = sys_sigaction, 593 [25] = sys_rt_sigreturn, 594 [26] = sys_getpid, 595 [27 ... 254] = system_call_not_exists, 596 [255] = sys_ahci_end_req, 597 }; 598