哈工大李治军老师操作系统笔记【24】:I/O与显示器(Learning OS Concepts By Coding Them !)

30 篇文章 26 订阅

1 设备驱动


在这里插入图片描述


  • 还是从那台计算机开始

1.1 让外设工作起来

  • CPU向控制器中的寄存器,读写数据
  • 控制器完成真正的工作,并向CPU发中断信号
  • 总的来说就是给控制器当中的存储器/寄存器写东西,发一个指令,然后控制器就会处理

在这里插入图片描述


  • 如何让外设执行起来?向控制器发指令,而向控制器发指令,就是查查控制器对应哪个端口或者对应什么东西,所以实际上那么多代码的核心就是out xx, al这样的指令,写这一句的原因就是让外设工作的更简单,当外设完事后就做一下中断的处理,这就是外设工作的全部秘密
  • 就是CPU向外设寄存器发出指令然其工作,完了之后外设再向CPU发出终端请求
  • 向设备控制器的寄存器写不就可以了吗?
  • 需要查寄存器地址、内容的格式和语义操作系统要给用户提供一个简单
    视图,即文件视图,这样方便,因为无论使用什么样的显卡,到操作系统上都是printf("xxx"),所以最终就是形成一个统一的接口

1.2 操纵外设的程序

int
fd open (/dev/xxx");
for (int i = 0; i < 10; i++){
	write(fd, i, sizeof(int));
}
close(fd);
  • 不论什么设备都是open, read, write, close
  • 操作系统为用户提供统一的接口
  • 不同的设备对应不同的设备文件(/dev/xxx)
  • 根据设备文件找到控制器的地址、内容格式等等

1.3 文件视图


在这里插入图片描述


  • orw之类的命令,根据文件名来找到对应的硬件再进行处理
  • 做完了就用中断处理,再回到文件视图里
  • 中断处理:键盘获得了输入字符,放到缓冲区,通知cpu取数据
  • 响应设备中断的 ,比如按下键盘k,就把键盘寄存器里存的按下去的键的映射给操作系统进入内存

1.4 printf


  • 无论访问的是什么设备,都是从文件接口开始,也就是系统调用那部分说过
  • write(1, buf)就是落实下来就是out指令
  • 设备虽然不同,但是接口都是readwrite
  • write通过系统调用,通过int 0x80到了内核里面,执行的就是sys_write
  • 关键在于write(1, )这个1很重要,1决定了是往显示器上写
  • 1对应的形参是int fd,fd是文件描述符,0:标准输入,1:标准输出,2:标准错误
  • file = current->filp[fd];
  • inode = file->f_inode;
  • current就是当前进程,这个数组的第一项就会赋值给文件file
  • 1这个地方对应了一个文件,实际上是1这个地方打开了文件
  • 然后inode就被打开了,inode里面就会取出到底往哪个地方输出
    在这里插入图片描述

  • 既然是1,就要知道1对应的这个文件是什么,从而才能知道file这个文件存放的信息是什么
  • 1是从PCB来的,那么PCB是怎么来的?
  • PCB是fork()创建的时候,拷贝来的
  • copy_process()

  • 都是从父进程那拷贝来的
  • 因为父子进程文件标识fd是数据,不写更改时是不需要复制的。这个的++操作的对象是被操作的文件,目的是文件信息更新(使用者加一)
  • filp[i]是打开文件的指针
  • 所有进程打开的指针都是父进程那里拷贝来的

在这里插入图片描述

  • 果然打开了这个文件,并且拷贝了两份,dup(0),duplicate复制
  • tty0是中断设备

1.5 open系统调用


  • 根据传入文件的名字,会把文件读入进来,最终实际上读入文件的inode
  • inode就是这个文件存放在磁盘上的一些信息
  • 对于设备文件就有对应的是哪个设备,哪个类型这些信息
  • 操作系统得到了这些信息,就会知道往哪里走,但是最终的都是显卡的out
  • open就是形成如下这个链
  • 1实际上就是找到这个dev/tty0对应的inode
  • 这个inode里面肯定有信息,把信息读进来
  • 根据这些信息选择走哪条路,磁盘,显示器等等
    在这里插入图片描述

  • 已经读进来的,看看信息是不是char设备
  • if (I_ISCHR())就是判断是否是字符设备(计算机通常分为字符设备以及块设备)
  • rw_char就是读写,还有既然是char设备也得告诉你是哪一个char设备,inode里面肯定有一个字段存放这个设备到底是第几个设备
  • 如下的i_zone[0]就是给出的char 设备号
  • 所以创建文件就得写进去

在这里插入图片描述


int rw char(int rw, int dev, char *buf, int cnt)
crw_ptr call_addr = crw_table [MAJOR(dev)];
call_addr(rw, dev, buf, cnt); ...}
  • 这个表里面存放的是函数指针
  • 根据这个函数指针,根据你是第几个字符设备就可以找到对应的处理函数

1.6 crw_table


  • 接下来跳到rw_ttyx
  • 终端设备就是键盘和显示器,显示器是写的,键盘是读的
    在这里插入图片描述

1.7 tty->write


在这里插入图片描述


  • *buf工作在用户态内存,从用户态内存取一个字符,放到队列调用函数进行输出
  • 文件视图 -> 字符设备 -> tty字符设备 -> 写到缓冲区 -> 调用函数 -> 提取缓冲区 -> 往各个地方进行写入 -> 接下来就是out
  • fd–>找inode(文件类型)–>确定了是tty(显示器)–>然后转交给驱动程序(由驱动程序写寄存器)
if(c>31&&c<127){
_asm_("mov_b attr, %%ah\n\t"
"movw %%ax, %1\n\t"::"a"(c),
"m"(*(short*)pos):"ax"); pos+=2;}
  • 从这里可以看出,就是al当中是数据,然后ah当中是属性
  • 最后就是mov ax, pos,没有用out,这个pos就是显卡的控制器(或者是外设的)
  • 有的外设控制器可以统一和内存编址,这时候寻址用mov,然后独立编址就用out
  • 现在就能打印到屏幕上了
  • 这些代码形成就是设备驱动

1.8 pos的修改


在这里插入图片描述


  • mov pos就是往显存里面写

  • pos从哪里来?每次写完都要+2,所以要知道初始的pos,在init里面

  • 初始的pos看con_init,里面有两个参数,然后通过这两个参数可以把pos计算出来

  • 然后写出这两个宏,就能知道这两个是什么

  • 90000和90001,这就是第一节课当中的bootsect.s把自己和setup.s移动到内存0x90000处

  • 这就是光标的位置


在这里插入图片描述


2 总结


在这里插入图片描述


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值