直接输出到文本视频内存时出现异常内核行为
Unusual kernel behaviour when outputting directly to text video memory
我正在研究基本内核。我学习了一些在线课程并开始从头开始写这篇文章。我在编写这个内核时看到异常行为。我在 C 中编写内核,在汇编中编写引导加载程序。源代码可用 here.
问题:
在打印 *const char*
时,我发现在一些垃圾值中有 0 个索引结果,而真正的字符串只能从索引 1 中看到。我决定坚持这个 hack 并继续编写内核,希望我稍后可以解决此问题。
当我开始编写用于更新打印例程中光标位置的例程时,我遇到了另一个问题。我更新了代码以使用光标位置作为我之前使用的 x-y 坐标的偏移量。令我惊讶的是,索引现在从 2 而不是 1 开始。
/** print msg at (x,y) or cursor */
void print_at(const char* msg, int x, int y){
unsigned char *video = (unsigned char *)VIDEO_ADDRESS;
unsigned int offset = 0, i = 1; // i=1?
// decide offset value
if(x>=0||y>=0){
// get offset from coordinates
offset = get_offset(x,y);
}else{
// get cursor
offset = get_cursor();
i+=1; // i=2?
}
while(1){
char c = msg[i];
if(c==0){
// end of string
break;
}else if(c=='\n'||(offset/(2*MAX_ROWS)==MAX_COLS)){
// go to next line
offset = get_offset((offset/(2*MAX_COLS)),MAX_COLS-1);
}else{
// print the character
video[offset] = c;
video[offset+1] = WHITE_ON_BLUE;
}
offset+=2;i++;
}
update_cursor(offset);
}
我的 get_offset(int row, int col) 例程表现异常。 offset的正常计算应该是(row*MAX_COLS+col)*2
。但是,这会导致如下结果:
如果我将公式设为 (row*MAX_COLS+col)*2+1
,则打印功能可以正常工作:
我的 Makefile 是:
# Makefile for OS
# Note: $^ = all dependencies, $< = first dependency, $@ = target
# Generate list of sources using wildcards
C_SOURCES= $(wildcard drivers/*.c kernel/*.c)
HEADERS = $(wildcard drivers/*.h kernel/*.h)
# List of objects to build
OBJ = ${C_SOURCES:.c=.o}
all: os-image
# run
run: all
qemu-system-i386 -drive format=raw,file=os-image
# debug mode
debug: all
qemu-system-i386 -s -S -drive format=raw,file=os-image
# build
os-image: boot/boot_sect.bin kernel.bin
cat $^ > os-image
kernel.bin: kernel/kernel_entry.o ${OBJ}
ld -o $@ -Ttext 0x1000 $^ --oformat binary
# Generic rule for compiling C code to an object file
# For simplicity , the C files depend on all header files .
%.o : %.c ${HEADERS}
gcc -ffreestanding -c $< -o $@
# Assemble the kernel_entry .
%.o : %.asm
nasm $< -f elf64 -o $@
%.bin : %.asm
nasm $< -f bin -o $@
clean :
rm -rf *.bin *.dis *.o os-image
rm -rf kernel/*.o boot/*.bin drivers/*.o
我的同事们也未能找出问题所在。我如何开始调试它?
我忽略了一个事实,即我需要在 64 位系统上精细地编译 32 位代码。我通过向 GCC 添加 -m32
和 -fno-PIC
标志,向 LD 添加 -melf_i386
,并将 NASM 中的 elf64
更改为 elf32
来解决问题生成文件。
我正在研究基本内核。我学习了一些在线课程并开始从头开始写这篇文章。我在编写这个内核时看到异常行为。我在 C 中编写内核,在汇编中编写引导加载程序。源代码可用 here.
问题:
在打印 *const char*
时,我发现在一些垃圾值中有 0 个索引结果,而真正的字符串只能从索引 1 中看到。我决定坚持这个 hack 并继续编写内核,希望我稍后可以解决此问题。
当我开始编写用于更新打印例程中光标位置的例程时,我遇到了另一个问题。我更新了代码以使用光标位置作为我之前使用的 x-y 坐标的偏移量。令我惊讶的是,索引现在从 2 而不是 1 开始。
/** print msg at (x,y) or cursor */
void print_at(const char* msg, int x, int y){
unsigned char *video = (unsigned char *)VIDEO_ADDRESS;
unsigned int offset = 0, i = 1; // i=1?
// decide offset value
if(x>=0||y>=0){
// get offset from coordinates
offset = get_offset(x,y);
}else{
// get cursor
offset = get_cursor();
i+=1; // i=2?
}
while(1){
char c = msg[i];
if(c==0){
// end of string
break;
}else if(c=='\n'||(offset/(2*MAX_ROWS)==MAX_COLS)){
// go to next line
offset = get_offset((offset/(2*MAX_COLS)),MAX_COLS-1);
}else{
// print the character
video[offset] = c;
video[offset+1] = WHITE_ON_BLUE;
}
offset+=2;i++;
}
update_cursor(offset);
}
我的 get_offset(int row, int col) 例程表现异常。 offset的正常计算应该是(row*MAX_COLS+col)*2
。但是,这会导致如下结果:
如果我将公式设为 (row*MAX_COLS+col)*2+1
,则打印功能可以正常工作:
我的 Makefile 是:
# Makefile for OS
# Note: $^ = all dependencies, $< = first dependency, $@ = target
# Generate list of sources using wildcards
C_SOURCES= $(wildcard drivers/*.c kernel/*.c)
HEADERS = $(wildcard drivers/*.h kernel/*.h)
# List of objects to build
OBJ = ${C_SOURCES:.c=.o}
all: os-image
# run
run: all
qemu-system-i386 -drive format=raw,file=os-image
# debug mode
debug: all
qemu-system-i386 -s -S -drive format=raw,file=os-image
# build
os-image: boot/boot_sect.bin kernel.bin
cat $^ > os-image
kernel.bin: kernel/kernel_entry.o ${OBJ}
ld -o $@ -Ttext 0x1000 $^ --oformat binary
# Generic rule for compiling C code to an object file
# For simplicity , the C files depend on all header files .
%.o : %.c ${HEADERS}
gcc -ffreestanding -c $< -o $@
# Assemble the kernel_entry .
%.o : %.asm
nasm $< -f elf64 -o $@
%.bin : %.asm
nasm $< -f bin -o $@
clean :
rm -rf *.bin *.dis *.o os-image
rm -rf kernel/*.o boot/*.bin drivers/*.o
我的同事们也未能找出问题所在。我如何开始调试它?
我忽略了一个事实,即我需要在 64 位系统上精细地编译 32 位代码。我通过向 GCC 添加 -m32
和 -fno-PIC
标志,向 LD 添加 -melf_i386
,并将 NASM 中的 elf64
更改为 elf32
来解决问题生成文件。