Use ELF kernel image.

This commit is contained in:
Alexander Myltsev 2022-11-17 23:16:57 +03:00
parent e31e56f8f9
commit 3acb397549
6 changed files with 91 additions and 12 deletions

View File

@ -7,17 +7,17 @@ run: image.bin
debug: image.bin
qemu-system-i386 -drive format=raw,file=$< -s -S &
i386-elf-gdb \
x86_64-elf-gdb \
-ex "target remote localhost:1234" \
-ex "set architecture i8086" \
-ex "break *0x7c00" \
-ex "break *0x7c5d" \
-ex "continue"
image.bin: mbr.bin kernel.bin
cat $^ >$@
kernel.bin: kernel.o vga.o string.o
$(LD) -m elf_i386 -o $@ -Ttext 0x1000 $^ --oformat binary
kernel.bin: kernel.o vga.o string.o drivers/ata.o
$(LD) -m elf_i386 -o $@ -Ttext 0x1000 $^
%.o: %.c
$(CC) -m32 -ffreestanding -c $< -o $@

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#include "ata.h"
#include "../ports.h"
#include "../port.h"
/*
BSY: a 1 means that the controller is busy executing a command. No register should be accessed (except the digital output register) while this bit is set.

38
elf.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <stdint.h>
enum {
EI_NIDENT = 16,
};
typedef uint32_t Elf32_Addr;
typedef uint32_t Elf32_Off;
typedef struct {
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} Elf32_Ehdr;
typedef struct {
uint32_t p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
} Elf32_Phdr;

View File

@ -1,11 +1,8 @@
asm("jmp main");
#include "vga.h"
int main() {
void _start() {
vga_clear_screen();
for (int i = 0; i < 24; i++) {
vga_print_string("hello world\n");
}
return 0;
}

40
mbr.S
View File

@ -11,11 +11,39 @@ _start:
jmp . // loop forever
.equ ELF32_ENTRY_OFFSET, 0x18
.equ ELF32_PHDR_OFFSET, 0x1c
.equ ELF32_PHDR_FILESZ_OFFSET, 4*4
.equ KERNEL_OFFSET, 0x1000
.equ MBR_SECTORS, 1
.equ SECTOR_BASE, 1
.equ ELFHDR_SECTORS, 8
.equ SECTOR_SIZE, 512
.equ SECTOR_SHIFT, 9
load_kernel:
mov $1, %al // sectors to read
mov $SECTOR_BASE + MBR_SECTORS, %cl // start after MBR
call bios_disk_read
mov KERNEL_OFFSET + ELF32_ENTRY_OFFSET, %si
mov %si, entry // store entry point
mov KERNEL_OFFSET + ELF32_PHDR_OFFSET, %di
mov KERNEL_OFFSET + ELF32_PHDR_FILESZ_OFFSET(%di), %ax
sub $0x1000, %ax // we won't load the header
add $SECTOR_SIZE - 1, %ax
shr $SECTOR_SHIFT, %ax // round up to sector count
mov $SECTOR_BASE + MBR_SECTORS + ELFHDR_SECTORS, %cl //start after ELF header
call bios_disk_read
ret
bios_disk_read:
// expects %al to specify number of sectors, %cl the initial sector
mov $2, %ah // read mode
mov $2, %al // sectors to read
mov $2, %cl // start from sector 2
mov $0, %ch // cylinder 0
mov $0, %dh // head 0
mov $KERNEL_OFFSET, %bx // bx -> destination
@ -46,7 +74,8 @@ init_32bit:
mov $0x90000, %ebp // 6. setup stack
mov %ebp, %esp
call KERNEL_OFFSET // 7. jump to the kernel
movzwl entry, %esi
call *%esi // 7. jump to the kernel
jmp . // 8. loop forever
@ -70,6 +99,11 @@ boot_drive:
banner:
.asciz "YABLOKO bootloader started\r\n"
.balign 2
entry:
.word 0
.balign 4
gdt_start:
.quad 0x0 // null descriptor

10
port.h
View File

@ -6,6 +6,16 @@ static unsigned char port_byte_in(unsigned short port) {
return result;
}
static unsigned short port_word_in(unsigned short port) {
unsigned short result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
static void port_byte_out(unsigned short port, unsigned char data) {
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}
static void port_long_out(unsigned short port, unsigned int data) {
__asm__("out %%eax, %%dx" : : "a" (data), "d" (port));
}