diff --git a/.vscode/settings.json b/.vscode/settings.json index 821a1f3c..fd29ea56 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -99,7 +99,8 @@ "arch.h": "c", "elf.h": "c", "stdio.h": "c", - "wait_queue.h": "c" + "wait_queue.h": "c", + "stddef.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "" diff --git a/kernel/common/printk.c b/kernel/common/printk.c index 073ffff2..e9f41e3d 100644 --- a/kernel/common/printk.c +++ b/kernel/common/printk.c @@ -119,6 +119,7 @@ void auto_newline() if (pos.x > pos.max_x) { #ifdef DEBUG + uart_send(COM1, '\r'); uart_send(COM1, '\n'); #endif pos.x = 0; @@ -127,6 +128,7 @@ void auto_newline() if (pos.y > pos.max_y) { #ifdef DEBUG + uart_send(COM1, '\r'); uart_send(COM1, '\n'); #endif pos.y = pos.max_y; diff --git a/user/Makefile b/user/Makefile index 36faedf4..74a4d2f4 100644 --- a/user/Makefile +++ b/user/Makefile @@ -24,7 +24,7 @@ all: $(shell if [ ! -e $(tmp_output_dir) ];then mkdir -p $(tmp_output_dir); fi) $(shell if [ ! -e $(output_dir) ];then mkdir -p $(output_dir); fi) - $(MAKE) sys_api_lib +# $(MAKE) sys_api_lib $(MAKE) shell # objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary sys_api_lib $(ROOT_PATH)/bin/user/init.bin #objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 sys_api_lib $(ROOT_PATH)/bin/user/init.bin @@ -35,7 +35,7 @@ sys_api_lib: #ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o $(shell find . -name "*.o") -T init.lds shell: - ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell $(shell find ./apps/shell -name "*.o") $(shell find ./libs -name "*.o") + ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell $(shell find ./apps/shell -name "*.o") $(shell find ./libs -name "*.o") -T ./apps/shell/shell.lds objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/shell $(output_dir)/shell.elf clean: diff --git a/user/apps/shell/Makefile b/user/apps/shell/Makefile index 9c0ffa49..1828179f 100644 --- a/user/apps/shell/Makefile +++ b/user/apps/shell/Makefile @@ -1,4 +1,7 @@ -all: shell.o +all: shell.o cmd.o shell.o: shell.c - gcc $(CFLAGS) -c shell.c -o shell.o \ No newline at end of file + gcc $(CFLAGS) -c shell.c -o shell.o + +cmd.o: cmd.c + gcc $(CFLAGS) -c cmd.c -o cmd.o diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c new file mode 100644 index 00000000..7c0ee951 --- /dev/null +++ b/user/apps/shell/cmd.c @@ -0,0 +1,166 @@ +#include "cmd.h" +#include +#include +#include + +// 当前工作目录(在main_loop中初始化) +char *shell_current_path = NULL; +/** + * @brief shell 内建函数的主命令与处理函数的映射表 + * + */ +struct built_in_cmd_t shell_cmds[] = + { + {"cd", shell_cmd_cd}, + {"cat", shell_cmd_cat}, + {"exec", shell_cmd_exec}, + {"ls", shell_cmd_ls}, + {"mkdir", shell_cmd_mkdir}, + {"pwd", shell_cmd_pwd}, + {"rm", shell_cmd_rm}, + {"rmdir", shell_cmd_rmdir}, + {"reboot", shell_cmd_reboot}, + {"touch", shell_cmd_touch}, + +}; +// 总共的内建命令数量 +const static int total_built_in_cmd_num = sizeof(shell_cmds) / sizeof(struct built_in_cmd_t); + +/** + * @brief 寻找对应的主命令编号 + * + * @param main_cmd 主命令 + * @return int 成功:主命令编号 + * 失败: -1 + */ +int shell_find_cmd(char *main_cmd) +{ + + for (int i = 0; i < total_built_in_cmd_num; ++i) + { + if (strcmp(main_cmd, shell_cmds[i].name) == 0) // 找到对应的命令号 + return i; + } + // 找不到该命令 + return -1; +} + +/** + * @brief 运行shell内建的命令 + * + * @param index 主命令编号 + * @param argc 参数数量 + * @param argv 参数列表 + */ +void shell_run_built_in_command(int index, int argc, char **argv) +{ + if (index >= total_built_in_cmd_num) + return; + // printf("run built-in command : %s\n", shell_cmds[index].name); + + shell_cmds[index].func(argc, argv); +} + +/** + * @brief cd命令:进入文件夹 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_cd(int argc, char **argv) {} + +/** + * @brief 查看文件夹下的文件列表 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_ls(int argc, char **argv) {} + +/** + * @brief 显示当前工作目录的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_pwd(int argc, char **argv) +{ + if (shell_current_path) + printf("%s\n", shell_current_path); +} + +/** + * @brief 查看文件内容的命令 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_cat(int argc, char **argv) {} + +/** + * @brief 创建空文件的命令 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_touch(int argc, char **argv) {} + +/** + * @brief 删除命令 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_rm(int argc, char **argv) {} + +/** + * @brief 创建文件夹的命令 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_mkdir(int argc, char **argv) {} + +/** + * @brief 删除文件夹的命令 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_rmdir(int argc, char **argv) {} + +/** + * @brief 执行新的程序的命令 + * + * @param argc + * @param argv + * @return int + */ + +// todo: +int shell_cmd_exec(int argc, char **argv) {} + +/** + * @brief 重启命令 + * + * @param argc + * @param argv + * @return int + */ +// todo: +int shell_cmd_reboot(int argc, char **argv) {} \ No newline at end of file diff --git a/user/apps/shell/cmd.h b/user/apps/shell/cmd.h new file mode 100644 index 00000000..0cbe9eef --- /dev/null +++ b/user/apps/shell/cmd.h @@ -0,0 +1,120 @@ +#pragma once + +/** + * @brief shell内建命令结构体 + * + */ +struct built_in_cmd_t +{ + char *name; + int (*func)(int argc, char **argv); +}; + +extern struct built_in_cmd_t shell_cmds[]; +/** + * @brief 寻找对应的主命令编号 + * + * @param main_cmd 主命令 + * @return int 主命令编号 + */ +int shell_find_cmd(char *main_cmd); + + +/** + * @brief 运行shell内建的命令 + * + * @param index 主命令编号 + * @param argc 参数数量 + * @param argv 参数列表 + */ +void shell_run_built_in_command(int index, int argc, char **argv); + +/** + * @brief cd命令:进入文件夹 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_cd(int argc, char **argv); + +/** + * @brief 查看文件夹下的文件列表 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_ls(int argc, char **argv); + +/** + * @brief 显示当前工作目录的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_pwd(int argc, char **argv); + +/** + * @brief 查看文件内容的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_cat(int argc, char **argv); + +/** + * @brief 创建空文件的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_touch(int argc, char **argv); + +/** + * @brief 删除命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_rm(int argc, char **argv); + +/** + * @brief 创建文件夹的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_mkdir(int argc, char **argv); + +/** + * @brief 删除文件夹的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_rmdir(int argc, char **argv); + +/** + * @brief 执行新的程序的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_exec(int argc, char **argv); + +/** + * @brief 重启命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_reboot(int argc, char **argv); diff --git a/user/apps/shell/shell.c b/user/apps/shell/shell.c index 2fb665dc..6a26d17f 100644 --- a/user/apps/shell/shell.c +++ b/user/apps/shell/shell.c @@ -3,81 +3,159 @@ #include #include #include -int main() +#include +#include + +#include "cmd.h" + +#define pause_cpu() asm volatile("pause\n\t"); + +/** + * @brief 循环读取每一行 + * + * @param fd 键盘文件描述符 + * @param buf 输入缓冲区 + * @return 读取的字符数 + */ +#define INPUT_BUFFER_SIZE 512 +int shell_readline(int fd, char *buf); + +extern char *shell_current_path; + +/** + * @brief 解析shell命令 + * + * @param buf 输入缓冲区 + * @param argc 返回值:参数数量 + * @param argv 返回值:参数列表 + * @return int + */ +int parse_command(char *buf, int *argc, char ***argv); + +/** + * @brief shell主循环 + * + * @param kb_fd 键盘文件描述符 + */ +static void main_loop(int kb_fd) { - char string[] = "/333.txt"; - uint8_t buf[128] = {0}; - char tips_str[] = "The first application 'init.bin' started successfully!\n"; - put_string(tips_str, COLOR_GREEN, COLOR_BLACK); + unsigned char input_buffer[INPUT_BUFFER_SIZE] = {0}; - printf("test printf: %s size: %d\n", string, sizeof(string)); + // 初始化当前工作目录的路径 + shell_current_path = (char *)malloc(256); + memset(shell_current_path, 0, 256); + shell_current_path = "/"; - char kb_file_path[] = "/dev/keyboard.dev"; - int kb_fd = open(kb_file_path, 0); - printf("keyboard fd = %d\n", kb_fd); + // shell命令行的主循环 while (true) { - int key = keyboard_analyze_keycode(kb_fd); - if(key) - printf("%c", (char)key); + int argc = 0; + char **argv; + + printf("[DragonOS] # "); + memset(input_buffer, 0, INPUT_BUFFER_SIZE); + + // 循环读取每一行到buffer + shell_readline(kb_fd, input_buffer); + + int cmd_num = parse_command(input_buffer, &argc, &argv); + printf("\n"); + if (cmd_num >= 0) + shell_run_built_in_command(cmd_num, argc, argv); + } - - - /* - int fd = open(string, 0); - printf("fd=%d\n", fd); +} - read(fd, buf, 128); +int main() +{ + // 打开键盘文件 + char kb_file_path[] = "/dev/keyboard.dev"; + int kb_fd = open(kb_file_path, 0); + // printf("keyboard fd = %d\n", kb_fd); - put_string(buf, COLOR_ORANGE, COLOR_BLACK); - - lseek(fd, 0, SEEK_SET); - write(fd, tips_str, sizeof(tips_str)-1); - lseek(fd, 0, SEEK_SET); - - // 由于暂时没有实现用户态的memset,因此先手动清零 - for(int i=0;i<128;++i) - buf[i] = 0; - - read(fd, buf, 128); - put_string(buf, COLOR_YELLOW, COLOR_BLACK); - close(fd); - - - void *ptr[256] = {0}; - for (int k = 0; k < 2; ++k) - { - printf("try to malloc 256*1M=256MB\n"); - uint64_t js = 0; - for (int i = 0; i < 256; ++i) - { - ptr[i] = malloc(1024 * 1024); - js += *(uint64_t *)((uint64_t)(ptr[i]) - sizeof(uint64_t)); - // if (*(uint64_t *)((uint64_t)(ptr[i]) - sizeof(uint64_t)) > 0x4008) - // printf("[%ld] start_addr = %#018lx, len = %#010lx\n", i, (uint64_t)(ptr[i]) - 8, *(uint64_t *)((uint64_t)(ptr[i]) - sizeof(uint64_t))); - } - - // printf("ptr[0]->len=%lld\n", *(uint64_t *)((uint64_t)ptr[0] - sizeof(uint64_t))); - // printf("ptr[1]->len=%lld\n", *(uint64_t *)((uint64_t)ptr[1] - sizeof(uint64_t))); - // printf("ptr[24]->len=%lld\n", *(uint64_t*)((uint64_t)ptr[24] - sizeof(uint64_t))); - printf("alloc done. total used: %lld bytes\n", js); - printf("try to free...\n"); - for (int i = 0; i < 256; ++i) - { - free(ptr[i]); - } - printf("free done!\n"); - } - */ - - - // *p = 'a'; - /* - pid_t p = fork(); - if(p == 0) - put_string("subproc\n", COLOR_PURPLE, COLOR_BLACK); - else put_string("parent proc\n", COLOR_ORANGE, COLOR_BLACK); -*/ + main_loop(kb_fd); while (1) ; +} + +/** + * @brief 循环读取每一行 + * + * @param fd 键盘文件描述符 + * @param buf 输入缓冲区 + * @return 读取的字符数 + */ +int shell_readline(int fd, char *buf) +{ + int key = 0; + int count = 0; + + while (1) + { + key = keyboard_analyze_keycode(fd); + if (key == '\n') + return count; + + if (key) + { + buf[count++] = key; + printf("%c", key); + } + + // 输入缓冲区满了之后,直接返回 + if (count >= INPUT_BUFFER_SIZE - 1) + return count; + + pause_cpu(); + } +} + +/** + * @brief 解析shell命令 + * + * @param buf 输入缓冲区 + * @param argc 返回值:参数数量 + * @param argv 返回值:参数列表 + * @return int 主命令的编号 + */ +int parse_command(char *buf, int *argc, char ***argv) +{ + int index = 0; // 当前访问的是buf的第几位 + // 去除命令前导的空格 + while (index < INPUT_BUFFER_SIZE && buf[index] == ' ') + ++index; + + // 计算参数数量 + for (int i = index; i < INPUT_BUFFER_SIZE - 1; ++i) + { + // 到达了字符串末尾 + if (!buf[i]) + break; + if (buf[i] != ' ' && (buf[i + 1] == ' ' || buf[i + 1] == '\0')) + ++(*argc); + } + + // printf("\nargc=%d\n", *argc); + + // 为指向每个指令的指针分配空间 + *argv = (char **)malloc(sizeof(char **) * (*argc)); + memset(*argv, 0, sizeof(char **) * (*argc)); + + // 将每个命令都单独提取出来 + for (int i = 0; i < *argc && index < INPUT_BUFFER_SIZE; ++i) + { + // 提取出命令,以空格作为分割 + *((*argv) + i) = &buf[index]; + while (index < INPUT_BUFFER_SIZE - 1 && buf[index] && buf[index] != ' ') + ++index; + buf[index++] = '\0'; + + // 删除命令间多余的空格 + while (index < INPUT_BUFFER_SIZE && buf[index] == ' ') + ++index; + + // printf("%s\n", (*argv)[i]); + } + // 以第一个命令作为主命令,查找其在命令表中的编号 + return shell_find_cmd(**argv); } \ No newline at end of file diff --git a/user/apps/shell/shell.lds b/user/apps/shell/shell.lds index d5888a55..0074c8a2 100644 --- a/user/apps/shell/shell.lds +++ b/user/apps/shell/shell.lds @@ -13,7 +13,7 @@ SECTIONS { _text = .; - init.o(.text) + *(.text) _etext = .; } diff --git a/user/libs/libc/string.h b/user/libs/libc/string.h index c11a74f0..404e394f 100644 --- a/user/libs/libc/string.h +++ b/user/libs/libc/string.h @@ -34,4 +34,35 @@ size_t strlen(const char *s) ++__res; } return __res; +} + + +/* + 比较字符串 FirstPart and SecondPart + FirstPart = SecondPart => 0 + FirstPart > SecondPart => 1 + FirstPart < SecondPart => -1 +*/ + +int strcmp(const char *FirstPart, const char *SecondPart) +{ + register int __res; + __asm__ __volatile__("cld \n\t" + "1: \n\t" + "lodsb \n\t" + "scasb \n\t" + "jne 2f \n\t" + "testb %%al, %%al \n\t" + "jne 1b \n\t" + "xorl %%eax, %%eax \n\t" + "jmp 3f \n\t" + "2: \n\t" + "movl $1, %%eax \n\t" + "jl 3f \n\t" + "negl %%eax \n\t" + "3: \n\t" + : "=a"(__res) + : "D"(FirstPart), "S"(SecondPart) + :); + return __res; } \ No newline at end of file