早在前面的教程中就已经实现并使用了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号