直接输出到文本视频内存时出现异常内核行为

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 来解决问题生成文件。