1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

add basic bootloader to support a non multi-kernel mode

=> HermitCore will support a classical unikernel mode
This commit is contained in:
Stefan Lankes 2016-07-18 23:06:40 +02:00
parent 5782edd4eb
commit 66195c7795
18 changed files with 2581 additions and 0 deletions

View file

@ -0,0 +1,66 @@
MAKE = make
QEMU = qemu-system-x86_64 -machine accel=kvm -cpu host
OBJDUMP = objdump
OBJCOPY = objcopy
CC = gcc
CFLAGS = -O2 -Wall -m64 -ffreestanding -mno-red-zone -fstrength-reduce -fomit-frame-pointer -finline-functions -Iinclude
NASM = nasm
NASMFLAGS = -felf64 -g
LD = ld
LDFLAGS = -T link.ld -z max-page-size=4096
STRIP_DEBUG = --strip-debug
KEEP_DEBUG = --only-keep-debug
OUTPUT_FORMAT = -O elf32-i386
NAME = ldhermit
C_source := main.c printf.c string.c stdio.c vga.c page.c
ASM_source := entry.asm
OBJS := $(C_source:.c=.o)
OBJS += $(ASM_source:.asm=.o)
# Prettify output
V = 0
ifeq ($V,0)
Q = @
P = > /dev/null
endif
# other implicit rules
%.o : %.c
@echo [CC] $@
$Q$(CC) -c $(CFLAGS) -o $@ $<
@echo [DEP] $*.dep
$Q$(CC) -MF $*.dep -MT $*.o -MM $(CFLAGS) $<
%.o : %.asm
@echo [ASM] $@
$Q$(NASM) $(NASMFLAGS) -o $@ $<
all: ldhermit.elf
$(NAME).elf: $(OBJS)
@echo [LD] $@
$Q$(LD) $(LDFLAGS) -o $@ $(OBJS)
@echo [OBJCOPY] $(NAME).sym
$Q$(OBJCOPY) $(KEEP_DEBUG) $(NAME).elf $(NAME).sym
@echo [OBJCOPY] $(NAME).elf
$Q$(OBJCOPY) $(STRIP_DEBUG) $(OUTPUT_FORMAT) $(NAME).elf
qemu:
$(QEMU) -smp 10 -m 4G -kernel $(NAME).elf -initrd ../../../usr/tests/hello \
-net nic,model=rtl8139 -net user -net dump \
-curses -monitor telnet:127.0.0.1:1235,server,nowait \
-s
clean:
@echo Cleaning loader
$Q$(RM) -rf *.o *~ *.bin *.obj
veryclean: clean
depend:
$(CC) -MM $(CFLAGS) *.c > Makefile.dep
-include -include $(C_source:.c=.dep)
# DO NOT DELETE

View file

@ -0,0 +1,289 @@
; Copyright (c) 2010-2016, Stefan Lankes, RWTH Aachen University
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; * Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; * Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; * Neither the name of the University nor the names of its contributors
; may be used to endorse or promote products derived from this software
; without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
; This is the kernel's entry point. We could either call main here,
; or we can use this to setup the stack or other nice stuff, like
; perhaps setting up the GDT and segments. Please note that interrupts
; are disabled at this point: More on interrupts later!
[BITS 32]
%define KERNEL_STACK_SIZE 4096
%define VIDEO_MEM_ADDR 0xB8000
extern kernel_start ; defined in linker script
extern kernel_end
; We use a special name to map this section at the begin of our kernel
; => Multiboot expects its magic number at the beginning of the kernel.
SECTION .mboot
global start
start:
jmp stublet
; This part MUST be 4 byte aligned, so we solve that issue using 'ALIGN 4'.
ALIGN 4
mboot:
; Multiboot macros to make a few lines more readable later
MULTIBOOT_PAGE_ALIGN equ (1 << 0)
MULTIBOOT_MEMORY_INFO equ (1 << 1)
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
; This is the GRUB Multiboot header. A boot signature
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM
dd 0, 0, 0, 0, 0 ; address fields
ALIGN 4
; we need already a valid GDT to switch in the 64bit modus
GDT64: ; Global Descriptor Table (64-bit).
.Null: equ $ - GDT64 ; The null descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 0 ; Access.
db 0 ; Granularity.
db 0 ; Base (high).
.Code: equ $ - GDT64 ; The code descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011000b ; Access.
db 00100000b ; Granularity.
db 0 ; Base (high).
.Data: equ $ - GDT64 ; The data descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010010b ; Access.
db 00000000b ; Granularity.
db 0 ; Base (high).
.Pointer: ; The GDT-pointer.
dw $ - GDT64 - 1 ; Limit.
dq GDT64 ; Base.
SECTION .text
ALIGN 4
stublet:
; Initialize stack pointer
mov esp, boot_stack
add esp, KERNEL_STACK_SIZE - 16
; Interpret multiboot information
mov DWORD [mb_info], ebx
; Initialize CPU features
call cpu_init
pop ebx ; restore pointer to multiboot structure
lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table.
jmp GDT64.Code:start64 ; Set the code segment and enter 64-bit long mode.
; This will set up the x86 control registers:
; Caching and the floating point unit are enabled
; Bootstrap page tables are loaded and page size
; extensions (huge pages) enabled.
global cpu_init
cpu_init:
; initialize page tables
; map vga 1:1
push edi
mov eax, VIDEO_MEM_ADDR ; map vga
and eax, 0xFFFFF000 ; page align lower half
mov edi, eax
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
add edi, boot_pgt
or eax, 0x113 ; set present, global, writable and cache disable bits
mov DWORD [edi], eax
pop edi
; map multiboot info 1:1
push edi
mov eax, DWORD [mb_info] ; map multiboot info
and eax, 0xFFFFF000 ; page align lower half
mov edi, eax
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
add edi, boot_pgt
or eax, 0x101 ; set present and global bits
mov DWORD [edi], eax
pop edi
; map kernel 1:1
push edi
push ebx
push ecx
mov ecx, kernel_start
mov ebx, kernel_end
add ebx, 0x1000
L0: cmp ecx, ebx
jae L1
mov eax, ecx
and eax, 0xFFFFF000 ; page align lower half
mov edi, eax
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
add edi, boot_pgt
or eax, 0x103 ; set present, global and writable bits
mov DWORD [edi], eax
add ecx, 0x1000
jmp L0
L1:
pop ecx
pop ebx
pop edi
; check for long mode
; do we have the instruction cpuid?
pushfd
pop eax
mov ecx, eax
xor eax, 1 << 21
push eax
popfd
pushfd
pop eax
push ecx
popfd
xor eax, ecx
jz Linvalid
; cpuid > 0x80000000?
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb Linvalid ; It is less, there is no long mode.
; do we have a long mode?
mov eax, 0x80000001
cpuid
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz Linvalid ; They aren't, there is no long mode.
; we need to enable PAE modus
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; switch to the compatibility mode (which is part of long mode)
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
; Set CR3
mov eax, boot_pml4
mov cr3, eax
; Set CR4
mov eax, cr4
and eax, 0xfffbf9ff ; disable SSE
or eax, (1 << 4) ; enable PSE
or eax, (1 << 7) ; enabel PGE
mov cr4, eax
; Set CR0
mov eax, cr0
and eax, ~(1 << 2) ; disable FPU emulation
or eax, (1 << 1) ; enable FPU montitoring
and eax, ~(1 << 30) ; enable caching
and eax, ~(1 << 29) ; disable write through caching
and eax, ~(1 << 16) ; allow kernel write access to read-only pages
or eax, (1 << 31) ; enable paging
or eax, (1 << 0) ; long mode also needs PM-bit set
mov cr0, eax
ret
; there is no long mode
Linvalid:
jmp $
[BITS 64]
start64:
; initialize segment registers
mov ax, GDT64.Data
mov ds, ax
mov es, ax
mov ss, ax
mov ax, 0x00
mov fs, ax
mov gs, ax
; set default stack pointer
mov rsp, boot_stack
add rsp, KERNEL_STACK_SIZE-16
; jump to the boot processors's C code
extern main
call main
jmp $
;global gdt_flush
;extern gp
; This will set up our new segment registers and is declared in
; C as 'extern void gdt_flush();'
;gdt_flush:
; lgdt [gp]
; ret
SECTION .data
global mb_info:
ALIGN 8
mb_info:
DQ 0
ALIGN 4096
global boot_stack
boot_stack:
TIMES (KERNEL_STACK_SIZE) DB 0xcd
; Bootstrap page tables are used during the initialization.
ALIGN 4096
boot_pml4:
DQ boot_pdpt + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
DQ boot_pml4 + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
boot_pdpt:
DQ boot_pgd + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
DQ boot_pml4 + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
boot_pgd:
DQ boot_pgt + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
DQ boot_pml4 + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
boot_pgt:
times 512 DQ 0
; add some hints to the ELF file
SECTION .note.GNU-stack noalloc noexec nowrite progbits

View file

@ -0,0 +1,177 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
*
* This file keeps define constants for identification and definition of ELF files.\n
* ELF files consist of up to five parts:
* - ELF header
* - program header table
* - section header table
* - ELF sections
* - ELF segment
*/
#ifndef __ELF_H__
#define __ELF_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ELF_MAGIC 0x464C457F
#define ELF_ET_NONE 0x0000 // no type
#define ELF_ET_REL 0x0001 // relocatable
#define ELF_ET_EXEC 0x0002 // executeable
#define ELF_ET_DYN 0x0003 // Shared-Object-File
#define ELF_ET_CORE 0x0004 // Corefile
#define ELF_ET_LOPROC 0xFF00 // Processor-specific
#define ELF_ET_HIPROC 0x00FF // Processor-specific
#define ELF_EM_NONE 0x0000 // no type
#define ELF_EM_M32 0x0001 // AT&T WE 32100
#define ELF_EM_SPARC 0x0002 // SPARC
#define ELF_EM_386 0x0003 // Intel 80386
#define ELF_EM_68K 0x0004 // Motorola 68000
#define ELF_EM_88K 0x0005 // Motorola 88000
#define ELF_EM_860 0x0007 // Intel 80860
#define ELF_EM_MIPS 0x0008 // MIPS RS3000
#define ELF_EM_X86_64 0x003e // Intel X86_64
#define ELF_CLASS_NONE 0x0000
#define ELF_CLASS_32 0x0001 // 32bit file
#define ELF_CLASS_64 0x0002 // 64bit file
#define ELF_DATA_NONE 0x0000
#define ELF_DATA_2LSB 0x0001
#define ELF_DATA_2MSB 0x002
/* Legal values for p_type (segment type). */
#define ELF_PT_NULL 0 /* Program header table entry unused */
#define ELF_PT_LOAD 1 /* Loadable program segment */
#define ELF_PT_DYNAMIC 2 /* Dynamic linking information */
#define ELF_PT_INTERP 3 /* Program interpreter */
#define ELF_PT_NOTE 4 /* Auxiliary information */
#define ELF_PT_SHLIB 5
#define ELF_PT_PHDR 6 /* Entry for header table itself */
#define ELF_PT_TLS 7 /* Thread-local storage segment */
#define ELF_PT_NUM 8 /* Number of defined types */
#define ELF_PT_LOOS 0x60000000 /* Start of OS-specific */
#define ELF_PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
#define ELF_PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
#define ELF_PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
#define ELF_PT_LOSUNW 0x6ffffffa
#define ELF_PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
#define ELF_PT_SUNWSTACK 0x6ffffffb /* Stack segment */
#define ELF_PT_HISUNW 0x6fffffff
#define ELF_PT_HIOS 0x6fffffff /* End of OS-specific */
#define ELF_PT_LOPROC 0x70000000 /* Start of processor-specific */
#define ELF_PT_HIPROC 0x7fffffff /* End of processor-specific */
/* These constants define the permissions on sections in the program
header, p_flags. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
/** @brief Identification part of an ELF-file's header
*
* This structure keeps information about the file format
*/
typedef struct {
uint32_t magic;
uint8_t _class;
uint8_t data;
uint8_t version;
uint8_t pad[8];
uint8_t nident;
} __attribute__ ((packed)) elf_ident_t;
/** @brief Information about the executable
*
* ELF header\n
* This structure keeps information about the format of the executable itself.
*/
typedef struct {
elf_ident_t ident;
uint16_t type;
uint16_t machine;
uint32_t version;
size_t entry;
size_t ph_offset;
size_t sh_offset;
uint32_t flags;
uint16_t header_size;
uint16_t ph_entry_size;
uint16_t ph_entry_count;
uint16_t sh_entry_size;
uint16_t sh_entry_count;
uint16_t sh_str_table_index;
} __attribute__ ((packed)) elf_header_t;
/** @brief program header information
*
* program header table\n
* This structure keeps information about the program header.
*/
typedef struct
{
uint32_t type;
uint32_t flags;
uint64_t offset;
uint64_t virt_addr;
uint64_t phys_addr;
uint64_t file_size;
uint64_t mem_size;
uint64_t alignment;
} __attribute__ ((packed)) elf_program_header_t;
/** @brief Information about ELF section
*
* ELF section\n
* This structure keeps information about a specific ELF section
*/
typedef struct {
uint32_t name;
uint32_t type;
uint64_t flags;
uint64_t addr;
uint64_t offset;
uint64_t size;
uint32_t link;
uint32_t info;
uint64_t align;
uint64_t enttry_size;
} __attribute__ ((packed)) elf_section_header_t;
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __IO_H__
#define __IO_H__
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Read a byte from an IO port
*
* @param _port The port you want to read from
* @return The value which reads out from this port
*/
inline static unsigned char inportb(unsigned short _port) {
unsigned char rv;
asm volatile("inb %1, %0":"=a"(rv):"dN"(_port));
return rv;
}
/** @brief Read a word (2 byte) from an IO port
*
* @param _port The port you want to read from
* @return The value which reads out from this port
*/
inline static unsigned short inportw(unsigned short _port) {
unsigned short rv;
asm volatile("inw %1, %0":"=a"(rv):"dN"(_port));
return rv;
}
/** @brief Read a double word (4 byte) from an IO port
*
* @param _port The port you want to read from
* @return The value which reads out from this port
*/
inline static unsigned int inportl(unsigned short _port) {
unsigned int rv;
asm volatile("inl %1, %0":"=a"(rv):"dN"(_port));
return rv;
}
/** @brief Write a byte to an IO port
*
* @param _port The port you want to write to
* @param _data the 1 byte value you want to write
*/
inline static void outportb(unsigned short _port, unsigned char _data) {
asm volatile("outb %1, %0"::"dN"(_port), "a"(_data));
}
/** @brief Write a word (2 bytes) to an IO port
*
* @param _port The port you want to write to
* @param _data the 2 byte value you want to write
*/
inline static void outportw(unsigned short _port, unsigned short _data) {
asm volatile("outw %1, %0"::"dN"(_port), "a"(_data));
}
/** @brief Write a double word (4 bytes) to an IO port
*
* @param _port The port you want to write to
* @param _data the 4 byte value you want to write
*/
inline static void outportl(unsigned short _port, unsigned int _data)
{
asm volatile("outl %1, %0"::"dN"(_port), "a"(_data));
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_MULTIBOOT_H__
#define __ARCH_MULTIBOOT_H__
#include <stddef.h>
/// Does the bootloader provide mem_* fields?
#define MULTIBOOT_INFO_MEM (1 << 0)
/// Does the bootloader provide the command-line?
#define MULTIBOOT_INFO_CMDLINE (1 << 2)
/// Does the bootloader provide a list of modules?
#define MULTIBOOT_INFO_MODS (1 << 3)
/// Does the bootloader provide a full memory map?
#define MULTIBOOT_INFO_MEM_MAP (1 << 6)
typedef uint16_t multiboot_uint16_t;
typedef uint32_t multiboot_uint32_t;
typedef uint64_t multiboot_uint64_t;
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
multiboot_uint32_t tabsize;
multiboot_uint32_t strsize;
multiboot_uint32_t addr;
multiboot_uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
multiboot_uint32_t num;
multiboot_uint32_t size;
multiboot_uint32_t addr;
multiboot_uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
struct multiboot_info
{
/** Multiboot info version number */
multiboot_uint32_t flags;
/** Available memory from BIOS */
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
/** "root" partition */
multiboot_uint32_t boot_device;
/** Kernel command line */
multiboot_uint32_t cmdline;
/** Boot-Module list */
multiboot_uint32_t mods_count;
multiboot_uint32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/** Memory Mapping buffer */
multiboot_uint32_t mmap_length;
multiboot_uint32_t mmap_addr;
/** Drive Info buffer */
multiboot_uint32_t drives_length;
multiboot_uint32_t drives_addr;
/** ROM configuration table */
multiboot_uint32_t config_table;
/** Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/** APM table */
multiboot_uint32_t apm_table;
/** Video */
multiboot_uint32_t vbe_control_info;
multiboot_uint32_t vbe_mode_info;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
multiboot_uint32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list
{
/** the memory used goes from bytes mod start to mod end-1 inclusive */
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
/** Module command line */
multiboot_uint32_t cmdline;
/** padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
/// Pointer to multiboot structure
/// This pointer is declared at set by entry.asm
extern multiboot_info_t* mb_info;
#endif

View file

@ -0,0 +1,164 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* 2014, Steffen Vogel, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#ifndef __PAGE_H__
#define __PAGE_H__
/// Page offset bits
#define PAGE_BITS 12
/// The size of a single page in bytes
#define PAGE_SIZE ( 1L << PAGE_BITS)
/// Mask the page address without page map flags and XD flag
#ifdef CONFIG_X86_32
#define PAGE_MASK (-1L << PAGE_BITS)
#elif defined(CONFIG_X86_64)
#define PAGE_MASK ((-1L << PAGE_BITS) & ~PG_XD)
#endif
#ifdef CONFIG_X86_32
/// Total operand width in bits
#define BITS 32
/// Physical address width (we dont support PAE)
#define PHYS_BITS BITS
/// Linear/virtual address width
#define VIRT_BITS BITS
/// Page map bits
#define PAGE_MAP_BITS 10
/// Number of page map indirections
#define PAGE_LEVELS 2
#elif defined(CONFIG_X86_64)
/// Total operand width in bits
#define BITS 64
/// Physical address width (maximum value)
#define PHYS_BITS 52
/// Linear/virtual address width
#define VIRT_BITS 48
/// Page map bits
#define PAGE_MAP_BITS 9
/// Number of page map indirections
#define PAGE_LEVELS 4
/** @brief Sign extending a integer
*
* @param addr The integer to extend
* @param bits The width if addr which should be extended
* @return The extended integer
*/
static inline size_t sign_extend(ssize_t addr, int bits)
{
int shift = BITS - bits;
return (addr << shift) >> shift; // sign bit gets copied during arithmetic right shift
}
#endif
/// Make address canonical
#ifdef CONFIG_X86_32
#define CANONICAL(addr) (addr) // only for 32 bit paging
#elif defined(CONFIG_X86_64)
#define CANONICAL(addr) sign_extend(addr, VIRT_BITS)
#endif
/// The number of entries in a page map table
#define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS)
/// Align to next page
#define PAGE_FLOOR(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
/// Align to page
#define PAGE_CEIL(addr) ( (addr) & PAGE_MASK)
/// Page is present
#define PG_PRESENT (1 << 0)
/// Page is read- and writable
#define PG_RW (1 << 1)
/// Page is addressable from userspace
#define PG_USER (1 << 2)
/// Page write through is activated
#define PG_PWT (1 << 3)
/// Page cache is disabled
#define PG_PCD (1 << 4)
/// Page was recently accessed (set by CPU)
#define PG_ACCESSED (1 << 5)
/// Page is dirty due to recent write-access (set by CPU)
#define PG_DIRTY (1 << 6)
/// Huge page: 4MB (or 2MB, 1GB)
#define PG_PSE (1 << 7)
/// Page attribute table
#define PG_PAT PG_PSE
/// Global TLB entry (Pentium Pro and later)
#define PG_GLOBAL (1 << 8)
/// This table is a self-reference and should skipped by page_map_copy()
#define PG_SELF (1 << 9)
#ifdef CONFIG_X86_64
/// Disable execution for this page
#define PG_XD (1L << 63)
#endif
/** @brief Converts a virtual address to a physical
*
* A non mapped virtual address causes a pagefault!
*
* @param addr Virtual address to convert
* @return physical address
*/
size_t virt_to_phys(size_t vir);
/** @brief Initialize paging subsystem
*
* This function uses the existing bootstrap page tables (boot_{pgd, pgt})
* to map required regions (video memory, kernel, etc..).
* Before calling page_init(), the bootstrap tables contain a simple identity
* paging. Which is replaced by more specific mappings.
*/
int page_init(void);
/** @brief Map a continuous region of pages
*
* @param viraddr Desired virtual address
* @param phyaddr Physical address to map from
* @param npages The region's size in number of pages
* @param bits Further page flags
* @return
*/
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits);
/** @brief Unmap a continuous region of pages
*
* @param viraddr The virtual start address
* @param npages The range's size in pages
* @return
*/
int page_unmap(size_t viraddr, size_t npages);
/** @brief Allocate a physical page frame
*/
size_t get_page(void);
#endif

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __STDARG_H__
#define __STDARG_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef __builtin_va_list va_list;
/// Initialize a variable argument list
#define va_start __builtin_va_start
/// Retrieve next argument
#define va_arg __builtin_va_arg
/// End using variable argument list
#define va_end __builtin_va_end
/// copies the (previously initialized) variable argument list
#define va_copy __builtin_va_copy
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This file contains typedefs for standard datatypes for numerical and character values.
*/
#ifndef __STDDEF_H__
#define __STDDEF_H__
#ifdef __cplusplus
extern "C" {
#endif
#define NULL ((void*) 0)
#define BUILTIN_EXPECT(exp, b) __builtin_expect((exp), (b))
//#define BUILTIN_EXPECT(exp, b) (exp)
#if __SIZEOF_POINTER__ == 4
#define CONFIG_X86_32
/// This type is used to represent the size of an object.
typedef unsigned long size_t;
/// Pointer differences
typedef long ptrdiff_t;
/// It is similar to size_t, but must be a signed type.
typedef long ssize_t;
/// The type represents an offset and is similar to size_t, but must be a signed type.
typedef long off_t;
#elif __SIZEOF_POINTER__ == 8
#define CONFIG_X86_64
// A popular type for addresses
typedef unsigned long long size_t;
/// Pointer differences
typedef long long ptrdiff_t;
typedef long long ssize_t;
typedef long long off_t;
#else
#error unsupported architecture
#endif
/// Unsigned 64 bit integer
typedef unsigned long long uint64_t;
/// Signed 64 bit integer
typedef long long int64_t;
/// Unsigned 32 bit integer
typedef unsigned int uint32_t;
/// Signed 32 bit integer
typedef int int32_t;
/// Unsigned 16 bit integer
typedef unsigned short uint16_t;
/// Signed 16 bit integer
typedef short int16_t;
/// Unsigned 8 bit integer (/char)
typedef unsigned char uint8_t;
/// Signed 8 bit integer (/char)
typedef char int8_t;
/// 16 bit wide char type
typedef unsigned short wchar_t;
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __STDIO_H__
#define __STDIO_H__
#include <stddef.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Works like the ANSI C function puts
*/
int kputs(const char *);
/**
* Works like the ANSI C function putchar
*/
int kputchar(int);
/**
* Works like the ANSI C function printf
*/
int kprintf(const char*, ...);
/**
* Initialize the I/O functions
*/
int koutput_init(void);
/**
* Works like the ANSI c function sprintf
*/
int ksprintf(char *str, const char *format, ...);
/**
* Works like the ANSI c function sprintf
*/
int ksnprintf(char *str, size_t size, const char *format, ...);
/**
* Scaled down version of printf(3)
*/
int kvprintf(char const *fmt, void (*func) (int, void *), void *arg, int radix, va_list ap);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __STRING_H__
#define __STRING_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void *memcpy(void *dest, const void *src, size_t count);
void *memset(void *dest, int val, size_t count);
size_t strlen(const char *str);
char *strncpy(char *dest, const char *src, size_t n);
char *strcpy(char *dest, const char *src);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strstr(const char *s, const char *find);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __VGA_H__
#define __VGA_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Initialize VGA output and clear the screen */
void vga_init(void);
/** @brief Simple string output on screen.
*
* If you want a new line you will have to "\\n".
*
* @return Length of output in bytes
*/
int vga_puts(const char *text);
/** @brief Simple character output on screen.
*
* @return The original input character casted to int
*/
int vga_putchar(unsigned char c);
/** @brief Clear the screen */
void vga_cls(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,28 @@
OUTPUT_FORMAT("elf64-x86-64")
OUTPUT_ARCH("i386:x86-64")
ENTRY(start)
phys = 0x000000100000;
SECTIONS
{
kernel_start = phys;
.mboot phys : AT(ADDR(.mboot)) {
*(.mboot)
}
.text ALIGN(4096) : AT(ADDR(.text)) {
*(.text)
}
.rodata ALIGN(4096) : AT(ADDR(.rodata)) {
*(.rodata)
*(.rodata.*)
}
.data ALIGN(4096) : AT(ADDR(.data)) {
*(.data)
}
.bss ALIGN(4096) : AT(ADDR(.bss)) {
bss_start = .;
*(.bss)
}
bss_end = .;
kernel_end = .;
}

View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2016, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <multiboot.h>
#include <elf.h>
#include <page.h>
/*
* Note that linker symbols are not variables, they have no memory allocated for
* maintaining a value, rather their address is their value.
*/
extern const void kernel_start;
extern const void kernel_end;
extern const void bss_start;
extern const void bss_end;
void main(void)
{
elf_header_t* header = NULL;
// initialize .bss section
memset((void*)&bss_start, 0x00, ((size_t) &bss_end - (size_t) &bss_start));
koutput_init();
kputs("HermitCore loader...\n");
kprintf("Loader starts at %p and ends at %p\n", &kernel_start, &kernel_end);
page_init();
if (mb_info) {
if (mb_info->flags & MULTIBOOT_INFO_MEM_MAP) {
size_t end_addr, start_addr;
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) ((size_t) mb_info->mmap_addr);
multiboot_memory_map_t* mmap_end = (void*) ((size_t) mb_info->mmap_addr + mb_info->mmap_length);
// mark available memory as free
while (mmap < mmap_end) {
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
/* set the available memory as "unused" */
start_addr = mmap->addr;
end_addr = start_addr + mmap->len;
kprintf("Free region 0x%zx - 0x%zx\n", start_addr, end_addr);
}
mmap = (multiboot_memory_map_t*) ((size_t) mmap + sizeof(uint32_t) + mmap->size);
}
} else {
goto failed;
}
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
if (!mb_info->mods_count) {
kputs("Ups, we need at least one module!\n");
goto failed;
}
// per default the first module is our HermitCore binary
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
header = (elf_header_t*) ((size_t) mmodule[0].mod_start);
kprintf("ELF file is located at %p\n", header);
}
} else {
goto failed;
}
if (BUILTIN_EXPECT(!header, 0))
goto failed;
if (BUILTIN_EXPECT(header->ident.magic != ELF_MAGIC, 0))
goto invalid;
if (BUILTIN_EXPECT(header->type != ELF_ET_EXEC, 0))
goto invalid;
if (BUILTIN_EXPECT(header->machine != ELF_EM_X86_64, 0))
goto invalid;
if (BUILTIN_EXPECT(header->ident._class != ELF_CLASS_64, 0))
goto invalid;
if (BUILTIN_EXPECT(header->ident.data != ELF_DATA_2LSB, 0))
goto invalid;
if (header->ident.pad[0] != 0x42) {
kprintf("ELF file doesn't contain a HermitCore application (OS/ABI 0x%x)\n", (uint32_t)header->ident.pad[0]);
goto invalid;
}
for (int i=0; i<header->ph_entry_count; i++) {
elf_program_header_t* prog_header;
prog_header = (elf_program_header_t*) (header->ph_offset+i*header->ph_entry_size+(size_t)header);
switch(prog_header->type)
{
case ELF_PT_LOAD: { // load program segment
size_t viraddr = prog_header->virt_addr;
size_t phyaddr = prog_header->offset + (size_t)header;
uint32_t npages = (prog_header->file_size >> PAGE_BITS);
if (prog_header->file_size & (PAGE_SIZE-1))
npages++;
kprintf("Map %u pages from physical start address 0x%zx linear to 0x%zx\n", npages, phyaddr, viraddr);
int ret = page_map(viraddr, phyaddr, npages, PG_GLOBAL|PG_RW);
if (ret)
goto failed;
*((uint64_t*) (viraddr + 0x08)) = phyaddr; // physical start address
*((uint32_t*) (viraddr + 0x1C)) = 0; // apicid;
*((uint32_t*) (viraddr + 0x24)) = 1; // number of used cpus
*((uint64_t*) (viraddr + 0x38)) = prog_header->file_size;
*((uint32_t*) (viraddr + 0x60)) = 1; // numa nodes
*((uint32_t*) (viraddr + 0x30)) = 0; // apicid
}
break;
case ELF_PT_GNU_STACK: // Indicates stack executability => nothing todo
break;
default:
kprintf("Unknown type %d\n", prog_header->type);
}
}
kprintf("Entry point: 0x%zx\n", header->entry);
// jump to the HermitCore app
asm volatile ("jmp *%0" :: "r"(header->entry) : "memory");
// we should never reach this point
while(1);
failed:
kputs("Upps, kernel panic!\n");
while(1);
invalid:
kprintf("Invalid executable!\n");
kprintf("magic number 0x%x\n", (uint32_t) header->ident.magic);
kprintf("header type 0x%x\n", (uint32_t) header->type);
kprintf("machine type 0x%x\n", (uint32_t) header->machine);
kprintf("elf ident class 0x%x\n", (uint32_t) header->ident._class);
kprintf("elf identdata 0x%x\n", header->ident.data);
kprintf("program entry point 0x%lx\n", (size_t) header->entry);
while(1);
}

View file

@ -0,0 +1,222 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* 2014, Steffen Vogel, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This is a 32/64 bit portable paging implementation for the x86 architecture
* using self-referenced page tables i.
* See http://www.noteblok.net/2014/06/14/bachelor/ for a detailed description.
*
* @author Steffen Vogel <steffen.vogel@rwth-aachen.de>
*/
#include <stdio.h>
#include <string.h>
#include <page.h>
#include <multiboot.h>
/* Note that linker symbols are not variables, they have no memory
* allocated for maintaining a value, rather their address is their value. */
extern const void kernel_start;
extern const void kernel_end;
/// This page is reserved for copying
#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE)
/** This PGD table is initialized in entry.asm */
extern size_t* boot_map;
#ifdef CONFIG_X86_32
/** A self-reference enables direct access to all page tables */
static size_t * const self[PAGE_LEVELS] = {
(size_t *) 0xFFC00000,
(size_t *) 0xFFFFF000
};
/** An other self-reference for page_map_copy() */
static size_t * const other[PAGE_LEVELS] = {
(size_t *) 0xFF800000,
(size_t *) 0xFFFFE000
};
#elif defined(CONFIG_X86_64)
/** A self-reference enables direct access to all page tables */
static size_t* const self[PAGE_LEVELS] = {
(size_t *) 0xFFFFFF8000000000,
(size_t *) 0xFFFFFFFFC0000000,
(size_t *) 0xFFFFFFFFFFE00000,
(size_t *) 0xFFFFFFFFFFFFF000
};
/** An other self-reference for page_map_copy() */
static size_t * const other[PAGE_LEVELS] = {
(size_t *) 0xFFFFFF0000000000,
(size_t *) 0xFFFFFFFF80000000,
(size_t *) 0xFFFFFFFFFFC00000,
(size_t *) 0xFFFFFFFFFFFFE000
};
#endif
/** @brief Flush a specific page entry in TLB
* * @param addr The (virtual) address of the page to flush
* */
static inline void tlb_flush_one_page(size_t addr)
{
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
}
size_t virt_to_phys(size_t addr)
{
size_t vpn = addr >> PAGE_BITS; // virtual page number
size_t entry = self[0][vpn]; // page table entry
size_t off = addr & ~PAGE_MASK; // offset within page
size_t phy = entry & PAGE_MASK; // physical page frame number
return phy | off;
}
static size_t first_page = (size_t) &kernel_start - PAGE_SIZE;
size_t get_page(void)
{
size_t ret = first_page;
first_page += PAGE_SIZE;
return ret;
}
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
{
int lvl, ret = -1;
long vpn = viraddr >> PAGE_BITS;
long first[PAGE_LEVELS], last[PAGE_LEVELS];
/* Calculate index boundaries for page map traversal */
for (lvl=0; lvl<PAGE_LEVELS; lvl++) {
first[lvl] = (vpn ) >> (lvl * PAGE_MAP_BITS);
last[lvl] = (vpn+npages-1) >> (lvl * PAGE_MAP_BITS);
}
/* Start iterating through the entries
* beginning at the root table (PGD or PML4) */
for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) {
for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) {
if (lvl) { /* PML4, PDPT, PGD */
if (!(self[lvl][vpn] & PG_PRESENT)) {
/* There's no table available which covers the region.
* Therefore we need to create a new empty table. */
size_t phyaddr = get_page();
if (BUILTIN_EXPECT(!phyaddr, 0))
goto out;
/* Reference the new table within its parent */
#ifdef CONFIG_X86_32
self[lvl][vpn] = phyaddr | bits | PG_PRESENT | PG_USER | PG_RW;
#elif defined(CONFIG_X86_64)
self[lvl][vpn] = (phyaddr | bits | PG_PRESENT | PG_USER | PG_RW) & ~PG_XD;
#endif
/* Fill new table with zeros */
memset(&self[lvl-1][vpn<<PAGE_MAP_BITS], 0, PAGE_SIZE);
}
}
else { /* PGT */
if (self[lvl][vpn] & PG_PRESENT)
/* There's already a page mapped at this address.
* We have to flush a single TLB entry. */
tlb_flush_one_page(vpn << PAGE_BITS);
self[lvl][vpn] = phyaddr | bits | PG_PRESENT;
phyaddr += PAGE_SIZE;
}
}
}
ret = 0;
out:
return ret;
}
/** Tables are freed by page_map_drop() */
int page_unmap(size_t viraddr, size_t npages)
{
/* We aquire both locks for kernel and task tables
* as we dont know to which the region belongs. */
/* Start iterating through the entries.
* Only the PGT entries are removed. Tables remain allocated. */
size_t vpn, start = viraddr>>PAGE_BITS;
for (vpn=start; vpn<start+npages; vpn++)
self[0][vpn] = 0;
/* This can't fail because we don't make checks here */
return 0;
}
int page_init(void)
{
/* Map multiboot information and modules */
if (mb_info) {
size_t addr, npages;
int ret;
// already mapped => entry.asm
//addr = (size_t) mb_info & PAGE_MASK;
//npages = PAGE_FLOOR(sizeof(*mb_info)) >> PAGE_BITS;
//page_map(addr, addr, npages, PG_GLOBAL);
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
addr = mb_info->mods_addr;
npages = PAGE_FLOOR(mb_info->mods_count*sizeof(multiboot_module_t)) >> PAGE_BITS;
ret = page_map(addr, addr, npages, PG_GLOBAL);
kprintf("Map module info at 0x%lx (ret %d)\n", addr, ret);
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
// at first we determine the first free page
for(int i=0; i<mb_info->mods_count; i++) {
if (first_page < mmodule[i].mod_end)
first_page = PAGE_FLOOR(mmodule[i].mod_end);
}
// we map only the first page of each module (= ELF file) because
// we need only the program header of the ELF file
for(int i=0; i<mb_info->mods_count; i++) {
addr = mmodule[i].mod_start;
//npages = PAGE_FLOOR(mmodule[i].mod_end - mmodule[i].mod_start) >> PAGE_BITS;
ret = page_map(addr, addr, 1 /*npages*/, PG_GLOBAL);
kprintf("Map first page of module %d at 0x%lx (ret %d)\n", i, addr, ret);
}
}
}
kprintf("Page pool starts at 0x%zx\n", first_page);
return 0;
}

View file

@ -0,0 +1,485 @@
/*-
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
*/
/*
* printf implementation is based on a implementation which was
* published at http://www.pagetable.com/?p=298.
* The authors built a full-featured standalone version of printf(). The
* base code has been taken from FreeBSD (sys/kern/subr_prf.c) and is
* consequently BSD-licensed. Unnecessary functions have been removed and
* all typedefs required have been added.
*/
#include <string.h>
#define __64BIT__
#ifdef __64BIT__
typedef unsigned long long uintmax_t;
typedef long long intmax_t;
#else
typedef unsigned int uintmax_t;
typedef int intmax_t;
#endif
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef unsigned short u_short;
typedef unsigned long long u_quad_t;
typedef long long quad_t;
typedef unsigned long uintptr_t;
#define NBBY 8 /* number of bits in a byte */
char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define hex2ascii(hex) (hex2ascii_data[hex])
#define va_list __builtin_va_list
#define va_start __builtin_va_start
#define va_arg __builtin_va_arg
#define va_end __builtin_va_end
#define toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z')))
/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
/*
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
* order; return an optional length and a pointer to the last character
* written in the buffer (i.e., the first character of the string).
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
*/
static char *ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
{
char *p, c;
p = nbuf;
*p = '\0';
do {
c = hex2ascii(num % base);
*++p = upper ? toupper(c) : c;
} while (num /= base);
if (lenp)
*lenp = p - nbuf;
return (p);
}
/*
* Scaled down version of printf(3).
*
* Two additional formats:
*
* The format %b is supported to decode error registers.
* Its usage is:
*
* printf("reg=%b\n", regval, "*");
*
* where the output base is expressed as a control character, e.g.
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
* the first of which gives the bit number to be inspected (origin 1), and
* the next characters (up to a control character, i.e. a character <= 32),
* give the name of the register. Thus:
*
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
*
* would produce output:
*
* reg=3
*
* XXX: %D -- Hexdump, takes pointer and separator string:
* ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
* ("%*D", len, ptr, " " -> XX XX XX XX ...
*/
int kvprintf(char const *fmt, void (*func) (int, void *), void *arg, int radix,
va_list ap)
{
#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
char nbuf[MAXNBUF];
char *d;
const char *p, *percent, *q;
u_char *up;
int ch, n;
uintmax_t num;
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
int cflag, hflag, jflag, tflag, zflag;
int dwidth, upper;
char padc;
int stop = 0, retval = 0;
num = 0;
if (!func)
d = (char *)arg;
else
d = NULL;
if (fmt == NULL)
fmt = "(fmt null)\n";
if (radix < 2 || radix > 36)
radix = 10;
for (;;) {
padc = ' ';
width = 0;
while ((ch = (u_char) * fmt++) != '%' || stop) {
if (ch == '\0')
return (retval);
PCHAR(ch);
}
percent = fmt - 1;
qflag = 0;
lflag = 0;
ladjust = 0;
sharpflag = 0;
neg = 0;
sign = 0;
dot = 0;
dwidth = 0;
upper = 0;
cflag = 0;
hflag = 0;
jflag = 0;
tflag = 0;
zflag = 0;
reswitch: switch (ch = (u_char) * fmt++) {
case '.':
dot = 1;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case '+':
sign = 1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '%':
PCHAR(ch);
break;
case '*':
if (!dot) {
width = va_arg(ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
} else {
dwidth = va_arg(ap, int);
}
goto reswitch;
case '0':
if (!dot) {
padc = '0';
goto reswitch;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
for (n = 0;; ++fmt) {
n = n * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
if (dot)
dwidth = n;
else
width = n;
goto reswitch;
case 'b':
num = (u_int) va_arg(ap, int);
p = va_arg(ap, char *);
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
PCHAR(*q--);
if (num == 0)
break;
for (tmp = 0; *p;) {
n = *p++;
if (num & (1 << (n - 1))) {
PCHAR(tmp ? ',' : '<');
for (; (n = *p) > ' '; ++p)
PCHAR(n);
tmp = 1;
} else
for (; *p > ' '; ++p)
continue;
}
if (tmp)
PCHAR('>');
break;
case 'c':
PCHAR(va_arg(ap, int));
break;
case 'D':
up = va_arg(ap, u_char *);
p = va_arg(ap, char *);
if (!width)
width = 16;
while (width--) {
PCHAR(hex2ascii(*up >> 4));
PCHAR(hex2ascii(*up & 0x0f));
up++;
if (width)
for (q = p; *q; q++)
PCHAR(*q);
}
break;
case 'd':
case 'i':
base = 10;
sign = 1;
goto handle_sign;
case 'h':
if (hflag) {
hflag = 0;
cflag = 1;
} else
hflag = 1;
goto reswitch;
case 'j':
jflag = 1;
goto reswitch;
case 'l':
if (lflag) {
lflag = 0;
qflag = 1;
} else
lflag = 1;
goto reswitch;
case 'n':
if (jflag)
*(va_arg(ap, intmax_t *)) = retval;
else if (qflag)
*(va_arg(ap, quad_t *)) = retval;
else if (lflag)
*(va_arg(ap, long *)) = retval;
else if (zflag)
*(va_arg(ap, size_t *)) = retval;
else if (hflag)
*(va_arg(ap, short *)) = retval;
else if (cflag)
*(va_arg(ap, char *)) = retval;
else
*(va_arg(ap, int *)) = retval;
break;
case 'o':
base = 8;
goto handle_nosign;
case 'p':
base = 16;
sharpflag = (width == 0);
sign = 0;
num = (uintptr_t) va_arg(ap, void *);
goto number;
case 'q':
qflag = 1;
goto reswitch;
case 'r':
base = radix;
if (sign)
goto handle_sign;
goto handle_nosign;
case 's':
p = va_arg(ap, char *);
if (p == NULL)
p = "(null)";
if (!dot)
n = strlen(p);
else
for (n = 0; n < dwidth && p[n]; n++)
continue;
width -= n;
if (!ladjust && width > 0)
while (width--)
PCHAR(padc);
while (n--)
PCHAR(*p++);
if (ladjust && width > 0)
while (width--)
PCHAR(padc);
break;
case 't':
tflag = 1;
goto reswitch;
case 'u':
base = 10;
goto handle_nosign;
case 'X':
upper = 1;
case 'x':
base = 16;
goto handle_nosign;
case 'y':
base = 16;
sign = 1;
goto handle_sign;
case 'z':
zflag = 1;
goto reswitch;
handle_nosign:
sign = 0;
if (jflag)
num = va_arg(ap, uintmax_t);
else if (qflag)
num = va_arg(ap, u_quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, u_long);
else if (zflag)
num = va_arg(ap, size_t);
else if (hflag)
num = (u_short) va_arg(ap, int);
else if (cflag)
num = (u_char) va_arg(ap, int);
else
num = va_arg(ap, u_int);
goto number;
handle_sign:
if (jflag)
num = va_arg(ap, intmax_t);
else if (qflag)
num = va_arg(ap, quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, long);
else if (zflag)
num = va_arg(ap, ssize_t);
else if (hflag)
num = (short)va_arg(ap, int);
else if (cflag)
num = (char)va_arg(ap, int);
else
num = va_arg(ap, int);
number:
if (sign && (intmax_t) num < 0) {
neg = 1;
num = -(intmax_t) num;
}
p = ksprintn(nbuf, num, base, &tmp, upper);
if (sharpflag && num != 0) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (!ladjust && padc != '0' && width
&& (width -= tmp) > 0)
while (width--)
PCHAR(padc);
if (neg)
PCHAR('-');
if (sharpflag && num != 0) {
if (base == 8) {
PCHAR('0');
} else if (base == 16) {
PCHAR('0');
PCHAR('x');
}
}
if (!ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
while (*p)
PCHAR(*p--);
if (ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
break;
default:
while (percent < fmt)
PCHAR(*percent++);
/*
* Since we ignore a formatting argument it is no
* longer safe to obey the remaining formatting
* arguments as the arguments will no longer match
* the format specs.
*/
stop = 1;
break;
}
}
#undef PCHAR
}
/*
* Print directly a character on the screen
*/
extern int kputchar(int);
/*
* A wrapper function for kputchar because
* kvprintf needs an output function, which possesses two arguments.
* The first arguments defines the output character, the second could be used to pass
* additional arguments. In the case of kputchar is no additional argument needed.
*/
static void _putchar(int c, void *arg)
{
kputchar(c);
}
int kprintf(const char *fmt, ...)
{
int ret;
/* http://www.pagetable.com/?p=298 */
va_list ap;
va_start(ap, fmt);
ret = kvprintf(fmt,
_putchar, /* output function */
NULL, /* additional argument for the output function */
10, ap);
va_end(ap);
return ret;
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <multiboot.h>
#include <vga.h>
int koutput_init(void)
{
vga_init();
return 0;
}
int kputchar(int c)
{
vga_putchar(c);
return 1;
}
int kputs(const char *str)
{
#if 0
int i, len = strlen(str);
for(i=0; i<len; i++)
vga_putchar(str[i]);
return len;
#else
return vga_puts(str);
#endif
}

View file

@ -0,0 +1,106 @@
/*
* Written by the Chair for Operating Systems, RWTH Aachen University
*
* NO Copyright (C) 2010-2011, Stefan Lankes
* consider these trivial functions to be public domain.
*
* These functions are distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
void *memcpy(void *dest, const void *src, size_t count)
{
size_t i;
if (BUILTIN_EXPECT(!dest || !src, 0))
return dest;
for (i = 0; i < count; i++)
((char*)dest)[i] = ((char*)src)[i];
return dest;
}
void *memset(void *dest, int val, size_t count)
{
size_t i;
if (BUILTIN_EXPECT(!dest, 0))
return dest;
for (i = 0; i < count; i++)
((char*) dest)[i] = (char) val;
return dest;
}
size_t strlen(const char *str)
{
size_t len = 0;
if (BUILTIN_EXPECT(!str, 0))
return len;
while (str[len] != '\0')
len++;
return len;
}
char* strncpy(char *dest, const char *src, size_t n)
{
size_t i;
if (BUILTIN_EXPECT(!dest || !src, 0))
return dest;
for (i = 0 ; i < n && src[i] != '\0' ; i++)
dest[i] = src[i];
if (i < n)
dest[i] = '\0';
else
dest[n-1] = '\0';
return dest;
}
char* strcpy(char *dest, const char *src)
{
size_t i;
if (BUILTIN_EXPECT(!dest || !src, 0))
return dest;
for (i = 0 ; src[i] != '\0' ; i++)
dest[i] = src[i];
dest[i] = '\0';
return dest;
}
int strcmp(const char *s1, const char *s2)
{
while (*s1 != '\0' && *s1 == *s2) {
s1++;
s2++;
}
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
}
int strncmp(const char *s1, const char *s2, size_t n)
{
if (BUILTIN_EXPECT(n == 0, 0))
return 0;
while (n-- != 0 && *s1 == *s2) {
if (n == 0 || *s1 == '\0')
break;
s1++;
s2++;
}
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
}

View file

@ -0,0 +1,237 @@
/*
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <io.h>
#include <vga.h>
#define VIDEO_MEM_ADDR 0xB8000 /* the video memory address */
/*
* These define our textpointer, our background and foreground
* colors (attributes), and x and y cursor coordinates
*/
static unsigned short *textmemptr;
static int attrib = 0x0F;
static int csr_x = 0, csr_y = 0;
inline static unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count)
{
size_t i;
if (BUILTIN_EXPECT(!dest, 0))
return dest;
for (i = 0; i < count; i++)
dest[i] = val;
return dest;
}
/* Scrolls the screen */
static void scroll(void)
{
unsigned blank, temp;
/*
* A blank is defined as a space... we need to give it
* backcolor too
*/
blank = 0x20 | (attrib << 8);
/* Row 25 is the end, this means we need to scroll up */
if (csr_y >= 25) {
/*
* Move the current text chunk that makes up the screen
*
* back in the buffer by one line
*/
temp = csr_y - 25 + 1;
memcpy(textmemptr, textmemptr + temp * 80,
(25 - temp) * 80 * 2);
/*
* Finally, we set the chunk of memory that occupies
* the last line of text to our 'blank' character
*/
memsetw(textmemptr + (25 - temp) * 80, blank, 80);
csr_y = 25 - 1;
}
}
/*
* Updates the hardware cursor: the little blinking line
* on the screen under the last character pressed!
*/
static void move_csr(void)
{
unsigned temp;
/*
* The equation for finding the index in a linear
* chunk of memory can be represented by:
* Index = [(y * width) + x] */
temp = csr_y * 80 + csr_x;
/*
* This sends a command to indicies 14 and 15 in the
* CRT Control Register of the VGA controller. These
* are the high and low bytes of the index that show
* where the hardware cursor is to be 'blinking'. To
* learn more, you should look up some VGA specific
* programming documents. A great start to graphics:
* http://www.brackeen.com/home/vga
*/
outportb(0x3D4, 14);
outportb(0x3D5, temp >> 8);
outportb(0x3D4, 15);
outportb(0x3D5, temp);
}
/* Clears the screen */
void vga_clear(void)
{
unsigned blank;
int i;
/*
* Again, we need the 'short' that will be used to
* represent a space with color
*/
blank = 0x20 | (attrib << 8);
/*
* Fills the entire screen with spaces in our current
* color
**/
for (i = 0; i < 25; i++)
memsetw(textmemptr + i * 80, blank, 80);
/*
* Update out virtual cursor, and then move the
* hardware cursor
*/
csr_x = 0;
csr_y = 0;
move_csr();
}
/* Puts a single character on the screen */
int vga_putchar(unsigned char c)
{
unsigned short *where;
unsigned att = attrib << 8;
/* Handle a backspace by moving the cursor back one space */
if (c == 0x08) {
if (csr_x != 0)
csr_x--;
}
/*
* Handles a tab by incrementing the cursor's x, but only
* to a point that will make it divisible by 8
*/
else if (c == 0x09) {
csr_x = (csr_x + 8) & ~(8 - 1);
}
/*
* Handles a 'Carriage Return', which simply brings the
* cursor back to the margin
*/
else if (c == '\r') {
csr_x = 0;
}
/*
* We handle our newlines the way DOS and BIOS do: we
* treat it as if a 'CR' was there also, so we bring the
* cursor to the margin and increment the 'y' value
*/
else if (c == '\n') {
csr_x = 0;
csr_y++;
}
/*
* Any character greater than and including the space is a
* printable character. The equation for finding the index
* in a linear chunk of memory can be represented by:
* Index = [(y * width) + x]
*/
else if (c >= ' ') {
where = textmemptr + (csr_y * 80 + csr_x);
*where = c | att; /* Character AND attributes: color */
csr_x++;
}
/*
* If the cursor has reached the edge of the screen's width, we
* insert a new line in there
*/
if (csr_x >= 80) {
csr_x = 0;
csr_y++;
}
/* Scroll the screen if needed, and finally move the cursor */
scroll();
move_csr();
return (int) c;
}
/* Uses the routine above to output a string... */
int vga_puts(const char *text)
{
size_t i;
for (i = 0; i < strlen(text); i++)
vga_putchar(text[i]);
return i-1;
}
/* Sets the forecolor and backcolor we will use */
//void settextcolor(unsigned char forecolor, unsigned char backcolor)
//{
/*
* Top 4 bytes are the background, bottom 4 bytes
* are the foreground color
*/
// attrib = (backcolor << 4) | (forecolor & 0x0F);
//}
/* Sets our text-mode VGA pointer, then clears the screen for us */
void vga_init(void)
{
textmemptr = (unsigned short *)VIDEO_MEM_ADDR;
vga_clear();
}