自制操作系统 - 用户态打印printf

自制操作系统 - 用户态打印printf

Posted by 王富杰 on Monday, February 12, 2024

一、用户态printf

进入用户态之后,就不能再调用printk函数了。内核需要实现printf函数来打印,printf是底层调用了write这个系统调用。

1.1、文件描述符

在linux系统中,有三个文件描述符分别为标准输入,标准输出,标准错误输出,对应表示为0、1、2。打印默认是打印到标准输出,因此需要先定义标准输出:

typedef int32 fd_t;
typedef enum std_fd_t
{
    stdin,
    stdout,
    stderr,
} std_fd_t;

如上所示,文件描述符是一个整型,标准输出,标准输出和标准错误输出通过枚举定义,分别是0, 1, 2。

1.2、write系统调用

printf需要通过write系统调用实现。write系统调用需要传入三个参数,因此还应该实现下三个参数的系统调用:

int32 write(fd_t fd, char *buf, u32 len)
{
    return _syscall3(SYS_NR_WRITE, fd, (u32)buf, len);
}

_syscall3为三个参数的系统调用,我们这里就不再粘贴代码,通过内联汇编实现,和1个参数、2个参数的系统调用类似。当执行系统调用后,将会调用系统调用的中断函数,这是会中断函数是 sys_write

int32 sys_write(fd_t fd, char *buf, u32 len)
{
    if (fd == stdout || fd == stderr)
    {
        return console_write(buf, len);
    }
    // todo
    panic("write!!!!");
    return 0;
}

sys_write 如果写入时标准输出或标准错误输出,就调用console_write打印到控制台,如果部署标准输出就panic,目前我们还未实现文件输出。 当然这是省略了write这个系统调用的初始化过程。最后我们就可以实现printf函数了:

static char buf[1024];

int printf(const char *fmt, ...)
{
    va_list args;
    int i;
    va_start(args, fmt);
    i = vsprintf(buf, fmt, args);
    va_end(args);
    write(stdout, buf, i);
    return i;
}

如上所示,printf和prink一样支持可变参数。获取可变参数列表后,调用write系统调用。

二、打印测试

在晚上printf函数的实现以后,就可以在用户态进行打印了。测试代码如下:

static void real_init_thread()
{
    u32 counter = 0;

    char ch;
    while (true)
    {
        printf("task is in user mode %d\n", counter++);
    }
}

运行该代码,就会在屏幕上持续打印。我们这里再详细说明下内核进入用户态以及系统调用进入内核态,调用结束再回到用户态的过程。

  1. 内核在进行初始化过程中,执行到进程初始化task_init,在进行init进程初始化时调用了task_to_user_mode(real_init_thread)
  2. task_to_user_mode中获取当前进程,即内核进程,修改该进程的栈内容,设置选择子为用户态选择子。申请一页内存并设置栈的esp指向这页内存,eip指向real_init_thread函数
  3. 直接执行中断返回函数,(此处只是模拟中断),返回后进入real_init_threa函数,此时已经进入用户态。
  4. 在内核态中,cs的值为23,即cpu的rpl被设置为3,运行在特权级3上。
  5. 在用户态中,执行printf函数。执行了write系统调用,CPU会自动检测当前的特权级属于用户态,进行特权级提升,栈自动从用户栈跳转到了内核栈,这是cpu硬件完成的,硬件自动 从 TSS(Task State Segment) 中加载 SS0 和 ESP0(内核栈指针),替换当前的用户栈 SS:ESP (SS0 和 ESP0在TSS初始化时就已经指定了)
  6. 进入内核态之后执行中断函数在屏幕上打印内容,中断结束恢复栈,回到用户态。

「真诚赞赏,手留余香」

WangFuJie Blog

真诚赞赏,手留余香

使用微信扫描二维码完成支付