Reorganize the whole thing

This commit is contained in:
Pierre Pronchery 2018-04-08 05:16:25 +02:00
parent 89f9b74a83
commit 9e30bc0315
28 changed files with 768 additions and 379 deletions

34
src/arch/amd64/gdt.S Normal file
View File

@ -0,0 +1,34 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
/* Originally from https://wiki.osdev.org/Bare_Bones */
/* text */
.section .text
/* arch_setgdt */
.global __arch_setgdt
.type __arch_setgdt,function
__arch_setgdt:
#if 0
lea gdt_descriptor, %rcx
#else
mov (gdt_descriptor), %rcx
#endif
/* set the offset of the GDT */
mov %rsi, 0x2(%rcx)
/* set the size of the GDT */
dec %rdi
mov %di, (%rcx)
/* load the GDT */
lgdt (%rcx)
ret
/* bss */
.section .bss
.align 16
gdt_descriptor:
.skip 2 /* size */
.skip 4 /* offset */

17
src/arch/amd64/gdt.h Normal file
View File

@ -0,0 +1,17 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#ifndef UKERNEL_ARCH_AMD64_GDT_H
# define UKERNEL_ARCH_AMD64_GDT_H
# include "../i386/gdt.h"
/* public */
/* prototypes */
int _arch_setgdt64(GDT const * gdt, size_t count);
#endif /* !UKERNEL_ARCH_I386_GDT_H */

View File

@ -5,6 +5,10 @@
#include "../i386/multiboot/header.S"
#include "../i386/idt.S"
/* sections */ /* sections */
/* bss */ /* bss */
.section .bss .section .bss
@ -26,6 +30,14 @@ _exit:
jmp 1b jmp 1b
/* setidt */
.global _setidt
.type _setidt,function
_setidt:
lidt (idt)
ret
/* start */ /* start */
.global _start .global _start
.type _start, @function .type _start, @function
@ -45,6 +57,11 @@ _start:
/* call the global constructors */ /* call the global constructors */
call _init call _init
/* set the interrupt descriptor */
call _setidt
/* FIXME setup paging */
/* start the kernel */ /* start the kernel */
xor %rdi, %rdi xor %rdi, %rdi
call main call main

36
src/arch/i386/gdt.S Normal file
View File

@ -0,0 +1,36 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
/* Originally from https://wiki.osdev.org/Bare_Bones */
/* text */
.section .text
/* arch_setgdt */
.global __arch_setgdt
.type __arch_setgdt,function
__arch_setgdt:
#if 0
lea gdt_descriptor, %ecx
#else
mov (gdt_descriptor), %ecx
#endif
/* set the offset of the GDT */
mov 0x4(%esp), %eax
mov %eax, 0x2(%ecx)
/* set the size of the GDT */
mov 0x8(%esp), %eax
dec %eax
mov %ax, (%ecx)
/* load the GDT */
lgdt (%ecx)
ret
/* bss */
.section .bss
.align 16
gdt_descriptor:
.skip 2 /* size */
.skip 4 /* offset */

27
src/arch/i386/gdt.h Normal file
View File

@ -0,0 +1,27 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#ifndef UKERNEL_ARCH_I386_GDT_H
# define UKERNEL_ARCH_I386_GDT_H
# include <sys/types.h>
# include <stdint.h>
/* public */
/* types */
typedef struct _GDT
{
vaddr_t base;
vaddr_t limit;
uint8_t type;
} GDT;
/* prototypes */
int _arch_setgdt(GDT const * gdt, size_t count);
#endif /* !UKERNEL_ARCH_I386_GDT_H */

23
src/arch/i386/idt.S Normal file
View File

@ -0,0 +1,23 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
/* Originally from https://wiki.osdev.org/Bare_Bones */
/* text */
.section .text
/* arch_setidt */
.global __arch_setidt
.type __arch_setidt,function
__arch_setidt:
lidt (idt)
ret
/* bss */
.section .bss
.align 16
idt:
.short 0x0 /* size */
.long 0x0 /* offset */

15
src/arch/i386/idt.h Normal file
View File

@ -0,0 +1,15 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#ifndef UKERNEL_ARCH_I386_IDT_H
# define UKERNEL_ARCH_I386_IDT_H
/* public */
/* prototypes */
int _arch_setidt(void);
#endif /* !UKERNEL_ARCH_I386_IDT_H */

View File

@ -5,22 +5,7 @@
/* variables */ #include "multiboot.S"
#define ALIGN (1 << 0) /* align the modules loaded on */
/* page boundaries */
#define MEMINFO (1 << 1) /* provide the memory map */
#define FLAGS ALIGN | MEMINFO /* multiboot flags */
#define MAGIC 0x1badb002 /* magic number */
#define CHECKSUM -(MAGIC + FLAGS) /* checksum for the above */
/* sections */
/* multiboot */
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
/* bss */ /* bss */
@ -54,6 +39,8 @@ _start:
mov $stack_top, %esp mov $stack_top, %esp
xor %ebp, %ebp xor %ebp, %ebp
push %eax
#if defined(__SSP__) #if defined(__SSP__)
/* initialize SSP */ /* initialize SSP */
call __stack_chk_setup call __stack_chk_setup
@ -62,8 +49,16 @@ _start:
/* call the global constructors */ /* call the global constructors */
call _init call _init
/* start the kernel */ /* detect multiboot */
pop %eax
cmp $MAGIC2, %eax
jne 1f
push %ebx push %ebx
call multiboot
1:
/* start the kernel */
push $0x0
call main call main
add $0x4, %esp add $0x4, %esp

View File

@ -5,22 +5,7 @@
/* variables */ #include "multiboot.S"
#define ALIGN (1 << 0) /* align the modules loaded on */
/* page boundaries */
#define MEMINFO (1 << 1) /* provide the memory map */
#define FLAGS ALIGN | MEMINFO /* multiboot flags */
#define MAGIC 0x1badb002 /* magic number */
#define CHECKSUM -(MAGIC + FLAGS) /* checksum for the above */
/* sections */
/* multiboot */
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
/* bss */ /* bss */
@ -31,12 +16,6 @@ stack_bottom:
stack_top: stack_top:
/* data */
.section .data
k_ptr:
.long 0x0
/* text */ /* text */
.section .text .section .text
/* exit */ /* exit */
@ -49,75 +28,6 @@ _exit:
jmp 1b jmp 1b
.global _kernel32
.type _kernel32,function
_kernel32:
/* jump into the 32-bit kernel */
mov 0x4(%esp), %ebx
mov 0x8(%esp), %eax
call *%eax
ret
.global _kernel64
.type _kernel64,function
_kernel64:
/* check for 64-bit capability */
pushf
pop %eax
mov %eax, %ecx
xor $0x00200000, %eax
push %eax
popf
pushf
pop %eax
cmp %ecx, %eax
jz 1f /* CPUID is not supported */
push %ebx
mov $0x80000001, %eax
cpuid
pop %ebx
cmp $0x80000000, %eax
jl 1f /* 64-bit mode is not supported */
/* jump into the 64-bit kernel */
mov 0x8(%esp), %esi
mov %esi, (k_ptr)
lgdt (_gdt64)
mov _gdt64_data, %ax
mov %ax, %ss
mov %ax, %ds
mov %ax, %es
jmp _gdt64_code
.jmp_k:
mov 0x4(%esp), %edi
mov k_ptr, %eax
.long 0x0
jmp *%eax
1:
mov $-1, %eax
ret
.global _setgdt
.type _setgdt,function
_setgdt:
lea gdt_descriptor, %ecx
/* set the offset of the GDT */
mov 0x4(%esp), %eax
mov %eax, 0x2(%ecx)
/* set the size of the GDT */
mov 0x8(%esp), %eax
dec %eax
mov %ax, (%ecx)
/* load the GDT */
lgdt (%ecx)
ret
/* start */ /* start */
.global _start .global _start
.type _start, @function .type _start, @function
@ -127,6 +37,8 @@ _start:
/* initialize the stack */ /* initialize the stack */
mov $stack_top, %esp mov $stack_top, %esp
xor %ebp, %ebp
push %eax
#if defined(__SSP__) #if defined(__SSP__)
/* initialize SSP */ /* initialize SSP */
@ -136,10 +48,19 @@ _start:
/* call the global constructors */ /* call the global constructors */
call _init call _init
/* start the loader */ /* detect multiboot */
pop %eax
cmp $MAGIC2, %eax
jne 1f
push %ebx push %ebx
call multiboot
1:
/* start the loader */
push $0x0
push $0x0
call main call main
add $0x4, %esp add $0x8, %esp
/* exit the kernel */ /* exit the kernel */
call _exit call _exit
@ -147,10 +68,3 @@ _start:
hlt hlt
.size _start, . - _start .size _start, . - _start
.section .bss
.align 16
gdt_descriptor:
.skip 2 /* size */
.skip 4 /* offset */

81
src/arch/i386/multiboot.S Normal file
View File

@ -0,0 +1,81 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#include "multiboot/header.S"
/* sections */
/* data */
.section .data
k_ptr:
.long 0x0
/* text */
/* multiboot_boot_kernel32 */
.global multiboot_boot_kernel32
.type multiboot_boot_kernel32,function
multiboot_boot_kernel32:
/* jump into the 32-bit kernel */
#if 0
mov 0x4(%esp), %ebx
mov 0x8(%esp), %eax
call *%eax
ret
#else
push %ebp
mov %esp, %ebp
mov 0x8(%ebp), %ebx
mov 0xc(%ebp), %eax
jmp *%eax
#endif
.global multiboot_boot_kernel64
.type multiboot_boot_kernel64,function
multiboot_boot_kernel64:
/* check for 64-bit capability */
pushf
pop %eax
mov %eax, %ecx
xor $0x00200000, %eax
push %eax
popf
pushf
pop %eax
cmp %ecx, %eax
jz 1f /* CPUID is not supported */
push %ebx
mov $0x80000001, %eax
cpuid
pop %ebx
cmp $0x80000000, %eax
jl 1f /* 64-bit mode is not supported */
/* jump into the 64-bit kernel */
mov 0x8(%esp), %esi
mov %esi, (k_ptr)
#if 0
lgdt (_gdt64)
mov _gdt64_data, %ax
mov %ax, %ss
mov %ax, %ds
mov %ax, %es
jmp _gdt64_code
.jmp_k:
mov 0x4(%esp), %edi
mov k_ptr, %eax
.long 0x0
jmp *%eax
#endif
1:
mov $-1, %eax
ret

View File

@ -0,0 +1,23 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
/* variables */
#define ALIGN (1 << 0) /* align the modules loaded on */
/* page boundaries */
#define MEMINFO (1 << 1) /* provide the memory map */
#define FLAGS ALIGN | MEMINFO /* multiboot flags */
#define MAGIC1 0x1badb002 /* magic number */
#define MAGIC2 0x2badb002 /* magic number */
#define CHECKSUM -(MAGIC1 + FLAGS) /* checksum for the above */
/* sections */
/* multiboot */
.section .multiboot
.align 4
.long MAGIC1
.long FLAGS
.long CHECKSUM

View File

@ -1 +1 @@
dist=Makefile,arch.h,crti.S,crtn.S,kernel.S,ioport.S,loader.S,uKernel.ld dist=Makefile,arch.h,crti.S,crtn.S,gdt.S,idt.S,kernel.S,ioport.S,loader.S,uKernel.ld

View File

@ -0,0 +1,116 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#if defined(__amd64__) || defined(__i386__)
# include <stdint.h>
# include <stdio.h>
# include <string.h>
# include <elf.h>
# include "arch/amd64/gdt.h"
# include "arch/i386/gdt.h"
# include "drivers/boot/multiboot.h"
/* private */
/* prototypes */
extern int _kernel32(ukMultibootInfo * mi, vaddr_t entrypoint);
extern int _kernel64(ukMultibootInfo * mi, vaddr_t entrypoint);
/* public */
/* functions */
/* multiboot_load_module */
static int _load_module32(ukMultibootMod * mod, vaddr_t * entrypoint,
Elf32_Ehdr * ehdr);
static int _load_module64(ukMultibootMod * mod, vaddr_t * entrypoint,
Elf64_Ehdr * ehdr);
int multiboot_load_module(ukMultibootMod * mod, unsigned char * elfclass,
vaddr_t * entrypoint)
{
Elf32_Ehdr * ehdr;
if(mod->end < mod->start || mod->end - mod->start < sizeof(ehdr))
{
puts("Could not load module: Invalid format");
return -1;
}
ehdr = (Elf32_Ehdr *)mod->start;
if(elfclass != NULL)
*elfclass = ehdr->e_ident[EI_CLASS];
switch(ehdr->e_ident[EI_CLASS])
{
case ELFCLASS32:
return _load_module32(mod, entrypoint, ehdr);
case ELFCLASS64:
return _load_module64(mod, entrypoint,
(Elf64_Ehdr *)ehdr);
}
return -1;
}
static int _load_module32(ukMultibootMod * mod, vaddr_t * entrypoint,
Elf32_Ehdr * ehdr)
{
Elf32_Phdr * phdr;
Elf32_Half i;
if(mod->start + ehdr->e_phoff + (ehdr->e_phnum * sizeof(*phdr))
> mod->end)
{
puts("Could not load 32-bit module: Invalid format");
return NULL;
}
phdr = (Elf32_Phdr *)(mod->start + ehdr->e_phoff);
for(i = 0; i < ehdr->e_phnum; i++)
{
if(phdr[i].p_type != PT_LOAD)
continue;
if(phdr[i].p_vaddr > ehdr->e_entry
|| phdr[i].p_vaddr + phdr[i].p_filesz
<= ehdr->e_entry)
continue;
if(entrypoint != NULL)
*entrypoint = mod->start + ehdr->e_entry
- phdr[i].p_vaddr + phdr[i].p_offset;
/* FIXME really look for main() directly? */
return 0;
}
puts("Could not load 32-bit module: Invalid entrypoint");
return -1;
}
static int _load_module64(ukMultibootMod * mod, vaddr_t * entrypoint,
Elf64_Ehdr * ehdr)
{
Elf64_Phdr * phdr;
Elf64_Quarter i;
if(mod->start + ehdr->e_phoff + (ehdr->e_phnum * sizeof(*phdr))
> mod->end)
{
puts("Could not load 64-bit module: Invalid format");
return -1;
}
phdr = (Elf64_Phdr *)(mod->start + ehdr->e_phoff);
for(i = 0; i < ehdr->e_phnum; i++)
{
if(phdr[i].p_type != PT_LOAD)
continue;
if(phdr[i].p_vaddr > ehdr->e_entry
|| phdr[i].p_vaddr + phdr[i].p_filesz
<= ehdr->e_entry)
continue;
if(entrypoint != NULL)
*entrypoint = mod->start + ehdr->e_entry
- phdr[i].p_vaddr + phdr[i].p_offset;
/* FIXME really look for main() directly? */
return 0;
}
puts("Could not load 64-bit module: Invalid entrypoint");
return -1;
}
#endif

View File

@ -9,6 +9,7 @@
# include <sys/types.h> # include <sys/types.h>
# include <stdint.h> # include <stdint.h>
# include <elf.h>
/* types */ /* types */
@ -102,4 +103,11 @@ struct _ukBootMultibootMod
# define BOOT_MULTIBOOT_INFO_HAS_LOADER_NAME 0x00000200 # define BOOT_MULTIBOOT_INFO_HAS_LOADER_NAME 0x00000200
# define BOOT_MULTIBOOT_INFO_HAS_VBE 0x00000800 # define BOOT_MULTIBOOT_INFO_HAS_VBE 0x00000800
/* prototypes */
int multiboot_boot_kernel32(ukMultibootInfo * info, vaddr_t entrypoint);
int multiboot_boot_kernel64(ukMultibootInfo * info, vaddr_t entrypoint);
int multiboot_load_module(ukMultibootMod * mod, unsigned char * elfclass,
vaddr_t * entrypoint);
#endif /* !UKERNEL_DRIVERS_BOOT_MULTIBOOT_H */ #endif /* !UKERNEL_DRIVERS_BOOT_MULTIBOOT_H */

View File

@ -1 +1,18 @@
dist=Makefile,multiboot.h dist=Makefile,multiboot.h
targets=multiboot.o
cppflags_force=-nostdinc -isystem ../../../include -I../..
as=$(CC)
asflags_force=$(CFLAGSF) $(CFLAGS) -c
cflags_force=`../../../tools/platform.sh -V UKERNEL_CFLAGS -C "$$ARCH"`
cflags=-W -Wall -g -O2
ldflags_force=`../../../tools/platform.sh -V UKERNEL_LDFLAGS -C "$$ARCH"`
dist=Makefile,bus.h,console.h
#targets
[multiboot.o]
type=object
sources=multiboot.c
#sources
[multiboot.c]
depends=multiboot.h

7
src/kernel/gdt.c Normal file
View File

@ -0,0 +1,7 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#include "../loader/gdt.c"

View File

@ -5,7 +5,6 @@
#include <stdio.h> #include <stdio.h>
#include "drivers/boot/multiboot.h"
#include "drivers/bus.h" #include "drivers/bus.h"
#include "drivers/console.h" #include "drivers/console.h"
@ -20,12 +19,16 @@
/* public */ /* public */
/* functions */ /* functions */
/* main */ /* main */
int main(ukMultibootInfo * mi) int main(int argc, char * argv[])
{ {
ukBus * bus; ukBus * bus;
int i;
bus = bus_init(KERNEL_BUS); bus = bus_init(KERNEL_BUS);
console_init(bus, KERNEL_CONSOLE); console_init(bus, KERNEL_CONSOLE);
puts("Starting DeforaOS..."); puts("Starting DeforaOS...");
for(i = 0; i < argc; i++)
printf("%s%s%s", (i > 0) ? " " : "", argv[i],
(i + 1 == argc) ? "\n" : "");
return 0; return 0;
} }

76
src/kernel/multiboot.c Normal file
View File

@ -0,0 +1,76 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#if defined(__amd64__) || defined(__i386__)
# include <stdio.h>
# include "arch/amd64/gdt.h"
# include "arch/i386/gdt.h"
# include "drivers/boot/multiboot.h"
# include "drivers/bus.h"
# include "drivers/console.h"
# ifndef LOADER_BUS
# define LOADER_BUS "ioport"
# endif
# ifndef LOADER_CONSOLE
# define LOADER_CONSOLE "vga"
# endif
/* private */
/* constants */
/* GDT: 4GB flat memory setup */
static const GDT _gdt_4gb[4] =
{
{ 0x00000000, 0x00000000, 0x00 },
{ 0x00000000, 0xffffffff, 0x9a },
{ 0x00000000, 0xffffffff, 0x92 },
{ 0x00000000, 0x00000000, 0x89 }
};
/* public */
/* functions */
/* multiboot */
int multiboot(ukMultibootInfo * mi)
{
ukBus * bus;
size_t i;
ukMultibootMod * mod;
bus = bus_init(LOADER_BUS);
console_init(bus, LOADER_CONSOLE);
puts("DeforaOS Multiboot");
if(mi->loader_name != NULL)
printf("Loader: %s\n", mi->loader_name);
if(mi->cmdline != NULL)
printf("Command line: %s\n", mi->cmdline);
printf("%u MB memory available\n",
(mi->mem_upper - mi->mem_lower) / 1024);
printf("Booted from %#x\n", mi->boot_device_drive);
if(!(mi->flags & BOOT_MULTIBOOT_HEADER_HAS_MODS))
{
puts("No modules provided");
return 2;
}
#if defined(__amd64__)
if(_arch_setgdt64(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
#else
if(_arch_setgdt(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
#endif
{
puts("Could not setup the GDT");
return 4;
}
puts("Loading modules...");
for(i = 0; i < mi->mods_count; i++)
{
mod = &mi->mods_addr[i];
multiboot_load_module(mod, NULL, NULL);
}
return 0;
}
#endif

View File

@ -26,9 +26,9 @@ sources=../common/crtn.S
[uKernel.bin] [uKernel.bin]
type=binary type=binary
sources=arch.S,start.S,main.c sources=arch.S,gdt.c,main.c,multiboot.c,start.S
ldflags=$(OBJDIR)crti.o $(OBJDIR)crtbegin.o $(OBJDIR)../drivers/bus.o $(OBJDIR)../drivers/console.o $(OBJDIR)../lib/libuKernel.a $(OBJDIR)crtend.o $(OBJDIR)crtn.o ldflags=$(OBJDIR)crti.o $(OBJDIR)crtbegin.o $(OBJDIR)../drivers/boot/multiboot.o $(OBJDIR)../drivers/bus.o $(OBJDIR)../drivers/console.o $(OBJDIR)../lib/libuKernel.a $(OBJDIR)crtend.o $(OBJDIR)crtn.o
depends=$(OBJDIR)crtbegin.o,$(OBJDIR)crtend.o,$(OBJDIR)crti.o,$(OBJDIR)crtn.o,$(OBJDIR)../drivers/bus.o,$(OBJDIR)../drivers/console.o,$(OBJDIR)../lib/libuKernel.a,../arch/amd64/uKernel.ld,../arch/i386/uKernel.ld depends=$(OBJDIR)crtbegin.o,$(OBJDIR)crtend.o,$(OBJDIR)crti.o,$(OBJDIR)crtn.o,$(OBJDIR)../drivers/boot/multiboot.o,$(OBJDIR)../drivers/bus.o,$(OBJDIR)../drivers/console.o,$(OBJDIR)../lib/libuKernel.a,../arch/amd64/uKernel.ld,../arch/i386/uKernel.ld
#sources #sources
[arch.S] [arch.S]
@ -40,8 +40,8 @@ depends=../arch/amd64/crti.S,../arch/i386/crti.S
[../common/crtn.S] [../common/crtn.S]
depends=../arch/amd64/crtn.S,../arch/i386/crtn.S depends=../arch/amd64/crtn.S,../arch/i386/crtn.S
[main.c] [multiboot.c]
depends=../drivers/bus.h,../drivers/console.h depends=../loader/multiboot.c,../drivers/boot/multiboot.h
[start.S] [start.S]
depends=../arch/i386/kernel.S depends=../arch/i386/kernel.S

View File

@ -6,8 +6,11 @@
/* check for supported architectures */ /* check for supported architectures */
#if defined(__amd64__) #if defined(__amd64__)
# include "arch/amd64/gdt.S"
# include "arch/amd64/kernel.S" # include "arch/amd64/kernel.S"
#elif defined(__i386__) #elif defined(__i386__)
# include "arch/i386/gdt.S"
# include "arch/i386/idt.S"
# include "arch/i386/kernel.S" # include "arch/i386/kernel.S"
#else #else
# warning Unsupported architecture # warning Unsupported architecture

112
src/loader/gdt.c Normal file
View File

@ -0,0 +1,112 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#if defined(__amd64__) || defined(__i386__)
# include <stdint.h>
# include <string.h>
# include <errno.h>
# include "arch/amd64/gdt.h"
# include "arch/i386/gdt.h"
/* prototypes */
extern void __arch_setgdt(uint8_t * buf, size_t count);
/* variables */
static uint8_t _buf[65536];
/* functions */
/* arch_setgdt */
int _arch_setgdt(GDT const * gdt, size_t count)
{
uint8_t * buf = _buf;
size_t i;
GDT g;
memset(&_buf, 0, sizeof(_buf));
/* check for errors */
if(count == 0 || count > sizeof(_buf) / sizeof(*gdt))
{
errno = ERANGE;
return -1;
}
for(i = 0; i < count; i++)
{
g = gdt[i];
buf = &_buf[sizeof(g) * i];
if(g.limit > 65536)
{
/* make sure the limit can be encoded */
if((g.limit & 0xfff) != 0xfff)
return -1;
g.limit = g.limit >> 12;
buf[6] = 0xc0;
}
else
buf[6] = 0x40;
//encode the limit
buf[0] = g.limit & 0xff;
buf[1] = (g.limit >> 8) & 0xff;
buf[6] |= (g.limit >> 16) & 0xf;
//encode the base
buf[2] = g.base & 0xff;
buf[3] = (g.base >> 8) & 0xff;
buf[4] = (g.base >> 16) & 0xff;
buf[7] = (g.base >> 24) & 0xff;
//encode the type
buf[5] = g.type;
}
__arch_setgdt(_buf, count);
return 0;
}
/* arch_setgdt64 */
int _arch_setgdt64(GDT const * gdt, size_t count)
{
uint8_t * buf;
size_t i;
GDT g;
memset(&_buf, 0, sizeof(_buf));
/* check for errors */
if(count == 0 || count > sizeof(_buf) / sizeof(*gdt))
{
errno = ERANGE;
return -1;
}
for(i = 0; i < count; i++)
{
g = gdt[i];
buf = &_buf[sizeof(g) * i];
if(g.limit > 65536)
{
/* make sure the limit can be encoded */
if((g.limit & 0xfff) != 0xfff)
return -1;
g.limit = g.limit >> 12;
buf[6] = 0xa0;
}
else
buf[6] = 0x20;
//encode the limit
buf[0] = g.limit & 0xff;
buf[1] = (g.limit >> 8) & 0xff;
buf[6] |= (g.limit >> 16) & 0xf;
//encode the base
buf[2] = g.base & 0xff;
buf[3] = (g.base >> 8) & 0xff;
buf[4] = (g.base >> 16) & 0xff;
buf[7] = (g.base >> 24) & 0xff;
//encode the type
buf[5] = g.type;
}
__arch_setgdt(_buf, count);
return 0;
}
#endif

View File

@ -17,5 +17,6 @@
#include "lib/string.c" #include "lib/string.c"
#include "lib/unistd.c" #include "lib/unistd.c"
#include "drivers/boot/multiboot.c"
#include "drivers/bus.c" #include "drivers/bus.c"
#include "drivers/console.c" #include "drivers/console.c"

View File

@ -4,265 +4,19 @@
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <errno.h>
#include <elf.h>
#include "drivers/boot/multiboot.h"
#include "drivers/bus.h"
#include "drivers/console.h"
#ifndef LOADER_BUS
# define LOADER_BUS "ioport"
#endif
#ifndef LOADER_CONSOLE
# define LOADER_CONSOLE "vga"
#endif
/* private */
/* types */
typedef int (*LoaderCallback)(ukMultibootInfo * mi, vaddr_t entrypoint);
/* prototypes */
static LoaderCallback _loader_kernel(ukMultibootMod * mod,
vaddr_t * entrypoint);
static int _loader_module(ukMultibootMod * mod);
extern int _kernel32(ukMultibootInfo * mi, vaddr_t entrypoint);
extern int _kernel64(ukMultibootInfo * mi, vaddr_t entrypoint);
/* platform-dependent */
#if defined(__i386__)
/* types */
typedef struct _GDT
{
vaddr_t base;
vaddr_t limit;
uint8_t type;
} GDT;
/* prototypes */
static int _loader_gdt(GDT const * gdt, size_t size);
extern void _setgdt(uint8_t * buf, size_t size);
/* constants */
/* GDT: flat memory setup */
static const GDT _gdt_4gb[4] =
{
{ 0x00000000, 0x00000000, 0x00 },
{ 0x00000000, 0xffffffff, 0x9a },
{ 0x00000000, 0xffffffff, 0x92 },
{ 0x00000000, 0x00000000, 0x89 }
};
/* variables */
static uint8_t _buf[65536];
/* functions */
/* loader_gdt */
static int _loader_gdt(GDT const * gdt, size_t size)
{
uint8_t * buf;
size_t i;
GDT g;
if(size == 0 || size > sizeof(_buf) / sizeof(*gdt))
{
errno = ERANGE;
return -1;
}
for(i = 0; i < size; i++)
{
g = gdt[i];
buf = &_buf[sizeof(g) * i];
if(g.limit > 65536)
{
/* make sure the limit can be encoded */
if((g.limit & 0xfff) != 0xfff)
return -1;
g.limit = g.limit >> 12;
buf[6] = 0xc0;
}
else
buf[6] = 0x40;
//encode the limit
buf[0] = g.limit & 0xff;
buf[1] = (g.limit >> 8) & 0xff;
buf[6] |= (g.limit >> 16) & 0xf;
//encode the base
buf[2] = g.base & 0xff;
buf[3] = (g.base >> 8) & 0xff;
buf[4] = (g.base >> 16) & 0xff;
buf[7] = (g.base >> 24) & 0xff;
//encode the type
buf[5] = g.type;
}
_setgdt(_buf, size);
return 0;
}
#endif
/* functions */
/* loader_kernel */
static LoaderCallback _loader_kernel32(ukMultibootMod * mod,
vaddr_t * entrypoint, Elf32_Ehdr * ehdr);
static LoaderCallback _loader_kernel64(ukMultibootMod * mod,
vaddr_t * entrypoint, Elf64_Ehdr * ehdr);
static LoaderCallback _loader_kernel(ukMultibootMod * mod, vaddr_t * entrypoint)
{
Elf32_Ehdr * ehdr;
printf("Loading kernel: %s (%#x, %#x)\n", mod->cmdline, mod->start,
mod->end);
if(mod->end < mod->start || mod->end - mod->start < sizeof(ehdr))
{
puts("Could not load kernel: Invalid format");
return NULL;
}
ehdr = (Elf32_Ehdr *)mod->start;
switch(ehdr->e_ident[EI_CLASS])
{
case ELFCLASS32:
puts("Detected 32-bit kernel");
return _loader_kernel32(mod, entrypoint, ehdr);
case ELFCLASS64:
puts("Detected 64-bit kernel");
return _loader_kernel64(mod, entrypoint,
(Elf64_Ehdr *)ehdr);
default:
puts("Could not load kernel: Invalid class");
break;
}
return NULL;
}
static LoaderCallback _loader_kernel32(ukMultibootMod * mod,
vaddr_t * entrypoint, Elf32_Ehdr * ehdr)
{
Elf32_Phdr * phdr;
Elf32_Half i;
if(mod->start + ehdr->e_phoff + (ehdr->e_phnum * sizeof(*phdr))
> mod->end)
{
puts("Could not load 32-bit kernel: Invalid format");
return NULL;
}
phdr = (Elf32_Phdr *)(mod->start + ehdr->e_phoff);
for(i = 0; i < ehdr->e_phnum; i++)
{
if(phdr[i].p_type != PT_LOAD)
continue;
if(phdr[i].p_vaddr > ehdr->e_entry
|| phdr[i].p_vaddr + phdr[i].p_filesz
<= ehdr->e_entry)
continue;
*entrypoint = mod->start + ehdr->e_entry - phdr[i].p_vaddr
+ phdr[i].p_offset;
return _kernel32;
}
puts("Could not load 32-bit kernel: Invalid entrypoint");
return NULL;
}
static LoaderCallback _loader_kernel64(ukMultibootMod * mod,
vaddr_t * entrypoint, Elf64_Ehdr * ehdr)
{
Elf64_Phdr * phdr;
Elf64_Quarter i;
if(mod->start + ehdr->e_phoff + (ehdr->e_phnum * sizeof(*phdr))
> mod->end)
{
puts("Could not load 64-bit kernel: Invalid format");
return NULL;
}
phdr = (Elf64_Phdr *)(mod->start + ehdr->e_phoff);
for(i = 0; i < ehdr->e_phnum; i++)
{
if(phdr[i].p_type != PT_LOAD)
continue;
if(phdr[i].p_vaddr > ehdr->e_entry
|| phdr[i].p_vaddr + phdr[i].p_filesz
<= ehdr->e_entry)
continue;
*entrypoint = mod->start + ehdr->e_entry - phdr[i].p_vaddr
+ phdr[i].p_offset;
return _kernel64;
}
puts("Could not load 64-bit kernel: Invalid entrypoint");
return NULL;
}
/* loader_module */
static int _loader_module(ukMultibootMod * mod)
{
const char msg_loading[] = "Loading module: ";
puts(msg_loading);
puts(mod->cmdline);
return 0;
}
/* public */ /* public */
/* functions */ /* functions */
/* main */ /* main */
int main(ukMultibootInfo * mi) int main(int argc, char * argv[])
{ {
ukBus * bus; int i;
size_t i;
const char msg_failed2[] = "No modules provided";
const char msg_failed3[] = "No kernel provided";
ukMultibootMod * mod;
LoaderCallback callback = NULL;
vaddr_t entrypoint;
bus = bus_init(LOADER_BUS);
console_init(bus, LOADER_CONSOLE);
puts("Booting DeforaOS..."); puts("Booting DeforaOS...");
if(mi->flags & BOOT_MULTIBOOT_INFO_HAS_LOADER_NAME) for(i = 0; i < argc; i++)
printf("Loader: %s\n", mi->loader_name); printf("%s%s%s", (i > 0) ? " " : "", argv[i],
if(mi->flags & BOOT_MULTIBOOT_INFO_HAS_CMDLINE) (i + 1 == argc) ? "\n" : "");
printf("Command line: %s\n", mi->cmdline); return 0;
printf("%u MB memory available\n",
(mi->mem_upper - mi->mem_lower) / 1024);
if(!(mi->flags & BOOT_MULTIBOOT_INFO_HAS_MODS))
{
puts(msg_failed2);
return 2;
}
if(mi->mods_count == 0)
{
puts(msg_failed3);
return 3;
}
#if defined(__i386__)
if(_loader_gdt(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
{
puts("Could not setup the GDT");
return 4;
}
#endif
puts("Loading modules...");
for(i = 0; i < mi->mods_count; i++)
{
mod = &mi->mods_addr[i];
if(i == 0)
callback = _loader_kernel(mod, &entrypoint);
else
_loader_module(mod);
}
if(callback == NULL)
{
puts("Could not load the kernel");
return 5;
}
return callback(mi, entrypoint);
} }

105
src/loader/multiboot.c Normal file
View File

@ -0,0 +1,105 @@
/* $Id$ */
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS uKernel */
#if defined(__i386__)
# include <stdint.h>
# include <stdio.h>
# include <string.h>
# include "arch/amd64/gdt.h"
# include "arch/i386/gdt.h"
# include "drivers/boot/multiboot.h"
# include "drivers/bus.h"
# include "drivers/console.h"
# ifndef LOADER_BUS
# define LOADER_BUS "ioport"
# endif
# ifndef LOADER_CONSOLE
# define LOADER_CONSOLE "vga"
# endif
/* private */
/* constants */
/* GDT: 4GB flat memory setup */
static const GDT _gdt_4gb[4] =
{
{ 0x00000000, 0x00000000, 0x00 },
{ 0x00000000, 0xffffffff, 0x9a },
{ 0x00000000, 0xffffffff, 0x92 },
{ 0x00000000, 0x00000000, 0x89 }
};
/* public */
/* functions */
/* multiboot */
int multiboot(ukMultibootInfo * mi)
{
ukBus * bus;
size_t i;
ukMultibootMod * mod;
int res = -1;
unsigned char elfclass;
vaddr_t entrypoint;
bus = bus_init(LOADER_BUS);
console_init(bus, LOADER_CONSOLE);
puts("DeforaOS Multiboot");
if(mi->loader_name != NULL)
printf("Loader: %s\n", mi->loader_name);
if(mi->cmdline != NULL)
printf("Command line: %s\n", mi->cmdline);
printf("%u MB memory available\n",
(mi->mem_upper - mi->mem_lower) / 1024);
printf("Booted from %#x\n", mi->boot_device_drive);
if(!(mi->flags & BOOT_MULTIBOOT_HEADER_HAS_MODS))
{
puts("No modules provided");
return 2;
}
if(mi->mods_count == 0)
{
puts("No kernel provided");
return 3;
}
if(_arch_setgdt(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
{
puts("Could not setup the GDT");
return 4;
}
puts("Loading modules...");
for(i = 0; i < mi->mods_count; i++)
{
mod = &mi->mods_addr[i];
printf("Loading module: %s\n", mod->cmdline);
if(i == 0)
res = multiboot_load_module(mod, &elfclass,
&entrypoint);
else
multiboot_load_module(mod, NULL, NULL);
}
if(res != 0)
{
puts("Could not load the kernel");
return 5;
}
printf("Jumping into the kernel at %#x (%u, %u, %#x) %p\n", entrypoint,
mi->elfshdr_num, mi->elfshdr_size, mi->elfshdr_addr,
multiboot);
switch(elfclass)
{
case ELFCLASS32:
puts("Detected 32-bit kernel");
return multiboot_boot_kernel32(mi, entrypoint);
case ELFCLASS64:
puts("Detected 64-bit kernel");
return multiboot_boot_kernel64(mi, entrypoint);
}
puts("Unsupported ELF class for the kernel");
return 6;
}
#endif

View File

@ -30,7 +30,7 @@ sources=lib.c
[uLoader.bin] [uLoader.bin]
type=binary type=binary
sources=arch.S,start.S,main.c sources=arch.S,gdt.c,main.c,multiboot.c,start.S
ldflags=$(OBJDIR)crti.o $(OBJDIR)crtbegin.o $(OBJDIR)crtend.o $(OBJDIR)crtn.o $(OBJDIR)libuLoader.a ldflags=$(OBJDIR)crti.o $(OBJDIR)crtbegin.o $(OBJDIR)crtend.o $(OBJDIR)crtn.o $(OBJDIR)libuLoader.a
depends=$(OBJDIR)crtbegin.o,$(OBJDIR)crtend.o,$(OBJDIR)crti.o,$(OBJDIR)crtn.o,$(OBJDIR)libuLoader.a,../arch/amd64/uKernel.ld,../arch/i386/uKernel.ld depends=$(OBJDIR)crtbegin.o,$(OBJDIR)crtend.o,$(OBJDIR)crti.o,$(OBJDIR)crtn.o,$(OBJDIR)libuLoader.a,../arch/amd64/uKernel.ld,../arch/i386/uKernel.ld
@ -44,7 +44,7 @@ depends=../arch/amd64/crti.S,../arch/i386/crti.S
[../common/crtn.S] [../common/crtn.S]
depends=../arch/amd64/crtn.S,../arch/i386/crtn.S depends=../arch/amd64/crtn.S,../arch/i386/crtn.S
[main.c] [multiboot.c]
depends=../drivers/boot/multiboot.h,../drivers/bus.h,../drivers/console.h depends=../drivers/boot/multiboot.h,../drivers/bus.h,../drivers/console.h
[start.S] [start.S]

View File

@ -6,6 +6,7 @@
/* check for supported architectures */ /* check for supported architectures */
#if defined(__amd64__) || defined(__i386__) #if defined(__amd64__) || defined(__i386__)
# include "../arch/i386/gdt.S"
# include "../arch/i386/loader.S" # include "../arch/i386/loader.S"
#else #else
# warning Unsupported architecture # warning Unsupported architecture

View File

@ -57,6 +57,8 @@ _grub()
amd64|i?86) amd64|i?86)
_info "Testing multiboot conformance ($machine)" _info "Testing multiboot conformance ($machine)"
$GRUBFILE --is-x86-multiboot "$OBJDIR$UKERNELBIN" $GRUBFILE --is-x86-multiboot "$OBJDIR$UKERNELBIN"
#FIXME look for multiboot2 instead?
#$GRUBFILE --is-x86-multiboot2 "$OBJDIR$UKERNELBIN"
ret=$? ret=$?
if [ $ret -eq 127 ]; then if [ $ret -eq 127 ]; then
_error "Cannot test: $GRUBFILE not available (ignored)" _error "Cannot test: $GRUBFILE not available (ignored)"

View File

@ -6,4 +6,6 @@
#define KERNEL_BUS "tty" #define KERNEL_BUS "tty"
#define KERNEL_CONSOLE "stdio" #define KERNEL_CONSOLE "stdio"
#include "../src/kernel/main.c" #include "../src/kernel/main.c"