Xv6驱动(三):console

阅读材料

  • Xv6代码:console.c
  • 教材第5章

console驱动

consputc函数

该函数在发送字符前增加了判断:如果是BACKSPACE,则用空格覆盖,否则直接调用uartputc_sync函数

void consputc(int c)
{
	if (c == BACKSPACE)
	{
		// if the user typed backspace, overwrite with a space.
		uartputc_sync('\b');
		uartputc_sync(' ');
		uartputc_sync('\b');
	}
	else
	{
		uartputc_sync(c);
	}
}

consolewrite函数 

该函数用于输出字符,一次一个字符,拷贝自用户/内核空间

  • user_src == 1:用户地址空间
  • user_src == 0:内核地址空间
int consolewrite(int user_src, uint64 src, int n)
{
	int i;

	for (i = 0; i < n; i++)
	{
		char c;
		if (either_copyin(&c, user_src, src + i, 1) == -1)
			break;
		uartputc(c);
	}

	return i;
}

 consoleread函数

该函数实际上是从缓冲区往外读

  1. 先判断缓冲区是否为空,如果为空,则主动调用sleep函数
  2. 如果读到EOF标志,且未达到目标读取字节数,则保存该字符并终止循环
  3. 如果读取到换行符\n,则认为已读取完整行,终止循环。
int consoleread(int user_dst, uint64 dst, int n)
{
	uint target;
	int c;
	char cbuf;

	target = n;
	acquire(&cons.lock);
	while (n > 0)
	{
		// wait until interrupt handler has put some
		// input into cons.buffer.
		while (cons.r == cons.w)
		{
			if (killed(myproc()))
			{
				release(&cons.lock);
				return -1;
			}
			sleep(&cons.r, &cons.lock);
		}

		c = cons.buf[cons.r++ % INPUT_BUF_SIZE];

		if (c == C('D'))
		{ // end-of-file
			if (n < target)
			{
				// Save ^D for next time, to make sure
				// caller gets a 0-byte result.
				cons.r--;
			}
			break;
		}

		// copy the input byte to the user-space buffer.
		cbuf = c;
		if (either_copyout(user_dst, dst, &cbuf, 1) == -1)
			break;

		dst++;
		--n;

		if (c == '\n')
		{
			// a whole line has arrived, return to
			// the user-level read().
			break;
		}
	}
	release(&cons.lock);

	return target - n;
}

consoleintr函数

uartintr函数发现RHR寄存器中有字符时,会调用该函数。

该函数具体功能:

  1. Ctrl+P:打印进程列表
  2. Ctrl+U:只要缓冲区非空或者不到上一个换行符,就不断调用consputc函数进行回退
  3. Ctrl+H:只要缓冲区非空,回退一个字符
  4. 默认情况:将字符显示到控制台,并存入缓冲区;如果缓冲区已满或者读到换行符\EOF,则唤醒等待的进程
void consoleintr(int c)
{
	acquire(&cons.lock);

	switch (c)
	{
	case C('P'): // Print process list.
		procdump();
		break;
	case C('U'): // Kill line.
		while (cons.e != cons.w &&
			   cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n')
		{
			cons.e--;
			consputc(BACKSPACE);
		}
		break;
	case C('H'): // Backspace
	case '\x7f': // Delete key
		if (cons.e != cons.w)
		{
			cons.e--;
			consputc(BACKSPACE);
		}
		break;
	default:
		if (c != 0 && cons.e - cons.r < INPUT_BUF_SIZE)
		{
			c = (c == '\r') ? '\n' : c;

			// echo back to the user.
			consputc(c);

			// store for consumption by consoleread().
			cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;

			if (c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE)
			{
				// wake up consoleread() if a whole line (or end-of-file)
				// has arrived.
				cons.w = cons.e;
				wakeup(&cons.r);
			}
		}
		break;
	}

	release(&cons.lock);
}

consoleinit函数 

  1. 初始化锁
  2. 调用uartinit函数,初始化UART
  3. 注册consolereadconsolewrite函数(这个后续在文件系统里面讲解)
void consoleinit(void)
{
	initlock(&cons.lock, "cons");

	uartinit();

	// connect read and write system calls
	// to consoleread and consolewrite.
	devsw[CONSOLE].read = consoleread;
	devsw[CONSOLE].write = consolewrite;
}

 参考资料

The xv6 Kernel-18 uart.c and console.c_哔哩哔哩_bilibili

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值