总体
程序b是简单的键盘
程序d加入优化过的tty
程序e加入优化的键盘处理
程序f把task_tty和TestA, TestB, TestC分开产生,一个任务和三个用户进程
程序g加入了一个printf函数
一、基本概率
1.开机时候是80x25文本模式
显存的范围为0xB8000~0xBFFFF,共计32KB。一个屏幕总共25行,每行80个字符,高位表示字符的属性,低位表示字符ASCII码。
2.VGA模式
二、TTY任务
1.TTY结构
Include\tty.h
typedef struct s_tty
{
t_32in_buf[TTY_IN_BYTES];/* TTY 输入缓冲区 */
t_32* p_inbuf_head; /* 指向缓冲区中下一个空闲位置 */
t_32* p_inbuf_tail; /* 指向键盘任务应处理的键值 */
int inbuf_count; /* 缓冲区中已经填充了多少 */
struct s_console * p_console;
}TTY;
2.CONSOLE结构
Include\console.h
typedef struct s_console
{
//struct s_tty* p_tty;
unsigned int current_start_addr; /* 当前显示到了什么位置 */
unsigned int original_addr; /* 当前控制台对应显存位置 */
unsigned int v_mem_limit; /* 当前控制台占的显存大小 */
unsigned int cursor; /* 当前光标位置 */
}CONSOLE;
三、程序e我们多加入一个控制台
按住alt+f1 f2 f3在三个控制台切换
Shift+箭头可以上下滚屏
可以回车和换行
1.kernel/tty.c
/*======================================================================*
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);
}
2.kernel/console.c
/*======================================================================*
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; /* 每个控制台占的显存大小 (in WORD) */
p_tty->p_console->original_addr = nr_tty * con_v_mem_size; /* 当前控制台占的显存开始地址 (in WORD) */
p_tty->p_console->v_mem_limit = con_v_mem_size / SCREEN_WIDTH * SCREEN_WIDTH; /* 当前控制台占的显存大小 (in WORD) */
p_tty->p_console->current_start_addr = p_tty->p_console->original_addr; /* 当前控制台显示到了显存的什么位置 (in WORD) */
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);
}
3.调用控制台切换代码
按下alt+fn做切换工作
kernel/tty.c
/*======================================================================*
in_process
*======================================================================*/
PUBLIC void in_process(TTY* p_tty, t_32 key)
{
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)) { /* Shift + Up */
scroll_screen(p_tty->p_console, SCROLL_SCREEN_UP); 滚屏
}
break;
case DOWN:
if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) { /* Shift + Down */
scroll_screen(p_tty->p_console, SCROLL_SCREEN_DOWN); 滚屏
}
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;
}
}
}
4. 控制台切换代码
kernel/console.c
/*======================================================================*
select_console
*======================================================================*/
PUBLIC void select_console(int nr_console) /* 0 ~ (NR_CONSOLES - 1) */
{
if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) { /* invalid console number */
return;
}
nr_current_console = nr_console;
flush(&console_table[nr_console]);
}
5.使用数字键盘
Kernel\keyboard.c
Caps Lock NumLock Scroll Lock这三个键有点特殊,每一个都对应一个小灯LED,实际上不通过敲击键盘来可以控制这些灯的亮灭,通过写8042的输入缓冲区可以做到这一点。
往0x64读取状态寄存器,得到的值第1位如果是0表示,输入缓冲区为空,可以写数据
PRIVATE void kb_wait() /* 等待 8042 的输入缓冲区空 */
{
t_8 kb_stat;
do {
kb_stat = in_byte(KB_CMD);// #define KB_CMD 0x64
} while (kb_stat & 0x02); //缓冲区是否为空,不为空机箱等待
}
从输入缓冲区读取数据
PRIVATE void kb_ack()
{
t_8 kb_read;
do {
kb_read = in_byte(KB_DATA); //#define KB_DATA 0x60
} while (kb_read =! KB_ACK); // #define KB_ACK 0xFA
}
四、程序f分析
ch7_f_mynote
程序e以后我们有四,TTY,A,B,C 其中ABC是用户只需的,而TTY很重要没有他我们都不能使用键盘
让ABC运行在ring3,任务TTY在ring1层
1. include\proc.h文件
以前是
#define NR_TASKS 4
改成
#define NR_TASKS1
#define NR_PROCS3
2.kernel\global.c
PUBLIC PROCESS proc_table[NR_TASKS + NR_PROCS];
PUBLIC TASK task_table[NR_TASKS] = {{task_tty, STACK_SIZE_TTY, "tty"}};
PUBLIC TASK user_proc_table[NR_PROCS] = {
{TestA, STACK_SIZE_TESTA, "TestA"},
{TestB, STACK_SIZE_TESTB, "TestB"},
{TestC, STACK_SIZE_TESTC, "TestC"}};
3.kernel\main.c
改变了用户进程的特权级,改变了eflags和剥夺了用户进程所有的I/O权限
其余的代码没多少变化