一個新的處理序需要:
注意:如果採用 64 位元 Linux Mint,可能需要安裝 gcc-multilib,以解決以下問題:
- 自己的程式碼、資料、堆疊
- 在 proc_table[] 中佔用一個位置
- 在 GDT 中佔用一個位置,用以存放處理序對應的 LDT 描述符號
程式碼
fs/disklog.c
/*************************************************************************//** ***************************************************************************** * @file disklog.c * @brief * @author Forrest Y. Yu * @date Thu Nov 20 16:22:45 2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "config.h" #include "stdio.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 "keyboard.h" #include "proto.h" #include "hd.h" #include "fs.h" #define DISKLOG_RD_SECT(dev,sect_nr) rw_sector(DEV_READ, \ dev, \ (sect_nr) * SECTOR_SIZE, \ SECTOR_SIZE, /* read one sector */ \ getpid(), \ logdiskbuf); #define DISKLOG_WR_SECT(dev,sect_nr) rw_sector(DEV_WRITE, \ dev, \ (sect_nr) * SECTOR_SIZE, \ SECTOR_SIZE, /* write one sector */ \ getpid(), \ logdiskbuf); /* /\***************************************************************************** */ /* * do_disklog */ /* *****************************************************************************\/ */ /* /\** */ /* * Perform syslog() system call . */ /* * */ /* * @return */ /* *****************************************************************************\/ */ /* PUBLIC int do_disklog() */ /* { */ /* char buf[STR_DEFAULT_LEN]; */ /* /\* get parameters from the message *\/ */ /* int str_len = fs_msg.CNT; /\* length of filename *\/ */ /* int src = fs_msg.source; /\* caller proc nr. *\/ */ /* assert(str_len < STR_DEFAULT_LEN); */ /* phys_copy((void*)va2la(TASK_FS, buf), /\* to *\/ */ /* (void*)va2la(src, fs_msg.BUF), /\* from *\/ */ /* str_len); */ /* buf[str_len] = 0; /\* terminate the string *\/ */ /* return disklog(buf); */ /* } */ /***************************************************************************** * disklog *****************************************************************************/ /** * <Ring 1> Write log string directly into disk. * * @param p Ptr to the MESSAGE. *****************************************************************************/ PUBLIC int disklog(char * logstr) { int device = root_inode->i_dev; struct super_block * sb = get_super_block(device); int nr_log_blk0_nr = sb->nr_sects - NR_SECTS_FOR_LOG; /* 0x9D41-0x800=0x9541 */ static int pos = 0; if (!pos) { /* first time invoking this routine */ #ifdef SET_LOG_SECT_SMAP_AT_STARTUP /* * set sector-map so that other files cannot use the log sectors */ int bits_per_sect = SECTOR_SIZE * 8; /* 4096 */ int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; /* 3 */ int sect_nr = smap_blk0_nr + nr_log_blk0_nr / bits_per_sect; /* 3+9=12 */ int byte_off = (nr_log_blk0_nr % bits_per_sect) / 8; /* 168 */ int bit_off = (nr_log_blk0_nr % bits_per_sect) % 8; /* 1 */ int sect_cnt = NR_SECTS_FOR_LOG / bits_per_sect + 2; /* 1 */ int bits_left= NR_SECTS_FOR_LOG; /* 2048 */ int i; for (i = 0; i < sect_cnt; i++) { DISKLOG_RD_SECT(device, sect_nr + i); /* DISKLOG_RD_SECT(?, 12) */ for (; byte_off < SECTOR_SIZE && bits_left > 0; byte_off++) { for (; bit_off < 8; bit_off++) { /* repeat till enough bits are set */ assert(((logdiskbuf[byte_off] >> bit_off) & 1) == 0); logdiskbuf[byte_off] |= (1 << bit_off); if (--bits_left == 0) break; } bit_off = 0; } byte_off = 0; bit_off = 0; DISKLOG_WR_SECT(device, sect_nr + i); if (bits_left == 0) break; } assert(bits_left == 0); #endif /* SET_LOG_SECT_SMAP_AT_STARTUP */ pos = 0x40; #ifdef MEMSET_LOG_SECTS /* write padding stuff to log sectors */ int chunk = min(MAX_IO_BYTES, LOGDISKBUF_SIZE >> SECTOR_SIZE_SHIFT); assert(chunk == 256); int sects_left = NR_SECTS_FOR_LOG; for (i = nr_log_blk0_nr; i < nr_log_blk0_nr + NR_SECTS_FOR_LOG; i += chunk) { memset(logdiskbuf, 0x20, chunk*SECTOR_SIZE); rw_sector(DEV_WRITE, device, i * SECTOR_SIZE, chunk * SECTOR_SIZE, getpid(), logdiskbuf); sects_left -= chunk; } if (sects_left != 0) panic("sects_left should be 0, current: %d.", sects_left); #endif /* MEMSET_LOG_SECTS */ } char * p = logstr; int bytes_left = strlen(logstr); int sect_nr = nr_log_blk0_nr + (pos >> SECTOR_SIZE_SHIFT); while (bytes_left) { DISKLOG_RD_SECT(device, sect_nr); int off = pos % SECTOR_SIZE; int bytes = min(bytes_left, SECTOR_SIZE - off); memcpy(&logdiskbuf[off], p, bytes); off += bytes; bytes_left -= bytes; DISKLOG_WR_SECT(device, sect_nr); sect_nr++; pos += bytes; p += bytes; } struct time t; MESSAGE msg; msg.type = GET_RTC_TIME; msg.BUF= &t; send_recv(BOTH, TASK_SYS, &msg); /* write `pos' and time into the log file header */ DISKLOG_RD_SECT(device, nr_log_blk0_nr); sprintf((char*)logdiskbuf, "%8d\n", pos); memset(logdiskbuf+9, ' ', 22); logdiskbuf[31] = '\n'; sprintf((char*)logdiskbuf+32, "<%d-%02d-%02d %02d:%02d:%02d>\n", t.year, t.month, t.day, t.hour, t.minute, t.second); memset(logdiskbuf+32+22, ' ', 9); logdiskbuf[63] = '\n'; DISKLOG_WR_SECT(device, nr_log_blk0_nr); memset(logdiskbuf+64, logdiskbuf[32+19], 512-64); DISKLOG_WR_SECT(device, nr_log_blk0_nr + NR_SECTS_FOR_LOG - 1); return pos; } /* /\***************************************************************************** */ /* * inode2filename */ /* *****************************************************************************\/ */ /* /\** */ /* * Get filename via i-node */ /* * */ /* * @param inode */ /* * @param filename */ /* * */ /* * @return */ /* *****************************************************************************\/ */ /* PRIVATE char * inode2filename(int inode, char * filename) */ /* { */ /* int i, j; */ /* struct inode * dir_inode = root_inode; */ /* /\** */ /* * Search the dir for the file. */ /* *\/ */ /* int dir_blk0_nr = dir_inode->i_start_sect; */ /* int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE; */ /* int nr_dir_entries = */ /* dir_inode->i_size / DIR_ENTRY_SIZE; /\** */ /* * including unused slots */ /* * (the file has been deleted */ /* * but the slot is still there) */ /* *\/ */ /* int m = 0; */ /* struct dir_entry * pde; */ /* for (i = 0; i < nr_dir_blks; i++) { */ /* DISKLOG_RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); */ /* pde = (struct dir_entry *)logdiskbuf; */ /* for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { */ /* if (pde->inode_nr == inode) { */ /* memcpy(filename, pde->name, MAX_FILENAME_LEN); */ /* filename[MAX_FILENAME_LEN] = 0; */ /* if (filename[0] == '.') */ /* filename[0] = '/'; */ /* return filename; */ /* } */ /* if (++m > nr_dir_entries) */ /* break; */ /* } */ /* if (m > nr_dir_entries) /\* all entries have been iterated *\/ */ /* break; */ /* } */ /* /\* file not found *\/ */ /* return 0; */ /* } */ #define LOG_PROCS 1 /* YES */ #define LOG_FD_TABLE 1 #define LOG_INODE_TABLE 1 #define LOG_SMAP 1 #define LOG_IMAP 1 #define LOG_INODE_ARRAY 1 #define LOG_ROOT_DIR 1 #define LOG_MSG_SRC2DST 1 /* YES */ #define LOG_ARROW_PARENT_CHILD 1 /* YES */ #define LOG_ARROW_PROC_FD 1 #define LOG_ARROW_FD_INODE 1 #define LOG_ARROW_INODE_INODEARRAY 1 #if (LOG_SMAP == 1 || LOG_IMAP == 1 || LOG_INODE_ARRAY || LOG_ROOT_DIR == 1) static char _buf[SECTOR_SIZE]; #endif /***************************************************************************** * dump_fd_graph *****************************************************************************/ /** * Output a dot graph file. * *****************************************************************************/ PUBLIC void dump_fd_graph(const char * fmt, ...) { int i; int logbufpos = 0; char title[STR_DEFAULT_LEN]; va_list arg = (va_list)((char*)(&fmt) + 4); /** * 4: size of `fmt' in * the stack */ i = vsprintf(title, fmt, arg); assert(strlen(title) == i); printl("dump_fd_graph: %s\n", title); struct proc* p_proc; int callerpid = getpid(); /* assert(getpid() == TASK_MM); */ printl("<|"); disable_int(); int tcks[NR_TASKS + NR_PROCS]; int prio[NR_TASKS + NR_PROCS]; p_proc = proc_table; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) { if (p_proc->p_flags == FREE_SLOT) continue; if ((i == TASK_TTY) || (i == TASK_SYS) || (i == TASK_HD) || /* (i == TASK_FS) || */ (i == callerpid)) continue; tcks[i] = p_proc->ticks; prio[i] = p_proc->priority; p_proc->ticks = 0; p_proc->priority = 0; } static int graph_idx = 0; #if (LOG_ROOT_DIR == 1) char filename[MAX_FILENAME_LEN+1]; #endif char * proc_flags[32]; for (i = 0; i < sizeof(proc_flags) / sizeof(proc_flags[0]); i++) { proc_flags[i] = "__NOT_DEFINED__"; } proc_flags[0] = "RUNNING"; proc_flags[SENDING] = "SENDING"; proc_flags[RECEIVING] = "RECEIVING"; proc_flags[WAITING] = "WAITING"; proc_flags[HANGING] = "HANGING"; proc_flags[FREE_SLOT] = "FREE_SLOT"; proc_flags[SENDING+WAITING] = "SENDING, WAITING"; proc_flags[RECEIVING+WAITING] = "RECEIVING, WAITING"; proc_flags[RECEIVING+HANGING] = "RECEIVING, HANGING"; /* int inode_list[64]; */ /* int il_idx = 0; */ #if (LOG_PROCS == 1 || LOG_ARROW_PARENT_CHILD == 1) struct proc_parent_map { int pid; int ppid; } ppm[256]; int ppm_idx = 0; #endif #if (LOG_PROCS == 1 || LOG_ARROW_PROC_FD == 1) struct proc_fdesc_map { int pid; /* PID */ int filp; /* idx of proc_table[pid].filp[] */ int desc; /* idx of f_desc_table[] */ } pfm[256]; int pfm_idx = 0; #endif #if (LOG_FD_TABLE == 1 || LOG_ARROW_FD_INODE == 1) struct fdesc_inode_map { int desc; /* idx of f_desc_table[] */ int inode; /* idx of inode_table[] */ } fim[256]; int fim_idx = 0; #endif struct msg_src_dst { int src; int dst; int dir; } msd[256]; int msd_idx = 0; printl("|_|"); /* head */ logbufpos += sprintf(logbuf + logbufpos, "digraph filedesc%02d {\n", graph_idx++); logbufpos += sprintf(logbuf + logbufpos, "\tgraph [\n"); logbufpos += sprintf(logbuf + logbufpos, " rankdir = \"LR\"\n"); logbufpos += sprintf(logbuf + logbufpos, " ];\n"); logbufpos += sprintf(logbuf + logbufpos, " node [\n"); logbufpos += sprintf(logbuf + logbufpos, " fontsize = \"16\"\n"); logbufpos += sprintf(logbuf + logbufpos, " shape = \"ellipse\"\n"); logbufpos += sprintf(logbuf + logbufpos, " ];\n"); logbufpos += sprintf(logbuf + logbufpos, " edge [\n"); logbufpos += sprintf(logbuf + logbufpos, " ];\n"); #if (LOG_PROCS == 1) int k; p_proc = proc_table; logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_0 {\n"); for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) { /* skip unused proc_table entries */ if (p_proc->p_flags == FREE_SLOT) continue; /* /\* skip procs which open no files *\/ */ /* for (k = 0; k < NR_FILES; k++) { */ /* if (p_proc->filp[k] != 0) */ /* break; */ /* } */ /* if (k == NR_FILES) */ /* continue; */ if (p_proc->p_parent != NO_TASK) { ppm[ppm_idx].pid = i; ppm[ppm_idx].ppid = p_proc->p_parent; ppm_idx++; } if (p_proc->p_flags & RECEIVING) { msd[msd_idx].src = p_proc->p_recvfrom; msd[msd_idx].dst = proc2pid(p_proc); msd[msd_idx].dir = RECEIVING; msd_idx++; } if (p_proc->p_flags & SENDING) { msd[msd_idx].src = proc2pid(p_proc); msd[msd_idx].dst = p_proc->p_sendto; msd[msd_idx].dir = SENDING; msd_idx++; } logbufpos += sprintf(logbuf + logbufpos, "\t\t\"proc%d\" [\n" "\t\t\tlabel = \"<f0>%s (%d) " "|<f1> p_flags:%d(%s)" "|<f2> p_parent:%d%s" "|<f3> eip:0x%x", i, p_proc->name, i, p_proc->p_flags, proc_flags[p_proc->p_flags], p_proc->p_parent, p_proc->p_parent == NO_TASK ? "(NO_TASK)" : "", p_proc->regs.eip); int fnr = 3; for (k = 0; k < NR_FILES; k++) { if (p_proc->filp[k] == 0) continue; int fdesc_tbl_idx = p_proc->filp[k] - f_desc_table; logbufpos += sprintf(logbuf + logbufpos, "\t|<f%d> filp[%d]: %d", fnr, k, fdesc_tbl_idx); pfm[pfm_idx].pid = i; pfm[pfm_idx].filp = fnr; pfm[pfm_idx].desc = fdesc_tbl_idx; fnr++; pfm_idx++; } logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); } i = ANY; logbufpos += sprintf(logbuf + logbufpos, "\t\t\"proc%d\" [\n", i); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0>ANY |<f1> "); logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"procs\";\n"); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("0"); #if (LOG_FD_TABLE == 1) logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_1 {\n"); for (i = 0; i < NR_FILE_DESC; i++) { if (f_desc_table[i].fd_inode == 0) continue; int inode_tbl_idx = f_desc_table[i].fd_inode - inode_table; logbufpos += sprintf(logbuf + logbufpos, "\t\t\"filedesc%d\" [\n", i); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0>filedesc %d" "|<f1> fd_mode:%d" "|<f2> fd_pos:%d" "|<f3> fd_cnt:%d" "|<f4> fd_inode:%d", i, f_desc_table[i].fd_mode, f_desc_table[i].fd_pos, f_desc_table[i].fd_cnt, inode_tbl_idx); fim[fim_idx].desc = i; fim[fim_idx].inode = inode_tbl_idx; fim_idx++; logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); } logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"filedescs\";\n"); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("1"); #if (LOG_INODE_TABLE == 1) logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_2 {\n"); for (i = 0; i < NR_INODE; i++) { if (inode_table[i].i_cnt == 0) continue; logbufpos += sprintf(logbuf + logbufpos, "\t\t\"inode%d\" [\n", i); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0>inode %d" "|<f1> i_mode:0x%x" "|<f2> i_size:0x%x" "|<f3> i_start_sect:0x%x" "|<f4> i_nr_sects:0x%x" "|<f5> i_dev:0x%x" "|<f6> i_cnt:%d" "|<f7> i_num:%d", i, inode_table[i].i_mode, inode_table[i].i_size, inode_table[i].i_start_sect, inode_table[i].i_nr_sects, inode_table[i].i_dev, inode_table[i].i_cnt, inode_table[i].i_num); logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); } logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"inodes\";\n"); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("2"); enable_int(); #if (LOG_SMAP == 1) logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_3 {\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tstyle=filled;\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tcolor=lightgrey;\n"); int smap_flag = 0; int bit_start = 0; /* i: sector index */ int j; /* byte index */ /* k: bit index */ struct super_block * sb = get_super_block(root_inode->i_dev); int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */ DISKLOG_RD_SECT(root_inode->i_dev, smap_blk0_nr + i); memcpy(_buf, logdiskbuf, SECTOR_SIZE); for (j = 0; j < SECTOR_SIZE; j++) { for (k = 0; k < 8; k++) { if (!smap_flag) { if ((_buf[j] >> k ) & 1) { smap_flag = 1; bit_start = (i * SECTOR_SIZE + j) * 8 + k; } else { continue; } } else { if ((_buf[j] >> k ) & 1) { continue; } else { smap_flag = 0; int bit_end = (i * SECTOR_SIZE + j) * 8 + k - 1; logbufpos += sprintf(logbuf + logbufpos, "\t\t\"sector %xh\" [\n", bit_start); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0>sect %xh-%xh", bit_start, bit_end); logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); } } } } } logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"sector map (dev size: %xh)\";\n", sb->nr_sects); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("3"); #if (LOG_IMAP == 1) logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_4 {\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tstyle=filled;\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tcolor=lightgrey;\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\"imap\" [\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0>bits"); /* i: sector index */ /* j: byte index */ /* k: bit index */ int imap_blk0_nr = 1 + 1; for (i = 0; i < sb->nr_imap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */ DISKLOG_RD_SECT(root_inode->i_dev, imap_blk0_nr + i); memcpy(_buf, logdiskbuf, SECTOR_SIZE); for (j = 0; j < SECTOR_SIZE; j++) { for (k = 0; k < 8; k++) { if ((_buf[j] >> k ) & 1) { int bit_nr = (i * SECTOR_SIZE + j) * 8 + k; logbufpos += sprintf(logbuf + logbufpos, "| %xh ", bit_nr); } } } } logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"inode map\";\n"); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("4"); #if (LOG_INODE_ARRAY == 1) logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_5 {\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tstyle=filled;\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tcolor=lightgrey;\n"); sb = get_super_block(root_inode->i_dev); int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects; DISKLOG_RD_SECT(root_inode->i_dev, blk_nr); memcpy(_buf, logdiskbuf, SECTOR_SIZE); char * p = _buf; for (i = 0; i < SECTOR_SIZE / sizeof(struct inode); i++,p+=INODE_SIZE) { struct inode * pinode = (struct inode*)p; if (pinode->i_start_sect == 0) continue; int start_sect; int end_sect; if (pinode->i_mode) { if (pinode->i_start_sect < sb->n_1st_sect) { panic("should not happen: %x < %x.", pinode->i_start_sect, sb->n_1st_sect); } start_sect = pinode->i_start_sect - sb->n_1st_sect + 1; end_sect = start_sect + pinode->i_nr_sects - 1; logbufpos += sprintf(logbuf + logbufpos, "\t\t\"inodearray%d\" [\n", i+1); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0> %d" "|<f2> i_size:0x%x" "|<f3> sect: %xh-%xh", i+1, pinode->i_size, start_sect, end_sect); logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); } else { start_sect = MAJOR(pinode->i_start_sect); end_sect = MINOR(pinode->i_start_sect); logbufpos += sprintf(logbuf + logbufpos, "\t\t\"inodearray%d\" [\n", i+1); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0> %d" "|<f2> i_size:0x%x" "|<f3> dev nr: (%xh,%xh)", i+1, pinode->i_size, start_sect, end_sect); logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); } } logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"inode array\";\n"); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("5"); #if (LOG_ROOT_DIR == 1) logbufpos += sprintf(logbuf + logbufpos, "\n\tsubgraph cluster_6 {\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tstyle=filled;\n"); logbufpos += sprintf(logbuf + logbufpos, "\n\t\tcolor=lightgrey;\n"); sb = get_super_block(root_inode->i_dev); int dir_blk0_nr = root_inode->i_start_sect; int nr_dir_blks = (root_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE; int nr_dir_entries = root_inode->i_size / DIR_ENTRY_SIZE; /** * including unused slots * (the file has been deleted * but the slot is still there) */ int m = 0; struct dir_entry * pde; for (i = 0; i < nr_dir_blks; i++) { DISKLOG_RD_SECT(root_inode->i_dev, dir_blk0_nr + i); memcpy(_buf, logdiskbuf, SECTOR_SIZE); pde = (struct dir_entry *)_buf; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { if (pde->inode_nr) { memcpy(filename, pde->name, MAX_FILENAME_LEN); if (filename[0] == '.') filename[0] = '/'; logbufpos += sprintf(logbuf + logbufpos, "\t\t\"rootdirent%d\" [\n", pde->inode_nr); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tlabel = \"<f0> %d" "|<f2> %s", pde->inode_nr, filename); logbufpos += sprintf(logbuf + logbufpos, "\t\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t\tshape = \"record\"\n"); logbufpos += sprintf(logbuf + logbufpos, "\t\t];\n"); logbufpos += sprintf(logbuf + logbufpos, "\t" "\"inodearray%d\":f0" " -> " "\"rootdirent%d\":f0" ";\n", pde->inode_nr, pde->inode_nr); } } if (m > nr_dir_entries) /* all entries have been iterated */ break; } logbufpos += sprintf(logbuf + logbufpos, "\t\tlabel = \"root dir\";\n"); logbufpos += sprintf(logbuf + logbufpos, "\t}\n"); #endif printl("6"); #if (LOG_MSG_SRC2DST == 1) for (i = 0; i < msd_idx; i++) { if (msd[i].dir == RECEIVING) logbufpos += sprintf(logbuf + logbufpos, "\t\"proc%d\":f0 -> \"proc%d\":f0 " "[arrowhead=\"crow\", color=\"green\", label=\"%d\"];\n", msd[i].dst, msd[i].src, i); else if (msd[i].dir == SENDING) logbufpos += sprintf(logbuf + logbufpos, "\t\"proc%d\":f0 -> \"proc%d\":f0 " "[arrowhead=\"vee\", color=\"blue\", label=\"%d\"];\n", msd[i].src, msd[i].dst, i); else assert(0); } #endif #if (LOG_ARROW_PARENT_CHILD == 1) for (i = 0; i < ppm_idx; i++) { logbufpos += sprintf(logbuf + logbufpos, "\t\"proc%d\":f0 -> \"proc%d\":f0 " "[arrowhead=\"dot\", color=\"ivory3\"];\n", ppm[i].ppid, ppm[i].pid); } #endif #if (LOG_ARROW_PROC_FD == 1) for (i = 0; i < pfm_idx; i++) { logbufpos += sprintf(logbuf + logbufpos, "\t\"proc%d\":f%d -> \"filedesc%d\":f3;\n", pfm[i].pid, pfm[i].filp, pfm[i].desc); } #endif #if (LOG_ARROW_FD_INODE == 1) for (i = 0; i < fim_idx; i++) { logbufpos += sprintf(logbuf + logbufpos, "\t\"filedesc%d\":f4 -> \"inode%d\":f6;\n", fim[i].desc, fim[i].inode); } #endif #if (LOG_ARROW_INODE_INODEARRAY == 1) for (i = 0; i < NR_INODE; i++) { if (inode_table[i].i_cnt != 0) logbufpos += sprintf(logbuf + logbufpos, "\t\"inode%d\":f7 -> \"inodearray%d\":f0;\n", i, inode_table[i].i_num); } #endif /* for (i = 0; i < il_idx; i++) { */ /* logbufpos += sprintf(logbuf + logbufpos, "\t\"inode%d\":f7 -> \"inodearray%d\":f0;\n", */ /* inode_list[i], inode_list[i]); */ /* } */ /* tail */ logbufpos += sprintf(logbuf + logbufpos, "\tlabel = \"%s\";\n", title); logbufpos += sprintf(logbuf + logbufpos, "}\n"); /* separator */ logbufpos += sprintf(logbuf + logbufpos, "--separator--\n"); assert(logbufpos < LOGBUF_SIZE); logbuf[logbufpos] = 0; char tmp[STR_DEFAULT_LEN/2]; int bytes_left = logbufpos; int pos = 0; while (bytes_left) { int bytes = min(bytes_left, STR_DEFAULT_LEN/2 - 1); memcpy(tmp, logbuf + pos, bytes); tmp[bytes] = 0; disklog(tmp); pos += bytes; bytes_left -= bytes; } disable_int(); p_proc = proc_table; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) { if (p_proc->p_flags == FREE_SLOT) continue; if ((i == TASK_TTY) || (i == TASK_SYS) || (i == TASK_HD) || /* (i == TASK_FS) || */ (i == getpid())) continue; p_proc->ticks = tcks[i]; p_proc->priority = prio[i]; } enable_int(); printl("|>"); /* int pos = logbufpos += sprintf(logbuf + logbufpos, "--separator--\n"); */ /* printl("dump_fd_graph(%s)::logbufpos:%d\n", title, logbufpos); */ }
fs/open.c
/*************************************************************************//** ***************************************************************************** * @file fs/open.c * The file contains: * - do_open() * - do_close() * - do_lseek() * - create_file() * @author Forrest Yu * @date 2007 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "stdio.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 "keyboard.h" #include "proto.h" PRIVATE struct inode * create_file(char * path, int flags); PRIVATE int alloc_imap_bit(int dev); PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc); PRIVATE struct inode * new_inode(int dev, int inode_nr, int start_sect); PRIVATE void new_dir_entry(struct inode * dir_inode, int inode_nr, char * filename); /***************************************************************************** * do_open *****************************************************************************/ /** * Open a file and return the file descriptor. * * @return File descriptor if successful, otherwise a negative error code. *****************************************************************************/ PUBLIC int do_open() { int fd = -1; /* return value */ char pathname[MAX_PATH]; /* get parameters from the message */ int flags = fs_msg.FLAGS; /* access mode */ int name_len = fs_msg.NAME_LEN; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(name_len < MAX_PATH); phys_copy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; /* find a free slot in PROCESS::filp[] */ int i; for (i = 0; i < NR_FILES; i++) { if (pcaller->filp[i] == 0) { fd = i; break; } } if ((fd < 0) || (fd >= NR_FILES)) panic("filp[] is full (PID:%d)", proc2pid(pcaller)); /* find a free slot in f_desc_table[] */ for (i = 0; i < NR_FILE_DESC; i++) if (f_desc_table[i].fd_inode == 0) break; if (i >= NR_FILE_DESC) panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller)); int inode_nr = search_file(pathname); struct inode * pin = 0; if (flags & O_CREAT) { if (inode_nr) { printl("{FS} file exists.\n"); return -1; } else { pin = create_file(pathname, flags); } } else { assert(flags & O_RDWR); char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; pin = get_inode(dir_inode->i_dev, inode_nr); } if (pin) { /* connects proc with file_descriptor */ pcaller->filp[fd] = &f_desc_table[i]; /* connects file_descriptor with inode */ f_desc_table[i].fd_inode = pin; f_desc_table[i].fd_mode = flags; f_desc_table[i].fd_cnt = 1; f_desc_table[i].fd_pos = 0; int imode = pin->i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { MESSAGE driver_msg; driver_msg.type = DEV_OPEN; int dev = pin->i_start_sect; driver_msg.DEVICE = MINOR(dev); assert(MAJOR(dev) == 4); assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg); } else if (imode == I_DIRECTORY) { assert(pin->i_num == ROOT_INODE); } else { assert(pin->i_mode == I_REGULAR); } } else { return -1; } return fd; } /***************************************************************************** * create_file *****************************************************************************/ /** * Create a file and return it's inode ptr. * * @param[in] path The full path of the new file * @param[in] flags Attribiutes of the new file * * @return Ptr to i-node of the new file if successful, otherwise 0. * * @see open() * @see do_open() * * @todo return values of routines called, return values of self. *****************************************************************************/ PRIVATE struct inode * create_file(char * path, int flags) { char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, path, &dir_inode) != 0) return 0; int inode_nr = alloc_imap_bit(dir_inode->i_dev); int free_sect_nr = alloc_smap_bit(dir_inode->i_dev, NR_DEFAULT_FILE_SECTS); struct inode *newino = new_inode(dir_inode->i_dev, inode_nr, free_sect_nr); new_dir_entry(dir_inode, newino->i_num, filename); return newino; } /***************************************************************************** * do_close *****************************************************************************/ /** * Handle the message CLOSE. * * @return Zero if success. *****************************************************************************/ PUBLIC int do_close() { int fd = fs_msg.FD; put_inode(pcaller->filp[fd]->fd_inode); if (--pcaller->filp[fd]->fd_cnt == 0) pcaller->filp[fd]->fd_inode = 0; pcaller->filp[fd] = 0; return 0; } /***************************************************************************** * do_lseek *****************************************************************************/ /** * Handle the message LSEEK. * * @return The new offset in bytes from the beginning of the file if successful, * otherwise a negative number. *****************************************************************************/ PUBLIC int do_lseek() { int fd = fs_msg.FD; int off = fs_msg.OFFSET; int whence = fs_msg.WHENCE; int pos = pcaller->filp[fd]->fd_pos; int f_size = pcaller->filp[fd]->fd_inode->i_size; switch (whence) { case SEEK_SET: pos = off; break; case SEEK_CUR: pos += off; break; case SEEK_END: pos = f_size + off; break; default: return -1; break; } if ((pos > f_size) || (pos < 0)) { return -1; } pcaller->filp[fd]->fd_pos = pos; return pos; } /***************************************************************************** * alloc_imap_bit *****************************************************************************/ /** * Allocate a bit in inode-map. * * @param dev In which device the inode-map is located. * * @return I-node nr. *****************************************************************************/ PRIVATE int alloc_imap_bit(int dev) { int inode_nr = 0; int i, j, k; int imap_blk0_nr = 1 + 1; /* 1 boot sector & 1 super block */ struct super_block * sb = get_super_block(dev); for (i = 0; i < sb->nr_imap_sects; i++) { RD_SECT(dev, imap_blk0_nr + i); for (j = 0; j < SECTOR_SIZE; j++) { /* skip `11111111' bytes */ if (fsbuf[j] == 0xFF) continue; /* skip `1' bits */ for (k = 0; ((fsbuf[j] >> k) & 1) != 0; k++) {} /* i: sector index; j: byte index; k: bit index */ inode_nr = (i * SECTOR_SIZE + j) * 8 + k; fsbuf[j] |= (1 << k); /* write the bit to imap */ WR_SECT(dev, imap_blk0_nr + i); break; } return inode_nr; } /* no free bit in imap */ panic("inode-map is probably full.\n"); return 0; } /***************************************************************************** * alloc_smap_bit *****************************************************************************/ /** * Allocate a bit in sector-map. * * @param dev In which device the sector-map is located. * @param nr_sects_to_alloc How many sectors are allocated. * * @return The 1st sector nr allocated. *****************************************************************************/ PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc) { /* int nr_sects_to_alloc = NR_DEFAULT_FILE_SECTS; */ int i; /* sector index */ int j; /* byte index */ int k; /* bit index */ struct super_block * sb = get_super_block(dev); int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; int free_sect_nr = 0; for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */ RD_SECT(dev, smap_blk0_nr + i); /* byte offset in current sect */ for (j = 0; j < SECTOR_SIZE && nr_sects_to_alloc > 0; j++) { k = 0; if (!free_sect_nr) { /* loop until a free bit is found */ if (fsbuf[j] == 0xFF) continue; for (; ((fsbuf[j] >> k) & 1) != 0; k++) {} free_sect_nr = (i * SECTOR_SIZE + j) * 8 + k - 1 + sb->n_1st_sect; } for (; k < 8; k++) { /* repeat till enough bits are set */ assert(((fsbuf[j] >> k) & 1) == 0); fsbuf[j] |= (1 << k); if (--nr_sects_to_alloc == 0) break; } } if (free_sect_nr) /* free bit found, write the bits to smap */ WR_SECT(dev, smap_blk0_nr + i); if (nr_sects_to_alloc == 0) break; } assert(nr_sects_to_alloc == 0); return free_sect_nr; } /***************************************************************************** * new_inode *****************************************************************************/ /** * Generate a new i-node and write it to disk. * * @param dev Home device of the i-node. * @param inode_nr I-node nr. * @param start_sect Start sector of the file pointed by the new i-node. * * @return Ptr of the new i-node. *****************************************************************************/ PRIVATE struct inode * new_inode(int dev, int inode_nr, int start_sect) { struct inode * new_inode = get_inode(dev, inode_nr); new_inode->i_mode = I_REGULAR; new_inode->i_size = 0; new_inode->i_start_sect = start_sect; new_inode->i_nr_sects = NR_DEFAULT_FILE_SECTS; new_inode->i_dev = dev; new_inode->i_cnt = 1; new_inode->i_num = inode_nr; /* write to the inode array */ sync_inode(new_inode); return new_inode; } /***************************************************************************** * new_dir_entry *****************************************************************************/ /** * Write a new entry into the directory. * * @param dir_inode I-node of the directory. * @param inode_nr I-node nr of the new file. * @param filename Filename of the new file. *****************************************************************************/ PRIVATE void new_dir_entry(struct inode *dir_inode,int inode_nr,char *filename) { /* write the dir_entry */ int dir_blk0_nr = dir_inode->i_start_sect; int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE; int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; /** * including unused slots * (the file has been * deleted but the slot * is still there) */ int m = 0; struct dir_entry * pde; struct dir_entry * new_de = 0; int i, j; for (i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { if (++m > nr_dir_entries) break; if (pde->inode_nr == 0) { /* it's a free slot */ new_de = pde; break; } } if (m > nr_dir_entries ||/* all entries have been iterated or */ new_de) /* free slot is found */ break; } if (!new_de) { /* reached the end of the dir */ new_de = pde; dir_inode->i_size += DIR_ENTRY_SIZE; } new_de->inode_nr = inode_nr; strcpy(new_de->name, filename); /* write dir block -- ROOT dir block */ WR_SECT(dir_inode->i_dev, dir_blk0_nr + i); /* update dir inode */ sync_inode(dir_inode); }
include/sys/config.h
/*************************************************************************//** ***************************************************************************** * @file config.h * @brief * @author Forrest Y. Yu * @date 2008 ***************************************************************************** *****************************************************************************/ #define MINOR_BOOT MINOR_hd2a /** * boot parameters are stored by the loader, they should be * there when kernel is running and should not be overwritten * since kernel might use them at any time. */ #define BOOT_PARAM_ADDR 0x900 /* physical address */ #define BOOT_PARAM_MAGIC 0xB007 /* magic number */ #define BI_MAG 0 #define BI_MEM_SIZE 1 #define BI_KERNEL_FILE 2 /* * disk log */ #define ENABLE_DISK_LOG #define SET_LOG_SECT_SMAP_AT_STARTUP #define MEMSET_LOG_SECTS #define NR_SECTS_FOR_LOG NR_DEFAULT_FILE_SECTS
include/sys/const.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ const.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_CONST_H_ #define _ORANGES_CONST_H_ /* 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 */ #define WAITING 0x08 /* set when proc waiting for the child to terminate */ #define HANGING 0x10 /* set when proc exits without being waited by parent */ #define FREE_SLOT 0x20 /* set when proc table entry is not used * (ok to allocated to a new process) */ /* 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 */ /* CMOS */ #define CLK_ELE 0x70 /* CMOS RAM address register port (write only) * Bit 7 = 1 NMI disable * 0 NMI enable * Bits 6-0 = RAM address */ #define CLK_IO 0x71 /* CMOS RAM data register port (read/write) */ #define YEAR 9 /* Clock register addresses in CMOS RAM */ #define MONTH 8 #define DAY 7 #define HOUR 4 #define MINUTE 2 #define SECOND 0 #define CLK_STATUS 0x0B /* Status register B: RTC configuration */ #define CLK_HEALTH 0x0E /* Diagnostic status: (should be set by Power * On Self-Test [POST]) * Bit 7 = RTC lost power * 6 = Checksum (for addr 0x10-0x2d) bad * 5 = Config. Info. bad at POST * 4 = Mem. size error at POST * 3 = I/O board failed initialization * 2 = CMOS time invalid * 1-0 = reserved */ /* 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 INIT 5 #define ANY (NR_TASKS + NR_PROCS + 10) #define NO_TASK (NR_TASKS + NR_PROCS + 20) #define MAX_TICKS 0x7FFFABCD /* 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, GET_PID, GET_RTC_TIME, /* FS */ OPEN, CLOSE, READ, WRITE, LSEEK, STAT, UNLINK, /* FS & TTY */ SUSPEND_PROC, RESUME_PROC, /* MM */ EXEC, WAIT, /* FS & MM */ FORK, EXIT, /* TTY, SYS, FS, MM, etc */ SYSCALL_RET, /* 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 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) #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 * 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) /* device numbers of hard disk */ #define MINOR_hd1a 0x10 #define MINOR_hd2a (MINOR_hd1a+NR_SUB_PER_PART) #define ROOT_DEV MAKE_DEV(DEV_HD, MINOR_BOOT) #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 12 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/sys/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. */ 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. */ struct super_block { u32 magic; /**< Magic number */ u32 nr_inodes; /**< How many inodes */ u32 nr_sects; /**< How many sectors */ 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_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 \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 */ 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 /** * @def MAX_FILENAME_LEN * @brief Max len of a filename * @see dir_entry */ #define MAX_FILENAME_LEN 12 /** * @struct dir_entry * @brief Directory Entry */ struct dir_entry { int inode_nr; /**< inode nr. */ char name[MAX_FILENAME_LEN]; /**< Filename */ }; /** * @def DIR_ENTRY_SIZE * @brief The size of directory entry in the device. * * It is as same as the size in memory. */ #define DIR_ENTRY_SIZE sizeof(struct dir_entry) /** * @struct file_desc * @brief File Descriptor */ struct file_desc { int fd_mode; /**< R or W */ int fd_pos; /**< Current position for R/W. */ int fd_cnt; /**< How many procs share this desc */ 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. */ #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/sys/global.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ global.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* EXTERN is defined as extern except in global.c */ #ifdef GLOBAL_VARIABLES_HERE #undef EXTERN #define EXTERN #endif EXTERN int ticks; EXTERN int disp_pos; EXTERN u8 gdt_ptr[6]; /* 0~15:Limit 16~47:Base */ EXTERN struct descriptor gdt[GDT_SIZE]; EXTERN u8 idt_ptr[6]; /* 0~15:Limit 16~47:Base */ EXTERN struct gate idt[IDT_SIZE]; EXTERN u32 k_reenter; EXTERN int current_console; EXTERN int key_pressed; /** * used for clock_handler * to wake up TASK_TTY when * a key is pressed */ EXTERN struct tss tss; EXTERN struct proc* p_proc_ready; extern char task_stack[]; extern struct proc proc_table[]; extern struct task task_table[]; extern struct task user_proc_table[]; extern irq_handler irq_table[]; extern TTY tty_table[]; extern CONSOLE console_table[]; /* MM */ EXTERN MESSAGE mm_msg; extern u8 * mmbuf; extern const int MMBUF_SIZE; EXTERN int memory_size; /* FS */ EXTERN struct file_desc f_desc_table[NR_FILE_DESC]; EXTERN struct inode inode_table[NR_INODE]; EXTERN struct super_block super_block[NR_SUPER_BLOCK]; extern u8 * fsbuf; extern const int FSBUF_SIZE; EXTERN MESSAGE fs_msg; EXTERN struct proc * pcaller; EXTERN struct inode * root_inode; extern struct dev_drv_map dd_map[]; /* for test only */ extern char * logbuf; extern const int LOGBUF_SIZE; extern char * logdiskbuf; extern const int LOGDISKBUF_SIZE;
include/sys/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 p_parent; /**< pid of parent process */ int exit_status; /**< for parent */ struct file_desc * filp[NR_FILES]; }; struct task { task_f initial_eip; int stacksize; char name[32]; }; #define proc2pid(x) (x - proc_table) /* Number of tasks & processes */ #define NR_TASKS 5 #define NR_PROCS 32 #define NR_NATIVE_PROCS 4 #define FIRST_PROC proc_table[0] #define LAST_PROC proc_table[NR_TASKS + NR_PROCS - 1] /** * All forked proc will use memory above PROCS_BASE. * * @attention make sure PROCS_BASE is higher than any buffers, such as * fsbuf, mmbuf, etc * @see global.c * @see global.h */ #define PROCS_BASE 0xA00000 /* 10 MB */ #define PROC_IMAGE_SIZE_DEFAULT 0x100000 /* 1 MB */ #define PROC_ORIGIN_STACK 0x400 /* 1 KB */ /* stacks of tasks */ #define STACK_SIZE_DEFAULT 0x4000 /* 16 KB */ #define STACK_SIZE_TTY STACK_SIZE_DEFAULT #define STACK_SIZE_SYS STACK_SIZE_DEFAULT #define STACK_SIZE_HD STACK_SIZE_DEFAULT #define STACK_SIZE_FS STACK_SIZE_DEFAULT #define STACK_SIZE_MM STACK_SIZE_DEFAULT #define STACK_SIZE_INIT STACK_SIZE_DEFAULT #define STACK_SIZE_TESTA STACK_SIZE_DEFAULT #define STACK_SIZE_TESTB STACK_SIZE_DEFAULT #define STACK_SIZE_TESTC STACK_SIZE_DEFAULT #define STACK_SIZE_TOTAL (STACK_SIZE_TTY + \ STACK_SIZE_SYS + \ STACK_SIZE_HD + \ STACK_SIZE_FS + \ STACK_SIZE_MM + \ STACK_SIZE_INIT + \ STACK_SIZE_TESTA + \ STACK_SIZE_TESTB + \ STACK_SIZE_TESTC)
include/sys/protect.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ protect.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_PROTECT_H_ #define _ORANGES_PROTECT_H_ /* 存儲段描述符/系統段描述符 */ struct descriptor /* 共 8 個字節 */ { u16 limit_low; /* Limit */ u16 base_low; /* Base */ u8 base_mid; /* Base */ u8 attr1; /* P(1) DPL(2) DT(1) TYPE(4) */ u8 limit_high_attr2; /* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */ u8 base_high; /* Base */ }; #define reassembly(high, high_shift, mid, mid_shift, low) \ (((high) << (high_shift)) + \ ((mid) << (mid_shift)) + \ (low)) /* 門描述符 */ struct gate { u16 offset_low; /* Offset Low */ u16 selector; /* Selector */ u8 dcount; /* 該字段只在調用門描述符中有效。 如果在利用調用門調用子程序時引起特權級的轉換和堆棧的改變,需要將外層堆棧中的參數複製到內層堆棧。 該雙字計數字段就是用於說明這種情況發生時,要複製的雙字參數的數量。 */ u8 attr; /* P(1) DPL(2) DT(1) TYPE(4) */ u16 offset_high; /* Offset High */ }; struct tss { u32 backlink; u32 esp0; /* stack pointer to use during interrupt */ u32 ss0; /* " segment " " " " */ u32 esp1; u32 ss1; u32 esp2; u32 ss2; u32 cr3; u32 eip; u32 flags; u32 eax; u32 ecx; u32 edx; u32 ebx; u32 esp; u32 ebp; u32 esi; u32 edi; u32 es; u32 cs; u32 ss; u32 ds; u32 fs; u32 gs; u32 ldt; u16 trap; u16 iobase; /* I/O位圖基址大於或等於TSS段界限,就表示沒有I/O許可位圖 */ /*u8 iomap[2];*/ }; /* GDT */ /* 描述符索引 */ #define INDEX_DUMMY 0 /* ┓ */ #define INDEX_FLAT_C 1 /* ┣ LOADER 裡面已經確定了的. */ #define INDEX_FLAT_RW 2 /* ┃ */ #define INDEX_VIDEO 3 /* ┛ */ #define INDEX_TSS 4 #define INDEX_LDT_FIRST 5 /* 選擇子 */ #define SELECTOR_DUMMY 0 /* ┓ */ #define SELECTOR_FLAT_C 0x08 /* ┣ LOADER 裡面已經確定了的. */ #define SELECTOR_FLAT_RW 0x10 /* ┃ */ #define SELECTOR_VIDEO (0x18+3) /* ┛<-- RPL=3 */ #define SELECTOR_TSS 0x20 /* TSS. 從外層跳到內存時 SS 和 ESP 的值從裡面獲得. */ #define SELECTOR_LDT_FIRST 0x28 #define SELECTOR_KERNEL_CS SELECTOR_FLAT_C #define SELECTOR_KERNEL_DS SELECTOR_FLAT_RW #define SELECTOR_KERNEL_GS SELECTOR_VIDEO /* 每個任務有一個單獨的 LDT, 每個 LDT 中的描述符個數: */ #define LDT_SIZE 2 /* descriptor indices in LDT */ #define INDEX_LDT_C 0 #define INDEX_LDT_RW 1 /* 描述符類型值說明 */ #define DA_32 0x4000 /* 32 位段 */ #define DA_LIMIT_4K 0x8000 /* 段界限粒度為 4K 字節 */ #define LIMIT_4K_SHIFT 12 #define DA_DPL0 0x00 /* DPL = 0 */ #define DA_DPL1 0x20 /* DPL = 1 */ #define DA_DPL2 0x40 /* DPL = 2 */ #define DA_DPL3 0x60 /* DPL = 3 */ /* 存儲段描述符類型值說明 */ #define DA_DR 0x90 /* 存在的只讀數據段類型值 */ #define DA_DRW 0x92 /* 存在的可讀寫數據段屬性值 */ #define DA_DRWA 0x93 /* 存在的已訪問可讀寫數據段類型值 */ #define DA_C 0x98 /* 存在的只執行代碼段屬性值 */ #define DA_CR 0x9A /* 存在的可執行可讀代碼段屬性值 */ #define DA_CCO 0x9C /* 存在的只執行一致代碼段屬性值 */ #define DA_CCOR 0x9E /* 存在的可執行可讀一致代碼段屬性值 */ /* 系統段描述符類型值說明 */ #define DA_LDT 0x82 /* 局部描述符表段類型值 */ #define DA_TaskGate 0x85 /* 任務門類型值 */ #define DA_386TSS 0x89 /* 可用 386 任務狀態段類型值 */ #define DA_386CGate 0x8C /* 386 調用門類型值 */ #define DA_386IGate 0x8E /* 386 中斷門類型值 */ #define DA_386TGate 0x8F /* 386 陷阱門類型值 */ /* 選擇子類型值說明 */ /* 其中, SA_ : Selector Attribute */ #define SA_RPL_MASK 0xFFFC #define SA_RPL0 0 #define SA_RPL1 1 #define SA_RPL2 2 #define SA_RPL3 3 #define SA_TI_MASK 0xFFFB #define SA_TIG 0 #define SA_TIL 4 /* 中斷向量 */ #define INT_VECTOR_DIVIDE 0x0 #define INT_VECTOR_DEBUG 0x1 #define INT_VECTOR_NMI 0x2 #define INT_VECTOR_BREAKPOINT 0x3 #define INT_VECTOR_OVERFLOW 0x4 #define INT_VECTOR_BOUNDS 0x5 #define INT_VECTOR_INVAL_OP 0x6 #define INT_VECTOR_COPROC_NOT 0x7 #define INT_VECTOR_DOUBLE_FAULT 0x8 #define INT_VECTOR_COPROC_SEG 0x9 #define INT_VECTOR_INVAL_TSS 0xA #define INT_VECTOR_SEG_NOT 0xB #define INT_VECTOR_STACK_FAULT 0xC #define INT_VECTOR_PROTECTION 0xD #define INT_VECTOR_PAGE_FAULT 0xE #define INT_VECTOR_COPROC_ERR 0x10 /* 中斷向量 */ #define INT_VECTOR_IRQ0 0x20 #define INT_VECTOR_IRQ8 0x28 /* 系統調用 */ #define INT_VECTOR_SYS_CALL 0x90 /* 宏 */ /* 線性地址 → 物理地址 */ //#define vir2phys(seg_base, vir) (u32)(((u32)seg_base) + (u32)(vir)) /* seg:off -> linear addr */ #define makelinear(seg,off) (u32)(((u32)(seg2linear(seg))) + (u32)(off)) #endif /* _ORANGES_PROTECT_H_ */
include/sys/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 seg2linear(u16 seg); PUBLIC void init_desc(struct descriptor * p_desc, u32 base, u32 limit, u16 attribute); /* klib.c */ PUBLIC void get_boot_params(struct boot_params * pbp); PUBLIC int get_kernel_map(unsigned int * b, unsigned int * l); 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 void Init(); 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); PUBLIC void dump_tty_buf(); /* for debug only */ /* systask.c */ PUBLIC void task_sys(); /* fs/main.c */ PUBLIC void task_fs(); PUBLIC int rw_sector(int io_type, int dev, u64 pos, int bytes, int proc_nr, void * buf); PUBLIC struct inode * get_inode(int dev, int num); PUBLIC void put_inode(struct inode * pinode); PUBLIC void sync_inode(struct inode * p); PUBLIC struct super_block * get_super_block(int dev); /* fs/open.c */ PUBLIC int do_open(); PUBLIC int do_close(); /* fs/read_write.c */ PUBLIC int do_rdwt(); /* fs/link.c */ PUBLIC int do_unlink(); /* fs/misc.c */ PUBLIC int do_stat(); PUBLIC int strip_path(char * filename, const char * pathname, struct inode** ppinode); PUBLIC int search_file(char * path); /* fs/disklog.c */ PUBLIC int do_disklog(); PUBLIC int disklog(char * logstr); /* for debug */ PUBLIC void dump_fd_graph(const char * fmt, ...); /* mm/main.c */ PUBLIC void task_mm(); PUBLIC int alloc_mem(int pid, int memsize); PUBLIC int free_mem(int pid); /* mm/forkexit.c */ PUBLIC int do_fork(); PUBLIC void do_exit(int status); PUBLIC void do_wait(); /* mm/exec.c */ /* PUBLIC int do_exec(); */ /* 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); /* 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);
include/stdio.h
/*************************************************************************//** ***************************************************************************** * @file stdio.h * @brief * @author Forrest Y. Yu * @date 2008 ***************************************************************************** *****************************************************************************/ /* 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 */ /* string */ #define STR_DEFAULT_LEN 1024 #define O_CREAT 1 #define O_RDWR 2 #define SEEK_SET 1 #define SEEK_CUR 2 #define SEEK_END 3 #define MAX_PATH 128 /** * @struct time * @brief RTC time from CMOS. */ struct time { u32 year; u32 month; u32 day; u32 hour; u32 minute; u32 second; }; #define BCD_TO_DEC(x) ( (x >> 4) * 10 + (x & 0x0f) ) /*========================* * printf, printl, printx * *========================* * * printf: * * [send msg] WRITE DEV_WRITE * USER_PROC ------------→ FS -------------→ TTY * ↖______________↙↖_______________/ * [recv msg] SYSCALL_RET SYSCALL_RET * *---------------------------------------------------------------------- * * printl: variant-parameter-version printx * * calls vsprintf, then printx (trap into kernel directly) * *---------------------------------------------------------------------- * * printx: low level print without using IPC * * trap directly * USER_PROC -- -- -- -- -- --> KERNEL * * *---------------------------------------------------------------------- */ /* printf.c */ PUBLIC int printf(const char *fmt, ...); PUBLIC int printl(const char *fmt, ...); /* vsprintf.c */ PUBLIC int vsprintf(char *buf, const char *fmt, va_list args); PUBLIC int sprintf(char *buf, const char *fmt, ...); /*--------*/ /* 庫函數 */ /*--------*/ #ifdef ENABLE_DISK_LOG #define SYSLOG syslog #endif /* lib/open.c */ PUBLIC int open (const char *pathname, int flags); /* lib/close.c */ PUBLIC int close (int fd); /* lib/read.c */ PUBLIC int read (int fd, void *buf, int count); /* lib/write.c */ PUBLIC int write (int fd, const void *buf, int count); /* lib/unlink.c */ PUBLIC int unlink (const char *pathname); /* lib/getpid.c */ PUBLIC int getpid (); /* lib/fork.c */ PUBLIC int fork (); /* lib/exit.c */ PUBLIC void exit (int status); /* lib/wait.c */ PUBLIC int wait (int * status); /* lib/syslog.c */ PUBLIC int syslog (const char *fmt, ...);
include/type.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ type.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_TYPE_H_ #define _ORANGES_TYPE_H_ /* routine types */ #define PUBLIC /* PUBLIC is the opposite of PRIVATE */ #define PRIVATE static /* PRIVATE x limits the scope of x */ typedef unsigned long long u64; typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; typedef char * va_list; typedef void (*int_handler) (); typedef void (*task_f) (); typedef void (*irq_handler) (int irq); typedef void* system_call; /** * MESSAGE mechanism is borrowed from MINIX */ struct mess1 { int m1i1; int m1i2; int m1i3; int m1i4; }; struct mess2 { void* m2p1; void* m2p2; void* m2p3; void* m2p4; }; struct mess3 { int m3i1; int m3i2; int m3i3; int m3i4; u64 m3l1; u64 m3l2; void* m3p1; void* m3p2; }; typedef struct { int source; int type; union { struct mess1 m1; struct mess2 m2; struct mess3 m3; } u; } MESSAGE; /* i have no idea of where to put this struct, so i put it here */ struct boot_params { int mem_size; /* memory size */ unsigned char * kernel_file; /* addr of kernel file */ }; #endif /* _ORANGES_TYPE_H_ */
kernel/global.c
/*************************************************************************//** ***************************************************************************** * @file global.c * @brief * @author Forrest Y. Yu * @date 2005 ***************************************************************************** *****************************************************************************/ #define GLOBAL_VARIABLES_HERE #include "type.h" #include "stdio.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]; /* 注意下面的 TASK 的順序要與 const.h 中對應 */ PUBLIC struct task task_table[NR_TASKS] = { /* entry stack size task name */ /* ----- ---------- --------- */ {task_tty, STACK_SIZE_TTY, "TTY" }, {task_sys, STACK_SIZE_SYS, "SYS" }, {task_hd, STACK_SIZE_HD, "HD" }, {task_fs, STACK_SIZE_FS, "FS" }, {task_mm, STACK_SIZE_MM, "MM" }}; PUBLIC struct task user_proc_table[NR_NATIVE_PROCS] = { /* entry stack size proc name */ /* ----- ---------- --------- */ {Init, STACK_SIZE_INIT, "INIT" }, {TestA, STACK_SIZE_TESTA, "TestA"}, {TestB, STACK_SIZE_TESTB, "TestB"}, {TestC, STACK_SIZE_TESTC, "TestC"}}; /* 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; /** * 7MB~8MB: buffer for MM */ PUBLIC u8 * mmbuf = (u8*)0x700000; PUBLIC const int MMBUF_SIZE = 0x100000; /** * 8MB~10MB: buffer for log (debug) */ PUBLIC char * logbuf = (char*)0x800000; PUBLIC const int LOGBUF_SIZE = 0x100000; PUBLIC char * logdiskbuf = (char*)0x900000; PUBLIC const int LOGDISKBUF_SIZE = 0x100000;
kernel/hd.c
/*************************************************************************//** ***************************************************************************** * @file hd.c * @brief Hard disk (winchester) driver. * The `device nr' in this file means minor device nr. * @author Forrest Y. Yu * @date 2005~2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "stdio.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_open (int device); PRIVATE void hd_close (int device); PRIVATE void hd_rdwt (MESSAGE * p); PRIVATE void hd_ioctl (MESSAGE * p); PRIVATE void hd_cmd_out (struct hd_cmd* cmd); PRIVATE void get_part_table (int drive, int sect_nr, struct part_ent * entry); PRIVATE void partition (int device, int style); PRIVATE void print_hdinfo (struct hd_info * hdi); 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]; PRIVATE struct hd_info hd_info[1]; #define DRV_OF_DEV(dev) (dev <= MAX_PRIM ? \ dev / NR_PRIM_PER_DRIVE : \ (dev - MINOR_hd1a) / NR_SUB_PER_DRIVE) /***************************************************************************** * 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_open(msg.DEVICE); break; case DEV_CLOSE: hd_close(msg.DEVICE); break; case DEV_READ: case DEV_WRITE: hd_rdwt(&msg); break; case DEV_IOCTL: hd_ioctl(&msg); 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() { int i; /* Get the number of drives from the BIOS data area */ u8 * pNrDrives = (u8*)(0x475); printl("{HD} NrDrives:%d.\n", *pNrDrives); assert(*pNrDrives); put_irq_handler(AT_WINI_IRQ, hd_handler); enable_irq(CASCADE_IRQ); enable_irq(AT_WINI_IRQ); for (i = 0; i < (sizeof(hd_info) / sizeof(hd_info[0])); i++) memset(&hd_info[i], 0, sizeof(hd_info[0])); hd_info[0].open_cnt = 0; } /***************************************************************************** * hd_open *****************************************************************************/ /** * <Ring 1> This routine handles DEV_OPEN message. It identify the drive * of the given device and read the partition table of the drive if it * has not been read. * * @param device The device to be opened. *****************************************************************************/ PRIVATE void hd_open(int device) { int drive = DRV_OF_DEV(device); assert(drive == 0); /* only one drive */ hd_identify(drive); if (hd_info[drive].open_cnt++ == 0) { partition(drive * (NR_PART_PER_DRIVE + 1), P_PRIMARY); print_hdinfo(&hd_info[drive]); } } /***************************************************************************** * hd_close *****************************************************************************/ /** * <Ring 1> This routine handles DEV_CLOSE message. * * @param device The device to be opened. *****************************************************************************/ PRIVATE void hd_close(int device) { int drive = DRV_OF_DEV(device); assert(drive == 0); /* only one drive */ hd_info[drive].open_cnt--; } /***************************************************************************** * hd_rdwt *****************************************************************************/ /** * <Ring 1> This routine handles DEV_READ and DEV_WRITE message. * * @param p Message ptr. *****************************************************************************/ PRIVATE void hd_rdwt(MESSAGE * p) { int drive = DRV_OF_DEV(p->DEVICE); u64 pos = p->POSITION; assert((pos >> SECTOR_SIZE_SHIFT) < (1 << 31)); /** * We only allow to R/W from a SECTOR boundary: */ assert((pos & 0x1FF) == 0); u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); /* pos / SECTOR_SIZE */ int logidx = (p->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += p->DEVICE < MAX_PRIM ? hd_info[drive].primary[p->DEVICE].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p->CNT; void * la = (void*)va2la(p->PROC_NR, p->BUF); while (bytes_left) { int bytes = min(SECTOR_SIZE, bytes_left); if (p->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) panic("hd writing error."); port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } } /***************************************************************************** * hd_ioctl *****************************************************************************/ /** * <Ring 1> This routine handles the DEV_IOCTL message. * * @param p Ptr to the MESSAGE. *****************************************************************************/ PRIVATE void hd_ioctl(MESSAGE * p) { int device = p->DEVICE; int drive = DRV_OF_DEV(device); struct hd_info * hdi = &hd_info[drive]; if (p->REQUEST == DIOCTL_GET_GEO) { void * dst = va2la(p->PROC_NR, p->BUF); void * src = va2la(TASK_HD, device < MAX_PRIM ? &hdi->primary[device] : &hdi->logical[(device - MINOR_hd1a) % NR_SUB_PER_DRIVE]); phys_copy(dst, src, sizeof(struct part_info)); } else { assert(0); } } /***************************************************************************** * get_part_table *****************************************************************************/ /** * <Ring 1> Get a partition table of a drive. * * @param drive Drive nr (0 for the 1st disk, 1 for the 2nd, ...)n * @param sect_nr The sector at which the partition table is located. * @param entry Ptr to part_ent struct. *****************************************************************************/ PRIVATE void get_part_table(int drive, int sect_nr, struct part_ent * entry) { struct hd_cmd cmd; cmd.features = 0; cmd.count = 1; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, /* LBA mode*/ drive, (sect_nr >> 24) & 0xF); cmd.command = ATA_READ; hd_cmd_out(&cmd); interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); memcpy(entry, hdbuf + PARTITION_TABLE_OFFSET, sizeof(struct part_ent) * NR_PART_PER_DRIVE); } /***************************************************************************** * partition *****************************************************************************/ /** * <Ring 1> This routine is called when a device is opened. It reads the * partition table(s) and fills the hd_info struct. * * @param device Device nr. * @param style P_PRIMARY or P_EXTENDED. *****************************************************************************/ PRIVATE void partition(int device, int style) { int i; int drive = DRV_OF_DEV(device); struct hd_info * hdi = &hd_info[drive]; struct part_ent part_tbl[NR_SUB_PER_DRIVE]; if (style == P_PRIMARY) { get_part_table(drive, drive, part_tbl); int nr_prim_parts = 0; for (i = 0; i < NR_PART_PER_DRIVE; i++) { /* 0~3 */ if (part_tbl[i].sys_id == NO_PART) continue; nr_prim_parts++; int dev_nr = i + 1; /* 1~4 */ hdi->primary[dev_nr].base = part_tbl[i].start_sect; hdi->primary[dev_nr].size = part_tbl[i].nr_sects; if (part_tbl[i].sys_id == EXT_PART) /* extended */ partition(device + dev_nr, P_EXTENDED); } assert(nr_prim_parts != 0); } else if (style == P_EXTENDED) { int j = device % NR_PRIM_PER_DRIVE; /* 1~4 */ int ext_start_sect = hdi->primary[j].base; int s = ext_start_sect; int nr_1st_sub = (j - 1) * NR_SUB_PER_PART; /* 0/16/32/48 */ for (i = 0; i < NR_SUB_PER_PART; i++) { int dev_nr = nr_1st_sub + i;/* 0~15/16~31/32~47/48~63 */ get_part_table(drive, s, part_tbl); hdi->logical[dev_nr].base = s + part_tbl[0].start_sect; hdi->logical[dev_nr].size = part_tbl[0].nr_sects; s = ext_start_sect + part_tbl[1].start_sect; /* no more logical partitions in this extended partition */ if (part_tbl[1].sys_id == NO_PART) break; } } else { assert(0); } } /***************************************************************************** * print_hdinfo *****************************************************************************/ /** * <Ring 1> Print disk info. * * @param hdi Ptr to struct hd_info. *****************************************************************************/ PRIVATE void print_hdinfo(struct hd_info * hdi) { int i; for (i = 0; i < NR_PART_PER_DRIVE + 1; i++) { printl("{HD} %sPART_%d: base %d(0x%x), size %d(0x%x) (in sector)\n", i == 0 ? " " : " ", i, hdi->primary[i].base, hdi->primary[i].base, hdi->primary[i].size, hdi->primary[i].size); } for (i = 0; i < NR_SUB_PER_DRIVE; i++) { if (hdi->logical[i].size == 0) continue; printl("{HD} " "%d: base %d(0x%x), size %d(0x%x) (in sector)\n", i, hdi->logical[i].base, hdi->logical[i].base, hdi->logical[i].size, hdi->logical[i].size); } } /***************************************************************************** * 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); u16* hdinfo = (u16*)hdbuf; hd_info[drive].primary[0].base = 0; /* Total Nr of User Addressable Sectors */ hd_info[drive].primary[0].size = ((int)hdinfo[61] << 16) + hdinfo[60]; } /***************************************************************************** * 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("{HD} %s: %s\n", iinfo[k].desc, s); } int capabilities = hdinfo[49]; printl("{HD} LBA supported: %s\n", (capabilities & 0x0200) ? "Yes" : "No"); int cmd_set_supported = hdinfo[83]; printl("{HD} LBA48 supported: %s\n", (cmd_set_supported & 0x0400) ? "Yes" : "No"); int sectors = ((int)hdinfo[61] << 16) + hdinfo[60]; printl("{HD} 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/main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "stdio.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 *****************************************************************************/ /** * jmp from kernel.asm::_start. * *****************************************************************************/ PUBLIC int kernel_main() { disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); int i, j, eflags, prio; u8 rpl; u8 priv; /* privilege */ struct task * t; struct proc * p = proc_table; char * stk = task_stack + STACK_SIZE_TOTAL; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++,t++) { if (i >= NR_TASKS + NR_NATIVE_PROCS) { p->p_flags = FREE_SLOT; continue; } if (i < NR_TASKS) { /* TASK */ t = task_table + i; priv = PRIVILEGE_TASK; rpl = RPL_TASK; eflags = 0x1202;/* IF=1, IOPL=1, bit 2 is always 1 */ prio = 15; } else { /* USER PROC */ t = user_proc_table + (i - NR_TASKS); priv = PRIVILEGE_USER; rpl = RPL_USER; eflags = 0x202; /* IF=1, bit 2 is always 1 */ prio = 5; } strcpy(p->name, t->name); /* name of the process */ p->p_parent = NO_TASK; if (strcmp(t->name, "INIT") != 0) { p->ldts[INDEX_LDT_C] = gdt[SELECTOR_KERNEL_CS >> 3]; p->ldts[INDEX_LDT_RW] = gdt[SELECTOR_KERNEL_DS >> 3]; /* change the DPLs */ p->ldts[INDEX_LDT_C].attr1 = DA_C | priv << 5; p->ldts[INDEX_LDT_RW].attr1 = DA_DRW | priv << 5; } else { /* INIT process */ unsigned int k_base; unsigned int k_limit; int ret = get_kernel_map(&k_base, &k_limit); assert(ret == 0); init_desc(&p->ldts[INDEX_LDT_C], 0, /* bytes before the entry point * are useless (wasted) for the * INIT process, doesn't matter */ (k_base + k_limit) >> LIMIT_4K_SHIFT, DA_32 | DA_LIMIT_4K | DA_C | priv << 5); init_desc(&p->ldts[INDEX_LDT_RW], 0, /* bytes before the entry point * are useless (wasted) for the * INIT process, doesn't matter */ (k_base + k_limit) >> LIMIT_4K_SHIFT, DA_32 | DA_LIMIT_4K | DA_DRW | priv << 5); } p->regs.cs = INDEX_LDT_C << 3 | SA_TIL | rpl; p->regs.ds = p->regs.es = p->regs.fs = p->regs.ss = INDEX_LDT_RW << 3 | SA_TIL | rpl; p->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl; p->regs.eip = (u32)t->initial_eip; p->regs.esp = (u32)stk; p->regs.eflags = eflags; p->ticks = p->priority = prio; p->p_flags = 0; p->p_msg = 0; p->p_recvfrom = NO_TASK; p->p_sendto = NO_TASK; p->has_int_msg = 0; p->q_sending = 0; p->next_sending = 0; for (j = 0; j < NR_FILES; j++) p->filp[j] = 0; stk -= t->stacksize; } 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; } /***************************************************************************** * Init *****************************************************************************/ /** * The hen. * *****************************************************************************/ void Init() { int fd_stdin = open("/dev_tty0", O_RDWR); assert(fd_stdin == 0); int fd_stdout = open("/dev_tty0", O_RDWR); assert(fd_stdout == 1); printf("Init() is running ...\n"); int pid = fork(); if (pid != 0) { /* parent process */ printf("parent is running, child pid:%d\n", pid); spin("parent"); } else { /* child process */ printf("child is running, pid:%d\n", getpid()); spin("child"); } } /*======================================================================* TestA *======================================================================*/ void TestA() { for(;;); } /*======================================================================* TestB *======================================================================*/ void TestB() { for(;;); } /*======================================================================* TestB *======================================================================*/ void TestC() { for(;;); } /***************************************************************************** * 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 "stdio.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_NATIVE_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"/* , */ ); }
kernel/protect.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ protect.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "stdio.h" #include "const.h" #include "protect.h" #include "fs.h" #include "tty.h" #include "console.h" #include "proc.h" #include "string.h" #include "global.h" #include "proto.h" /* 本文件內函數聲明 */ PRIVATE void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege); /* 中斷處理函數 */ void divide_error(); void single_step_exception(); void nmi(); void breakpoint_exception(); void overflow(); void bounds_check(); void inval_opcode(); void copr_not_available(); void double_fault(); void copr_seg_overrun(); void inval_tss(); void segment_not_present(); void stack_exception(); void general_protection(); void page_fault(); void copr_error(); void hwint00(); void hwint01(); void hwint02(); void hwint03(); void hwint04(); void hwint05(); void hwint06(); void hwint07(); void hwint08(); void hwint09(); void hwint10(); void hwint11(); void hwint12(); void hwint13(); void hwint14(); void hwint15(); /*======================================================================* init_prot *----------------------------------------------------------------------* 初始化 IDT *======================================================================*/ PUBLIC void init_prot() { init_8259A(); /* 全部初始化成中斷門(沒有陷阱門) */ init_idt_desc(INT_VECTOR_DIVIDE, DA_386IGate, divide_error, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_DEBUG, DA_386IGate, single_step_exception, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_NMI, DA_386IGate, nmi, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_BREAKPOINT, DA_386IGate, breakpoint_exception, PRIVILEGE_USER); init_idt_desc(INT_VECTOR_OVERFLOW, DA_386IGate, overflow, PRIVILEGE_USER); init_idt_desc(INT_VECTOR_BOUNDS, DA_386IGate, bounds_check, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_INVAL_OP, DA_386IGate, inval_opcode, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_COPROC_NOT, DA_386IGate, copr_not_available, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_DOUBLE_FAULT, DA_386IGate, double_fault, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_COPROC_SEG, DA_386IGate, copr_seg_overrun, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_INVAL_TSS, DA_386IGate, inval_tss, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_SEG_NOT, DA_386IGate, segment_not_present, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_STACK_FAULT, DA_386IGate, stack_exception, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_PROTECTION, DA_386IGate, general_protection, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_PAGE_FAULT, DA_386IGate, page_fault, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_COPROC_ERR, DA_386IGate, copr_error, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 0, DA_386IGate, hwint00, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 1, DA_386IGate, hwint01, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 2, DA_386IGate, hwint02, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 3, DA_386IGate, hwint03, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 4, DA_386IGate, hwint04, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 5, DA_386IGate, hwint05, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 6, DA_386IGate, hwint06, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 7, DA_386IGate, hwint07, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 0, DA_386IGate, hwint08, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 1, DA_386IGate, hwint09, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 2, DA_386IGate, hwint10, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 3, DA_386IGate, hwint11, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 4, DA_386IGate, hwint12, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 5, DA_386IGate, hwint13, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 6, DA_386IGate, hwint14, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 7, DA_386IGate, hwint15, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_SYS_CALL, DA_386IGate, sys_call, PRIVILEGE_USER); /* Fill the TSS descriptor in GDT */ memset(&tss, 0, sizeof(tss)); tss.ss0 = SELECTOR_KERNEL_DS; init_desc(&gdt[INDEX_TSS], makelinear(SELECTOR_KERNEL_DS, &tss), sizeof(tss) - 1, DA_386TSS); tss.iobase = sizeof(tss); /* No IO permission bitmap */ /* Fill the LDT descriptors of each proc in GDT */ int i; for (i = 0; i < NR_TASKS + NR_PROCS; i++) { memset(&proc_table[i], 0, sizeof(struct proc)); proc_table[i].ldt_sel = SELECTOR_LDT_FIRST + (i << 3); assert(INDEX_LDT_FIRST + i < GDT_SIZE); init_desc(&gdt[INDEX_LDT_FIRST + i], makelinear(SELECTOR_KERNEL_DS, proc_table[i].ldts), LDT_SIZE * sizeof(struct descriptor) - 1, DA_LDT); } } /*======================================================================* init_idt_desc *----------------------------------------------------------------------* 初始化 386 中斷門 *======================================================================*/ PUBLIC void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege) { struct gate * p_gate = &idt[vector]; u32 base = (u32)handler; p_gate->offset_low = base & 0xFFFF; p_gate->selector = SELECTOR_KERNEL_CS; p_gate->dcount = 0; p_gate->attr = desc_type | (privilege << 5); p_gate->offset_high = (base >> 16) & 0xFFFF; } /*======================================================================* seg2phys *----------------------------------------------------------------------* 由段名求絕對地址 *======================================================================*/ PUBLIC u32 seg2linear(u16 seg) { struct descriptor* p_dest = &gdt[seg >> 3]; return (p_dest->base_high << 24) | (p_dest->base_mid << 16) | (p_dest->base_low); } /*======================================================================* init_descriptor *----------------------------------------------------------------------* 初始化段描述符 *======================================================================*/ PUBLIC void init_desc(struct descriptor * p_desc, u32 base, u32 limit, u16 attribute) { p_desc->limit_low = limit & 0x0FFFF; /* 段界限 1 (2 字節) */ p_desc->base_low = base & 0x0FFFF; /* 段基址 1 (2 字節) */ p_desc->base_mid = (base >> 16) & 0x0FF; /* 段基址 2 (1 字節) */ p_desc->attr1 = attribute & 0xFF; /* 屬性 1 */ p_desc->limit_high_attr2= ((limit >> 16) & 0x0F) | ((attribute >> 8) & 0xF0); /* 段界限 2 + 屬性 2 */ p_desc->base_high = (base >> 24) & 0x0FF; /* 段基址 3 (1 字節) */ } /*======================================================================* exception_handler *----------------------------------------------------------------------* 異常處理 *======================================================================*/ PUBLIC void exception_handler(int vec_no, int err_code, int eip, int cs, int eflags) { int i; int text_color = 0x74; /* 灰底紅字 */ char err_description[][64] = { "#DE Divide Error", "#DB RESERVED", "— NMI Interrupt", "#BP Breakpoint", "#OF Overflow", "#BR BOUND Range Exceeded", "#UD Invalid Opcode (Undefined Opcode)", "#NM Device Not Available (No Math Coprocessor)", "#DF Double Fault", " Coprocessor Segment Overrun (reserved)", "#TS Invalid TSS", "#NP Segment Not Present", "#SS Stack-Segment Fault", "#GP General Protection", "#PF Page Fault", "— (Intel reserved. Do not use.)", "#MF x87 FPU Floating-Point Error (Math Fault)", "#AC Alignment Check", "#MC Machine Check", "#XF SIMD Floating-Point Exception" }; /* 通過打印空格的方式清空屏幕的前五行,並把 disp_pos 清零 */ disp_pos = 0; for(i=0;i<80*5;i++){ disp_str(" "); } disp_pos = 0; disp_color_str("Exception! --> ", text_color); disp_color_str(err_description[vec_no], text_color); disp_color_str("\n\n", text_color); disp_color_str("EFLAGS:", text_color); disp_int(eflags); disp_color_str("CS:", text_color); disp_int(cs); disp_color_str("EIP:", text_color); disp_int(eip); if(err_code != 0xFFFFFFFF){ disp_color_str("Error code:", text_color); disp_int(err_code); } }
kernel/systask.c
/*************************************************************************//** ***************************************************************************** * @file systask.c * @brief * @author Forrest Y. Yu * @date 2007 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "stdio.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 "keyboard.h" #include "proto.h" PRIVATE int read_register(char reg_addr); PRIVATE u32 get_rtc_time(struct time *t); /***************************************************************************** * task_sys *****************************************************************************/ /** * <Ring 1> The main loop of TASK SYS. * *****************************************************************************/ PUBLIC void task_sys() { MESSAGE msg; struct time t; while (1) { send_recv(RECEIVE, ANY, &msg); int src = msg.source; switch (msg.type) { case GET_TICKS: msg.RETVAL = ticks; send_recv(SEND, src, &msg); break; case GET_PID: msg.type = SYSCALL_RET; msg.PID = src; send_recv(SEND, src, &msg); break; case GET_RTC_TIME: msg.type = SYSCALL_RET; get_rtc_time(&t); phys_copy(va2la(src, msg.BUF), va2la(TASK_SYS, &t), sizeof(t)); send_recv(SEND, src, &msg); break; default: panic("unknown msg type"); break; } } } /***************************************************************************** * get_rtc_time *****************************************************************************/ /** * Get RTC time from the CMOS * * @return Zero. *****************************************************************************/ PRIVATE u32 get_rtc_time(struct time *t) { t->year = read_register(YEAR); t->month = read_register(MONTH); t->day = read_register(DAY); t->hour = read_register(HOUR); t->minute = read_register(MINUTE); t->second = read_register(SECOND); if ((read_register(CLK_STATUS) & 0x04) == 0) { /* Convert BCD to binary (default RTC mode) */ t->year = BCD_TO_DEC(t->year); t->month = BCD_TO_DEC(t->month); t->day = BCD_TO_DEC(t->day); t->hour = BCD_TO_DEC(t->hour); t->minute = BCD_TO_DEC(t->minute); t->second = BCD_TO_DEC(t->second); } t->year += 2000; return 0; } /***************************************************************************** * read_register *****************************************************************************/ /** * Read register from CMOS. * * @param reg_addr * * @return *****************************************************************************/ PRIVATE int read_register(char reg_addr) { out_byte(CLK_ELE, reg_addr); return in_byte(CLK_IO); }
lib/klib.c
/*************************************************************************//** ***************************************************************************** * @file klib.c * @brief * @author Forrest Y. Yu * @date 2005 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "config.h" #include "stdio.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 "elf.h" /***************************************************************************** * get_boot_params *****************************************************************************/ /** * <Ring 0~1> The boot parameters have been saved by LOADER. * We just read them out. * * @param pbp Ptr to the boot params structure *****************************************************************************/ PUBLIC void get_boot_params(struct boot_params * pbp) { /** * Boot params should have been saved at BOOT_PARAM_ADDR. */ int * p = (int*)BOOT_PARAM_ADDR; assert(p[BI_MAG] == BOOT_PARAM_MAGIC); pbp->mem_size = p[BI_MEM_SIZE]; pbp->kernel_file = (unsigned char *)(p[BI_KERNEL_FILE]); /** * the kernel file should be a ELF executable, * check it's magic number */ assert(memcmp(pbp->kernel_file, ELFMAG, SELFMAG) == 0); } /***************************************************************************** * get_kernel_map *****************************************************************************/ /** * <Ring 0~1> Parse the kernel file, get the memory range of the kernel image. * * - The meaning of `base': base => first_valid_byte * - The meaning of `limit': base + limit => last_valid_byte * * @param b Memory base of kernel. * @param l Memory limit of kernel. *****************************************************************************/ PUBLIC int get_kernel_map(unsigned int * b, unsigned int * l) { struct boot_params bp; get_boot_params(&bp); Elf32_Ehdr* elf_header = (Elf32_Ehdr*)(bp.kernel_file); /* the kernel file should be in ELF format */ if (memcmp(elf_header->e_ident, ELFMAG, SELFMAG) != 0) return -1; *b = ~0; unsigned int t = 0; int i; for (i = 0; i < elf_header->e_shnum; i++) { Elf32_Shdr* section_header = (Elf32_Shdr*)(bp.kernel_file + elf_header->e_shoff + i * elf_header->e_shentsize); if (section_header->sh_flags & SHF_ALLOC) { int bottom = section_header->sh_addr; int top = section_header->sh_addr + section_header->sh_size; if (*b > bottom) *b = bottom; if (t < top) t = top; } } assert(*b < t); *l = t - *b - 1; return 0; } /*======================================================================* itoa *======================================================================*/ PUBLIC char * itoa(char * str, int num)/* 數字前面的 0 不被顯示出來, 比如 0000B800 被顯示成 B800 */ { char * p = str; char ch; int i; int flag = 0; *p++ = '0'; *p++ = 'x'; if(num == 0){ *p++ = '0'; } else{ for(i=28;i>=0;i-=4){ ch = (num >> i) & 0xF; if(flag || (ch > 0)){ flag = 1; ch += '0'; if(ch > '9'){ ch += 7; } *p++ = ch; } } } *p = 0; return str; } /*======================================================================* disp_int *======================================================================*/ PUBLIC void disp_int(int input) { char output[16]; itoa(output, input); disp_str(output); } /*======================================================================* delay *======================================================================*/ PUBLIC void delay(int time) { int i, j, k; for(k=0;k<time;k++){ /*for(i=0;i<10000;i++){ for Virtual PC */ for(i=0;i<10;i++){/* for Bochs */ for(j=0;j<10000;j++){} } } }
lib/syslog.c
/*************************************************************************//** ***************************************************************************** * @file syslog.c * @brief * @author Forrest Y. Yu * @date Thu Nov 20 17:02:42 2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "stdio.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" /***************************************************************************** * syslog *****************************************************************************/ /** * Write log directly to the disk by sending message to FS. * * @param fmt The format string. * * @return How many chars have been printed. *****************************************************************************/ PUBLIC int syslog(const char *fmt, ...) { int i; char buf[STR_DEFAULT_LEN]; va_list arg = (va_list)((char*)(&fmt) + 4); /** * 4: size of `fmt' in * the stack */ i = vsprintf(buf, fmt, arg); assert(strlen(buf) == i); return disklog(buf); }
mm/forkexit.c
/*************************************************************************//** ***************************************************************************** * @file forkexit.c * @brief * @author Forrest Y. Yu * @date Tue May 6 00:37:15 2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "stdio.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 "keyboard.h" #include "proto.h" PRIVATE void cleanup(struct proc * proc); /***************************************************************************** * do_fork *****************************************************************************/ /** * Perform the fork() syscall. * * @return Zero if success, otherwise -1. *****************************************************************************/ PUBLIC int do_fork() { /* find a free slot in proc_table */ struct proc* p = proc_table; int i; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++) if (p->p_flags == FREE_SLOT) break; int child_pid = i; assert(p == &proc_table[child_pid]); assert(child_pid >= NR_TASKS + NR_NATIVE_PROCS); if (i == NR_TASKS + NR_PROCS) /* no free slot */ return -1; assert(i < NR_TASKS + NR_PROCS); /* duplicate the process table */ int pid = mm_msg.source; u16 child_ldt_sel = p->ldt_sel; *p = proc_table[pid]; p->ldt_sel = child_ldt_sel; p->p_parent = pid; sprintf(p->name, "%s_%d", proc_table[pid].name, child_pid); /* duplicate the process: T, D & S */ struct descriptor * ppd; /* Text segment */ ppd = &proc_table[pid].ldts[INDEX_LDT_C]; /* base of T-seg, in bytes */ int caller_T_base = reassembly(ppd->base_high, 24, ppd->base_mid, 16, ppd->base_low); /* limit of T-seg, in 1 or 4096 bytes, depending on the G bit of descriptor */ int caller_T_limit = reassembly(0, 0, (ppd->limit_high_attr2 & 0xF), 16, ppd->limit_low); /* size of T-seg, in bytes */ int caller_T_size = ((caller_T_limit + 1) * ((ppd->limit_high_attr2 & (DA_LIMIT_4K >> 8)) ? 4096 : 1)); /* Data & Stack segments */ ppd = &proc_table[pid].ldts[INDEX_LDT_RW]; /* base of D&S-seg, in bytes */ int caller_D_S_base = reassembly(ppd->base_high, 24, ppd->base_mid, 16, ppd->base_low); /* limit of D&S-seg, in 1 or 4096 bytes, depending on the G bit of descriptor */ int caller_D_S_limit = reassembly((ppd->limit_high_attr2 & 0xF), 16, 0, 0, ppd->limit_low); /* size of D&S-seg, in bytes */ int caller_D_S_size = ((caller_T_limit + 1) * ((ppd->limit_high_attr2 & (DA_LIMIT_4K >> 8)) ? 4096 : 1)); /* we don't separate T, D & S segments, so we have: */ assert((caller_T_base == caller_D_S_base ) && (caller_T_limit == caller_D_S_limit) && (caller_T_size == caller_D_S_size )); /* base of child proc, T, D & S segments share the same space, so we allocate memory just once */ int child_base = alloc_mem(child_pid, caller_T_size); /* int child_limit = caller_T_limit; */ printl("{MM} 0x%x <- 0x%x (0x%x bytes)\n", child_base, caller_T_base, caller_T_size); /* child is a copy of the parent */ phys_copy((void*)child_base, (void*)caller_T_base, caller_T_size); /* child's LDT */ init_desc(&p->ldts[INDEX_LDT_C], child_base, (PROC_IMAGE_SIZE_DEFAULT - 1) >> LIMIT_4K_SHIFT, DA_LIMIT_4K | DA_32 | DA_C | PRIVILEGE_USER << 5); init_desc(&p->ldts[INDEX_LDT_RW], child_base, (PROC_IMAGE_SIZE_DEFAULT - 1) >> LIMIT_4K_SHIFT, DA_LIMIT_4K | DA_32 | DA_DRW | PRIVILEGE_USER << 5); /* tell FS, see fs_fork() */ MESSAGE msg2fs; msg2fs.type = FORK; msg2fs.PID = child_pid; send_recv(BOTH, TASK_FS, &msg2fs); /* child PID will be returned to the parent proc */ mm_msg.PID = child_pid; /* birth of the child */ MESSAGE m; m.type = SYSCALL_RET; m.RETVAL = 0; m.PID = 0; send_recv(SEND, child_pid, &m); return 0; } /***************************************************************************** * do_exit *****************************************************************************/ /** * Perform the exit() syscall. * * If proc A calls exit(), then MM will do the following in this routine: * <1> inform FS so that the fd-related things will be cleaned up * <2> tell TASK_SYS (TODO) * <3> free A's memory * <4> set A.exit_status, which is for the parent * <5> depends on parent's status. if parent (say P) is: * (1) WAITING * - clean P's WAITING bit, and * - send P a message to unblock it * {P's wait() call is done} * - release A's proc_table[] slot * {A's exit() call is done} * (2) not WAITING * - set A's HANGING bit * {things will be done at do_wait()::comment::<1>} * <6> iterate proc_table[], if proc B is found as A's child, then: * (1) make INIT the new parent of B, and * (2) if INIT is WAITING and B is HANGING, then: * - clean INIT's WAITING bit, and * - send INIT a message to unblock it * {INIT's wait() call is done} * - release B's proc_table[] slot * {B's exit() call is done} * else * if INIT is WAITING but B is not HANGING, then * - B will call exit() and things will be done at * do_exit()::comment::<5>::(1) * if B is HANGING but INIT is not WAITING, then * - INIT will call wait() and things will be doen at * do_wait()::comment::<1> * * TERMs: * - HANGING: everything except the proc_table entry has been cleaned up. * - WAITING: a proc has at least one child, and it is waiting for the * child(ren) to exit() * - zombie: say P has a child A, A will become a zombie if * - A exit(), and * - P does not wait(), neither does it exit(). that is to say, P just * keeps running without terminating itself or its child * - @see Linux manpage for more details: * - man 2 exit * - man 3 exit * - man 2 wait * * @param status Exiting status for parent. * *****************************************************************************/ PUBLIC void do_exit(int status) { int i; int pid = mm_msg.source; /* PID of caller */ int parent_pid = proc_table[pid].p_parent; struct proc * p = &proc_table[pid]; /* struct proc * p_parent = &proc_table[parent_pid]; */ /* tell FS, see fs_exit() */ MESSAGE msg2fs; msg2fs.type = EXIT; msg2fs.PID = pid; send_recv(BOTH, TASK_FS, &msg2fs); /** * @todo should also send a message to TASK_SYS to do some cleanup work. * e.g. if the proc is killed by another proc, TASK_SYS should * check if the proc happens to be SENDING a message, if so, * the proc should be removed from the sending queue. * @see MINIX::src/kernel/system.c:do_xit() */ free_mem(pid); p->exit_status = status; if (proc_table[parent_pid].p_flags & WAITING) { /* parent is waiting */ printl("{MM} ((--do_exit():: %s (%d) is WAITING, %s (%d) will be cleaned up.--))\n", proc_table[parent_pid].name, parent_pid, p->name, pid); /* dump_fd_graph("((--do_exit():: %s (%d) is WAITING, %s (%d) will be cleaned up.--))", */ /* proc_table[parent_pid].name, parent_pid, */ /* p->name, pid); */ /* assert(proc_table[parent_pid].p_flags & RECEIVING); */ printl("{MM} ((--do_exit():1: proc_table[parent_pid].p_flags: 0x%x--))\n", proc_table[parent_pid].p_flags); /* dump_fd_graph("((--do_exit():1: proc_table[parent_pid].p_flags: 0x%x--))", */ /* proc_table[parent_pid].p_flags); */ proc_table[parent_pid].p_flags &= ~WAITING; cleanup(&proc_table[pid]); } else { /* parent is not waiting */ printl("{MM} ((--do_exit():: %s (%d) is not WAITING, %s (%d) will be HANGING--))\n", proc_table[parent_pid].name, parent_pid, p->name, pid); /* dump_fd_graph("((--do_exit():: %s (%d) is not WAITING, %s (%d) will be HANGING--))", */ /* proc_table[parent_pid].name, parent_pid, */ /* p->name, pid); */ proc_table[pid].p_flags |= HANGING; } /* if the proc has any child, make INIT the new parent */ for (i = 0; i < NR_TASKS + NR_PROCS; i++) { if (proc_table[i].p_parent == pid) { /* is a child */ proc_table[i].p_parent = INIT; /* FIXME: make sure INIT always waits */ printl("{MM} %s (%d) exit(), so %s (%d) is INIT's child now\n", p->name, pid, proc_table[i].name, i); /* dump_fd_graph("%s (%d) exit(), so %s (%d) is INIT's child now", */ /* p->name, pid, proc_table[i].name, i); */ printl("{MM} ((--do_exit():2: proc_table[INIT].p_flags: 0x%x--))\n", proc_table[INIT].p_flags); /* dump_fd_graph("((--do_exit():2: proc_table[INIT].p_flags: 0x%x--))", */ /* proc_table[INIT].p_flags); */ if ((proc_table[INIT].p_flags & WAITING) && (proc_table[i].p_flags & HANGING)) { /* assert(proc_table[INIT].p_flags & RECEIVING); */ proc_table[INIT].p_flags &= ~WAITING; cleanup(&proc_table[i]); assert(0); } else { /* assert(0); */ } } } } /***************************************************************************** * cleanup *****************************************************************************/ /** * Do the last jobs to clean up a proc thoroughly: * - Send proc's parent a message to unblock it, and * - release proc's proc_table[] entry * * @param proc Process to clean up. *****************************************************************************/ PRIVATE void cleanup(struct proc * proc) { MESSAGE msg2parent; msg2parent.type = SYSCALL_RET; msg2parent.PID = proc2pid(proc); msg2parent.STATUS = proc->exit_status; send_recv(SEND, proc->p_parent, &msg2parent); proc->p_flags = FREE_SLOT; printl("{MM} ((--cleanup():: %s (%d) has been cleaned up.--))\n", proc->name, proc2pid(proc)); /* dump_fd_graph("((--cleanup():: %s (%d) has been cleaned up.--))", proc->name, proc2pid(proc)); */ } /***************************************************************************** * do_wait *****************************************************************************/ /** * Perform the wait() syscall. * * If proc P calls wait(), then MM will do the following in this routine: * <1> iterate proc_table[], * if proc A is found as P's child and it is HANGING * - reply to P (cleanup() will send P a messageto unblock it) * {P's wait() call is done} * - release A's proc_table[] entry * {A's exit() call is done} * - return (MM will go on with the next message loop) * <2> if no child of P is HANGING * - set P's WAITING bit * {things will be done at do_exit()::comment::<5>::(1)} * <3> if P has no child at all * - reply to P with error * {P's wait() call is done} * <4> return (MM will go on with the next message loop) * *****************************************************************************/ PUBLIC void do_wait() { printl("{MM} ((--do_wait()--))"); /* dump_fd_graph("((--do_wait()--))"); */ int pid = mm_msg.source; int i; int children = 0; struct proc* p_proc = proc_table; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) { if (p_proc->p_parent == pid) { children++; if (p_proc->p_flags & HANGING) { printl("{MM} ((--do_wait():: %s (%d) is HANGING, " "so let's clean it up.--))", p_proc->name, i); /* dump_fd_graph("((--do_wait():: %s (%d) is HANGING, " */ /* "so let's clean it up.--))", */ /* p_proc->name, i); */ cleanup(p_proc); return; } } } if (children) { /* has children, but no child is HANGING */ proc_table[pid].p_flags |= WAITING; printl("{MM} ((--do_wait():: %s (%d) is WAITING for child " "to exit().--))\n", proc_table[pid].name, pid); /* dump_fd_graph("((--do_wait():: %s (%d) is WAITING for child " */ /* "to exit().--))", proc_table[pid].name, pid); */ } else { /* no child at all */ printl("{MM} ((--do_wait():: %s (%d) has no child at all.--))\n", proc_table[pid].name, pid); /* dump_fd_graph("((--do_wait():: %s (%d) is has no child at all.--))", */ /* proc_table[pid].name, pid); */ MESSAGE msg; msg.type = SYSCALL_RET; msg.PID = NO_TASK; send_recv(SEND, pid, &msg); } }
mm/main.c
/*************************************************************************//** ***************************************************************************** * @file mm/main.c * @brief Orange'S Memory Management. * @author Forrest Y. Yu * @date Tue May 6 00:33:39 2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "config.h" #include "stdio.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 "keyboard.h" #include "proto.h" PUBLIC void do_fork_test(); PRIVATE void init_mm(); /***************************************************************************** * task_mm *****************************************************************************/ /** * <Ring 1> The main loop of TASK MM. * *****************************************************************************/ PUBLIC void task_mm() { init_mm(); while (1) { send_recv(RECEIVE, ANY, &mm_msg); int src = mm_msg.source; int reply = 1; int msgtype = mm_msg.type; switch (msgtype) { case FORK: mm_msg.RETVAL = do_fork(); break; case EXIT: do_exit(mm_msg.STATUS); reply = 0; break; /* case EXEC: */ /* mm_msg.RETVAL = do_exec(); */ /* break; */ case WAIT: do_wait(); reply = 0; break; default: dump_msg("MM::unknown msg", &mm_msg); assert(0); break; } if (reply) { mm_msg.type = SYSCALL_RET; send_recv(SEND, src, &mm_msg); } } } /***************************************************************************** * init_mm *****************************************************************************/ /** * Do some initialization work. * *****************************************************************************/ PRIVATE void init_mm() { struct boot_params bp; get_boot_params(&bp); memory_size = bp.mem_size; /* print memory size */ printl("{MM} memsize:%dMB\n", memory_size / (1024 * 1024)); } /***************************************************************************** * alloc_mem *****************************************************************************/ /** * Allocate a memory block for a proc. * * @param pid Which proc the memory is for. * @param memsize How many bytes is needed. * * @return The base of the memory just allocated. *****************************************************************************/ PUBLIC int alloc_mem(int pid, int memsize) { assert(pid >= (NR_TASKS + NR_NATIVE_PROCS)); if (memsize > PROC_IMAGE_SIZE_DEFAULT) { panic("unsupported memory request: %d. " "(should be less than %d)", memsize, PROC_IMAGE_SIZE_DEFAULT); } int base = PROCS_BASE + (pid - (NR_TASKS + NR_NATIVE_PROCS)) * PROC_IMAGE_SIZE_DEFAULT; if (base + memsize >= memory_size) panic("memory allocation failed. pid:%d", pid); return base; } /***************************************************************************** * free_mem *****************************************************************************/ /** * Free a memory block. Because a memory block is corresponding with a PID, so * we don't need to really `free' anything. In another word, a memory block is * dedicated to one and only one PID, no matter what proc actually uses this * PID. * * @param pid Whose memory is to be freed. * * @return Zero if success. *****************************************************************************/ PUBLIC int free_mem(int pid) { return 0; }
Makefile
######################### # Makefile for Orange'S # ######################### # Entry point of Orange'S # It must have the same value with 'KernelEntryPointPhyAddr' in load.inc! ENTRYPOINT = 0x1000 # 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/ -I include/sys/ -f elf CFLAGS = -I include/ -I include/sys/ -m32 -c -fno-builtin -fno-stack-protector LDFLAGS = -s -melf_i386 -Ttext $(ENTRYPOINT) -Map krnl.map DASMFLAGS = -D # This Program ORANGESBOOT = boot/boot.bin boot/loader.bin ORANGESKERNEL = kernel.bin OBJS = kernel/kernel.o lib/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\ lib/printf.o lib/vsprintf.o\ lib/kliba.o lib/klib.o lib/string.o lib/misc.o\ lib/open.o lib/read.o lib/write.o lib/close.o lib/unlink.o\ lib/getpid.o lib/syslog.o\ fs/main.o fs/open.o fs/misc.o fs/read_write.o\ lib/fork.o lib/exit.o lib/wait.o\ mm/main.o mm/forkexit.o\ fs/link.o\ fs/disklog.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 $(ASM) $(ASMKFLAGS) -o $@ $< lib/syscall.o : lib/syscall.asm $(ASM) $(ASMKFLAGS) -o $@ $< kernel/start.o: kernel/start.c $(CC) $(CFLAGS) -o $@ $< kernel/main.o: kernel/main.c $(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 $(CC) $(CFLAGS) -o $@ $< kernel/global.o: kernel/global.c $(CC) $(CFLAGS) -o $@ $< kernel/protect.o: kernel/protect.c $(CC) $(CFLAGS) -o $@ $< kernel/proc.o: kernel/proc.c $(CC) $(CFLAGS) -o $@ $< lib/printf.o: lib/printf.c $(CC) $(CFLAGS) -o $@ $< lib/vsprintf.o: lib/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 $(CC) $(CFLAGS) -o $@ $< lib/misc.o: lib/misc.c $(CC) $(CFLAGS) -o $@ $< lib/kliba.o : lib/kliba.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/string.o : lib/string.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/open.o: lib/open.c $(CC) $(CFLAGS) -o $@ $< lib/read.o: lib/read.c $(CC) $(CFLAGS) -o $@ $< lib/write.o: lib/write.c $(CC) $(CFLAGS) -o $@ $< lib/close.o: lib/close.c $(CC) $(CFLAGS) -o $@ $< lib/unlink.o: lib/unlink.c $(CC) $(CFLAGS) -o $@ $< lib/getpid.o: lib/getpid.c $(CC) $(CFLAGS) -o $@ $< lib/fork.o: lib/fork.c $(CC) $(CFLAGS) -o $@ $< lib/exit.o: lib/exit.c $(CC) $(CFLAGS) -o $@ $< lib/wait.o: lib/wait.c $(CC) $(CFLAGS) -o $@ $< mm/main.o: mm/main.c $(CC) $(CFLAGS) -o $@ $< mm/forkexit.o: mm/forkexit.c $(CC) $(CFLAGS) -o $@ $< lib/syslog.o: lib/syslog.c $(CC) $(CFLAGS) -o $@ $< fs/main.o: fs/main.c $(CC) $(CFLAGS) -o $@ $< fs/open.o: fs/open.c $(CC) $(CFLAGS) -o $@ $< fs/read_write.o: fs/read_write.c $(CC) $(CFLAGS) -o $@ $< fs/link.o: fs/link.c $(CC) $(CFLAGS) -o $@ $< fs/disklog.o: fs/disklog.c $(CC) $(CFLAGS) -o $@ $<
boot/loader.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; loader.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ org 0100h jmp LABEL_START ; Start ; 下面是 FAT12 磁碟的頭, 之所以包含它是因為下面用到了磁碟的一些訊息 %include "fat12hdr.inc" %include "load.inc" %include "pm.inc" ; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------ ; 段基址 段界限 , 屬性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 | DA_LIMIT_4K ; 0 ~ 4G LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_32 | DA_LIMIT_4K ; 0 ~ 4G LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW | DA_DPL3 ; 顯示卡記憶體首位址 ; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------ GdtLen equ $ - LABEL_GDT GdtPtr dw GdtLen - 1 ; 段界限 dd LOADER_PHY_ADDR + LABEL_GDT ; 基位址 (讓基位址八字元對齊將起到優化速度之效果,目前懶得改) ; The GDT is not a segment itself; instead, it is a data structure in linear address space. ; The base linear address and limit of the GDT must be loaded into the GDTR register. -- IA-32 Software Developer’s Manual, Vol.3A ; GDT 選擇子 ---------------------------------------------------------------------------------- SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3 ; GDT 選擇子 ---------------------------------------------------------------------------------- BaseOfStack equ 0100h LABEL_START: ; <--- 從這裡開始 ************* mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, BaseOfStack mov dh, 0 ; "Loading " call DispStrRealMode ; 顯示字元串 ; 得到記憶體數 mov ebx, 0 ; ebx = 後續值, 開始時需為 0 mov di, _MemChkBuf ; es:di 指向一個位址範圍描述符結構(Address Range Descriptor Structure) .MemChkLoop: mov eax, 0E820h ; eax = 0000E820h mov ecx, 20 ; ecx = 位址範圍描述符結構的大小 mov edx, 0534D4150h ; edx = 'SMAP' int 15h ; int 15h jc .MemChkFail add di, 20 inc dword [_dwMCRNumber] ; dwMCRNumber = ARDS 的個數 cmp ebx, 0 jne .MemChkLoop jmp .MemChkOK .MemChkFail: mov dword [_dwMCRNumber], 0 .MemChkOK: ; 下面在 A 碟的根目錄尋找 KERNEL.BIN mov word [wSectorNo], SectorNoOfRootDirectory xor ah, ah ; ┓ xor dl, dl ; ┣ 軟體驅動復位 int 13h ; ┛ LABEL_SEARCH_IN_ROOT_DIR_BEGIN: cmp word [wRootDirSizeForLoop], 0 ; ┓ jz LABEL_NO_KERNELBIN ; ┣ 判斷根目錄區是不是已經讀完, 如果讀完表示沒有找到 KERNEL.BIN dec word [wRootDirSizeForLoop] ; ┛ mov ax, KERNEL_FILE_SEG mov es, ax ; es <- KERNEL_FILE_SEG mov bx, KERNEL_FILE_OFF ; bx <- KERNEL_FILE_OFF 於是, es:bx = KERNEL_FILE_SEG:KERNEL_FILE_OFF = KERNEL_FILE_SEG * 10h + KERNEL_FILE_OFF mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 號 mov cl, 1 call ReadSector mov si, KernelFileName ; ds:si -> "KERNEL BIN" mov di, KERNEL_FILE_OFF ; es:di -> KERNEL_FILE_SEG:???? = KERNEL_FILE_SEG*10h+???? cld mov dx, 10h LABEL_SEARCH_FOR_KERNELBIN: cmp dx, 0 ; ┓ jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣ 循環次數控制, 如果已經讀完了一個 Sector, 就跳到下一個 Sector dec dx ; ┛ mov cx, 11 LABEL_CMP_FILENAME: cmp cx, 0 ; ┓ jz LABEL_FILENAME_FOUND ; ┣ 循環次數控制, 如果比較了 11 個字元都相等, 表示找到 dec cx ; ┛ lodsb ; ds:si -> al cmp al, byte [es:di] ; if al == es:di jz LABEL_GO_ON jmp LABEL_DIFFERENT LABEL_GO_ON: inc di jmp LABEL_CMP_FILENAME ; 繼續循環 LABEL_DIFFERENT: and di, 0FFE0h ; else┓ 這時di的值不知道是什麼, di &= e0 為了讓它是 20h 的倍數 add di, 20h ; ┃ mov si, KernelFileName ; ┣ di += 20h 下一個目錄項目 jmp LABEL_SEARCH_FOR_KERNELBIN; ┛ LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR: add word [wSectorNo], 1 jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN LABEL_NO_KERNELBIN: mov dh, 3 ; "No KERNEL." call DispStrRealMode ; 顯示字元串 jmp $ ; 沒有找到 KERNEL.BIN, 死循環在這裡 LABEL_FILENAME_FOUND: ; 找到 KERNEL.BIN 後便來到這裡繼續 mov ax, RootDirSectors and di, 0FFF0h ; di -> 當前項目的開始 push eax mov eax, [es : di + 01Ch] ; ┓ mov dword [dwKernelSize], eax ; ┛保存 KERNEL.BIN 檔案大小 cmp eax, KERNEL_VALID_SPACE ja .1 pop eax jmp .2 .1: mov dh, 4 ; "Too Large" call DispStrRealMode ; 顯示字元串 jmp $ ; KERNEL.BIN 太大,死循環在這裡 .2: add di, 01Ah ; di -> 首 Sector mov cx, word [es:di] push cx ; 保存此 Sector 在 FAT 中的序號 add cx, ax add cx, DeltaSectorNo ; 這時 cl 裡面是 LOADER.BIN 的起始磁區號 (從 0 開始數的序號) mov ax, KERNEL_FILE_SEG mov es, ax ; es <- KERNEL_FILE_SEG mov bx, KERNEL_FILE_OFF ; bx <- KERNEL_FILE_OFF 於是, es:bx = KERNEL_FILE_SEG:KERNEL_FILE_OFF = KERNEL_FILE_SEG * 10h + KERNEL_FILE_OFF mov ax, cx ; ax <- Sector 號 LABEL_GOON_LOADING_FILE: push ax ; ┓ push bx ; ┃ mov ah, 0Eh ; ┃ 每讀一個磁區就在 "Loading " 後面 mov al, '.' ; ┃ 打一個點, 形成這樣的效果: mov bl, 0Fh ; ┃ Loading ...... int 10h ; ┃ pop bx ; ┃ pop ax ; ┛ mov cl, 1 call ReadSector pop ax ; 取出此 Sector 在 FAT 中的序號 call GetFATEntry cmp ax, 0FFFh jz LABEL_FILE_LOADED push ax ; 保存 Sector 在 FAT 中的序號 mov dx, RootDirSectors add ax, dx add ax, DeltaSectorNo add bx, [BPB_BytsPerSec] jc .1 ; 如果 bx 重新變成 0,說明內核大於 64K jmp .2 .1: push ax ; es += 0x1000 ← es 指向下一個段 mov ax, es add ax, 1000h mov es, ax pop ax .2: jmp LABEL_GOON_LOADING_FILE LABEL_FILE_LOADED: call KillMotor ; 關閉軟體驅動馬達 ;;; ;; 取硬碟訊息 ;;; xor eax, eax ;;; mov ah, 08h ; Code for drive parameters ;;; mov dx, 80h ; hard drive ;;; int 0x13 ;;; jb .hderr ; No such drive? ;;; ;; cylinder number ;;; xor ax, ax ; ax <- 0 ;;; mov ah, cl ; ax <- cl ;;; shr ah, 6 ;;; and ah, 3 ; cl bits 7-6: high two bits of maximum cylinder number ;;; mov al, ch ; CH = low eight bits of maximum cylinder number ;;; ;; sector number ;;; and cl, 3Fh ; cl bits 5-0: max sector number (1-origin) ;;; ;; head number ;;; inc dh ; dh = 1 + max head number (0-origin) ;;; mov [_dwNrHead], dh ;;; mov [_dwNrSector], cl ;;; mov [_dwNrCylinder], ax ;;; jmp .hdok ;;; .hderr: ;;; mov dword [_dwNrHead], 0FFFFh ;;; .hdok: ;; 將硬碟引導磁區內容讀入記憶體 0500h 處 xor ax, ax mov es, ax mov ax, 0201h ; AH = 02 ; AL = number of sectors to read (must be nonzero) mov cx, 1 ; CH = low eight bits of cylinder number ; CL = sector number 1-63 (bits 0-5) ; high two bits of cylinder (bits 6-7, hard disk only) mov dx, 80h ; DH = head number ; DL = drive number (bit 7 set for hard disk) mov bx, 500h ; ES:BX -> data buffer int 13h ;; 硬碟操作完畢 mov dh, 2 ; "Ready." call DispStrRealMode ; 顯示字元串 ; 下面準備跳入保護模式 ------------------------------------------- ; 加載 GDTR lgdt [GdtPtr] ; 關中斷 cli ; 打開位址線A20 in al, 92h or al, 00000010b out 92h, al ; 準備切換到保護模式 mov eax, cr0 or eax, 1 mov cr0, eax ; 真正進入保護模式 jmp dword SelectorFlatC:(LOADER_PHY_ADDR+LABEL_PM_START) ;============================================================================ ;變量 ;---------------------------------------------------------------------------- wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的磁區數 wSectorNo dw 0 ; 要讀取的磁區號 bOdd db 0 ; 奇數還是偶數 dwKernelSize dd 0 ; KERNEL.BIN 檔案大小 ;============================================================================ ;字元串 ;---------------------------------------------------------------------------- KernelFileName db "KERNEL BIN", 0 ; KERNEL.BIN 之檔案名 ; 為簡化程式碼, 下面每個字元串的長度均為 MessageLength MessageLength equ 9 LoadMessage: db "Loading " Message1 db " " Message2 db "Ready. " Message3 db "No KERNEL" Message4 db "Too Large" ;============================================================================ ;---------------------------------------------------------------------------- ; 函數名: DispStrRealMode ;---------------------------------------------------------------------------- ; 運行環境: ; 實模式(保護模式下顯示字元串由函數 DispStr 完成) ; 作用: ; 顯示一個字元串, 函數開始時 dh 中應該是字元串序號(0-based) DispStrRealMode: mov ax, MessageLength mul dh add ax, LoadMessage mov bp, ax ; ┓ mov ax, ds ; ┣ ES:BP = 串位址 mov es, ax ; ┛ mov cx, MessageLength ; CX = 串長度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 0007h ; 頁號為0(BH = 0) 黑底白字(BL = 07h) mov dl, 0 add dh, 3 ; 從第 3 行往下顯示 int 10h ; int 10h ret ;---------------------------------------------------------------------------- ; 函數名: ReadSector ;---------------------------------------------------------------------------- ; 作用: ; 從序號(Directory Entry 中的 Sector 號)為 ax 的的 Sector 開始, 將 cl 個 Sector 讀入 es:bx 中 ReadSector: ; ----------------------------------------------------------------------- ; 怎樣由磁區號求磁區在磁碟中的位置 (磁區號 -> 柱面號, 起始磁區, 磁頭號) ; ----------------------------------------------------------------------- ; 設磁區號為 x ; ┌ 柱面號 = y >> 1 ; x ┌ 商 y ┤ ; -------------- => ┤ └ 磁頭號 = y & 1 ; 每磁道磁區數 │ ; └ 余 z => 起始磁區號 = z + 1 push bp mov bp, sp sub esp, 2 ; 辟出兩個字元的堆疊區域保存要讀的磁區數: byte [bp-2] mov byte [bp-2], cl push bx ; 保存 bx mov bl, [BPB_SecPerTrk] ; bl: 除數 div bl ; y 在 al 中, z 在 ah 中 inc ah ; z ++ mov cl, ah ; cl <- 起始磁區號 mov dh, al ; dh <- y shr al, 1 ; y >> 1 (其實是 y/BPB_NumHeads, 這裡BPB_NumHeads=2) mov ch, al ; ch <- 柱面號 and dh, 1 ; dh & 1 = 磁頭號 pop bx ; 恢復 bx ; 至此, "柱面號, 起始磁區, 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^ mov dl, [BS_DrvNum] ; 驅動器號 (0 表示 A 碟) .GoOnReading: mov ah, 2 ; 讀 mov al, byte [bp-2] ; 讀 al 個磁區 int 13h jc .GoOnReading ; 如果讀取錯誤 CF 會被置為 1, 這時就不停地讀, 直到正確為止 add esp, 2 pop bp ret ;---------------------------------------------------------------------------- ; 函數名: GetFATEntry ;---------------------------------------------------------------------------- ; 作用: ; 找到序號為 ax 的 Sector 在 FAT 中的項目, 結果放在 ax 中 ; 需要注意的是, 中間需要讀 FAT 的磁區到 es:bx 處, 所以函數一開始保存了 es 和 bx GetFATEntry: push es push bx push ax mov ax, KERNEL_FILE_SEG ; ┓ sub ax, 0100h ; ┣ 在 KERNEL_FILE_SEG 後面留出 4K 空間用於存放 FAT mov es, ax ; ┛ pop ax mov byte [bOdd], 0 mov bx, 3 mul bx ; dx:ax = ax * 3 mov bx, 2 div bx ; dx:ax / 2 ==> ax <- 商, dx <- 餘數 cmp dx, 0 jz LABEL_EVEN mov byte [bOdd], 1 LABEL_EVEN:;偶數 xor dx, dx ; 現在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面來計算 FATEntry 在哪個磁區中(FAT占用不止一個磁區) mov bx, [BPB_BytsPerSec] div bx ; dx:ax / BPB_BytsPerSec ==> ax <- 商 (FATEntry 所在的磁區相對於 FAT 來說的磁區號) ; dx <- 餘數 (FATEntry 在磁區內的偏移)。 push dx mov bx, 0 ; bx <- 0 於是, es:bx = (KERNEL_FILE_SEG - 100):00 = (KERNEL_FILE_SEG - 100) * 10h add ax, SectorNoOfFAT1 ; 此句執行之後的 ax 就是 FATEntry 所在的磁區號 mov cl, 2 call ReadSector ; 讀取 FATEntry 所在的磁區, 一次讀兩個, 避免在邊界發生錯誤, 因為一個 FATEntry 可能跨越兩個磁區 pop dx add bx, dx mov ax, [es:bx] cmp byte [bOdd], 1 jnz LABEL_EVEN_2 shr ax, 4 LABEL_EVEN_2: and ax, 0FFFh LABEL_GET_FAT_ENRY_OK: pop bx pop es ret ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; 函數名: KillMotor ;---------------------------------------------------------------------------- ; 作用: ; 關閉軟體驅動馬達 KillMotor: push dx mov dx, 03F2h mov al, 0 out dx, al pop dx ret ;---------------------------------------------------------------------------- ; 從此以後的程式碼在保護模式下執行 ---------------------------------------------------- ; 32 位程式碼段. 由實模式跳入 --------------------------------------------------------- [SECTION .s32] ALIGN 32 [BITS 32] LABEL_PM_START: mov ax, SelectorVideo mov gs, ax mov ax, SelectorFlatRW mov ds, ax mov es, ax mov fs, ax mov ss, ax mov esp, TopOfStack call DispMemInfo ;;; call DispReturn ;;; call DispHDInfo ; int 13h 讀出的硬碟 geometry 好像有點不對頭,不知道為什麼,乾脆不管它了 call SetupPaging ;mov ah, 0Fh ; 0000: 黑底 1111: 白字 ;mov al, 'P' ;mov [gs:((80 * 0 + 39) * 2)], ax ; 螢幕第 0 行, 第 39 列。 call InitKernel ;jmp $ ;; fill in BootParam[] mov dword [BOOT_PARAM_ADDR], BOOT_PARAM_MAGIC ; Magic Number mov eax, [dwMemSize] mov [BOOT_PARAM_ADDR + 4], eax ; memory size mov eax, KERNEL_FILE_SEG shl eax, 4 add eax, KERNEL_FILE_OFF mov [BOOT_PARAM_ADDR + 8], eax ; phy-addr of kernel.bin ;*************************************************************** jmp SelectorFlatC:KRNL_ENT_PT_PHY_ADDR ; 正式进入内核 * ;*************************************************************** ; 内存看上去是这样的: ; ┃ ┃ ; ┃ . ┃ ; ┃ . ┃ ; ┃ . ┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■Page Tables■■■■■■┃ ; ┃■■■■■(大小由LOADER决定)■■■■┃ ; 00101000h ┃■■■■■■■■■■■■■■■■■■┃ PAGE_TBL_BASE ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■■■■■■■■■■■■┃ ; 00100000h ┃■■■■Page Directory Table■■■■┃ PAGE_DIR_BASE <- 1M ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□□□□□□□□□□□□□□□┃ ; F0000h ┃□□□□□□□System ROM□□□□□□┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□□□□□□□□□□□□□□□┃ ; E0000h ┃□□□□Expansion of system ROM □□┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□□□□□□□□□□□□□□□┃ ; C0000h ┃□□□Reserved for ROM expansion□□┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□□□□□□□□□□□□□□□┃ B8000h ← gs ; A0000h ┃□□□Display adapter reserved□□□┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□□□□□□□□□□□□□□□┃ ; 9FC00h ┃□□extended BIOS data area (EBDA)□┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■■■■■■■■■■■■┃ ; 90000h ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; 70000h ┃■■■■■■■KERNEL.BIN■■■■■■┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ 7C00h~7DFFh : BOOT SECTOR, overwritten by the kernel ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; ┃■■■■■■■■■■■■■■■■■■┃ ; 1000h ┃■■■■■■■■KERNEL■■■■■■■┃ 1000h ← KERNEL 入口 (KRNL_ENT_PT_PHY_ADDR) ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃ ┃ ; 500h ┃ F R E E ┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃□□□□□□□□□□□□□□□□□□┃ ; 400h ┃□□□□ROM BIOS parameter area □□┃ ; ┣━━━━━━━━━━━━━━━━━━┫ ; ┃◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇┃ ; 0h ┃◇◇◇◇◇◇Int Vectors◇◇◇◇◇◇┃ ; ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss ; ; ; ┏━━━┓ ┏━━━┓ ; ┃■■■┃ 我们使用 ┃□□□┃ 不能使用的内存 ; ┗━━━┛ ┗━━━┛ ; ┏━━━┓ ┏━━━┓ ; ┃ ┃ 未使用空间 ┃◇◇◇┃ 可以覆盖的内存 ; ┗━━━┛ ┗━━━┛ ; ; 注:KERNEL 的位置实际上是很灵活的,可以通过同时改变 LOAD.INC 中的 KRNL_ENT_PT_PHY_ADDR 和 MAKEFILE 中参数 -Ttext 的值来改变。 ; 比如,如果把 KRNL_ENT_PT_PHY_ADDR 和 -Ttext 的值都改为 0x400400,则 KERNEL 就会被加载到内存 0x400000(4M) 处,入口在 0x400400。 ; ; ------------------------------------------------------------------------ ; 显示 AL 中的数字 ; ------------------------------------------------------------------------ DispAL: push ecx push edx push edi mov edi, [dwDispPos] mov ah, 0Fh ; 0000b: 黑底 1111b: 白字 mov dl, al shr al, 4 mov ecx, 2 .begin: and al, 01111b cmp al, 9 ja .1 add al, '0' jmp .2 .1: sub al, 0Ah add al, 'A' .2: mov [gs:edi], ax add edi, 2 mov al, dl loop .begin ;add edi, 2 mov [dwDispPos], edi pop edi pop edx pop ecx ret ; DispAL 结束------------------------------------------------------------- ; ------------------------------------------------------------------------ ; 显示一个整形数 ; ------------------------------------------------------------------------ DispInt: mov eax, [esp + 4] shr eax, 24 call DispAL mov eax, [esp + 4] shr eax, 16 call DispAL mov eax, [esp + 4] shr eax, 8 call DispAL mov eax, [esp + 4] call DispAL mov ah, 07h ; 0000b: 黑底 0111b: 灰字 mov al, 'h' push edi mov edi, [dwDispPos] mov [gs:edi], ax add edi, 4 mov [dwDispPos], edi pop edi ret ; DispInt 结束------------------------------------------------------------ ; ------------------------------------------------------------------------ ; 显示一个字元串 ; ------------------------------------------------------------------------ DispStr: push ebp mov ebp, esp push ebx push esi push edi mov esi, [ebp + 8] ; pszInfo mov edi, [dwDispPos] mov ah, 0Fh .1: lodsb test al, al jz .2 cmp al, 0Ah ; 是回车吗? 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 [dwDispPos], edi pop edi pop esi pop ebx pop ebp ret ; DispStr 结束------------------------------------------------------------ ; ------------------------------------------------------------------------ ; 换行 ; ------------------------------------------------------------------------ DispReturn: push szReturn call DispStr ;printf("\n"); add esp, 4 ret ; DispReturn 结束--------------------------------------------------------- ; ------------------------------------------------------------------------ ; 内存拷贝,仿 memcpy ; ------------------------------------------------------------------------ ; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize); ; ------------------------------------------------------------------------ MemCpy: push ebp mov ebp, esp push esi push edi push ecx mov edi, [ebp + 8] ; Destination mov esi, [ebp + 12] ; Source mov ecx, [ebp + 16] ; Counter .1: cmp ecx, 0 ; 判断计数器 jz .2 ; 计数器为零时跳出 mov al, [ds:esi] ; ┓ inc esi ; ┃ ; ┣ 逐字节移动 mov byte [es:edi], al ; ┃ inc edi ; ┛ dec ecx ; 计数器减一 jmp .1 ; 循环 .2: mov eax, [ebp + 8] ; 返回值 pop ecx pop edi pop esi mov esp, ebp pop ebp ret ; 函数结束,返回 ; MemCpy 结束------------------------------------------------------------- ; 显示内存訊息 -------------------------------------------------------------- DispMemInfo: push esi push edi push ecx push szMemChkTitle call DispStr add esp, 4 mov esi, MemChkBuf mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构 .loop: ;{ mov edx, 5 ; for(int j=0;j<5;j++) // 每次得到一个ARDS中的成员,共5个成员 mov edi, ARDStruct ; { // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type .1: ; push dword [esi] ; call DispInt ; DispInt(MemChkBuf[j*4]); // 显示一个成员 pop eax ; stosd ; ARDStruct[j*4] = MemChkBuf[j*4]; add esi, 4 ; dec edx ; cmp edx, 0 ; jnz .1 ; } call DispReturn ; printf("\n"); cmp dword [dwType], 1 ; if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2 jne .2 ; { mov eax, [dwBaseAddrLow] ; add eax, [dwLengthLow] ; cmp eax, [dwMemSize] ; if(BaseAddrLow + LengthLow > MemSize) jb .2 ; mov [dwMemSize], eax ; MemSize = BaseAddrLow + LengthLow; .2: ; } loop .loop ;} ; call DispReturn ;printf("\n"); push szRAMSize ; call DispStr ;printf("RAM size:"); add esp, 4 ; ; push dword [dwMemSize] ; call DispInt ;DispInt(MemSize); add esp, 4 ; pop ecx pop edi pop esi ret ; --------------------------------------------------------------------------- ;;; ; 显示内存訊息 -------------------------------------------------------------- ;;; DispHDInfo: ;;; push eax ;;; cmp dword [dwNrHead], 0FFFFh ;;; je .nohd ;;; push szCylinder ;;; call DispStr ; printf("C:"); ;;; add esp, 4 ;;; push dword [dwNrCylinder] ; NR Cylinder ;;; call DispInt ;;; pop eax ;;; push szHead ;;; call DispStr ; printf(" H:"); ;;; add esp, 4 ;;; push dword [dwNrHead] ; NR Head ;;; call DispInt ;;; pop eax ;;; push szSector ;;; call DispStr ; printf(" S:"); ;;; add esp, 4 ;;; push dword [dwNrSector] ; NR Sector ;;; call DispInt ;;; pop eax ;;; jmp .hdinfo_finish ;;; .nohd: ;;; push szNOHD ;;; call DispStr ; printf("No hard drive. System halt."); ;;; add esp, 4 ;;; jmp $ ; 没有硬盘,死在这里 ;;; .hdinfo_finish: ;;; call DispReturn ;;; pop eax ;;; ret ;;; ; --------------------------------------------------------------------------- ; 启动分页机制 -------------------------------------------------------------- SetupPaging: ; 根据内存大小计算应初始化多少PDE以及多少页表 xor edx, edx mov eax, [dwMemSize] mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小 div ebx mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数 test edx, edx jz .no_remainder inc ecx ; 如果余数不为 0 就需增加一个页表 .no_remainder: push ecx ; 暂存页表个数 ; 为简化处理, 所有线性位址对应相等的物理位址. 并且不考虑内存空洞. ; 首先初始化页目录 mov ax, SelectorFlatRW mov es, ax mov edi, PAGE_DIR_BASE ; 此段首位址为 PAGE_DIR_BASE xor eax, eax mov eax, PAGE_TBL_BASE | PG_P | PG_USU | PG_RWW .1: stosd add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. loop .1 ; 再初始化所有页表 pop eax ; 页表个数 mov ebx, 1024 ; 每个页表 1024 个 PTE mul ebx mov ecx, eax ; PTE个数 = 页表个数 * 1024 mov edi, PAGE_TBL_BASE ; 此段首位址为 PAGE_TBL_BASE xor eax, eax mov eax, PG_P | PG_USU | PG_RWW .2: stosd add eax, 4096 ; 每一页指向 4K 的空间 loop .2 mov eax, PAGE_DIR_BASE mov cr3, eax mov eax, cr0 or eax, 80000000h mov cr0, eax jmp short .3 .3: nop ret ; 分页机制启动完毕 ---------------------------------------------------------- ; InitKernel --------------------------------------------------------------------------------- ; 将 KERNEL.BIN 的内容经过整理对齐后放到新的位置 ; -------------------------------------------------------------------------------------------- InitKernel: ; 遍历每一个 Program Header,根据 Program Header 中的訊息来确定把什么放进内存,放到什么位置,以及放多少。 xor esi, esi mov cx, word [KERNEL_FILE_PHY_ADDR + 2Ch]; ┓ ecx <- pELFHdr->e_phnum movzx ecx, cx ; ┛ mov esi, [KERNEL_FILE_PHY_ADDR + 1Ch] ; esi <- pELFHdr->e_phoff add esi, KERNEL_FILE_PHY_ADDR ; esi <- OffsetOfKernel + pELFHdr->e_phoff .Begin: mov eax, [esi + 0] cmp eax, 0 ; PT_NULL jz .NoAction push dword [esi + 010h] ; size ┓ mov eax, [esi + 04h] ; ┃ add eax, KERNEL_FILE_PHY_ADDR ; ┣ ::memcpy( (void*)(pPHdr->p_vaddr), push eax ; src ┃ uchCode + pPHdr->p_offset, push dword [esi + 08h] ; dst ┃ pPHdr->p_filesz; call MemCpy ; ┃ add esp, 12 ; ┛ .NoAction: add esi, 020h ; esi += pELFHdr->e_phentsize dec ecx jnz .Begin ret ; InitKernel ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; SECTION .data1 之开始 --------------------------------------------------------------------------------------------- [SECTION .data1] ALIGN 32 LABEL_DATA: ; 实模式下使用这些符号 ; 字元串 _szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0 _szRAMSize: db "RAM size: ", 0 ;;; _szCylinder db "HD Info : C=", 0 ;;; _szHead db " H=", 0 ;;; _szSector db " S=", 0 ;;; _szNOHD db "No hard drive. System halt.", 0 _szReturn: db 0Ah, 0 ;; 变量 ;;; _dwNrCylinder dd 0 ;;; _dwNrHead dd 0 ;;; _dwNrSector dd 0 _dwMCRNumber: dd 0 ; Memory Check Result _dwDispPos: dd (80 * 7 + 0) * 2 ; 螢幕第 7 行, 第 0 列。 _dwMemSize: dd 0 _ARDStruct: ; Address Range Descriptor Structure _dwBaseAddrLow: dd 0 _dwBaseAddrHigh: dd 0 _dwLengthLow: dd 0 _dwLengthHigh: dd 0 _dwType: dd 0 _MemChkBuf: times 256 db 0 ; ;; 保护模式下使用这些符号 szMemChkTitle equ LOADER_PHY_ADDR + _szMemChkTitle szRAMSize equ LOADER_PHY_ADDR + _szRAMSize ;;; szCylinder equ LOADER_PHY_ADDR + _szCylinder ;;; szHead equ LOADER_PHY_ADDR + _szHead ;;; szSector equ LOADER_PHY_ADDR + _szSector ;;; szNOHD equ LOADER_PHY_ADDR + _szNOHD szReturn equ LOADER_PHY_ADDR + _szReturn ;;; dwNrCylinder equ LOADER_PHY_ADDR + _dwNrCylinder ;;; dwNrHead equ LOADER_PHY_ADDR + _dwNrHead ;;; dwNrSector equ LOADER_PHY_ADDR + _dwNrSector dwDispPos equ LOADER_PHY_ADDR + _dwDispPos dwMemSize equ LOADER_PHY_ADDR + _dwMemSize dwMCRNumber equ LOADER_PHY_ADDR + _dwMCRNumber ARDStruct equ LOADER_PHY_ADDR + _ARDStruct dwBaseAddrLow equ LOADER_PHY_ADDR + _dwBaseAddrLow dwBaseAddrHigh equ LOADER_PHY_ADDR + _dwBaseAddrHigh dwLengthLow equ LOADER_PHY_ADDR + _dwLengthLow dwLengthHigh equ LOADER_PHY_ADDR + _dwLengthHigh dwType equ LOADER_PHY_ADDR + _dwType MemChkBuf equ LOADER_PHY_ADDR + _MemChkBuf ; 堆栈就在数据段的末尾 StackSpace: times 1000h db 0 TopOfStack equ LOADER_PHY_ADDR + $ ; 栈顶 ; SECTION .data1 之结束 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
注意:如果採用 64 位元 Linux Mint,可能需要安裝 gcc-multilib,以解決以下問題:
gcc -I include/ -I include/sys/ -m32 -c -fno-builtin -fno-stack-protector -o lib/klib.o lib/klib.c
In file included from /usr/include/elf.h:24:0,
from lib/klib.c:24:
/usr/include/features.h:324:26: 嚴重錯誤: bits/predefs.h:沒有此一檔案或目錄
![]() |
執行畫面 |
目錄結構
. ├── 80m.img ├── 80m.vdi ├── a.img ├── boot │ ├── boot.asm │ ├── include │ │ ├── fat12hdr.inc │ │ ├── load.inc │ │ └── pm.inc │ └── loader.asm ├── fs │ ├── disklog.c │ ├── link.c │ ├── main.c │ ├── misc.c │ ├── open.c │ └── read_write.c ├── include │ ├── stdio.h │ ├── string.h │ ├── sys │ │ ├── config.h │ │ ├── console.h │ │ ├── const.h │ │ ├── fs.h │ │ ├── global.h │ │ ├── hd.h │ │ ├── keyboard.h │ │ ├── keymap.h │ │ ├── proc.h │ │ ├── protect.h │ │ ├── proto.h │ │ ├── sconst.inc │ │ └── tty.h │ └── type.h ├── kernel │ ├── clock.c │ ├── console.c │ ├── global.c │ ├── hd.c │ ├── i8259.c │ ├── kernel.asm │ ├── keyboard.c │ ├── main.c │ ├── proc.c │ ├── protect.c │ ├── start.c │ ├── systask.c │ └── tty.c ├── lib │ ├── close.c │ ├── exit.c │ ├── fork.c │ ├── getpid.c │ ├── kliba.asm │ ├── klib.c │ ├── misc.c │ ├── open.c │ ├── printf.c │ ├── read.c │ ├── string.asm │ ├── syscall.asm │ ├── syslog.c │ ├── unlink.c │ ├── vsprintf.c │ ├── wait.c │ └── write.c ├── Makefile └── mm ├── forkexit.c └── main.c
留言
張貼留言