os-xv6分析-设备管理-console.c 代码分析
Console.c 描述了控制台的基本功能
//Console.c 描述了控制台的基本功能
// Console input and output.
// Input is from the keyboard or serial port.
// Output is written to the screen and serial port.
//控制台输入和输出。
//输入来自键盘或串行端口。
//输出被写入屏幕和串行端口。
// 导包
#include "types.h"
#include "defs.h"
#include "param.h"
#include "traps.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "fs.h"
#include "file.h"
#include "memlayout.h"
#include "mmu.h"
#include "proc.h"
#include "x86.h"
// 声明显示输出函数
static void consputc(int);
// 静态变量 panicked
static int panicked = 0;
// 定义cons结构体,描述控制台
static struct {struct spinlock lock; int locking;
} cons;
// 定义函数printint,打印base进制字符 base<= 16
static void
printint(int xx, int base, int sign)
{static char digits[] = "0123456789abcdef";// 定义十六进制字符char buf[16]; int i;uint x;if(sign && (sign = xx < 0)) // 根据sign和xx值判断x为多少x = -xx;elsex = xx;i = 0;do{buf[i++] = digits[x % base]; // x%base余数}while((x /= base) != 0); // 进制转换if(sign) // 判断是否是负数buf[i++] = '-';while(--i >= 0) // 倒序调用显示函数,输出xx的base进制表示consputc(buf[i]);
}
//PAGEBREAK: 50// Print to the console. only understands %d, %x, %p, %s.
// 打印到控制台。仅理解%d、%x、%p、%s。
// 定义打印函数,理解printf中的%d,%x,%p和%s,并输出对应值
void
cprintf(char *fmt, ...)
{int i, c, locking;uint *argp;char *s;locking = cons.locking; // 获取cons的锁标记if(locking) //判断是否被锁,若被锁申请锁acquire(&cons.lock);if (fmt == 0)panic("null fmt"); //无须打印argp = (uint*)(void*)(&fmt + 1); //定义函数for(i = 0; (c = fmt[i] & 0xff) != 0; i++){if(c != '%'){consputc(c); //调用显示函数,显示字符continue;}c = fmt[++i] & 0xff;//取下一个字符if(c == 0)break;switch(c){ //按照条件打印ccase 'd': //数字printint(*argp++, 10, 1); //调用printint打印十进制数字break;case 'x': //十六进制case 'p': // 输出内存地址printint(*argp++, 16, 0);break;case 's': //输出字符穿if((s = (char*)*argp++) == 0)s = "(null)"; //s赋值为nullfor(; *s; s++) //循环调用输出sconsputc(*s); break;case '%':consputc('%'); //打印%break;default:// Print unknown % sequence to sputc('%'); //打印%consputc(c); //打印cbreak;}}if(locking)// 若被锁release(&cons.lock); //释放锁
}void
panic(char *s) //
{int i;uint pcs[10];cli(); //调用命令行界面函数cons.locking = 0; //控制台locking置0// use lapiccpunum so that we can call panic from mycpu()
//使用lapiccpunum,以便我们可以从mycpu()调用paniccprintf("lapicid %d: panic: ", lapicid());// 调用cprintf,输出lapicid //lapicid(): panic:cprintf(s); // 打印字符串scprintf("n"); //换行getcallerpcs(&s, pcs); // 获取调用信息for(i=0; i<10; i++) //输出前10个cprintf(" %p", pcs[i]);panicked = 1; // freeze other CPU //冻结其他CPUfor(;;) // 死循环;
}//PAGEBREAK: 50
// 声明变量
#define BACKSPACE 0x100 //退格键
#define CRTPORT 0x3d4
static ushort *crt = (ushort*)P2V(0xb8000); // CGA memory //CGA存储器
// 对应CGA设备使用的0xb8000地址物理区,通过P2V转换成虚地址
static void
cgaputc(int c) //将显示字符送往CRT显示器
{int pos; //光标变量函数// Cursor position: col + 80*row. //光标位置:列+80*行。outb(CRTPORT, 14); //指出十四号寄存器要被操作pos = inb(CRTPORT+1) << 8; //读14号寄存器,并左移8位outb(CRTPORT, 15); //指出十五号寄存器要被操作pos |= inb(CRTPORT+1); //读15号寄存器,并添加到pos后八位if(c == 'n') //若字符为换行符pos += 80 - pos%80; //光标位置跳到下一行行首else if(c == BACKSPACE){ //若为退格键if(pos > 0) --pos; //如果光标不在首位,则位置回退1} elsecrt[pos++] = (c&0xff) | 0x0700; // black on white //显示字符if(pos < 0 || pos > 25*80) //如果光标位置出错,则输出pos under/overflowpanic("pos under/overflow");if((pos/80) >= 24){ // Scroll up. //换行显示memmove(crt, crt+80, sizeof(crt[0])*23*80);pos -= 80;memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));}outb(CRTPORT, 14); //指出要操作的字节outb(CRTPORT+1, pos>>8);outb(CRTPORT, 15);outb(CRTPORT+1, pos);crt[pos] = ' ' | 0x0700; //显示空
}void
consputc(int c) //显示输出函数
{if(panicked){ //是否出错,若出错,则停止运行,进入死循环cli();for(;;);}if(c == BACKSPACE){ //判断是否是回退键uartputc('b'); uartputc(' '); uartputc('b'); //是通过uarputc函数将空送往串口} else uartputc(c); //否通过uarputc函数将字符送往串口显示cgaputc(c); //CRT显示器显示
}//定义输入缓冲区
#define INPUT_BUF 128
struct {char buf[INPUT_BUF];uint r; // Read index //读指针uint w; // Write index //写指针uint e; // Edit index //编辑指针
} input;#define C(x) ((x)-'@') // Control-x //ctrl 键与其他按键的组合void
consoleintr(int (*getc)(void)) //控制器中断 串口中断传入uartgec函数指针
// 键盘中断传入kbdgetc函数指针
{int c, doprocdump = 0;acquire(&cons.lock); //获得锁while((c = getc()) >= 0){ //读入输入字符switch(c){ //分情况判断case C('P'): // Process listing. //ctrl+P 组合键// procdump() locks cons.lock indirectly; invoke later// procdump()间接锁定cons.lock;稍后调用doprocdump = 1; break;
case C('U'): // Kill line. //ctrl+U 组合键// 循环回退撤销指令执行while(input.e != input.w &&input.buf[(input.e-1) % INPUT_BUF] != 'n'){input.e--;consputc(BACKSPACE); //显示回退键}break;
case C('H'): case 'x7f': // Backspace //ctrl+H组合键//撤回操作if(input.e != input.w){input.e--;consputc(BACKSPACE); //显示回退键}break;default: //写缓存if(c != 0 && input.e-input.r < INPUT_BUF){c = (c == 'r') ? 'n' : c;input.buf[input.e++ % INPUT_BUF] = c; //字符存入循坏缓存区consputc(c); //显示字符// 换行||C(‘D’)|| 编辑指针位置==输入指针+缓冲区大小if(c == 'n' || c == C('D') || input.e == input.r+INPUT_BUF){input.w = input.e; // 写指针赋值为编辑指针值wakeup(&input.r); //唤醒}}break;}}release(&cons.lock); //释放锁if(doprocdump) {procdump(); // now call procdump() wo. cons.lock held现在调用//procdump()wo。消费者锁定}
}int
consoleread(struct inode *ip, char *dst, int n)//从输入缓冲区input.buf[]读入数据,输入缓冲区的唯一“消费者”,通过//cons.lock 自旋锁与此缓冲区的“生产者”(键盘中断,串口代码中断)实现//互斥
{uint target;int c;iunlock(ip); //释放指定inode锁target = n;acquire(&cons.lock); //获得锁while(n > 0){while(input.r == input.w){ //互斥判断if(myproc()->killed){release(&cons.lock); //释放锁ilock(ip);return -1;}sleep(&input.r, &cons.lock); //睡眠}c = input.buf[input.r++ % INPUT_BUF]; //读指定大小的数据if(c == C('D')){ // EOF //结束if(n < target){// Save ^D for next time, to make sure// caller gets a 0-byte result. //保存以备下次使用,以确保调用者得到0字节的结果。input.r--;}break;}*dst++ = c; //写入磁盘--n;if(c == 'n') //换行break;}release(&cons.lock); //释放锁ilock(ip); //获取指定inode锁return target - n; //返回读入数据数量
}int
consolewrite(struct inode *ip, char *buf, int n)
//向控制台设备(文件类型3)文件进行写操作,可以实现输出显示。此文件操//作实际指向consloewrite()函数,通过uartputc函数和cgaputc将输出缓//冲区内容逐个字节输出到CGA显卡和串口终端上。
{int i;iunlock(ip); // 释放指定inode锁acquire(&cons.lock); //获得锁for(i = 0; i < n; i++) // 循坏在控制台显示consputc(buf[i] & 0xff); release(&cons.lock); //释放锁ilock(ip); //获得指定inode锁return n;
}void
consoleinit(void)
{initlock(&cons.lock, "console"); // 初始化自旋锁// 建立文件系统于控制台设备的联系devsw[CONSOLE].write = consolewrite; //写devsw[CONSOLE].read = consoleread; // 读cons.locking = 1; //锁置1ioapicenable(IRQ_KBD, 0); //使能键盘中断
}
本文发布于:2024-01-27 18:03:01,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063497841790.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |