按下键盘后为什么屏幕上就会有输出
短篇合集全文阅读目录-短篇合集500全文目录手机官网-黄直播
短篇合集全文阅读目录-短篇合集500全文目录手机官网-黄直播

黄直播软件永久看的

按下键盘后为什么屏幕上就会有输出

发布日期:2022-01-13 13:15    点击次数:151

书接上回,上回书咱们说到,继内存管理组织 mem_map 和休止描述符外 idt 竖立益之后,吾们又在内存中倒腾出一个新的数据组织 request。

并且把它们都放在了一个数组中。

这是块设备驱动程序与内存缓冲区的桥梁,经过它能够完善地外示一个块设备读写操作要做的事。

吾们不息去下望,tty_init。

void main(void) {     ...     mem_init(main_memory_start,memory_end);     trap_init();     blk_dev_init();     chr_dev_init();     tty_init();     time_init();     sched_init();     buffer_init(buffer_memory_end);     hd_init();     floppy_init();          sti();     move_to_user_mode();     if (!fork()) {init();}     for(;;) pause(); } 

这个手段实走完善之后,吾们将会具备键盘输入到表现器输出字符这个最常用的功能。

掀开这个函数后吾有点慌。

void tty_init(void) {     rs_init();     con_init(); } 

望来这个手段已经多到必要拆成两个子手段了。

掀开第一个手段,还益。

void rs_init(void) {     set_intr_gate(0x24,rs1_interrupt);     set_intr_gate(0x23,rs2_interrupt);     init(tty_table[1].read_q.data);     init(tty_table[2].read_q.data);     outb(inb_p(0x21)&0xE7,0x21); } 

这个手段是串口休止的开启,以及竖立对答的休止处理程序,串口在吾们现在的 PC 机上已经很少用到了,于是这个直接无视,要讲吾也不懂。

望第二个手段,这是重点。代码专门长,有点吓人,吾先把大体框架写出。

void con_init(void) {     ...     if (ORIG_VIDEO_MODE == 7) {         ...         if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {...}         else {...}     } else {         ...         if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {...}         else {...}     }     ... } 

能够望出,专门多的 if else。

这是为了答对差别的表现模式,来分配差别的变量值,那倘若吾们仅仅找出一个表现模式,这些分支就能够只望一个了。 啥是表现模式呢?那吾们得浅易说说表现,一个字符是如何表现在屏幕上的呢?换句话说,倘若你能够肆意操作内存和 CPU 等设备,你如何操作才能使得你的表现器上,表现一个字符‘a’呢?

吾们先望一张图。

内存中有如许一片面区域,是和显存映射的。啥有趣,就是你去上图的这些内存区域中写数据,相等于写在了显存中。而去显存中写数据,就相等于在屏幕上输出文本了。

没错,就是这么浅易。 倘若吾们写这一走汇编语句。

mov [0xB8000],'h' 

后面谁人 h 相等于汇编编辑器帮吾们转换成 ASCII 码的二进制数值,自然吾们也能够直接写。

mov [0xB8000],0x68 

其实就是去内存中 0xB8000 这个位置写了一个值,只要一写,屏幕上就会是如许。

浅易吧,详细说来,这片内存是每两个字节外示一个表现在屏幕上的字符,第一个是字符的编码,第二个是字符的颜色,那吾们先不管颜色,倘若多写几个字符就像如许。

mov [0xB8000],'h' mov [0xB8002],'e' mov [0xB8004],'l' mov [0xB8006],'l' mov [0xB8008],'o' 

此时屏幕上就会是如许。

是不是贼浅易?那吾们回过头望刚刚的代码,吾们就倘若表现模式是吾们现在的这栽文本模式,那条件分支就能够去失踪益多。 代码能够简化成这个样子。

#define ORIG_X          (*(unsigned char *)0x90000) #define ORIG_Y          (*(unsigned char *)0x90001) void con_init(void) {     register unsigned char a;     // 第一片面 获取表现模式有关新闻     video_num_columns = (((*(unsigned short *)0x90006) & 0xff00) >> 8);     video_size_row = video_num_columns * 2;     video_num_lines = 25;     video_page = (*(unsigned short *)0x90004);     video_erase_char = 0x0720;     // 第二片面 显存映射的内存区域      video_mem_start = 0xb8000;     video_port_reg  = 0x3d4;     video_port_val  = 0x3d5;     video_mem_end = 0xba000;     // 第三片面 起伏屏幕操作时的新闻     origin  = video_mem_start;     scr_end = video_mem_start + video_num_lines * video_size_row;     top = 0;     bottom  = video_num_lines;     // 第四片面 定位光标并开启键盘休止     gotoxy(ORIG_X, ORIG_Y);     set_trap_gate(0x21,&keyboard_interrupt);     outb_p(inb_p(0x21)&0xfd,0x21);     a=inb_p(0x61);     outb_p(a|0x80,0x61);     outb(a,0x61); } 

别望这么多,一点都不难。

最先还记不记得之前汇编说话的时候做的做事,存了益多以后要用的数据在内存中。

内存地址 长度(字节) 名称 0x90000 2 光标位置 0x90002 2 扩展内存数 0x90004 2 表现页面 0x90006 1 表现模式 0x90007 1 字符列数 0x90008 2 未知 0x9000A 1 表现内存 0x9000B 1 表近况态 0x9000C 2 显卡特性参数 0x9000E 1 屏幕走数 0x9000F 1 屏幕列数 0x90080 16 硬盘1参数外 0x90090 16 硬盘2参数外 0x901FC 2 根设备号

于是,第一片面获取 0x90006 地址处的数据,就是获取表现模式等有关新闻。

第二片面就是显存映射的内存地址周围,吾们现在倘若是 CGA 类型的文本模式,于是映射的内存是从 0xB8000 到 0xBA000。

第三片面是竖立一些起伏屏幕时必要的参数,定义顶走和底走是那里,这边顶走就是第一走,底走就是末了一走,很相符理。

第四片面是把光标定位到之前保存的光标位置处(取内存地址 0x90000 处的数据),然后竖立并开启键盘休止。

开启键盘休止后,键盘上敲击一个按键后就会触发休止,休止程序就会读键盘码转换成 ASCII 码,然后写到光标处的内存地址,也就相等于去显存写,于是这个键盘敲击的字符就表现在了屏幕上。

这总共详细是怎么做到的呢?吾们先望望吾们干了什么。

1. 吾们现在按照已有新闻已经能够实现去屏幕上的肆意位置写字符了,而且还能指定颜色。

2. 并且,吾们也能批准键盘休止,按照键盘码休止处理程序就能够得知哪个键按下了。

有了这俩功能,那吾们想干嘛还不是作威作福?

益,接下来吾们望望代码是怎么处理的,很浅易。总共的首点,就是第四步的 gotoxy 函数,定位现在光标。

#define ORIG_X          (*(unsigned char *)0x90000) #define ORIG_Y          (*(unsigned char *)0x90001) void con_init(void) {     ...     // 第四片面 定位光标并开启键盘休止     gotoxy(ORIG_X, ORIG_Y);     ... } 

这内里干嘛了呢?

static inline void gotoxy(unsigned int new_x,unsigned int new_y) {    ...    x = new_x;    y = new_y;    pos = origin + y*video_size_row + (x<<1); } 

就是给 x y pos 这三个参数附上了值。

其中 x 外示光标在哪一列,y 外示光标在哪一走,pos 外示按照列号和走号计算出来的内存指针,也就是去这个 pos 指向的地址处写数据,就相等于去限制台的 x 列 y 走处写入字符了,浅易吧?

然后,当你按下键盘后,触发键盘休止,之后的程序调用链是如许的。

_keyboard_interrupt:     ...     call _do_tty_interrupt     ...      void do_tty_interrupt(int tty) {    copy_to_cooked(tty_table+tty); }  void copy_to_cooked(struct tty_struct * tty) {     ...     tty->write(tty);     ... }  // 限制台时 tty 的 write 为 con_write 函数 void con_write(struct tty_struct * tty) {     ...     __asm__("movb _attr,%%ah\n\t"       "movw %%ax,%1\n\t"       ::"a" (c),"m" (*(short *)pos)       :"ax");      pos += 2;      x++;     ... } 

前线的过程不必管,吾们望末了一个函数 con_write 中的关键代码。

__asm__ 内联汇编,就是把键盘输入的字符 c 写入pos 指针指向的内存,相等于去屏幕输出了。

之后两走 pos+=2 和 x++,就是调整所谓的光标。

你望,写入一个字符,最底层,其实就是去内存的某处写个数据,然后趁便调整一下光标。

由此吾们也能够望出,光标的内心,其实就是这边的 x y pos 这仨变量而已。

吾们还能够做换走成绩,当发现光标位置处于某一走的末了时(这个答该很益算吧,吾们都清新屏幕上统统有几走几列了),就把光标计算出一个新值,让其处于下一走的起头。

就一个幼计算公式即可搞定,照样在 con_write 源码处有表现,就是判定列号 x 是否大于了总列数。

void con_write(struct tty_struct * tty) {     ...     if (x>=video_num_columns) {         x -= video_num_columns;         pos -= video_size_row;         lf();   }   ... }  static void lf(void) {    if (y+1<bottom) {       y++;       pos += video_size_row;       return;    }  ... } 

相通的,吾们还能够实现滚屏的成绩,无非就是当检测到光标已经出现在末了一走末了一列了,那就把每一走的字符,都复制到它上一走,其实就是算益哪些内存地址上的值,拷贝到哪些内存地址,就益了。

这边行家本身望源码追求。 于是,有了这个初首化做事,吾们就能够行使这些新闻,弄几个幼算法,实现各栽吾们常见限制台的操作。

或者换句话说,吾们见惯不怪的限制台,回车、换走、删除、滚屏、清屏等操作,其实底层都要实现响答的代码的。 于是 console.c 中的其他手段就是做这个事的,吾们就不睁开每一个功能的手段体了,浅易望望有哪些手段。

// 定位光标的 static inline void gotoxy(unsigned int new_x, unsigned int new_y){} // 滚屏,即内容向上起伏一走 static void scrup(void){} // 光标同列位置下移一走 static void lf(int currcons){} // 光标回到第一列 static void cr(void){} ... // 删除一走 static void delete_line(void){} 

内容众多,但没什么难度,只要理解了基本原理即可了。

OK,整个 console.c 就讲完了,要清新这个文件可是整个内核中代码量最大的文件,可是功能稀奇单一,也都很浅易,主要是处理键盘各栽差别的按键,必要写益多 switch case 等语句,相等麻烦,吾们这边就十足没必要去睁开了,就是个苦力活。 到这边,吾们就正式讲完了 tty_init 的作用。

在此之后,内核代码就能够用它来方便地在限制台输出字符啦!这在之后内核想要在启动过程中通知用户一些新闻,以及后面内核十足竖立首来之后,由用户用 shell 进走操作时手动输入命令,都是能够用到这边的代码的! 让吾们不息向提高发,望下一个被初首化的不利鬼是什么东东。 欲知后事如何,且听下回分解。

本文转载自微信公多号「矮并发编程」,能够经过以下二维码关注。转载本文请有关矮并发编程公多号。本网站已获得矮并发编程的授权。

【编辑保举】

鸿蒙官方战略配相符共建——HarmonyOS技术社区 网络坦然等级珍惜之商用暗号管理手段 郭主任带你轻盈学基本网络通讯原理/思科CCNA/华为HCIA/网络技术 盘点 | 2021年最具影响力的网络坦然事件 一篇文章商议单现在图像中保持拓扑的片面道路网络推想 如何关闭Windows 11中的“搜索网络”终局?