跟我一起写操作系统

    返回首页    发表留言
本文作者:李德强
          第一节 输出函数
 
 

        早在前面的教程中就已经实现并使用了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-2018 问渠网 辽ICP备15013245号