寫入 TTY 跟寫入普通檔是很類似的,不同之處在於 TTY 不需要進行任何埠操作,只是寫入顯示卡記憶體即可。而對於讀出操作,則有很大的不同。TTY 收到處理序讀出請求的訊息,並不能馬上返回資料,因為此時並沒有任何輸入,而需要使用者輸入字元,等輸入結束後,TTY才可以返回給處理序。問題在於:
- 怎樣是「輸入結束」:是美一次鍵盤敲擊後算結束(面向字元,Raw mode)?還是等敲 Enter 才算結果(面向行,Cooked mode)?或者其它?
- 是否要讓檔案系統等待輸入過程結束?
- TTY 需要馬上向檔案系統發送訊息以示返回。而檔案系統則完全應該阻塞想要得到輸入的處理序,直到輸入結束。
讀 TTY 的過程:
- 假設處理序 P 要求讀取 TTY,它會發送訊息給檔案系統
- 檔案系統將訊息傳遞給 TTY
- TTY 記下發出請求的處理序號等資訊後立即返回
- 檔案系統此時並不對 P 接觸阻塞,因為結果尚未準備好
- 檔案系統一如往常等待任何處理序之請求
- TTY 將鍵盤輸入複製進 P 傳入的記憶體位址
- 一旦遇到 Enter,TTY 就告訴檔案系統,P 的請求已被滿足
- 檔案系統會解除對 P 的阻塞
- 讀取工作結束
寫 TTY 的過程:
- P 發訊息給檔案系統
- 檔案系統傳遞給 TTY
- TTY 受到訊息候立即將字元寫入顯示卡記憶體(保持 P 和 FS 處理序的阻塞)
- 完成後發訊息給檔案系統
- 檔案系統在發訊息給 P
- 整個過程結束
程式碼
fs/main.c
/*************************************************************************//**
*****************************************************************************
* @file main.c
* @brief
* @author Forrest Y. Yu
* @date 2007
*****************************************************************************
*****************************************************************************/
#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 "hd.h"
PRIVATE void init_fs();
PRIVATE void mkfs();
PRIVATE void read_super_block(int dev);
/*****************************************************************************
* task_fs
*****************************************************************************/
/**
* <Ring 1> The main loop of TASK FS.
*
*****************************************************************************/
PUBLIC void task_fs()
{
printl("Task FS begins.\n");
init_fs();
while (1) {
send_recv(RECEIVE, ANY, &fs_msg);
int msgtype = fs_msg.type;
int src = fs_msg.source;
pcaller = &proc_table[src];
switch (msgtype) {
case OPEN:
fs_msg.FD = do_open();
break;
case CLOSE:
fs_msg.RETVAL = do_close();
break;
case READ:
case WRITE:
fs_msg.CNT = do_rdwt();
break;
case UNLINK:
fs_msg.RETVAL = do_unlink();
break;
/* case LSEEK: */
/* fs_msg.OFFSET = do_lseek(); */
/* break; */
/* case RESUME_PROC: */
/* src = fs_msg.PROC_NR; */
/* break; */
/* case FORK: */
/* fs_msg.RETVAL = fs_fork(); */
/* break; */
/* case EXIT: */
/* fs_msg.RETVAL = fs_exit(); */
/* break; */
/* case STAT: */
/* fs_msg.RETVAL = do_stat(); */
/* break; */
default:
dump_msg("FS::unknown message:", &fs_msg);
assert(0);
break;
}
#ifdef ENABLE_DISK_LOG
char * msg_name[128];
msg_name[OPEN] = "OPEN";
msg_name[CLOSE] = "CLOSE";
msg_name[READ] = "READ";
msg_name[WRITE] = "WRITE";
msg_name[LSEEK] = "LSEEK";
msg_name[UNLINK] = "UNLINK";
/* msg_name[FORK] = "FORK"; */
/* msg_name[EXIT] = "EXIT"; */
/* msg_name[STAT] = "STAT"; */
switch (msgtype) {
case CLOSE:
case UNLINK:
//dump_fd_graph("%s just finished.", msg_name[msgtype]);
//panic("");
case OPEN:
case READ:
case WRITE:
/* case FORK: */
/* case LSEEK: */
/* case EXIT: */
/* case STAT: */
break;
/* case RESUME_PROC: */
case DISK_LOG:
break;
default:
assert(0);
}
#endif
/* reply */
fs_msg.type = SYSCALL_RET;
send_recv(SEND, src, &fs_msg);
}
}
/*****************************************************************************
* init_fs
*****************************************************************************/
/**
* <Ring 1> Do some preparation.
*
*****************************************************************************/
PRIVATE void init_fs()
{
int i;
/* f_desc_table[] */
for (i = 0; i < NR_FILE_DESC; i++)
memset(&f_desc_table[i], 0, sizeof(struct file_desc));
/* inode_table[] */
for (i = 0; i < NR_INODE; i++)
memset(&inode_table[i], 0, sizeof(struct inode));
/* super_block[] */
struct super_block * sb = super_block;
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++)
sb->sb_dev = NO_DEV;
/* open the device: hard disk */
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
driver_msg.DEVICE = MINOR(ROOT_DEV);
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
/* make FS */
mkfs();
/* load super block of ROOT */
read_super_block(ROOT_DEV);
sb = get_super_block(ROOT_DEV);
assert(sb->magic == MAGIC_V1);
root_inode = get_inode(ROOT_DEV, ROOT_INODE);
}
/*****************************************************************************
* mkfs
*****************************************************************************/
/**
* <Ring 1> Make a available Orange'S FS in the disk. It will
* - Write a super block to sector 1.
* - Create three special files: dev_tty0, dev_tty1, dev_tty2
* - Create the inode map
* - Create the sector map
* - Create the inodes of the files
* - Create `/', the root directory
*****************************************************************************/
PRIVATE void mkfs()
{
MESSAGE driver_msg;
int i, j;
int bits_per_sect = SECTOR_SIZE * 8; /* 8 bits per byte */
/* get the geometry of ROOTDEV */
struct part_info geo;
driver_msg.type = DEV_IOCTL;
driver_msg.DEVICE = MINOR(ROOT_DEV);
driver_msg.REQUEST = DIOCTL_GET_GEO;
driver_msg.BUF = &geo;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
printl("dev size: 0x%x sectors\n", geo.size);
/************************/
/* super block */
/************************/
struct super_block sb;
sb.magic = MAGIC_V1;
sb.nr_inodes = bits_per_sect;
sb.nr_inode_sects = sb.nr_inodes * INODE_SIZE / SECTOR_SIZE;
sb.nr_sects = geo.size; /* partition size in sector */
sb.nr_imap_sects = 1;
sb.nr_smap_sects = sb.nr_sects / bits_per_sect + 1;
sb.n_1st_sect = 1 + 1 + /* boot sector & super block */
sb.nr_imap_sects + sb.nr_smap_sects + sb.nr_inode_sects;
sb.root_inode = ROOT_INODE;
sb.inode_size = INODE_SIZE;
struct inode x;
sb.inode_isize_off= (int)&x.i_size - (int)&x;
sb.inode_start_off= (int)&x.i_start_sect - (int)&x;
sb.dir_ent_size = DIR_ENTRY_SIZE;
struct dir_entry de;
sb.dir_ent_inode_off = (int)&de.inode_nr - (int)&de;
sb.dir_ent_fname_off = (int)&de.name - (int)&de;
memset(fsbuf, 0x90, SECTOR_SIZE);
memcpy(fsbuf, &sb, SUPER_BLOCK_SIZE);
/* write the super block */
WR_SECT(ROOT_DEV, 1);
printl("devbase:0x%x00, sb:0x%x00, imap:0x%x00, smap:0x%x00\n"
" inodes:0x%x00, 1st_sector:0x%x00\n",
geo.base * 2,
(geo.base + 1) * 2,
(geo.base + 1 + 1) * 2,
(geo.base + 1 + 1 + sb.nr_imap_sects) * 2,
(geo.base + 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects) * 2,
(geo.base + sb.n_1st_sect) * 2);
/************************/
/* inode map */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 0; i < (NR_CONSOLES + 2); i++)
fsbuf[0] |= 1 << i;
assert(fsbuf[0] == 0x1F);/* 0001 1111 :
* | ||||
* | |||`--- bit 0 : reserved
* | ||`---- bit 1 : the first inode,
* | || which indicates `/'
* | |`----- bit 2 : /dev_tty0
* | `------ bit 3 : /dev_tty1
* `-------- bit 4 : /dev_tty2
*/
WR_SECT(ROOT_DEV, 2);
/************************/
/* secter map */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
int nr_sects = NR_DEFAULT_FILE_SECTS + 1;
/* ~~~~~~~~~~~~~~~~~~~|~ |
* | `--- bit 0 is reserved
* `-------- for `/'
*/
for (i = 0; i < nr_sects / 8; i++)
fsbuf[i] = 0xFF;
for (j = 0; j < nr_sects % 8; j++)
fsbuf[i] |= (1 << j);
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects);
/* zeromemory the rest sector-map */
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 1; i < sb.nr_smap_sects; i++)
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + i);
/************************/
/* inodes */
/************************/
/* inode of `/' */
memset(fsbuf, 0, SECTOR_SIZE);
struct inode * pi = (struct inode*)fsbuf;
pi->i_mode = I_DIRECTORY;
pi->i_size = DIR_ENTRY_SIZE * 4; /* 4 files:
* `.',
* `dev_tty0', `dev_tty1', `dev_tty2',
*/
pi->i_start_sect = sb.n_1st_sect;
pi->i_nr_sects = NR_DEFAULT_FILE_SECTS;
/* inode of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++) {
pi = (struct inode*)(fsbuf + (INODE_SIZE * (i + 1)));
pi->i_mode = I_CHAR_SPECIAL;
pi->i_size = 0;
pi->i_start_sect = MAKE_DEV(DEV_CHAR_TTY, i);
pi->i_nr_sects = 0;
}
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + sb.nr_smap_sects);
/************************/
/* `/' */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
struct dir_entry * pde = (struct dir_entry *)fsbuf;
pde->inode_nr = 1;
strcpy(pde->name, ".");
/* dir entries of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++) {
pde++;
pde->inode_nr = i + 2; /* dev_tty0's inode_nr is 2 */
sprintf(pde->name, "dev_tty%d", i);
}
WR_SECT(ROOT_DEV, sb.n_1st_sect);
}
/*****************************************************************************
* rw_sector
*****************************************************************************/
/**
* <Ring 1> R/W a sector via messaging with the corresponding driver.
*
* @param io_type DEV_READ or DEV_WRITE
* @param dev device nr
* @param pos Byte offset from/to where to r/w.
* @param bytes r/w count in bytes.
* @param proc_nr To whom the buffer belongs.
* @param buf r/w buffer.
*
* @return Zero if success.
*****************************************************************************/
PUBLIC int rw_sector(int io_type, int dev, u64 pos, int bytes, int proc_nr,
void* buf)
{
MESSAGE driver_msg;
driver_msg.type = io_type;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = pos;
driver_msg.BUF = buf;
driver_msg.CNT = bytes;
driver_msg.PROC_NR = proc_nr;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
return 0;
}
/*****************************************************************************
* read_super_block
*****************************************************************************/
/**
* <Ring 1> Read super block from the given device then write it into a free
* super_block[] slot.
*
* @param dev From which device the super block comes.
*****************************************************************************/
PRIVATE void read_super_block(int dev)
{
int i;
MESSAGE driver_msg;
driver_msg.type = DEV_READ;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = SECTOR_SIZE * 1;
driver_msg.BUF = fsbuf;
driver_msg.CNT = SECTOR_SIZE;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
/* find a free slot in super_block[] */
for (i = 0; i < NR_SUPER_BLOCK; i++)
if (super_block[i].sb_dev == NO_DEV)
break;
if (i == NR_SUPER_BLOCK)
panic("super_block slots used up");
assert(i == 0); /* currently we use only the 1st slot */
struct super_block * psb = (struct super_block *)fsbuf;
super_block[i] = *psb;
super_block[i].sb_dev = dev;
}
/*****************************************************************************
* get_super_block
*****************************************************************************/
/**
* <Ring 1> Get the super block from super_block[].
*
* @param dev Device nr.
*
* @return Super block ptr.
*****************************************************************************/
PUBLIC struct super_block * get_super_block(int dev)
{
struct super_block * sb = super_block;
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++)
if (sb->sb_dev == dev)
return sb;
panic("super block of devie %d not found.\n", dev);
return 0;
}
/*****************************************************************************
* get_inode
*****************************************************************************/
/**
* <Ring 1> Get the inode ptr of given inode nr. A cache -- inode_table[] -- is
* maintained to make things faster. If the inode requested is already there,
* just return it. Otherwise the inode will be read from the disk.
*
* @param dev Device nr.
* @param num I-node nr.
*
* @return The inode ptr requested.
*****************************************************************************/
PUBLIC struct inode * get_inode(int dev, int num)
{
if (num == 0)
return 0;
struct inode * p;
struct inode * q = 0;
for (p = &inode_table[0]; p < &inode_table[NR_INODE]; p++) {
if (p->i_cnt) { /* not a free slot */
if ((p->i_dev == dev) && (p->i_num == num)) {
/* this is the inode we want */
p->i_cnt++;
return p;
}
}
else { /* a free slot */
if (!q) /* q hasn't been assigned yet */
q = p; /* q <- the 1st free slot */
}
}
if (!q)
panic("the inode table is full");
q->i_dev = dev;
q->i_num = num;
q->i_cnt = 1;
struct super_block * sb = get_super_block(dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects +
((num - 1) / (SECTOR_SIZE / INODE_SIZE));
RD_SECT(dev, blk_nr);
struct inode * pinode =
(struct inode*)((u8*)fsbuf +
((num - 1 ) % (SECTOR_SIZE / INODE_SIZE))
* INODE_SIZE);
q->i_mode = pinode->i_mode;
q->i_size = pinode->i_size;
q->i_start_sect = pinode->i_start_sect;
q->i_nr_sects = pinode->i_nr_sects;
return q;
}
/*****************************************************************************
* put_inode
*****************************************************************************/
/**
* Decrease the reference nr of a slot in inode_table[]. When the nr reaches
* zero, it means the inode is not used any more and can be overwritten by
* a new inode.
*
* @param pinode I-node ptr.
*****************************************************************************/
PUBLIC void put_inode(struct inode * pinode)
{
assert(pinode->i_cnt > 0);
pinode->i_cnt--;
}
/*****************************************************************************
* sync_inode
*****************************************************************************/
/**
* <Ring 1> Write the inode back to the disk. Commonly invoked as soon as the
* inode is changed.
*
* @param p I-node ptr.
*****************************************************************************/
PUBLIC void sync_inode(struct inode * p)
{
struct inode * pinode;
struct super_block * sb = get_super_block(p->i_dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects +
((p->i_num - 1) / (SECTOR_SIZE / INODE_SIZE));
RD_SECT(p->i_dev, blk_nr);
pinode = (struct inode*)((u8*)fsbuf +
(((p->i_num - 1) % (SECTOR_SIZE / INODE_SIZE))
* INODE_SIZE));
pinode->i_mode = p->i_mode;
pinode->i_size = p->i_size;
pinode->i_start_sect = p->i_start_sect;
pinode->i_nr_sects = p->i_nr_sects;
WR_SECT(p->i_dev, blk_nr);
}
include/sys/console.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
console.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_CONSOLE_H_
#define _ORANGES_CONSOLE_H_
/* CONSOLE */
typedef struct s_console
{
unsigned int crtc_start; /* set CRTC start addr reg */
unsigned int orig; /* start addr of the console */
unsigned int con_size; /* how many words does the console have */
unsigned int cursor;
int is_full;
}CONSOLE;
#define SCR_UP 1 /* scroll upward */
#define SCR_DN -1 /* scroll downward */
#define SCR_SIZE (80 * 25)
#define SCR_WIDTH 80
#define DEFAULT_CHAR_COLOR (MAKE_COLOR(BLACK, WHITE))
#define GRAY_CHAR (MAKE_COLOR(BLACK, BLACK) | BRIGHT)
#define RED_CHAR (MAKE_COLOR(BLUE, RED) | BRIGHT)
#endif /* _ORANGES_CONSOLE_H_ */
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 */
/* TTY */
#define NR_CONSOLES 3 /* consoles */
/* 8259A interrupt controller ports. */
#define INT_M_CTL 0x20 /* I/O port for interrupt controller <Master> */
#define INT_M_CTLMASK 0x21 /* setting bits in this port disables ints <Master> */
#define INT_S_CTL 0xA0 /* I/O port for second interrupt controller <Slave> */
#define INT_S_CTLMASK 0xA1 /* setting bits in this port disables ints <Slave> */
/* 8253/8254 PIT (Programmable Interval Timer) */
#define TIMER0 0x40 /* I/O port for timer channel 0 */
#define TIMER_MODE 0x43 /* I/O port for timer mode control */
#define RATE_GENERATOR 0x34 /* 00-11-010-0 :
* Counter0 - LSB then MSB - rate generator - binary
*/
#define TIMER_FREQ 1193182L/* clock frequency for timer in PC and AT */
#define HZ 100 /* clock freq (software settable on IBM-PC) */
/* AT keyboard */
/* 8042 ports */
#define KB_DATA 0x60 /* I/O port for keyboard data
Read : Read Output Buffer
Write: Write Input Buffer(8042 Data&8048 Command) */
#define KB_CMD 0x64 /* I/O port for keyboard command
Read : Read Status Register
Write: Write Input Buffer(8042 Command) */
#define LED_CODE 0xED
#define KB_ACK 0xFA
/* VGA */
#define CRTC_ADDR_REG 0x3D4 /* CRT Controller Registers - Addr Register */
#define CRTC_DATA_REG 0x3D5 /* CRT Controller Registers - Data Register */
#define START_ADDR_H 0xC /* reg index of video mem start addr (MSB) */
#define START_ADDR_L 0xD /* reg index of video mem start addr (LSB) */
#define CURSOR_H 0xE /* reg index of cursor position (MSB) */
#define CURSOR_L 0xF /* reg index of cursor position (LSB) */
#define V_MEM_BASE 0xB8000 /* base of color video memory */
#define V_MEM_SIZE 0x8000 /* 32K: B8000H -> BFFFFH */
/* Hardware interrupts */
#define NR_IRQ 16 /* Number of IRQs */
#define CLOCK_IRQ 0
#define KEYBOARD_IRQ 1
#define CASCADE_IRQ 2 /* cascade enable for 2nd AT controller */
#define ETHER_IRQ 3 /* default ethernet interrupt vector */
#define SECONDARY_IRQ 3 /* RS232 interrupt vector for port 2 */
#define RS232_IRQ 4 /* RS232 interrupt vector for port 1 */
#define XT_WINI_IRQ 5 /* xt winchester */
#define FLOPPY_IRQ 6 /* floppy disk */
#define PRINTER_IRQ 7
#define AT_WINI_IRQ 14 /* at winchester */
/* tasks */
/* 注意 TASK_XXX 的定義要與 global.c 中對應 */
#define INVALID_DRIVER -20
#define INTERRUPT -10
#define TASK_TTY 0
#define TASK_SYS 1
#define TASK_HD 2
#define TASK_FS 3
/* #define TASK_MM 4 */
#define ANY (NR_TASKS + NR_PROCS + 10)
#define NO_TASK (NR_TASKS + NR_PROCS + 20)
#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,
/* FS */
OPEN, CLOSE, READ, WRITE, LSEEK, STAT, UNLINK,
/* FS & TTY */
SUSPEND_PROC, RESUME_PROC,
/* TTY, SYS, FS, MM, etc */
SYSCALL_RET,
/* message type for drivers */
DEV_OPEN = 1001,
DEV_CLOSE,
DEV_READ,
DEV_WRITE,
DEV_IOCTL,
/* for debug */
DISK_LOG
};
/* 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/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[];
/* 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[];
include/sys/keyboard.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
keyboard.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, December, 2003
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_KEYBOARD_H_
#define _ORANGES_KEYBOARD_H_
/************************************************************************/
/* Macros Declaration */
/************************************************************************/
#define KB_IN_BYTES 32 /* size of keyboard input buffer */
#define MAP_COLS 3 /* Number of columns in keymap */
#define NR_SCAN_CODES 0x80 /* Number of scan codes (rows in keymap) */
#define FLAG_BREAK 0x0080 /* Break Code */
#define FLAG_EXT 0x0100 /* Normal function keys */
#define FLAG_SHIFT_L 0x0200 /* Shift key */
#define FLAG_SHIFT_R 0x0400 /* Shift key */
#define FLAG_CTRL_L 0x0800 /* Control key */
#define FLAG_CTRL_R 0x1000 /* Control key */
#define FLAG_ALT_L 0x2000 /* Alternate key */
#define FLAG_ALT_R 0x4000 /* Alternate key */
#define FLAG_PAD 0x8000 /* keys in num pad */
#define MASK_RAW 0x01FF /* raw key value = code passed to tty & MASK_RAW
the value can be found either in the keymap column 0
or in the list below */
/* Special keys */
#define ESC (0x01 + FLAG_EXT) /* Esc */
#define TAB (0x02 + FLAG_EXT) /* Tab */
#define ENTER (0x03 + FLAG_EXT) /* Enter */
#define BACKSPACE (0x04 + FLAG_EXT) /* BackSpace */
#define GUI_L (0x05 + FLAG_EXT) /* L GUI */
#define GUI_R (0x06 + FLAG_EXT) /* R GUI */
#define APPS (0x07 + FLAG_EXT) /* APPS */
/* Shift, Ctrl, Alt */
#define SHIFT_L (0x08 + FLAG_EXT) /* L Shift */
#define SHIFT_R (0x09 + FLAG_EXT) /* R Shift */
#define CTRL_L (0x0A + FLAG_EXT) /* L Ctrl */
#define CTRL_R (0x0B + FLAG_EXT) /* R Ctrl */
#define ALT_L (0x0C + FLAG_EXT) /* L Alt */
#define ALT_R (0x0D + FLAG_EXT) /* R Alt */
/* Lock keys */
#define CAPS_LOCK (0x0E + FLAG_EXT) /* Caps Lock */
#define NUM_LOCK (0x0F + FLAG_EXT) /* Number Lock */
#define SCROLL_LOCK (0x10 + FLAG_EXT) /* Scroll Lock */
/* Function keys */
#define F1 (0x11 + FLAG_EXT) /* F1 */
#define F2 (0x12 + FLAG_EXT) /* F2 */
#define F3 (0x13 + FLAG_EXT) /* F3 */
#define F4 (0x14 + FLAG_EXT) /* F4 */
#define F5 (0x15 + FLAG_EXT) /* F5 */
#define F6 (0x16 + FLAG_EXT) /* F6 */
#define F7 (0x17 + FLAG_EXT) /* F7 */
#define F8 (0x18 + FLAG_EXT) /* F8 */
#define F9 (0x19 + FLAG_EXT) /* F9 */
#define F10 (0x1A + FLAG_EXT) /* F10 */
#define F11 (0x1B + FLAG_EXT) /* F11 */
#define F12 (0x1C + FLAG_EXT) /* F12 */
/* Control Pad */
#define PRINTSCREEN (0x1D + FLAG_EXT) /* Print Screen */
#define PAUSEBREAK (0x1E + FLAG_EXT) /* Pause/Break */
#define INSERT (0x1F + FLAG_EXT) /* Insert */
#define DELETE (0x20 + FLAG_EXT) /* Delete */
#define HOME (0x21 + FLAG_EXT) /* Home */
#define END (0x22 + FLAG_EXT) /* End */
#define PAGEUP (0x23 + FLAG_EXT) /* Page Up */
#define PAGEDOWN (0x24 + FLAG_EXT) /* Page Down */
#define UP (0x25 + FLAG_EXT) /* Up */
#define DOWN (0x26 + FLAG_EXT) /* Down */
#define LEFT (0x27 + FLAG_EXT) /* Left */
#define RIGHT (0x28 + FLAG_EXT) /* Right */
/* ACPI keys */
#define POWER (0x29 + FLAG_EXT) /* Power */
#define SLEEP (0x2A + FLAG_EXT) /* Sleep */
#define WAKE (0x2B + FLAG_EXT) /* Wake Up */
/* Num Pad */
#define PAD_SLASH (0x2C + FLAG_EXT) /* / */
#define PAD_STAR (0x2D + FLAG_EXT) /* * */
#define PAD_MINUS (0x2E + FLAG_EXT) /* - */
#define PAD_PLUS (0x2F + FLAG_EXT) /* + */
#define PAD_ENTER (0x30 + FLAG_EXT) /* Enter */
#define PAD_DOT (0x31 + FLAG_EXT) /* . */
#define PAD_0 (0x32 + FLAG_EXT) /* 0 */
#define PAD_1 (0x33 + FLAG_EXT) /* 1 */
#define PAD_2 (0x34 + FLAG_EXT) /* 2 */
#define PAD_3 (0x35 + FLAG_EXT) /* 3 */
#define PAD_4 (0x36 + FLAG_EXT) /* 4 */
#define PAD_5 (0x37 + FLAG_EXT) /* 5 */
#define PAD_6 (0x38 + FLAG_EXT) /* 6 */
#define PAD_7 (0x39 + FLAG_EXT) /* 7 */
#define PAD_8 (0x3A + FLAG_EXT) /* 8 */
#define PAD_9 (0x3B + FLAG_EXT) /* 9 */
#define PAD_UP PAD_8 /* Up */
#define PAD_DOWN PAD_2 /* Down */
#define PAD_LEFT PAD_4 /* Left */
#define PAD_RIGHT PAD_6 /* Right */
#define PAD_HOME PAD_7 /* Home */
#define PAD_END PAD_1 /* End */
#define PAD_PAGEUP PAD_9 /* Page Up */
#define PAD_PAGEDOWN PAD_3 /* Page Down */
#define PAD_INS PAD_0 /* Ins */
#define PAD_MID PAD_5 /* Middle key */
#define PAD_DEL PAD_DOT /* Del */
/************************************************************************/
/* Stucture Definition */
/************************************************************************/
/* Keyboard structure, 1 per console. */
struct kb_inbuf {
char* p_head; /* 指向緩衝區中下一個空閒位置 */
char* p_tail; /* 指向鍵盤任務應處理的字節 */
int count; /* 緩衝區中共有多少字節 */
char buf[KB_IN_BYTES]; /* 緩衝區 */
};
#endif /* _ORANGES_KEYBOARD_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 seg2phys(u16 seg);
/* klib.c */
PUBLIC void delay(int time);
PUBLIC void disp_int(int input);
PUBLIC char * itoa(char * str, int num);
/* kernel.asm */
PUBLIC void restart();
/* main.c */
PUBLIC int get_ticks();
PUBLIC void TestA();
PUBLIC void TestB();
PUBLIC void TestC();
PUBLIC void panic(const char *fmt, ...);
/* i8259.c */
PUBLIC void init_8259A();
PUBLIC void put_irq_handler(int irq, irq_handler handler);
PUBLIC void spurious_irq(int irq);
/* clock.c */
PUBLIC void clock_handler(int irq);
PUBLIC void init_clock();
PUBLIC void milli_delay(int milli_sec);
/* kernel/hd.c */
PUBLIC void task_hd();
PUBLIC void hd_handler(int irq);
/* keyboard.c */
PUBLIC void init_keyboard();
PUBLIC void keyboard_read(TTY* p_tty);
/* tty.c */
PUBLIC void task_tty();
PUBLIC void in_process(TTY* p_tty, u32 key);
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, ...);
/* console.c */
PUBLIC void out_char(CONSOLE* p_con, char ch);
PUBLIC void scroll_screen(CONSOLE* p_con, int direction);
PUBLIC void select_console(int nr_console);
PUBLIC void init_screen(TTY* p_tty);
PUBLIC int is_current_console(CONSOLE* p_con);
/* printf.c */
PUBLIC int printf(const char *fmt, ...);
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, ...);
/* 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/sys/tty.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tty.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_TTY_H_
#define _ORANGES_TTY_H_
#define TTY_IN_BYTES 256 /* tty input queue size */
#define TTY_OUT_BUF_LEN 2 /* tty output buffer size */
struct s_tty;
struct s_console;
/* TTY */
typedef struct s_tty
{
u32 ibuf[TTY_IN_BYTES]; /* TTY input buffer */
u32* ibuf_head; /* the next free slot */
u32* ibuf_tail; /* the val to be processed by TTY */
int ibuf_cnt; /* how many */
int tty_caller;
int tty_procnr;
void* tty_req_buf;
int tty_left_cnt;
int tty_trans_cnt;
struct s_console * console;
}TTY;
#endif /* _ORANGES_TTY_H_ */
kernel/clock.c
/*************************************************************************//**
*****************************************************************************
* @file clock.c
* @brief
* @author Forrest Y. Yu
* @date 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"
/*****************************************************************************
* clock_handler
*****************************************************************************/
/**
* <Ring 0> This routine handles the clock interrupt generated by 8253/8254
* programmable interval timer.
*
* @param irq The IRQ nr, unused here.
*****************************************************************************/
PUBLIC void clock_handler(int irq)
{
if (++ticks >= MAX_TICKS)
ticks = 0;
if (p_proc_ready->ticks)
p_proc_ready->ticks--;
if (key_pressed)
inform_int(TASK_TTY);
if (k_reenter != 0) {
return;
}
if (p_proc_ready->ticks > 0) {
return;
}
schedule();
}
/*****************************************************************************
* milli_delay
*****************************************************************************/
/**
* <Ring 1~3> Delay for a specified amount of time.
*
* @param milli_sec How many milliseconds to delay.
*****************************************************************************/
PUBLIC void milli_delay(int milli_sec)
{
int t = get_ticks();
while(((get_ticks() - t) * 1000 / HZ) < milli_sec) {}
}
/*****************************************************************************
* init_clock
*****************************************************************************/
/**
* <Ring 0> Initialize 8253/8254 PIT (Programmable Interval Timer).
*
*****************************************************************************/
PUBLIC void init_clock()
{
/* 初始化 8253 PIT */
out_byte(TIMER_MODE, RATE_GENERATOR);
out_byte(TIMER0, (u8) (TIMER_FREQ/HZ) );
out_byte(TIMER0, (u8) ((TIMER_FREQ/HZ) >> 8));
put_irq_handler(CLOCK_IRQ, clock_handler); /* 设定时钟中断处理程序 */
enable_irq(CLOCK_IRQ); /* 让8259A可以接收时钟中断 */
}
kernel/console.c
/*************************************************************************//**
*****************************************************************************
* @file console.c
* @brief Manipulate the console.
* @author Forrest Y. Yu
* @date 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 "keyboard.h"
#include "proto.h"
/* #define __TTY_DEBUG__ */
/* local routines */
PRIVATE void set_cursor(unsigned int position);
PRIVATE void set_video_start_addr(u32 addr);
PRIVATE void flush(CONSOLE* con);
PRIVATE void w_copy(unsigned int dst, const unsigned int src, int size);
PRIVATE void clear_screen(int pos, int len);
/*****************************************************************************
* init_screen
*****************************************************************************/
/**
* Initialize the console of a certain tty.
*
* @param tty Whose console is to be initialized.
*****************************************************************************/
PUBLIC void init_screen(TTY* tty)
{
int nr_tty = tty - tty_table;
tty->console = console_table + nr_tty;
/*
* NOTE:
* variables related to `position' and `size' below are
* in WORDs, but not in BYTEs.
*/
int v_mem_size = V_MEM_SIZE >> 1; /* size of Video Memory */
int size_per_con = v_mem_size / NR_CONSOLES;
tty->console->orig = nr_tty * size_per_con;
tty->console->con_size = size_per_con / SCR_WIDTH * SCR_WIDTH;
tty->console->cursor = tty->console->crtc_start = tty->console->orig;
tty->console->is_full = 0;
if (nr_tty == 0) {
tty->console->cursor = disp_pos / 2;
disp_pos = 0;
}
else {
/*
* `?' in this string will be replaced with 0, 1, 2, ...
*/
const char prompt[] = "[TTY #?]\n";
const char * p = prompt;
for (; *p; p++)
out_char(tty->console, *p == '?' ? nr_tty + '0' : *p);
}
set_cursor(tty->console->cursor);
}
/*****************************************************************************
* out_char
*****************************************************************************/
/**
* Print a char in a certain console.
*
* @param con The console to which the char is printed.
* @param ch The char to print.
*****************************************************************************/
PUBLIC void out_char(CONSOLE* con, char ch)
{
u8* pch = (u8*)(V_MEM_BASE + con->cursor * 2);
assert(con->cursor - con->orig < con->con_size);
/*
* calculate the coordinate of cursor in current console (not in
* current screen)
*/
int cursor_x = (con->cursor - con->orig) % SCR_WIDTH;
int cursor_y = (con->cursor - con->orig) / SCR_WIDTH;
switch(ch) {
case '\n':
con->cursor = con->orig + SCR_WIDTH * (cursor_y + 1);
break;
case '\b':
if (con->cursor > con->orig) {
con->cursor--;
*(pch - 2) = ' ';
*(pch - 1) = DEFAULT_CHAR_COLOR;
}
break;
default:
*pch++ = ch;
*pch++ = DEFAULT_CHAR_COLOR;
con->cursor++;
break;
}
if (con->cursor - con->orig >= con->con_size) {
cursor_x = (con->cursor - con->orig) % SCR_WIDTH;
cursor_y = (con->cursor - con->orig) / SCR_WIDTH;
int cp_orig = con->orig + (cursor_y + 1) * SCR_WIDTH - SCR_SIZE;
w_copy(con->orig, cp_orig, SCR_SIZE - SCR_WIDTH);
con->crtc_start = con->orig;
con->cursor = con->orig + (SCR_SIZE - SCR_WIDTH) + cursor_x;
clear_screen(con->cursor, SCR_WIDTH);
if (!con->is_full)
con->is_full = 1;
}
assert(con->cursor - con->orig < con->con_size);
while (con->cursor >= con->crtc_start + SCR_SIZE ||
con->cursor < con->crtc_start) {
scroll_screen(con, SCR_UP);
clear_screen(con->cursor, SCR_WIDTH);
}
flush(con);
}
/*****************************************************************************
* clear_screen
*****************************************************************************/
/**
* Write whitespaces to the screen.
*
* @param pos Write from here.
* @param len How many whitespaces will be written.
*****************************************************************************/
PRIVATE void clear_screen(int pos, int len)
{
u8 * pch = (u8*)(V_MEM_BASE + pos * 2);
while (--len >= 0) {
*pch++ = ' ';
*pch++ = DEFAULT_CHAR_COLOR;
}
}
/*****************************************************************************
* is_current_console
*****************************************************************************/
/**
* Uses `nr_current_console' to determine if a console is the current one.
*
* @param con Ptr to console.
*
* @return TRUE if con is the current console.
*****************************************************************************/
PUBLIC int is_current_console(CONSOLE* con)
{
return (con == &console_table[current_console]);
}
/*****************************************************************************
* set_cursor
*****************************************************************************/
/**
* Display the cursor by setting CRTC (6845 compatible) registers.
*
* @param position Position of the cursor based on the beginning of the video
* memory. Note that it counts in WORDs, not in BYTEs.
*****************************************************************************/
PRIVATE void set_cursor(unsigned int position)
{
disable_int();
out_byte(CRTC_ADDR_REG, CURSOR_H);
out_byte(CRTC_DATA_REG, (position >> 8) & 0xFF);
out_byte(CRTC_ADDR_REG, CURSOR_L);
out_byte(CRTC_DATA_REG, position & 0xFF);
enable_int();
}
/*****************************************************************************
* set_video_start_addr
*****************************************************************************/
/**
* Routine for hardware screen scrolling.
*
* @param addr Offset in the video memory.
*****************************************************************************/
PRIVATE void set_video_start_addr(u32 addr)
{
disable_int();
out_byte(CRTC_ADDR_REG, START_ADDR_H);
out_byte(CRTC_DATA_REG, (addr >> 8) & 0xFF);
out_byte(CRTC_ADDR_REG, START_ADDR_L);
out_byte(CRTC_DATA_REG, addr & 0xFF);
enable_int();
}
/*****************************************************************************
* select_console
*****************************************************************************/
/**
* Select a console as the current.
*
* @param nr_console Console nr, range in [0, NR_CONSOLES-1].
*****************************************************************************/
PUBLIC void select_console(int nr_console)
{
if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) return;
flush(&console_table[current_console = nr_console]);
}
/*****************************************************************************
* scroll_screen
*****************************************************************************/
/**
* Scroll the screen.
*
* Note that scrolling UP means the content of the screen will go upwards, so
* that the user can see lines below the bottom. Similarly scrolling DOWN means
* the content of the screen will go downwards so that the user can see lines
* above the top.
*
* When there is no line below the bottom of the screen, scrolling UP takes no
* effects; when there is no line above the top of the screen, scrolling DOWN
* takes no effects.
*
* @param con The console whose screen is to be scrolled.
* @param dir SCR_UP : scroll the screen upwards;
* SCR_DN : scroll the screen downwards
*****************************************************************************/
PUBLIC void scroll_screen(CONSOLE* con, int dir)
{
/*
* variables below are all in-console-offsets (based on con->orig)
*/
int oldest; /* addr of the oldest available line in the console */
int newest; /* .... .. ... latest ......... .... .. ... ....... */
int scr_top;/* position of the top of current screen */
newest = (con->cursor - con->orig) / SCR_WIDTH * SCR_WIDTH;
oldest = con->is_full ? (newest + SCR_WIDTH) % con->con_size : 0;
scr_top = con->crtc_start - con->orig;
if (dir == SCR_DN) {
if (!con->is_full && scr_top > 0) {
con->crtc_start -= SCR_WIDTH;
}
else if (con->is_full && scr_top != oldest) {
if (con->cursor - con->orig >= con->con_size - SCR_SIZE) {
if (con->crtc_start != con->orig)
con->crtc_start -= SCR_WIDTH;
}
else if (con->crtc_start == con->orig) {
scr_top = con->con_size - SCR_SIZE;
con->crtc_start = con->orig + scr_top;
}
else {
con->crtc_start -= SCR_WIDTH;
}
}
}
else if (dir == SCR_UP) {
if (!con->is_full && newest >= scr_top + SCR_SIZE) {
con->crtc_start += SCR_WIDTH;
}
else if (con->is_full && scr_top + SCR_SIZE - SCR_WIDTH != newest) {
if (scr_top + SCR_SIZE == con->con_size)
con->crtc_start = con->orig;
else
con->crtc_start += SCR_WIDTH;
}
}
else {
assert(dir == SCR_DN || dir == SCR_UP);
}
flush(con);
}
/*****************************************************************************
* flush
*****************************************************************************/
/**
* Set the cursor and starting address of a console by writing the
* CRT Controller Registers.
*
* @param con The console to be set.
*****************************************************************************/
PRIVATE void flush(CONSOLE* con)
{
if (is_current_console(con)) {
set_cursor(con->cursor);
set_video_start_addr(con->crtc_start);
}
#ifdef __TTY_DEBUG__
int lineno = 0;
for (lineno = 0; lineno < con->con_size / SCR_WIDTH; lineno++) {
u8 * pch = (u8*)(V_MEM_BASE +
(con->orig + (lineno + 1) * SCR_WIDTH) * 2
- 4);
*pch++ = lineno / 10 + '0';
*pch++ = RED_CHAR;
*pch++ = lineno % 10 + '0';
*pch++ = RED_CHAR;
}
#endif
}
/*****************************************************************************
* w_copy
*****************************************************************************/
/**
* Copy data in WORDS.
*
* Note that the addresses of dst and src are not pointers, but integers, 'coz
* in most cases we pass integers into it as parameters.
*
* @param dst Addr of destination.
* @param src Addr of source.
* @param size How many words will be copied.
*****************************************************************************/
PRIVATE void w_copy(unsigned int dst, const unsigned int src, int size)
{
phys_copy((void*)(V_MEM_BASE + (dst << 1)),
(void*)(V_MEM_BASE + (src << 1)),
size << 1);
}
kernel/keyboard.c
/*************************************************************************//**
*****************************************************************************
* @file keyboard.c
* @brief
* @author Forrest Y. Yu
* @date 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 "keyboard.h"
#include "keymap.h"
#include "proto.h"
PRIVATE struct kb_inbuf kb_in;
PRIVATE int code_with_E0;
PRIVATE int shift_l; /* l shift state */
PRIVATE int shift_r; /* r shift state */
PRIVATE int alt_l; /* l alt state */
PRIVATE int alt_r; /* r left state */
PRIVATE int ctrl_l; /* l ctrl state */
PRIVATE int ctrl_r; /* l ctrl state */
PRIVATE int caps_lock; /* Caps Lock */
PRIVATE int num_lock; /* Num Lock */
PRIVATE int scroll_lock; /* Scroll Lock */
PRIVATE int column;
PRIVATE u8 get_byte_from_kb_buf();
PRIVATE void set_leds();
PRIVATE void kb_wait();
PRIVATE void kb_ack();
/*****************************************************************************
* keyboard_handler
*****************************************************************************/
/**
* <Ring 0> Handles the interrupts generated by the keyboard controller.
*
* @param irq The IRQ corresponding to the keyboard, unused here.
*****************************************************************************/
PUBLIC void keyboard_handler(int irq)
{
u8 scan_code = in_byte(KB_DATA);
if (kb_in.count < KB_IN_BYTES) {
*(kb_in.p_head) = scan_code;
kb_in.p_head++;
if (kb_in.p_head == kb_in.buf + KB_IN_BYTES)
kb_in.p_head = kb_in.buf;
kb_in.count++;
}
key_pressed = 1;
}
/*****************************************************************************
* init_keyboard
*****************************************************************************/
/**
* <Ring 1> Initialize some variables and set keyboard interrupt handler.
*
*****************************************************************************/
PUBLIC void init_keyboard()
{
kb_in.count = 0;
kb_in.p_head = kb_in.p_tail = kb_in.buf;
shift_l = shift_r = 0;
alt_l = alt_r = 0;
ctrl_l = ctrl_r = 0;
caps_lock = 0;
num_lock = 1;
scroll_lock = 0;
column = 0;
set_leds();
put_irq_handler(KEYBOARD_IRQ, keyboard_handler);
enable_irq(KEYBOARD_IRQ);
}
/*****************************************************************************
* keyboard_read
*****************************************************************************/
/**
* Yes, it is an ugly function.
*
* @todo Re-write this ugly function.
*
* @param tty Which TTY is reading the keyboard input.
*****************************************************************************/
PUBLIC void keyboard_read(TTY* tty)
{
u8 scan_code;
/**
* 1 : make
* 0 : break
*/
int make;
/**
* We use a integer to record a key press.
* For instance, if the key HOME is pressed, key will be evaluated to
* `HOME' defined in keyboard.h.
*/
u32 key = 0;
/**
* This var points to a row in keymap[]. I don't use two-dimension
* array because I don't like it.
*/
u32* keyrow;
while (kb_in.count > 0) {
code_with_E0 = 0;
scan_code = get_byte_from_kb_buf();
/* parse the scan code below */
if (scan_code == 0xE1) {
int i;
u8 pausebreak_scan_code[] = {0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5};
int is_pausebreak = 1;
for (i = 1; i < 6; i++) {
if (get_byte_from_kb_buf() != pausebreak_scan_code[i]) {
is_pausebreak = 0;
break;
}
}
if (is_pausebreak) {
key = PAUSEBREAK;
}
}
else if (scan_code == 0xE0) {
code_with_E0 = 1;
scan_code = get_byte_from_kb_buf();
/* PrintScreen is pressed */
if (scan_code == 0x2A) {
code_with_E0 = 0;
if ((scan_code = get_byte_from_kb_buf()) == 0xE0) {
code_with_E0 = 1;
if ((scan_code = get_byte_from_kb_buf()) == 0x37) {
key = PRINTSCREEN;
make = 1;
}
}
}
/* PrintScreen is released */
else if (scan_code == 0xB7) {
code_with_E0 = 0;
if ((scan_code = get_byte_from_kb_buf()) == 0xE0) {
code_with_E0 = 1;
if ((scan_code = get_byte_from_kb_buf()) == 0xAA) {
key = PRINTSCREEN;
make = 0;
}
}
}
}
if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) {
int caps;
/* make or break */
make = (scan_code & FLAG_BREAK ? 0 : 1);
keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS];
column = 0;
caps = shift_l || shift_r;
if (caps_lock &&
keyrow[0] >= 'a' && keyrow[0] <= 'z')
caps = !caps;
if (caps)
column = 1;
if (code_with_E0)
column = 2;
key = keyrow[column];
switch(key) {
case SHIFT_L:
shift_l = make;
break;
case SHIFT_R:
shift_r = make;
break;
case CTRL_L:
ctrl_l = make;
break;
case CTRL_R:
ctrl_r = make;
break;
case ALT_L:
alt_l = make;
break;
case ALT_R:
alt_l = make;
break;
case CAPS_LOCK:
if (make) {
caps_lock = !caps_lock;
set_leds();
}
break;
case NUM_LOCK:
if (make) {
num_lock = !num_lock;
set_leds();
}
break;
case SCROLL_LOCK:
if (make) {
scroll_lock = !scroll_lock;
set_leds();
}
break;
default:
break;
}
}
if(make){ /* Break Code is ignored */
int pad = 0;
/* deal with the numpad first */
if ((key >= PAD_SLASH) && (key <= PAD_9)) {
pad = 1;
switch(key) { /* '/', '*', '-', '+',
* and 'Enter' in num pad
*/
case PAD_SLASH:
key = '/';
break;
case PAD_STAR:
key = '*';
break;
case PAD_MINUS:
key = '-';
break;
case PAD_PLUS:
key = '+';
break;
case PAD_ENTER:
key = ENTER;
break;
default:
/* the value of these keys
* depends on the Numlock
*/
if (num_lock) { /* '0' ~ '9' and '.' in num pad */
if (key >= PAD_0 && key <= PAD_9)
key = key - PAD_0 + '0';
else if (key == PAD_DOT)
key = '.';
}
else{
switch(key) {
case PAD_HOME:
key = HOME;
break;
case PAD_END:
key = END;
break;
case PAD_PAGEUP:
key = PAGEUP;
break;
case PAD_PAGEDOWN:
key = PAGEDOWN;
break;
case PAD_INS:
key = INSERT;
break;
case PAD_UP:
key = UP;
break;
case PAD_DOWN:
key = DOWN;
break;
case PAD_LEFT:
key = LEFT;
break;
case PAD_RIGHT:
key = RIGHT;
break;
case PAD_DOT:
key = DELETE;
break;
default:
break;
}
}
break;
}
}
key |= shift_l ? FLAG_SHIFT_L : 0;
key |= shift_r ? FLAG_SHIFT_R : 0;
key |= ctrl_l ? FLAG_CTRL_L : 0;
key |= ctrl_r ? FLAG_CTRL_R : 0;
key |= alt_l ? FLAG_ALT_L : 0;
key |= alt_r ? FLAG_ALT_R : 0;
key |= pad ? FLAG_PAD : 0;
in_process(tty, key);
}
}
}
/*****************************************************************************
* get_byte_from_kb_buf
*****************************************************************************/
/**
* Read a byte from the keyboard buffer.
*
* @return The byte read.
*****************************************************************************/
PRIVATE u8 get_byte_from_kb_buf()
{
u8 scan_code;
while (kb_in.count <= 0) {} /* wait for a byte to arrive */
disable_int(); /* for synchronization */
scan_code = *(kb_in.p_tail);
kb_in.p_tail++;
if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) {
kb_in.p_tail = kb_in.buf;
}
kb_in.count--;
enable_int(); /* for synchronization */
return scan_code;
}
/*****************************************************************************
* kb_wait
*****************************************************************************/
/**
* Wait until the input buffer of 8042 is empty.
*
*****************************************************************************/
PRIVATE void kb_wait() /* 等待 8042 的輸入緩衝區空 */
{
u8 kb_stat;
do {
kb_stat = in_byte(KB_CMD);
} while (kb_stat & 0x02);
}
/*****************************************************************************
* kb_ack
*****************************************************************************/
/**
* Read from the keyboard controller until a KB_ACK is received.
*
*****************************************************************************/
PRIVATE void kb_ack()
{
u8 kb_read;
do {
kb_read = in_byte(KB_DATA);
} while (kb_read != KB_ACK);
}
/*****************************************************************************
* set_leds
*****************************************************************************/
/**
* Set the leds according to: caps_lock, num_lock & scroll_lock.
*
*****************************************************************************/
PRIVATE void set_leds()
{
u8 leds = (caps_lock << 2) | (num_lock << 1) | scroll_lock;
kb_wait();
out_byte(KB_DATA, LED_CODE);
kb_ack();
kb_wait();
out_byte(KB_DATA, leds);
kb_ack();
}
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
*======================================================================*/
PUBLIC int kernel_main()
{
disp_str("-----\"kernel_main\" begins-----\n");
struct task* p_task;
struct proc* p_proc= proc_table;
char* p_task_stack = task_stack + STACK_SIZE_TOTAL;
u16 selector_ldt = SELECTOR_LDT_FIRST;
u8 privilege;
u8 rpl;
int eflags;
int i, j;
int prio;
for (i = 0; i < NR_TASKS+NR_PROCS; i++) {
if (i < NR_TASKS) { /* 任務 */
p_task = task_table + i;
privilege = PRIVILEGE_TASK;
rpl = RPL_TASK;
eflags = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */
prio = 15;
}
else { /* 用戶進程 */
p_task = user_proc_table + (i - NR_TASKS);
privilege = PRIVILEGE_USER;
rpl = RPL_USER;
eflags = 0x202; /* IF=1, bit 2 is always 1 */
prio = 5;
}
strcpy(p_proc->name, p_task->name); /* name of the process */
p_proc->pid = i; /* pid */
p_proc->ldt_sel = selector_ldt;
memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],
sizeof(struct descriptor));
p_proc->ldts[0].attr1 = DA_C | privilege << 5;
memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
sizeof(struct descriptor));
p_proc->ldts[1].attr1 = DA_DRW | privilege << 5;
p_proc->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;
p_proc->regs.eip = (u32)p_task->initial_eip;
p_proc->regs.esp = (u32)p_task_stack;
p_proc->regs.eflags = eflags;
/* p_proc->nr_tty = 0; */
p_proc->p_flags = 0;
p_proc->p_msg = 0;
p_proc->p_recvfrom = NO_TASK;
p_proc->p_sendto = NO_TASK;
p_proc->has_int_msg = 0;
p_proc->q_sending = 0;
p_proc->next_sending = 0;
for (j = 0; j < NR_FILES; j++)
p_proc->filp[j] = 0;
p_proc->ticks = p_proc->priority = prio;
p_task_stack -= p_task->stacksize;
p_proc++;
p_task++;
selector_ldt += 1 << 3;
}
/* proc_table[NR_TASKS + 0].nr_tty = 0; */
/* proc_table[NR_TASKS + 1].nr_tty = 1; */
/* proc_table[NR_TASKS + 2].nr_tty = 1; */
k_reenter = 0;
ticks = 0;
p_proc_ready = proc_table;
init_clock();
init_keyboard();
restart();
while(1){}
}
/*****************************************************************************
* get_ticks
*****************************************************************************/
PUBLIC int get_ticks()
{
MESSAGE msg;
reset_msg(&msg);
msg.type = GET_TICKS;
send_recv(BOTH, TASK_SYS, &msg);
return msg.RETVAL;
}
/*======================================================================*
TestA
*======================================================================*/
void TestA()
{
int fd;
int i, n;
char filename[MAX_FILENAME_LEN+1] = "blah";
const char bufw[] = "abcde";
const int rd_bytes = 3;
char bufr[rd_bytes];
assert(rd_bytes <= strlen(bufw));
/* create */
fd = open(filename, O_CREAT | O_RDWR);
assert(fd != -1);
printl("File created: %s (fd %d)\n", filename, fd);
/* write */
n = write(fd, bufw, strlen(bufw));
assert(n == strlen(bufw));
/* close */
close(fd);
/* open */
fd = open(filename, O_RDWR);
assert(fd != -1);
printl("File opened. fd: %d\n", fd);
/* read */
n = read(fd, bufr, rd_bytes);
assert(n == rd_bytes);
bufr[n] = 0;
printl("%d bytes read: %s\n", n, bufr);
/* close */
close(fd);
char * filenames[] = {"/foo", "/bar", "/baz"};
/* create files */
for (i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
fd = open(filenames[i], O_CREAT | O_RDWR);
assert(fd != -1);
printl("File created: %s (fd %d)\n", filenames[i], fd);
close(fd);
}
char * rfilenames[] = {"/bar", "/foo", "/baz", "/dev_tty0"};
/* remove files */
for (i = 0; i < sizeof(rfilenames) / sizeof(rfilenames[0]); i++) {
if (unlink(rfilenames[i]) == 0)
printl("File removed: %s\n", rfilenames[i]);
else
printl("Failed to remove file: %s\n", rfilenames[i]);
}
spin("TestA");
}
/*======================================================================*
TestB
*======================================================================*/
void TestB()
{
char tty_name[] = "/dev_tty1";
int fd_stdin = open(tty_name, O_RDWR);
assert(fd_stdin == 0);
int fd_stdout = open(tty_name, O_RDWR);
assert(fd_stdout == 1);
char rdbuf[128];
while (1) {
printf("$ ");
int r = read(fd_stdin, rdbuf, 70);
rdbuf[r] = 0;
if (strcmp(rdbuf, "hello") == 0)
printf("hello world!\n");
else
if (rdbuf[0])
printf("{%s}\n", rdbuf);
}
assert(0); /* never arrive here */
}
/*======================================================================*
TestB
*======================================================================*/
void TestC()
{
spin("TestC");
/* assert(0); */
}
/*****************************************************************************
* 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/tty.c
/*************************************************************************//**
*****************************************************************************
* @file kernel/tty.c
* @brief The terminal driver.
*
* As a common driver, TTY accepts these MESSAGEs:
* - DEV_OPEN
* - DEV_READ
* - DEV_WRITE
*
* Besides, it accepts the other two types of MESSAGE from clock_handler() and
* a PROC (who is not FS):
*
* - MESSAGE from clock_handler(): HARD_INT
* - Every time clock interrupt occurs, the clock handler will check whether
* any key has been pressed. If so, it'll invoke inform_int() to wake up
* TTY. It is a special message because it is not from a process -- clock
* handler is not a process.
*
* - MESSAGE from a PROC: TTY_WRITE
* - TTY is a driver. In most cases MESSAGE is passed from a PROC to FS then
* to TTY. For some historical reason, PROC is allowed to pass a TTY_WRITE
* MESSAGE directly to TTY. Thus a PROC can write to a tty directly.
*
* @note Do not get confused by these function names:
* - tty_dev_read() vs tty_do_read()
* - tty_dev_read() reads chars from keyboard buffer
* - tty_do_read() handles DEV_READ message
* - tty_dev_write() vs tty_do_write() vs tty_write()
* - tty_dev_write() returns chars to a process waiting for input
* - tty_do_write() handles DEV_WRITE message
* - tty_write() handles TTY_WRITE message
*
* @author Forrest Y. Yu
* @date 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"
#define TTY_FIRST (tty_table)
#define TTY_END (tty_table + NR_CONSOLES)
PRIVATE void init_tty (TTY* tty);
PRIVATE void tty_dev_read (TTY* tty);
PRIVATE void tty_dev_write (TTY* tty);
PRIVATE void tty_do_read (TTY* tty, MESSAGE* msg);
PRIVATE void tty_do_write (TTY* tty, MESSAGE* msg);
PRIVATE void put_key (TTY* tty, u32 key);
/*****************************************************************************
* task_tty
*****************************************************************************/
/**
* <Ring 1> Main loop of task TTY.
*****************************************************************************/
PUBLIC void task_tty()
{
TTY * tty;
MESSAGE msg;
init_keyboard();
for (tty = TTY_FIRST; tty < TTY_END; tty++)
init_tty(tty);
select_console(0);
while (1) {
for (tty = TTY_FIRST; tty < TTY_END; tty++) {
do {
tty_dev_read(tty);
tty_dev_write(tty);
} while (tty->ibuf_cnt);
}
send_recv(RECEIVE, ANY, &msg);
int src = msg.source;
assert(src != TASK_TTY);
TTY* ptty = &tty_table[msg.DEVICE];
switch (msg.type) {
case DEV_OPEN:
reset_msg(&msg);
msg.type = SYSCALL_RET;
send_recv(SEND, src, &msg);
break;
case DEV_READ:
tty_do_read(ptty, &msg);
break;
case DEV_WRITE:
tty_do_write(ptty, &msg);
break;
case HARD_INT:
/**
* waked up by clock_handler -- a key was just pressed
* @see clock_handler() inform_int()
*/
key_pressed = 0;
continue;
default:
dump_msg("TTY::unknown msg", &msg);
break;
}
}
}
/*****************************************************************************
* init_tty
*****************************************************************************/
/**
* Things to be initialized before a tty can be used:
* -# the input buffer
* -# the corresponding console
*
* @param tty TTY stands for teletype, a cool ancient magic thing.
*****************************************************************************/
PRIVATE void init_tty(TTY* tty)
{
tty->ibuf_cnt = 0;
tty->ibuf_head = tty->ibuf_tail = tty->ibuf;
init_screen(tty);
}
/*****************************************************************************
* in_process
*****************************************************************************/
/**
* keyboard_read() will invoke this routine after having recognized a key press.
*
* @param tty The key press is for whom.
* @param key The integer key with metadata.
*****************************************************************************/
PUBLIC void in_process(TTY* tty, u32 key)
{
if (!(key & FLAG_EXT)) {
put_key(tty, key);
}
else {
int raw_code = key & MASK_RAW;
switch(raw_code) {
case ENTER:
put_key(tty, '\n');
break;
case BACKSPACE:
put_key(tty, '\b');
break;
case UP:
if ((key & FLAG_SHIFT_L) ||
(key & FLAG_SHIFT_R)) { /* Shift + Up */
scroll_screen(tty->console, SCR_DN);
}
break;
case DOWN:
if ((key & FLAG_SHIFT_L) ||
(key & FLAG_SHIFT_R)) { /* Shift + Down */
scroll_screen(tty->console, SCR_UP);
}
break;
case F1:
case F2:
case F3:
case F4:
case F5:
case F6:
case F7:
case F8:
case F9:
case F10:
case F11:
case F12:
if ((key & FLAG_ALT_L) ||
(key & FLAG_ALT_R)) { /* Alt + F1~F12 */
select_console(raw_code - F1);
}
break;
default:
break;
}
}
}
/*****************************************************************************
* put_key
*****************************************************************************/
/**
* Put a key into the in-buffer of TTY.
*
* @callergraph
*
* @param tty To which TTY the key is put.
* @param key The key. It's an integer whose higher 24 bits are metadata.
*****************************************************************************/
PRIVATE void put_key(TTY* tty, u32 key)
{
if (tty->ibuf_cnt < TTY_IN_BYTES) {
*(tty->ibuf_head) = key;
tty->ibuf_head++;
if (tty->ibuf_head == tty->ibuf + TTY_IN_BYTES)
tty->ibuf_head = tty->ibuf;
tty->ibuf_cnt++;
}
}
/*****************************************************************************
* tty_dev_read
*****************************************************************************/
/**
* Get chars from the keyboard buffer if the TTY::console is the `current'
* console.
*
* @see keyboard_read()
*
* @param tty Ptr to TTY.
*****************************************************************************/
PRIVATE void tty_dev_read(TTY* tty)
{
if (is_current_console(tty->console))
keyboard_read(tty);
}
/*****************************************************************************
* tty_dev_write
*****************************************************************************/
/**
* Echo the char just pressed and transfer it to the waiting process.
*
* @param tty Ptr to a TTY struct.
*****************************************************************************/
PRIVATE void tty_dev_write(TTY* tty)
{
while (tty->ibuf_cnt) {
char ch = *(tty->ibuf_tail);
tty->ibuf_tail++;
if (tty->ibuf_tail == tty->ibuf + TTY_IN_BYTES)
tty->ibuf_tail = tty->ibuf;
tty->ibuf_cnt--;
if (tty->tty_left_cnt) {
if (ch >= ' ' && ch <= '~') { /* printable */
out_char(tty->console, ch);
void * p = tty->tty_req_buf +
tty->tty_trans_cnt;
phys_copy(p, (void *)va2la(TASK_TTY, &ch), 1);
tty->tty_trans_cnt++;
tty->tty_left_cnt--;
}
else if (ch == '\b' && tty->tty_trans_cnt) {
out_char(tty->console, ch);
tty->tty_trans_cnt--;
tty->tty_left_cnt++;
}
if (ch == '\n' || tty->tty_left_cnt == 0) {
out_char(tty->console, '\n');
MESSAGE msg;
msg.type = RESUME_PROC;
msg.PROC_NR = tty->tty_procnr;
msg.CNT = tty->tty_trans_cnt;
send_recv(SEND, tty->tty_caller, &msg);
tty->tty_left_cnt = 0;
}
}
}
}
/*****************************************************************************
* tty_do_read
*****************************************************************************/
/**
* Invoked when task TTY receives DEV_READ message.
*
* @note The routine will return immediately after setting some members of
* TTY struct, telling FS to suspend the proc who wants to read. The real
* transfer (tty buffer -> proc buffer) is not done here.
*
* @param tty From which TTY the caller proc wants to read.
* @param msg The MESSAGE just received.
*****************************************************************************/
PRIVATE void tty_do_read(TTY* tty, MESSAGE* msg)
{
/* tell the tty: */
tty->tty_caller = msg->source; /* who called, usually FS */
tty->tty_procnr = msg->PROC_NR; /* who wants the chars */
tty->tty_req_buf = va2la(tty->tty_procnr,
msg->BUF);/* where the chars should be put */
tty->tty_left_cnt = msg->CNT; /* how many chars are requested */
tty->tty_trans_cnt= 0; /* how many chars have been transferred */
msg->type = SUSPEND_PROC;
msg->CNT = tty->tty_left_cnt;
send_recv(SEND, tty->tty_caller, msg);
}
/*****************************************************************************
* tty_do_write
*****************************************************************************/
/**
* Invoked when task TTY receives DEV_WRITE message.
*
* @param tty To which TTY the calller proc is bound.
* @param msg The MESSAGE.
*****************************************************************************/
PRIVATE void tty_do_write(TTY* tty, MESSAGE* msg)
{
char buf[TTY_OUT_BUF_LEN];
char * p = (char*)va2la(msg->PROC_NR, msg->BUF);
int i = msg->CNT;
int j;
while (i) {
int bytes = min(TTY_OUT_BUF_LEN, i);
phys_copy(va2la(TASK_TTY, buf), (void*)p, bytes);
for (j = 0; j < bytes; j++)
out_char(tty->console, buf[j]);
i -= bytes;
p += bytes;
}
msg->type = SYSCALL_RET;
send_recv(SEND, msg->source, msg);
}
/*****************************************************************************
* sys_printx
*****************************************************************************/
/**
* System calls accept four parameters. `printx' needs only two, so it wastes
* the other two.
*
* @note `printx' accepts only one parameter -- `char* s', the other one --
* `struct proc * proc' -- is pushed by kernel.asm::sys_call so that the
* kernel can easily know who invoked the system call.
*
* @note s[0] (the first char of param s) is a magic char. if it equals
* MAG_CH_PANIC, then this syscall was invoked by `panic()', which means
* something goes really wrong and the system is to be halted; if it equals
* MAG_CH_ASSERT, then this syscall was invoked by `assert()', which means
* an assertion failure has occured. @see kernel/main lib/misc.c.
*
* @param _unused1 Ignored.
* @param _unused2 Ignored.
* @param s The string to be printed.
* @param p_proc Caller proc.
*
* @return Zero if success.
*****************************************************************************/
PUBLIC int sys_printx(int _unused1, int _unused2, char* s, struct proc* p_proc)
{
const char * p;
char ch;
char reenter_err[] = "? k_reenter is incorrect for unknown reason";
reenter_err[0] = MAG_CH_PANIC;
/**
* @note Code in both Ring 0 and Ring 1~3 may invoke printx().
* If this happens in Ring 0, no linear-physical address mapping
* is needed.
*
* @attention The value of `k_reenter' is tricky here. When
* -# printx() is called in Ring 0
* - k_reenter > 0. When code in Ring 0 calls printx(),
* an `interrupt re-enter' will occur (printx() generates
* a software interrupt). Thus `k_reenter' will be increased
* by `kernel.asm::save' and be greater than 0.
* -# printx() is called in Ring 1~3
* - k_reenter == 0.
*/
if (k_reenter == 0) /* printx() called in Ring<1~3> */
p = va2la(proc2pid(p_proc), s);
else if (k_reenter > 0) /* printx() called in Ring<0> */
p = s;
else /* this should NOT happen */
p = reenter_err;
/**
* @note if assertion fails in any TASK, the system will be halted;
* if it fails in a USER PROC, it'll return like any normal syscall
* does.
*/
if ((*p == MAG_CH_PANIC) ||
(*p == MAG_CH_ASSERT && p_proc_ready < &proc_table[NR_TASKS])) {
disable_int();
char * v = (char*)V_MEM_BASE;
const char * q = p + 1; /* +1: skip the magic char */
while (v < (char*)(V_MEM_BASE + V_MEM_SIZE)) {
*v++ = *q++;
*v++ = RED_CHAR;
if (!*q) {
while (((int)v - V_MEM_BASE) % (SCR_WIDTH * 16)) {
/* *v++ = ' '; */
v++;
*v++ = GRAY_CHAR;
}
q = p + 1;
}
}
__asm__ __volatile__("hlt");
}
while ((ch = *p++) != 0) {
if (ch == MAG_CH_PANIC || ch == MAG_CH_ASSERT)
continue; /* skip the magic char */
/* TTY * ptty; */
/* for (ptty = TTY_FIRST; ptty < TTY_END; ptty++) */
/* out_char(ptty->console, ch); /\* output chars to all TTYs *\/ */
out_char(TTY_FIRST->console, ch);
}
//__asm__ __volatile__("nop;jmp 1f;ud2;1: nop");
//__asm__ __volatile__("nop;cli;1: jmp 1b;ud2;nop");
return 0;
}
/*****************************************************************************
* dump_tty_buf
*****************************************************************************/
/**
* For debug only.
*
*****************************************************************************/
PUBLIC void dump_tty_buf()
{
TTY * tty = &tty_table[1];
static char sep[] = "--------------------------------\n";
printl(sep);
printl("head: %d\n", tty->ibuf_head - tty->ibuf);
printl("tail: %d\n", tty->ibuf_tail - tty->ibuf);
printl("cnt: %d\n", tty->ibuf_cnt);
int pid = tty->tty_caller;
printl("caller: %s (%d)\n", proc_table[pid].name, pid);
pid = tty->tty_procnr;
printl("caller: %s (%d)\n", proc_table[pid].name, pid);
printl("req_buf: %d\n", (int)tty->tty_req_buf);
printl("left_cnt: %d\n", tty->tty_left_cnt);
printl("trans_cnt: %d\n", tty->tty_trans_cnt);
printl("--------------------------------\n");
strcpy(sep, "\n");
}
lib/printf.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
printf.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 "keyboard.h"
#include "proto.h"
/******************************************************************************************
可變參數函數調用原理(其中涉及的數字皆為舉例)
===========================================================================================
i = 0x23;
j = 0x78;
char fmt[] = "%x%d";
printf(fmt, i, j);
push j
push i
push fmt
call printf
add esp, 3 * 4
┃ HIGH ┃ ┃ HIGH ┃
┃ ... ┃ ┃ ... ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ ┃ 0x32010┃ '\0' ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
0x3046C┃ 0x78 ┃ 0x3200c┃ d ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
arg = 0x30468┃ 0x23 ┃ 0x32008┃ % ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
0x30464┃ 0x32000 ───╂────┐ 0x32004┃ x ┃
┣━━━━━━━━━━┫ │ ┣━━━━━━━━━━┫
┃ ┃ └──→ 0x32000┃ % ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ ... ┃ ┃ ... ┃
┃ LOW ┃ ┃ LOW ┃
實際上,調用 vsprintf 的情形是這樣的:
vsprintf(buf, 0x32000, 0x30468);
******************************************************************************************/
/*****************************************************************************
* printf
*****************************************************************************/
/**
* The most famous one.
*
* @param fmt The format string
*
* @return The number of chars printed.
*****************************************************************************/
PUBLIC int printf(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);
int c = write(1, buf, i);
assert(c == i);
return i;
}
/*****************************************************************************
* printl
*****************************************************************************/
/**
* low level print
*
* @param fmt The format string
*
* @return The number of chars printed.
*****************************************************************************/
PUBLIC int printl(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);
printx(buf);
return i;
}
lib/syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; syscall.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %include "sconst.inc" INT_VECTOR_SYS_CALL equ 0x90 _NR_printx equ 0 _NR_sendrec equ 1 ; 導出符號 global printx global sendrec bits 32 [section .text] ; ==================================================================================== ; sendrec(int function, int src_dest, MESSAGE* msg); ; ==================================================================================== ; Never call sendrec() directly, call send_recv() instead. sendrec: push ebx ; . push ecx ; > 12 bytes push edx ; / mov eax, _NR_sendrec mov ebx, [esp + 12 + 4] ; function mov ecx, [esp + 12 + 8] ; src_dest mov edx, [esp + 12 + 12] ; p_msg int INT_VECTOR_SYS_CALL pop edx pop ecx pop ebx ret ; ==================================================================================== ; void printx(char* s); ; ==================================================================================== printx: push edx ; 4 bytes mov eax, _NR_printx mov edx, [esp + 4 + 4] ; s int INT_VECTOR_SYS_CALL pop edx ret
include/sys/proc.h
int nr_tty; // 註解
kernel/proc.c
sprintf(info, "nr_tty: 0x%x. ", p->nr_tty); disp_color_str(info, text_color); // 註解
![]() |
| 執行結果(Alt + F2) |
目錄結構
. ├── 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 │ ├── getpid.c │ ├── kliba.asm │ ├── klib.c │ ├── misc.c │ ├── open.c │ ├── printf.c │ ├── read.c │ ├── string.asm │ ├── syscall.asm │ ├── syslog.c │ ├── unlink.c │ ├── vsprintf.c │ └── write.c └── Makefile

留言
張貼留言