diff --git a/frame.c b/frame.c new file mode 100644 index 0000000000000000000000000000000000000000..5ee340f3b49232c5f1fe0e8a2c1471c5ce6c20a9 --- /dev/null +++ b/frame.c @@ -0,0 +1,101 @@ +#include <system.h> + +/* 帧ä½å›¾ï¼Œç”¨äºŽè®°å½•æ¯ä¸ªå¸§çš„使用状æ€ï¼ˆ1=已分é…,0=空闲) */ +unsigned int* frame_bitmap; +unsigned int total_frames; + +/** + * 设置帧ä½å›¾ä¸çš„æŒ‡å®šä½ + * @param frame_addr è¦è®¾ç½®çš„å¸§åœ°å€ + */ +static void set_frame(addr frame_addr) { + addr frame_index = frame_addr / 0x1000; // 计算帧索引 + addr bitmap_index = INDEX_FROM_BIT(frame_index); // 计算ä½å›¾æ•°ç»„ä¸çš„索引 + addr bit_offset = OFFSET_FROM_BIT(frame_index); // 计算ä½å›¾ç´¢å¼•内的åç§»é‡ + frame_bitmap[bitmap_index] |= (0x1 << bit_offset); // 设置该ä½ä¸º 1 +} + +/** + * 清除帧ä½å›¾ä¸çš„æŒ‡å®šä½ + * @param frame_addr è¦æ¸…é™¤çš„å¸§åœ°å€ + */ +static void clear_frame(addr frame_addr) { + addr frame_index = frame_addr / 0x1000; // 计算帧索引 + addr bitmap_index = INDEX_FROM_BIT(frame_index); // 计算ä½å›¾æ•°ç»„ä¸çš„索引 + addr bit_offset = OFFSET_FROM_BIT(frame_index); // 计算ä½å›¾ç´¢å¼•内的åç§»é‡ + frame_bitmap[bitmap_index] &= ~(0x1 << bit_offset); // æ¸…é™¤è¯¥ä½ +} + +/** + * 检查帧ä½å›¾ä¸çš„æŒ‡å®šä½æ˜¯å¦å·²è®¾ç½® + * @param frame_addr è¦æ£€æŸ¥çš„å¸§åœ°å€ + * @return 返回 1 表示帧已分é…,0 表示帧空闲 + */ +static unsigned int test_frame(addr frame_addr) { + addr frame_index = frame_addr / 0x1000; // 计算帧索引 + addr bitmap_index = INDEX_FROM_BIT(frame_index); // 计算ä½å›¾æ•°ç»„ä¸çš„索引 + addr bit_offset = OFFSET_FROM_BIT(frame_index); // 计算ä½å›¾ç´¢å¼•内的åç§»é‡ + return (frame_bitmap[bitmap_index] & (0x1 << bit_offset)); // 返回该ä½çš„çŠ¶æ€ +} + +/** + * 查找第一个空闲帧 + * @return 返回空闲帧的索引,如果没有空闲帧,返回 -1 + */ +static addr find_first_free_frame() { + // é历帧ä½å›¾ + for (unsigned int i = 0; i < INDEX_FROM_BIT(total_frames); i++) { + if (frame_bitmap[i] != 0xFFFFFFFF) { // 如果当å‰ä½å›¾å—未完全å 用 + for (unsigned int j = 0; j < 32; j++) { + unsigned int test_bit = 0x1 << j; + if (!(frame_bitmap[i] & test_bit)) { + return i * 32 + j; // 计算帧索引并返回 + } + } + } + } + // 未找到空闲帧 + return (addr)-1; +} + +/** + * 分é…一个物ç†å¸§ + * @param p è¦åˆ†é…å¸§çš„é¡µé¢ + * @param is_kernel 是å¦ä¸ºå†…æ ¸æ¨¡å¼é¡µé¢ + * @param is_writable 页颿˜¯å¦å¯å†™ + */ +void frame_alloc(struct page* p, int is_kernel, int is_writable) { + if (p->frame != 0) { + // 页é¢å·²åˆ†é…物ç†å¸§ï¼Œç›´æŽ¥è¿”回 + return; + } + + // 查找第一个空闲帧 + addr frame_index = find_first_free_frame(); + if (frame_index == (addr)-1) { + PANIC("没有空闲帧ï¼"); // 如果没有空闲帧,抛出异常 + } + + // 设置帧ä½å›¾å¹¶æ›´æ–°é¡µé¢å±žæ€§ + set_frame(frame_index * 0x1000); // å°†å¸§æ ‡è®°ä¸ºå·²åˆ†é… + p->present = 1; // 设置页é¢ä¸ºå˜åœ¨ + p->rw = is_writable ? 1 : 0; // è®¾ç½®é¡µé¢æ˜¯å¦å¯å†™ + p->user = is_kernel ? 0 : 1; // è®¾ç½®é¡µé¢æ˜¯å¦ä¸ºç”¨æˆ·æ¨¡å¼ + p->frame = frame_index; // 记录分é…的帧索引 +} + +/** + * 释放物ç†å¸§ + * @param p è¦é‡Šæ”¾å¸§çš„é¡µé¢ + */ +void frame_free(struct page* p) { + if (p->frame == 0) { + // 页颿œªåˆ†é…物ç†å¸§ï¼Œç›´æŽ¥è¿”回 + return; + } + + // 清除帧ä½å›¾å¹¶æ›´æ–°é¡µé¢å±žæ€§ + clear_frame(p->frame * 0x1000); // å°†å¸§æ ‡è®°ä¸ºç©ºé—² + p->frame = 0x0; // 清除页é¢çš„帧索引 +} + diff --git a/gdt.c b/gdt.c index c4d0d9c4878531a1be529ddae71fc66b8eab0881..26588df31a294856e2084d277c604e3ef1861455 100755 --- a/gdt.c +++ b/gdt.c @@ -1,8 +1,6 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) +/* * æè¿°ï¼šå…¨å±€æè¿°ç¬¦è¡¨ï¼ˆGDTï¼‰ç®¡ç† -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ +*/ /* 定义一个GDTæ¡ç›® */ struct gdt_entry @@ -68,6 +66,13 @@ void gdt_install() * 但这个æ¡ç›®çš„访问å—节ä¸çš„æè¿°ç¬¦ç±»åž‹è¯´å®ƒæ˜¯ä¸€ä¸ªæ•°æ®æ®µ */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + /* å®‰è£…ç”¨æˆ·æ¨¡å¼æ®µåˆ°å…¨å±€æè¿°ç¬¦è¡¨ï¼ˆGDT)ä¸ã€‚ */ + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); + + tss_install(5, 0x10, 0x0); // 安装TSS到GDTä¸ + /* 刷新旧的GDTå¹¶å®‰è£…æ–°çš„æ›´æ”¹ï¼ */ gdt_flush(); + tss_flush(); } diff --git a/idt.c b/idt.c index fcbc50cd02a237c02fab7eabb20c375bc8e9af80..bdbb3d3ea28353510862bfcc95531884d72f6bf2 100755 --- a/idt.c +++ b/idt.c @@ -1,8 +1,6 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) +/* * æè¿°ï¼šä¸æ–æè¿°ç¬¦è¡¨ï¼ˆIDTï¼‰ç®¡ç† -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ +*/ #include <system.h> /* 定义一个IDTæ¡ç›® */ diff --git a/include/system.h b/include/system.h index 5456667c4c5c9dae95abe446de9f3128f22e7d83..114f30d58b3b8f0c62a420b270be19b82c5e9332 100755 --- a/include/system.h +++ b/include/system.h @@ -7,6 +7,7 @@ #define __SYSTEM_H typedef int size_t; +typedef unsigned long int addr; /* This defines what the stack looks like after an ISR was running */ struct regs @@ -18,12 +19,11 @@ struct regs }; /* MAIN.C */ -extern void *memcpy(void *dest, const void *src, size_t count); -extern void *memset(void *dest, char val, size_t count); -extern unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count); -extern size_t strlen(const char *str); -extern unsigned char inportb (unsigned short _port); -extern void outportb (unsigned short _port, unsigned char _data); +extern void* memcpy(void* dest, const void* src, int count); +extern void* memset(void* dest, unsigned char val, int count); +extern unsigned short* memsetw(unsigned short* dest, unsigned short val, int count); +extern unsigned char inportb(unsigned short _port); +extern void outportb(unsigned short _port, unsigned char _data); /* CONSOLE.C */ extern void init_video(void); @@ -32,13 +32,23 @@ extern void putch(unsigned char c); extern void cls(); /* GDT.C */ +extern void gdt_flush(); extern void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran); extern void gdt_install(); /* IDT.C */ +extern void idt_load(); extern void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags); extern void idt_install(); +struct regs +{ + unsigned int ds; /* data segment selector */ + unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */ + unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */ + unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */ +}; + /* ISRS.C */ extern void isrs_install(); @@ -54,4 +64,313 @@ extern void timer_install(); /* KEYBOARD.C */ extern void keyboard_install(); +/* Macros used in the bitset algorithms */ +#define INDEX_FROM_BIT(a) (a/(8*4)) +#define OFFSET_FROM_BIT(a) (a%(8*4)) + +/* FRAME.C */ +extern void frame_alloc(struct page* p, int is_kernel, int is_writable); +extern void frame_free(struct page* p); + +/*kmem*/ +extern addr kmalloc_a(addr size); +extern addr kmalloc_p(addr size, addr* phys); +extern addr kmalloc_ap(addr size, addr* phys); +extern addr kmalloc(addr size); +extern void kfree(addr pos); + +extern addr kmem_total(); +extern void kmem_install(struct multiboot_info* mbt); + +/* Multiboot structure definitions for information passed + * by GRUB to the main() function */ +struct multiboot_header +{ + unsigned long magic, flags, checksum; + unsigned long header_addr; + unsigned long load_addr, load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} __attribute__((packed)); + +struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} __attribute__((packed)); + +struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower, mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count, mods_addr; + struct aout_symbol_table symbols; + unsigned long mmap_length; + unsigned long mmap_addr; +} __attribute__((packed)); + +struct multiboot_memory_map +{ + unsigned int size; + unsigned long long int base_addr; + unsigned long long int length; + unsigned int type; +} __attribute__((packed)); + +/*page*/ +/* Structures */ +typedef struct page +{ + unsigned int present : 1; /* Page present in memory */ + unsigned int rw : 1; /* Read-only if clear, read-write if set */ + unsigned int user : 1; /* Supervisor level if clear */ + unsigned int accessed : 1; /* Has the page been accessed since last refresh? */ + unsigned int dirty : 1; /* Has the page been written since last refresh? */ + unsigned int unused : 7; /* Amalgamation of unused and reserved bits */ + unsigned int frame : 20; /* Frame address (shifted 12 bits */ +} page_t; + +struct page_table +{ + struct page pages[1024]; +} __attribute__((packed)); + + +struct page_directory +{ + /* Array of pointers to page tables */ + struct page_table* tables[1024]; + + /* Array of pointers to the page tables above, but + * gives their physical location, for loading into + * the CR3 register */ + addr tables_phys[1024]; + + /* The physical address of tables_phys. This comes + * into play when we get our kernel heap allocated + * and the directory may be in a different location + * in virtual memory */ + addr phys_addr; +} __attribute__((packed)); + + + +extern struct page_directory* current_directory; +extern struct page_directory* kernel_directory; + +/* PAGE.C */ +extern void page_install(); +extern void page_switch(struct page_directory* dir); +extern page_t page_get(addr address, int make, struct page_directory* dir); + +/* SCRN.C */ +extern void cls(); +extern void putch(unsigned char c); +extern void puts(unsigned char* str); +extern void putp(addr pointer); +extern void settextcolor(unsigned char forecolor, unsigned char backcolor); +extern void init_video(); + +/* STRING.C */ +extern int strlen(const unsigned char* str); +extern int strcpy(unsigned char* dest, const unsigned char* src, unsigned int size); +extern int strcmp(const unsigned char* a, const unsigned char* b); +extern unsigned char* strrev(unsigned char* str); +extern unsigned char* itoa(unsigned long num, unsigned char* str, int base); + +/* Macro definitions */ +#define __QUOTEME_(x) #x +#define __QUOTEME(x) __QUOTEME_(x) +#define ASSERT(expr) \ + if (!(expr)) \ + panic("kernel panic (" __FILE__ ":" __QUOTEME(__LINE__) ") - assert \"" __QUOTEME(expr) "\" failed"); +#define PANIC(msg) \ + panic("kernel panic (" __FILE__ ":" __QUOTEME(__LINE__) ") - " msg); + +/* Type definitions */ +typedef unsigned long int addr; + +/* SYSTEM.C */ +extern void panic(unsigned char* msg); + +#define KERNEL_STACK_SIZE 2048 /* Use a 2KB stack */ + +/* Structure for a process */ +struct task +{ + int id; /* Process ID */ + addr esp, ebp; /* Stack and base pointers */ + addr eip; /* Instruction pointer */ + struct page_directory* page_directory; /* Page directory */ + addr kernel_stack; /* Kernel stack location */ + struct task* next; /* Next task in a linked list */ +}; + +/* TASK.C */ +extern void task_install(); +extern void task_switch(); +extern void move_stack(void* new_stack_start, addr size); + +extern int fork(); +extern int getpid(); + +typedef volatile struct tss +{ + unsigned short link; + unsigned short link_h; + + unsigned long esp0; + unsigned short ss0; + unsigned short ss0_h; + + unsigned long esp1; + unsigned short ss1; + unsigned short ss1_h; + + unsigned long esp2; + unsigned short ss2; + unsigned short ss2_h; + + unsigned long cr3; + unsigned long eip; + unsigned long eflags; + + unsigned long eax; + unsigned long ecx; + unsigned long edx; + unsigned long ebx; + + unsigned long esp; + unsigned long ebp; + + unsigned long esi; + unsigned long edi; + + unsigned short es; + unsigned short es_h; + + unsigned short cs; + unsigned short cs_h; + + unsigned short ss; + unsigned short ss_h; + + unsigned short ds; + unsigned short ds_h; + + unsigned short fs; + unsigned short fs_h; + + unsigned short gs; + unsigned short gs_h; + + unsigned short ldt; + unsigned short ldt_h; + + unsigned short trap; + unsigned short iomap; +} __attribute__((packed)) tss_t; + +/* TSS.C */ +extern void tss_set_kernel_stack(unsigned int stack); +extern void tss_install(signed int num, unsigned short ss0, unsigned short esp0); +extern void tss_switch(); + +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x03 +#define FS_BLOCKDEVICE 0x04 +#define FS_PIPE 0x05 +#define FS_SYMLINK 0x06 +#define FS_MOUNTPOINT 0x08 + +struct fs_node; + +/* Function definitions for virtual filesystems to implement */ +typedef unsigned int (*read_type_t)(struct fs_node*, unsigned int, unsigned int, unsigned char*); +typedef unsigned int (*write_type_t)(struct fs_node*, unsigned int, unsigned int, unsigned char*); +typedef void (*open_type_t)(struct fs_node*); +typedef void (*close_type_t)(struct fs_node*); +typedef struct dirent* (*readdir_type_t)(struct fs_node*, unsigned int); +typedef struct fs_node* (*finddir_type_t)(struct fs_node*, char* name); + +/* The definition of a filesystem inode */ +typedef struct fs_node +{ + signed char name[128]; /* The filename */ + unsigned int inode; /* The node ID */ + unsigned int flags; /* The node type */ + unsigned int mask; /* The permissions mask */ + unsigned int uid; /* The owner ID */ + unsigned int gid; /* The group ID */ + unsigned int length; /* The length */ + unsigned int impl; /* Implementation-specific number */ + read_type_t read; + write_type_t write; + open_type_t open; + close_type_t close; + readdir_type_t readdir; + finddir_type_t finddir; + struct fs_node* ptr; /* Used by mountpoints and symlinks */ +} fs_node_t; + +/* The structure of a directory entry */ +struct dirent +{ + char name[128]; + unsigned int inode; /* The node ID */ +}; + +/* Variable declaring the root filesystem */ +extern struct fs_node* fs_root; + +/* Functions called by the kernel to read and write to + * the filesystem */ +unsigned int read_fs(struct fs_node* node, unsigned int offset, unsigned int size, unsigned char* buffer); +unsigned int write_fs(struct fs_node* node, unsigned int offset, unsigned int size, unsigned char* buffer); +void open_fs(struct fs_node* node, unsigned char read, unsigned char write); +void close_fs(struct fs_node* node); +struct dirent* readdir_fs(struct fs_node* node, unsigned int index); +struct fs_node* finddir_fs(struct fs_node* node, char* name); + +#define VMEM_START 0xC0000000 +#define VMEM_INITIAL_SIZE 0x100000 +#define VMEM_INDEX_SIZE 0x20000 +#define VMEM_MAGIC 0x123890AB +#define VMEM_MIN_SIZE 0x70000 + +/* Structure definitions */ +struct vmem_header +{ + unsigned int magic; /* Magic number, used for error checking and identification */ + unsigned char is_hole; /* 1 if this is a hole, 0 if this is a block */ + unsigned int size; /* Size of the block, including this and the footer */ +}; + +struct vmem_footer +{ + unsigned int magic; /* Magic number, same as in header */ + struct vmem_header* header; /* Pointer to the block header */ +}; + +typedef struct vmem_heap +{ + struct ordered_array index; + addr start_address; /* The start of our allocated space */ + addr end_address; /* The end of our allocated space. May be expanded up to max_address */ + addr max_address; /* The maximum address the heap can be expanded to */ + unsigned char supervisor; /* Should extra pages requested by us be mapped as supervisor-only? */ + unsigned char readonly; /* Should extra pages requested by us be mapped as read-only? */ +} vmem_heap_t; + +/* VMEM.C */ +extern vmem_heap_t* create_heap(addr start, addr end, addr max, unsigned char supervisor, unsigned char readonly); +extern void* vmalloc(addr size, unsigned char page_align, struct vmem_heap* heap); +extern void vfree(void* p, struct vmem_heap* heap); + + #endif diff --git a/irq.c b/irq.c index b764b1eada6e3cab8e7b47f2e298d85b7062a29c..48901ebadb1b6b505b3e47418ae32a99ed96805f 100755 --- a/irq.c +++ b/irq.c @@ -1,8 +1,6 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) +/* * æè¿°ï¼šä¸æ–è¯·æ±‚ç®¡ç† -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ +*/ #include <system.h> /* 这些是我们自己的ISRï¼Œå®ƒä»¬æŒ‡å‘æˆ‘们的特殊IRQ处ç†ç¨‹åº @@ -112,4 +110,10 @@ void irq_handler(struct regs *r) /* 在任何情况下,我们都需è¦å‘䏻䏿–控制器å‘é€ä¸€ä¸ªEOI */ outportb(0x20, 0x20); + + /*åœ¨å®šæ—¶å™¨ä¸æ–事件ä¸ï¼Œæˆ‘们å¯èƒ½æ£åœ¨è¿›è¡Œä»»åŠ¡åˆ‡æ¢ï¼Œ + *å› æ¤æˆ‘们åªèƒ½åœ¨å‘䏿–控制器å‘é€EOIï¼ˆä¸æ–结æŸï¼‰ä¹‹åŽæ‰§è¡Œä»»åŠ¡åˆ‡æ¢ï¼Œ + *å› æ¤æˆ‘ä»¬åœ¨è¿™é‡Œè°ƒç”¨å®šæ—¶å™¨ä¸æ–的处ç†ç¨‹åºã€‚*/ + if (handler && r.int_no - 32 == 0) + handler(&r); } diff --git a/isrs.c b/isrs.c index 082882c6e6b89c51d9cab2a6349e3c8b40ec92ab..c60d97f8517b60abd2987e2d24402c51cc372b83 100755 --- a/isrs.c +++ b/isrs.c @@ -1,8 +1,6 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) +/* * æè¿°ï¼šä¸æ–æœåŠ¡ç¨‹åºå®‰è£…程åºå’Œå¼‚常 -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ +*/ #include <system.h> /* 这些是所有异常处ç†ç¨‹åºçš„原型:IDTä¸çš„å‰32个æ¡ç›®ç”±Intelä¿ç•™ï¼Œ @@ -39,9 +37,9 @@ extern void isr28(); extern void isr29(); extern void isr30(); extern void isr31(); +extern void isr80(); -/* 这是一个éžå¸¸é‡å¤çš„函数...它ä¸éš¾ï¼Œåªæ˜¯çƒ¦äººã€‚æ£å¦‚ä½ æ‰€çœ‹åˆ°çš„ï¼Œ -* 我们将IDTä¸çš„å‰32个æ¡ç›®è®¾ç½®ä¸ºå‰32个ISR。我们ä¸èƒ½ä¸ºæ¤ä½¿ç”¨for循环, +/* 我们将IDTä¸çš„å‰32个æ¡ç›®è®¾ç½®ä¸ºå‰32个ISR。我们ä¸èƒ½ä¸ºæ¤ä½¿ç”¨for循环, * å› ä¸ºæ²¡æœ‰åŠžæ³•èŽ·å–与给定æ¡ç›®å¯¹åº”的函数åã€‚æˆ‘ä»¬å°†è®¿é—®æ ‡å¿—è®¾ç½®ä¸º0x8E。 * è¿™æ„å‘³ç€æ¡ç›®å˜åœ¨ï¼Œè¿è¡Œåœ¨çޝ0ï¼ˆå†…æ ¸çº§åˆ«ï¼‰ï¼Œå¹¶ä¸”å°†æ‰€éœ€çš„'14'设置为 * 低5ä½ï¼Œè¿™åœ¨åå…进制ä¸è¡¨ç¤ºä¸º'E'。 */ @@ -82,6 +80,7 @@ void isrs_install() idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); + idt_set_gate(0x80, (unsigned)isr80, 0x08, 0x8E | 0x60); } /* 这是一个简å•çš„å—ç¬¦ä¸²æ•°ç»„ã€‚å®ƒåŒ…å«æ¯ä¸ªå¼‚常对应的消æ¯ã€‚ @@ -126,16 +125,45 @@ unsigned char *exception_messages[] = "Reserved" }; +/* 所有的外部定义的故障处ç†ç¨‹åºï¼Œæˆ‘们䏿ƒ³è®©æ•´ä¸ªå†…æ ¸éƒ½èƒ½çœ‹åˆ°å®ƒä»¬ã€‚ + * å¯ä»¥å°†è¿™äº›æ”¾åœ¨å¤´æ–‡ä»¶ä¸ */ +extern void _page_fault(struct regs* r); + /* 我们所有的异常处ç†ä¸æ–æœåŠ¡ç¨‹åºéƒ½å°†æŒ‡å‘这个函数。 * 这将告诉我们å‘生了什么异常ï¼çŽ°åœ¨ï¼Œæˆ‘ä»¬åªæ˜¯é€šè¿‡è¿›å…¥ä¸€ä¸ª * æ— å°½å¾ªçŽ¯æ¥åœæ¢ç³»ç»Ÿã€‚所有ISR在æœåŠ¡æ—¶éƒ½ä¼šç¦ç”¨ä¸æ–ï¼Œä½œä¸ºä¸€ç§ * 'é”定'机制,以防æ¢IRQå‘ç”Ÿå¹¶ç ´åå†…æ ¸æ•°æ®ç»“æž„ */ -void fault_handler(struct regs *r) +void _fault_handler(struct regs r) { - if (r->int_no < 32) - { - puts(exception_messages[r->int_no]); - puts(" Exception. System Halted!\n"); - for (;;); - } + /* æ˜¯å¦æ˜¯æˆ‘们è¦å¤„ç†çš„æ•…障? */ + switch (r.int_no) + { + case 13: + return; + case 14: + /* 页错误;å‘é€åˆ°page.c */ + page_fault(&r); + return; + case 80: + /* 系统调用;å‘é€åˆ°syscall.c */ + syscall_handler(&r); + return; + default: + /* 䏿˜¯æˆ‘们è¦ç‰¹åˆ«å¤„ç†çš„æ•…障, + * 所以让它通过下é¢çš„ifè¯å¥ */ + break; + } + + /* æ˜¯å¦æ˜¯ç¼–å·ä¸º0到31的故障? */ + if (r.int_no < 32) + { + /* 显示å‘生的异常的æè¿°ã€‚ + * 在本教程ä¸ï¼Œæˆ‘们将简å•åœ°ä½¿ç”¨æ— é™å¾ªçޝæ¥åœæ¢ç³»ç»Ÿã€‚ */ + putch('\n'); + settextcolor(4, 0); + puts(exception_messages[r.int_no]); + puts(" 异常。\nç³»ç»Ÿå·²åœæ¢ï¼\n\0"); + for (;;); + } } + diff --git a/kb.c b/kb.c index bbe59628fd358889972ddd44f278ca942e26d3e3..b425e0b4c9598548488589e884631709abd68453 100755 --- a/kb.c +++ b/kb.c @@ -1,16 +1,15 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) -* æè¿°ï¼šé”®ç›˜é©±åŠ¨ç¨‹åº -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ #include <system.h> -/* KBDUS 表示美国键盘布局。这是一个扫æç 表 -* ç”¨äºŽå¸ƒå±€æ ‡å‡†ç¾Žå›½é”®ç›˜ã€‚æˆ‘ç•™ä¸‹äº†ä¸€äº›æ³¨é‡Š -* ç»™ä½ ä¸€ä¸ªå…³äºŽä»€ä¹ˆé”®æ˜¯ä»€ä¹ˆçš„æƒ³æ³•ï¼Œå³ä½¿æˆ‘将它的数组索引设置为0。 -* ä½ å¯ä»¥ä½¿ç”¨å®å°†å…¶æ›´æ”¹ä¸ºä½ 想è¦çš„ä»»ä½•å†…å®¹ï¼Œå¦‚æžœä½ æ„¿æ„ï¼ */ -unsigned char kbdus[128] = -{ +/* 键盘修饰键定义 */ +#define KB_SHIFT 0x11 +#define KB_ALT 0x12 +#define KB_CTRL 0x13 + +/* 键盘状æ€ä½ï¼Œç”¨äºŽè®°å½• Shiftã€Ctrl å’Œ Alt é”®çš„çŠ¶æ€ */ +unsigned short key_status = 0x0000; + +/* 美国键盘布局的扫æç 表 */ +unsigned char us_keyboard_layout[128] = { 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ '9', '0', '-', '=', '\b', /* é€€æ ¼é”® */ '\t', /* 制表符 */ @@ -49,38 +48,50 @@ unsigned char kbdus[128] = 0, /* 所有其他键都是未定义的 */ }; -/* 处ç†é”®ç›˜ä¸æ– */ -void keyboard_handler(struct regs *r) -{ +/** + * é”®ç›˜ä¸æ–处ç†å‡½æ•° + * @param r ä¿å˜çš„寄å˜å™¨ä¸Šä¸‹æ–‡ + */ +void keyboard_handler(struct regs* r) { unsigned char scancode; - /* 从键盘的数æ®ç¼“å†²åŒºè¯»å– */ + // 从键盘数æ®ç«¯å£è¯»å–扫æç scancode = inportb(0x60); - /* 如果我们从键盘读å–çš„å—节的最高ä½è¢«è®¾ç½®ï¼Œ - * é‚£æ„味ç€ä¸€ä¸ªé”®åˆšåˆšè¢«é‡Šæ”¾ */ - if (scancode & 0x80) - { - /* ä½ å¯ä»¥ä½¿ç”¨è¿™ä¸ªæ¥æŸ¥çœ‹ç”¨æˆ·æ˜¯å¦é‡Šæ”¾äº† - * shift,alt或controlé”®... */ - } - else - { - /* 这里,一个键刚刚被按下。请注æ„ï¼Œå¦‚æžœä½ - * 按ä½ä¸€ä¸ªé”®ï¼Œä½ 会得到é‡å¤çš„æŒ‰é”®ä¸æ–。 + // 检查扫æç 的最高ä½ï¼Œåˆ¤æ–是按键按下还是释放 + if (scancode & 0x80) { + // æŒ‰é”®é‡Šæ”¾å¤„ç† + unsigned char released_key = us_keyboard_layout[scancode & 0x7F]; // 去掉最高ä½å¾—到对应按键 + if (released_key == KB_SHIFT) { + key_status &= ~0x0100; // 清除 Shift çŠ¶æ€ + } else if (released_key == KB_CTRL) { + key_status &= ~0x0010; // 清除 Ctrl çŠ¶æ€ + } else if (released_key == KB_ALT) { + key_status &= ~0x0001; // 清除 Alt çŠ¶æ€ + } + } else { + // æŒ‰é”®æŒ‰ä¸‹å¤„ç† + unsigned char pressed_key = us_keyboard_layout[scancode]; + if (pressed_key == KB_SHIFT) { + key_status |= 0x0100; // 设置 Shift çŠ¶æ€ + } else if (pressed_key == KB_CTRL) { + key_status |= 0x0010; // 设置 Ctrl çŠ¶æ€ + } else if (pressed_key == KB_ALT) { + key_status |= 0x0001; // 设置 Alt çŠ¶æ€ + } - /* 为了å‘ä½ å±•ç¤ºè¿™æ˜¯å¦‚ä½•å·¥ä½œçš„ï¼Œæˆ‘ä»¬ç®€å•地将 - * 键盘扫æç 转æ¢ä¸ºASCII值,然åŽå°†å…¶æ˜¾ç¤ºåˆ°å±å¹•上。 - * ä½ å¯ä»¥å‘挥创æ„ï¼Œä½¿ç”¨ä¸€äº›æ ‡å¿—æ¥æŸ¥çœ‹æ˜¯å¦æŒ‰ä¸‹äº†shift, - * 并使用ä¸åŒçš„å¸ƒå±€ï¼Œæˆ–è€…ä½ å¯ä»¥å‘ä¸Šè¿°å¸ƒå±€æ·»åŠ å¦ä¸€ä¸ª128个æ¡ç›® - * 以对应于按ä½'shift'。如果使用较大的查找表按ä½shift, - * ä½ ä¼šåœ¨æŸ¥æ‰¾æ—¶å°†scancodeå¢žåŠ 128 */ - putch(kbdus[scancode]); + // æ£€æŸ¥æ˜¯å¦æŒ‰ä¸‹ Shift 键,使用对应的å—符表输出 + if (key_status & 0x0100) { // 如果 Shift 被按下 + putch(us_keyboard_layout[scancode + 128]); // 使用大写å—ç¬¦æˆ–ç‰¹æ®Šç¬¦å· + } else { + putch(us_keyboard_layout[scancode]); // 输出普通å—符 + } } } -/* 将键盘处ç†ç¨‹åºå®‰è£…到IRQ1 */ -void keyboard_install() -{ - irq_install_handler(1, keyboard_handler); +/** + * å®‰è£…é”®ç›˜ä¸æ–处ç†ç¨‹åº + */ +void keyboard_install() { + irq_install_handler(1, keyboard_handler); // å°†é”®ç›˜ä¸æ–处ç†ç¨‹åºæŒ‚载到 IRQ1 } diff --git a/kmem.c b/kmem.c new file mode 100644 index 0000000000000000000000000000000000000000..07925a114b27bf13ba0e2fb2db765b355f1bca25 --- /dev/null +++ b/kmem.c @@ -0,0 +1,122 @@ +#include <system.h> + +/* 外部å˜é‡ï¼Œè¡¨ç¤ºå†…æ ¸ç»“æŸåœ°å€ */ +extern unsigned int end; + +/* å†…æ ¸å†…å˜åˆ†é…器的全局å˜é‡ */ +addr kmem_addr = (addr)&end; /* å†…æ ¸å½“å‰å¯ç”¨çš„åœ°å€ */ +addr kmem_memtotal = 0; /* 系统总内å˜å¤§å° */ +struct vmem_heap* kmem_heap = 0; /* å†…æ ¸å †çš„æŒ‡é’ˆ */ + +/** + * 内部内å˜åˆ†é…函数 + * @param size è¦åˆ†é…的内å˜å¤§å° + * @param align 是å¦éœ€è¦å¯¹é½åˆ°é¡µé¢è¾¹ç•Œ + * @param phys 返回物ç†åœ°å€çš„æŒ‡é’ˆï¼ˆå¦‚果需è¦ï¼‰ + * @return 返回分é…çš„è™šæ‹Ÿåœ°å€ + */ +static addr kmalloc_internal(addr size, int align, addr* phys) { + // å¦‚æžœå†…æ ¸å †å·²åˆå§‹åŒ–ï¼Œä½¿ç”¨å †åˆ†é… + if (kmem_heap != 0) { + void* address = vmalloc(size, (unsigned char)align, kmem_heap); + if (phys != 0) { + struct page* page = (struct page*)get_page((addr)address, 0, kernel_directory); + *phys = page->frame * 0x1000 + ((addr)address & 0xFFF); // 计算物ç†åœ°å€ + } + return (addr)address; + } + + // 如果需è¦å¯¹é½ï¼Œå¹¶ä¸”当å‰åœ°å€æœªå¯¹é½åˆ°é¡µé¢è¾¹ç•Œ + if (align == 1 && (kmem_addr & 0xFFFFF000)) { + kmem_addr &= 0xFFFFF000; // 对é½åˆ°é¡µé¢è¾¹ç•Œ + kmem_addr += 0x1000; // 移动到下一页 + } + + // 如果需è¦è¿”回物ç†åœ°å€ + if (phys) { + *phys = kmem_addr; + } + + // 返回当å‰åœ°å€ï¼Œå¹¶å°†åœ°å€å‘å‰ç§»åŠ¨åˆ†é…çš„å¤§å° + addr allocated_addr = kmem_addr; + kmem_addr += size; + return allocated_addr; +} + +/** + * 分é…对é½çš„å†…å˜ + * @param size è¦åˆ†é…的内å˜å¤§å° + * @return 返回分é…的虚拟地å€ï¼ˆå¯¹é½åˆ°é¡µé¢è¾¹ç•Œï¼‰ + */ +addr kmalloc_a(addr size) { + return kmalloc_internal(size, 1, 0); +} + +/** + * 分é…内å˜ï¼Œå¹¶è¿”回物ç†åœ°å€ + * @param size è¦åˆ†é…的内å˜å¤§å° + * @param phys 返回物ç†åœ°å€çš„æŒ‡é’ˆ + * @return 返回分é…çš„è™šæ‹Ÿåœ°å€ + */ +addr kmalloc_p(addr size, addr* phys) { + return kmalloc_internal(size, 0, phys); +} + +/** + * 分é…对é½çš„内å˜ï¼Œå¹¶è¿”回物ç†åœ°å€ + * @param size è¦åˆ†é…的内å˜å¤§å° + * @param phys 返回物ç†åœ°å€çš„æŒ‡é’ˆ + * @return 返回分é…的虚拟地å€ï¼ˆå¯¹é½åˆ°é¡µé¢è¾¹ç•Œï¼‰ + */ +addr kmalloc_ap(addr size, addr* phys) { + return kmalloc_internal(size, 1, phys); +} + +/** + * åˆ†é…æœªå¯¹é½çš„å†…å˜ + * @param size è¦åˆ†é…的内å˜å¤§å° + * @return 返回分é…çš„è™šæ‹Ÿåœ°å€ + */ +addr kmalloc(addr size) { + return kmalloc_internal(size, 0, 0); +} + +/** + * é‡Šæ”¾å†…å˜ + * @param pos è¦é‡Šæ”¾çš„内å˜åœ°å€ + */ +void kfree(addr pos) { + if (kmem_heap != 0) { + vfree((void*)pos, kmem_heap); + } +} + +/** + * 获å–系统的总内å˜å¤§å° + * @return 系统的总内å˜å¤§å°ï¼ˆå—节) + */ +addr kmem_total() { + return kmem_memtotal; +} + +/** + * 安装内å˜ç®¡ç†å™¨å¹¶è®¡ç®—ç³»ç»Ÿæ€»å†…å˜ + * @param mbt Multiboot ä¿¡æ¯ç»“构指针 + */ +void kmem_install(struct multiboot_info* mbt) { + struct multiboot_memory_map* mmap = (struct multiboot_memory_map*)mbt->mmap_addr; + + // é历 Multiboot æä¾›çš„å†…å˜æ˜ 射表,计算系统总内å˜å¤§å° + while ((addr)mmap < mbt->mmap_addr + mbt->mmap_length) { + addr region_end = (addr)mmap->base_addr + (addr)mmap->length; + if (region_end > kmem_memtotal) { + kmem_memtotal = region_end; // 更新总内å˜å¤§å° + } + + // ç§»åŠ¨åˆ°ä¸‹ä¸€ä¸ªå†…å˜æ˜ 射表项 + mmap = (struct multiboot_memory_map*)((addr)mmap + mmap->size + sizeof(addr)); + } + + // è°ƒæ•´å†…æ ¸åœ°å€ï¼Œä»¥é€‚应 Multiboot 模å—ä¿¡æ¯ + kmem_addr += mbt->mods_count * sizeof(unsigned int); +} diff --git a/main.c b/main.c index 8548a5b44c58af160e1975c23b1027ef2d171317..e05d1198ace829de049ca8b1334117e55b066bb6 100755 --- a/main.c +++ b/main.c @@ -1,8 +1,4 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* By: Brandon F. (friesenb@gmail.com) -* Desc: Main.c: C code entry. -* -* Notes: No warranty expressed or implied. Use at own risk. */ + #include <system.h> @@ -54,24 +50,106 @@ void outportb (unsigned short _port, unsigned char _data) } -void main() + +/* 这是一个éžå¸¸ç®€å•çš„main()函数。它所åšçš„就是ååœ¨ä¸€ä¸ªæ— é™å¾ªçޝä¸ã€‚ + * 这将是我们的'idle'循环 */ +void _main(struct multiboot_info* mbt, addr stack) { - int i; + /* å°†å †æ ˆä½ç½®å˜å‚¨åœ¨å…¨å±€å˜é‡ä¸ */ + initial_esp = stack; + + /* è®¾ç½®å†…æ ¸/ CPU æ“ä½œçš„æ ¸å¿ƒç»„ä»¶ */ + unsigned char itoa_buffer[256]; + gdt_install(); + idt_install(); + isrs_install(); + irq_install(); + init_video(); + + /* å¯ç”¨IRQs */ + asm volatile("sti"); + + /* 在内å˜ç®¡ç†å’Œä»»åŠ¡ç®¡ç†ä¹‹å‰å®‰è£…initrd文件系统, + * ä»¥é˜²æ¢æˆ‘们在读å–它之å‰è¦†ç›–它 */ + ASSERT(mbt->mods_count > 0); + puts("åˆå§‹åŒ–initrd... "); + fs_root = initrd_install(*((addr*)(mbt->mods_addr))); + puts("完æˆã€‚\n"); + + /* 安装内å˜å’Œä»»åŠ¡ç®¡ç† */ + kmem_install(mbt); + page_install(); + task_install(); + + /* 安装并处ç†ç³»ç»Ÿä¸çš„å„ç§è®¾å¤‡ */ + puts("å¯ç”¨è®¾å¤‡... "); + timer_install(); + kb_install(); + puts("完æˆã€‚\n"); + + /* æµ‹è¯•ç”¨æˆ·æ¨¡å¼ */ + puts("进入用户模å¼... \n"); + int a; + for (a = 0; a < 16; a += 1) + puts("====="); + puts("\n"); + tss_switch(); + entry(); - gdt_install(); - idt_install(); - isrs_install(); - irq_install(); - init_video(); - timer_install(); - keyboard_install(); + for (;;); - __asm__ __volatile__ ("sti"); + /* 测试任务管ç†ç³»ç»Ÿ */ + puts("æ´¾ç”Ÿå†…æ ¸...\n"); + int ret = fork(); + puts("fork() 返回 "); + puts(itoa(ret, itoa_buffer, 10)); + puts(", 并且 getpid() 返回 "); + puts(itoa(getpid(), itoa_buffer, 10)); + puts("\n==========================================\n"); - puts("Hello World!\n"); + /* 下é¢çš„代ç éƒ¨åˆ†ä¸æ˜¯å¯é‡å…¥çš„ï¼ˆå› ä¸ºinitrd VFS使用全局å˜é‡ï¼Œ + * 这些å˜é‡å°†åœ¨ä¸¤ä¸ªè¿›ç¨‹ä¹‹é—´å…±äº«ï¼‰ï¼Œæ‰€ä»¥ç¡®ä¿åœ¨åˆ—出/çš„ + * å†…å®¹æ—¶æ²¡æœ‰ä¸æ– */ + asm volatile("cli"); -// i = 10 / 0; -// putch(i); + /* 列出initrd的内容 */ + int i = 0; + struct dirent* node = 0; + while ((node = readdir_fs(fs_root, i)) != 0) + { + puts("找到文件 "); + puts(node->name); + struct fs_node* fsnode = finddir_fs(fs_root, node->name); - for (;;); + if ((fsnode->flags & 0x7) == FS_DIRECTORY) + puts("\n\t(目录)\n"); + else + { + puts("\n\t内容: \""); + char buf[256]; + unsigned int sz = read_fs(fsnode, 0, 256, buf); + int j; + for (j = 0; j < sz; j++) + putch(buf[j]); + puts("\"\n"); + } + i++; + } + puts("\n"); + + /* 釿–°å¯ç”¨ä¸æ– */ + asm volatile("sti"); + + ret = fork(); + puts("è¿™æ¡æ¶ˆæ¯åº”该被é‡å¤4次ï¼\n"); + + /* ...并且留下这个循环。在'start.asm'ä¸ä¹Ÿæœ‰ä¸€ä¸ªæ— é™å¾ªçŽ¯ï¼Œ + * å¦‚æžœä½ æ„å¤–åœ°åˆ é™¤äº†ä¸‹ä¸€è¡Œ */ + for (;;); } + + + + + + diff --git a/page.c b/page.c new file mode 100644 index 0000000000000000000000000000000000000000..ff2fe0ce0ad33d550f8332b8de363c2537617c0b --- /dev/null +++ b/page.c @@ -0,0 +1,210 @@ +#include <system.h> + +/* 当剿£åœ¨ä½¿ç”¨çš„页é¢ç›®å½• */ +struct page_directory* current_directory = 0; + +/* å†…æ ¸çš„é¡µé¢ç›®å½• */ +struct page_directory* kernel_directory = 0; + +/* å¤–éƒ¨å®šä¹‰ï¼Œç”¨äºŽè®¿é—®å†…æ ¸å†…å˜å’Œè™šæ‹Ÿå†…å˜çš„相关全局å˜é‡ */ +extern addr kmem_addr; +extern struct vmem_heap* kmem_heap; +extern unsigned int* frames; +extern unsigned int nframes; +extern unsigned int end; + +/** + * èŽ·å–æŒ‡å®šçš„é¡µé¢ + * @param address è™šæ‹Ÿåœ°å€ + * @param make 是å¦éœ€è¦åˆ›å»ºæ–°çš„页é¢è¡¨ï¼ˆ1 表示需è¦ï¼‰ + * @param dir 页é¢ç›®å½• + * @return 返回对应页é¢çš„æŒ‡é’ˆï¼Œå¦‚果失败返回 0 + */ +page_t* get_page(addr address, int make, struct page_directory* dir) { + // 将地å€è½¬æ¢ä¸ºé¡µé¢ç´¢å¼• + address /= 0x1000; + + // 计算页é¢è¡¨çš„索引 + unsigned int table_index = address / 1024; + + // 检查该页é¢è¡¨æ˜¯å¦å·²å˜åœ¨ + if (dir->tables[table_index]) { + // è¿”å›žé¡µé¢æŒ‡é’ˆ + return &dir->tables[table_index]->pages[address % 1024]; + } else if (make) { + // 如果页é¢è¡¨ä¸å˜åœ¨ä¸”需è¦åˆ›å»ºï¼Œåˆ†é…一个新的页é¢è¡¨ + unsigned int temp_phys_addr; + dir->tables[table_index] = (struct page_table*)kmalloc_ap(sizeof(struct page_table), &temp_phys_addr); + memset(dir->tables[table_index], 0, sizeof(struct page_table)); + + // 设置页é¢è¡¨çš„物ç†åœ°å€ + dir->tables_phys[table_index] = temp_phys_addr | 0x7; // 设置为 presentã€rw å’Œç”¨æˆ·æ¨¡å¼ + return &dir->tables[table_index]->pages[address % 1024]; + } else { + // 页é¢è¡¨ä¸å˜åœ¨ï¼Œä¸”ä¸éœ€è¦åˆ›å»º + return 0; + } +} + +/** + * 切æ¢åˆ°æŒ‡å®šçš„页é¢ç›®å½• + * @param dir è¦åˆ‡æ¢çš„页é¢ç›®å½• + */ +void page_switch(struct page_directory* dir) { + current_directory = dir; + + // åŠ è½½æ–°çš„é¡µé¢ç›®å½•地å€åˆ° CR3 + asm volatile("mov %0, %%cr3" :: "r"(dir->phys_addr)); + + // å¯ç”¨åˆ†é¡µï¼ˆè®¾ç½® CR0 的最高ä½ï¼‰ + unsigned int cr0; + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + cr0 |= 0x80000000; // è®¾ç½®åˆ†é¡µæ ‡å¿—ä½ + asm volatile("mov %0, %%cr0" :: "r"(cr0)); +} + +/* 外部定义,用于物ç†å¤åˆ¶é¡µé¢ */ +extern void copy_page_physical(addr src, addr dest); + +/** + * 克隆一个页é¢è¡¨ + * @param src æºé¡µé¢è¡¨ + * @param phys_addr 新页é¢è¡¨çš„物ç†åœ°å€ + * @return 返回克隆的页é¢è¡¨ + */ +struct page_table* clone_table(struct page_table* src, addr* phys_addr) { + // 分é…一个新的页é¢è¡¨ + struct page_table* new_table = (struct page_table*)kmalloc_ap(sizeof(struct page_table), phys_addr); + memset(new_table, 0, sizeof(struct page_table)); + + // é历æºé¡µé¢è¡¨ä¸çš„æ¯ä¸ªé¡µé¢ + for (int i = 0; i < 1024; i++) { + if (!src->pages[i].frame) + continue; // å¦‚æžœé¡µé¢æ²¡æœ‰ç‰©ç†å¸§ï¼Œè·³è¿‡ + + // 为新页é¢åˆ†é…一个物ç†å¸§ + frame_alloc(&new_table->pages[i], 0, 0); + + // å¤åˆ¶é¡µé¢çš„æ ‡å¿—ä½ + new_table->pages[i].present = src->pages[i].present; + new_table->pages[i].rw = src->pages[i].rw; + new_table->pages[i].user = src->pages[i].user; + new_table->pages[i].accessed = src->pages[i].accessed; + new_table->pages[i].dirty = src->pages[i].dirty; + + // 物ç†å¤åˆ¶é¡µé¢å†…容 + copy_page_physical(src->pages[i].frame * 0x1000, new_table->pages[i].frame * 0x1000); + } + + return new_table; +} + +/** + * 克隆页é¢ç›®å½• + * @param src æºé¡µé¢ç›®å½• + * @return 返回克隆的页é¢ç›®å½• + */ +struct page_directory* clone_directory(struct page_directory* src) { + addr phys; + struct page_directory* new_dir = (struct page_directory*)kmalloc_ap(sizeof(struct page_directory), &phys); + memset(new_dir, 0, sizeof(struct page_directory)); + + // 计算物ç†åœ°å€çš„åç§»é‡ + addr offset = (addr)new_dir->tables_phys - (addr)new_dir; + new_dir->phys_addr = phys + offset; + + // é历æºé¡µé¢ç›®å½•ä¸çš„æ¯ä¸ªé¡µé¢è¡¨ + for (int i = 0; i < 1024; i++) { + if (!src->tables[i]) + continue; + + if (kernel_directory->tables[i] == src->tables[i]) { + // å¦‚æžœæ˜¯å†…æ ¸é¡µé¢è¡¨ï¼Œç›´æŽ¥ä½¿ç”¨ç›¸åŒçš„æŒ‡é’ˆ + new_dir->tables[i] = src->tables[i]; + new_dir->tables_phys[i] = src->tables_phys[i]; + } else { + // å¦åˆ™ï¼Œå…‹éš†é¡µé¢è¡¨ + addr new_phys; + new_dir->tables[i] = clone_table(src->tables[i], &new_phys); + new_dir->tables_phys[i] = new_phys | 0x07; // 设置为 presentã€rw å’Œç”¨æˆ·æ¨¡å¼ + } + } + + return new_dir; +} + +/** + * 页颿•…障处ç†å‡½æ•° + * @param r ä¿å˜å¯„å˜å™¨çš„上下文 + */ +void _page_fault(struct regs* r) { + addr fault_addr; + asm volatile("mov %%cr2, %0" : "=r"(fault_addr)); // 获å–引å‘页é¢é”™è¯¯çš„åœ°å€ + + unsigned char buffer[256]; + + // è§£æžé”™è¯¯ä»£ç + int present = !(r->err_code & 0x1); // 页é¢ä¸å˜åœ¨ + int rw = r->err_code & 0x2; // 写æ“作 + int user = r->err_code & 0x4; // 用户模å¼è®¿é—® + int reserved = r->err_code & 0x8; // CPU ä¿ç•™ä½è¢«è¦†ç›– + int id = r->err_code & 0x10; // 由指令引起 + + // 打å°é”™è¯¯ä¿¡æ¯ + settextcolor(4, 0); + puts("\n页é¢é”™è¯¯ ( "); + if (present) puts("ä¸å˜åœ¨ "); + if (rw) puts("写æ“作 "); + if (user) puts("ç”¨æˆ·æ¨¡å¼ "); + if (reserved) puts("ä¿ç•™ "); + puts(") åœ¨åœ°å€ 0x"); + puts(itoa(fault_addr, buffer, 16)); + puts(".\nç³»ç»Ÿå·²åœæ¢ï¼\n"); + + for (;;); // æ»å¾ªçŽ¯ï¼Œåœæ¢ç³»ç»Ÿ +} + +/** + * 安装分页系统 + * @param upper 系统支æŒçš„æœ€å¤§å†…å˜åœ°å€ + */ +void page_install(addr upper) { + unsigned char buffer[256]; + addr memory_end = kmem_total(); + + puts("åˆå§‹åŒ–物ç†å¸§... "); + nframes = memory_end / 0x1000; // è®¡ç®—å¸§çš„æ•°é‡ + frames = (unsigned int*)kmalloc(INDEX_FROM_BIT(nframes)); + memset(frames, 0, INDEX_FROM_BIT(nframes)); + puts("å®Œæˆ ("); + puts(itoa(nframes, buffer, 10)); + puts(" 帧).\n"); + + // åˆå§‹åŒ–å†…æ ¸é¡µé¢ç›®å½• + puts("åˆå§‹åŒ–页é¢ç›®å½•... "); + addr phys; + kernel_directory = (struct page_directory*)kmalloc_a(sizeof(struct page_directory)); + memset(kernel_directory, 0, sizeof(struct page_directory)); + kernel_directory->phys_addr = (addr)kernel_directory->tables_phys; + puts("完æˆã€‚\n"); + + // è®¾ç½®åˆ†é¡µçš„å†…æ ¸éƒ¨åˆ† + for (addr i = 0; i < kmem_addr + 0x1000; i += 0x1000) { + frame_alloc(get_page(i, 1, kernel_directory), 0, 0); + } + + puts("å¯ç”¨åˆ†é¡µ... "); + page_switch(kernel_directory); + puts("完æˆã€‚\n"); + + // åˆå§‹åŒ–å†…æ ¸å † + puts("åˆå§‹åŒ–å†…æ ¸è™šæ‹Ÿå†…å˜å †... "); + kmem_heap = create_heap(VMEM_START, VMEM_START + VMEM_INITIAL_SIZE, 0xCFFFF000, 0, 0); + puts("完æˆã€‚\n"); + + // å…‹éš†å†…æ ¸é¡µé¢ç›®å½• + puts("å…‹éš†å†…æ ¸é¡µé¢ç›®å½•... "); + current_directory = clone_directory(kernel_directory); + page_switch(current_directory); + puts("分页系统安装完æˆã€‚\n"); +} diff --git a/scrn.c b/scrn.c index 8a37bd4352ec774f101948a38903cff357742595..ad849e7ab4600b69b3e39ca3bbb44fecc331971a 100755 --- a/scrn.c +++ b/scrn.c @@ -1,8 +1,6 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) +/* * æè¿°ï¼šæŽ§åˆ¶å°è¾“å…¥/输出的å±å¹•输出函数 -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ +*/ #include <system.h> /* è¿™äº›å®šä¹‰äº†æˆ‘ä»¬çš„æ–‡æœ¬æŒ‡é’ˆï¼ŒèƒŒæ™¯å’Œå‰æ™¯é¢œè‰²ï¼ˆå±žæ€§ï¼‰ï¼Œä»¥åŠ x å’Œ y å…‰æ ‡åæ ‡ */ diff --git a/start.asm b/start.asm index f17cc8fa68b619023ca3de50f70839b11d975fe0..d85bd81f4fe43f280a19556c8d81645182efcee9 100755 --- a/start.asm +++ b/start.asm @@ -1,10 +1,6 @@ -; bkerndev - Bran's Kernel Development Tutorial -; 作者:Brandon F. (friesenb@gmail.com) ; æè¿°ï¼šå†…æ ¸å…¥å£ç‚¹ï¼Œå †æ ˆï¼Œä»¥åŠä¸æ–æœåŠ¡ç¨‹åºã€‚ ; -; 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 -; ; è¿™æ˜¯å†…æ ¸çš„å…¥å£ç‚¹ã€‚我们å¯ä»¥åœ¨è¿™é‡Œè°ƒç”¨main, ; 或者我们å¯ä»¥ä½¿ç”¨å®ƒæ¥è®¾ç½®å †æ ˆæˆ–其他一些好的东西, ; 比如设置GDT和段。请注æ„ï¼Œæ¤æ—¶ä¸æ–是ç¦ç”¨çš„ï¼šå…³äºŽä¸æ–的更多信æ¯ç¨åŽè®¨è®º! @@ -105,6 +101,7 @@ global isr28 global isr29 global isr30 global isr31 +global isr80 ; 0: 除以零异常_isr0: isr0: @@ -324,6 +321,13 @@ isr31: push byte 31 jmp isr_common_stub +; 80: 系统调用 +isr80: + cli + push byte 0 + push byte 80 + jmp isr_common_stub + ; 我们在这里调用一个C函数。我们需è¦è®©æ±‡ç¼–å™¨çŸ¥é“ ; '_fault_handler'å˜åœ¨äºŽå¦ä¸€ä¸ªæ–‡ä»¶ä¸ @@ -332,28 +336,32 @@ extern fault_handler ; 这是我们的通用ISRå˜æ ¹ã€‚它ä¿å˜å¤„ç†å™¨çжæ€ï¼Œè®¾ç½® ; å†…æ ¸æ¨¡å¼æ®µï¼Œè°ƒç”¨C级故障处ç†ç¨‹åºï¼Œæœ€åŽæ¢å¤å †æ ˆå¸§ã€‚isr_common_stub: isr_common_stub: - pusha - push ds - push es - push fs - push gs - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov eax, esp - push eax - mov eax, fault_handler - call eax - pop eax - pop gs - pop fs - pop es - pop ds - popa - add esp, 8 - iret + pusha ; å°†edi, esi, ebp, esp, ebx, edx, ecx, eaxåŽ‹å…¥æ ˆä¸ + + mov ax, ds ; å°†ds寄å˜å™¨çš„低16ä½å˜å…¥eax + push eax ; ä¿å˜æ•°æ®æ®µæè¿°ç¬¦ + + mov ax, 0x10 ; åŠ è½½å†…æ ¸æ•°æ®æ®µæè¿°ç¬¦ + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + call fault_handler + + pop eax ; æ¢å¤åŽŸå§‹çš„æ•°æ®æ®µæè¿°ç¬¦ + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; 弹出edi, esi, ebp... + add esp, 8 ; 清ç†åŽ‹å…¥çš„é”™è¯¯ä»£ç å’ŒISRç¼–å· + ; çš„æ ˆç©ºé—´ + + sti + iret ; 一次性弹出5个东西:CS, EIP, EFLAGS, SSå’ŒESP! + global irq0 global irq1 @@ -487,31 +495,32 @@ irq15: extern irq_handler irq_common_stub: - pusha - push ds - push es - push fs - push gs + pusha ; å°†edi, esi, ebp, esp, ebx, edx, ecx, eaxåŽ‹å…¥æ ˆä¸ + + mov ax, ds ; å°†ds寄å˜å™¨çš„低16ä½å˜å…¥eax + push eax ; ä¿å˜æ•°æ®æ®µæè¿°ç¬¦ + + mov ax, 0x10 ; åŠ è½½å†…æ ¸æ•°æ®æ®µæè¿°ç¬¦ + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + call irq_handler + + pop eax ; æ¢å¤åŽŸå§‹çš„æ•°æ®æ®µæè¿°ç¬¦ + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; 弹出edi, esi, ebp... + add esp, 8 ; 清ç†åŽ‹å…¥çš„é”™è¯¯ä»£ç å’ŒISRç¼–å· + ; çš„æ ˆç©ºé—´ + + sti + iret ; 一次性弹出5个东西:CS, EIP, EFLAGS, SSå’ŒESP! - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov eax, esp - - push eax - mov eax, irq_handler - call eax - pop eax - - pop gs - pop fs - pop es - pop ds - popa - add esp, 8 - iret ; 这是我们的BSS段定义。目å‰ï¼Œæˆ‘们åªä½¿ç”¨å®ƒæ¥å˜å‚¨å †æ ˆã€‚ ; è®°ä½ï¼Œå †æ ˆå®žé™…上是å‘下增长的,所以我们先声明数æ®å¤§å°ï¼Œ diff --git a/string.c b/string.c new file mode 100644 index 0000000000000000000000000000000000000000..b86cfedde3c5f38afd4a68cf1e2bc100140839c7 --- /dev/null +++ b/string.c @@ -0,0 +1,113 @@ +#include <system.h> + +/** + * 计算å—符串长度 + * @param str 指å‘å—符串的指针 + * @return 返回å—符串的长度(ä¸åŒ…括结尾的 '\0') + */ +int strlen(const unsigned char* str) { + // é历å—符串直到é‡åˆ° '\0',返回å—符个数 + const unsigned char* current_char; + for (current_char = str; *current_char; ++current_char); + return (current_char - str); +} + +/** + * å¤åˆ¶å—符串 + * @param dest ç›®æ ‡åœ°å€ + * @param src æºåœ°å€ + * @param size è¦å¤åˆ¶çš„å—节数 + * @return 返回 0 表示æˆåŠŸ + */ +int strcpy(unsigned char* dest, const unsigned char* src, unsigned int size) { + // 使用内å˜å¤åˆ¶å‡½æ•° memcpy 实现å—符串å¤åˆ¶ + memcpy(dest, src, size); + return 0; // 返回 0 表示æˆåŠŸ +} + +/** + * 比较两个å—符串 + * @param a 第一个å—符串 + * @param b 第二个å—符串 + * @return 如果 a > b 返回 1,如果 a < b 返回 -1,如果相ç‰è¿”回 0 + */ +int strcmp(const unsigned char* a, const unsigned char* b) { + unsigned int len_a = strlen(a); + unsigned int len_b = strlen(b); + + // 比较å—符串长度 + if (len_a > len_b) return 1; + if (len_a < len_b) return -1; + + // 按å—符é€ä¸€æ¯”较 + for (unsigned int i = 0; i < len_a; i++) { + if (a[i] != b[i]) { + return (a[i] > b[i]) ? 1 : -1; + } + } + + // 两个å—ç¬¦ä¸²ç›¸ç‰ + return 0; +} + +/** + * å转å—符串 + * @param str è¦å转的å—符串 + * @return 返回å转åŽçš„å—符串 + */ +unsigned char* strrev(unsigned char* str) { + if (!str || !*str) { + // 如果å—符串为空或长度为 0,直接返回 + return str; + } + + unsigned char* start = str; // 指å‘å—符串开头 + unsigned char* end = str + strlen(str) - 1; // 指å‘å—符串末尾 + + // 交æ¢é¦–å°¾å—ç¬¦ï¼Œç›´åˆ°ä¸¤ä¸ªæŒ‡é’ˆç›¸é‡ + while (end > start) { + unsigned char temp = *start; + *start = *end; + *end = temp; + start++; + end--; + } + + return str; +} + +/** + * 整数转æ¢ä¸ºå—符串 + * @param num è¦è½¬æ¢çš„æ•´æ•° + * @param str 用于å˜å‚¨è½¬æ¢ç»“果的å—符串缓冲区 + * @param base 转æ¢çš„进制(例如 10 表示å进制,16 表示åå…进制) + * @return 返回转æ¢åŽçš„å—符串 + */ +unsigned char* itoa(unsigned long num, unsigned char* str, int base) { + static unsigned char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; // 支æŒçš„æ•°å—å’Œå—æ¯ + unsigned long index = 0; + int is_negative = 0; // è®°å½•æ˜¯å¦æ˜¯è´Ÿæ•°ï¼ˆä»…适用于å进制) + + // 如果是负数且是å进制,记录符å·å¹¶å–ç»å¯¹å€¼ + if ((int)num < 0 && base == 10) { + is_negative = 1; + num = -num; + } + + // 按ä½è®¡ç®—æ¯ä¸€ä½å¯¹åº”çš„å—符 + do { + str[index++] = digits[num % base]; + num /= base; + } while (num > 0); + + // å¦‚æžœæ˜¯è´Ÿæ•°ï¼Œæ·»åŠ è´Ÿå· + if (is_negative) { + str[index++] = '-'; + } + + // æ·»åŠ å—符串结æŸç¬¦ + str[index] = '\0'; + + // å转å—符串,返回结果 + return strrev(str); +} diff --git a/syscall.c b/syscall.c new file mode 100644 index 0000000000000000000000000000000000000000..f831103a9ee78c76c833e9236f7ed24f26c3a43f --- /dev/null +++ b/syscall.c @@ -0,0 +1,44 @@ + +#include <system.h> + +/* 定义å¯è°ƒç”¨çš„å†…æ ¸å‡½æ•° */ +static void *syscalls[1] = +{ + &puts +}; +unsigned int num_syscalls = 1; + +/* 处ç†ç”¨æˆ·ç©ºé—´ä»£ç å‘出的系统调用 */ +void _syscall_handler(struct regs* r) +{ + /* æ£€æŸ¥ç³»ç»Ÿè°ƒç”¨å·æ˜¯å¦æœ‰æ•ˆ */ + if (r->eax > num_syscalls) + return; + + /* èŽ·å–æ‰€éœ€çš„系统调用ä½ç½® */ + void* location = syscalls[r->eax]; + + /* 我们ä¸çŸ¥é“函数需è¦å¤šå°‘ä¸ªå‚æ•°ï¼Œ + * æ‰€ä»¥æˆ‘ä»¬åªæ˜¯æŒ‰ç…§æ£ç¡®çš„顺åºå°†å®ƒä»¬ + * éƒ½åŽ‹å…¥æ ˆä¸ã€‚函数将使用它需è¦çš„æ‰€æœ‰ + * 傿•°ï¼Œç„¶åŽæˆ‘们å¯ä»¥å°†å®ƒä»¬å…¨éƒ¨å¼¹å‡º */ + int ret; + asm volatile (" \ +push %1; \ +push %2; \ +push %3; \ +push %4; \ +push %5; \ +call *%6; \ +pop %%ebx; \ +pop %%ebx; \ +pop %%ebx; \ +pop %%ebx; \ +pop %%ebx; \ +" : "=a" (ret) : "r" (r->edi), "r" (r->esi), "r" (r->edx), "r" (r->ecx), "r" (r->ebx), "r" (location)); + r->eax = ret; +} + + + + diff --git a/system.c b/system.c new file mode 100644 index 0000000000000000000000000000000000000000..1da3fd0d875fa9c32bee8d876ac2ac234b900e74 --- /dev/null +++ b/system.c @@ -0,0 +1,12 @@ +#include <system.h> + + +void panic(unsigned char* msg) +{ + putch('\n'); + settextcolor(4, 0); + puts(msg); + putch('\n'); + for(;;); +} + diff --git a/task.c b/task.c new file mode 100644 index 0000000000000000000000000000000000000000..179ef719f4c9d738b0f5014bc62ad4c9b0455a7e --- /dev/null +++ b/task.c @@ -0,0 +1,198 @@ +#include <system.h> + +/* 当å‰è¿è¡Œçš„任务 */ +volatile struct task* current_task; + +/* 任务链表的起始节点 */ +volatile struct task* task_queue; + +/* 引入外部定义以访问 page.c / process.asm çš„æˆå‘˜ */ +extern addr initial_stack_ptr; +extern addr read_eip(); + +/* 下一个å¯ç”¨çš„进程 ID */ +unsigned int process_id = 1; + +/** + * 将当å‰å †æ ˆç§»åŠ¨åˆ°æ–°çš„å†…å˜ä½ç½® + * @param new_stack_start æ–°å †æ ˆçš„èµ·å§‹åœ°å€ + * @param size å †æ ˆçš„å¤§å° + */ +void move_stack(void* new_stack_start, addr size) { + addr addr_iter; + + // ä¸ºæ–°å †æ ˆåˆ†é…内å˜ï¼ˆä»Žæ–°å †æ ˆé¡¶éƒ¨å¼€å§‹å‘下分é…) + for (addr_iter = (addr)new_stack_start; addr_iter >= ((addr)new_stack_start - size); addr_iter -= 0x1000) { + frame_alloc((struct page*)get_page(addr_iter, 1, current_directory), 0 /* ç”¨æˆ·æ¨¡å¼ */, 1 /* å¯å†™ */); + } + + // 刷新 TLBï¼ˆé€šè¿‡é‡æ–°åŠ è½½é¡µé¢ç›®å½•地å€ï¼‰ + addr page_dir_address; + asm volatile("mov %%cr3, %0" : "=r"(page_dir_address)); + asm volatile("mov %0, %%cr3" : : "r"(page_dir_address)); + + // ä¿å˜æ—§çš„å †æ ˆæŒ‡é’ˆå’ŒåŸºæŒ‡é’ˆ + addr old_esp, old_ebp; + asm volatile("mov %%esp, %0" : "=r"(old_esp)); + asm volatile("mov %%ebp, %0" : "=r"(old_ebp)); + + // è®¡ç®—å †æ ˆåç§»é‡ + addr stack_offset = (addr)new_stack_start - initial_stack_ptr; + addr new_esp = old_esp + stack_offset; + addr new_ebp = old_ebp + stack_offset; + + // å¤åˆ¶æ—§å †æ ˆå†…容到新ä½ç½® + memcpy((void*)new_esp, (void*)old_esp, initial_stack_ptr - old_esp); + + // ä¿®å¤æ–°å †æ ˆä¸çš„æŒ‡é’ˆï¼ˆå¦‚基指针) + for (addr_iter = (addr)new_stack_start; addr_iter > (addr)new_stack_start - size; addr_iter -= 4) { + addr temp_value = *(addr*)addr_iter; + if ((old_esp < temp_value) && (temp_value < initial_stack_ptr)) { + temp_value += stack_offset; + *(addr*)addr_iter = temp_value; + } + } + + // 切æ¢åˆ°æ–°çš„å †æ ˆæŒ‡é’ˆå’ŒåŸºæŒ‡é’ˆ + asm volatile("mov %0, %%esp" : : "r"(new_esp)); + asm volatile("mov %0, %%ebp" : : "r"(new_ebp)); +} + +/** + * 分å‰å½“å‰è¿›ç¨‹ + * @return 返回å进程的 PID(在父进程ä¸ï¼‰ï¼Œåœ¨å进程ä¸è¿”回 0 + */ +int fork() { + // ç¦ç”¨ä¸æ–以确ä¿è¿›ç¨‹åˆ†å‰çš„安全性 + asm volatile("cli"); + + // 获å–当å‰ä»»åŠ¡çš„å¼•ç”¨ + struct task* parent_task = (struct task*)current_task; + + // 克隆当å‰è¿›ç¨‹çš„地å€ç©ºé—´ + struct page_directory* new_page_dir = (struct page_directory*)clone_directory(current_directory); + + // 创建新任务(å进程) + struct task* child_task = (struct task*)kmalloc(sizeof(struct task)); + child_task->id = process_id++; + child_task->esp = child_task->ebp = 0; + child_task->eip = 0; + child_task->page_directory = new_page_dir; + child_task->kernel_stack = kmalloc_a(KERNEL_STACK_SIZE); + child_task->next = 0; + + // å°†æ–°ä»»åŠ¡æ·»åŠ åˆ°ä»»åŠ¡é˜Ÿåˆ—æœ«å°¾ + struct task* queue_iter = (struct task*)task_queue; + while (queue_iter->next) + queue_iter = queue_iter->next; + queue_iter->next = child_task; + + // 获å–当å‰çš„ EIP(执行指令指针) + addr instruction_ptr = read_eip(); + + // 如果当å‰ä»»åŠ¡æ˜¯çˆ¶è¿›ç¨‹ï¼Œè®¾ç½®å任务的寄å˜å™¨çŠ¶æ€ + if (current_task == parent_task) { + addr current_esp, current_ebp; + asm volatile("mov %%esp, %0" : "=r"(current_esp)); + asm volatile("mov %%ebp, %0" : "=r"(current_ebp)); + + child_task->esp = current_esp; + child_task->ebp = current_ebp; + child_task->eip = instruction_ptr; + + // 釿–°å¯ç”¨ä¸æ– + asm volatile("sti"); + + // 返回å进程的 PID + return child_task->id; + } else { + // å进程的返回值:0 + return 0; + } +} + +/** + * 获å–当å‰è¿›ç¨‹çš„ PID + * @return 当å‰ä»»åŠ¡çš„ PID + */ +int getpid() { + return current_task->id; +} + +/** + * 在任务之间切æ¢ï¼›ç”±å®šæ—¶å™¨ä¸æ–自动调用 + */ +void switch_task() { + // 如果当å‰ä»»åŠ¡æœªåˆå§‹åŒ–,则直接返回 + if (!current_task) + return; + + // ä¿å˜å½“å‰ä»»åŠ¡çš„çŠ¶æ€ + addr current_esp, current_ebp, current_eip; + asm volatile("mov %%esp, %0" : "=r"(current_esp)); + asm volatile("mov %%ebp, %0" : "=r"(current_ebp)); + + current_eip = read_eip(); + + // 检查是å¦å‘ç”Ÿäº†ä»»åŠ¡åˆ‡æ¢ + if (current_eip == 0x12345) + return; + + current_task->eip = current_eip; + current_task->esp = current_esp; + current_task->ebp = current_ebp; + + // 切æ¢åˆ°ä¸‹ä¸€ä¸ªä»»åŠ¡ + current_task = current_task->next; + if (!current_task) + current_task = task_queue; + + // æ¢å¤æ–°ä»»åŠ¡çš„çŠ¶æ€ + current_eip = current_task->eip; + current_esp = current_task->esp; + current_ebp = current_task->ebp; + current_directory = current_task->page_directory; + + // è®¾ç½®æ–°ä»»åŠ¡çš„å†…æ ¸å †æ ˆ + tss_set_kernel_stack(current_task->kernel_stack + KERNEL_STACK_SIZE); + + // 执行任务切æ¢ï¼ˆä¿®æ”¹å¯„å˜å™¨å’Œæ®µå¯„å˜å™¨ï¼‰ + asm volatile( + "cli; " + "mov %0, %%ecx; " + "mov %1, %%esp; " + "mov %2, %%ebp; " + "mov %3, %%cr3; " + "mov $0x12345, %%eax; " + "sti; " + "jmp *%%ecx" + : + : "r"(current_eip), "r"(current_esp), "r"(current_ebp), "r"(current_directory->phys_addr)); +} + +/** + * åˆå§‹åŒ–任务管ç†å™¨å¹¶å¯ç”¨å¤šä»»åŠ¡ + */ +void task_install() { + puts("å¯ç”¨å¤šä»»åŠ¡... "); + + // ç¦ç”¨ä¸æ– + asm volatile("cli"); + + // å°†å †æ ˆé‡æ–°å®šä½åˆ°æŒ‡å®šä½ç½® + move_stack((void*)0xE0000000, 0x2000); + + // åˆå§‹åŒ–ç¬¬ä¸€ä¸ªä»»åŠ¡ï¼ˆå†…æ ¸ä»»åŠ¡ï¼‰ + current_task = task_queue = (struct task*)kmalloc(sizeof(struct task)); + current_task->id = process_id++; + current_task->esp = current_task->ebp = 0; + current_task->eip = 0; + current_task->page_directory = current_directory; + current_task->next = 0; + current_task->kernel_stack = kmalloc_a(KERNEL_STACK_SIZE); + + // 釿–°å¯ç”¨ä¸æ– + asm volatile("sti"); + + puts("完æˆã€‚\n"); +} diff --git a/timer.c b/timer.c index e42f4361ccf9e8fb100ed61b3b7420af49db017c..7a134a44ddd308a75a8ba409b27fc59ceb7cf5f2 100755 --- a/timer.c +++ b/timer.c @@ -1,8 +1,6 @@ -/* bkerndev - Bran's Kernel Development Tutorial -* 作者:Brandon F. (friesenb@gmail.com) +/* * æè¿°ï¼šå®šæ—¶å™¨é©±åŠ¨ç¨‹åº -* -* 注æ„ï¼šæ— æ˜Žç¤ºæˆ–æš—ç¤ºçš„ä¿è¯ã€‚使用风险自负。 */ +*/ #include <system.h> /* 这将跟踪系统è¿è¡Œäº†å¤šå°‘æ»´ç”(ticks) */ @@ -11,30 +9,39 @@ int timer_ticks = 0; /* 处ç†å®šæ—¶å™¨ã€‚åœ¨è¿™ç§æƒ…况下,它éžå¸¸ç®€å•ï¼šæ¯æ¬¡å®šæ—¶å™¨è§¦å‘时, * æˆ‘ä»¬éƒ½ä¼šå¢žåŠ 'timer_ticks' å˜é‡ã€‚默认情况下,定时器æ¯ç§’è§¦å‘ * 18.222次。为什么是18.222Hz?IBMçš„æŸä¸ªå·¥ç¨‹å¸ˆä¸€å®šæŠ½äº†äº›å¥‡æ€ªçš„东西 */ -void timer_handler(struct regs *r) +void timer_handler(struct regs* r) { - /* å¢žåŠ æˆ‘ä»¬çš„ 'æ»´ç”计数' */ - timer_ticks++; - - /* æ¯18个滴ç”(大约1秒),我们将在å±å¹•ä¸Šæ˜¾ç¤ºä¸€æ¡æ¶ˆæ¯ */ - if (timer_ticks % 18 == 0) - { - puts("One second has passed\n"); - } + /* å¢žåŠ æˆ‘ä»¬çš„'tick count' */ + timer_ticks++; + + /* 指示任务管ç†ç³»ç»Ÿå¯èƒ½åˆ‡æ¢ä»»åŠ¡ */ + switch_task(); } -/* 这将æŒç»å¾ªçŽ¯ï¼Œç›´åˆ°è¾¾åˆ°ç»™å®šçš„æ—¶é—´ */ +/* è®¾ç½®ç¡¬ä»¶å®šæ—¶å™¨çš„ç›¸ä½ */ +void timer_phase(int hz) +{ + int divisor = 1193180 / hz; /* 计算我们的除数 */ + outportb(0x43, 0x36); /* 设置我们的命令å—节为0x36 */ + outportb(0x40, divisor & 0xFF); /* 设置除数的低å—节 */ + outportb(0x40, divisor >> 8); /* 设置除数的高å—节 */ +} + +/* è¿™å°†ä¸æ–循环,直到达到给定的时间 */ void timer_wait(int ticks) { - unsigned long eticks; + unsigned long eticks; - eticks = timer_ticks + ticks; - while(timer_ticks < eticks); + eticks = timer_ticks + ticks; + while (timer_ticks < eticks); } /* 通过将定时器处ç†ç¨‹åºå®‰è£…到IRQ0æ¥è®¾ç½®ç³»ç»Ÿæ—¶é’Ÿ */ void timer_install() { - /* å°† 'timer_handler' 安装到IRQ0 */ - irq_install_handler(0, timer_handler); + /* 设置相ä½ï¼Œä½¿å®šæ—¶å™¨æ¯100ms触å‘一次 */ + timer_phase(100); + + /* å°†'timer_handler'安装到IRQ0 */ + irq_install_handler(0, timer_handler); } diff --git a/tss.c b/tss.c new file mode 100644 index 0000000000000000000000000000000000000000..c9700d236d1f6e04026467c0fa8b9469f647e8b6 --- /dev/null +++ b/tss.c @@ -0,0 +1,93 @@ +#include <system.h> + +/* 定义全局 TSS 结构 */ +tss_t sys_tss; + +/* 外部汇编函数,用于刷新 GDT ä¸çš„ TSS ä½ç½® */ +extern void _tss_flush(); + +/** + * è®¾ç½®å†…æ ¸å †æ ˆ + * @param stack å†…æ ¸å †æ ˆæŒ‡é’ˆåœ°å€ + * + * å°†å†…æ ¸å †æ ˆåœ°å€å†™å…¥ TSS çš„ esp0 å—æ®µï¼Œè¿™æ˜¯åœ¨å‘生用户模å¼åˆ°å†…æ ¸æ¨¡å¼åˆ‡æ¢æ—¶ + * ä½¿ç”¨çš„å †æ ˆã€‚ + */ +void tss_set_kernel_stack(unsigned int stack) { + sys_tss.esp0 = stack; +} + +/** + * 在 GDT ä¸å®‰è£… TSS + * @param num GDT ä¸çš„ TSS æè¿°ç¬¦ç´¢å¼• + * @param ss0 å†…æ ¸æ•°æ®æ®µé€‰æ‹©å + * @param esp0 å†…æ ¸å †æ ˆæŒ‡é’ˆåœ°å€ + * + * å°† TSS çš„æè¿°ç¬¦æ·»åŠ åˆ° GDT ä¸ï¼Œåˆå§‹åŒ– TSS ç»“æž„ï¼Œå¹¶è®¾ç½®é»˜è®¤çš„å†…æ ¸æ®µå’Œå †æ ˆã€‚ + */ +void tss_install(signed int num, unsigned short ss0, unsigned short esp0) { + // 计算 TSS 的基地å€å’Œå¤§å° + addr base = (addr)&sys_tss; + addr size = base + sizeof(tss_t); + + // å°† TSS æè¿°ç¬¦æ·»åŠ åˆ° GDT ä¸ + gdt_set_gate(num, base, size, 0xE9, 0x00); // 0xE9 表示 TSS 的类型和æƒé™ + + // ç¡®ä¿ TSS 结构åˆå§‹åŒ–为 0 + memset(&sys_tss, 0, sizeof(sys_tss)); + + // è®¾ç½®å†…æ ¸å †æ ˆæ®µé€‰æ‹©åå’Œå †æ ˆæŒ‡é’ˆ + sys_tss.ss0 = ss0; + sys_tss.esp0 = esp0; + + /* + * 设置 TSS ä¸çš„æ®µé€‰æ‹©å: + * cs: å†…æ ¸ä»£ç æ®µ (RPL = 3) + * ss, ds, es, fs, gs: å†…æ ¸æ•°æ®æ®µ (RPL = 3) + * RPL (请求特æƒçº§åˆ«) 为 3 表示用户模å¼å¯ä»¥è®¿é—®è¿™äº›æ®µã€‚ + */ + sys_tss.cs = 0x0B; // å†…æ ¸ä»£ç æ®µ (RPL = 3) + sys_tss.ss = sys_tss.ds = sys_tss.es = sys_tss.fs = sys_tss.gs = 0x13; // å†…æ ¸æ•°æ®æ®µ (RPL = 3) +} + +/* 外部定义,用于访问当å‰ä»»åŠ¡ */ +extern volatile struct task* current_task; + +/** + * 切æ¢åˆ°ç”¨æˆ·æ¨¡å¼ + * + * 将处ç†å™¨ä»Žå†…æ ¸æ¨¡å¼åˆ‡æ¢åˆ°ç”¨æˆ·æ¨¡å¼ï¼Œå¹¶è®¾ç½®ç›¸å…³æ®µå¯„å˜å™¨å’Œå †æ ˆã€‚ + */ +void tss_switch() { + // 设置当å‰ä»»åŠ¡çš„å†…æ ¸å †æ ˆ + tss_set_kernel_stack(current_task->kernel_stack + KERNEL_STACK_SIZE); + + /* + * 汇编代ç 将处ç†å™¨ä»Žå†…æ ¸æ¨¡å¼åˆ‡æ¢åˆ°ç”¨æˆ·æ¨¡å¼ã€‚ + * - è®¾ç½®æ•°æ®æ®µå¯„å˜å™¨ï¼ˆds, es, fs, gsï¼‰ä¸ºç”¨æˆ·æ¨¡å¼æ®µé€‰æ‹©å (0x23)。 + * - è®¾ç½®å †æ ˆæŒ‡é’ˆå’Œä»£ç æ®µå¯„å˜å™¨ï¼ˆcsï¼‰ä¸ºç”¨æˆ·æ¨¡å¼æ®µé€‰æ‹©å (0x1B)。 + * - 使用 iret 指令跳转到用户模å¼ä»£ç 段。 + */ + asm volatile( + "cli; " /* ç¦ç”¨ä¸æ– */ + "mov $0x23, %%ax; " /* åŠ è½½ç”¨æˆ·æ¨¡å¼æ•°æ®æ®µé€‰æ‹©å (RPL = 3) */ + "mov %%ax, %%ds; " /* 设置 ds 段寄å˜å™¨ */ + "mov %%ax, %%es; " /* 设置 es 段寄å˜å™¨ */ + "mov %%ax, %%fs; " /* 设置 fs 段寄å˜å™¨ */ + "mov %%ax, %%gs; " /* 设置 gs 段寄å˜å™¨ */ + "mov %%esp, %%eax; " /* ä¿å˜å½“å‰å †æ ˆæŒ‡é’ˆåˆ° eax */ + "pushl $0x23; " /* åŽ‹å…¥ç”¨æˆ·æ¨¡å¼æ•°æ®æ®µé€‰æ‹©ååˆ°å †æ ˆ */ + "pushl %%eax; " /* 压入用户模å¼çš„å †æ ˆæŒ‡é’ˆ */ + "pushf; " /* åŽ‹å…¥å½“å‰ EFLAGS 寄å˜å™¨ */ + "pop %%eax; " /* 弹出 EFLAGS 到 eax */ + "or $0x200, %%eax; " /* 设置 IF æ ‡å¿— (å¯ç”¨ä¸æ–) */ + "push %%eax; " /* 压回修改åŽçš„ EFLAGS */ + "pushl $0x1B; " /* 压入用户模å¼ä»£ç 段选择å */ + "push $1f; " /* åŽ‹å…¥è¿”å›žåœ°å€ (è·³è½¬åˆ°æ ‡ç¾ 1) */ + "iret; " /* æ‰§è¡Œä¸æ–返回,切æ¢åˆ°ç”¨æˆ·æ¨¡å¼ */ + "1: " + : + : + : "eax" + ); +} diff --git a/tutortial.txt b/tutortial.txt deleted file mode 100644 index 81ee46f34274c1891195b362f0141274de35bfc7..0000000000000000000000000000000000000000 --- a/tutortial.txt +++ /dev/null @@ -1,49 +0,0 @@ -需è¦qemuã€gccã€nasmï¼Œç„¶åŽæ‰§è¡Œä»¥ä¸‹å‘½ä»¤ï¼ˆlinux): - - -#!/bin/bash - -echo "Now assembling, compiling, and linking your kernel:" - -# Assemble the start.asm file for x86_64 architecture -nasm -f elf32 -o start.o start.asm - -# Compile C source files with the appropriate flags -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o main.o main.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o scrn.o scrn.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o gdt.o gdt.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o idt.o idt.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o isrs.o isrs.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o irq.o irq.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o timer.o timer.c - -gcc -m32 -fno-pic -mno-red-zone -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -nostdinc -fno-builtin -I./include -c -o kb.o kb.c - -# Link all object files into the kernel binary -ld -m elf_i386 -T link.ld -o kernel.bin start.o main.o scrn.o gdt.o idt.o isrs.o irq.o timer.o kb.o - -echo "Cleaning up object files..." -rm -f *.o - -echo "Done!" - - -ç„¶åŽæ‰§è¡Œï¼š -sudo apt update -sudo apt install qemu qemu-system-i386 -ä¸‹è½½å¯¹åº”æ¨¡æ‹Ÿå™¨ï¼Œç„¶åŽæ‰§è¡Œ: -qemu-system-i386 -kernel kernel.bin diff --git a/vfs,c b/vfs,c new file mode 100644 index 0000000000000000000000000000000000000000..79f76bb44babe26bba6ed319f2fa4818cc60a279 --- /dev/null +++ b/vfs,c @@ -0,0 +1,96 @@ +#include <system.h> + +/* 定义全局å˜é‡ï¼Œè¡¨ç¤ºæ ¹æ–‡ä»¶ç³»ç»Ÿ */ +struct fs_node* fs_root = 0; /* æ ¹æ–‡ä»¶ç³»ç»ŸèŠ‚ç‚¹ */ + +/** + * 从文件系统ä¸çš„ inode è¯»å–æ•°æ® + * @param node è¦è¯»å–的文件节点 + * @param offset åç§»é‡ï¼Œä»Žæ–‡ä»¶çš„哪个ä½ç½®å¼€å§‹è¯»å– + * @param size è¦è¯»å–的大å°ï¼ˆå—节) + * @param buffer 用于å˜å‚¨è¯»å–内容的缓冲区 + * @return æˆåŠŸè¯»å–çš„å—èŠ‚æ•°ï¼Œå¦‚æžœèŠ‚ç‚¹ä¸æ”¯æŒè¯»å–,则返回 0 + */ +unsigned int read_fs(struct fs_node* node, unsigned int offset, unsigned int size, unsigned char* buffer) { + if (node->read != 0) { + // 如果节点æä¾›äº†è¯»å–函数,则调用该函数 + return node->read(node, offset, size, buffer); + } else { + // èŠ‚ç‚¹ä¸æ”¯æŒè¯»å– + return 0; + } +} + +/** + * 呿–‡ä»¶ç³»ç»Ÿä¸çš„ inode å†™å…¥æ•°æ® + * @param node è¦å†™å…¥çš„æ–‡ä»¶èŠ‚ç‚¹ + * @param offset åç§»é‡ï¼Œä»Žæ–‡ä»¶çš„哪个ä½ç½®å¼€å§‹å†™å…¥ + * @param size è¦å†™å…¥çš„大å°ï¼ˆå—节) + * @param buffer 包å«è¦å†™å…¥æ•°æ®çš„缓冲区 + * @return æˆåŠŸå†™å…¥çš„å—èŠ‚æ•°ï¼Œå¦‚æžœèŠ‚ç‚¹ä¸æ”¯æŒå†™å…¥ï¼Œåˆ™è¿”回 0 + */ +unsigned int write_fs(struct fs_node* node, unsigned int offset, unsigned int size, unsigned char* buffer) { + if (node->write != 0) { + // 如果节点æä¾›äº†å†™å…¥å‡½æ•°ï¼Œåˆ™è°ƒç”¨è¯¥å‡½æ•° + return node->write(node, offset, size, buffer); + } else { + // èŠ‚ç‚¹ä¸æ”¯æŒå†™å…¥ + return 0; + } +} + +/** + * 打开文件系统ä¸çš„ inode + * @param node è¦æ‰“开的文件节点 + * @param read 是å¦ä»¥åªè¯»æ¨¡å¼æ‰“å¼€ + * @param write 是å¦ä»¥å†™å…¥æ¨¡å¼æ‰“å¼€ + */ +void open_fs(struct fs_node* node, unsigned char read, unsigned char write) { + if (node->open != 0) { + // 如果节点æä¾›äº†æ‰“开函数,则调用该函数 + node->open(node); + } + // 如果没有æä¾›æ‰“å¼€å‡½æ•°ï¼Œåˆ™ä¸æ‰§è¡Œä»»ä½•æ“作 +} + +/** + * 关闿–‡ä»¶ç³»ç»Ÿä¸çš„ inode + * @param node è¦å…³é—的文件节点 + */ +void close_fs(struct fs_node* node) { + if (node->close != 0) { + // 如果节点æä¾›äº†å…³é—函数,则调用该函数 + node->close(node); + } + // 如果没有æä¾›å…³é—å‡½æ•°ï¼Œåˆ™ä¸æ‰§è¡Œä»»ä½•æ“作 +} + +/** + * 从文件系统ä¸çš„目录读å–目录项 + * @param node è¦è¯»å–的目录节点 + * @param index è¦è¯»å–的目录项索引(从 0 开始) + * @return è¿”å›žç›®å½•é¡¹ç»“æž„çš„æŒ‡é’ˆï¼Œå¦‚æžœèŠ‚ç‚¹ä¸æ˜¯ç›®å½•æˆ–ä¸æ”¯æŒè¯»å–目录,则返回 0 + */ +struct dirent* readdir_fs(struct fs_node* node, unsigned int index) { + // æ£€æŸ¥èŠ‚ç‚¹æ˜¯å¦æ˜¯ç›®å½•ï¼Œå¹¶ä¸”æ˜¯å¦æä¾› readdir 函数 + if ((node->flags & 0x7) == FS_DIRECTORY && node->readdir != 0) { + return node->readdir(node, index); // 调用 readdir 函数 + } else { + return 0; // èŠ‚ç‚¹ä¸æ˜¯ç›®å½•æˆ–ä¸æ”¯æŒè¯»å–目录 + } +} + +/** + * 在文件系统ä¸çš„ç›®å½•ä¸æŸ¥æ‰¾å目录 + * @param node è¦æŸ¥æ‰¾çš„目录节点 + * @param name å目录或文件的åç§° + * @return è¿”å›žå¯¹åº”çš„èŠ‚ç‚¹æŒ‡é’ˆï¼Œå¦‚æžœæœªæ‰¾åˆ°æˆ–èŠ‚ç‚¹ä¸æ˜¯ç›®å½•,则返回 0 + */ +struct fs_node* finddir_fs(struct fs_node* node, char* name) { + // æ£€æŸ¥èŠ‚ç‚¹æ˜¯å¦æ˜¯ç›®å½•ï¼Œå¹¶ä¸”æ˜¯å¦æä¾› finddir 函数 + if ((node->flags & 0x7) == FS_DIRECTORY && node->finddir != 0) { + return node->finddir(node, name); // 调用 finddir 函数 + } else { + return 0; // èŠ‚ç‚¹ä¸æ˜¯ç›®å½•æˆ–ä¸æ”¯æŒæŸ¥æ‰¾ + } +} diff --git a/vmem.c b/vmem.c new file mode 100644 index 0000000000000000000000000000000000000000..21a0be9e661be95fd0f9a50ad96c7f9c22ede3de --- /dev/null +++ b/vmem.c @@ -0,0 +1,215 @@ +#include <system.h> + +/** + * 找到适åˆçš„å†…å˜ hole(空闲å—)。 + * @param size 需è¦åˆ†é…çš„å¤§å° + * @param page_align 是å¦éœ€è¦é¡µé¢å¯¹é½ + * @param heap è¦æ“ä½œçš„å † + * @return 返回找到的 hole åœ¨å †ç´¢å¼•ä¸çš„ä½ç½®ï¼Œ-1 表示未找到 + */ +static signed int find_smallest_hole(addr size, unsigned char page_align, struct vmem_heap* heap) { + for (unsigned int i = 0; i < heap->index.size; i++) { + struct vmem_header* header = (struct vmem_header*)lookup_ordered_array(i, &heap->index); + addr location = (addr)header; + + // 如果需è¦é¡µé¢å¯¹é½ï¼Œè®¡ç®—åç§»é‡ + signed int offset = (page_align && ((location + sizeof(struct vmem_header)) % 0x1000 != 0)) + ? 0x1000 - (location + sizeof(struct vmem_header)) % 0x1000 + : 0; + + // 如果该 hole 的大å°è¶³å¤Ÿåˆ†é…内å˜ï¼ˆåŒ…括å移),返回它的ä½ç½® + if ((header->size - offset) >= size) { + return i; + } + } + return -1; // 没有找到åˆé€‚çš„ hole +} + +/** + * æ¯”è¾ƒä¸¤ä¸ªå†…å˜ header 的大å°ï¼Œç”¨äºŽå †çš„æœ‰åºæ•°ç»„。 + * @param a 第一个 header + * @param b 第二个 header + * @return 返回 1 表示 a 的大å°å°äºŽ b + */ +static signed char vmem_header_less_than(void* a, void* b) { + return ((struct vmem_header*)a)->size < ((struct vmem_header*)b)->size; +} + +/** + * åˆ›å»ºå † + * @param start å †çš„èµ·å§‹åœ°å€ + * @param end_addr å †çš„ç»“æŸåœ°å€ + * @param max å †çš„æœ€å¤§åœ°å€ + * @param supervisor 是å¦ä¸ºå†…æ ¸æ¨¡å¼ + * @param readonly 是å¦åªè¯» + * @return è¿”å›žæ–°åˆ›å»ºçš„å †æŒ‡é’ˆ + */ +vmem_heap_t* create_heap(addr start, addr end_addr, addr max, unsigned char supervisor, unsigned char readonly) { + struct vmem_heap* heap = (struct vmem_heap*)kmalloc(sizeof(struct vmem_heap)); + + // ç¡®ä¿èµ·å§‹å’Œç»“æŸåœ°å€æ˜¯é¡µé¢å¯¹é½çš„ + ASSERT((start % 0x1000 == 0) && (end_addr % 0x1000 == 0)); + + // åˆå§‹åŒ–å †ç´¢å¼•æ•°ç»„ï¼Œå˜å‚¨å†…å˜å—çš„ä¿¡æ¯ + heap->index = place_ordered_array((void*)start, VMEM_INDEX_SIZE, &vmem_header_less_than); + start += sizeof(type_t) * VMEM_INDEX_SIZE; // 调整 start ä½ç½®ï¼Œé¿å¼€ç´¢å¼•数组所å 空间 + + // ç¡®ä¿èµ·å§‹åœ°å€å¯¹é½åˆ°é¡µé¢è¾¹ç•Œ + if (start % 0x1000 != 0) start = (start & 0xFFFFF000) + 0x1000; + + // åˆå§‹åŒ–å †ç»“æž„ + heap->start_address = start; + heap->end_address = end_addr; + heap->max_address = max; + heap->supervisor = supervisor; + heap->readonly = readonly; + + // åˆå§‹åŒ–第一个大的 holeï¼Œè¦†ç›–æ•´ä¸ªå †ç©ºé—´ + struct vmem_header* hole = (struct vmem_header*)start; + hole->size = end_addr - start; + hole->magic = VMEM_MAGIC; + hole->is_hole = 1; + + // æ’入第一个 hole åˆ°ç´¢å¼•æ•°ç»„ä¸ + insert_ordered_array((void*)hole, &heap->index); + + return heap; +} + +/** + * æ‰©å±•å †çš„å¤§å° + * @param new_size æ–°çš„å †å¤§å° + * @param heap æ“ä½œçš„å † + */ +static void expand(addr new_size, struct vmem_heap* heap) { + ASSERT(new_size > (heap->end_address - heap->start_address)); // 新大å°å¿…须大于当å‰å †å¤§å° + + // 对é½åˆ°é¡µé¢è¾¹ç•Œ + new_size = (new_size + 0xFFF) & 0xFFFFF000; + ASSERT(heap->start_address + new_size <= heap->max_address); // ç¡®ä¿ä¸ä¼šè¶…è¿‡å †çš„æœ€å¤§é™åˆ¶ + + addr old_size = heap->end_address - heap->start_address; + + // åˆ†é…æ–°é¡µé¢ä»¥æ‰©å±•å † + for (addr i = old_size; i < new_size; i += 0x1000) { + frame_alloc((struct page*)get_page(heap->start_address + i, 1, kernel_directory), + heap->supervisor, !heap->readonly); + } + heap->end_address = heap->start_address + new_size; // æ›´æ–°å †çš„ç»“æŸåœ°å€ +} + +/** + * æ”¶ç¼©å †çš„å¤§å° + * @param new_size æ–°çš„å †å¤§å° + * @param heap æ“ä½œçš„å † + * @return 返回调整åŽçš„å †å¤§å° + */ +static addr contract(addr new_size, struct vmem_heap* heap) { + ASSERT(new_size < (heap->end_address - heap->start_address)); // 新大å°å¿…é¡»å°äºŽå½“å‰å †å¤§å° + + // 最å°å †å¤§å°é™åˆ¶ + if (new_size < VMEM_MIN_SIZE) new_size = VMEM_MIN_SIZE; + + // 对é½åˆ°é¡µé¢è¾¹ç•Œ + new_size = (new_size + 0xFFF) & 0xFFFFF000; + + addr old_size = heap->end_address - heap->start_address; + + // 释放页é¢ï¼Œå‡å°‘å †å¤§å° + for (addr i = old_size; i > new_size; i -= 0x1000) { + frame_free((struct page*)get_page(heap->start_address + i - 0x1000, 0, kernel_directory)); + } + heap->end_address = heap->start_address + new_size; // æ›´æ–°å †çš„ç»“æŸåœ°å€ + return new_size; +} + +/** + * 分é…å†…å˜ + * @param size è¦åˆ†é…çš„å¤§å° + * @param page_align 是å¦éœ€è¦é¡µé¢å¯¹é½ + * @param heap æ“ä½œçš„å † + * @return 返回分é…的内å˜åœ°å€ + */ +void* vmalloc(addr size, unsigned char page_align, struct vmem_heap* heap) { + addr total_size = size + sizeof(struct vmem_header) + sizeof(struct vmem_footer); + signed int iterator = find_smallest_hole(total_size, page_align, heap); + + // 如果没有找到åˆé€‚çš„ holeï¼Œéœ€è¦æ‰©å±•å † + if (iterator == -1) { + addr old_size = heap->end_address - heap->start_address; + expand(old_size + total_size, heap); // æ‰©å±•å †å¤§å° + iterator = find_smallest_hole(total_size, page_align, heap); + ASSERT(iterator != -1); // 必须能找到 hole,å¦åˆ™å‡ºé”™ + } + + struct vmem_header* hole = (struct vmem_header*)lookup_ordered_array(iterator, &heap->index); + addr hole_size = hole->size; + + // 检查是å¦éœ€è¦æ‹†åˆ† hole,如果剩余空间足够创建新 hole,则拆分 + if (hole_size - total_size > (sizeof(struct vmem_header) + sizeof(struct vmem_footer))) { + struct vmem_header* new_hole = (struct vmem_header*)((addr)hole + total_size); + new_hole->magic = VMEM_MAGIC; + new_hole->is_hole = 1; + new_hole->size = hole_size - total_size; + + struct vmem_footer* new_footer = (struct vmem_footer*)((addr)new_hole + new_hole->size - sizeof(struct vmem_footer)); + new_footer->magic = VMEM_MAGIC; + new_footer->header = new_hole; + + insert_ordered_array((void*)new_hole, &heap->index); // æ’入新 hole åˆ°ç´¢å¼•ä¸ + hole->size = total_size; // 调整原 hole çš„å¤§å° + } + + remove_ordered_array(iterator, &heap->index); // 从索引ä¸ç§»é™¤å·²åˆ†é…çš„ hole + + hole->is_hole = 0; // æ ‡è®°ä¸ºå·²åˆ†é… + hole->magic = VMEM_MAGIC; + + struct vmem_footer* footer = (struct vmem_footer*)((addr)hole + hole->size - sizeof(struct vmem_footer)); + footer->magic = VMEM_MAGIC; + footer->header = hole; + + return (void*)((addr)hole + sizeof(struct vmem_header)); +} + +/** + * é‡Šæ”¾å†…å˜ + * @param ptr è¦é‡Šæ”¾çš„å†…å˜æŒ‡é’ˆ + * @param heap æ“ä½œçš„å † + */ +void vfree(void* ptr, struct vmem_heap* heap) { + if (!ptr) return; // 如果指针为空,直接返回 + + struct vmem_header* header = (struct vmem_header*)((addr)ptr - sizeof(struct vmem_header)); + struct vmem_footer* footer = (struct vmem_footer*)((addr)header + header->size - sizeof(struct vmem_footer)); + + // 检查 header å’Œ footer 的完整性 + ASSERT(header->magic == VMEM_MAGIC && footer->magic == VMEM_MAGIC); + + header->is_hole = 1; // æ ‡è®°ä¸º hole + + // åˆå¹¶å·¦ä¾§çš„ hole + struct vmem_footer* prev_footer = (struct vmem_footer*)((addr)header - sizeof(struct vmem_footer)); + if ((addr)prev_footer >= heap->start_address && prev_footer->magic == VMEM_MAGIC && prev_footer->header->is_hole) { + header = prev_footer->header; + header->size += footer->header->size; + footer = (struct vmem_footer*)((addr)header + header->size - sizeof(struct vmem_footer)); + } + + // åˆå¹¶å³ä¾§çš„ hole + struct vmem_header* next_header = (struct vmem_header*)((addr)footer + sizeof(struct vmem_footer)); + if ((addr)next_header < heap->end_address && next_header->magic == VMEM_MAGIC && next_header->is_hole) { + header->size += next_header->size; + footer = (struct vmem_footer*)((addr)header + header->size - sizeof(struct vmem_footer)); + } + + footer->magic = VMEM_MAGIC; + footer->header = header; + + // 如果释放的 block åœ¨å †çš„æœ«å°¾ï¼Œæ”¶ç¼©å † + if ((addr)footer + sizeof(struct vmem_footer) == heap->end_address) { + contract((addr)header - heap->start_address, heap); + } else { + insert_ordered_array((void*)header, &heap->index); // å°† hole æ’å…¥åˆ°ç´¢å¼•ä¸ + } +}