一個新的處理序需要:
注意:如果採用 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

留言
張貼留言