diff --git a/hermit/arch/x86/loader/Makefile b/hermit/arch/x86/loader/Makefile new file mode 100644 index 000000000..58c269554 --- /dev/null +++ b/hermit/arch/x86/loader/Makefile @@ -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 diff --git a/hermit/arch/x86/loader/entry.asm b/hermit/arch/x86/loader/entry.asm new file mode 100644 index 000000000..7d6325808 --- /dev/null +++ b/hermit/arch/x86/loader/entry.asm @@ -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 diff --git a/hermit/arch/x86/loader/include/elf.h b/hermit/arch/x86/loader/include/elf.h new file mode 100644 index 000000000..44c0fb8e5 --- /dev/null +++ b/hermit/arch/x86/loader/include/elf.h @@ -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 + +#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 diff --git a/hermit/arch/x86/loader/include/io.h b/hermit/arch/x86/loader/include/io.h new file mode 100644 index 000000000..84c2619e2 --- /dev/null +++ b/hermit/arch/x86/loader/include/io.h @@ -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 diff --git a/hermit/arch/x86/loader/include/multiboot.h b/hermit/arch/x86/loader/include/multiboot.h new file mode 100644 index 000000000..298091610 --- /dev/null +++ b/hermit/arch/x86/loader/include/multiboot.h @@ -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 + +/// 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 diff --git a/hermit/arch/x86/loader/include/page.h b/hermit/arch/x86/loader/include/page.h new file mode 100644 index 000000000..ddb158505 --- /dev/null +++ b/hermit/arch/x86/loader/include/page.h @@ -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 + +#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 diff --git a/hermit/arch/x86/loader/include/stdarg.h b/hermit/arch/x86/loader/include/stdarg.h new file mode 100644 index 000000000..c8596ab01 --- /dev/null +++ b/hermit/arch/x86/loader/include/stdarg.h @@ -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 diff --git a/hermit/arch/x86/loader/include/stddef.h b/hermit/arch/x86/loader/include/stddef.h new file mode 100644 index 000000000..36f95f25f --- /dev/null +++ b/hermit/arch/x86/loader/include/stddef.h @@ -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 diff --git a/hermit/arch/x86/loader/include/stdio.h b/hermit/arch/x86/loader/include/stdio.h new file mode 100644 index 000000000..db7f54d47 --- /dev/null +++ b/hermit/arch/x86/loader/include/stdio.h @@ -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 +#include + +#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 diff --git a/hermit/arch/x86/loader/include/string.h b/hermit/arch/x86/loader/include/string.h new file mode 100644 index 000000000..84ef64a67 --- /dev/null +++ b/hermit/arch/x86/loader/include/string.h @@ -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 + +#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 diff --git a/hermit/arch/x86/loader/include/vga.h b/hermit/arch/x86/loader/include/vga.h new file mode 100644 index 000000000..ff85ff996 --- /dev/null +++ b/hermit/arch/x86/loader/include/vga.h @@ -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 + +#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 diff --git a/hermit/arch/x86/loader/link.ld b/hermit/arch/x86/loader/link.ld new file mode 100644 index 000000000..a14b411ca --- /dev/null +++ b/hermit/arch/x86/loader/link.ld @@ -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 = .; +} diff --git a/hermit/arch/x86/loader/main.c b/hermit/arch/x86/loader/main.c new file mode 100644 index 000000000..457a8d8b1 --- /dev/null +++ b/hermit/arch/x86/loader/main.c @@ -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 +#include +#include +#include +#include +#include + +/* + * 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; iph_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); +} diff --git a/hermit/arch/x86/loader/page.c b/hermit/arch/x86/loader/page.c new file mode 100644 index 000000000..39eb54265 --- /dev/null +++ b/hermit/arch/x86/loader/page.c @@ -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 + */ + +#include +#include +#include +#include + +/* 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> (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_BITS; + for (vpn=start; vpn 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; imods_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; imods_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; +} diff --git a/hermit/arch/x86/loader/printf.c b/hermit/arch/x86/loader/printf.c new file mode 100644 index 000000000..25e4b20a5 --- /dev/null +++ b/hermit/arch/x86/loader/printf.c @@ -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 + +#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; +} diff --git a/hermit/arch/x86/loader/stdio.c b/hermit/arch/x86/loader/stdio.c new file mode 100644 index 000000000..e37296437 --- /dev/null +++ b/hermit/arch/x86/loader/stdio.c @@ -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 +#include +#include + +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 + +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); +} diff --git a/hermit/arch/x86/loader/vga.c b/hermit/arch/x86/loader/vga.c new file mode 100644 index 000000000..589df0a4d --- /dev/null +++ b/hermit/arch/x86/loader/vga.c @@ -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 +#include +#include + +#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(); +}