打印调试
为了方便测试数据,需要在控制台进行数据输出。linux内核的控制台输出使用printk.c文件,调用vprintf方法。
vprintf方法可以使用参数列表发送格式化输出到标准输出 stdout。
vprintf方法可以使用C语言格式化输出。
实现stdout输出
为了简单方便,就不使用c标准库的vprintf方法了。重新定义了简单的控制台输出方法。
创建printk文件,订阅打印方法。
字符打印时,需要对回车,换行,tab,空格等字符进行特殊处理
字符打印流程

代码
printk.h
1 2 3 4 5 6 7 8 9 10 11
| void print_char(char ch);
void print_string(char* str);
void print_int16(int16 num);
void print_int32(int32 num);
void print_int64(int64 num);
void print_pointer(uint32 addr);
|
printk.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#include "../include/stdint.h" #include "../include/io.h" #include "../include/printk.h"
#define VGA_BASE 0xB8000 #define ROW 25 #define COL 80
static char printBuf[1024];
uint16 get_cursor() { io_out8(0x3d4, 0x0e); uint8 cursor_high = io_in8(0x3d5); io_out8(0x3d4, 0x0f); uint8 cursor_low = io_in8(0x3d5); return (cursor_high << 8) + (cursor_low & 0xff); }
void set_cursor(uint16 pos) { uint8 cursor_high = pos >> 8; uint8 cursor_low = pos & 0xff; io_out8(0x3d4, 0x0e); io_out8(0x3d5, cursor_high); io_out8(0x3d4, 0x0f); io_out8(0x3d5, cursor_low); }
void print_char(char ch) {
uint16 pos = get_cursor(); char *pvga = (char *)VGA_BASE;
switch (ch) { case 0x0d: pos = (pos / COL) * COL; break; case 0x0a: pos = pos + COL; pos = (pos / COL) * COL; break; case 0x09: pos=pos+4; break; case 0x08: pos--; *(pvga + pos * 2) = 0x00; break; default: *(pvga + pos * 2) = ch; *(pvga + pos * 2 + 1) = 0x17; pos++; } if (pos + 1 > ROW * COL ) { int display = (ROW -1) * COL; pos = pos - COL; for (int i = 0; i < display; i++) { *(pvga + 0x00 + i * 2) = *(pvga + 0xa0 + i * 2); } for (int i = 0; i < COL ; i++) { *(pvga + display * 2 + i * 2) = 0x0; } } set_cursor(pos); }
void print_string(char *chs) { int i = 0; while (*(chs + i) != 0) { print_char(*(chs + i)); i++; } }
void print_int16(int16 num) { int i = 0; char *chs = (char *)printBuf; do { *(chs + i) = (char)(num % 10 + '0'); i++;
} while ((num /= 10) > 0); for (int j = i-1; j >= 0; j--) { print_char(*(chs + j)); *(chs + j) = 0; } }
void print_int32(int32 num) { int i = 0; char *chs = (char *)printBuf; do { *(chs + i) = (char)(num % 10 + '0'); i++;
} while ((num /= 10) > 0); for (int j = i-1 ; j >= 0; j--) { print_char(*(chs + j)); *(chs + j) = 0; } }
void print_int64(int64 num) { }
void print_pointer(uint32 addr) { print_char('0'); print_char('x'); int i = 0; char *chs = (char *)printBuf; do { int ch = addr % 16; if(ch==0x0f) { *(chs + i)='F'; } else if(ch==0x0e) { *(chs + i)='E'; } else if(ch==0x0d) { *(chs + i)='D'; } else if(ch==0x0c) { *(chs + i)='C'; } else if(ch==0x0b) { *(chs + i)='B'; } else if(ch==0x0a) { *(chs + i)='A'; } else { *(chs + i) = (char)(addr % 16 + '0'); } i++;
} while ((addr /= 16) > 0); for (int j = 7; j > i-1; j--) { print_char('0'); *(chs + j) = 0; } for (int j = i-1; j >= 0; j--) { print_char(*(chs + j)); *(chs + j) = 0; } }
|
修改加载文件,输出打印调试信息
1 2 3 4 5 6 7
| #include "../include/printk.h"
int _start(){ print_string("rast os system begin start...\0"); fin: goto fin; }
|
显示结果如下:

Makefile文件更新
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| # tools PLATFORM=Linux NASM=nasm BOCHS=bochs BXIMAGE=bximage
# args boot=boot asm=asm lib=lib build=build ENTRY_POINT=0x10000 CFLAGS=-m32 -c -nostdinc -nostdlib -fno-builtin -Wall -W -Wstrict-prototypes -Wmissing-prototypes LDFLAGS=-m elf_i386 -s -e _start -Ttext $(ENTRY_POINT)
target: $(build)/rastos.img @echo "build img completed"
$(build)/rastos.img:$(build)/boot.bin $(build)/loader.bin $(build)/loaderELF.bin $(BXIMAGE) -func=create -imgmode=flat -hd=16M -q $(build)/rastos.img sleep 2 dd if=$(build)/boot.bin of=$(build)/rastos.img bs=512 count=1 conv=notrunc dd if=$(build)/loader.bin of=$(build)/rastos.img bs=512 count=1 seek=1 conv=notrunc dd if=$(build)/loaderELF.bin of=$(build)/rastos.img bs=512 count=30 seek=2 conv=notrunc
$(build)/loaderELF.bin: $(build)/loaderELF.o $(build)/io.o $(build)/printk.o $(LD) -o $@ $^ $(LDFLAGS)
$(build)/loaderELF.o: $(boot)/loaderELF.c $(CC) $(boot)/loaderELF.c -o $(build)/loaderELF.o $(CFLAGS)
$(build)/io.o: $(NASM) -f elf -o $(build)/io.o $(asm)/io.asm
$(build)/%.bin: $(boot)/%.asm $(NASM) -f bin -o $(build)/$*.bin $(boot)/$*.asm
$(build)/%.o: $(CC) -o $(build)/$*.o $(lib)/$*.c -I include $(CFLAGS)
prepare: $(build) @echo "prepare dir $(build)" ifeq ($(build), $(wildcard $(build))) @echo "build directory exist..." else mkdir -p $(build) endif
clean: @echo "clean dir $(build)" rm -rf $(build)/*
platform: @echo $(PLATFORM)
|