开发单片类Unix操作系统-内核系统日志(3)

前面的第二篇文章中,我们开发了使用C库中的字符串的必要函数,在本课程中,我们将完整的调试输出实现到屏幕上-内核系统日志。

目录


  1. 构建系统(make,gcc,gas)。 初始引导(多次引导)。 启动(qemu)。 C库(strcpy,memcpy,strext)。
  2. C库(sprintf,strcpy,strcmp,strtok,va_list ...)。 以内核模式和用户应用程序模式构建库。
  3. 内核系统日志。 显存 输出到终端(kprintf,kpanic,kassert)。
  4. 动态内存,堆(kmalloc,kfree)。
  5. 内存和中断处理的组织(GDT,IDT,PIC,syscall)。 例外情况
  6. 虚拟内存(页面目录和页面表)。
  7. 过程。 策划人 多任务处理。 系统调用(kill,exit,ps)。
  8. 内核(initrd),elf及其内部文件系统。 系统调用(执行)。
  9. 字符设备驱动程序。 系统调用(ioctl,fopen,fread,fwrite)。 C库(fopen,fclose,fprintf,fscanf)。
  10. Shell作为内核的完整程序。
  11. 用户保护模式(ring3)。 任务状态段(tss)。

内核系统日志


在开始之前,我们将需要介绍一些使用I / O端口的有用功能。 程序员的I / O端口与内存中的普通单元没有什么不同,除了有单独的命令可操作它们。 在这些端口上运行的设备已连接到内存总线。 还有一个专用的地址空间。 我们将需要两个汇编器功能来使用输入/输出端口,因为您已经记住,我不容许汇编器插入。

extern u_char asm_read_port(u_char port); extern void asm_write_port(u_int port, u_char data); 

同样,有两个用于控制屏蔽的处理器中断的命令。

 extern void asm_lock(); extern void asm_unlock(); 

好吧,为了在发生致命错误后节省能量,您需要一个处理器停止命令。

 extern void asm_hlt(); 

您还记得,视频内存从0xB8000开始,但是我建议先以纯文本格式将消息写入缓冲区。 然后考虑到颜色属性,只需将该缓冲区复制到视频内存中即可。 为此,我实现了几个实用程序来使用这些缓冲区。 一个缓冲区将用于内核syslog,其余缓冲区将用于虚拟终端。 滚动屏幕也将在缓冲区上执行。 并且只有video_flush函数会将缓冲区复制到视频内存,并使用属性对其进行扩展。

 extern void video_init(); extern void video_disable_cursor(); extern void* video_scroll(char const* video_buff, char* pos); extern char* video_clear(char const* video_buff); extern void video_flush(char const* video_buff); 

现在该介绍最常用的功能了。 当惰性由调试器调试时,最后两个将用于调试内核。 相信我,我在编写此内核时从未使用过调试器。

 extern void kpanic(char* message, ...); extern void kassert(const char* file, u_int line, bool expr); extern void kunreachable(const char* file, u_int line); 

好吧,实际上,是用于内核系统日志的功能。 为了控制屏幕上显示的内容,我在系统日志或用户控制台中输入了kmode功能。 要将系统日志读入缓冲区,将需要klog函数,因为用户进程除非通过系统调用,否则将无法访问内核。

 extern void kclear(); extern void kprintf(const char* format, ...); extern void kvprintf(const char* format, va_list list); extern void kmode(bool is_early); extern void klog(char* buf, u_int n); 

我在这里给出了最有趣的功能:

 /* * Api - Scroll video buffer up * Returns new position */ extern void* video_scroll(char const* video_buff, char* pos) { char* ptr = (void*)video_buff; /* scroll up */ for (int i = 1; i < VIDEO_SCREEN_HEIGHT; ++i) { for (int j = 0; j < VIDEO_SCREEN_WIDTH; ++j) { ptr[(i - 1) * VIDEO_SCREEN_WIDTH + j] = ptr[i * VIDEO_SCREEN_WIDTH + j]; } } /* empty last line */ for (int j = 0; j < VIDEO_SCREEN_WIDTH; ++j) { ptr[(VIDEO_SCREEN_HEIGHT - 1) * VIDEO_SCREEN_WIDTH + j] = ' '; } /* move position up */ pos -= VIDEO_SCREEN_WIDTH; return pos; } 

 /* * Api - Print kernel message */ extern void kvprintf(const char* format, va_list list) { char buff[VIDEO_SCREEN_WIDTH]; int len = vsprintf(buff, format, list); for (int i = 0; i < len; ++i) { if (buff[i] != '\n') { kputc(buff[i]); } else { int line_pos = (syslog_pos - syslog) % VIDEO_SCREEN_WIDTH; for (int j = 0; j < VIDEO_SCREEN_WIDTH - line_pos; ++j) { kputc(' '); } } } kflush(); } 

 /* * Put character to syslog */ static void kputc(char ch) { if ((size_t)syslog_pos - (size_t)syslog + 1 < VIDEO_SCREEN_SIZE) { *syslog_pos++ = ch; } else { syslog_pos = video_scroll(syslog, syslog_pos); kputc(ch); } } 

请参阅视频教程中的详细教程。

参考文献


本文的视频教程
源代码 (您需要一个lesson3分支)

参考文献


  1. 詹姆斯·莫洛伊(James Molloy)。 滚动自己的玩具UNIX克隆操作系统。
  2. 祖布科夫。 DOS,Windows,Unix的汇编器
  3. 卡拉什尼科夫。 汇编程序很简单!
  4. Tanenbaum。 操作系统。 实施与开发。
  5. 罗伯特·洛夫(Robert Love)。 Linux内核 开发过程的描述。

Source: https://habr.com/ru/post/zh-CN466765/


All Articles