早在前面的教程中就已经实现并使用了printf函数。在编写shell程序(普通外壳程序)时也调用这个函数,就是0x82号中断服务,只不过我们是采用内嵌汇编的形式来调用的:
//调用0x82号中断程序,显示一个数字
int params[2];
params[0] = 1;
params[1] = num;
__asm__ volatile("int $0x82" :: "a"(params));
//调用0x82号中断程序,显示一个字符串
char *str = "Start System Process.";
int params[2];
params[0] = 0;
params[1] = (int) str;
__asm__ volatile("int $0x82" :: "a"(params));
这样的调用方式很不方便易懂。下面我们就来完善putchar函数puts函数和printf函数,让它们为普通程序提供简单方便的使用方式:
/*
* putch : 显示一个字符
* - char ch : 待显示字符
* return : void
*/
void putch(char ch)
{
int params[2];
params[0] = 0;
params[1] = ch;
__asm__ volatile ("int $0x82" :: "a"(params));
}
/*
* putchar : 显示一个字符,只显示可显字符
* - char ch : 待显示字符
* return : void
*/
void putchar(char ch)
{
if ((ch >= 0x20 && ch <= 0x7e) || ch == '\n' || ch == '\t')
{
putch(ch);
}
}
/*
* puts : 显示字符串
* - char *str : 字符串
* return : void
*/
int puts(char *str)
{
int count = 0;
int params[2];
params[0] = 1;
params[1] = (int) str;
params[2] = (int) &count;
__asm__ volatile ("int $0x82" :: "a"(params));
return count;
}
/*
* number_to_str : 将整数转为字符串
* - char *buff : 数据地址
* - int number : 整数
* - int hex : 10进制或16进制
* return : void
*/
void number_to_str(char *buff, int number, int hex)
{
char temp[0x800];
char num[0x20] = "0123456789ABCDEFG";
int i = 0;
int length = 0;
int rem;
char sign = '+';
temp[i++] = '\0';
if (number < 0)
{
sign = '-';
number = 0 - number;
}
else if (number == 0)
{
temp[i++] = '0';
}
while (number > 0)
{
rem = number % hex;
temp[i++] = num[rem];
number = number / hex;
}
if (sign == '-')
{
temp[i++] = sign;
}
length = i;
for (i = length - 1; i >= 0; i--)
{
*buff++ = temp[i];
}
}
/*
* printf : 标准设备显示函数
* - char *fmt : 显示格式
* - ... : 动态参数
* return : int显示字符数
*/
int printf(char *fmt, ...)
{
//显示数字缓冲区
char buff[0x800];
//显示字符串指针
char *str;
//显示字符变量
char ch;
//显示字符总数
int count = 0;
//动态参数
va_list args;
//初始化动态参数
va_init(args, fmt);
//读到\0为结束
while (*fmt != '\0')
{
//格式化标记%
if (*fmt == '%')
{
//显示一个字符
if ('c' == *(fmt + 1))
{
ch = va_arg(args, char);
putchar(ch);
count++;
fmt += 2;
}
//显示字符串
else if ('s' == *(fmt + 1))
{
str = va_arg(args, char*);
count += puts(str);
fmt += 2;
}
//显示整数
else if ('d' == *(fmt + 1))
{
number_to_str(buff, va_arg(args, int), 10);
count += puts(buff);
fmt += 2;
}
//显示无符号16进制整数
else if ('x' == *(fmt + 1))
{
number_to_str(buff, va_arg(args, u32), 16);
count += puts(buff);
fmt += 2;
}
}
//显示普通字符
else
{
putchar(*fmt++);
count++;
}
}
return count;
}
实现过程非常的简单,只不过通过函数内部调用0x82号中断来显示相关内容。再来修改一下sys_stdio中断服务程序:
void sys_stdio(int *params)
{
set_ds(GDT_INDEX_KERNEL_DS);
set_cr3(PAGE_DIR);
u32 cr3 = pcb_cur->tss.cr3;
params = addr_parse(cr3, params);
//type为0显示字符
if (params[0] == 0)
{
putchar((char) params[1]);
}
//type为1显示字符串
else if (params[0] == 1)
{
int *count = (int *) params[2];
count = addr_parse(cr3, count);
char *str = (char *) params[1];
str = addr_parse(cr3, str);
*count = puts(str);
}
set_cr3(cr3);
set_ds(0xf);
}
修改shell程序中显示部分:
//系统进程system.c
int main(int argc, char **args)
{
printf("Start System Process.\n");
for (;;)
{
}
return 0;
}
//进程等待example_sleep.c
int main(int argc, char **args)
{
for (int i = 1; i <= 5; i++)
{
msleep(1000);
printf("Example: sleep %ds.\n", i);
}
return 0;
}
//信号量控制售票example_sem中的售票函数
void sell_ticket(int num)
{
printf("%d\n", num);
}
编译运行程序并查看结果:

源代码的下载地址为:
https https://github.com/magicworldos/lidqos.git git git@github.com:magicworldos/lidqos.git subverion https://github.com/magicworldos/lidqos branch v0.24
Copyright © 2015-2023 问渠网 辽ICP备15013245号