TTY任務
在 TTY 任務中執行一個迴圈,此迴圈將輪詢每一個 TTY,處理它的事件,包括從鍵盤緩衝區讀取資料、顯示字元等內容。
- 並非每輪詢到某個 TTY 時,箭頭所對應的全部事件都會發生,只有當某個 TTY 對應的控制台是現在控制台時,它才可以讀取鍵盤緩衝區(虛線)
- TTY 可以對輸入的資料作更多的處理,但在這裡,我們只把它簡化為「顯示」一項。
- 雖然圖中鍵盤和顯示器的畫在 TTY 的外面,但應把鍵盤和顯示器算做每一個 TTY 的一部分,它們是公用的。
執行的過程如上,則輪詢到每個 TTY 不外乎作兩件事:
- 處理輸入:查看是不是現在 TTY,如果是則從鍵盤緩衝區讀取資料
- 處理輸出:如果有要顯示的內容則要顯示它
 |
TTY 任務程式碼示意 |
與先前程式實現的區別在於:
- 每個 TTY 都應該有自己的讀和寫的動作。所以在 keyboard_read() 內部,函數需要了解自己是被哪一個 TTY 使用。我們透過為函數傳入一個參數來作到這一點,此參數指向當前 TTY 的指針。
- 為了讓輸入和輸出分離,被 keyboard_read() 使用的 in_process() 不應該在直接回顯字元,而應該將回顯的任務交給 TTY 來完成,這樣,我們就需要為每個 TTY 建立一塊緩衝區,用以放置將被回顯的字元。
- 每個 TTY 回顯字元時操作的 CONSOLE 是不同的,故每個 TTY 都應該有一個成員來記載其對應的 CONSOLE 資訊。
TTY 結構
#define TTY_IN_BYTES 256 /* tty input queue size */
struct s_console;
/* TTY */
typedef struct s_tty
{
u32 in_buf[TTY_IN_BYTES]; /* TTY 輸入緩衝區 */
u32* p_inbuf_head; /* 指向緩衝區中下一個空閒位置 */
u32* p_inbuf_tail; /* 指向鍵盤任務應處理的鍵值 */
int inbuf_count; /* 緩衝區中已經填充了多少 */
struct s_console * p_console;
} TTY;
CONSOLE 結構
typedef struct s_console
{
unsigned int current_start_addr; /* 當前顯示到了什麼位置 */
unsigned int original_addr; /* 當前控制台對應顯示卡記憶體位置 */
unsigned int v_mem_limit; /* 當前控制台占的顯示卡記憶體大小 */
unsigned int cursor; /* 當前光標位置 */
} CONSOLE;
 |
TTY 任務程式碼示意 |
程式碼
include/console.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
console.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_CONSOLE_H_
#define _ORANGES_CONSOLE_H_
/* CONSOLE */
typedef struct s_console
{
unsigned int current_start_addr; /* 當前顯示到了什麼位置 */
unsigned int original_addr; /* 當前控制台對應顯存位置 */
unsigned int v_mem_limit; /* 當前控制台占的顯存大小 */
unsigned int cursor; /* 當前光標位置 */
}CONSOLE;
#define SCR_UP 1 /* scroll forward */
#define SCR_DN -1 /* scroll backward */
#define SCREEN_SIZE (80 * 25)
#define SCREEN_WIDTH 80
#define DEFAULT_CHAR_COLOR 0x07 /* 0000 0111 黑底白字 */
#endif /* _ORANGES_CONSOLE_H_ */
include/const.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_CONST_H_
#define _ORANGES_CONST_H_
/* EXTERN */
#define EXTERN extern /* EXTERN is defined as extern except in global.c */
/* 函數類型 */
#define PUBLIC /* PUBLIC is the opposite of PRIVATE */
#define PRIVATE static /* PRIVATE x limits the scope of x */
/* 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 | 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
/* 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 */
/* system call */
#define NR_SYS_CALL 1
#endif /* _ORANGES_CONST_H_ */
include/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 DESCRIPTOR gdt[GDT_SIZE];
EXTERN u8 idt_ptr[6]; // 0~15:Limit 16~47:Base
EXTERN GATE idt[IDT_SIZE];
EXTERN u32 k_reenter;
EXTERN TSS tss;
EXTERN PROCESS* p_proc_ready;
EXTERN int nr_current_console;
extern PROCESS proc_table[];
extern char task_stack[];
extern TASK task_table[];
extern irq_handler irq_table[];
extern TTY tty_table[];
extern CONSOLE console_table[];
include/proto.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* klib.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);
/* protect.c */
PUBLIC void init_prot();
PUBLIC u32 seg2phys(u16 seg);
/* klib.c */
PUBLIC void delay(int time);
/* kernel.asm */
void restart();
/* main.c */
void TestA();
void TestB();
void TestC();
/* i8259.c */
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();
/* keyboard.c */
PUBLIC void init_keyboard();
/* tty.c */
PUBLIC void task_tty();
PUBLIC void in_process(TTY* p_tty, u32 key);
/* console.c */
PUBLIC void out_char(CONSOLE* p_con, char ch);
PUBLIC void scroll_screen(CONSOLE* p_con, int direction);
/* 以下是系統調用相關 */
/* proc.c */
PUBLIC int sys_get_ticks(); /* sys_call */
/* syscall.asm */
PUBLIC void sys_call(); /* int_handler */
PUBLIC int get_ticks();
include/tty.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tty.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_TTY_H_
#define _ORANGES_TTY_H_
#define TTY_IN_BYTES 256 /* tty input queue size */
struct s_console;
/* TTY */
typedef struct s_tty
{
u32 in_buf[TTY_IN_BYTES]; /* TTY 輸入緩衝區 */
u32* p_inbuf_head; /* 指向緩衝區中下一個空閒位置 */
u32* p_inbuf_tail; /* 指向鍵盤任務應處理的鍵值 */
int inbuf_count; /* 緩衝區中已經填充了多少 */
struct s_console * p_console;
}TTY;
#endif /* _ORANGES_TTY_H_ */
kernel/console.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
console.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*
迴車鍵: 把光標移到第一列
換行鍵: 把光標前進到下一行
*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
PRIVATE void set_cursor(unsigned int position);
PRIVATE void set_video_start_addr(u32 addr);
PRIVATE void flush(CONSOLE* p_con);
/*======================================================================*
init_screen
*======================================================================*/
PUBLIC void init_screen(TTY* p_tty)
{
int nr_tty = p_tty - tty_table;
p_tty->p_console = console_table + nr_tty;
int v_mem_size = V_MEM_SIZE >> 1; /* 顯存總大小 (in WORD) */
int con_v_mem_size = v_mem_size / NR_CONSOLES;
p_tty->p_console->original_addr = nr_tty * con_v_mem_size;
p_tty->p_console->v_mem_limit = con_v_mem_size;
p_tty->p_console->current_start_addr = p_tty->p_console->original_addr;
/* 默認光標位置在最開始處 */
p_tty->p_console->cursor = p_tty->p_console->original_addr;
if (nr_tty == 0) {
/* 第一個控制台沿用原來的光標位置 */
p_tty->p_console->cursor = disp_pos / 2;
disp_pos = 0;
}
else {
out_char(p_tty->p_console, nr_tty + '0');
out_char(p_tty->p_console, '#');
}
set_cursor(p_tty->p_console->cursor);
}
/*======================================================================*
is_current_console
*======================================================================*/
PUBLIC int is_current_console(CONSOLE* p_con)
{
return (p_con == &console_table[nr_current_console]);
}
/*======================================================================*
out_char
*======================================================================*/
PUBLIC void out_char(CONSOLE* p_con, char ch)
{
u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2);
switch(ch) {
case '\n':
if (p_con->cursor < p_con->original_addr +
p_con->v_mem_limit - SCREEN_WIDTH) {
p_con->cursor = p_con->original_addr + SCREEN_WIDTH *
((p_con->cursor - p_con->original_addr) /
SCREEN_WIDTH + 1);
}
break;
case '\b':
if (p_con->cursor > p_con->original_addr) {
p_con->cursor--;
*(p_vmem-2) = ' ';
*(p_vmem-1) = DEFAULT_CHAR_COLOR;
}
break;
default:
if (p_con->cursor <
p_con->original_addr + p_con->v_mem_limit - 1) {
*p_vmem++ = ch;
*p_vmem++ = DEFAULT_CHAR_COLOR;
p_con->cursor++;
}
break;
}
while (p_con->cursor >= p_con->current_start_addr + SCREEN_SIZE) {
scroll_screen(p_con, SCR_DN);
}
flush(p_con);
}
/*======================================================================*
flush
*======================================================================*/
PRIVATE void flush(CONSOLE* p_con)
{
set_cursor(p_con->cursor);
set_video_start_addr(p_con->current_start_addr);
}
/*======================================================================*
set_cursor
*======================================================================*/
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
*======================================================================*/
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
*======================================================================*/
PUBLIC void select_console(int nr_console) /* 0 ~ (NR_CONSOLES - 1) */
{
if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) {
return;
}
nr_current_console = nr_console;
set_cursor(console_table[nr_console].cursor);
set_video_start_addr(console_table[nr_console].current_start_addr);
}
/*======================================================================*
scroll_screen
*----------------------------------------------------------------------*
滾屏.
*----------------------------------------------------------------------*
direction:
SCR_UP : 向上滾屏
SCR_DN : 向下滾屏
其它 : 不做處理
*======================================================================*/
PUBLIC void scroll_screen(CONSOLE* p_con, int direction)
{
if (direction == SCR_UP) {
if (p_con->current_start_addr > p_con->original_addr) {
p_con->current_start_addr -= SCREEN_WIDTH;
}
}
else if (direction == SCR_DN) {
if (p_con->current_start_addr + SCREEN_SIZE <
p_con->original_addr + p_con->v_mem_limit) {
p_con->current_start_addr += SCREEN_WIDTH;
}
}
else{
}
set_video_start_addr(p_con->current_start_addr);
set_cursor(p_con->cursor);
}
kernel/global.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
global.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#define GLOBAL_VARIABLES_HERE
#include "type.h"
#include "const.h"
#include "protect.h"
#include "tty.h"
#include "console.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
PUBLIC PROCESS proc_table[NR_TASKS];
PUBLIC char task_stack[STACK_SIZE_TOTAL];
PUBLIC TASK task_table[NR_TASKS] = {{task_tty, STACK_SIZE_TTY, "tty"},
{TestA, STACK_SIZE_TESTA, "TestA"},
{TestB, STACK_SIZE_TESTB, "TestB"},
{TestC, STACK_SIZE_TESTC, "TestC"}};
PUBLIC TTY tty_table[NR_CONSOLES];
PUBLIC CONSOLE console_table[NR_CONSOLES];
PUBLIC irq_handler irq_table[NR_IRQ];
PUBLIC system_call sys_call_table[NR_SYS_CALL] = {sys_get_ticks};
kernel/keyboard.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
keyboard.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "keyboard.h"
#include "keymap.h"
PRIVATE KB_INPUT 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 int caps_lock; /* Caps Lock */
PRIVATE int num_lock; /* Num Lock */
PRIVATE int scroll_lock; /* Scroll Lock */
PRIVATE u8 get_byte_from_kbuf();
PRIVATE void set_leds();
PRIVATE void kb_wait();
PRIVATE void kb_ack();
/*======================================================================*
keyboard_handler
*======================================================================*/
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++;
}
}
/*======================================================================*
init_keyboard
*======================================================================*/
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;
set_leds();
put_irq_handler(KEYBOARD_IRQ, keyboard_handler);/*設定鍵盤中斷處理程序*/
enable_irq(KEYBOARD_IRQ); /*開鍵盤中斷*/
}
/*======================================================================*
keyboard_read
*======================================================================*/
PUBLIC void keyboard_read(TTY* p_tty)
{
u8 scan_code;
char output[2];
int make; /* 1: make; 0: break. */
u32 key = 0;/* 用一個整型來表示一個鍵。比如,如果 Home 被按下,
* 則 key 值將為定義在 keyboard.h 中的 'HOME'。
*/
u32* keyrow; /* 指向 keymap[] 的某一行 */
if(kb_in.count > 0){
code_with_E0 = 0;
scan_code = get_byte_from_kbuf();
/* 下面開始解析掃描碼 */
if (scan_code == 0xE1) {
int i;
u8 pausebrk_scode[] = {0xE1, 0x1D, 0x45,
0xE1, 0x9D, 0xC5};
int is_pausebreak = 1;
for(i=1;i<6;i++){
if (get_byte_from_kbuf() != pausebrk_scode[i]) {
is_pausebreak = 0;
break;
}
}
if (is_pausebreak) {
key = PAUSEBREAK;
}
}
else if (scan_code == 0xE0) {
scan_code = get_byte_from_kbuf();
/* PrintScreen 被按下 */
if (scan_code == 0x2A) {
if (get_byte_from_kbuf() == 0xE0) {
if (get_byte_from_kbuf() == 0x37) {
key = PRINTSCREEN;
make = 1;
}
}
}
/* PrintScreen 被釋放 */
if (scan_code == 0xB7) {
if (get_byte_from_kbuf() == 0xE0) {
if (get_byte_from_kbuf() == 0xAA) {
key = PRINTSCREEN;
make = 0;
}
}
}
/* 不是PrintScreen, 此時scan_code為0xE0緊跟的那個值. */
if (key == 0) {
code_with_E0 = 1;
}
}
if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) {
/* 首先判斷Make Code 還是 Break Code */
make = (scan_code & FLAG_BREAK ? 0 : 1);
/* 先定位到 keymap 中的行 */
keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS];
column = 0;
int caps = shift_l || shift_r;
if (caps_lock) {
if ((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 */
int pad = 0;
/* 首先處理小鍵盤 */
if ((key >= PAD_SLASH) && (key <= PAD_9)) {
pad = 1;
switch(key) {
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:
if (num_lock &&
(key >= PAD_0) &&
(key <= PAD_9)) {
key = key - PAD_0 + '0';
}
else if (num_lock &&
(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(p_tty, key);
}
}
}
}
/*======================================================================*
get_byte_from_kbuf
*======================================================================*/
PRIVATE u8 get_byte_from_kbuf() /* 從鍵盤緩衝區中讀取下一個字節 */
{
u8 scan_code;
while (kb_in.count <= 0) {} /* 等待下一個字節到來 */
disable_int();
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();
return scan_code;
}
/*======================================================================*
kb_wait
*======================================================================*/
PRIVATE void kb_wait() /* 等待 8042 的輸入緩衝區空 */
{
u8 kb_stat;
do {
kb_stat = in_byte(KB_CMD);
} while (kb_stat & 0x02);
}
/*======================================================================*
kb_ack
*======================================================================*/
PRIVATE void kb_ack()
{
u8 kb_read;
do {
kb_read = in_byte(KB_DATA);
} while (kb_read =! KB_ACK);
}
/*======================================================================*
set_leds
*======================================================================*/
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/clock.c, kernel/i8259.c, kernel/main.c, kernel/proc.c, kernel/protect.c, kernel/start.c, lib/klib.c (新增)
#include "tty.h"
#include "console.h"
kernel/tty.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tty.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.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* p_tty);
PRIVATE void tty_do_read(TTY* p_tty);
PRIVATE void tty_do_write(TTY* p_tty);
PRIVATE void put_key(TTY* p_tty, u32 key);
/*======================================================================*
task_tty
*======================================================================*/
PUBLIC void task_tty()
{
TTY* p_tty;
init_keyboard();
for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
init_tty(p_tty);
}
select_console(0);
while (1) {
for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
tty_do_read(p_tty);
tty_do_write(p_tty);
}
}
}
/*======================================================================*
init_tty
*======================================================================*/
PRIVATE void init_tty(TTY* p_tty)
{
p_tty->inbuf_count = 0;
p_tty->p_inbuf_head = p_tty->p_inbuf_tail = p_tty->in_buf;
init_screen(p_tty);
}
/*======================================================================*
in_process
*======================================================================*/
PUBLIC void in_process(TTY* p_tty, u32 key)
{
char output[2] = {'\0', '\0'};
if (!(key & FLAG_EXT)) {
put_key(p_tty, key);
}
else {
int raw_code = key & MASK_RAW;
switch(raw_code) {
case ENTER:
put_key(p_tty, '\n');
break;
case BACKSPACE:
put_key(p_tty, '\b');
break;
case UP:
if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {
scroll_screen(p_tty->p_console, SCR_DN);
}
break;
case DOWN:
if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {
scroll_screen(p_tty->p_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:
/* Alt + F1~F12 */
if ((key & FLAG_ALT_L) || (key & FLAG_ALT_R)) {
select_console(raw_code - F1);
}
break;
default:
break;
}
}
}
/*======================================================================*
put_key
*======================================================================*/
PRIVATE void put_key(TTY* p_tty, u32 key)
{
if (p_tty->inbuf_count < TTY_IN_BYTES) {
*(p_tty->p_inbuf_head) = key;
p_tty->p_inbuf_head++;
if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES) {
p_tty->p_inbuf_head = p_tty->in_buf;
}
p_tty->inbuf_count++;
}
}
/*======================================================================*
tty_do_read
*======================================================================*/
PRIVATE void tty_do_read(TTY* p_tty)
{
if (is_current_console(p_tty->p_console)) {
keyboard_read(p_tty);
}
}
/*======================================================================*
tty_do_write
*======================================================================*/
PRIVATE void tty_do_write(TTY* p_tty)
{
if (p_tty->inbuf_count) {
char ch = *(p_tty->p_inbuf_tail);
p_tty->p_inbuf_tail++;
if (p_tty->p_inbuf_tail == p_tty->in_buf + TTY_IN_BYTES) {
p_tty->p_inbuf_tail = p_tty->in_buf;
}
p_tty->inbuf_count--;
out_char(p_tty->p_console, ch);
}
}
Makefile
#########################
# Makefile for Orange'S #
#########################
# Entry point of Orange'S
# It must have the same value with 'KernelEntryPointPhyAddr' in load.inc!
ENTRYPOINT = 0x30400
# Offset of entry point in kernel file
# It depends on ENTRYPOINT
ENTRYOFFSET = 0x400
# Programs, flags, etc.
ASM = nasm
DASM = ndisasm
CC = gcc
LD = ld
ASMBFLAGS = -I boot/include/
ASMKFLAGS = -I include/ -f elf
CFLAGS = -I include/ -m32 -c -fno-builtin -fno-stack-protector
LDFLAGS = -s -melf_i386 -Ttext $(ENTRYPOINT)
DASMFLAGS = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)
# This Program
ORANGESBOOT = boot/boot.bin boot/loader.bin
ORANGESKERNEL = kernel.bin
OBJS = kernel/kernel.o kernel/syscall.o kernel/start.o kernel/main.o\
kernel/clock.o kernel/keyboard.o kernel/tty.o kernel/console.o\
kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\
lib/kliba.o lib/klib.o lib/string.o
DASMOUTPUT = kernel.bin.asm
# All Phony Targets
.PHONY : everything final image clean realclean disasm all buildimg
# Default starting position
nop :
@echo "why not \`make image' huh? :)"
everything : $(ORANGESBOOT) $(ORANGESKERNEL)
all : realclean everything
image : realclean everything clean buildimg
clean :
rm -f $(OBJS)
realclean :
rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL)
disasm :
$(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT)
# We assume that "a.img" exists in current folder
buildimg :
mkdir tmp
sleep 1
sudo mount -o loop a.img tmp
sleep 1
sudo cp -fv boot/loader.bin tmp
sudo cp -fv kernel.bin tmp
sleep 1
sudo umount tmp
sleep 1
rmdir tmp
boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
$(ASM) $(ASMBFLAGS) -o $@ $<
boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc
$(ASM) $(ASMBFLAGS) -o $@ $<
$(ORANGESKERNEL) : $(OBJS)
$(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS)
kernel/kernel.o : kernel/kernel.asm include/sconst.inc
$(ASM) $(ASMKFLAGS) -o $@ $<
kernel/syscall.o : kernel/syscall.asm include/sconst.inc
$(ASM) $(ASMKFLAGS) -o $@ $<
kernel/start.o: kernel/start.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
include/global.h
$(CC) $(CFLAGS) -o $@ $<
kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
include/global.h
$(CC) $(CFLAGS) -o $@ $<
kernel/clock.o: kernel/clock.c
$(CC) $(CFLAGS) -o $@ $<
kernel/i8259.o: kernel/i8259.c include/type.h include/const.h include/protect.h include/proto.h
$(CC) $(CFLAGS) -o $@ $<
kernel/global.o: kernel/global.c include/type.h include/const.h include/protect.h include/proc.h \
include/global.h include/proto.h
$(CC) $(CFLAGS) -o $@ $<
kernel/protect.o: kernel/protect.c include/type.h include/const.h include/protect.h include/proc.h include/proto.h \
include/global.h
$(CC) $(CFLAGS) -o $@ $<
kernel/proc.o: kernel/proc.c
$(CC) $(CFLAGS) -o $@ $<
kernel/keyboard.o: kernel/keyboard.c
$(CC) $(CFLAGS) -o $@ $<
kernel/tty.o: kernel/tty.c
kernel/console.o: kernel/console.c
$(CC) $(CFLAGS) -o $@ $<
lib/klib.o: lib/klib.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
include/global.h
$(CC) $(CFLAGS) -o $@ $<
lib/kliba.o : lib/kliba.asm
$(ASM) $(ASMKFLAGS) -o $@ $<
lib/string.o : lib/string.asm
$(ASM) $(ASMKFLAGS) -o $@ $<
 |
執行結果 |
目錄結構
.
├── a.img
├── boot
│ ├── boot.asm
│ ├── include
│ │ ├── fat12hdr.inc
│ │ ├── load.inc
│ │ └── pm.inc
│ └── loader.asm
├── include
│ ├── console.h
│ ├── const.h
│ ├── global.h
│ ├── keyboard.h
│ ├── keymap.h
│ ├── proc.h
│ ├── protect.h
│ ├── proto.h
│ ├── sconst.inc
│ ├── string.h
│ ├── tty.h
│ └── type.h
├── kernel
│ ├── clock.c
│ ├── console.c
│ ├── global.c
│ ├── i8259.c
│ ├── kernel.asm
│ ├── keyboard.c
│ ├── main.c
│ ├── proc.c
│ ├── protect.c
│ ├── start.c
│ ├── syscall.asm
│ └── tty.c
├── lib
│ ├── kliba.asm
│ ├── klib.c
│ └── string.asm
└── Makefile
留言
張貼留言