請先建立一顆硬碟(80MB),分為 1 個 primary partition, 1 個 extended partitions, 4 個 logical partitions。
而我在此處採用 VirtualBox,故需要將 raw file 轉成 vdi 格式。
而我在此處採用 VirtualBox,故需要將 raw file 轉成 vdi 格式。
$ bximage -hd -mode=flat -size=80 -q 80m.img $ fdisk 80m.img $ VBoxManage convertfromraw -format VDI 80m.img 80m.vdi
![]() |
硬碟分割結果(自由切割) |
程式碼
fs/main.c
/*************************************************************************//** ***************************************************************************** * @file main.c * @brief * @author Forrest Y. Yu * @date 2007 ***************************************************************************** *****************************************************************************/ #include "type.h" //#include "config.h" #include "const.h" #include "protect.h" #include "string.h" #include "fs.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "proto.h" #include "hd.h" /***************************************************************************** * task_fs *****************************************************************************/ /** * <Ring 1> The main loop of TASK FS. * *****************************************************************************/ PUBLIC void task_fs() { printl("Task FS begins.\n"); /* open the device: hard disk */ MESSAGE driver_msg; driver_msg.type = DEV_OPEN; send_recv(BOTH, TASK_HD, &driver_msg); spin("FS"); }
include/const.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ const.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_CONST_H_ #define _ORANGES_CONST_H_ /* the assert macro */ #define ASSERT #ifdef ASSERT void assertion_failure(char *exp, char *file, char *base_file, int line); #define assert(exp) if (exp) ; \ else assertion_failure(#exp, __FILE__, __BASE_FILE__, __LINE__) #else #define assert(exp) #endif /* EXTERN */ #define EXTERN extern /* EXTERN is defined as extern except in global.c */ /* 函數類型 */ #define PUBLIC /* PUBLIC is the opposite of PRIVATE */ #define PRIVATE static /* PRIVATE x limits the scope of x */ #define STR_DEFAULT_LEN 1024 /* max() & min() */ #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) /* Color */ /* * e.g. MAKE_COLOR(BLUE, RED) * MAKE_COLOR(BLACK, RED) | BRIGHT * MAKE_COLOR(BLACK, RED) | BRIGHT | FLASH */ #define BLACK 0x0 /* 0000 */ #define WHITE 0x7 /* 0111 */ #define RED 0x4 /* 0100 */ #define GREEN 0x2 /* 0010 */ #define BLUE 0x1 /* 0001 */ #define FLASH 0x80 /* 1000 0000 */ #define BRIGHT 0x08 /* 0000 1000 */ #define MAKE_COLOR(x,y) ((x<<4) | y) /* MAKE_COLOR(Background,Foreground) */ /* GDT 和 IDT 中描述符的個數 */ #define GDT_SIZE 128 #define IDT_SIZE 256 /* 權限 */ #define PRIVILEGE_KRNL 0 #define PRIVILEGE_TASK 1 #define PRIVILEGE_USER 3 /* RPL */ #define RPL_KRNL SA_RPL0 #define RPL_TASK SA_RPL1 #define RPL_USER SA_RPL3 /* Process */ #define SENDING 0x02 /* set when proc trying to send */ #define RECEIVING 0x04 /* set when proc trying to recv */ /* TTY */ #define NR_CONSOLES 3 /* consoles */ /* 8259A interrupt controller ports. */ #define INT_M_CTL 0x20 /* I/O port for interrupt controller <Master> */ #define INT_M_CTLMASK 0x21 /* setting bits in this port disables ints <Master> */ #define INT_S_CTL 0xA0 /* I/O port for second interrupt controller <Slave> */ #define INT_S_CTLMASK 0xA1 /* setting bits in this port disables ints <Slave> */ /* 8253/8254 PIT (Programmable Interval Timer) */ #define TIMER0 0x40 /* I/O port for timer channel 0 */ #define TIMER_MODE 0x43 /* I/O port for timer mode control */ #define RATE_GENERATOR 0x34 /* 00-11-010-0 : * Counter0 - LSB then MSB - rate generator - binary */ #define TIMER_FREQ 1193182L/* clock frequency for timer in PC and AT */ #define HZ 100 /* clock freq (software settable on IBM-PC) */ /* AT keyboard */ /* 8042 ports */ #define KB_DATA 0x60 /* I/O port for keyboard data Read : Read Output Buffer Write: Write Input Buffer(8042 Data&8048 Command) */ #define KB_CMD 0x64 /* I/O port for keyboard command Read : Read Status Register Write: Write Input Buffer(8042 Command) */ #define LED_CODE 0xED #define KB_ACK 0xFA /* VGA */ #define CRTC_ADDR_REG 0x3D4 /* CRT Controller Registers - Addr Register */ #define CRTC_DATA_REG 0x3D5 /* CRT Controller Registers - Data Register */ #define START_ADDR_H 0xC /* reg index of video mem start addr (MSB) */ #define START_ADDR_L 0xD /* reg index of video mem start addr (LSB) */ #define CURSOR_H 0xE /* reg index of cursor position (MSB) */ #define CURSOR_L 0xF /* reg index of cursor position (LSB) */ #define V_MEM_BASE 0xB8000 /* base of color video memory */ #define V_MEM_SIZE 0x8000 /* 32K: B8000H -> BFFFFH */ /* Hardware interrupts */ #define NR_IRQ 16 /* Number of IRQs */ #define CLOCK_IRQ 0 #define KEYBOARD_IRQ 1 #define CASCADE_IRQ 2 /* cascade enable for 2nd AT controller */ #define ETHER_IRQ 3 /* default ethernet interrupt vector */ #define SECONDARY_IRQ 3 /* RS232 interrupt vector for port 2 */ #define RS232_IRQ 4 /* RS232 interrupt vector for port 1 */ #define XT_WINI_IRQ 5 /* xt winchester */ #define FLOPPY_IRQ 6 /* floppy disk */ #define PRINTER_IRQ 7 #define AT_WINI_IRQ 14 /* at winchester */ /* tasks */ /* 注意 TASK_XXX 的定義要與 global.c 中對應 */ #define INVALID_DRIVER -20 #define INTERRUPT -10 #define TASK_TTY 0 #define TASK_SYS 1 #define TASK_HD 2 /* #define TASK_FS 3 */ /* #define TASK_MM 4 */ #define ANY (NR_TASKS + NR_PROCS + 10) #define NO_TASK (NR_TASKS + NR_PROCS + 20) /* system call */ #define NR_SYS_CALL 3 /* ipc */ #define SEND 1 #define RECEIVE 2 #define BOTH 3 /* BOTH = (SEND | RECEIVE) */ /* magic chars used by `printx' */ #define MAG_CH_PANIC '\002' #define MAG_CH_ASSERT '\003' /** * @enum msgtype * @brief MESSAGE types */ enum msgtype { /* * when hard interrupt occurs, a msg (with type==HARD_INT) will * be sent to some tasks */ HARD_INT = 1, /* SYS task */ GET_TICKS, /* message type for drivers */ DEV_OPEN = 1001, DEV_CLOSE, DEV_READ, DEV_WRITE, DEV_IOCTL }; /* macros for messages */ /* #define FD u.m3.m3i1 */ /* #define PATHNAME u.m3.m3p1 */ /* #define FLAGS u.m3.m3i1 */ /* #define NAME_LEN u.m3.m3i2 */ #define CNT u.m3.m3i2 #define REQUEST u.m3.m3i2 #define PROC_NR u.m3.m3i3 #define DEVICE u.m3.m3i4 #define POSITION u.m3.m3l1 #define BUF u.m3.m3p2 /* #define OFFSET u.m3.m3i2 */ /* #define WHENCE u.m3.m3i3 */ /* #define PID u.m3.m3i2 */ /* #define STATUS u.m3.m3i1 */ #define RETVAL u.m3.m3i1 /* #define STATUS u.m3.m3i1 */ #define DIOCTL_GET_GEO 1 /* Hard Drive */ #define SECTOR_SIZE 512 #define SECTOR_BITS (SECTOR_SIZE * 8) #define SECTOR_SIZE_SHIFT 9 /* major device numbers (corresponding to kernel/global.c::dd_map[]) */ #define NO_DEV 0 #define DEV_FLOPPY 1 #define DEV_CDROM 2 #define DEV_HD 3 #define DEV_CHAR_TTY 4 #define DEV_SCSI 5 /* make device number from major and minor numbers */ #define MAJOR_SHIFT 8 #define MAKE_DEV(a,b) ((a << MAJOR_SHIFT) | b) /* separate major and minor numbers from device number */ #define MAJOR(x) ((x >> MAJOR_SHIFT) & 0xFF) #define MINOR(x) (x & 0xFF) /* device numbers of hard disk */ #define MINOR_hd1a 0x10 #define MINOR_hd2a 0x20 #define MINOR_hd2b 0x21 #define MINOR_hd3a 0x30 #define MINOR_hd4a 0x40 #define ROOT_DEV MAKE_DEV(DEV_HD, MINOR_BOOT) /* 3, 0x21 */ #define INVALID_INODE 0 #define ROOT_INODE 1 #define MAX_DRIVES 2 #define NR_PART_PER_DRIVE 4 #define NR_SUB_PER_PART 16 #define NR_SUB_PER_DRIVE (NR_SUB_PER_PART * NR_PART_PER_DRIVE) #define NR_PRIM_PER_DRIVE (NR_PART_PER_DRIVE + 1) /** * @def MAX_PRIM_DEV * Defines the max minor number of the primary partitions. * If there are 2 disks, prim_dev ranges in hd[0-9], this macro will * equals 9. */ #define MAX_PRIM (MAX_DRIVES * NR_PRIM_PER_DRIVE - 1) #define MAX_SUBPARTITIONS (NR_SUB_PER_DRIVE * MAX_DRIVES) #define P_PRIMARY 0 #define P_EXTENDED 1 #define ORANGES_PART 0x99 /* Orange'S partition */ #define NO_PART 0x00 /* unused entry */ #define EXT_PART 0x05 /* extended partition */ #define NR_FILES 64 #define NR_FILE_DESC 64 /* FIXME */ #define NR_INODE 64 /* FIXME */ #define NR_SUPER_BLOCK 8 /* INODE::i_mode (octal, lower 32 bits reserved) */ #define I_TYPE_MASK 0170000 #define I_REGULAR 0100000 #define I_BLOCK_SPECIAL 0060000 #define I_DIRECTORY 0040000 #define I_CHAR_SPECIAL 0020000 #define I_NAMED_PIPE 0010000 #define is_special(m) ((((m) & I_TYPE_MASK) == I_BLOCK_SPECIAL) || \ (((m) & I_TYPE_MASK) == I_CHAR_SPECIAL)) #define NR_DEFAULT_FILE_SECTS 2048 /* 2048 * 512 = 1MB */ #endif /* _ORANGES_CONST_H_ */
include/fs.h
/*************************************************************************//** ***************************************************************************** * @file include/sys/fs.h * @brief Header file for File System. * @author Forrest Yu * @date 2008 ***************************************************************************** *****************************************************************************/ #ifndef _ORANGES_FS_H_ #define _ORANGES_FS_H_ /** * @struct dev_drv_map fs.h "include/sys/fs.h" * @brief The Device_nr.\ - Driver_nr.\ MAP. * * \dot * digraph DD_MAP { * graph[rankdir=LR]; * node [shape=record, fontname=Helvetica]; * b [ label="Device Nr."]; * c [ label="Driver (the task)"]; * b -> c [ label="DD_MAP", fontcolor=blue, URL="\ref DD_MAP", arrowhead="open", style="dashed" ]; * } * \enddot */ struct dev_drv_map { int driver_nr; /**< The proc nr.\ of the device driver. */ }; /** * @def MAGIC_V1 * @brief Magic number of FS v1.0 */ #define MAGIC_V1 0x111 /** * @struct super_block fs.h "include/fs.h" * @brief The 2nd sector of the FS * * Remember to change SUPER_BLOCK_SIZE if the members are changed. * * @attention Remember to change boot/include/load.inc::SB_* if the members * are changed. * * \dot * digraph super_block { * node [shape=plaintext]; * * sb [label=<<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0"> * <TR> * <TD HEIGHT="20" WIDTH="70" ALIGN="right" VALIGN="top" BORDER="0">Sector # </TD> * <TD HEIGHT="20" WIDTH="90" ALIGN="left" VALIGN="top" BORDER="0">0</TD> * <TD HEIGHT="20" WIDTH="90" ALIGN="left" VALIGN="top" BORDER="0">1</TD> * <TD HEIGHT="20" WIDTH="290" ALIGN="center" VALIGN="top" BORDER="0">...</TD> * <TD HEIGHT="20" WIDTH="10" ALIGN="right" BORDER="0"></TD> * </TR> * <TR> * <TD HEIGHT="30" WIDTH="70" ALIGN="right" BORDER="0"></TD> * <TD HEIGHT="30" WIDTH="90" ALIGN="center" BORDER="1" BGCOLOR="white">Boot Sector</TD> * <TD HEIGHT="30" WIDTH="90" ALIGN="center" BORDER="1" BGCOLOR="grey">Super Block</TD> * <TD HEIGHT="30" WIDTH="290" ALIGN="center" BORDER="1" BGCOLOR="white">...</TD> * <TD HEIGHT="30" WIDTH="10" ALIGN="right" BORDER="0"></TD> * </TR> * </TABLE>>]; * } * \enddot */ struct super_block { u32 magic; /**< Magic number */ u32 nr_inodes; /**< How many inodes */ u32 nr_sects; /**< How many sectors (including bit maps) */ u32 nr_imap_sects; /**< How many inode-map sectors */ u32 nr_smap_sects; /**< How many sector-map sectors */ u32 n_1st_sect; /**< Number of the 1st data sector */ u32 nr_inode_sects; /**< How many inode sectors */ u32 root_inode; /**< Inode nr of root directory */ u32 inode_size; /**< INODE_SIZE */ u32 inode_isize_off; /**< Offset of `struct inode::i_size' */ u32 inode_start_off; /**< Offset of `struct inode::i_start_sect' */ u32 dir_ent_size; /**< DIR_ENTRY_SIZE */ u32 dir_ent_inode_off;/**< Offset of `struct dir_entry::inode_nr' */ u32 dir_ent_fname_off;/**< Offset of `struct dir_entry::name' */ /* * the following item(s) are only present in memory */ int sb_dev; /**< the super block's home device */ }; /** * @def SUPER_BLK_MAGIC_V1 * @brief Magic number of super block, version 1. * @attention It must correspond with boot/include/load.h::SB_MAGIC_V1 */ #define SUPER_BLK_MAGIC_V1 0x111 /** * @def SUPER_BLOCK_SIZE * @brief The size of super block \b in \b the \b device. * * Note that this is the size of the struct in the device, \b NOT in memory. * The size in memory is larger because of some more members. */ #define SUPER_BLOCK_SIZE 56 /** * @struct inode * @brief i-node * * The file, currently, have tree valid attributes only: * - size * - start_sect * - nr_sects * * The \c start_sect and\c nr_sects locate the file in the device, * and the size show how many bytes is used. * If <tt> size < (nr_sects * SECTOR_SIZE) </tt>, the rest bytes * are wasted and reserved for later writing. * * \b NOTE: Remember to change INODE_SIZE if the members are changed */ struct inode { u32 i_mode; /**< Accsess mode. Unused currently */ u32 i_size; /**< File size */ u32 i_start_sect; /**< The first sector of the data */ u32 i_nr_sects; /**< How many sectors the file occupies */ u8 _unused[16]; /**< Stuff for alignment */ /* the following items are only present in memory */ int i_dev; int i_cnt; /**< How many procs share this inode */ int i_num; /**< inode nr. */ }; /** * @def INODE_SIZE * @brief The size of i-node stored \b in \b the \b device. * * Note that this is the size of the struct in the device, \b NOT in memory. * The size in memory is larger because of some more members. */ #define INODE_SIZE 32 /** * @struct file_desc * @brief File Descriptor */ struct file_desc { int fd_mode; /**< R or W */ int fd_pos; /**< Current position for R/W. */ struct inode* fd_inode; /**< Ptr to the i-node */ }; /** * Since all invocations of `rw_sector()' in FS look similar (most of the * params are the same), we use this macro to make code more readable. * * Before I wrote this macro, I found almost every rw_sector invocation * line matchs this emacs-style regex: * `rw_sector(\([-a-zA-Z0-9_>\ \*()+.]+,\)\{3\}\ *SECTOR_SIZE,\ *TASK_FS,\ *fsbuf)' */ #define RD_SECT(dev,sect_nr) rw_sector(DEV_READ, \ dev, \ (sect_nr) * SECTOR_SIZE, \ SECTOR_SIZE, /* read one sector */ \ TASK_FS, \ fsbuf); #define WR_SECT(dev,sect_nr) rw_sector(DEV_WRITE, \ dev, \ (sect_nr) * SECTOR_SIZE, \ SECTOR_SIZE, /* write one sector */ \ TASK_FS, \ fsbuf); #endif /* _ORANGES_FS_H_ */
include/proc.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ proc.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ struct stackframe { /* proc_ptr points here ↑ Low */ u32 gs; /* ┓ │ */ u32 fs; /* ┃ │ */ u32 es; /* ┃ │ */ u32 ds; /* ┃ │ */ u32 edi; /* ┃ │ */ u32 esi; /* ┣ pushed by save() │ */ u32 ebp; /* ┃ │ */ u32 kernel_esp; /* <- 'popad' will ignore it │ */ u32 ebx; /* ┃ ↑棧從高地址往低地址增長*/ u32 edx; /* ┃ │ */ u32 ecx; /* ┃ │ */ u32 eax; /* ┛ │ */ u32 retaddr; /* return address for assembly code save() │ */ u32 eip; /* ┓ │ */ u32 cs; /* ┃ │ */ u32 eflags; /* ┣ these are pushed by CPU during interrupt │ */ u32 esp; /* ┃ │ */ u32 ss; /* ┛ ┷High */ }; struct proc { struct stackframe regs; /* process registers saved in stack frame */ u16 ldt_sel; /* gdt selector giving ldt base and limit */ struct descriptor ldts[LDT_SIZE]; /* local descs for code and data */ int ticks; /* remained ticks */ int priority; u32 pid; /* process id passed in from MM */ char name[16]; /* name of the process */ int p_flags; /** * process flags. * A proc is runnable iff p_flags==0 */ MESSAGE * p_msg; int p_recvfrom; int p_sendto; int has_int_msg; /** * nonzero if an INTERRUPT occurred when * the task is not ready to deal with it. */ struct proc * q_sending; /** * queue of procs sending messages to * this proc */ struct proc * next_sending;/** * next proc in the sending * queue (q_sending) */ int nr_tty; }; struct task { task_f initial_eip; int stacksize; char name[32]; }; #define proc2pid(x) (x - proc_table) /* Number of tasks & procs */ #define NR_TASKS 4 #define NR_PROCS 3 #define FIRST_PROC proc_table[0] #define LAST_PROC proc_table[NR_TASKS + NR_PROCS - 1] /* stacks of tasks */ #define STACK_SIZE_TTY 0x8000 #define STACK_SIZE_SYS 0x8000 #define STACK_SIZE_HD 0x8000 #define STACK_SIZE_FS 0x8000 #define STACK_SIZE_TESTA 0x8000 #define STACK_SIZE_TESTB 0x8000 #define STACK_SIZE_TESTC 0x8000 #define STACK_SIZE_TOTAL (STACK_SIZE_TTY + \ STACK_SIZE_SYS + \ STACK_SIZE_HD + \ STACK_SIZE_FS + \ STACK_SIZE_TESTA + \ STACK_SIZE_TESTB + \ STACK_SIZE_TESTC)
include/proto.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ proto.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* kliba.asm */ PUBLIC void out_byte(u16 port, u8 value); PUBLIC u8 in_byte(u16 port); PUBLIC void disp_str(char * info); PUBLIC void disp_color_str(char * info, int color); PUBLIC void disable_irq(int irq); PUBLIC void enable_irq(int irq); PUBLIC void disable_int(); PUBLIC void enable_int(); PUBLIC void port_read(u16 port, void* buf, int n); PUBLIC void port_write(u16 port, void* buf, int n); PUBLIC void glitter(int row, int col); /* string.asm */ PUBLIC char* strcpy(char* dst, const char* src); /* protect.c */ PUBLIC void init_prot(); PUBLIC u32 seg2phys(u16 seg); /* klib.c */ PUBLIC void delay(int time); PUBLIC void disp_int(int input); PUBLIC char * itoa(char * str, int num); /* kernel.asm */ PUBLIC void restart(); /* main.c */ PUBLIC int get_ticks(); PUBLIC void TestA(); PUBLIC void TestB(); PUBLIC void TestC(); PUBLIC void panic(const char *fmt, ...); /* i8259.c */ PUBLIC void init_8259A(); PUBLIC void put_irq_handler(int irq, irq_handler handler); PUBLIC void spurious_irq(int irq); /* clock.c */ PUBLIC void clock_handler(int irq); PUBLIC void init_clock(); PUBLIC void milli_delay(int milli_sec); /* kernel/hd.c */ PUBLIC void task_hd(); PUBLIC void hd_handler(int irq); /* keyboard.c */ PUBLIC void init_keyboard(); PUBLIC void keyboard_read(TTY* p_tty); /* tty.c */ PUBLIC void task_tty(); PUBLIC void in_process(TTY* p_tty, u32 key); /* systask.c */ PUBLIC void task_sys(); /* fs/main.c */ PUBLIC void task_fs(); /* console.c */ PUBLIC void out_char(CONSOLE* p_con, char ch); PUBLIC void scroll_screen(CONSOLE* p_con, int direction); PUBLIC void select_console(int nr_console); PUBLIC void init_screen(TTY* p_tty); PUBLIC int is_current_console(CONSOLE* p_con); /* printf.c */ PUBLIC int printf(const char *fmt, ...); #define printl printf /* vsprintf.c */ PUBLIC int vsprintf(char *buf, const char *fmt, va_list args); PUBLIC int sprintf(char *buf, const char *fmt, ...); /* proc.c */ PUBLIC void schedule(); PUBLIC void* va2la(int pid, void* va); PUBLIC int ldt_seg_linear(struct proc* p, int idx); PUBLIC void reset_msg(MESSAGE* p); PUBLIC void dump_msg(const char * title, MESSAGE* m); PUBLIC void dump_proc(struct proc * p); PUBLIC int send_recv(int function, int src_dest, MESSAGE* msg); PUBLIC void inform_int(int task_nr); /* lib/misc.c */ PUBLIC void spin(char * func_name); /* 以下是系統調用相關 */ /* 系統調用 - 系統級 */ /* proc.c */ PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, struct proc* p); PUBLIC int sys_printx(int _unused1, int _unused2, char* s, struct proc * p_proc); /* syscall.asm */ PUBLIC void sys_call(); /* int_handler */ /* 系統調用 - 用戶級 */ PUBLIC int sendrec(int function, int src_dest, MESSAGE* p_msg); PUBLIC int printx(char* str);
kernel/global.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ global.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #define GLOBAL_VARIABLES_HERE #include "type.h" #include "const.h" #include "protect.h" #include "fs.h" #include "tty.h" #include "console.h" #include "proc.h" #include "global.h" #include "proto.h" PUBLIC struct proc proc_table[NR_TASKS + NR_PROCS]; PUBLIC struct task task_table[NR_TASKS] = { {task_tty, STACK_SIZE_TTY, "TTY"}, {task_sys, STACK_SIZE_SYS, "SYS"}, {task_hd, STACK_SIZE_HD, "HD" }, {task_fs, STACK_SIZE_FS, "FS" }}; PUBLIC struct task user_proc_table[NR_PROCS] = { {TestA, STACK_SIZE_TESTA, "TestA"}, {TestB, STACK_SIZE_TESTB, "TestB"}, {TestC, STACK_SIZE_TESTC, "TestC"}}; PUBLIC char task_stack[STACK_SIZE_TOTAL]; PUBLIC TTY tty_table[NR_CONSOLES]; PUBLIC CONSOLE console_table[NR_CONSOLES]; PUBLIC irq_handler irq_table[NR_IRQ]; PUBLIC system_call sys_call_table[NR_SYS_CALL] = {sys_printx, sys_sendrec}; /* FS related below */ /*****************************************************************************/ /** * For dd_map[k], * `k' is the device nr.\ dd_map[k].driver_nr is the driver nr. * * Remeber to modify include/const.h if the order is changed *****************************************************************************/ struct dev_drv_map dd_map[] = { /* driver nr. major device nr. ---------- ---------------- */ {INVALID_DRIVER}, /**< 0 : Unused */ {INVALID_DRIVER}, /**< 1 : Reserved for floppy driver */ {INVALID_DRIVER}, /**< 2 : Reserved for cdrom driver */ {TASK_HD}, /**< 3 : Hard disk */ {TASK_TTY}, /**< 4 : TTY */ {INVALID_DRIVER} /**< 5 : Reserved for scsi disk driver */ }; /** * 6MB~7MB: buffer for FS */ PUBLIC u8 * fsbuf = (u8*)0x600000; PUBLIC const int FSBUF_SIZE = 0x100000;
kernel/hd.c
/*************************************************************************//** ***************************************************************************** * @file hd.c * @brief HD driver. * @author Forrest Y. Yu * @date 2005~2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "const.h" #include "protect.h" #include "string.h" #include "fs.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "proto.h" #include "hd.h" PRIVATE void init_hd (); PRIVATE void hd_cmd_out (struct hd_cmd* cmd); PRIVATE int waitfor (int mask, int val, int timeout); PRIVATE void interrupt_wait (); PRIVATE void hd_identify (int drive); PRIVATE void print_identify_info (u16* hdinfo); PRIVATE u8 hd_status; PRIVATE u8 hdbuf[SECTOR_SIZE * 2]; /***************************************************************************** * task_hd *****************************************************************************/ /** * Main loop of HD driver. * *****************************************************************************/ PUBLIC void task_hd() { MESSAGE msg; init_hd(); while (1) { send_recv(RECEIVE, ANY, &msg); int src = msg.source; switch (msg.type) { case DEV_OPEN: hd_identify(0); break; default: dump_msg("HD driver::unknown msg", &msg); spin("FS::main_loop (invalid msg.type)"); break; } send_recv(SEND, src, &msg); } } /***************************************************************************** * init_hd *****************************************************************************/ /** * <Ring 1> Check hard drive, set IRQ handler, enable IRQ and initialize data * structures. *****************************************************************************/ PRIVATE void init_hd() { /* Get the number of drives from the BIOS data area */ u8 * pNrDrives = (u8*)(0x475); printl("NrDrives:%d.\n", *pNrDrives); assert(*pNrDrives); put_irq_handler(AT_WINI_IRQ, hd_handler); enable_irq(CASCADE_IRQ); enable_irq(AT_WINI_IRQ); } /***************************************************************************** * hd_identify *****************************************************************************/ /** * <Ring 1> Get the disk information. * * @param drive Drive Nr. *****************************************************************************/ PRIVATE void hd_identify(int drive) { struct hd_cmd cmd; cmd.device = MAKE_DEVICE_REG(0, drive, 0); cmd.command = ATA_IDENTIFY; hd_cmd_out(&cmd); interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); print_identify_info((u16*)hdbuf); } /***************************************************************************** * print_identify_info *****************************************************************************/ /** * <Ring 1> Print the hdinfo retrieved via ATA_IDENTIFY command. * * @param hdinfo The buffer read from the disk i/o port. *****************************************************************************/ PRIVATE void print_identify_info(u16* hdinfo) { int i, k; char s[64]; struct iden_info_ascii { int idx; int len; char * desc; } iinfo[] = {{10, 20, "HD SN"}, /* Serial number in ASCII */ {27, 40, "HD Model"} /* Model number in ASCII */ }; for (k = 0; k < sizeof(iinfo)/sizeof(iinfo[0]); k++) { char * p = (char*)&hdinfo[iinfo[k].idx]; for (i = 0; i < iinfo[k].len/2; i++) { s[i*2+1] = *p++; s[i*2] = *p++; } s[i*2] = 0; printl("%s: %s\n", iinfo[k].desc, s); } int capabilities = hdinfo[49]; printl("LBA supported: %s\n", (capabilities & 0x0200) ? "Yes" : "No"); int cmd_set_supported = hdinfo[83]; printl("LBA48 supported: %s\n", (cmd_set_supported & 0x0400) ? "Yes" : "No"); int sectors = ((int)hdinfo[61] << 16) + hdinfo[60]; printl("HD size: %dMB\n", sectors * 512 / 1000000); } /***************************************************************************** * hd_cmd_out *****************************************************************************/ /** * <Ring 1> Output a command to HD controller. * * @param cmd The command struct ptr. *****************************************************************************/ PRIVATE void hd_cmd_out(struct hd_cmd* cmd) { /** * For all commands, the host must first check if BSY=1, * and should proceed no further unless and until BSY=0 */ if (!waitfor(STATUS_BSY, 0, HD_TIMEOUT)) panic("hd error."); /* Activate the Interrupt Enable (nIEN) bit */ out_byte(REG_DEV_CTRL, 0); /* Load required parameters in the Command Block Registers */ out_byte(REG_FEATURES, cmd->features); out_byte(REG_NSECTOR, cmd->count); out_byte(REG_LBA_LOW, cmd->lba_low); out_byte(REG_LBA_MID, cmd->lba_mid); out_byte(REG_LBA_HIGH, cmd->lba_high); out_byte(REG_DEVICE, cmd->device); /* Write the command code to the Command Register */ out_byte(REG_CMD, cmd->command); } /***************************************************************************** * interrupt_wait *****************************************************************************/ /** * <Ring 1> Wait until a disk interrupt occurs. * *****************************************************************************/ PRIVATE void interrupt_wait() { MESSAGE msg; send_recv(RECEIVE, INTERRUPT, &msg); } /***************************************************************************** * waitfor *****************************************************************************/ /** * <Ring 1> Wait for a certain status. * * @param mask Status mask. * @param val Required status. * @param timeout Timeout in milliseconds. * * @return One if sucess, zero if timeout. *****************************************************************************/ PRIVATE int waitfor(int mask, int val, int timeout) { int t = get_ticks(); while(((get_ticks() - t) * 1000 / HZ) < timeout) if ((in_byte(REG_STATUS) & mask) == val) return 1; return 0; } /***************************************************************************** * hd_handler *****************************************************************************/ /** * <Ring 0> Interrupt handler. * * @param irq IRQ nr of the disk interrupt. *****************************************************************************/ PUBLIC void hd_handler(int irq) { /* * Interrupts are cleared when the host * - reads the Status Register, * - issues a reset, or * - writes to the Command Register. */ hd_status = in_byte(REG_STATUS); inform_int(TASK_HD); }
kernel/kernel.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; kernel.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %include "sconst.inc" ; 導入函數 extern cstart extern kernel_main extern exception_handler extern spurious_irq extern clock_handler extern disp_str extern delay extern irq_table ; 導入全局變量 extern gdt_ptr extern idt_ptr extern p_proc_ready extern tss extern disp_pos extern k_reenter extern sys_call_table bits 32 [SECTION .data] clock_int_msg db "^", 0 [SECTION .bss] StackSpace resb 2 * 1024 StackTop: ; 堆疊頂 [section .text] ; 程式碼在此 global _start ; 導出 _start global restart global sys_call global divide_error global single_step_exception global nmi global breakpoint_exception global overflow global bounds_check global inval_opcode global copr_not_available global double_fault global copr_seg_overrun global inval_tss global segment_not_present global stack_exception global general_protection global page_fault global copr_error global hwint00 global hwint01 global hwint02 global hwint03 global hwint04 global hwint05 global hwint06 global hwint07 global hwint08 global hwint09 global hwint10 global hwint11 global hwint12 global hwint13 global hwint14 global hwint15 _start: ; 此時記憶體看上去是這樣的(更詳細的記憶體情況在 LOADER.ASM 中有說明): ; ┃ ┃ ; ┃ ... ┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■Page Tables■■■■■■┃ ; ┃■■■■■(大小由LOADER決定)■■■■┃ PageTblBase ; 00101000h ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■Page Directory Table■■■■┃ PageDirBase = 1M ; 00100000h ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□ Hardware Reserved □□□□┃ B8000h ← gs ; 9FC00h ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp ; 90000h ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■KERNEL.BIN■■■■■■┃ ; 80000h ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■■KERNEL■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr) ; 30000h ┣━━━━━━━━━━━━━━━━━━┫ ; ┋ ... ┋ ; ┋ ┋ ; 0h ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss ; ; ; GDT 以及相應的描述符是這樣的: ; ; Descriptors Selectors ; ┏━━━━━━━━━━━━━━━━━━┓ ; ┃ Dummy Descriptor ┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃ DESC_FLAT_C (0~4G) ┃ 8h = cs ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃ DESC_FLAT_RW (0~4G) ┃ 10h = ds, es, fs, ss ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃ DESC_VIDEO ┃ 1Bh = gs ; ┗━━━━━━━━━━━━━━━━━━┛ ; ; 注意! 在使用 C 程式碼的時候一定要保證 ds, es, ss 這幾個段暫存器的值是一樣的 ; 因為編譯器有可能編譯出使用它們的程式碼, 而編譯器默認它們是一樣的. 比如串拷貝操作會用到 ds 和 es. ; ; ; 把 esp 從 LOADER 挪到 KERNEL mov esp, StackTop ; 堆疊在 bss 段中 mov dword [disp_pos], 0 sgdt [gdt_ptr] ; cstart() 中將會用到 gdt_ptr call cstart ; 在此函數中改變了gdt_ptr,讓它指向新的GDT lgdt [gdt_ptr] ; 使用新的GDT lidt [idt_ptr] jmp SELECTOR_KERNEL_CS:csinit csinit: ; “這個跳轉指令強制使用剛剛初始化的結構”——<<OS:D&I 2nd>> P90. ;jmp 0x40:0 ;ud2 xor eax, eax mov ax, SELECTOR_TSS ltr ax ;sti jmp kernel_main ;hlt ; 中斷和異常 -- 硬件中斷 ; --------------------------------- %macro hwint_master 1 call save in al, INT_M_CTLMASK ; `. or al, (1 << %1) ; | 屏蔽當前中斷 out INT_M_CTLMASK, al ; / mov al, EOI ; `. 置EOI位 out INT_M_CTL, al ; / sti ; CPU在響應中斷的過程中會自動關中斷,這句之後就允許響應新的中斷 push %1 ; `. call [irq_table + 4 * %1] ; | 中斷處理程序 pop ecx ; / cli in al, INT_M_CTLMASK ; `. and al, ~(1 << %1) ; | 恢復接受當前中斷 out INT_M_CTLMASK, al ; / ret %endmacro ALIGN 16 hwint00: ; Interrupt routine for irq 0 (the clock). hwint_master 0 ALIGN 16 hwint01: ; Interrupt routine for irq 1 (keyboard) hwint_master 1 ALIGN 16 hwint02: ; Interrupt routine for irq 2 (cascade!) hwint_master 2 ALIGN 16 hwint03: ; Interrupt routine for irq 3 (second serial) hwint_master 3 ALIGN 16 hwint04: ; Interrupt routine for irq 4 (first serial) hwint_master 4 ALIGN 16 hwint05: ; Interrupt routine for irq 5 (XT winchester) hwint_master 5 ALIGN 16 hwint06: ; Interrupt routine for irq 6 (floppy) hwint_master 6 ALIGN 16 hwint07: ; Interrupt routine for irq 7 (printer) hwint_master 7 ; --------------------------------- %macro hwint_slave 1 call save in al, INT_S_CTLMASK ; `. or al, (1 << (%1 - 8)) ; | 屏蔽當前中斷 out INT_S_CTLMASK, al ; / mov al, EOI ; `. 置EOI位(master) out INT_M_CTL, al ; / nop ; `. 置EOI位(slave) out INT_S_CTL, al ; / 一定注意:slave和master都要置EOI sti ; CPU在響應中斷的過程中會自動關中斷,這句之後就允許響應新的中斷 push %1 ; `. call [irq_table + 4 * %1] ; | 中斷處理程序 pop ecx ; / cli in al, INT_S_CTLMASK ; `. and al, ~(1 << (%1 - 8)) ; | 恢復接受當前中斷 out INT_S_CTLMASK, al ; / ret %endmacro ; --------------------------------- ALIGN 16 hwint08: ; Interrupt routine for irq 8 (realtime clock). hwint_slave 8 ALIGN 16 hwint09: ; Interrupt routine for irq 9 (irq 2 redirected) hwint_slave 9 ALIGN 16 hwint10: ; Interrupt routine for irq 10 hwint_slave 10 ALIGN 16 hwint11: ; Interrupt routine for irq 11 hwint_slave 11 ALIGN 16 hwint12: ; Interrupt routine for irq 12 hwint_slave 12 ALIGN 16 hwint13: ; Interrupt routine for irq 13 (FPU exception) hwint_slave 13 ALIGN 16 hwint14: ; Interrupt routine for irq 14 (AT winchester) hwint_slave 14 ALIGN 16 hwint15: ; Interrupt routine for irq 15 hwint_slave 15 ; 中斷和異常 -- 異常 divide_error: push 0xFFFFFFFF ; no err code push 0 ; vector_no = 0 jmp exception single_step_exception: push 0xFFFFFFFF ; no err code push 1 ; vector_no = 1 jmp exception nmi: push 0xFFFFFFFF ; no err code push 2 ; vector_no = 2 jmp exception breakpoint_exception: push 0xFFFFFFFF ; no err code push 3 ; vector_no = 3 jmp exception overflow: push 0xFFFFFFFF ; no err code push 4 ; vector_no = 4 jmp exception bounds_check: push 0xFFFFFFFF ; no err code push 5 ; vector_no = 5 jmp exception inval_opcode: push 0xFFFFFFFF ; no err code push 6 ; vector_no = 6 jmp exception copr_not_available: push 0xFFFFFFFF ; no err code push 7 ; vector_no = 7 jmp exception double_fault: push 8 ; vector_no = 8 jmp exception copr_seg_overrun: push 0xFFFFFFFF ; no err code push 9 ; vector_no = 9 jmp exception inval_tss: push 10 ; vector_no = A jmp exception segment_not_present: push 11 ; vector_no = B jmp exception stack_exception: push 12 ; vector_no = C jmp exception general_protection: push 13 ; vector_no = D jmp exception page_fault: push 14 ; vector_no = E jmp exception copr_error: push 0xFFFFFFFF ; no err code push 16 ; vector_no = 10h jmp exception exception: call exception_handler add esp, 4*2 ; 讓堆疊頂指向 EIP,堆疊中從頂向下依次是:EIP、CS、EFLAGS hlt ; ============================================================================= ; save ; ============================================================================= save: pushad ; `. push ds ; | push es ; | 保存原暫存器值 push fs ; | push gs ; / ;; 注意,從這裡開始,一直到 `mov esp, StackTop',中間堅決不能用 push/pop 指令, ;; 因為當前 esp 指向 proc_table 裡的某個位置,push 會破壞掉進程表,導致災難性後果! mov esi, edx ; 保存 edx,因為 edx 裡保存了系統使用的參數 ;(沒用堆疊,而是用了另一個暫存器 esi) mov dx, ss mov ds, dx mov es, dx mov fs, dx mov edx, esi ; 恢復 edx mov esi, esp ;esi = 進程表起始位址 inc dword [k_reenter] ;k_reenter++; cmp dword [k_reenter], 0 ;if(k_reenter ==0) jne .1 ;{ mov esp, StackTop ; mov esp, StackTop <--切換到內核堆疊 push restart ; push restart jmp [esi + RETADR - P_STACKBASE]; return; .1: ;} else { 已經在內核堆疊,不需要再切換 push restart_reenter ; push restart_reenter jmp [esi + RETADR - P_STACKBASE]; return; ;} ; ============================================================================= ; sys_call ; ============================================================================= sys_call: call save sti push esi push dword [p_proc_ready] push edx push ecx push ebx call [sys_call_table + eax * 4] add esp, 4 * 4 pop esi mov [esi + EAXREG - P_STACKBASE], eax cli ret ; ==================================================================================== ; restart ; ==================================================================================== restart: mov esp, [p_proc_ready] lldt [esp + P_LDT_SEL] lea eax, [esp + P_STACKTOP] mov dword [tss + TSS3_S_SP0], eax restart_reenter: dec dword [k_reenter] pop gs pop fs pop es pop ds popad add esp, 4 iretd
kernel/main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "const.h" #include "protect.h" #include "string.h" #include "fs.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "proto.h" /*======================================================================* kernel_main *======================================================================*/ PUBLIC int kernel_main() { disp_str("-----\"kernel_main\" begins-----\n"); struct task* p_task; struct proc* p_proc= proc_table; char* p_task_stack = task_stack + STACK_SIZE_TOTAL; u16 selector_ldt = SELECTOR_LDT_FIRST; u8 privilege; u8 rpl; int eflags; int i; int prio; for (i = 0; i < NR_TASKS+NR_PROCS; i++) { if (i < NR_TASKS) { /* 任務 */ p_task = task_table + i; privilege = PRIVILEGE_TASK; rpl = RPL_TASK; eflags = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */ prio = 15; } else { /* 用戶進程 */ p_task = user_proc_table + (i - NR_TASKS); privilege = PRIVILEGE_USER; rpl = RPL_USER; eflags = 0x202; /* IF=1, bit 2 is always 1 */ prio = 5; } strcpy(p_proc->name, p_task->name); /* name of the process */ p_proc->pid = i; /* pid */ p_proc->ldt_sel = selector_ldt; memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3], sizeof(struct descriptor)); p_proc->ldts[0].attr1 = DA_C | privilege << 5; memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3], sizeof(struct descriptor)); p_proc->ldts[1].attr1 = DA_DRW | privilege << 5; p_proc->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; p_proc->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; p_proc->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; p_proc->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; p_proc->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl; p_proc->regs.eip = (u32)p_task->initial_eip; p_proc->regs.esp = (u32)p_task_stack; p_proc->regs.eflags = eflags; p_proc->nr_tty = 0; p_proc->p_flags = 0; p_proc->p_msg = 0; p_proc->p_recvfrom = NO_TASK; p_proc->p_sendto = NO_TASK; p_proc->has_int_msg = 0; p_proc->q_sending = 0; p_proc->next_sending = 0; p_proc->ticks = p_proc->priority = prio; p_task_stack -= p_task->stacksize; p_proc++; p_task++; selector_ldt += 1 << 3; } proc_table[NR_TASKS + 0].nr_tty = 0; proc_table[NR_TASKS + 1].nr_tty = 1; proc_table[NR_TASKS + 2].nr_tty = 1; k_reenter = 0; ticks = 0; p_proc_ready = proc_table; init_clock(); init_keyboard(); restart(); while(1){} } /***************************************************************************** * get_ticks *****************************************************************************/ PUBLIC int get_ticks() { MESSAGE msg; reset_msg(&msg); msg.type = GET_TICKS; send_recv(BOTH, TASK_SYS, &msg); return msg.RETVAL; } /*======================================================================* TestA *======================================================================*/ void TestA() { for(;;); while (1) { printf("<Ticks:%d>", get_ticks()); milli_delay(200); } } /*======================================================================* TestB *======================================================================*/ void TestB() { while(1){ printf("B"); milli_delay(200); } } /*======================================================================* TestB *======================================================================*/ void TestC() { /* assert(0); */ while(1){ printf("C"); milli_delay(200); } } /***************************************************************************** * panic *****************************************************************************/ PUBLIC void panic(const char *fmt, ...) { int i; char buf[256]; /* 4 is the size of fmt in the stack */ va_list arg = (va_list)((char*)&fmt + 4); i = vsprintf(buf, fmt, arg); printl("%c !!panic!! %s", MAG_CH_PANIC, buf); /* should never arrive here */ __asm__ __volatile__("ud2"); }
kernel/proc.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ proc.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "const.h" #include "protect.h" #include "tty.h" #include "console.h" #include "string.h" #include "fs.h" #include "proc.h" #include "global.h" #include "proto.h" PRIVATE void block(struct proc* p); PRIVATE void unblock(struct proc* p); PRIVATE int msg_send(struct proc* current, int dest, MESSAGE* m); PRIVATE int msg_receive(struct proc* current, int src, MESSAGE* m); PRIVATE int deadlock(int src, int dest); /***************************************************************************** * schedule *****************************************************************************/ /** * <Ring 0> Choose one proc to run. * *****************************************************************************/ PUBLIC void schedule() { struct proc* p; int greatest_ticks = 0; while (!greatest_ticks) { for (p = &FIRST_PROC; p <= &LAST_PROC; p++) { if (p->p_flags == 0) { if (p->ticks > greatest_ticks) { greatest_ticks = p->ticks; p_proc_ready = p; } } } if (!greatest_ticks) for (p = &FIRST_PROC; p <= &LAST_PROC; p++) if (p->p_flags == 0) p->ticks = p->priority; } } /***************************************************************************** * sys_sendrec *****************************************************************************/ /** * <Ring 0> The core routine of system call `sendrec()'. * * @param function SEND or RECEIVE * @param src_dest To/From whom the message is transferred. * @param m Ptr to the MESSAGE body. * @param p The caller proc. * * @return Zero if success. *****************************************************************************/ PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, struct proc* p) { assert(k_reenter == 0); /* make sure we are not in ring0 */ assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) || src_dest == ANY || src_dest == INTERRUPT); int ret = 0; int caller = proc2pid(p); MESSAGE* mla = (MESSAGE*)va2la(caller, m); mla->source = caller; assert(mla->source != src_dest); /** * Actually we have the third message type: BOTH. However, it is not * allowed to be passed to the kernel directly. Kernel doesn't know * it at all. It is transformed into a SEND followed by a RECEIVE * by `send_recv()'. */ if (function == SEND) { ret = msg_send(p, src_dest, m); if (ret != 0) return ret; } else if (function == RECEIVE) { ret = msg_receive(p, src_dest, m); if (ret != 0) return ret; } else { panic("{sys_sendrec} invalid function: " "%d (SEND:%d, RECEIVE:%d).", function, SEND, RECEIVE); } return 0; } /***************************************************************************** * send_recv *****************************************************************************/ /** * <Ring 1~3> IPC syscall. * * It is an encapsulation of `sendrec', * invoking `sendrec' directly should be avoided * * @param function SEND, RECEIVE or BOTH * @param src_dest The caller's proc_nr * @param msg Pointer to the MESSAGE struct * * @return always 0. *****************************************************************************/ PUBLIC int send_recv(int function, int src_dest, MESSAGE* msg) { int ret = 0; if (function == RECEIVE) memset(msg, 0, sizeof(MESSAGE)); switch (function) { case BOTH: ret = sendrec(SEND, src_dest, msg); if (ret == 0) ret = sendrec(RECEIVE, src_dest, msg); break; case SEND: case RECEIVE: ret = sendrec(function, src_dest, msg); break; default: assert((function == BOTH) || (function == SEND) || (function == RECEIVE)); break; } return ret; } /***************************************************************************** * ldt_seg_linear *****************************************************************************/ /** * <Ring 0~1> Calculate the linear address of a certain segment of a given * proc. * * @param p Whose (the proc ptr). * @param idx Which (one proc has more than one segments). * * @return The required linear address. *****************************************************************************/ PUBLIC int ldt_seg_linear(struct proc* p, int idx) { struct descriptor * d = &p->ldts[idx]; return d->base_high << 24 | d->base_mid << 16 | d->base_low; } /***************************************************************************** * va2la *****************************************************************************/ /** * <Ring 0~1> Virtual addr --> Linear addr. * * @param pid PID of the proc whose address is to be calculated. * @param va Virtual address. * * @return The linear address for the given virtual address. *****************************************************************************/ PUBLIC void* va2la(int pid, void* va) { struct proc* p = &proc_table[pid]; u32 seg_base = ldt_seg_linear(p, INDEX_LDT_RW); u32 la = seg_base + (u32)va; if (pid < NR_TASKS + NR_PROCS) { assert(la == (u32)va); } return (void*)la; } /***************************************************************************** * reset_msg *****************************************************************************/ /** * <Ring 0~3> Clear up a MESSAGE by setting each byte to 0. * * @param p The message to be cleared. *****************************************************************************/ PUBLIC void reset_msg(MESSAGE* p) { memset(p, 0, sizeof(MESSAGE)); } /***************************************************************************** * block *****************************************************************************/ /** * <Ring 0> This routine is called after `p_flags' has been set (!= 0), it * calls `schedule()' to choose another proc as the `proc_ready'. * * @attention This routine does not change `p_flags'. Make sure the `p_flags' * of the proc to be blocked has been set properly. * * @param p The proc to be blocked. *****************************************************************************/ PRIVATE void block(struct proc* p) { assert(p->p_flags); schedule(); } /***************************************************************************** * unblock *****************************************************************************/ /** * <Ring 0> This is a dummy routine. It does nothing actually. When it is * called, the `p_flags' should have been cleared (== 0). * * @param p The unblocked proc. *****************************************************************************/ PRIVATE void unblock(struct proc* p) { assert(p->p_flags == 0); } /***************************************************************************** * deadlock *****************************************************************************/ /** * <Ring 0> Check whether it is safe to send a message from src to dest. * The routine will detect if the messaging graph contains a cycle. For * instance, if we have procs trying to send messages like this: * A -> B -> C -> A, then a deadlock occurs, because all of them will * wait forever. If no cycles detected, it is considered as safe. * * @param src Who wants to send message. * @param dest To whom the message is sent. * * @return Zero if success. *****************************************************************************/ PRIVATE int deadlock(int src, int dest) { struct proc* p = proc_table + dest; while (1) { if (p->p_flags & SENDING) { if (p->p_sendto == src) { /* print the chain */ p = proc_table + dest; printl("=_=%s", p->name); do { assert(p->p_msg); p = proc_table + p->p_sendto; printl("->%s", p->name); } while (p != proc_table + src); printl("=_="); return 1; } p = proc_table + p->p_sendto; } else { break; } } return 0; } /***************************************************************************** * msg_send *****************************************************************************/ /** * <Ring 0> Send a message to the dest proc. If dest is blocked waiting for * the message, copy the message to it and unblock dest. Otherwise the caller * will be blocked and appended to the dest's sending queue. * * @param current The caller, the sender. * @param dest To whom the message is sent. * @param m The message. * * @return Zero if success. *****************************************************************************/ PRIVATE int msg_send(struct proc* current, int dest, MESSAGE* m) { struct proc* sender = current; struct proc* p_dest = proc_table + dest; /* proc dest */ assert(proc2pid(sender) != dest); /* check for deadlock here */ if (deadlock(proc2pid(sender), dest)) { panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); } if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */ (p_dest->p_recvfrom == proc2pid(sender) || p_dest->p_recvfrom == ANY)) { assert(p_dest->p_msg); assert(m); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), m), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */ p_dest->p_recvfrom = NO_TASK; unblock(p_dest); assert(p_dest->p_flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->p_recvfrom == NO_TASK); assert(p_dest->p_sendto == NO_TASK); assert(sender->p_flags == 0); assert(sender->p_msg == 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == NO_TASK); } else { /* dest is not waiting for the msg */ sender->p_flags |= SENDING; assert(sender->p_flags == SENDING); sender->p_sendto = dest; sender->p_msg = m; /* append to the sending queue */ struct proc * p; if (p_dest->q_sending) { p = p_dest->q_sending; while (p->next_sending) p = p->next_sending; p->next_sending = sender; } else { p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->p_flags == SENDING); assert(sender->p_msg != 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == dest); } return 0; } /***************************************************************************** * msg_receive *****************************************************************************/ /** * <Ring 0> Try to get a message from the src proc. If src is blocked sending * the message, copy the message from it and unblock src. Otherwise the caller * will be blocked. * * @param current The caller, the proc who wanna receive. * @param src From whom the message will be received. * @param m The message ptr to accept the message. * * @return Zero if success. *****************************************************************************/ PRIVATE int msg_receive(struct proc* current, int src, MESSAGE* m) { struct proc* p_who_wanna_recv = current; /** * This name is a little bit * wierd, but it makes me * think clearly, so I keep * it. */ struct proc* p_from = 0; /* from which the message will be fetched */ struct proc* prev = 0; int copyok = 0; assert(proc2pid(p_who_wanna_recv) != src); if ((p_who_wanna_recv->has_int_msg) && ((src == ANY) || (src == INTERRUPT))) { /* There is an interrupt needs p_who_wanna_recv's handling and * p_who_wanna_recv is ready to handle it. */ MESSAGE msg; reset_msg(&msg); msg.source = INTERRUPT; msg.type = HARD_INT; assert(m); phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg, sizeof(MESSAGE)); p_who_wanna_recv->has_int_msg = 0; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); return 0; } /* Arrives here if no interrupt for p_who_wanna_recv. */ if (src == ANY) { /* p_who_wanna_recv is ready to receive messages from * ANY proc, we'll check the sending queue and pick the * first proc in it. */ if (p_who_wanna_recv->q_sending) { p_from = p_who_wanna_recv->q_sending; copyok = 1; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } else { /* p_who_wanna_recv wants to receive a message from * a certain proc: src. */ p_from = &proc_table[src]; if ((p_from->p_flags & SENDING) && (p_from->p_sendto == proc2pid(p_who_wanna_recv))) { /* Perfect, src is sending a message to * p_who_wanna_recv. */ copyok = 1; struct proc* p = p_who_wanna_recv->q_sending; assert(p); /* p_from must have been appended to the * queue, so the queue must not be NULL */ while (p) { assert(p_from->p_flags & SENDING); if (proc2pid(p) == src) { /* if p is the one */ p_from = p; break; } prev = p; p = p->next_sending; } assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } if (copyok) { /* It's determined from which proc the message will * be copied. Note that this proc must have been * waiting for this moment in the queue, so we should * remove it from the queue. */ if (p_from == p_who_wanna_recv->q_sending) { /* the 1st one */ assert(prev == 0); p_who_wanna_recv->q_sending = p_from->next_sending; p_from->next_sending = 0; } else { assert(prev); prev->next_sending = p_from->next_sending; p_from->next_sending = 0; } assert(m); assert(p_from->p_msg); /* copy the message */ phys_copy(va2la(proc2pid(p_who_wanna_recv), m), va2la(proc2pid(p_from), p_from->p_msg), sizeof(MESSAGE)); p_from->p_msg = 0; p_from->p_sendto = NO_TASK; p_from->p_flags &= ~SENDING; unblock(p_from); } else { /* nobody's sending any msg */ /* Set p_flags so that p_who_wanna_recv will not * be scheduled until it is unblocked. */ p_who_wanna_recv->p_flags |= RECEIVING; p_who_wanna_recv->p_msg = m; if (src == ANY) p_who_wanna_recv->p_recvfrom = ANY; else p_who_wanna_recv->p_recvfrom = proc2pid(p_from); block(p_who_wanna_recv); assert(p_who_wanna_recv->p_flags == RECEIVING); assert(p_who_wanna_recv->p_msg != 0); assert(p_who_wanna_recv->p_recvfrom != NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); } return 0; } /***************************************************************************** * inform_int *****************************************************************************/ /** * <Ring 0> Inform a proc that an interrupt has occured. * * @param task_nr The task which will be informed. *****************************************************************************/ PUBLIC void inform_int(int task_nr) { struct proc* p = proc_table + task_nr; if ((p->p_flags & RECEIVING) && /* dest is waiting for the msg */ ((p->p_recvfrom == INTERRUPT) || (p->p_recvfrom == ANY))) { p->p_msg->source = INTERRUPT; p->p_msg->type = HARD_INT; p->p_msg = 0; p->has_int_msg = 0; p->p_flags &= ~RECEIVING; /* dest has received the msg */ p->p_recvfrom = NO_TASK; assert(p->p_flags == 0); unblock(p); assert(p->p_flags == 0); assert(p->p_msg == 0); assert(p->p_recvfrom == NO_TASK); assert(p->p_sendto == NO_TASK); } else { p->has_int_msg = 1; } } /***************************************************************************** * dump_proc *****************************************************************************/ PUBLIC void dump_proc(struct proc* p) { char info[STR_DEFAULT_LEN]; int i; int text_color = MAKE_COLOR(GREEN, RED); int dump_len = sizeof(struct proc); out_byte(CRTC_ADDR_REG, START_ADDR_H); out_byte(CRTC_DATA_REG, 0); out_byte(CRTC_ADDR_REG, START_ADDR_L); out_byte(CRTC_DATA_REG, 0); sprintf(info, "byte dump of proc_table[%d]:\n", p - proc_table); disp_color_str(info, text_color); for (i = 0; i < dump_len; i++) { sprintf(info, "%x.", ((unsigned char *)p)[i]); disp_color_str(info, text_color); } /* printl("^^"); */ disp_color_str("\n\n", text_color); sprintf(info, "ANY: 0x%x.\n", ANY); disp_color_str(info, text_color); sprintf(info, "NO_TASK: 0x%x.\n", NO_TASK); disp_color_str(info, text_color); disp_color_str("\n", text_color); sprintf(info, "ldt_sel: 0x%x. ", p->ldt_sel); disp_color_str(info, text_color); sprintf(info, "ticks: 0x%x. ", p->ticks); disp_color_str(info, text_color); sprintf(info, "priority: 0x%x. ", p->priority); disp_color_str(info, text_color); sprintf(info, "pid: 0x%x. ", p->pid); disp_color_str(info, text_color); sprintf(info, "name: %s. ", p->name); disp_color_str(info, text_color); disp_color_str("\n", text_color); sprintf(info, "p_flags: 0x%x. ", p->p_flags); disp_color_str(info, text_color); sprintf(info, "p_recvfrom: 0x%x. ", p->p_recvfrom); disp_color_str(info, text_color); sprintf(info, "p_sendto: 0x%x. ", p->p_sendto); disp_color_str(info, text_color); sprintf(info, "nr_tty: 0x%x. ", p->nr_tty); disp_color_str(info, text_color); disp_color_str("\n", text_color); sprintf(info, "has_int_msg: 0x%x. ", p->has_int_msg); disp_color_str(info, text_color); } /***************************************************************************** * dump_msg *****************************************************************************/ PUBLIC void dump_msg(const char * title, MESSAGE* m) { int packed = 0; printl("{%s}<0x%x>{%ssrc:%s(%d),%stype:%d,%s(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)%s}%s", //, (0x%x, 0x%x, 0x%x)}", title, (int)m, packed ? "" : "\n ", proc_table[m->source].name, m->source, packed ? " " : "\n ", m->type, packed ? " " : "\n ", m->u.m3.m3i1, m->u.m3.m3i2, m->u.m3.m3i3, m->u.m3.m3i4, (int)m->u.m3.m3p1, (int)m->u.m3.m3p2, packed ? "" : "\n", packed ? "" : "\n"/* , */ ); }
lib/kliba.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; klib.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %include "sconst.inc" ; 導入全局變量 extern disp_pos [SECTION .text] ; 導出函數 global disp_str global disp_color_str global out_byte global in_byte global enable_irq global disable_irq global enable_int global disable_int global port_read global port_write global glitter ; ======================================================================== ; void disp_str(char * info); ; ======================================================================== disp_str: push ebp mov ebp, esp mov esi, [ebp + 8] ; pszInfo mov edi, [disp_pos] mov ah, 0Fh .1: lodsb test al, al jz .2 cmp al, 0Ah ; 是ENTER嗎? jnz .3 push eax mov eax, edi mov bl, 160 div bl and eax, 0FFh inc eax mov bl, 160 mul bl mov edi, eax pop eax jmp .1 .3: mov [gs:edi], ax add edi, 2 jmp .1 .2: mov [disp_pos], edi pop ebp ret ; ======================================================================== ; void disp_color_str(char * info, int color); ; ======================================================================== disp_color_str: push ebp mov ebp, esp mov esi, [ebp + 8] ; pszInfo mov edi, [disp_pos] mov ah, [ebp + 12] ; color .1: lodsb test al, al jz .2 cmp al, 0Ah ; 是ENTER嗎? jnz .3 push eax mov eax, edi mov bl, 160 div bl and eax, 0FFh inc eax mov bl, 160 mul bl mov edi, eax pop eax jmp .1 .3: mov [gs:edi], ax add edi, 2 jmp .1 .2: mov [disp_pos], edi pop ebp ret ; ======================================================================== ; void out_byte(u16 port, u8 value); ; ======================================================================== out_byte: mov edx, [esp + 4] ; port mov al, [esp + 4 + 4] ; value out dx, al nop ; 一點延遲 nop ret ; ======================================================================== ; u8 in_byte(u16 port); ; ======================================================================== in_byte: mov edx, [esp + 4] ; port xor eax, eax in al, dx nop ; 一點延遲 nop ret ; ======================================================================== ; void port_read(u16 port, void* buf, int n); ; ======================================================================== port_read: mov edx, [esp + 4] ; port mov edi, [esp + 4 + 4] ; buf mov ecx, [esp + 4 + 4 + 4] ; n shr ecx, 1 cld rep insw ret ; ======================================================================== ; void port_write(u16 port, void* buf, int n); ; ======================================================================== port_write: mov edx, [esp + 4] ; port mov esi, [esp + 4 + 4] ; buf mov ecx, [esp + 4 + 4 + 4] ; n shr ecx, 1 cld rep outsw ret ; ======================================================================== ; void disable_irq(int irq); ; ======================================================================== ; Disable an interrupt request line by setting an 8259 bit. ; Equivalent code: ; if(irq < 8){ ; out_byte(INT_M_CTLMASK, in_byte(INT_M_CTLMASK) | (1 << irq)); ; } ; else{ ; out_byte(INT_S_CTLMASK, in_byte(INT_S_CTLMASK) | (1 << irq)); ; } disable_irq: mov ecx, [esp + 4] ; irq pushf cli mov ah, 1 rol ah, cl ; ah = (1 << (irq % 8)) cmp cl, 8 jae disable_8 ; disable irq >= 8 at the slave 8259 disable_0: in al, INT_M_CTLMASK test al, ah jnz dis_already ; already disabled? or al, ah out INT_M_CTLMASK, al ; set bit at master 8259 popf mov eax, 1 ; disabled by this function ret disable_8: in al, INT_S_CTLMASK test al, ah jnz dis_already ; already disabled? or al, ah out INT_S_CTLMASK, al ; set bit at slave 8259 popf mov eax, 1 ; disabled by this function ret dis_already: popf xor eax, eax ; already disabled ret ; ======================================================================== ; void enable_irq(int irq); ; ======================================================================== ; Enable an interrupt request line by clearing an 8259 bit. ; Equivalent code: ; if(irq < 8){ ; out_byte(INT_M_CTLMASK, in_byte(INT_M_CTLMASK) & ~(1 << irq)); ; } ; else{ ; out_byte(INT_S_CTLMASK, in_byte(INT_S_CTLMASK) & ~(1 << irq)); ; } ; enable_irq: mov ecx, [esp + 4] ; irq pushf cli mov ah, ~1 rol ah, cl ; ah = ~(1 << (irq % 8)) cmp cl, 8 jae enable_8 ; enable irq >= 8 at the slave 8259 enable_0: in al, INT_M_CTLMASK and al, ah out INT_M_CTLMASK, al ; clear bit at master 8259 popf ret enable_8: in al, INT_S_CTLMASK and al, ah out INT_S_CTLMASK, al ; clear bit at slave 8259 popf ret ; ======================================================================== ; void disable_int(); ; ======================================================================== disable_int: cli ret ; ======================================================================== ; void enable_int(); ; ======================================================================== enable_int: sti ret ; ======================================================================== ; void glitter(int row, int col); ; ======================================================================== glitter: push eax push ebx push edx mov eax, [.current_char] inc eax cmp eax, .strlen je .1 jmp .2 .1: xor eax, eax .2: mov [.current_char], eax mov dl, byte [eax + .glitter_str] xor eax, eax mov al, [esp + 16] ; row mov bl, .line_width mul bl ; ax <- row * 80 mov bx, [esp + 20] ; col add ax, bx shl ax, 1 movzx eax, ax mov [gs:eax], dl inc eax mov byte [gs:eax], 4 jmp .end .current_char: dd 0 .glitter_str: db '-\|/' db '1234567890' db 'abcdefghijklmnopqrstuvwxyz' db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' .strlen equ $ - .glitter_str .line_width equ 80 .end: pop edx pop ebx pop eax ret
Makefile
######################### # Makefile for Orange'S # ######################### # Entry point of Orange'S # It must have the same value with 'KernelEntryPointPhyAddr' in load.inc! ENTRYPOINT = 0x30400 # Offset of entry point in kernel file # It depends on ENTRYPOINT ENTRYOFFSET = 0x400 # Programs, flags, etc. ASM = nasm DASM = objdump CC = gcc LD = ld ASMBFLAGS = -I boot/include/ ASMKFLAGS = -I include/ -f elf CFLAGS = -I include/ -m32 -c -fno-builtin -fno-stack-protector -Wall LDFLAGS = -s -melf_i386 -Ttext $(ENTRYPOINT) DASMFLAGS = -D # This Program ORANGESBOOT = boot/boot.bin boot/loader.bin ORANGESKERNEL = kernel.bin OBJS = kernel/kernel.o kernel/syscall.o kernel/start.o kernel/main.o\ kernel/clock.o kernel/keyboard.o kernel/tty.o kernel/console.o\ kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\ kernel/systask.o kernel/hd.o\ kernel/printf.o kernel/vsprintf.o\ lib/kliba.o lib/klib.o lib/string.o lib/misc.o\ fs/main.o DASMOUTPUT = kernel.bin.asm # All Phony Targets .PHONY : everything final image clean realclean disasm all buildimg # Default starting position nop : @echo "why not \`make image' huh? :)" everything : $(ORANGESBOOT) $(ORANGESKERNEL) all : realclean everything image : realclean everything clean buildimg clean : rm -f $(OBJS) realclean : rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL) disasm : $(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT) # We assume that "a.img" exists in current folder buildimg : mkdir tmp sleep 1 sudo mount -o loop a.img tmp sleep 1 sudo cp -fv boot/loader.bin tmp sudo cp -fv kernel.bin tmp sleep 1 sudo umount tmp sleep 1 rmdir tmp boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc $(ASM) $(ASMBFLAGS) -o $@ $< boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc $(ASM) $(ASMBFLAGS) -o $@ $< $(ORANGESKERNEL) : $(OBJS) $(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS) kernel/kernel.o : kernel/kernel.asm include/sconst.inc $(ASM) $(ASMKFLAGS) -o $@ $< kernel/syscall.o : kernel/syscall.asm include/sconst.inc $(ASM) $(ASMKFLAGS) -o $@ $< kernel/start.o: kernel/start.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \ include/global.h $(CC) $(CFLAGS) -o $@ $< kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \ include/global.h $(CC) $(CFLAGS) -o $@ $< kernel/clock.o: kernel/clock.c $(CC) $(CFLAGS) -o $@ $< kernel/keyboard.o: kernel/keyboard.c $(CC) $(CFLAGS) -o $@ $< kernel/tty.o: kernel/tty.c $(CC) $(CFLAGS) -o $@ $< kernel/console.o: kernel/console.c $(CC) $(CFLAGS) -o $@ $< kernel/i8259.o: kernel/i8259.c include/type.h include/const.h include/protect.h include/proto.h $(CC) $(CFLAGS) -o $@ $< kernel/global.o: kernel/global.c include/type.h include/const.h include/protect.h include/proc.h \ include/global.h include/proto.h $(CC) $(CFLAGS) -o $@ $< kernel/protect.o: kernel/protect.c include/type.h include/const.h include/protect.h include/proc.h include/proto.h \ include/global.h $(CC) $(CFLAGS) -o $@ $< kernel/proc.o: kernel/proc.c $(CC) $(CFLAGS) -o $@ $< kernel/printf.o: kernel/printf.c $(CC) $(CFLAGS) -o $@ $< kernel/vsprintf.o: kernel/vsprintf.c $(CC) $(CFLAGS) -o $@ $< kernel/systask.o: kernel/systask.c $(CC) $(CFLAGS) -o $@ $< kernel/hd.o: kernel/hd.c $(CC) $(CFLAGS) -o $@ $< lib/klib.o: lib/klib.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \ include/global.h $(CC) $(CFLAGS) -o $@ $< lib/misc.o: lib/misc.c $(CC) $(CFLAGS) -o $@ $< lib/kliba.o : lib/kliba.asm $(ASM) $(ASMKFLAGS) -o $@ $< fs/main.o: fs/main.c $(CC) $(CFLAGS) -o $@ $< lib/string.o : lib/string.asm $(ASM) $(ASMKFLAGS) -o $@ $<
include/global.h (新增)
extern struct dev_drv_map dd_map[];
kernel/clock.c, kernel/console.c, kernel/i8259.c, kernel/keyboard.c, kernel/printf.c, kernel/protect.c, kernel/start.c, kernel/systask.c, kernel/tty.c, kernel/vsprintf.c, lib/klib.c, lib/misc.c
#include "fs.h" // 新增
kernel/tty.c (修改)
sys_printx // 刪除 sys_write // 新增
執行畫面
目錄結構
. ├── a.img ├── boot │ ├── boot.asm │ ├── include │ │ ├── fat12hdr.inc │ │ ├── load.inc │ │ └── pm.inc │ └── loader.asm ├── fs │ └── main.c ├── include │ ├── console.h │ ├── const.h │ ├── fs.h │ ├── global.h │ ├── hd.h │ ├── keyboard.h │ ├── keymap.h │ ├── proc.h │ ├── protect.h │ ├── proto.h │ ├── sconst.inc │ ├── string.h │ ├── tty.h │ └── type.h ├── kernel │ ├── clock.c │ ├── console.c │ ├── global.c │ ├── hd.c │ ├── i8259.c │ ├── kernel.asm │ ├── keyboard.c │ ├── main.c │ ├── printf.c │ ├── proc.c │ ├── protect.c │ ├── start.c │ ├── syscall.asm │ ├── systask.c │ ├── tty.c │ └── vsprintf.c ├── lib │ ├── kliba.asm │ ├── klib.c │ ├── misc.c │ └── string.asm └── Makefile
留言
張貼留言