寫入 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
留言
張貼留言