冬天OS(二十一):内核的 printf

--------------------------------------------------------

printf("_")

--------------------------------------------------------

注意我们的 printf 必须实现为系统调用,因为用户进程没有操作显存的权限,必须通过系统调用跳到高特权级之后由内核来替进程完成任务!

 

我们的思路是这样的,假设有三个进程,我们将进程绑定到 TTY 上,让进程在 TTY 上运行,言外之意就是进程产生的所有输出都将输出到进程所在的 TTY 上(也就是 TTY 所在的控制台上),具体怎么实现呢?进程 PROCESS 结构体有个 nr_tty 成员,指定进程绑定的 TTY 号,这里重点在于 printf 的实现,因为是进程使用 printf ,那么 printf 的输出就必须在调用它的进程所在的 console 上
——printf 运行的时候必须知道自己是被哪个进程调用的,然后根据此进程的 nr_tty 获得此进程基于的 TTY,最后将字符输出到这个 TTY 对应的 console 上!
——当一个进程在运行期间,那么全局变量 p_proc_ready 就指向此进程的 PROCESS 结构,所以进程只要在调用 printf 的时候将 p_proc_ready 传递给 printf ,就能标识是以他的身份调用 printf!
 

PROCESS 结构体:
typedef struct s_proc {
	STACK_FRAME	regs;			/* process' registers saved in stack frame */
	t_16		ldt_sel;		/* selector in gdt giving ldt base and limit*/
	DESCRIPTOR	ldts[LDT_SIZE];		/* local descriptors for code and data */
	int		ticks;			/* remained ticks */
	int		priority;
	t_32		pid;			/* process id passed in from MM */
	char		name[16];		/* name of the process */
	int 		nr_tty;
}PROCESS;
// ----------------------------
// <printf.c>
// Jack Zheng 12.2
// ----------------------------
#include "type.h"
#include "const.h"

int printf(const char *fmt, ...)
{
	int i;
	char buf[256];

	va_list arg = (va_list)((char*)(&fmt) + 4);        
	i = vsprintf(buf, fmt, arg);
	write(buf, i);

	return i;
}
// ----------------------------
// <vsprintf.c>
// Jack Zheng 12.2
// ----------------------------
#include "type.h"
#include "const.h"
#include "string.h"

int vsprintf(char *buf, const char *fmt, va_list args)
{
	char*	p;
	char	tmp[256];
	va_list	p_next_arg = args;

	for (p=buf;*fmt;fmt++) {
		if (*fmt != '%') {
			*p++ = *fmt;
			continue;
		}

		fmt++;

		switch (*fmt) {
		case 'x':
			itoa(tmp, *((int*)p_next_arg));
			strcpy(p, tmp);
			p_next_arg += 4;
			p += strlen(tmp);
			break;
		case 's':
			break;
		default:
			break;
		}
	}

	return (p - buf);
}
; ----------------------------
; <syscall.asm>
; Jack Zheng 11.28
; ----------------------------
%include "sconst.inc"

INT_VECTOR_SYS_CALL	equ	0x90
_NR_get_ticks		equ	0
_NR_write		equ	1	

global	get_ticks
global	write

bits 32
[section .text]

; ----------------------------
; int get_ticks();
; ----------------------------
get_ticks:
	mov	eax, _NR_get_ticks
	int	INT_VECTOR_SYS_CALL
	ret
; ----------------------------

; ----------------------------
; void write(char* buf, int len);
; ----------------------------
write:
	mov	eax, _NR_write
	; can't pass params by stack, because stack will be different after call 'INT'
	mov	ebx, [esp + 4]		; buf
	mov	ecx, [esp + 8]		; len
	int	INT_VECTOR_SYS_CALL
	ret
; ----------------------------
// ----------------------------
// <tty.c>
// Jack Zheng 11.30
// ----------------------------
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

#define TTY_FIRST	(tty_table)
#define TTY_END		(tty_table + NR_CONSOLES)

/* 本文件内函数声明 */
PRIVATE void	init_tty(TTY* p_tty);
PRIVATE void	tty_do_read(TTY* p_tty);
PRIVATE void	tty_do_write(TTY* p_tty);
PRIVATE void 	put_key(TTY* p_tty, t_32 key);

PUBLIC void task_tty()
{
	TTY*	p_tty;

	init_keyboard();

	for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
		init_tty(p_tty);
	}

	// active tty0 in begining!
	select_console(0);

	while (1) {
		for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
			tty_do_read(p_tty);
			tty_do_write(p_tty);
		}
	}
}

PRIVATE void init_tty(TTY* p_tty)
{
	p_tty->inbuf_count = 0;
	p_tty->p_inbuf_head = p_tty->p_inbuf_tail = p_tty->in_buf;

	init_screen(p_tty);
}

PUBLIC void in_process(TTY* p_tty, t_32 key)
{
	if (!(key & FLAG_EXT)) {
		put_key(p_tty, key);
	}
	else {
		int raw_code = key & MASK_RAW;
		switch(raw_code) {
		case ENTER:
			put_key(p_tty, '\n');
			break;
		case BACKSPACE:
			put_key(p_tty, '\b');
			break;
		case UP:
			if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {	/* Shift + Up */
				scroll_screen(p_tty->p_console, SCROLL_SCREEN_UP);
			}
			break;
		case DOWN:
			if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {	/* Shift + Down */
				scroll_screen(p_tty->p_console, SCROLL_SCREEN_DOWN);
			}
			break;
		case F1:
		case F2:
		case F3:
		case F4:
		case F5:
		case F6:
		case F7:
		case F8:
		case F9:
		case F10:
		case F11:
		case F12:
			if ((key & FLAG_ALT_L) || (key & FLAG_ALT_R)) {	/* Alt + F1~F12 */
				select_console(raw_code - F1);
			}
			break;
		default:
			break;
		}
	}
}

PRIVATE void put_key(TTY* p_tty, t_32 key)
{
	if (p_tty->inbuf_count < TTY_IN_BYTES) {
		*(p_tty->p_inbuf_head) = key;
		p_tty->p_inbuf_head++;
		if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES) {
			p_tty->p_inbuf_head = p_tty->in_buf;
		}
		p_tty->inbuf_count++;
	}
}

PRIVATE void tty_do_read(TTY* p_tty)
{
	if (is_current_console(p_tty->p_console)) {
		keyboard_read(p_tty);
	}
}

PRIVATE void tty_do_write(TTY* p_tty)
{
	if (p_tty->inbuf_count) {
		char ch = *(p_tty->p_inbuf_tail);
		p_tty->p_inbuf_tail++;
		if (p_tty->p_inbuf_tail == p_tty->in_buf + TTY_IN_BYTES) {
			p_tty->p_inbuf_tail = p_tty->in_buf;
		}
		p_tty->inbuf_count--;

		out_char(p_tty->p_console, ch);
	}
}

PUBLIC	void tty_write(TTY* p_tty, char* buf, int len){
	char* p = buf;
	int i = len;
	while(i){
		out_char(p_tty->p_console, *p++);
		i--;
	}
}

PUBLIC	int sys_write(char* buf, int len, PROCESS* p_proc){
	tty_write(&tty_table[p_proc->nr_tty], buf, len);
	return 0;
}
·kernel.asm 节选
; ----------------------------
; sys_call
; ----------------------------
sys_call:
	call	save
	; ---
	push	dword [p_proc_ready]			; 将 p_proc_ready 指针的值入栈
	push	ecx
	push	ebx
	; ---
	sti
	call	[sys_call_table + eax * 4]
	add 	esp, 4 * 3
	mov	[esi + EAXREG - P_STACKBASE], eax	; 返回值
	cli
	ret
; ----------------------------

运行:

OK,我们看到 printf 不只是打印字符那么简单,它还牵连出了进程的输出要到进程所在的 TTY 上!

 

PS:毫无疑问这节又是架构的问题(操作系统的涉及充满了架构了问题...)!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柔弱胜刚强.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值