commit 62575faf4309bd77d0ca9a032d6d2ad018845a04 Author: xiaoyi1212 Date: Tue Apr 9 23:46:56 2024 +0800 实现多进程 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93faeea --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.vscode/ + +i686_elf_tools/ + +cmake-build-debug/ + +isodir/ \ No newline at end of file diff --git a/boot/boot.asm b/boot/boot.asm new file mode 100644 index 0000000..85cda49 --- /dev/null +++ b/boot/boot.asm @@ -0,0 +1,33 @@ + +.set ALIGN, 1<<0 +.set MEMINFO, 1<<1 +.set FLAGS, ALIGN | MEMINFO +.set MAGIC, 0x1BADB002 +.set CHECKSUM, -(MAGIC + FLAGS) + +.section .multiboot +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +.section .bss +.align 16 +stack_bottom: +.skip 16384 # 16 KiB +stack_top: + +.section .text +.global _start +.type _start, @function +_start: + + mov $stack_top, %esp + + call kernel_main + + cli +1: hlt + jmp 1b + +.size _start, . - _start \ No newline at end of file diff --git a/boot/interrupt.asm b/boot/interrupt.asm new file mode 100644 index 0000000..cd1febc --- /dev/null +++ b/boot/interrupt.asm @@ -0,0 +1,128 @@ +%macro ISR_NOERRCODE 1 ; nasm宏:定义ISR_NOERRCODE,接收一个参数 +[global isr%1] ; %1代表第一个参数 +isr%1: + cli + push byte 0 + push %1 + jmp isr_common_stub +%endmacro + +%macro ISR_ERRCODE 1 +[global isr%1] +isr%1: + cli + push %1 + jmp isr_common_stub +%endmacro + +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_ERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_ERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 + +[extern isr_handler] ; 将会在isr.c中被定义 + +; 通用中断处理程序 +isr_common_stub: + pusha ; 存储所有寄存器 + + mov ax, ds + push eax ; 存储ds + + mov ax, 0x10 ; 将内核数据段赋值给各段 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + call isr_handler ; 调用C语言处理函数 + pop eax ; 恢复各段 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; 弹出所有寄存器 + + add esp, 8 ; 弹出错误码和中断ID + iret ; 从中断返回 + +%macro IRQ 2 +global irq%1 +irq%1: + cli + push byte 0 + push %2 + jmp irq_common_stub +%endmacro + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +[extern irq_handler] +; 通用中断处理程序 +irq_common_stub: + pusha ; 存储所有寄存器 + + mov ax, ds + push eax ; 存储ds + + mov ax, 0x10 ; 将内核数据段赋值给各段 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + call irq_handler ; 调用C语言处理函数 + + pop eax ; 恢复各段 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; 弹出所有寄存器 + + add esp, 8 ; 弹出错误码和中断ID + iret ; 从中断返回 \ No newline at end of file diff --git a/boot/io.asm b/boot/io.asm new file mode 100644 index 0000000..f3e9a0b --- /dev/null +++ b/boot/io.asm @@ -0,0 +1,142 @@ +section .data + +global io_hlt, io_cli, io_sti, io_stihlt +global io_in8, io_in16, io_in32 +global io_out8, io_out16, io_out32 +global io_load_eflags, io_store_eflags +global load_gdtr, load_idtr +global tss_flush, gdt_flush, switch_to + +section .text + +switch_to: + mov eax, [esp+4] + + mov [eax+0], esp + mov [eax+4], ebp + mov [eax+8], ebx + mov [eax+12], esi + mov [eax+16], edi + pushf + pop ecx + mov [eax+20], ecx + + mov eax, [esp+8] + + mov esp, [eax+0] + mov ebp, [eax+4] + mov ebx, [eax+8] + mov esi, [eax+12] + mov edi, [eax+16] + mov eax, [eax+20] + push eax + popf + + ret + +[global read_port] + +read_port: + mov edx, [esp + 4] + in al, dx + ret + +[global idt_flush] + +idt_flush: ; void idt_flush(uint32_t); + mov eax, [esp + 4] + lidt [eax] + ret + +[global gdt_flush] + +gdt_flush: ; void gdt_flush(uint32_t gdtr); + mov eax, [esp + 4] ; [esp+4]按规定是第一个参数,即gdtr + lgdt [eax] ; 加载新gdt指针,传入的是地址 + + mov ax, 0x10 ; 新数据段 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax ; 各数据段全部划给这一数据段 + jmp 0x08:.flush ; cs没法mov,只能用farjmp/farcall,这里用farjmp刷新cs +.flush: + ret ; 刷新完毕,返回 + +tss_flush: + mov ax, 0x2B + ltr ax + ret + +io_hlt: ; void io_hlt(void); + HLT + RET + +io_cli: ; void io_cli(void); + CLI + RET +io_sti: ; void io_sti(void); + STI + RET +io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET +io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET \ No newline at end of file diff --git a/build.py b/build.py new file mode 100644 index 0000000..a5537c2 --- /dev/null +++ b/build.py @@ -0,0 +1,104 @@ +import os + +gcc = '/i686_elf_tools/bin/i686-elf-gcc.exe -I include/ -std=gnu99 -ffreestanding -O2 -c -Wincompatible-pointer-types' +asm = '/i686_elf_tools/bin/i686-elf-as.exe' +nasm = "nasm -f elf32" +ld = '/i686_elf_tools/bin/i686-elf-ld.exe' + +cd = os.getcwd() # 获取当前执行目录 'D:\CrashPowerDOS-main\' + +out = "target" + + +def clean(): + print("Clean target flolder") + for file in os.listdir(cd + "\\target"): # 遍历指定文件夹下所有文件 + os.remove(cd + "\\target\\" + file) + return 0 + + +def build_boot(): # 构建引导程序 + print("Building boot source code...") + status = True + for file in os.listdir(cd + '\\boot'): + if status and file == 'boot.asm': + cmd = cd + asm + " " + cd + "\\boot\\" + file + " -o " + cd + "\\target\\" + file.split(".")[0] + ".o" + status = False + else: + cmd = nasm + " " + cd + "\\boot\\" + file + " -o " + cd + "\\target\\" + file.split(".")[0] + ".o" + e = os.system(cmd) # os.system 执行命令 e为返回值(非0即不正常退出,可做判断终止构建流程) + if e != 0: + return -1 + return 0 + + +def build_driver(): # 构建内置驱动程序 + print("Building driver source code...") + for file in os.listdir(cd + '\\driver'): + cmd = cd + gcc + " " + "driver\\" + file + " -o " + "target\\" + file.split(".")[0] + ".o" + e = os.system(cmd) + if e != 0: + return -1 + return 0 + + +def build_kernel(): # 构建内核本体 + print("Building kernel source code...") + for file in os.listdir(cd + '\\kernel'): + cmd = cd + gcc + " " + "kernel\\" + file + " -o " + "target\\" + file.split(".")[0] + ".o" + e = os.system(cmd) + if e != 0: + return -1 + return 0 + + +def build_data(): # 构建数据结构实现 + print("Building data source code...") + for file in os.listdir(cd + '\\data'): + cmd = cd + gcc + " " + "data\\" + file + " -o " + "target\\" + file.split(".")[0] + ".o" + e = os.system(cmd) + if e != 0: + return -1 + return 0 + + +def build_sysapp(): # 构建内置系统应用 + print("Building sysapp source code...") + for file in os.listdir(cd + '\\sysapp'): + cmd = cd + gcc + " " + "sysapp\\" + file + " -o " + "target\\" + file.split(".")[0] + ".o" + e = os.system(cmd) + if e != 0: + return -1 + return 0 + + +def linker(): # 交叉编译链接 + print("Linking object files...") + source_file = "" + for file in os.listdir(cd + '\\target'): + source_file = source_file + " target\\" + file + return os.system( + cd + "/i686_elf_tools/bin/i686-elf-gcc.exe -T linker.ld -o isodir\\sys\\kernel.elf -ffreestanding -O2 -nostdlib " + source_file + " -lgcc") + + +clean() +a = build_boot() +if a != 0: + exit(-1) +a = build_driver() +if a != 0: + exit(-1) +a = build_kernel() +if a != 0: + exit(-1) +a = build_data() +if a != 0: + exit(-1) +a = build_sysapp() +if a != 0: + exit(-1) +a = linker() +if a != 0: + exit(-1) +print("Launching i386 vm...") +os.system("qemu-system-i386 -kernel isodir\\sys\\kernel.elf -drive format=qcow2,file=cpos.qcow2") diff --git a/cpos.qcow2 b/cpos.qcow2 new file mode 100644 index 0000000..97c2d7e Binary files /dev/null and b/cpos.qcow2 differ diff --git a/data/queue.c b/data/queue.c new file mode 100644 index 0000000..d6a9338 --- /dev/null +++ b/data/queue.c @@ -0,0 +1,58 @@ +#include "../include/queue.h" +#include "../include/memory.h" +#include "../include/vga.h" +#include "../include/io.h" + +Queue *create_queue() { + Queue *queue = (Queue *) kmalloc(sizeof(Queue)); + queue->phead = NULL; + queue->ptail = NULL; + queue->size = 0; + return queue; +} + +void free_queue(Queue *queue) { + QNode *cur = queue->phead; + while (cur) { + QNode *next = cur->next; + kfree(cur); + cur = next; + } + queue->phead = queue->ptail = NULL; + kfree(queue); +} + +void queue_push(Queue *pq, char x) { + QNode *newnode = (QNode *) kmalloc(sizeof(QNode));//为新节点申请内存空间 + if (newnode == NULL) { + printf("OUT_OF_MEMORY: The kernel memory out of."); + io_cli(); + for (;;)io_hlt(); + } + newnode->data = x; //新节点储存数据 + newnode->next = NULL;//新节点的下一个指向NULL,即新节点作为队尾 + if (pq->phead == NULL)//将新节点入队 + { + pq->phead = pq->ptail = newnode; + pq->phead->next = newnode; + } else { + pq->ptail->next = newnode; + pq->ptail = newnode; + } + pq->size++; +} + +char queue_pop(Queue *pq) { + if (pq->size == 0)return NULL; + QNode *next = pq->phead->next; + kfree(pq->phead); + pq->phead = next; + if (pq->phead == NULL) { + pq->ptail = NULL; + } + pq->size -= 1; + return next->data; +} + + + diff --git a/driver/cmos.c b/driver/cmos.c new file mode 100644 index 0000000..508c04e --- /dev/null +++ b/driver/cmos.c @@ -0,0 +1,113 @@ +#include "../include/cmos.h" +#include "../include/memory.h" +#include "../include/io.h" +#include "../include/vga.h" +#include "../include/common.h" + +static void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { + *eax = op; + *ecx = 0; + asm volatile("cpuid" + : "=a" (*eax), //输出参数 + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx) //输入参数 + : "memory"); +} + +static void get_vendor_name(cpu_t *c) { + int cpuid_level; + char x86_vendor_id[16] = {0}; + cpuid(0x00000000, (unsigned int *) &cpuid_level, + (unsigned int *) &x86_vendor_id[0], + (unsigned int *) &x86_vendor_id[8], + (unsigned int *) &x86_vendor_id[4]); + c->vendor = x86_vendor_id; +} + +static void get_model_name(cpu_t *c) { + unsigned int *v = (unsigned int *) c->model_name; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + c->model_name[48] = 0; +} + +static void get_cpu_address_sizes(cpu_t *c) { + unsigned int eax, ebx, ecx, edx; + cpuid(0x80000008, &eax, &ebx, &ecx, &edx); + + c->virt_bits = (eax >> 8) & 0xff; + c->phys_bits = eax & 0xff; +} + +void print_cpu_id() { + cpu_t *c = (cpu_t *) kmalloc(sizeof(cpu_t)); + get_vendor_name(c); + get_model_name(c); + get_cpu_address_sizes(c); + printf("CPU Vendor: %s\n", c->vendor); + printf("CPU Name: %s\n", c->model_name); + printf("CPU Cache: %d\n",c->phys_bits); + printf("CPU Virtual Address: 0x%x\n",c->virt_bits); + kfree(c); +} + +uint8_t read_cmos(uint8_t p) { + uint8_t data; + outb(CMOS_INDEX, p); + data = inb(CMOS_DATA); + outb(CMOS_INDEX, 0x80); + return data; +} + +static uint32_t get_hour() { + return bcd2hex(read_cmos(CMOS_CUR_HOUR)); +} + +;static uint32_t get_min() { + return bcd2hex(read_cmos(CMOS_CUR_MIN)); +} + +static uint32_t get_sec() { + return bcd2hex(read_cmos(CMOS_CUR_SEC)); +} + +static uint32_t get_day_of_month() { + return bcd2hex(read_cmos(CMOS_MON_DAY)); +} + +static uint32_t get_day_of_week() { + return bcd2hex(read_cmos(CMOS_WEEK_DAY)); +} + +static uint32_t get_mon() { + return bcd2hex(read_cmos(CMOS_CUR_MON)); +} + +static uint32_t get_year() { + return (bcd2hex(read_cmos(CMOS_CUR_CEN)) * 100) + bcd2hex(read_cmos(CMOS_CUR_YEAR)) + 1980; +} + +static int is_leap_year(int year) { + if (year % 4 != 0) return 0; + if (year % 400 == 0) return 1; + return year % 100 != 0; +} + +char *get_date_time() { + char *s = (char *) kmalloc(40); + int year = get_year(), month = get_mon(), day = get_day_of_month(); + int hour = get_hour(), min = get_min(), sec = get_sec(); + int day_of_months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (is_leap_year(year)) day_of_months[2]++; +#ifdef NEED_UTC_8 + hour += 8; + if (hour >= 24) hour -= 24, day++; + if (day > day_of_months[month]) day = 1, month++; + if (month > 12) month = 1, year++; +#endif + sprintf(s, "%d/%d/%d %d:%d:%d", year, month, day, hour, min, sec); + return s; +} \ No newline at end of file diff --git a/driver/disk.c b/driver/disk.c new file mode 100644 index 0000000..9372186 --- /dev/null +++ b/driver/disk.c @@ -0,0 +1,60 @@ +#include "../include/disk.h" +#include "../include/io.h" + +void wait_disk_ready() { + while (1) { + int data = io_in8(0x1f7); + if ((data & 0x88) == 0x08) // 第3位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙。 + { + return; + } + } +} + +void select_sector(int lba) { + io_out8(0x1f2, 1); + io_out8(0x1f3, lba); + io_out8(0x1f4, lba >> 8); + io_out8(0x1f5, lba >> 16); + io_out8(0x1f6, (((lba >> 24) & 0x0f) | 0xe0)); +} + +void read_disk_one_sector(int lba, unsigned int memory_addrress) { + while (io_in8(0x1f7) & 0x80); + select_sector(lba); + io_out8(0x1f7, 0x20); + wait_disk_ready(); + for (int i = 0; i < 256; i++) { + short data = (short) io_in16(0x1f0); + *((short *) memory_addrress) = data; + memory_addrress += 2; + } +} + +void write_disk_one_sertor(int lba, unsigned int memory_addrress) { + while (io_in8(0x1f7) & 0x80); + select_sector(lba); + io_out8(0x1f7, 0x30); + wait_disk_ready(); + for (int i = 0; i < 256; i++) { + short data = *((short *) memory_addrress); + io_out16(0x1f0, data); + memory_addrress += 2; + } +} + +void read_disk(int lba, int sector_count, unsigned int memory_addrress) { + for (int i = 0; i < sector_count; i++) { + read_disk_one_sector(lba, memory_addrress); + lba++; + memory_addrress += 512; + } +} + +void write_disk(int lba, int sector_count, unsigned int memory_addrress) { + for (int i = 0; i < sector_count; i++) { + write_disk_one_sertor(lba, memory_addrress); + lba++; + memory_addrress += 512; + } +} \ No newline at end of file diff --git a/driver/keyboard.c b/driver/keyboard.c new file mode 100644 index 0000000..d438216 --- /dev/null +++ b/driver/keyboard.c @@ -0,0 +1,121 @@ +#include "../include/keyboard.h" + +#include "../include/vga.h" +#include "../include/memory.h" +#include "../include/queue.h" +#include "../include/io.h" + +static KEY_STATUS *key_status; +Queue *key_char_queue; + +unsigned char keyboard_map[128] = + { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ + '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', /* 19 */ + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ + '\'', '`', -1, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ + 'm', ',', '.', '/', -1, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', + 0, /* Left Arrow */ + 0, + 0, /* Right Arrow */ + '+', + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, + 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ + }; + +unsigned char shift_keyboard_map[128] = + { + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */ + '(', ')', '_', '+', '\b', /* Backspace */ + '\t', /* Tab */ + 'Q', 'W', 'E', 'R', /* 19 */ + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */ + '"', '~', -1, /* Left shift */ + '|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */ + 'M', '<', '>', '?', -1, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', + 0, /* Left Arrow */ + 0, + 0, /* Right Arrow */ + '+', + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, + 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ + }; + +void init_keyboard(){ + key_status = (KEY_STATUS*) alloc(sizeof(KEY_STATUS)); + key_status->is_shift = 0; + + key_char_queue = create_queue(); + register_interrupt_handler(0x21,handle_keyboard_input); +} + +int handle_keyboard_input(){ + unsigned char status = read_port(KEYBOARD_STATUS_PORT); + uint32_t key = read_port(KEYBOARD_DATA_PORT); + int release = key & 0xb10000000; + char c = key_status->is_shift ? shift_keyboard_map[(unsigned char )key] : keyboard_map[(unsigned char )key]; + + if(!release) { + if(c == -1) { + key_status->is_shift = 1; + return 0; + } + + if(c == 0) return 0; + + queue_push(key_char_queue,(char)c); + } else { + if(c == -1){ + key_status->is_shift = 0; + } + } + + return 0; +} diff --git a/driver/vga.c b/driver/vga.c new file mode 100644 index 0000000..64139a8 --- /dev/null +++ b/driver/vga.c @@ -0,0 +1,135 @@ +#include "../include/vga.h" +#include "../include/common.h" +#include "../include/io.h" + +static const size_t VGA_WIDTH = 80; +static const size_t VGA_HEIGHT = 25; + +size_t terminal_row; +size_t terminal_column; +uint8_t terminal_color; +uint16_t *terminal_buffer; + +static uint16_t cursor_x = 0, cursor_y = 0; // 光标位置 + +static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) { + return fg | bg << 4; +} + +static inline uint16_t vga_entry(unsigned char uc, uint8_t color) { + return (uint16_t) uc | (uint16_t) color << 8; +} + +static void scroll() { + uint8_t attributeByte = (0 << 4) | (15 & 0x0F); + uint16_t blank = 0x20 | (attributeByte << 8); + + if (cursor_y >= 25) { + int i; + for (i = 0 * 80; i < 24 * 80; i++) terminal_buffer[i] = terminal_buffer[i + 80]; + for (i = 24 * 80; i < 25 * 80; i++) terminal_buffer[i] = blank; + cursor_y = 24; + } +} + +void vga_install(void) { + terminal_row = 0; + terminal_column = 0; + terminal_color = vga_entry_color(VGA_COLOR_DARK_GREY, VGA_COLOR_BLACK); + terminal_buffer = (uint16_t *) 0xB8000; + //terminal_buffer = (uint16_t*) 0xA0000; + for (size_t y = 0; y < VGA_HEIGHT; y++) { + for (size_t x = 0; x < VGA_WIDTH; x++) { + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(' ', terminal_color); + } + } +} + +void vga_clear() { + for (size_t y = 0; y < VGA_HEIGHT; y++) { + for (size_t x = 0; x < VGA_WIDTH; x++) { + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(' ', terminal_color); + } + } + cursor_x = 0; + cursor_y = 0; + move_cursor(); +} + +void move_cursor() { + uint16_t cursorLocation = cursor_y * 80 + cursor_x; + outb(0x3D4, 14); + outb(0x3D5, cursorLocation >> 8); + outb(0x3D4, 15); + outb(0x3D5, cursorLocation); +} + +void vga_setcolor(uint8_t color) { + terminal_color = color; +} + +void vga_putentryat(char c, uint8_t color, size_t x, size_t y) { + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(c, color); +} + +void vga_putchar(char c) { + uint8_t backColor = 0, foreColor = 15; + uint8_t attributeByte = (backColor << 4) | (foreColor & 0x07); // 黑底白字 + uint16_t attribute = attributeByte << 8; + uint16_t *location; + + if (c == 0x08 && cursor_x) { + cursor_x--; + location = terminal_buffer + (cursor_y * 80 + cursor_x); + *location = ' ' | attribute; + } else if (c == 0x09) { + location = terminal_buffer + (cursor_y * 80 + cursor_x); + *location = ' ' | attribute; + cursor_x = (cursor_x + 8) & ~(8 - 1); + } else if (c == '\r') { + cursor_x = 0; + } else if (c == '\n') { + cursor_x = 0; // 光标回首 + cursor_y++; // 下一行 + } else if (c >= ' ' && c <= '~') { + location = terminal_buffer + (cursor_y * 80 + cursor_x); + *location = c | attribute; + cursor_x++; + } + + if (cursor_x >= 80) { + cursor_x = 0; + cursor_y++; + } + + scroll(); + move_cursor(); +} + +void vga_write_dec(uint32_t dec) { + int upper = dec / 10, rest = dec % 10; + if (upper) vga_write_dec(upper); + vga_putchar(rest + '0'); +} + +void vga_write(const char *data, size_t size) { + for (size_t i = 0; i < size; i++) + vga_putchar(data[i]); +} + +void vga_writestring(const char *data) { + vga_write(data, strlen(data)); +} + +void printf(const char *formet, ...) { + int len; + va_list ap; + va_start(ap, formet); + char *buf[1024] = {0}; + len = vsprintf(buf, formet, ap); + vga_writestring(buf); + va_end(ap); +} \ No newline at end of file diff --git a/include/cmos.h b/include/cmos.h new file mode 100644 index 0000000..1488ad9 --- /dev/null +++ b/include/cmos.h @@ -0,0 +1,33 @@ +#ifndef CRASHPOWEROS_CMOS_H +#define CRASHPOWEROS_CMOS_H + +#include + +#define NEED_UTC_8 + +#define CMOS_INDEX 0x70 +#define CMOS_DATA 0x71 + +#define CMOS_CUR_SEC 0x0 +#define CMOS_CUR_MIN 0x2 +#define CMOS_CUR_HOUR 0x4 +#define CMOS_WEEK_DAY 0x6 +#define CMOS_MON_DAY 0x7 +#define CMOS_CUR_MON 0x8 +#define CMOS_CUR_YEAR 0x9 +#define CMOS_CUR_CEN 0x32 + +#define bcd2hex(n) ((n >> 4) * 10) + (n & 0xf) + +typedef struct { + char* vendor; + char model_name[64]; + unsigned int virt_bits; + unsigned int phys_bits; +}cpu_t; + +uint8_t read_cmos(uint8_t p); +char *get_date_time(); +void print_cpu_id(); + +#endif //CRASHPOWEROS_CMOS_H diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..759ab93 --- /dev/null +++ b/include/common.h @@ -0,0 +1,30 @@ +#ifndef CRASHPOWEROS_COMMON_H +#define CRASHPOWEROS_COMMON_H + +#define OS_NAME "CrashPowerDOS" +#define OS_VERSION "v0.2.0" + +#include +#include +#include + +void assert(int b,char* message); +size_t strlen(const char* str); +int strcmp(const char *s1, const char *s2); +char *strcpy(char *dest, const char *src); +char* strcat(char *dest, const char*src); +void trim(char *s); +int isspace(int c); +int isdigit(int c); +int isalpha(int c); +int isupper(int c); +char *int32_to_str_dec(int32_t num, int flag, int width); +char *int64_to_str_dec(int64_t num, int flag, int width); +char *uint32_to_str_hex(uint32_t num, int flag, int width); +char *uint64_to_str_hex(uint64_t num, int flag, int width); +char *uint32_to_str_oct(uint32_t num, int flag, int width); +char *insert_str(char *buf, const char *str); +int vsprintf(char *buf, const char *fmt, va_list args); +int sprintf(char *buf, const char *fmt, ...); + +#endif //CRASHPOWEROS_COMMON_H diff --git a/include/description_table.h b/include/description_table.h new file mode 100644 index 0000000..5a696c6 --- /dev/null +++ b/include/description_table.h @@ -0,0 +1,129 @@ +#ifndef CRASHPOWEROS_DESCRIPTION_TABLE_H +#define CRASHPOWEROS_DESCRIPTION_TABLE_H + +#include + +#define GDT_LENGTH 6 + +typedef struct gdt_entry_t { + uint16_t limit_low; // 段基址 | 低16位置 + uint16_t base_low; // 段基址 | 高16位置 + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; +} __attribute__((packed)) gdt_entry_t; + +typedef struct gdt_ptr_t { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) gdt_ptr_t; + +#define DECLARE_ISR(i) extern void isr##i(); + +DECLARE_ISR(0) +DECLARE_ISR(1) +DECLARE_ISR(2) +DECLARE_ISR(3) +DECLARE_ISR(4) +DECLARE_ISR(5) +DECLARE_ISR(6) +DECLARE_ISR(7) +DECLARE_ISR(8) +DECLARE_ISR(9) +DECLARE_ISR(10) +DECLARE_ISR(11) +DECLARE_ISR(12) +DECLARE_ISR(13) +DECLARE_ISR(14) +DECLARE_ISR(15) +DECLARE_ISR(16) +DECLARE_ISR(17) +DECLARE_ISR(18) +DECLARE_ISR(19) +DECLARE_ISR(20) +DECLARE_ISR(21) +DECLARE_ISR(22) +DECLARE_ISR(23) +DECLARE_ISR(24) +DECLARE_ISR(25) +DECLARE_ISR(26) +DECLARE_ISR(27) +DECLARE_ISR(28) +DECLARE_ISR(29) +DECLARE_ISR(30) +DECLARE_ISR(31) +#undef DECLARE_ISR +#define DECLARE_IRQ(i) extern void irq##i(); +DECLARE_IRQ(0) +DECLARE_IRQ(1) +DECLARE_IRQ(2) +DECLARE_IRQ(3) +DECLARE_IRQ(4) +DECLARE_IRQ(5) +DECLARE_IRQ(6) +DECLARE_IRQ(7) +DECLARE_IRQ(8) +DECLARE_IRQ(9) +DECLARE_IRQ(10) +DECLARE_IRQ(11) +DECLARE_IRQ(12) +DECLARE_IRQ(13) +DECLARE_IRQ(14) +DECLARE_IRQ(15) +#undef DECLARE_IRQ + +struct idt_entry_struct { + uint16_t base_low; + uint16_t sel; + uint8_t always0; + uint8_t flags; + uint16_t base_high; +} __attribute__((packed)); + +typedef struct idt_entry_struct idt_entry_t; + +// IDTR +struct idt_ptr_struct { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +typedef struct idt_ptr_struct idt_ptr_t; + +typedef struct tss_table { + uint32_t prev_tss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} tss_entry; + +void write_tss(int32_t num, uint16_t ss0, uint32_t esp0); + +void gdt_install(); +void idt_install(); + +#endif //CRASHPOWEROS_DESCRIPTION_TABLE_H diff --git a/include/disk.h b/include/disk.h new file mode 100644 index 0000000..0350aef --- /dev/null +++ b/include/disk.h @@ -0,0 +1,11 @@ +#ifndef CPOS_DISK_H +#define CPOS_DISK_H + +void wait_disk_ready(); //不适用于SATA硬盘 +void select_sector(int lba); +void read_disk_one_sector(int lba, unsigned int memory_addrress); +void write_disk_one_sertor(int lba, unsigned int memory_addrress); +void read_disk(int lba, int sector_count, unsigned int memory_addrress); +void write_disk(int lba, int sector_count, unsigned int memory_addrress); + +#endif \ No newline at end of file diff --git a/include/fat16.h b/include/fat16.h new file mode 100644 index 0000000..b842703 --- /dev/null +++ b/include/fat16.h @@ -0,0 +1,48 @@ +#ifndef CPOS_FAT16_H +#define CPOS_FAT16_H + +#define SECTOR_SIZE 512 +#define FAT1_SECTORS 32 //FAT1占用扇区数 +#define ROOT_DIR_SECTORS 32 //根目录占用扇区数 +#define SECTOR_NUM_OF_FAT1_START 1 //FAT1起始扇区号 +#define SECTOR_NUM_OF_ROOT_DIR_START 33 //根目录起始扇区号 +#define SECTOR_NUM_OF_DATA_START 65 //数据区起始扇区号,对应簇号为2。 +#define SECTOR_CLUSTER_BALANCE SECTOR_NUM_OF_DATA_START - 2 //簇号加上该值正好对应扇区号。 +#define MAX_FILE_NUM 16 //最大文件数 + +// FAT16目录项结构(32B); +struct File { + // 文件名 如果第一个字节为0xe5,代表这个文件已经被删除;如果第一个字节为0x00,代表这一段不包含任何文件名信息。 + unsigned char name[8]; + unsigned char ext[3]; // 扩展名 + // 属性:bit0只读文件,bit1隐藏文件,bit2系统文件,bit3非文件信息(比如磁盘名称),bit4目录,bit5文件。 + unsigned char type; // 0x20 文件 | 0x10 目录 + unsigned char reserve[10]; // 保留 + unsigned short time; // 最后一次写入时间 + unsigned short date; // 最后一次写入日期 + unsigned short clustno; // 起始簇号 + unsigned int size; // 文件大小 +}; + +void read_root_dir_sector1(struct File *root_entries); +void save_root_dir_sector1(struct File *root_entries); +void read_one_cluster(unsigned short clustno, unsigned int memory_addrress); +int read_root_dir(struct File *file_infos); +void get_fat1(unsigned short *fat1); +void save_fat1(unsigned short *fat1); +void get_file_all_clustnos(unsigned short first_clustno, unsigned short *clustnos); +void get_file_all_clustnos(unsigned short first_clustno, unsigned short *clustnos); +void read_file(struct File *file, void *file_addr); +void check_name_or_ext(char *str, int len); +void check_name_and_ext(char *name, char *ext); +void analyse_fullname(char *fullname, char *name, char *ext); +int find_file(char *name, char *ext, struct File *const file); +struct File *create_file(char *fullname); +struct File *create_dir(char *fullname); +struct File *open_file(char *fullname); +void alter_file_name(struct File *file, char *new_fullname); +void alter_dir_entry(struct File *file); +void save_file(struct File *file, char *content); +void delete_file(struct File *file); + +#endif \ No newline at end of file diff --git a/include/io.h b/include/io.h new file mode 100644 index 0000000..3b10650 --- /dev/null +++ b/include/io.h @@ -0,0 +1,57 @@ +#ifndef CRASHPOWEROS_IO_H +#define CRASHPOWEROS_IO_H + + +#include + +void gdt_flush(uint32_t gdtr); + +void io_hlt(void); + +void io_cli(void); + +void io_sti(void); + +void io_stihlt(void); + +int io_in8(int port); + +int io_in16(int port); + +int io_in32(int port); + +void io_out8(int port, int data); + +void io_out16(int port, int data); + +void io_out32(int port, int data); + +int io_load_eflags(void); + +void io_store_eflags(int eflags); + +void load_gdtr(int limit, int addr); + +void load_idtr(int limit, int addr); + +extern char read_port(unsigned short port); + +static inline void outb(uint16_t port, uint8_t data) { + asm volatile("outb %b0, %w1" : : "a"(data), "Nd"(port)); +} + +static inline void outsw(uint16_t port, const void *addr, uint32_t word_cnt) { + asm volatile("cld; rep outsw" : "+S"(addr), "+c"(word_cnt) : "d"(port)); +} + +static inline uint8_t inb(uint16_t port) { + uint8_t data; + asm volatile("inb %w1, %b0" : "=a"(data) : "Nd"(port)); + return data; +} + +static inline void insw(uint16_t port, void *addr, uint32_t word_cnt) { + asm volatile("cld; rep insw" : "+D"(addr), "+c"(word_cnt) : "d"(port) : "memory"); +} + +#endif //CRASHPOWEROS_IO_H diff --git a/include/isr.h b/include/isr.h new file mode 100644 index 0000000..2349886 --- /dev/null +++ b/include/isr.h @@ -0,0 +1,35 @@ +#ifndef CPOS_ISR_H +#define CPOS_ISR_H + +#include + +typedef struct registers { + uint32_t ds; // 我们自己弹入的,当前数据段 + uint32_t edi, esi, ebp, useless, ebx, edx, ecx, eax; // 按pusha顺序 + // 其中esp一项不会被popa还原至对应寄存器中,因为esp寄存器代表的是当前的栈而不是进入中断前的,因此用useless代替 + uint32_t int_no, err_code; // 中断代号是自己push的,err_code有的自带,有的不自带 + uint32_t eip, cs, eflags, esp, ss; // 进入中断时自动压入的 +} registers_t; + +#define IRQ0 32 +#define IRQ1 33 +#define IRQ2 34 +#define IRQ3 35 +#define IRQ4 36 +#define IRQ5 37 +#define IRQ6 38 +#define IRQ7 39 +#define IRQ8 40 +#define IRQ9 41 +#define IRQ10 42 +#define IRQ11 43 +#define IRQ12 44 +#define IRQ13 45 +#define IRQ14 46 +#define IRQ15 47 + +typedef void (*isr_t)(registers_t *); + +void register_interrupt_handler(uint8_t n, isr_t handler); + +#endif \ No newline at end of file diff --git a/include/keyboard.h b/include/keyboard.h new file mode 100644 index 0000000..5c65b4c --- /dev/null +++ b/include/keyboard.h @@ -0,0 +1,19 @@ +#ifndef CRASHPOWEROS_KEYBOARD_H +#define CRASHPOWEROS_KEYBOARD_H + +#define KEYBOARD_DATA_PORT 0x60 +#define KEYBOARD_STATUS_PORT 0x64 + +typedef struct { + int is_shift; +}KEY_STATUS; + +typedef struct { + unsigned char *keyboard_map[128]; + unsigned char *shift_keyboard_map[128]; +}KEY_MAP; + +void init_keyboard(); +int handle_keyboard_input(); + +#endif //CRASHPOWEROS_KEYBOARD_H diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 0000000..0ef8493 --- /dev/null +++ b/include/memory.h @@ -0,0 +1,82 @@ +#ifndef CRASHPOWEROS_MEMORY_H +#define CRASHPOWEROS_MEMORY_H + +#include +#include +#include "isr.h" + +#define KHEAP_INITIAL_SIZE 0xf00000 +#define KHEAP_START 0xc0000000 +#define STACK_SIZE 32768 + +#define INDEX_FROM_BIT(a) (a / (8*4)) +#define OFFSET_FROM_BIT(a) (a % (8*4)) + +typedef char ALIGN[16]; + +typedef struct page { + uint32_t present: 1; + uint32_t rw: 1; + uint32_t user: 1; + uint32_t accessed: 1; + uint32_t dirty: 1; + uint32_t unused: 7; + uint32_t frame: 20; +} page_t; + +typedef struct page_table { + page_t pages[1024]; +} page_table_t; + +typedef struct page_directory { + page_table_t *tables[1024]; + uint32_t tablesPhysical[1024]; + uint32_t physicalAddr; +} page_directory_t; + +typedef union header { + struct { + uint32_t size; + uint32_t is_free; + union header *next; + } s; + ALIGN stub; +} header_t; + +void *memcpy(void *dst_, const void *src_, uint32_t size); + +int memcmp(const void *a_, const void *b_, uint32_t size); + +void *memset(void *s, int c, size_t n); + +void *memmove(void *dest, const void *src, size_t num); + +void switch_page_directory(page_directory_t *dir); + +page_t *get_page(uint32_t address, int make, page_directory_t *dir); + +void alloc_frame(page_t *page, int is_kernel, int is_writable); + +uint32_t first_frame(); + +void page_fault(registers_t *regs); + +void flush_tlb(); + +void *ksbrk(int incr); + +void *alloc(uint32_t size); + +void kfree(void *ptr); + +uint32_t kmalloc_a(uint32_t size); + +uint32_t kmalloc_p(uint32_t size, uint32_t *phy); + +uint32_t kmalloc(size_t size); + +uint32_t kmalloc_ap(uint32_t size, uint32_t *phys); + +void init_page(); + +#endif //CRASHPOWEROS_MEMORY_H diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 0000000..7f0c784 --- /dev/null +++ b/include/queue.h @@ -0,0 +1,20 @@ +#ifndef CPOS_QUEUE_H +#define CPOS_QUEUE_H + +typedef struct queue_node { + char data; + struct queue_node *next; +}QNode; + +typedef struct queue { + QNode *phead; //队头 + QNode *ptail; //队尾 + int size; +}Queue; + +Queue *create_queue(); +void free_queue(Queue *queue); +char queue_pop(Queue *pq); +void queue_push(Queue *pq, char x); + +#endif diff --git a/include/shell.h b/include/shell.h new file mode 100644 index 0000000..59b9066 --- /dev/null +++ b/include/shell.h @@ -0,0 +1,16 @@ +#ifndef CRASHPOWEROS_SHELL_H +#define CRASHPOWEROS_SHELL_H + +#define MAX_COMMAND_LEN 100 +#define MAX_ARG_NR 50 + +char getc(); +int gets(char *buf, int buf_size); +void setup_shell(); + +//内置命令 +void cmd_echo(int argc,char **argv); +void cmd_proc(); +void cmd_date(); + +#endif //CRASHPOWEROS_SHELL_H diff --git a/include/task.h b/include/task.h new file mode 100644 index 0000000..249b374 --- /dev/null +++ b/include/task.h @@ -0,0 +1,50 @@ +#ifndef CRASHPOWEROS_TASK_H +#define CRASHPOWEROS_TASK_H + +#include "memory.h" + +typedef +enum task_state { + TASK_UNINIT = 0, // 未初始化 + TASK_SLEEPING = 1, // 睡眠中 + TASK_RUNNABLE = 2, // 可运行(也许正在运行) + TASK_ZOMBIE = 3, // 僵尸状态 +} task_state; + +struct context { + uint32_t esp; + uint32_t ebp; + uint32_t ebx; + uint32_t esi; + uint32_t edi; + uint32_t eflags; +}; + +struct mm_struct { + page_directory_t *pgd_dir; // 进程页表 +}; + +// 进程控制块 PCB +struct task_struct { + volatile task_state state; // 进程当前状态 + int pid; // 进程标识符 + char *name; // 进程名 + void *stack; // 进程的内核栈地址 + struct mm_struct *mm; // 当前进程的内存地址映像 + struct context context; // 进程切换需要的上下文信息 + struct task_struct *next; // 链表指针 +}; + +int32_t kernel_thread(int (*fn)(void *), void *arg, char *name); + +void kthread_exit(); + +void print_proc(); + +void init_sched(); + +void schedule(); + +void change_task_to(struct task_struct *next); + +#endif //CRASHPOWEROS_TASK_H diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..ebaa223 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,10 @@ +#ifndef CRASHPOWEROS_TIMER_H +#define CRASHPOWEROS_TIMER_H + +#include + +void init_timer(uint32_t timer); + +void clock_sleep(uint32_t timer); + +#endif //CRASHPOWEROS_TIMER_H diff --git a/include/vga.h b/include/vga.h new file mode 100644 index 0000000..028bce2 --- /dev/null +++ b/include/vga.h @@ -0,0 +1,65 @@ +#ifndef CPOS_VGA_H +#define CPOS_VGA_H + +#include +#include +#include + +#define FLAG_ALTNT_FORM 0x01 +#define FLAG_ALTNT_FORM_CH '#' + +#define FLAG_ZERO_PAD 0x02 +#define FLAG_ZERO_PAD_CH '0' + +#define FLAG_LEFT_ADJUST 0x04 +#define FLAG_LEFT_ADJUST_CH '-' + +#define FLAG_SPACE_BEFORE_POS_NUM 0x08 +#define FLAG_SPACE_BEFORE_POS_NUM_CH ' ' + +#define FLAG_SIGN 0x10 +#define FLAG_SIGN_CH '+' + +#define FLAG_LOWER 0x20 + +#define INT_TYPE_CHAR 0x1 +#define INT_TYPE_SHORT 0x2 +#define INT_TYPE_INT 0x4 +#define INT_TYPE_LONG 0x8 +#define INT_TYPE_LONG_LONG 0x10 +#define INT_TYPE_MIN INT_TYPE_CHAR +#define INT_TYPE_MAX INT_TYPE_LONG_LONG + +#define BUF_SIZE 4096 + +enum vga_color { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15, +}; + +void vga_install(void); +void vga_setcolor(uint8_t color); +void vga_putentryat(char c, uint8_t color, size_t x, size_t y); +void vga_putchar(char c); +void vga_write(const char* data, size_t size); +void vga_writestring(const char* data); +void vga_write_dec(uint32_t dec); +void vga_clear(); +void move_cursor(); +void printf(const char *formet, ...); + +#endif \ No newline at end of file diff --git a/kernel/common.c b/kernel/common.c new file mode 100644 index 0000000..84b6ea4 --- /dev/null +++ b/kernel/common.c @@ -0,0 +1,578 @@ +#include "../include/common.h" +#include "../include/vga.h" +#include "../include/memory.h" +#include "../include/io.h" + +static char num_str_buf[BUF_SIZE]; + +int sprintf(char *buf, const char *fmt, ...) { + va_list args; + int retval; + va_start(args, fmt); + retval = vsprintf(buf, fmt, args); + va_end(args); + return retval; +} + +size_t strlen(const char *str) { + size_t len = 0; + while (str[len]) + len++; + return len; +} + +int strcmp(const char *s1, const char *s2) { + char is_equal = 1; + + for (; (*s1 != '\0') && (*s2 != '\0'); s1++, s2++) { + if (*s1 != *s2) { + is_equal = 0; + break; + } + } + + if (is_equal) { + if (*s1 != '\0') { + return 1; + } else if (*s2 != '\0') { + return -1; + } else { + return 0; + } + } else { + return (int) (*s1 - *s2); + } +} + +char *strcpy(char *dest, const char *src) { + do { + *dest++ = *src++; + } while (*src != 0); +} + +char *strcat(char *dest, const char *src) { + char *temp = dest; + while (*temp != '\0') + temp++; + while ((*temp++ = *src++) != '\0'); +} + +int isspace(int c) { + return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || + c == '\v'); +} + +// isdigit +int isdigit(int c) { + return (c >= '0' && c <= '9'); +} + +// isalpha +int isalpha(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +// isupper +int isupper(int c) { + return (c >= 'A' && c <= 'Z'); +} + +char *int32_to_str_dec(int32_t num, int flag, int width) { + int32_t num_tmp = num; + char *p = num_str_buf; + char *q = NULL; + int len = 0; + char *str_first = NULL; + char *str_end = NULL; + char ch = 0; + + memset(num_str_buf, 0, sizeof(num_str_buf)); + + char dic[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + if (num_tmp < 0) { + *p++ = '-'; + } else if (flag & FLAG_SIGN) { + *p++ = '+'; + } else { + *p++ = ' '; + } + str_first = num_str_buf; + + if (num_tmp >= 0 && !(flag & FLAG_SIGN)) { + str_first++; + } + + if (num_tmp == 0) { + *p++ = '0'; + } else { + if (num_tmp < 0) + num_tmp = -num_tmp; + + while (num_tmp) { + *p++ = dic[num_tmp % 10]; + num_tmp /= 10; + } + } + *p = '\0'; + + str_end = p; + len = str_end - str_first; + + q = num_str_buf + 1; + p--; + while (q < p) { + ch = *q; + *q = *p; + *p = ch; + p--; + q++; + } + + if (len < width) { + p = str_end; + + if (flag & FLAG_LEFT_ADJUST) { + for (int i = 0; i < width - len; i++) + *p++ = ' '; + *p = '\0'; + str_end = p; + } else { + while (p >= str_first) { + *(p + width - len) = *p; + p--; + } + + if (flag & FLAG_ZERO_PAD) { + for (int i = 0; i < width - len; i++) { + num_str_buf[i + 1] = '0'; + } + } else { + for (int i = 0; i < width - len; i++) + str_first[i] = ' '; + } + } + } + + return str_first; +} + +char *int64_to_str_dec(int64_t num, int flag, int width) { + return 0; +} + +char *uint32_to_str_hex(uint32_t num, int flag, int width) { + uint32_t num_tmp = num; + char *p = num_str_buf; + char *q = NULL; + int len = 0; + char *str_first = NULL; + char *str_end = NULL; + char ch = 0; + + memset(num_str_buf, 0, sizeof(num_str_buf)); + + char dic_lower[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + char dic_upper[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + char *dic = (flag & FLAG_LOWER) ? dic_lower : dic_upper; + + str_first = num_str_buf; + + *p++ = '0'; + *p++ = (flag & FLAG_LOWER) ? 'x' : 'X'; + + if (!(flag & FLAG_ALTNT_FORM)) { + str_first += 2; + } + + do { + *p++ = dic[num_tmp % 16]; + num_tmp /= 16; + } while (num_tmp); + *p = '\0'; + + str_end = p; + len = str_end - str_first; + + q = num_str_buf + 2; + p--; + while (q < p) { + ch = *q; + *q = *p; + *p = ch; + p--; + q++; + } + + if (len < width) { + p = str_end; + + if (flag & FLAG_LEFT_ADJUST) { + for (int i = 0; i < width - len; i++) + *p++ = ' '; + *p = '\0'; + str_end = p; + } else { + while (p >= str_first) { + *(p + width - len) = *p; + p--; + } + if (flag & FLAG_ALTNT_FORM) + str_first[1] = (flag & FLAG_LOWER) ? 'x' : 'X'; + + if (flag & FLAG_ZERO_PAD) { + for (int i = 0; i < width - len; i++) { + num_str_buf[i + 2] = '0'; + } + } else { + for (int i = 0; i < width - len; i++) + str_first[i] = ' '; + } + } + } + + if (num == 0 && flag & FLAG_ALTNT_FORM) + str_first[1] = '0'; + + return str_first; +} + +char *uint64_to_str_hex(uint64_t num, int flag, int width) { + uint64_t num_tmp = num; + char *p = num_str_buf; + char *q = NULL; + int len = 0; + char *str_first = NULL; + char *str_end = NULL; + char ch = 0; + + memset(num_str_buf, 0, sizeof(num_str_buf)); + + char dic_lower[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + char dic_upper[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + char *dic = (flag & FLAG_LOWER) ? dic_lower : dic_upper; + + str_first = num_str_buf; + + *p++ = '0'; + *p++ = (flag & FLAG_LOWER) ? 'x' : 'X'; + + if (!(flag & FLAG_ALTNT_FORM)) { + str_first += 2; + } + + while (num_tmp) { + *p++ = dic[num_tmp % 16]; + num_tmp /= 16; + } + *p = '\0'; + + str_end = p; + len = str_end - str_first; + + q = num_str_buf + 2; + p--; + while (q < p) { + ch = *q; + *q = *p; + *p = ch; + p--; + q++; + } + + if (len < width) { + p = str_end; + + while (p >= str_first) { + *(p + width - len) = *p; + p--; + } + + if (flag & FLAG_ZERO_PAD) { + for (int i = 0; i < width - len; i++) { + num_str_buf[i + 2] = '0'; + } + } else { + for (int i = 0; i < width - len; i++) + str_first[i] = ' '; + } + } + + return str_first; +} + +char *uint32_to_str_oct(uint32_t num, int flag, int width) { + uint32_t num_tmp = num; + char *p = num_str_buf; + char *q = NULL; + int len = 0; + char *str_first = NULL; + char *str_end = NULL; + char ch = 0; + + memset(num_str_buf, 0, sizeof(num_str_buf)); + + char dic[] = {'0', '1', '2', '3', '4', '5', '6', '7'}; + + str_first = num_str_buf; + + *p++ = '0'; + + if (!(flag & FLAG_ALTNT_FORM)) { + str_first += 1; + } + + while (num_tmp) { + *p++ = dic[num_tmp % 8]; + num_tmp /= 8; + } + *p = '\0'; + + str_end = p; + len = str_end - str_first; + + q = num_str_buf + 1; + p--; + while (q < p) { + ch = *q; + *q = *p; + *p = ch; + p--; + q++; + } + + if (len < width) { + p = str_end; + + if (flag & FLAG_LEFT_ADJUST) { + for (int i = 0; i < width - len; i++) + *p++ = ' '; + *p = '\0'; + str_end = p; + } else { + while (p >= str_first) { + *(p + width - len) = *p; + p--; + } + + if (flag & FLAG_ZERO_PAD) { + for (int i = 0; i < width - len; i++) { + num_str_buf[i + 1] = '0'; + } + } else { + for (int i = 0; i < width - len; i++) + str_first[i] = ' '; + } + } + } + + return str_first; +} + +char *insert_str(char *buf, const char *str) { + char *p = buf; + + while (*str) { + *p++ = *str++; + } + + return p; +} + +int vsprintf(char *buf, const char *fmt, va_list args) { + char *str = buf; + int flag = 0; + int int_type = INT_TYPE_INT; + int tot_width = 0; + int sub_width = 0; + char buf2[64] = {0}; + char *s = NULL; + char ch = 0; + int8_t num_8 = 0; + uint8_t num_u8 = 0; + int16_t num_16 = 0; + uint16_t num_u16 = 0; + int32_t num_32 = 0; + uint32_t num_u32 = 0; + int64_t num_64 = 0; + uint64_t num_u64 = 0; + + for (const char *p = fmt; *p; p++) { + if (*p != '%') { + *str++ = *p; + continue; + } + + flag = 0; + tot_width = 0; + sub_width = 0; + int_type = INT_TYPE_INT; + + p++; + + while (*p == FLAG_ALTNT_FORM_CH || *p == FLAG_ZERO_PAD_CH || + *p == FLAG_LEFT_ADJUST_CH || *p == FLAG_SPACE_BEFORE_POS_NUM_CH || + *p == FLAG_SIGN_CH) { + if (*p == FLAG_ALTNT_FORM_CH) { + flag |= FLAG_ALTNT_FORM; + } else if (*p == FLAG_ZERO_PAD_CH) { + flag |= FLAG_ZERO_PAD; + } else if (*p == FLAG_LEFT_ADJUST_CH) { + flag |= FLAG_LEFT_ADJUST; + flag &= ~FLAG_ZERO_PAD; + } else if (*p == FLAG_SPACE_BEFORE_POS_NUM_CH) { + flag |= FLAG_SPACE_BEFORE_POS_NUM; + } else if (*p == FLAG_SIGN_CH) { + flag |= FLAG_SIGN; + } else { + } + + p++; + } + + if (*p == '*') { + tot_width = va_arg(args, + int); + if (tot_width < 0) + tot_width = 0; + p++; + } else { + while (isdigit(*p)) { + tot_width = tot_width * 10 + *p - '0'; + p++; + } + } + if (*p == '.') { + if (*p == '*') { + sub_width = va_arg(args, + int); + if (sub_width < 0) + sub_width = 0; + p++; + } else { + while (isdigit(*p)) { + sub_width = sub_width * 10 + *p - '0'; + p++; + } + } + } + + LOOP_switch: + switch (*p) { + case 'h': + p++; + if (int_type >= INT_TYPE_MIN) { + int_type >>= 1; + goto LOOP_switch; + } else { + *str++ = '%'; + break; + } + case 'l': + p++; + if (int_type <= INT_TYPE_MAX) { + int_type <<= 1; + goto LOOP_switch; + } else { + *str++ = '%'; + break; + } + case 's': + s = va_arg(args, + char *); + str = insert_str(str, s); + break; + case 'c': + ch = (char) (va_arg(args, + int) & + 0xFF); + *str++ = ch; + break; + case 'd': + switch (int_type) { + case INT_TYPE_CHAR: + num_8 = (int8_t) va_arg(args, int32_t); + str = insert_str(str, int32_to_str_dec(num_8, flag, tot_width)); + break; + case INT_TYPE_SHORT: + num_16 = (int16_t) va_arg(args, int32_t); + str = insert_str(str, int32_to_str_dec(num_16, flag, tot_width)); + break; + case INT_TYPE_INT: + num_32 = va_arg(args, int32_t); + str = insert_str(str, int32_to_str_dec(num_32, flag, tot_width)); + break; + case INT_TYPE_LONG: + num_64 = va_arg(args, int64_t); + str = insert_str(str, int64_to_str_dec(num_64, flag, tot_width)); + break; + case INT_TYPE_LONG_LONG: + num_64 = va_arg(args, int64_t); + str = insert_str(str, int64_to_str_dec(num_64, flag, tot_width)); + break; + } + break; + case 'x': + flag |= FLAG_LOWER; + case 'X': + switch (int_type) { + case INT_TYPE_CHAR: + num_u8 = (uint8_t) + va_arg(args, uint32_t); + str = insert_str(str, uint32_to_str_hex(num_u8, flag, tot_width)); + break; + case INT_TYPE_SHORT: + num_u16 = (uint16_t) + va_arg(args, uint32_t); + str = insert_str(str, uint32_to_str_hex(num_u16, flag, tot_width)); + break; + case INT_TYPE_INT: + num_u32 = va_arg(args, uint32_t); + str = insert_str(str, uint32_to_str_hex(num_u32, flag, tot_width)); + break; + case INT_TYPE_LONG: + num_u64 = va_arg(args, uint64_t); + str = insert_str(str, uint64_to_str_hex(num_u64, flag, tot_width)); + break; + case INT_TYPE_LONG_LONG: + num_u64 = va_arg(args, uint64_t); + str = insert_str(str, uint64_to_str_hex(num_u64, flag, tot_width)); + break; + } + break; + case 'o': + num_u32 = va_arg(args, uint32_t); + str = insert_str(str, uint32_to_str_oct(num_u32, flag, tot_width)); + break; + case '%': + *str++ = '%'; + break; + default: + *str++ = '%'; + *str++ = *p; + break; + } + } + *str = '\0'; + + return str - buf; +} + +void assert(int b,char* message){ + if(!b){ + printf("[KERNEL-PANIC]: %s",message); + while (1) io_hlt(); + } +} + +void trim(char *s){ + char *p = s; + int len = strlen(p); + while (isspace(p[len - 1])) p[--len] = 0; + while (*p && isspace(*p)) ++p,--len; + memmove(s,p,len+1); +} diff --git a/kernel/fat16.c b/kernel/fat16.c new file mode 100644 index 0000000..fce60a8 --- /dev/null +++ b/kernel/fat16.c @@ -0,0 +1,327 @@ +#include "../include/fat16.h" +#include "../include/memory.h" +#include "../include/disk.h" + +void read_root_dir_sector1(struct File *root_entries) { + read_disk(SECTOR_NUM_OF_ROOT_DIR_START, 1, (unsigned int) root_entries); +} + +void save_root_dir_sector1(struct File *root_entries) { + write_disk(SECTOR_NUM_OF_ROOT_DIR_START, 1, (unsigned int) root_entries); +} + +void read_one_cluster(unsigned short clustno, unsigned int memory_addrress) { + read_disk(clustno + SECTOR_CLUSTER_BALANCE, 1, memory_addrress); +} + +int read_root_dir(struct File *file_infos) { + struct File *root_entries = (struct File *) kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + int n = 0; // 记录文件数 + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (root_entries[i].name[0] == 0) { + break; + } + if (root_entries[i].name[0] != 0xe5) { + file_infos[n] = root_entries[i]; + n++; + } + } + kfree(root_entries); + return n; +} + +void get_fat1(unsigned short *fat1) { + read_disk(SECTOR_NUM_OF_FAT1_START, FAT1_SECTORS, (unsigned int) fat1); // 将FAT1全部读取到内存中。 +} + +void save_fat1(unsigned short *fat1) { + write_disk(SECTOR_NUM_OF_FAT1_START, FAT1_SECTORS, (unsigned int) fat1); // 将FAT1全部写回到内存中。 +} + +void get_file_all_clustnos(unsigned short first_clustno, unsigned short *clustnos) { + unsigned short *fat1 = kmalloc(FAT1_SECTORS * SECTOR_SIZE); + get_fat1(fat1); + *clustnos = first_clustno; + while (1) { + unsigned short clustno = *(fat1 + *clustnos); + clustnos++; + *clustnos = clustno; + if (clustno >= 0xfff8) // 大于等于0xfff8表示文件的最后一个簇 + { + break; + } + } + kfree(fat1); +} + +void read_file(struct File *file, void *file_addr) { + if (file->size == 0) { + return; + } + int cluster_count = (file->size + 511) / 512; + unsigned short *clustnos = kmalloc(cluster_count * 2); + get_file_all_clustnos(file->clustno, clustnos); + for (int i = 0; i < cluster_count; i++) { + read_one_cluster(clustnos[i], (unsigned int) file_addr); + file_addr += 512; + } + kfree(clustnos); +} + +void check_name_or_ext(char *str, int len) { + for (int i = 0; i < len; i++) { + if (str[i] == 0) { + str[i] = ' '; + } else if ('a' <= str[i] && str[i] <= 'z') { + str[i] -= 0x20; + } + } +} + +void check_name_and_ext(char *name, char *ext) { + check_name_or_ext(name, 8); + check_name_or_ext(ext, 3); +} + +void analyse_fullname(char *fullname, char *name, char *ext) { + int ext_dot_index = -1; + for (int i = 11; i >= 0; i--) { + if (fullname[i] == '.') { + ext_dot_index = i; + } + } + if (ext_dot_index == -1) // 没有后缀名的情况 + { + memcpy(name, fullname, 8); + memset(ext, ' ', 3); + } else if (ext_dot_index == 0) // 没有文件名的情况 + { + memset(name, ' ', 8); + memcpy(ext, fullname + 1, 3); + } else { + memcpy(name, fullname, ext_dot_index); + memcpy(ext, fullname + ext_dot_index + 1, 3); + } + check_name_and_ext(name, ext); +} + +int find_file(char *name, char *ext, struct File *const file) { + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + int isfind = 0; + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, name, 8) == 0 && memcmp(root_entries[i].ext, ext, 3) == 0) { + if (file != 0) { + *file = root_entries[i]; + } + isfind = 1; + } + } + kfree(root_entries); + return isfind; +} + +struct File *create_dir(char *fullname) { + char name[8] = {0}; + char ext[3] = {0}; + analyse_fullname(fullname, name, ext); + int isfind = find_file(name, ext, 0); + if (isfind) { + return 0; //文件已存在。 + } + + struct File *file = (struct File *) kmalloc(32); + memcpy(file->name, name, 8); + memcpy(file->ext, " ", 3); + file->type = 0x10; + file->time = 0; + file->date = 0; + file->clustno = 0; + file->size = 0; + + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (root_entries[i].name[0] == 0 || root_entries[i].name[0] == 0xe5) { //找一个空闲的文件项存放。 + root_entries[i] = *file; + break; + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); + return file; +} + +struct File *create_file(char *fullname) { + char name[8] = {0}; + char ext[3] = {0}; + analyse_fullname(fullname, name, ext); + int isfind = find_file(name, ext, 0); + if (isfind) { + return 0; //文件已存在。 + } + + struct File *file = (struct File *) kmalloc(32); + memcpy(file->name, name, 8); + memcpy(file->ext, ext, 3); + file->type = 0x20; + file->time = 0; + file->date = 0; + file->clustno = 0; + file->size = 0; + + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (root_entries[i].name[0] == 0 || root_entries[i].name[0] == 0xe5) { //找一个空闲的文件项存放。 + root_entries[i] = *file; + break; + } + } + save_root_dir_sector1(root_entries); + + kfree(root_entries); + //open_file_task(file); + kfree(name); + kfree(ext); + return file; +} + +struct File *open_file(char *fullname) { + char name[8] = {0}; + char ext[3] = {0}; + analyse_fullname(fullname, name, ext); + struct File *file = (struct File *) kmalloc(32); + int isfind = find_file(name, ext, file); + if (!isfind) { + kfree(file); + file = 0; + } else { + //set_opened_file(file); + } + return file; +} + +void alter_file_name(struct File *file, char *new_fullname) { + char new_name[8] = {0}; + char new_ext[3] = {0}; + analyse_fullname(new_fullname, new_name, new_ext); + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, file->name, 8) == 0 && memcmp(root_entries[i].ext, file->ext, 3) == 0) { + memcpy(root_entries[i].name, new_name, 8); + memcpy(root_entries[i].ext, new_ext, 3); + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); +} + +void alter_dir_entry(struct File *file) { + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, file->name, 8) == 0 && memcmp(root_entries[i].ext, file->ext, 3) == 0) { + root_entries[i] = *file; + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); +} + +void save_file(struct File *file, char *content) { + unsigned int file_size = strlen(content); //内容大小 + if (file_size == 0 && file->size == 0) { + return; + } + file->size = file_size; + int sector_num = (file_size + 511) / 512; //将要占用的扇区数 + unsigned short *fat1 = kmalloc(FAT1_SECTORS * SECTOR_SIZE); + get_fat1(fat1); + unsigned short clustno = file->clustno; + unsigned short next_clustno; + if (file->clustno == 0) //第一次写入 + { + clustno = 2; //可用簇号从2开始 + while (1) { + if (*(fat1 + clustno) == 0) //空闲簇号 + { + file->clustno = clustno; //分配起始簇号 + break; + } else { + clustno++; + } + } + } + int i = 0; + while (1) { + write_disk(SECTOR_CLUSTER_BALANCE + clustno, 1, (unsigned int) content); + if (i == sector_num - 1) { //已写完最后一扇区。 + break; + } + i++; + content += 512; + next_clustno = *(fat1 + clustno); + if (next_clustno == 0 || next_clustno >= 0xfff8) { //寻找下一个可用簇号 + next_clustno = clustno + 1; + while (1) { + if (*(fat1 + next_clustno) == 0) { + *(fat1 + clustno) = next_clustno; + break; + } else { + next_clustno++; + } + } + } + clustno = next_clustno; + } + next_clustno = *(fat1 + clustno); + *(fat1 + clustno) = 0xffff; //0xfff8~0xffff表示文件结束,没有下一个簇了。 + //如果本次写入的内容比上次的少,上次用过的簇号本次用不完,以下将剩下的簇号清零处理。 + if (1 < next_clustno && next_clustno < 0xfff0) { + while (1) { + clustno = next_clustno; + next_clustno = *(fat1 + clustno); + *(fat1 + clustno) = 0; + if (next_clustno >= 0xfff8) { + break; + } + } + } + alter_dir_entry(file); + save_fat1(fat1); + kfree(fat1); +} + +void delete_file(struct File *file) { + //1.标记目录项为已删除。 + struct File *root_entries = kmalloc(SECTOR_SIZE); + read_root_dir_sector1(root_entries); + for (int i = 0; i < MAX_FILE_NUM; i++) { + if (memcmp(root_entries[i].name, file->name, 8) == 0 && memcmp(root_entries[i].ext, file->ext, 3) == 0) { + root_entries[i].name[0] = 0xe5; + break; + } + } + save_root_dir_sector1(root_entries); + kfree(root_entries); + if (file->clustno == 0) { + return; + } + unsigned short *fat1 = kmalloc(FAT1_SECTORS * SECTOR_SIZE); + get_fat1(fat1); + unsigned short clustno = file->clustno; + unsigned short next_clustno = 0; + while (1) { + next_clustno = *(fat1 + clustno); + *(fat1 + clustno) = 0; + if (next_clustno >= 0xfff8) { + break; + } + clustno = next_clustno; + } + save_fat1(fat1); + kfree(fat1); +} \ No newline at end of file diff --git a/kernel/gdt.c b/kernel/gdt.c new file mode 100644 index 0000000..b3ed616 --- /dev/null +++ b/kernel/gdt.c @@ -0,0 +1,64 @@ +#include "../include/description_table.h" +#include "../include/memory.h" +#include "../include/io.h" + +extern void tss_flush(); +extern uint32_t stack; + +gdt_entry_t gdt_entries[GDT_LENGTH]; +gdt_ptr_t gdt_ptr; +tss_entry tss; + +void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + gdt_entries[num].base_low = (base & 0xFFFF); + gdt_entries[num].base_middle = (base >> 16) & 0xFF; + gdt_entries[num].base_high = (base >> 24) & 0xFF; + + gdt_entries[num].limit_low = (limit & 0xFFFF); + gdt_entries[num].granularity = (limit >> 16) & 0x0F; + + gdt_entries[num].granularity |= gran & 0xF0; + gdt_entries[num].access = access; +} + +void write_tss(int32_t num, uint16_t ss0, uint32_t esp0) { + uintptr_t base = (uintptr_t) & tss; + uintptr_t limit = base + sizeof(tss); + + gdt_set_gate(num, base, limit, 0xE9, 0x00); + + memset((uint8_t * ) & tss, 0x0, sizeof(tss)); + + tss.ss0 = ss0; + tss.esp0 = esp0; + tss.cs = 0x0b; + tss.ss = 0x13; + tss.ds = 0x13; + tss.es = 0x13; + tss.fs = 0x13; + tss.gs = 0x13; + + tss.iomap_base = sizeof(tss); +} + +void set_kernel_stack(uintptr_t stack) { + tss.esp0 = stack; +} + +void gdt_install() { + gdt_ptr.limit = sizeof(gdt_entry_t) * GDT_LENGTH - 1; + gdt_ptr.base = (uint32_t)&gdt_entries; + + gdt_set_gate(0, 0, 0, 0, 0); // 按照 Intel 文档要求,第一个描述符必须全 0 + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // 指令段 + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // 数据段 + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // 用户模式代码段 + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // 用户模式数据段 + + gdt_flush((uint32_t)&gdt_ptr); + + write_tss(5, 0x10, 0x0); + tss_flush(); +} + + diff --git a/kernel/idt.c b/kernel/idt.c new file mode 100644 index 0000000..f9351e9 --- /dev/null +++ b/kernel/idt.c @@ -0,0 +1,117 @@ +#include "../include/description_table.h" +#include "../include/memory.h" +#include "../include/io.h" +#include "../include/isr.h" +#include "../include/vga.h" + +static isr_t interrupt_handlers[256]; +idt_entry_t idt_entries[256]; // IDT有256个描述符 +idt_ptr_t idt_ptr; + +extern void idt_flush(uint32_t); + +static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { + idt_entries[num].base_low = base & 0xFFFF; + idt_entries[num].base_high = (base >> 16) & 0xFFFF; // 拆成低位和高位 + + idt_entries[num].sel = sel; + idt_entries[num].always0 = 0; + idt_entries[num].flags = flags; + // flags | 0x60,即可被Ring3调用 +} + +void isr_handler(registers_t regs) { + printf("\n[Kernel]: received interrupt: %d",regs.int_no); + + if (interrupt_handlers[regs.int_no]) { + isr_t handler = interrupt_handlers[regs.int_no]; // 有自定义处理程序,调用之 + handler(®s); // 传入寄存器 + } +} + +void irq_handler(registers_t regs) { + if (regs.int_no >= 40) outb(0xA0, 0x20); // 中断号 >= 40,来自从片,发送EOI给从片 + outb(0x20, 0x20); // 发送EOI给主片 + + if (interrupt_handlers[regs.int_no]) { + isr_t handler = interrupt_handlers[regs.int_no]; // 有自定义处理程序,调用之 + handler(®s); // 传入寄存器 + } +} + +void register_interrupt_handler(uint8_t n, isr_t handler) { + interrupt_handlers[n] = handler; +} + +void idt_install() { + idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; + idt_ptr.base = (uint32_t) & idt_entries; + + memset(&idt_entries, 0, sizeof(idt_entry_t) * 256); + + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, 0x20); + outb(0xA1, 0x28); + outb(0x21, 0x04); + outb(0xA1, 0x02); + outb(0x21, 0x01); + outb(0xA1, 0x01); + outb(0x21, 0x0); + outb(0xA1, 0x0); + + +#define REGISTER_ISR(id) idt_set_gate(id, (uint32_t) isr##id, 0x08, 0x8E) + REGISTER_ISR(0); + REGISTER_ISR(1); + REGISTER_ISR(2); + REGISTER_ISR(3); + REGISTER_ISR(4); + REGISTER_ISR(5); + REGISTER_ISR(6); + REGISTER_ISR(7); + REGISTER_ISR(8); + REGISTER_ISR(9); + REGISTER_ISR(10); + REGISTER_ISR(11); + REGISTER_ISR(12); + REGISTER_ISR(13); + REGISTER_ISR(14); + REGISTER_ISR(15); + REGISTER_ISR(16); + REGISTER_ISR(17); + REGISTER_ISR(18); + REGISTER_ISR(19); + REGISTER_ISR(20); + REGISTER_ISR(21); + REGISTER_ISR(22); + REGISTER_ISR(23); + REGISTER_ISR(24); + REGISTER_ISR(25); + REGISTER_ISR(26); + REGISTER_ISR(27); + REGISTER_ISR(28); + REGISTER_ISR(29); + REGISTER_ISR(30); + REGISTER_ISR(31); +#undef REGISTER_ISR +#define REGISTER_IRQ(id, irq_id) idt_set_gate(id, (uint32_t) irq##irq_id, 0x08, 0x8E) + REGISTER_IRQ(32, 0); + REGISTER_IRQ(33, 1); + REGISTER_IRQ(34, 2); + REGISTER_IRQ(35, 3); + REGISTER_IRQ(36, 4); + REGISTER_IRQ(37, 5); + REGISTER_IRQ(38, 6); + REGISTER_IRQ(39, 7); + REGISTER_IRQ(40, 8); + REGISTER_IRQ(41, 9); + REGISTER_IRQ(42, 10); + REGISTER_IRQ(43, 11); + REGISTER_IRQ(44, 12); + REGISTER_IRQ(45, 13); + REGISTER_IRQ(46, 14); + REGISTER_IRQ(47, 15); +#undef REGISTER_IRQ + idt_flush((uint32_t) & idt_ptr); +} \ No newline at end of file diff --git a/kernel/kernel.c b/kernel/kernel.c new file mode 100644 index 0000000..cbb4309 --- /dev/null +++ b/kernel/kernel.c @@ -0,0 +1,42 @@ +#include "../include/common.h" +#include "../include/vga.h" +#include "../include/description_table.h" +#include "../include/io.h" +#include "../include/memory.h" +#include "../include/timer.h" +#include "../include/task.h" +#include "../include/cmos.h" +#include "../include/keyboard.h" +#include "../include/shell.h" + +extern uint32_t end; +uint32_t placement_address = (uint32_t) & end; + + +void kernel_main() { + io_cli(); + vga_install(); + printf("[kernel]: VGA driver load success!\n"); + gdt_install(); + idt_install(); + printf("[kernel]: description table config success!\n"); + init_timer(10); + init_page(); + printf("[kernel]: page set success!\n"); + init_sched(); + printf("[kernel]: PCB load success!\n"); + init_keyboard(); + printf("[kernel]: Keyboard driver load success!\n"); + print_cpu_id(); + io_sti(); + + clock_sleep(25); + + kernel_thread(setup_shell,NULL,"CPOS-Shell"); + + + for (;;){ + io_hlt(); + clock_sleep(1); + } +} \ No newline at end of file diff --git a/kernel/kheap.c b/kernel/kheap.c new file mode 100644 index 0000000..42a6a7a --- /dev/null +++ b/kernel/kheap.c @@ -0,0 +1,108 @@ +#include "../include/memory.h" + +header_t *head = NULL, *tail = NULL; // 内存块链表 +extern page_directory_t *current_directory; +extern uint32_t end; // declared in linker.ld +static uint32_t placement_address = (uint32_t) &end; +void *program_break, *program_break_end; + +static uint32_t kmalloc_int(uint32_t sz, uint32_t align, uint32_t *phys) { + if (program_break) { + // 有内存堆 + void *addr = alloc(sz); // 直接malloc,align丢掉了 + if (phys) { + // 需要物理地址,先找到对应页 + page_t *page = get_page((uint32_t) addr, 0, current_directory); + *phys = page->frame * 0x1000 + ((uint32_t) addr & 0xfff); + } + return (uint32_t) addr; + } + if (align && (placement_address & 0x00000FFF)) { + placement_address &= 0xFFFFF000; + placement_address += 0x1000; + } + if (phys) *phys = placement_address; + uint32_t tmp = placement_address; + placement_address += sz; + return tmp; +} + +uint32_t kmalloc_a(uint32_t size) { + return kmalloc_int(size, 1, 0); +} + +uint32_t kmalloc_p(uint32_t size, uint32_t *phys) { + return kmalloc_int(size, 0, phys); +} + +uint32_t kmalloc_ap(uint32_t size, uint32_t *phys) { + return kmalloc_int(size, 1, phys); +} + +uint32_t kmalloc(uint32_t size) { + return kmalloc_int(size, 0, 0); +} + +void *ksbrk(int incr) { + if (program_break == 0 || program_break + incr >= program_break_end) return (void *) -1; + + void *prev_break = program_break; + program_break += incr; + return prev_break; +} + +// 寻找一个符合条件的指定大小的空闲内存块 +static header_t *get_free_block(uint32_t size) { + header_t *curr = head; + while (curr) { + if (curr->s.is_free && curr->s.size >= size) return curr; + curr = curr->s.next; + } + return NULL; +} + +void *alloc(uint32_t size) { + uint32_t total_size; + void *block; + header_t *header; + if (!size) return NULL; + header = get_free_block(size); + if (header) { + header->s.is_free = 0; + return (void *) (header + 1); + } + total_size = sizeof(header_t) + size; + block = ksbrk(total_size); + if (block == (void *) -1) return NULL; + header = block; + header->s.size = size; + header->s.is_free = 0; + header->s.next = NULL; + if (!head) head = header; + if (tail) tail->s.next = header; + tail = header; + return (void *) (header + 1); +} + +void kfree(void *block) { + header_t *header, *tmp; + if (!block) return; + header = (header_t *) block - 1; + + if ((char *) block + header->s.size == program_break) { + if (head == tail) head = tail = NULL; + else { + tmp = head; + while (tmp) { + if (tmp->s.next == tail) { + tmp->s.next = NULL; + tail = tmp; + } + tmp = tmp->s.next; + } + } + ksbrk(0 - sizeof(header_t) - header->s.size); + return; + } + header->s.is_free = 1; +} diff --git a/kernel/memory.c b/kernel/memory.c new file mode 100644 index 0000000..d3e170b --- /dev/null +++ b/kernel/memory.c @@ -0,0 +1,44 @@ +#include "../include/memory.h" + + +void *memcpy(void *dst_, const void *src_, uint32_t size) { + uint8_t *dst = dst_; + const uint8_t *src = src_; + while (size-- > 0) *dst++ = *src++; + return (void *) src_; +} + +int memcmp(const void *a_, const void *b_, uint32_t size) { + const char *a = a_; + const char *b = b_; + while (size-- > 0) { + if (*a != *b) return *a > *b ? 1 : -1; + a++, b++; + } + return 0; +} + +void *memset(void *s, int c, size_t n) { + unsigned char *p = s; + while (n-- > 0) + *p++ = c; + return s; +} + +void *memmove(void *dest, const void *src, size_t num) { + void *ret = dest; + if (dest < src) { + while (num--)//前->后 + { + *(char *) dest = *(char *) src; + dest = (char *) dest + 1; + src = (char *) src + 1; + } + } else { + while (num--)//后->前 + { + *((char *) dest + num) = *((char *) src + num); + } + } + return ret; +} \ No newline at end of file diff --git a/kernel/page.c b/kernel/page.c new file mode 100644 index 0000000..e6269d9 --- /dev/null +++ b/kernel/page.c @@ -0,0 +1,151 @@ +#include "../include/memory.h" +#include "../include/vga.h" +#include "../include/io.h" + +page_directory_t *kernel_directory = 0; // 内核用页目录 +page_directory_t *current_directory = 0; // 当前页目录 + +uint32_t *frames; +uint32_t nframes; + +extern uint32_t placement_address; +extern void *program_break, *program_break_end; + +static void set_frame(uint32_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + frames[idx] |= (0x1 << off); +} + +static void clear_frame(uint32_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + frames[idx] &= ~(0x1 << off); +} + +static uint32_t test_frame(uint32_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + return (frames[idx] & (0x1 << off)); +} + +uint32_t first_frame() { + for (int i = 0; i < INDEX_FROM_BIT(nframes); i++) { + if (frames[i] != 0xffffffff) { + for (int j = 0; j < 32; j++) { + uint32_t toTest = 0x1 << j; + if (!(frames[i] & toTest)) { + return i * 4 * 8 + j; + } + } + } + } + return (uint32_t) -1; +} + +void alloc_frame(page_t *page, int is_kernel, int is_writable) { + if (page->frame) return; + else { + uint32_t idx = first_frame(); + if (idx == (uint32_t) -1) { + printf("FRAMES_FREE_ERROR: Cannot free frames!\n"); + asm("cli"); + for (;;)io_hlt(); + } + set_frame(idx * 0x1000); + page->present = 1; // 现在这个页存在了 + page->rw = is_writable ? 1 : 0; // 是否可写由is_writable决定 + page->user = is_kernel ? 0 : 1; // 是否为用户态由is_kernel决定 + page->frame = idx; + } +} + +void free_frame(page_t *page) { + uint32_t frame = page->frame; + if (!frame) return; + else { + clear_frame(frame); + page->frame = 0x0; + } +} + +void switch_page_directory(page_directory_t *dir) { + current_directory = dir; + asm volatile("mov %0, %%cr3" : : "r"(&dir->tablesPhysical)); + uint32_t cr0; + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + cr0 |= 0x80000000; + asm volatile("mov %0, %%cr0" : : "r"(cr0)); +} + +page_t *get_page(uint32_t address, int make, page_directory_t *dir) { + address /= 0x1000; + uint32_t table_idx = address / 1024; + if (dir->tables[table_idx]) return &dir->tables[table_idx]->pages[address % 1024]; + else if (make) { + uint32_t tmp; + dir->tables[table_idx] = (page_table_t *) kmalloc_ap(sizeof(page_table_t), &tmp); + memset(dir->tables[table_idx], 0, 0x1000); + dir->tablesPhysical[table_idx] = tmp | 0x7; + return &dir->tables[table_idx]->pages[address % 1024]; + } else return 0; +} + +void page_fault(registers_t *regs) { + asm("cli"); + uint32_t faulting_address; + asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // + + int present = !(regs->err_code & 0x1); // 页不存在 + int rw = regs->err_code & 0x2; // 只读页被写入 + int us = regs->err_code & 0x4; // 用户态写入内核页 + int reserved = regs->err_code & 0x8; // 写入CPU保留位 + int id = regs->err_code & 0x10; // 由取指引起 + + printf("[ERROR]: Page fault |"); + if (present) + printf("Type: present;\n\taddress: %x ", faulting_address); + else if (rw) + printf("Type: read-only;\n\taddress: %x", faulting_address); + else if (us) + printf("Type: user-mode;\n\taddres: %x", faulting_address); + else if (reserved) + printf("Type: reserved;\n\taddress: %x", faulting_address); + else if (id) + printf("Type: decode address;\n\taddress: %x", faulting_address); + + + for (;;) io_hlt(); +} + +void init_page() { + uint32_t mem_end_page = 0xFFFFFFFF; // 4GB Page + + nframes = mem_end_page / 0x1000; + frames = (uint32_t *) kmalloc(INDEX_FROM_BIT(nframes)); + memset(frames, 0, INDEX_FROM_BIT(nframes)); + + kernel_directory = (page_directory_t *) kmalloc_a(sizeof(page_directory_t)); //kmalloc: 无分页情况自动在内核后方分配 | 有分页从内核堆分配 + + memset(kernel_directory, 0, sizeof(page_directory_t)); + current_directory = kernel_directory; + int i = 0; + while (i < placement_address) { + // 内核部分对ring3而言可读不可写 | 无偏移页表映射 + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); + i += 0x1000; + } + + for (int i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i++) { + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); + } + + register_interrupt_handler(14, page_fault); + switch_page_directory(kernel_directory); + + program_break = (void *) KHEAP_START; + program_break_end = (void *) (KHEAP_START + KHEAP_INITIAL_SIZE); +} diff --git a/kernel/task.c b/kernel/task.c new file mode 100644 index 0000000..8e0f3a4 --- /dev/null +++ b/kernel/task.c @@ -0,0 +1,129 @@ +#include "../include/task.h" +#include "../include/common.h" +#include "../include/vga.h" + +struct task_struct *running_proc_head = NULL; +struct task_struct *wait_proc_head = NULL; +struct task_struct *current = NULL; + +extern void switch_to(struct context *prev, struct context *next); + +int now_pid = 0; + +void print_proc_t(int *i,struct task_struct *base,struct task_struct *cur){ + if(cur->pid == base->pid){ + switch (cur->state) { + case TASK_RUNNABLE: + printf("%s %d %s\n",cur->name,cur->pid,"Running"); + break; + case TASK_SLEEPING: + printf("%s %d %s\n",cur->name,cur->pid,"Sleeping"); + break; + case TASK_UNINIT: + printf("%s %d %s\n",cur->name,cur->pid,"Init"); + break; + case TASK_ZOMBIE: + printf("%s %d %s\n",cur->name,cur->pid,"Zombie"); + break; + } + (*i)++; + } else{ + switch (cur->state) { + case TASK_RUNNABLE: + printf("%s %d %s\n",cur->name,cur->pid,"Running"); + break; + case TASK_SLEEPING: + printf("%s %d %s\n",cur->name,cur->pid,"Sleeping"); + break; + case TASK_UNINIT: + printf("%s %d %s\n",cur->name,cur->pid,"Init"); + break; + case TASK_ZOMBIE: + printf("%s %d %s\n",cur->name,cur->pid,"Zombie"); + break; + } + (*i)++; + print_proc_t(i,base,cur->next); + } +} + +void print_proc(){ + printf("====--------[Processes]---------===\n"); + int index = 0; + print_proc_t(&index,current,current->next); + printf("Name Pid Status [All Proc: %d]\n\n",index); +} + +void schedule() { + if (current) { + change_task_to(current->next); + } +} + +void change_task_to(struct task_struct *next) { + if (current != next) { + struct task_struct *prev = current; + current = next; + switch_to(&(prev->context), &(current->context)); + } +} + +int32_t kernel_thread(int (*fn)(void *), void *arg,char* name) { + struct task_struct *new_task = (struct task_struct *) kmalloc(STACK_SIZE); + assert(new_task != NULL, "kern_thread: kmalloc error"); + + // 将栈低端结构信息初始化为 0 + memset(new_task,0, sizeof(struct task_struct)); + + new_task->state = TASK_RUNNABLE; + new_task->stack = current; + new_task->pid = now_pid++; + new_task->mm = NULL; + new_task->name = name; + + uint32_t *stack_top = (uint32_t * )((uint32_t) new_task + STACK_SIZE); + + *(--stack_top) = (uint32_t) arg; + *(--stack_top) = (uint32_t) kthread_exit; + *(--stack_top) = (uint32_t) fn; + + new_task->context.esp = (uint32_t) new_task + STACK_SIZE - sizeof(uint32_t) * 3; + + // 设置新任务的标志寄存器未屏蔽中断,很重要 + new_task->context.eflags = 0x200; + new_task->next = running_proc_head; + + // 找到当前进任务队列,插入到末尾 + struct task_struct *tail = running_proc_head; + assert(tail != NULL, "Must init sched!"); + + while (tail->next != running_proc_head) { + tail = tail->next; + } + tail->next = new_task; + + return new_task->pid; +} + +void kthread_exit() { + register uint32_t val asm ("eax"); + + printf("Thread exited with value %d\n", val); + + while (1); +} + +void init_sched() { + // 为当前执行流创建信息结构体 该结构位于当前执行流的栈最低端 + current = (struct task_struct *) kmalloc(sizeof(struct task_struct)); + + current->state = TASK_RUNNABLE; + current->pid = now_pid++; + current->stack = current; // 该成员指向栈低地址 + current->mm = NULL; // 内核线程不需要该成员 + current->name = "CPOS-System"; + + current->next = current; + + running_proc_head = current; +} \ No newline at end of file diff --git a/kernel/timer.c b/kernel/timer.c new file mode 100644 index 0000000..449c0f2 --- /dev/null +++ b/kernel/timer.c @@ -0,0 +1,35 @@ +#include "../include/timer.h" +#include "../include/io.h" +#include "../include/vga.h" +#include "../include/isr.h" +#include "../include/task.h" + +uint32_t tick = 0; + +static void timer_handle(registers_t *regs) { + io_cli(); + tick++; + schedule(); + io_sti(); +} + +void clock_sleep(uint32_t timer){ + uint32_t sleep = tick + timer; + while(1){ + printf(""); + if(tick >= sleep)break; + } +} + +void init_timer(uint32_t timer) { + register_interrupt_handler(IRQ0, &timer_handle); + uint32_t divisor = 1193180 / timer; + + outb(0x43, 0x36); // 频率 + + uint8_t l = (uint8_t) (divisor & 0xFF); + uint8_t h = (uint8_t) ((divisor >> 8) & 0xFF); + + outb(0x40, l); + outb(0x40, h); +} diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..a2c4c22 --- /dev/null +++ b/linker.ld @@ -0,0 +1,34 @@ +ENTRY(_start) + +SECTIONS +{ + + . = 2M; + + .text BLOCK(4K) : ALIGN(4K) + { + code = .; _code = .; __code = .; + *(.multiboot) + *(.text) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + data = .; _data = .; __data = .; + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + bss = .; _bss = .; __bss = .; + *(COMMON) + *(.bss) + } + + end = .; _end = .; __end = .; +} \ No newline at end of file diff --git a/sysapp/shell.c b/sysapp/shell.c new file mode 100644 index 0000000..64d5127 --- /dev/null +++ b/sysapp/shell.c @@ -0,0 +1,217 @@ +#include "../include/shell.h" +#include "../include/queue.h" +#include "../include/vga.h" +#include "../include/common.h" +#include "../include/io.h" +#include "../include/task.h" +#include "../include/cmos.h" +#include "../include/fat16.h" + +extern Queue *key_char_queue; + +char getc() { + while (key_char_queue->size == 0x00) { + io_hlt(); + + } + return queue_pop(key_char_queue); +} + +int gets(char *buf, int buf_size) { + int index = 0; + char c; + while ((c = getc()) != '\n') { + if (c == '\b') { + if (index > 0) { + index--; + vga_writestring("\b \b"); + } + } else { + buf[index++] = c; + vga_putchar(c); + } + } + buf[index] = '\0'; + vga_putchar(c); + return index; +} + +int cmd_parse(char *cmd_str, char **argv, char token) { + int arg_idx = 0; + while (arg_idx < MAX_ARG_NR) { + argv[arg_idx] = NULL; + arg_idx++; + } + char *next = cmd_str; + int argc = 0; + + while (*next) { + while (*next == token) *next++; + if (*next == 0) break; + argv[argc] = next; + while (*next && *next != token) *next++; + if (*next) *next++ = 0; + if (argc > MAX_ARG_NR) return -1; + argc++; + } + + return argc; +} + +void cmd_echo(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (i == 1) vga_writestring(""); + else vga_writestring(" "); + vga_writestring(argv[i]); + } + vga_putchar('\n'); +} + +void cmd_proc(){ + print_proc(); +} + +void cmd_date(){ + printf("System Time: %s\n",get_date_time()); + print_cpu_id(); +} + +void cmd_ls() { + struct File *root = (struct File *) kmalloc(sizeof(struct File) * MAX_FILE_NUM); + int files = read_root_dir(root); + int index = 0, size = 0; + + for (int i = 0; i < files; ++i) { + struct File file = root[i]; + if (!strcmp(file.name, "\0")) continue; + printf("%s %s %d\n", file.name, file.type == 0x20 ? "" : " ", file.size); + index++; + size += file.size; + } + printf(" All File: %d | All Size: %dByte\n", index, size); + kfree(root); +} + +void cmd_cat(int argc, char **argv) { + if (argc <= 2) { + printf("[Shell-CAT]: If there are too few parameters, please specify the filename and data."); + return; + } + struct File *file = open_file(argv[1]); + if (file == NULL) { + printf("[Shell-CAT]: Not found [%s] \n", argv[1]); + return; + } + + char *buffer[1024] = {0}; + + for (int i = 2; i < argc; i++) { + if (i == 2) strcat(buffer, ""); + else strcat(buffer, " "); + strcat(buffer, argv[i]); + } + + save_file(file, buffer); + kfree(file); +} + +void cmd_read(int argc, char **argv) { + if (argc == 1) { + printf("[Shell-READ]: If there are too few parameters, please specify the filename"); + return; + } + struct File *file = open_file(argv[1]); + char *buffer = (char *) kmalloc(sizeof(char) * 4096); + if (file == NULL) { + printf("[Shell-READ]: Not found [%s] \n", argv[1]); + return; + } + + read_file(file, buffer); + printf("%s\n", buffer); + kfree(buffer); + kfree(file); +} + +void cmd_mkdir(int argc, char **argv) { + if (argc == 1) { + printf("[Shell-MKDIR]: If there are too few parameters, please specify the directory name"); + return; + } + printf("Create directory: %s\n",argv[1]); + struct File *dir = create_dir(argv[1]); + if (dir == NULL) { + printf("[Shell-MKDIR]: Cannot create directory '%s'.", argv[1]); + return; + } + kfree(dir); +} + +void cmd_del(int argc, char **argv) { + if (argc == 1) { + vga_writestring("[Shell-DEL]: If there are too few parameters, please specify the folder name.\n"); + return; + } + struct File *info = open_file(argv[1]); + if (info == NULL) { + printf("[Shell-DEL]: Not found [%s] \n", argv[1]); + return; + } + delete_file(info); + kfree(info); +} + +void setup_shell(){ + vga_clear(); + printf("%s for x86 [Version %s] \n",OS_NAME, OS_VERSION); + printf("Copyright 2024 XIAOYI12 (Build by GCC i686-elf-tools)\n"); + + char com[MAX_COMMAND_LEN]; + char *argv[MAX_ARG_NR]; + int argc = -1; + + while (1) { + printf("CPOS/> "); + if (gets(com, MAX_COMMAND_LEN) <= 0) continue; + argc = cmd_parse(com, argv, ' '); + + if (argc == -1) { + vga_writestring("[Shell]: Error: out of arguments buffer\n"); + continue; + } + + if (!strcmp("version", argv[0])) + printf("%s for x86 [%s]\n",OS_NAME, OS_VERSION); + else if (!strcmp("echo", argv[0])) + cmd_echo(argc, argv); + else if (!strcmp("clear", argv[0])) + vga_clear(); + else if (!strcmp("proc", argv[0])) + cmd_proc(); + else if (!strcmp("sysinfo", argv[0])) + cmd_date(); + else if (!strcmp("ls", argv[0])) + cmd_ls(); + else if (!strcmp("cat", argv[0])) + cmd_cat(argc, argv); + else if (!strcmp("read", argv[0])) + cmd_read(argc, argv); + else if (!strcmp("mkdir", argv[0])) + cmd_mkdir(argc, argv); + else if (!strcmp("del", argv[0]) || !strcmp("rm", argv[0])) + cmd_del(argc, argv); + else if (!strcmp("help", argv[0]) || !strcmp("?", argv[0]) || !strcmp("h", argv[0])) { + vga_writestring("-=[CrashPowerShell Helper]=-\n"); + vga_writestring("help ? h Print shell help info.\n"); + vga_writestring("version Print os version.\n"); + vga_writestring("echo Print message.\n"); + vga_writestring("ls List all files.\n"); + vga_writestring("cat Edit a file\n"); + vga_writestring("read Read a file\n"); + vga_writestring("mkdir Make a directory\n"); + vga_writestring("del rm Delete a file\n"); + vga_writestring("sysinfo Print system info.\n"); + vga_writestring("proc Lists all running processes.\n"); + } else printf("[Shell]: Unknown command '%s'.\n", argv[0]); + } +}