0%

L26-IO与显示器

  • 在讲完了 CPU 管理和内存管理后,接下来就是 I/O 设备的管理,和前面一样,I/O 设备的管理就是通过对 I/O 设备的使用引出来的。

L26 I/O与显示器

★I/O设备的使用

  • 在讲完了 CPU 管理和内存管理后,接下来就是 I/O 设备的管理,和前面一样,I/O 设备的管理就是通过对 I/O 设备的使用引出来的。

  • 对每个 I/O 设备,都有一个控制器(例如显示器的控制器是显卡),CPU 通过对这些控制器中的寄存器发送指令,就可以让这些控制器控制 I/O 设备去做指令所要求做的事,这时 CPU 就可以去做别的事情了;等到设备做完了指令所要求做的事后,就会向 CPU 发出中断,让 CPU 去做(在 I/O 设备做完指令所要求做的事后)剩下的事情,即中断处理。

    所以 CPU 要做的就是两件事:一是用类似于 out xx.al 的指令让 I/O 设备工作;二是处理 I/O 设备完成指令后发出的中断,进行中断处理。

  • 为了方便 CPU 向设备控制器的寄存器写指令,还需要操作系统给用户提供一个简单的视图——文件视图,来方便用户使用 I/O 设备

    如下面两张图所示,文件视图的作用在于,不论是使用了什么设备,操作系统都为用户提供了统一的接口:openreadwriteclose ,这就方便了用户使用 I/O 设备。

  • ★总结:I/O 设备的使用总结起来就是三件事:

    • CPU 用类似于 out xx.al 的指令让 I/O 设备工作;
    • 操作系统给用户提供一个简单的视图——文件视图,来方便用户使用 I/O 设备;
    • CPU 处理 I/O 设备完成指令后发出的中断,进行中断处理。

显示器

  • 接下来以显示器显示输出来具体描述 I/O 设备的使用过程(终端设备包括显示器和键盘)。

    首先在用户程序里,通过调用 printf 函数来输出内容,而由前面已知,printf 是一个库函数,将该库函数展开,包含有文件接口 write ,所以一切的故事就从 write 这里展开…

文件视图
  • 前面已经说过,不管对于什么设备,都用 openreadwriteclose 接口来使用设备,所以write 函数那里,就要进行“分支”,根据传进来的参数来确定到底是对什么设备(如键盘、显示器、磁盘等)进行 write 操作,在下图中,就往 write 接口中传进去了参数 “1”,根据传进来的参数 “1” 得到对应的 inode,该 inode 中存储了显示器的信息。

    那么 filp 数组是怎么来的呢?因为对一个进程来说,它都是通过父进程 fork 来的,它的 PCB 的大部分内容都复制了父进程的 PCB,所以就要找到最初的那个进程——进程 0,在 init 函数中,发现有一句 (void) open("/dev/tty0",O_RDWR,0); ,打开了 dev/tty0 文件,而在该文件中,就存储了终端设备的内容。

    于是继续进入 (void) open("/dev/tty0",O_RDWR,0); 语句,通过 sys_open 系统调用看到,inode 正是在这里。

    所以 (void) open("/dev/tty0",O_RDWR,0); 的核心就是建立了这样一个链:PCB 中存储有 filp 数组,该数组中的每一项对应了 file_table 中的每一项 f ,然后 file_table 中的每一项 f 又存储有 inode,inode 中就有设备的信息。

    根据上面所说的内容,就实现了不管对于什么设备,都可以统一用四个系统接口实现对设备的使用。

字符设备接口
  • 在得到了 inode 之后,就需要根据 inode 中的信息进一步确定是要对显示器进行写操作,如下图所示。

    由于显示器是字符设备,所以又跳到 rw_char 函数执行,rw_char 函数有 crw_table ,是一个函数指针表(字符设备接口),根据该函数指针表及传进去的参数找到 rw_ttyx ,由于是写,所以传给形参 rw 的实参为 WRITE,所以调用 tty_write 将要输出的内容存储到缓冲中。

tty_write和con_write
  • 最后真正开始往显示器写入要输出的内容,**tty_write 是将数据写到缓冲区里,而 con_write 则是从缓冲区中读取数据,真正输出到显示器上**。

  • 下面两张图是关于 pos 的内容。

  • 总结:文件视图(系统接口) -> 字符设备接口 -> tty_write-> 缓冲区 -> con_write 从缓冲区中读取数据并输出

---------------The End---------------