L26 IO与显示器.pdf
操操作作系系统统Operating Systems L26 I/O与与显显示示器器 printf(Display) - 2 -Operating Systems 继继续续那那台台“计计算算机机” CPU管管理理 内内存存管管理理 磁磁盘盘管管理理 终终端端设设备备管管理理 PCI总总线线 图图形形控控制制器器 IDE控控制制器器 总总线线控控制制器器 CPU-内内存存总总线线 扩扩展展总总线线接接口口 扩扩展展总总线线 并并行行口口 进进程程(fork() 进进程程管管理理 地地址址(*p=7) 虚虚拟拟内内存存 文文件件(open) 文文件件系系统统 设设备备文文件件 设设备备管管理理 - 3 -Operating Systems 让让外外设设工工作作起起来来 PCI总总线线 总总线线控控制制器器 CPU-内内存存总总线线 显显卡卡、键键盘盘发发出出写写命命令令 读读数数据据到到内内存存 向向CPU发发出出中中断断 CPU向向控控制制器器中中的的寄寄存存器器 读读写写数数据据 控控制制器器完完成成真真正正的的工工作作, 并并向向CPU发发中中断断信信号号 写写显显存存 - 4 -Operating Systems 向向设设备备控控制制器器的的寄寄存存器器写写不不就就可可以以了了吗吗? 需需要要查查寄寄存存器器地地址址、内内容容的的格格式式和和语语义义操操作作系系统统要要给给用用户户提提供供一一个个简简单单 视视图图文文件件视视图图,这这样样方方便便 - 5 -Operating Systems 一一段段操操纵纵外外设设的的程程序序 int fd = open(“/dev/xxx”); for (int i = 0; i filpfd; inode = file-f_inode; fd是是找找到到file的的索索引引! current不不陌陌生生吧吧,进进程程 带带动动整整个个系系统统的的视视图图 file的的目目的的是是得得到到inode,显显示示器器信信息息应应该该就就在在这这里里 - 8 -Operating Systems fd=1的的filp从从哪哪里里来来? n因因为为是是被被current指指向向,所所以以是是从从fork中中来来 void main(void) if(!fork() init(); void init(void) open(“dev/tty0”,O_RDWR,0);dup(0);dup(0); execve(/bin/sh,argv,envp) int copy_process(.) *p = *current; for (i=0; ifilpi) f-f_count+; 显显然然是是拷拷贝贝来来的的,那那么么是是谁谁一一开开始始打打开开的的? shell进进程程启启动动了了whoami命命令令,shell是是其其父父进进程程 - 9 -Operating Systems open系系统统调调用用完完成成了了什什么么? 在在linux/fs/open.c中中 int sys_open(const char* filename, int flag) i=open_namei(filename,flag, cuurent-filpfd=f; /第第一一个个空空闲闲的的fd f-f_mode=inode-i_mode; f-f_inode=inode; f-f_count=1; return fd; 解解析析目目录录,找找到到inode! 核核心心就就是是建建立立这这样样一一个个链链 PCB filp file_table inode inode f dev/tty0 0 - 10 -Operating Systems 准准备备好好了了,真真正正向向屏屏幕幕输输出出! 继继续续sys_write! 在在linux/fs/read_write.c中中 int sys_write(unsigned int fd, char *buf,int cnt) inode = file-f_inode; if(S_ISCHR(inode-i_mode) return rw_char(WRITE,inode-i_zone0, buf, cnt); . 转转到到rw_char! 在在linux/fs/char_dev.c中中 int rw_char(int rw, int dev, char *buf, int cnt) crw_ptr call_addr=crw_tableMAJOR(dev); call_addr(rw, dev, buf, cnt); . /dev/tty0的的inode中中的的 信信息息是是字字符符设设备备 - 11 -Operating Systems 看看看看crw_table! static crw_ptr crw_table=.,rw_ttyx,; typedef (*crw_ptr)(int rw, unsigned minor, char *buf, int count) 第第4个个! 再再转转到到tty_write! /实实现现输输出出的的核核心心函函数数 static int rw_ttyx(int rw, unsigned minor, char *buf, int count) return (rw=READ)? tty_read(minor,buf): tty_write(minor,buf); 在在linux/kernel/tty_io.c中中 int tty_write(unsigned channel,char *buf,int nr) struct tty_struct *tty;tty=channel+tty_table; sleep_if_full( . 可可以以猜猜测测:输输出出就就是是 放放入入队队列列! - 12 -Operating Systems 继继续续tty_write这这一一核核心心函函数数 在在linux/kernel/tty_io.c中中 int tty_write(unsigned channel, char *buf, int nr) . char c, *b=buf; while(nr0 if(c=r)PUTCH(13,tty-write_q);continue; if(O_LCUC(tty) c = toupper(c); b+; nr-; PUTCH(c,tty-write_q); /输输出出完完事事或或写写队队列列满满! tty-write(tty); fs:从从用用户户缓缓存存区区读读! tty-write应应该该就就是是真真的的开开始始输输出出屏屏幕幕了了! - 13 -Operating Systems 看看看看tty-write 在在include/linux/tty.h中中 struct tty_struct void (*write)(struct tty_struct *tty); struct tty_queue read_q, write_q; 需需要要看看tty_struct结结构构的的初初始始化化! struct tty_struct tty_table = con_write,0,0,0,0,”,0,0,0,0,”,; 到到了了con_write,真真正正写写显显示示器器! 在在linux/kernel/chr_drv/console.c中中 void con_write(struct tty_struct *tty) GETCH(tty-write_q,c); if(c31 pos+=2; - 14 -Operating Systems 只只有有一一句句话话:mov pos PC/AT机机内内存存区区域域图图 0 x00000 0 xA0000 显显存存 0 xC0000 ROM BIOS VGA ROM BIOS 0 x100000 0 xffffffff pos指指向向显显存存: pos=0 xA0000 完完成成显显示示中中最最核核心心的的秘秘密密就就是是 mov pos, c con_init(); void con_init(void) gotoxy(ORIG_X,ORIG_Y); static inline void gotoxy() pos=origin+y*video_size_ro w +(x<<1); #define ORIG_X (*(unsigned char*)0 x90000) /初初始始光光标标列列号号 #define ORIG_Y (*(unsigned char*)0 x90001) /初初始始光光标标行行号号 - 15 -Operating Systems pos的的修修改改 pos的的修修改改: pos+=2 为为什什么么加加2? 屏屏幕幕上上的的一一个个字字符符在在显显存存中中除除了了字字符符本本身身还还应应该该有有字字符符的的属属性性(如如颜颜色色等等) CGA 彩彩色色图图形形适适 配配器器 0 xb8000 0 xbc000 适适配配器器标标准准内内存存地地址址字字符符属属性性字字节节 BL D7 R D6 G D5 B D4 I D3 R D2 G D1 B D0 闪闪烁烁高高亮亮度度 背背景景色色前前景景色色 Static unsigned char attr=0 x07; _asm_(“movb _attr,%ahnt” “movw %ax, %1nt”:”a”(c),”m”(*(short *)pos):”ax”); 黑黑底底白白字字! console.c中中 - 16 -Operating Systems printf的的整整个个过过程程! 库库函函数数(printf) read_write.c char_dev.c tty设设备备写写(tty_write) 字字符符设设备备接接口口(crw_table) 系系统统调调用用(write) write_q队队列列 显显示示器器写写(con_write) tty_io.c 显显存存 mov pos, c console.c