问题描述
所以我一直在尝试编写一个基本的内核,并且达到了写入屏幕的程度。
我可以很容易地从 Assembly 中做到这一点,但不能从 C 中做到。以下是从 Assembly 写入屏幕的代码:
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x10
print_string_pm:
pusha
mov edx,VIDEO_MEMORY
print_string_pm_loop:
mov al,[ebx]
mov ah,WHITE_ON_BLACK
cmp al,0
je print_string_pm_done
mov [edx],ax
add ebx,1
add edx,2
jmp print_string_pm_loop
print_string_pm_done:
popa
ret
这工作得很好,但是从 C 代码开始尝试:
#define VIDEO_MEMORY 0xb8000
#define WHITE_ON_BLACK 0x0f
void main(void) {
char* video_memory = (char*) VIDEO_MEMORY;
*video_memory = 'H';
*(video_memory + 2) = WHITE_ON_BLACK;
*(video_memory + 3) = 'e';
*(video_memory + 5) = 'l';
*(video_memory + 7) = 'l';
*(video_memory + 9) = 'o';
*(video_memory + 11) = ' ';
*(video_memory + 13) = 'W';
*(video_memory + 15) = 'o';
*(video_memory + 17) = 'r';
*(video_memory + 19) = 'l';
*(video_memory + 21) = 'd';
}
这有效但效率不高,然后当我尝试声明一个字符串时:
void main(void) {
char* video_memory = (char*) VIDEO_MEMORY;
char* str = "Hello World!";
*video_memory = str[0];
*(video_memory + 2) = WHITE_ON_BLACK;
video_memory += 3;
for (int i = 0; str[i] != '\0'; i++) {
*(video_memory) = str[i];
video_memory += 2;
}
}
我的Makefile:
C_SOURCES = $(wildcard src/*.c)
HEADERS = $(wildcard headers/*.h)
OBJ = ${C_SOURCES:.c=.o}
all: build run
boot_sect.bin:bootloader/main.asm bootloader/gdt.asm bootloader/print_string_pm.asm bootloader/printf.asm bootloader/switch_to_pm.asm bootloader/readdisk.asm
nasm -i./bootloader/ -f bin bootloader/main.asm -o $@
clean:
rm -f *.bin **/*.o
clean_src:
rm -f src/*.o
run: image
qemu-system-x86_64 $<
%.o: src/%.c ${HEADERS}
gcc -I../headers/ -ffreestanding -c $< -o build/$@
%.o: bootloader/%.asm
nasm $< -f elf64 -o build/$@
kernel.bin: ${OBJ} build/kernel_entry.o
ld -o $@ -T link.ld $^ --oformat binary
image: boot_sect.bin kernel.bin
cat $^ > image
build: clean boot_sect.bin kernel.o kernel_entry.o kernel.bin image
我尝试过的事情:
这会为字母 H 创建一个空白空间,但该字母不存在并且该空间是 红色。
typedef struct char_with_attribute {
char ch,attribute;
} char_with_attribute;
char_with_attribute* convert_to_struct(char,char);
void main(void) {
volatile char_with_attribute *video_memory = (void*)VIDEO_MEMORY;
char* str = "Hello World!";
*video_memory = *convert_to_struct('H',(char)0x0f);
}
char_with_attribute* convert_to_struct(char ch,char attr) {
char_with_attribute* combination;
combination->ch = ch;
combination->attribute = attr;
return combination;
}
解决方法
看起来您正在关注 cfenollosa 的 os-tutorial,或者至少偶然发现了其内容的副本,因为您的汇编代码片段来自 chapter 08。>
简单地说,你一个一个字节地写你的角色和属性,每次增加你的视频内存偏移量。一个粗略的例子:
const char *s = "Hello world";
char *base = (void *) 0xb8000;
while (*s) {
*base++ = *s++;
*base++ = 0x0f;
}
Chapter 15 涵盖使用处理光标位置的 VGA I/O 端口。
Chapter 16 引入了许多在 VGA 文本模式下写入屏幕的高级函数,其中许多专门用于处理 80x25 boundaries。