Kernel.c 没有执行完整的代码 [OS 从头开始]
Kernel.c not executing complete code [OS from scratch]
我是操作系统的初学者,我正在尝试从头开始构建 os(在 tutorial 之后)。虽然我可以执行作者提供的代码。但是当我添加我的自定义引导加载程序(这显然需要更多内存,并等待键盘中断加载内核)然后尝试添加教程中提到的 drivers 时,我的内核不会执行完整的代码(可能会也可能不会)。
实际上我在 kernel.c 中有 5 个打印语句(当我不添加任何 driver 时所有语句都工作正常),但是一旦我开始添加 drivers(即使我没有执行任何 driver 函数),代码似乎避免了底部的打印语句。
我试过更改内核偏移量,但似乎没有任何效果。
kernel.c
void clear_screen() // clear the entire text screen
{
char *vga = (char *)0xb8000;
unsigned int i = 0;
while (i < (80 * 25 * 2))
{
vga[i] = ' ';
i++;
vga[i] = COLOR;
i++;
}
}
unsigned int kprintf(char *message, unsigned int line) // the message and then the line #
{
char *vga = (char *)0xb8000;
unsigned int i = 0;
i = (line * 80 * 2);
while (*message != 0)
{
if (*message == '\n')
{
line++;
i = (line * 80 * 2);
*message++;
}
else
{
vga[i] = *message;
*message++;
i++;
vga[i] = COLOR;
i++;
}
}
return (1);
}
void main() // like main in a normal C program
{
clear_screen();
kprintf("Hi!\nThis is our Kernel\n", 2);
kprintf("Our Team Members:\n", 12);
kprintf("1. Aditya Garg \n",13);
kprintf("2. Ayush Agarwal\n", 14);
kprintf("3. Anup Aglawe \n", 15);
kprintf("4. Anshuman yadav \n", 16);
kprintf("5. Ujjaval shah \n", 17);
};
bootsect.asm
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
call start1
call load_kernel
call switch_to_pm
jmp $
%include "boot/print.asm"
%include "boot/print_hex.asm"
%include "boot/disk.asm"
%include "boot/gdt.asm"
%include "boot/32bit_print.asm"
%include "boot/switch_pm.asm"
[bits 16]
start1:
mov ax, 0x0
mov ds, ax
mov es, ax
mov bx, 0x8000
mov ax, 13;clearScreen
int 0x10
mov ah,2 ;big font
int 0x10
;Position
mov ah,0x02
mov bh,0x00
mov dh,0x06
mov dl,0x09
int 0x10
mov si, start_os_intro
call Color_String
;New Position
mov ah,0x02
mov bh,0x00
mov dh,0x10
mov dl,0x0a
int 0x10
mov si, press_key
call RedColor_String
mov ax,0x00
int 0x16
mov al,2 ;change font
mov ah,0 ;clear screen
int 0x10
ret
start_os_intro db 'Welcome to DarkraiOS!',0
press_key db '>>Press any key<<',0
; text db 'loading ', 0
load_kernel:
mov bx, KERNEL_OFFSET
mov dh, 1
mov dl, [BOOT_DRIVE]
call disk_load
ret
[bits 32]
BEGIN_PM:
call KERNEL_OFFSET
jmp $
BOOT_DRIVE db 0
times 510 - ($-$$) db 0
dw 0xaa55
生成文件
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o}
# Change this if your cross-compiler is somewhere else
CC = i686-elf-gcc
GDB = i686-elf-gdb
# -g: Use debugging symbols in gcc
CFLAGS = -g
# First rule is run by default
os-image.bin: boot\bootsect.bin kernel.bin
type $^ > os-image.bin
# '--oformat binary' deletes all symbols as a collateral, so we don't need
# to 'strip' them manually on this case
kernel.bin: boot/kernel_entry.o ${OBJ}
i686-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
# Used for debugging purposes
kernel.elf: boot\kernel_entry.o ${OBJ}
i686-elf-ld -o $@ -Ttext 0x1000 $^
run: os-image.bin
qemu-system-i386 -fda os-image.bin
# Open the connection to qemu and load our kernel-object file with symbols
debug: os-image.bin kernel.elf
qemu-system-x86_64 -s -fda os-image.bin &
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
# Generic rules for wildcards
# To make an object, always compile from its .c
%.o: %.c ${HEADERS}
${CC} ${CFLAGS} -ffreestanding -c $< -o $@
%.o: %.asm
nasm $< -f elf -o $@
%.bin: %.asm
nasm $< -f bin -o $@
clean:
rm -rf *.bin *.dis *.o os-image.bin *.elf
rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o
司机ports.c
unsigned char result;
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
return result;
}
void port_byte_out (unsigned short port, unsigned char data) {
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}
unsigned short port_word_in (unsigned short port) {
unsigned short result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
void port_word_out (unsigned short port, unsigned short data) {
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
}
Drivers/ports.h
unsigned char port_byte_in (unsigned short port);
void port_byte_out (unsigned short port, unsigned char data);
unsigned short port_word_in (unsigned short port);
void port_word_out (unsigned short port, unsigned short data);
添加 driver 文件夹之前
添加 drivers' 文件夹后(我没有使用 driver 的任何功能)
P.S。 - 如果有人需要,我可以分享我的全部代码。
根据仅打印了部分菜单的屏幕截图,我可以猜测您的内核 (kernel.bin
) 尚未完全加载到内存中。在 load_kernel
你做:
load_kernel:
mov bx, KERNEL_OFFSET
mov dh, 1 ; <----- Number of sectors to read
mov dl, [BOOT_DRIVE]
call disk_load
ret
您正在使用的教程将要读取的扇区数传递给 DH。它在 boot_sect_disk.asm
中记录为:
; load 'dh' sectors from drive 'dl' into ES:BX
你需要增加这个数字来读取足够的扇区来加载你的整个内核。要计算要加载的扇区数,请找到 kernel.bin
的大小,将其加上 511,然后除以 512。numsectors=(filesize+511)/512 计算加载一个文件所需的 512 字节扇区数filesize
的文件四舍五入到最接近的 512 字节扇区。将该值加载到 DH.
我是操作系统的初学者,我正在尝试从头开始构建 os(在 tutorial 之后)。虽然我可以执行作者提供的代码。但是当我添加我的自定义引导加载程序(这显然需要更多内存,并等待键盘中断加载内核)然后尝试添加教程中提到的 drivers 时,我的内核不会执行完整的代码(可能会也可能不会)。
实际上我在 kernel.c 中有 5 个打印语句(当我不添加任何 driver 时所有语句都工作正常),但是一旦我开始添加 drivers(即使我没有执行任何 driver 函数),代码似乎避免了底部的打印语句。
我试过更改内核偏移量,但似乎没有任何效果。
kernel.c
void clear_screen() // clear the entire text screen
{
char *vga = (char *)0xb8000;
unsigned int i = 0;
while (i < (80 * 25 * 2))
{
vga[i] = ' ';
i++;
vga[i] = COLOR;
i++;
}
}
unsigned int kprintf(char *message, unsigned int line) // the message and then the line #
{
char *vga = (char *)0xb8000;
unsigned int i = 0;
i = (line * 80 * 2);
while (*message != 0)
{
if (*message == '\n')
{
line++;
i = (line * 80 * 2);
*message++;
}
else
{
vga[i] = *message;
*message++;
i++;
vga[i] = COLOR;
i++;
}
}
return (1);
}
void main() // like main in a normal C program
{
clear_screen();
kprintf("Hi!\nThis is our Kernel\n", 2);
kprintf("Our Team Members:\n", 12);
kprintf("1. Aditya Garg \n",13);
kprintf("2. Ayush Agarwal\n", 14);
kprintf("3. Anup Aglawe \n", 15);
kprintf("4. Anshuman yadav \n", 16);
kprintf("5. Ujjaval shah \n", 17);
};
bootsect.asm
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
call start1
call load_kernel
call switch_to_pm
jmp $
%include "boot/print.asm"
%include "boot/print_hex.asm"
%include "boot/disk.asm"
%include "boot/gdt.asm"
%include "boot/32bit_print.asm"
%include "boot/switch_pm.asm"
[bits 16]
start1:
mov ax, 0x0
mov ds, ax
mov es, ax
mov bx, 0x8000
mov ax, 13;clearScreen
int 0x10
mov ah,2 ;big font
int 0x10
;Position
mov ah,0x02
mov bh,0x00
mov dh,0x06
mov dl,0x09
int 0x10
mov si, start_os_intro
call Color_String
;New Position
mov ah,0x02
mov bh,0x00
mov dh,0x10
mov dl,0x0a
int 0x10
mov si, press_key
call RedColor_String
mov ax,0x00
int 0x16
mov al,2 ;change font
mov ah,0 ;clear screen
int 0x10
ret
start_os_intro db 'Welcome to DarkraiOS!',0
press_key db '>>Press any key<<',0
; text db 'loading ', 0
load_kernel:
mov bx, KERNEL_OFFSET
mov dh, 1
mov dl, [BOOT_DRIVE]
call disk_load
ret
[bits 32]
BEGIN_PM:
call KERNEL_OFFSET
jmp $
BOOT_DRIVE db 0
times 510 - ($-$$) db 0
dw 0xaa55
生成文件
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o}
# Change this if your cross-compiler is somewhere else
CC = i686-elf-gcc
GDB = i686-elf-gdb
# -g: Use debugging symbols in gcc
CFLAGS = -g
# First rule is run by default
os-image.bin: boot\bootsect.bin kernel.bin
type $^ > os-image.bin
# '--oformat binary' deletes all symbols as a collateral, so we don't need
# to 'strip' them manually on this case
kernel.bin: boot/kernel_entry.o ${OBJ}
i686-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
# Used for debugging purposes
kernel.elf: boot\kernel_entry.o ${OBJ}
i686-elf-ld -o $@ -Ttext 0x1000 $^
run: os-image.bin
qemu-system-i386 -fda os-image.bin
# Open the connection to qemu and load our kernel-object file with symbols
debug: os-image.bin kernel.elf
qemu-system-x86_64 -s -fda os-image.bin &
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
# Generic rules for wildcards
# To make an object, always compile from its .c
%.o: %.c ${HEADERS}
${CC} ${CFLAGS} -ffreestanding -c $< -o $@
%.o: %.asm
nasm $< -f elf -o $@
%.bin: %.asm
nasm $< -f bin -o $@
clean:
rm -rf *.bin *.dis *.o os-image.bin *.elf
rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o
司机ports.c
unsigned char result;
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
return result;
}
void port_byte_out (unsigned short port, unsigned char data) {
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}
unsigned short port_word_in (unsigned short port) {
unsigned short result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
void port_word_out (unsigned short port, unsigned short data) {
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
}
Drivers/ports.h
unsigned char port_byte_in (unsigned short port);
void port_byte_out (unsigned short port, unsigned char data);
unsigned short port_word_in (unsigned short port);
void port_word_out (unsigned short port, unsigned short data);
添加 driver 文件夹之前
添加 drivers' 文件夹后(我没有使用 driver 的任何功能)
P.S。 - 如果有人需要,我可以分享我的全部代码。
根据仅打印了部分菜单的屏幕截图,我可以猜测您的内核 (kernel.bin
) 尚未完全加载到内存中。在 load_kernel
你做:
load_kernel:
mov bx, KERNEL_OFFSET
mov dh, 1 ; <----- Number of sectors to read
mov dl, [BOOT_DRIVE]
call disk_load
ret
您正在使用的教程将要读取的扇区数传递给 DH。它在 boot_sect_disk.asm
中记录为:
; load 'dh' sectors from drive 'dl' into ES:BX
你需要增加这个数字来读取足够的扇区来加载你的整个内核。要计算要加载的扇区数,请找到 kernel.bin
的大小,将其加上 511,然后除以 512。numsectors=(filesize+511)/512 计算加载一个文件所需的 512 字节扇区数filesize
的文件四舍五入到最接近的 512 字节扇区。将该值加载到 DH.