diff --git a/.gitmodules b/.gitmodules index ee284bdb0..e1624b412 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = usr/libomp url = https://github.com/RWTH-OS/libomp_oss.git branch = hermit +[submodule "librs/rust"] + path = librs/rust + url = https://github.com/RWTH-OS/rust.git diff --git a/.travis.yml b/.travis.yml index f7b44a0ac..c8c57585d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,102 @@ sudo: required dist: trusty +language: c + git: submodules: true env: global: - PATH=$PATH:~/.cargo/bin -language: c -compiler: - - clang - - gcc +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: + - COMPILERCXX=g++-4.9 + - COMPILERC=gcc-4.9 + - DEPLOY=true + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: + - COMPILERCXX=g++-5 + - COMPILERC=gcc-5 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: + - COMPILERCXX=g++-6 + - COMPILERC=gcc-6 + - compiler: clang + env: + - COMPILERC=clang + - COMPILERCXX=clang++ + - CLANGV=3.8.1 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + - compiler: clang + env: + - COMPILERC=clang + - COMPILERCXX=clang++ + - CLANGV=3.9.1 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + - compiler: clang + env: + - COMPILERC=clang + - COMPILERCXX=clang++ + - CLANGV=4.0.1 + - RUNCLANGTIDY=TRUE + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + before_install: - echo "deb https://dl.bintray.com/rwth-os/hermitcore vivid main" | sudo tee -a /etc/apt/sources.list - travis_retry sudo apt-get -qq update - travis_retry sudo apt-get install -y curl wget qemu-system-x86 nasm texinfo libmpfr-dev libmpc-dev libgmp-dev libisl-dev flex bison packaging-dev rpm g++-multilib - travis_retry sudo apt-get install -y --force-yes binutils-hermit libhermit newlib-hermit pthread-embedded-hermit gcc-hermit + - git submodule update --init lwip usr/libomp + # download clang + - mkdir $HOME/clang+llvm + - export PATH=$HOME/clang+llvm/bin:$PATH + - if [ -n "$CLANGV" ]; then wget http://llvm.org/releases/$CLANGV/clang+llvm-$CLANGV-x86_64-linux-gnu-debian8.tar.xz -O $HOME/clang+llvm.tar.xz; fi + - if [ -n "$CLANGV" ]; then tar xf $HOME/clang+llvm.tar.xz -C $HOME/clang+llvm --strip-components 1; fi script: - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly - source cmake/local-cmake.sh + - cd librs + - make runtime + - cd - - mkdir build - cd build - - cmake .. - - make -j1 package + - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=true .. + - CC=$COMPILERC CXX=$COMPILERCXX make -j1 package - cd $TRAVIS_BUILD_DIR # - ./tests.sh @@ -29,9 +104,9 @@ notifications: slack: hermitcore:UtcfeEXkbpx3WyIDK2Wm2beS deploy: - on: + on: branch: master - condition: "$CC = gcc" + condition: $DEPLOY = true provider: bintray file: .bintray_descriptor.json user: diff --git a/CMakeLists.txt b/CMakeLists.txt index ef41c0992..0cf814b8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,53 @@ set_target_properties(hermit-bootstrap PROPERTIES # dependency makes sure that this is done before hermit is linked add_dependencies(hermit-bootstrap ${X86_KERNEL_TARGET}) +# add external project hermit-rs +ExternalProject_Add( + objmv + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND cargo build --release + BINARY_DIR "${CMAKE_SOURCE_DIR}/objmv" + INSTALL_COMMAND "" + LOG_BUILD ON) + +# add external project hermit-rs +ExternalProject_Add( + hermit-rs + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND make all + BINARY_DIR "${CMAKE_SOURCE_DIR}/librs" + INSTALL_COMMAND "" + LOG_BUILD ON) + +# Create dependency of hermit-rs objmv +add_dependencies(hermit-rs objmv) +# Create dependency of hermit-boostrap hermit-rs +add_dependencies(hermit-bootstrap hermit-rs) + +add_custom_command( + TARGET + hermit-rs POST_BUILD + # rename sections in rust library + COMMAND + ${CMAKE_SOURCE_DIR}/objmv/target/release/objmv + ${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a + + # convert rust library to hermitcore's osabi + COMMAND + ${CMAKE_ELFEDIT} --output-osabi HermitCore ${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a + + # copy libhermit_rs.a into local prefix directory so that all subsequent + # targets can link against the freshly built version (as opposed to + # linking against the one supplied by the toolchain) + COMMAND + ${CMAKE_COMMAND} -E make_directory ${LOCAL_PREFIX_ARCH_LIB_DIR} + COMMAND + ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a + ${LOCAL_PREFIX_ARCH_LIB_DIR}/) + add_custom_command( TARGET hermit-bootstrap POST_BUILD @@ -76,6 +123,18 @@ add_custom_command( --rename-section .data=.kdata $ + # merge libhermit.a and libhermit_rs.a + COMMAND + ${CMAKE_AR} x ${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a + COMMAND + ${CMAKE_AR} rcs $ *.o + COMMAND + ${CMAKE_COMMAND} -E remove *.o + + # redefine _Unwind_Resume to avoid collision with libgcc.a + COMMAND + ${CMAKE_OBJCOPY} --redefine-sym _Unwind_Resume=_Unwind_Resume_rs $ + # copy libhermit.a into local prefix directory so that all subsequent # targets can link against the freshly built version (as opposed to # linking against the one supplied by the toolchain) diff --git a/README.md b/README.md index 12b358dce..c1cc54a11 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ the HermitCore kernel and applications you need: * Netwide Assember (NASM) * recent host compiler such as GCC * HermitCore cross-toolchain, i.e. Binutils, GCC, newlib, pthreads + * [Rust compiler (nightly release)](https://www.rust-lang.org/en-US/install.html) ### HermitCore cross-toolchain diff --git a/arch/x86/include/asm/gdt.h b/arch/x86/include/asm/gdt.h index e66ef8972..1f8c7f01d 100644 --- a/arch/x86/include/asm/gdt.h +++ b/arch/x86/include/asm/gdt.h @@ -111,7 +111,7 @@ typedef struct { } __attribute__ ((packed)) gdt_ptr_t; // a TSS descriptor is twice larger than a code/data descriptor -#define GDT_ENTRIES (6+MAX_CORES*2) +#define GDT_ENTRIES (7+MAX_CORES*2) #if GDT_ENTRIES > 8192 #error Too many GDT entries! diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 1c41dc58e..e273c6f57 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -48,11 +48,11 @@ #define PAGE_SIZE ( 1L << PAGE_BITS) /// Mask the page address without page map flags and XD flag #if 0 -#define PAGE_MASK ((~0L) << PAGE_BITS) -#define PAGE_2M_MASK (~0L) << PAGE_2M_BITS) +#define PAGE_MASK ((~0UL) << PAGE_BITS) +#define PAGE_2M_MASK (~0UL) << PAGE_2M_BITS) #else -#define PAGE_MASK (((~0L) << PAGE_BITS) & ~PG_XD) -#define PAGE_2M_MASK (((~0L) << PAGE_2M_BITS) & ~PG_XD) +#define PAGE_MASK (((~0UL) << PAGE_BITS) & ~PG_XD) +#define PAGE_2M_MASK (((~0UL) << PAGE_2M_BITS) & ~PG_XD) #endif #if 0 diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 5775dfbcc..a0951e7ba 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -141,6 +141,7 @@ start64: ; store pointer to the multiboot information mov [mb_info], QWORD rdx + ; ; relocate page tables mov rdi, boot_pml4 mov rax, QWORD [rdi] @@ -256,31 +257,6 @@ Lsmp_main: jmp $ %endif -ALIGN 64 -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] - ; reload the segment descriptors - mov eax, 0x10 - mov ds, eax - mov es, eax - mov ss, eax - xor eax, eax - mov fs, eax - mov gs, eax - ; create pseudo interrupt to set cs - push QWORD 0x10 ; SS - push rsp ; RSP - add QWORD [rsp], 0x08 ; => value of rsp before the creation of a pseudo interrupt - pushfq ; RFLAGS - push QWORD 0x08 ; CS - push QWORD rollback ; RIP - iretq - ; The first 32 interrupt service routines (ISR) entries correspond to exceptions. ; Some exceptions will push an error code onto the stack which is specific to ; the exception caused. To decrease the complexity, we handle this by pushing a diff --git a/arch/x86/kernel/gdt.c b/arch/x86/kernel/gdt.c index 8c1149c9f..3cc993130 100644 --- a/arch/x86/kernel/gdt.c +++ b/arch/x86/kernel/gdt.c @@ -35,6 +35,7 @@ #include #include +#if 0 #define MAX_IST 3 gdt_ptr_t gp; @@ -117,7 +118,7 @@ void gdt_install(void) * this entry's access byte says it's a Data Segment */ gdt_set_gate(num++, 0, 0, - GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, 0); + GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); /* * Create code segment for 32bit user-space applications (ring 3) @@ -141,7 +142,7 @@ void gdt_install(void) * Create data segment for 64bit user-space applications (ring 3) */ gdt_set_gate(num++, 0, 0, - GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, 0); + GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); /* * Create TSS for each core (we use these segments for task switching) @@ -160,3 +161,4 @@ void gdt_install(void) /* Flush out the old GDT and install the new changes! */ gdt_flush(); } +#endif diff --git a/arch/x86/loader/include/page.h b/arch/x86/loader/include/page.h index adf46fc72..8e93f7259 100644 --- a/arch/x86/loader/include/page.h +++ b/arch/x86/loader/include/page.h @@ -37,9 +37,9 @@ #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) +#define PAGE_MASK (~0UL << PAGE_BITS) #elif defined(CONFIG_X86_64) -#define PAGE_MASK ((-1L << PAGE_BITS) & ~PG_XD) +#define PAGE_MASK ((~0UL << PAGE_BITS) & ~PG_XD) #endif #ifdef CONFIG_X86_32 diff --git a/kernel/main.c b/kernel/main.c index b5c0bf214..ab06ccff5 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -98,7 +98,9 @@ extern volatile int libc_sd; islelock_t* rcce_lock = NULL; rcce_mpb_t* rcce_mpb = NULL; -extern void signal_init(); +extern void signal_init(void); +extern void rust_main(void); +extern void rust_init(void); static int hermit_init(void) { @@ -113,6 +115,7 @@ static int hermit_init(void) memcpy((char*) &percore_start + i*sz, (char*) &percore_start, sz); koutput_init(); + rust_init(); system_init(); irq_init(); timer_init(); @@ -539,6 +542,8 @@ int hermit_main(void) LOG_INFO("Kernel cmdline: %s\n", (char*) (size_t) mb_info->cmdline); if (hbmem_base) LOG_INFO("Found high bandwidth memory at 0x%zx (size 0x%zx)\n", hbmem_base, hbmem_size); + LOG_INFO("rust_main at %p\n", rust_main); + rust_main(); #if 0 print_pci_adapters(); diff --git a/libkern/muloti4.c b/libkern/muloti4.c new file mode 100644 index 000000000..76bb35a09 --- /dev/null +++ b/libkern/muloti4.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, 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 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. + * + */ + +/* HermitCore prelude */ +#include +#include +#include + +typedef int ti_int; + +/* + * Workarount for the LLVM bug https://llvm.org/bugs/show_bug.cgi?id=16404 + * + * rustc based on LLVM and uses this builtin function, which isn't part of + * libgcc. + */ +ti_int +__muloti4(ti_int a, ti_int b, int* overflow) +{ + size_t flags; + ti_int result; + + *overflow = 0; + result = a * b; + + asm volatile("pushf; pop %0": "=r"(flags) : : "memory"); + if (flags & (1ULL << 11)) + *overflow = 1; + + return result; +} diff --git a/librs/.gitignore b/librs/.gitignore new file mode 100644 index 000000000..a9d37c560 --- /dev/null +++ b/librs/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/librs/Cargo.toml b/librs/Cargo.toml new file mode 100644 index 000000000..a284446e6 --- /dev/null +++ b/librs/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "hermit-rs" +version = "0.2.2" +authors = [ + "Stefan Lankes ", +] + +[lib] +crate-type = ["staticlib"] + +[dependencies] +rlibc = "1.0.0" # Low-level functions like memcpy. +spin = "0.4.5" # Spinlocks. +raw-cpuid = "3.0.0" + +#[dependencies.lazy_static] +#version = "0.2.8" +#features = ["spin_no_std"] + +[dependencies.x86] +version = "0.7" +default-features = false + +# The development profile, used for `cargo build`. +[profile.dev] +opt-level = 0 # controls the `--opt-level` the compiler builds with +debug = true # controls whether the compiler passes `-C debuginfo` + # a value of `true` is equivalent to `2` +rpath = false # controls whether the compiler passes `-C rpath` +lto = false # controls `-C lto` for binaries and staticlibs +debug-assertions = true # controls whether debug assertions are enabled +codegen-units = 1 # controls whether the compiler passes `-C codegen-units` + # `codegen-units` is ignored when `lto = true` + +# The release profile, used for `cargo build --release`. +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 diff --git a/librs/Makefile b/librs/Makefile new file mode 100644 index 000000000..61f1493c5 --- /dev/null +++ b/librs/Makefile @@ -0,0 +1,51 @@ +# derived from http://blog.phil-opp.com/rust-os/multiboot-kernel.html + +arch ?= x86_64 +target ?= $(arch)-hermit +rust_os := target/$(target)/release/libhermit_rs.a + +.PHONY: all lib default clean cargo + +default: lib + +lib: cargo $(rust_os) + +all: runtime lib + +clean: + @cargo clean --target $(target) + +cargo: + @echo CARGO + @cargo build --target $(target) --release + +#========================================================================== +# Building the Rust runtime for our bare-metal target + +# Where to put our compiled runtime libraries for this platform. +installed_target_libs := \ + $(shell rustup which rustc | \ + sed s,bin/rustc,lib/rustlib/$(target)/lib,) + +runtime_rlibs := \ + $(installed_target_libs)/libcore.rlib \ + $(installed_target_libs)/libstd_unicode.rlib \ + $(installed_target_libs)/liballoc.rlib \ + $(installed_target_libs)/libcollections.rlib + +RUSTC := \ + rustc --verbose --target $(target) \ + -Z no-landing-pads \ + --out-dir $(installed_target_libs) + +.PHONY: runtime + +runtime: $(runtime_rlibs) + +$(installed_target_libs): + @mkdir -p $(installed_target_libs) + +$(installed_target_libs)/%.rlib: rust/src/%/lib.rs $(installed_target_libs) + @echo RUSTC $< + @$(RUSTC) $< + @echo Check $(installed_target_libs) diff --git a/librs/rust b/librs/rust new file mode 160000 index 000000000..230a379a4 --- /dev/null +++ b/librs/rust @@ -0,0 +1 @@ +Subproject commit 230a379a452e5a2bcdfd0a956b259e0a1d83b512 diff --git a/librs/src/arch/mod.rs b/librs/src/arch/mod.rs new file mode 100644 index 000000000..206742688 --- /dev/null +++ b/librs/src/arch/mod.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Export our platform-specific modules. +#[cfg(target_arch="x86_64")] +pub use self::x86_64::{processor, gdt}; + +// Implementations for x86_64. +#[cfg(target_arch="x86_64")] +pub mod x86_64; diff --git a/librs/src/arch/x86_64/gdt.rs b/librs/src/arch/x86_64/gdt.rs new file mode 100644 index 000000000..5072bc900 --- /dev/null +++ b/librs/src/arch/x86_64/gdt.rs @@ -0,0 +1,291 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#![allow(dead_code)] +#![allow(private_no_mangle_fns)] + +use consts::*; +use spin; +use x86::dtables::{self, DescriptorTablePointer}; +use x86::segmentation::{self, SegmentSelector}; +use core::mem::size_of; + +const GDT_NULL: usize = 0; +const GDT_KERNEL_CODE: usize = 1; +const GDT_KERNEL_DATA: usize = 2; + +// This segment is a data segment +const GDT_FLAG_DATASEG: u8 = 0x02; +/// This segment is a code segment +const GDT_FLAG_CODESEG: u8 = 0x0a; +const GDT_FLAG_TSS: u8 = 0x09; +const GDT_FLAG_TSS_BUSY: u8 = 0x02; + +const GDT_FLAG_SEGMENT: u8 = 0x10; +/// Privilege level: Ring 0 +const GDT_FLAG_RING0: u8 = 0x00; +/// Privilege level: Ring 1 +const GDT_FLAG_RING1: u8 = 0x20; +/// Privilege level: Ring 2 +const GDT_FLAG_RING2: u8 = 0x40; +/// Privilege level: Ring 3 +const GDT_FLAG_RING3: u8 = 0x60; +/// Segment is present +const GDT_FLAG_PRESENT: u8 = 0x80; +/// Segment was accessed +const GDT_FLAG_ACCESSED: u8 = 0x01; +/// Granularity of segment limit +/// - set: segment limit unit is 4 KB (page size) +/// - not set: unit is bytes +const GDT_FLAG_4K_GRAN: u8 = 0x80; +/// Default operand size +/// - set: 32 bit +/// - not set: 16 bit +const GDT_FLAG_16_BIT: u8 = 0x00; +const GDT_FLAG_32_BIT: u8 = 0x40; +const GDT_FLAG_64_BIT: u8 = 0x20; + +// a TSS descriptor is twice larger than a code/data descriptor +const GDT_ENTRIES: usize = (7+MAX_CORES*2); +const MAX_IST: usize = 3; + +// thread_local on a static mut, signals that the value of this static may +// change depending on the current thread. +static mut GDT: [GdtEntry; GDT_ENTRIES] = [GdtEntry::new(0, 0, 0, 0); GDT_ENTRIES]; +static mut GDTR: DescriptorTablePointer = DescriptorTablePointer { limit: 0, base: 0 }; +static mut TSS_BUFFER: TssBuffer = TssBuffer::new(); +static STACK_TABLE: [[IrqStack; MAX_IST]; MAX_CORES] = [[IrqStack::new(); MAX_IST]; MAX_CORES]; +static GDT_INIT: spin::Once<()> = spin::Once::new(); + +extern "C" { + static boot_stack: [u8; MAX_CORES*KERNEL_STACK_SIZE]; +} + +#[derive(Copy, Clone)] +#[repr(C, packed)] +struct GdtEntry { + /// Lower 16 bits of limit range + limit_low: u16, + /// Lower 16 bits of base address + base_low: u16, + /// middle 8 bits of base address + base_middle: u8, + /// Access bits + access: u8, + /// Granularity bits + granularity: u8, + /// Higher 8 bits of base address + base_high: u8 +} + +impl GdtEntry { + pub const fn new(base: u32, limit: u32, access: u8, gran: u8) -> Self { + GdtEntry { + limit_low: (limit & 0xFFFF) as u16, + base_low: (base & 0xFFFF) as u16, + base_middle: ((base >> 16) & 0xFF) as u8, + access: access, + granularity: (gran & 0xF0) as u8 | ((limit >> 16) & 0x0F) as u8, + base_high: ((base >> 24) & 0xFF) as u8 + } + } +} + +#[derive(Copy, Clone)] +#[repr(C, packed)] +struct TaskStateSegment { + reserved: u32, + /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2. + rsp: [u64; 3], + reserved2: u64, + /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers. + ist: [u64; 7], + reserved3: u64, + reserved4: u16, + /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base. + iomap_base: u16, +} + +impl TaskStateSegment { + const fn new() -> TaskStateSegment { + TaskStateSegment { + reserved: 0, + rsp: [0; 3], + reserved2: 0, + ist: [0; 7], + reserved3: 0, + reserved4: 0, + iomap_base: 0, + } + } +} + +// workaround to use th enew repr(align) feature +// currently, it is only supported by structs +// => map all TSS in a struct +#[repr(align(4096))] +struct TssBuffer { + tss: [TaskStateSegment; MAX_CORES], +} + +impl TssBuffer { + const fn new() -> TssBuffer { + TssBuffer { + tss: [TaskStateSegment::new(); MAX_CORES], + } + } +} + +// workaround to use th enew repr(align) feature +// currently, it is only supported by structs +// => map stacks in a struct +#[derive(Copy)] +#[repr(C, align(4096))] +struct IrqStack { + buffer: [u8; KERNEL_STACK_SIZE], +} + +impl Clone for IrqStack { + fn clone(&self) -> IrqStack + { + *self + } +} + +impl IrqStack { + pub const fn new() -> IrqStack { + IrqStack { + buffer: [0; KERNEL_STACK_SIZE], + } + } +} + +/// This will setup the special GDT +/// pointer, set up the entries in our GDT, and then +/// finally to load the new GDT and to update the +/// new segment registers +#[no_mangle] +pub unsafe fn gdt_install() +{ + GDT_INIT.call_once(|| { + let mut num: usize = 0; + + GDTR.limit = (size_of::() * GDT.len() - 1) as u16; + GDTR.base = GDT.as_ptr() as u64; + + /* Our NULL descriptor */ + GDT[num] = GdtEntry::new(0, 0, 0, 0); + num += 1; + + /* + * The second entry is our Code Segment. The base address + * is 0, the limit is 4 GByte, it uses 4KByte granularity, + * and is a Code Segment descriptor. + */ + GDT[num] = GdtEntry::new(0, 0, + GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); + num += 1; + + /* + * The third entry is our Data Segment. It's EXACTLY the + * same as our code segment, but the descriptor type in + * this entry's access byte says it's a Data Segment + */ + GDT[num] = GdtEntry::new(0, 0, + GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); + num += 1; + + /* + * Create code segment for 32bit user-space applications (ring 3) + */ + GDT[num] = GdtEntry::new(0, 0xFFFFFFFF, + GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, + GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN); + num += 1; + + /* + * Create data segment for 32bit user-space applications (ring 3) + */ + GDT[num] = GdtEntry::new(0, 0xFFFFFFFF, + GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, + GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN); + num += 1; + + /* + * Create code segment for 64bit user-space applications (ring 3) + */ + GDT[num] = GdtEntry::new(0, 0, + GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, + GDT_FLAG_64_BIT); + num += 1; + + /* + * Create data segment for 64bit user-space applications (ring 3) + */ + GDT[num] = GdtEntry::new(0, 0, + GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); + num += 1; + + /* + * Create TSS for each core (we use these segments for task switching) + */ + for i in 0..MAX_CORES { + TSS_BUFFER.tss[i].rsp[0] = (&(boot_stack[0]) as *const _) as u64; + TSS_BUFFER.tss[i].rsp[0] += ((i+1) * KERNEL_STACK_SIZE - 0x10) as u64; + TSS_BUFFER.tss[i].ist[0] = 0; // ist will created per task + TSS_BUFFER.tss[i].ist[1] = (&(STACK_TABLE[i][2 /*IST number */ - 2]) as *const _) as u64; + TSS_BUFFER.tss[i].ist[1] += (KERNEL_STACK_SIZE - 0x10) as u64; + TSS_BUFFER.tss[i].ist[2] = (&(STACK_TABLE[i][3 /*IST number */ - 2]) as *const _) as u64; + TSS_BUFFER.tss[i].ist[2] += (KERNEL_STACK_SIZE - 0x10) as u64; + TSS_BUFFER.tss[i].ist[3] = (&(STACK_TABLE[i][4 /*IST number */ - 2]) as *const _) as u64; + TSS_BUFFER.tss[i].ist[3] += (KERNEL_STACK_SIZE - 0x10) as u64; + + let tss_ptr = &(TSS_BUFFER.tss[i]) as *const TaskStateSegment; + GDT[num+i*2] = GdtEntry::new(tss_ptr as u32, size_of::() as u32, + GDT_FLAG_PRESENT | GDT_FLAG_TSS | GDT_FLAG_RING0, 0); + } + }); + + gdt_flush(); +} + +#[no_mangle] +pub unsafe fn set_tss(rsp: u64, ist: u64) +{ + TSS_BUFFER.tss[core_id!()].rsp[0] = rsp; + TSS_BUFFER.tss[core_id!()].ist[0] = ist; +} + +#[no_mangle] +pub unsafe fn gdt_flush() +{ + dtables::lgdt(&GDTR); + + // Reload the segment descriptors + segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16)); + segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16)); + segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16)); + segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16)); + //segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_DATA as u16)); + //segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16)); +} diff --git a/librs/src/arch/x86_64/mod.rs b/librs/src/arch/x86_64/mod.rs new file mode 100644 index 000000000..d52e5ac5c --- /dev/null +++ b/librs/src/arch/x86_64/mod.rs @@ -0,0 +1,25 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +pub mod processor; +pub mod gdt; diff --git a/librs/src/arch/x86_64/processor.rs b/librs/src/arch/x86_64/processor.rs new file mode 100644 index 000000000..24209f8b6 --- /dev/null +++ b/librs/src/arch/x86_64/processor.rs @@ -0,0 +1,602 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#![allow(dead_code)] + +use logging::*; +use spin; +use raw_cpuid::*; + +// feature list 0x00000001 (ebx) +const CPU_FEATURE_FPU : u32 = (1 << 0); +const CPU_FEATURE_PSE : u32 = (1 << 3); +const CPU_FEATURE_MSR : u32 = (1 << 5); +const CPU_FEATURE_PAE : u32 = (1 << 6); +const CPU_FEATURE_APIC : u32 = (1 << 9); +const CPU_FEATURE_SEP : u32 = (1 << 11); +const CPU_FEATURE_PGE : u32 = (1 << 13); +const CPU_FEATURE_PAT : u32 = (1 << 16); +const CPU_FEATURE_PSE36 : u32 = (1 << 17); +const CPU_FEATURE_CLFLUSH : u32 = (1 << 19); +const CPU_FEATURE_MMX : u32 = (1 << 23); +const CPU_FEATURE_FXSR : u32 = (1 << 24); +const CPU_FEATURE_SSE : u32 = (1 << 25); +const CPU_FEATURE_SSE2 : u32 = (1 << 26); + +// feature list 0x00000001 (ecx) +const CPU_FEATURE_MWAIT : u32 = (1 << 3); +const CPU_FEATURE_VMX : u32 = (1 << 5); +const CPU_FEATURE_EST : u32 = (1 << 7); +const CPU_FEATURE_SSE3 : u32 = (1 << 9); +const CPU_FEATURE_FMA : u32 = (1 << 12); +const CPU_FEATURE_DCA : u32 = (1 << 18); +const CPU_FEATURE_SSE4_1 : u32 = (1 << 19); +const CPU_FEATURE_SSE4_2 : u32 = (1 << 20); +const CPU_FEATURE_X2APIC : u32 = (1 << 21); +const CPU_FEATURE_MOVBE : u32 = (1 << 22); +const CPU_FEATURE_XSAVE : u32 = (1 << 26); +const CPU_FEATURE_OSXSAVE : u32 = (1 << 27); +const CPU_FEATURE_AVX : u32 = (1 << 28); +const CPU_FEATURE_RDRAND : u32 = (1 << 30); +const CPU_FEATURE_HYPERVISOR : u32 = (1 << 31); + +// const.80000001H:EDX feature list +const CPU_FEATURE_SYSCALL : u32 = (1 << 11); +const CPU_FEATURE_NX : u32 = (1 << 20); +const CPU_FEATURE_1GBHP : u32 = (1 << 26); +const CPU_FEATURE_RDTSCP : u32 = (1 << 27); +const CPU_FEATURE_LM : u32 = (1 << 29); + +// feature list 0x00000007:0 +const CPU_FEATURE_FSGSBASE : u32 = (1 << 0); +const CPU_FEATURE_TSC_ADJUST : u32 = (1 << 1); +const CPU_FEATURE_BMI1 : u32 = (1 << 3); +const CPU_FEATURE_HLE : u32 = (1 << 4); +const CPU_FEATURE_AVX2 : u32 = (1 << 5); +const CPU_FEATURE_SMEP : u32 = (1 << 7); +const CPU_FEATURE_BMI2 : u32 = (1 << 8); +const CPU_FEATURE_ERMS : u32 = (1 << 9); +const CPU_FEATURE_INVPCID : u32 = (1 << 10); +const CPU_FEATURE_RTM : u32 = (1 << 11); +const CPU_FEATURE_CQM : u32 = (1 << 12); +const CPU_FEATURE_MPX : u32 = (1 << 14); +const CPU_FEATURE_AVX512F : u32 = (1 << 16); +const CPU_FEATURE_RDSEED : u32 = (1 << 18); +const CPU_FEATURE_ADX : u32 = (1 << 19); +const CPU_FEATURE_SMAP : u32 = (1 << 20); +const CPU_FEATURE_PCOMMIT : u32 = (1 << 22); +const CPU_FEATURE_CLFLUSHOPT : u32 = (1 << 23); +const CPU_FEATURE_CLWB : u32 = (1 << 24); +const CPU_FEATURE_AVX512PF : u32 = (1 << 26); +const CPU_FEATURE_AVX512ER : u32 = (1 << 27); +const CPU_FEATURE_AVX512CD : u32 = (1 << 28); +const CPU_FEATURE_SHA_NI : u32 = (1 << 29); + +// feature list 0x00000006 +const CPU_FEATURE_IDA : u32 = (1 << 0); +const CPU_FEATURE_EPB : u32 = (1 << 3); +const CPU_FEATURE_HWP : u32 = (1 << 10); + +/* +* EFLAGS bits +*/ +const EFLAGS_CF : u32 = (1 << 0); /* Carry Flag */ +const EFLAGS_FIXED : u32 = (1 << 1); /* Bit 1 - always on */ +const EFLAGS_PF : u32 = (1 << 2); /* Parity Flag */ +const EFLAGS_AF : u32 = (1 << 4); /* Auxiliary carry Flag */ +const EFLAGS_ZF : u32 = (1 << 6); /* Zero Flag */ +const EFLAGS_SF : u32 = (1 << 7); /* Sign Flag */ +const EFLAGS_TF : u32 = (1 << 8); /* Trap Flag */ +const EFLAGS_IF : u32 = (1 << 9); /* Interrupt Flag */ +const EFLAGS_DF : u32 = (1 << 10); /* Direction Flag */ +const EFLAGS_OF : u32 = (1 << 11); /* Overflow Flag */ +const EFLAGS_IOPL : u32 = (1 << 12); /* I/O Privilege Level (2 bits) */ +const EFLAGS_NT : u32 = (1 << 14); /* Nested Task */ +const EFLAGS_RF : u32 = (1 << 16); /* Resume Flag */ +const EFLAGS_VM : u32 = (1 << 17); /* Virtual Mode */ +const EFLAGS_AC : u32 = (1 << 18); /* Alignment Check/Access Control */ +const EFLAGS_VIF : u32 = (1 << 19); /* Virtual Interrupt Flag */ +const EFLAGS_VIP : u32 = (1 << 20); /* Virtual Interrupt Pending */ +const EFLAGS_ID : u32 = (1 << 21); /* const detection */ + +// x86 control registers + +/// Protected Mode Enable +const CR0_PE : u32 = (1 << 0); +/// Monitor coprocessor +const CR0_MP : u32 = (1 << 1); +/// Enable FPU emulation +const CR0_EM : u32 = (1 << 2); +/// Task switched +const CR0_TS : u32 = (1 << 3); +/// Extension type of coprocessor +const CR0_ET : u32 = (1 << 4); +/// Enable FPU error reporting +const CR0_NE : u32 = (1 << 5); +/// Enable write protected pages +const CR0_WP : u32 = (1 << 16); +/// Enable alignment checks +const CR0_AM : u32 = (1 << 18); +/// Globally enables/disable write-back caching +const CR0_NW : u32 = (1 << 29); +/// Globally disable memory caching +const CR0_CD : u32 = (1 << 30); +/// Enable paging +const CR0_PG : u32 = (1 << 31); + +/// Virtual 8086 Mode Extensions +const CR4_VME: u32 = (1 << 0); +/// Protected-mode Virtual Interrupts +const CR4_PVI : u32 = (1 << 1); +/// Disable Time Stamp Counter register (rdtsc instruction) +const CR4_TSD : u32 = (1 << 2); +/// Enable debug extensions +const CR4_DE : u32 = (1 << 3); +/// Enable hugepage support +const CR4_PSE : u32 = (1 << 4); +/// Enable physical address extension +const CR4_PAE : u32 = (1 << 5); +/// Enable machine check exceptions +const CR4_MCE : u32 = (1 << 6); +/// Enable global pages +const CR4_PGE : u32 = (1 << 7); +/// Enable Performance-Monitoring Counter +const CR4_PCE : u32 = (1 << 8); +/// Enable Operating system support for FXSAVE and FXRSTOR instructions +const CR4_OSFXSR : u32 = (1 << 9); +/// Enable Operating System Support for Unmasked SIMD Floating-Point Exceptions +const CR4_OSXMMEXCPT : u32 = (1 << 10); +/// Enable Virtual Machine Extensions, see Intel VT-x +const CR4_VMXE : u32 = (1 << 13); +/// Enable Safer Mode Extensions, see Trusted Execution Technology (TXT) +const CR4_SMXE : u32 = (1 << 14); +/// Enables the instructions RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE +const CR4_FSGSBASE : u32 = (1 << 16); +/// Enables process-context identifiers +const CR4_PCIDE : u32 = (1 << 17); +/// Enable XSAVE and Processor Extended States +const CR4_OSXSAVE : u32 = (1 << 18); +/// Enable Supervisor Mode Execution Protection +const CR4_SMEP : u32 = (1 << 20); +/// Enable Supervisor Mode Access Protection +const CR4_SMAP : u32 = (1 << 21); + +// x86-64 specific MSRs + +/// APIC register +const MSR_APIC_BASE : u32 = 0x0000001B; +/// extended feature register +const MSR_EFER : u32 = 0xc0000080; +/// legacy mode SYSCALL target +const MSR_STAR : u32 = 0xc0000081; +/// long mode SYSCALL target +const MSR_LSTAR : u32 = 0xc0000082; +/// compat mode SYSCALL target +const MSR_CSTAR : u32 = 0xc0000083; +/// EFLAGS mask for syscall +const MSR_SYSCALL_MASK : u32 = 0xc0000084; +/// 64bit FS base +const MSR_FS_BASE : u32 = 0xc0000100; +/// 64bit GS base +const MSR_GS_BASE : u32 = 0xc0000101; +/// SwapGS GS shadow +const MSR_KERNEL_GS_BASE : u32 = 0xc0000102; + +const MSR_XAPIC_ENABLE : u32 = (1 << 11); +const MSR_X2APIC_ENABLE : u32 = (1 << 10); + +const MSR_IA32_PLATFORM_ID : u32 = 0x00000017; + +const MSR_IA32_PERFCTR0 : u32 = 0x000000c1; +const MSR_IA32_PERFCTR1 : u32 = 0x000000c2; +const MSR_FSB_FREQ : u32 = 0x000000cd; +const MSR_PLATFORM_INFO : u32 = 0x000000ce; + +const MSR_IA32_MPERF : u32 = 0x000000e7; +const MSR_IA32_APERF : u32 = 0x000000e8; +const MSR_IA32_MISC_ENABLE : u32 = 0x000001a0; +const MSR_IA32_FEATURE_CONTROL : u32 = 0x0000003a; +const MSR_IA32_ENERGY_PERF_BIAS : u32 = 0x000001b0; +const MSR_IA32_PERF_STATUS : u32 = 0x00000198; +const MSR_IA32_PERF_CTL : u32 = 0x00000199; +const MSR_IA32_CR_PAT : u32 = 0x00000277; +const MSR_MTRRDEFTYPE : u32 = 0x000002ff; + +const MSR_PPERF : u32 = 0x0000064e; +const MSR_PERF_LIMIT_REASONS : u32 = 0x0000064f; +const MSR_PM_ENABLE : u32 = 0x00000770; +const MSR_HWP_CAPABILITIES : u32 = 0x00000771; +const MSR_HWP_REQUEST_PKG : u32 = 0x00000772; +const MSR_HWP_INTERRUPT : u32 = 0x00000773; +const MSR_HWP_REQUEST : u32 = 0x00000774; +const MSR_HWP_STATUS : u32 = 0x00000777; + +const MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP : u64 = (1 << 16); +const MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK : u64 = (1 << 20); +const MSR_IA32_MISC_ENABLE_TURBO_DISABLE : u64 = (1 << 38); + +const MSR_MTRRFIX64K_00000 : u32 = 0x00000250; +const MSR_MTRRFIX16K_80000 : u32 = 0x00000258; +const MSR_MTRRFIX16K_A0000 : u32 = 0x00000259; +const MSR_MTRRFIX4K_C0000 : u32 = 0x00000268; +const MSR_MTRRFIX4K_C8000 : u32 = 0x00000269; +const MSR_MTRRFIX4K_D0000 : u32 = 0x0000026a; +const MSR_MTRRFIX4K_D8000 : u32 = 0x0000026b; +const MSR_MTRRFIX4K_E0000 : u32 = 0x0000026c; +const MSR_MTRRFIX4K_E8000 : u32 = 0x0000026d; +const MSR_MTRRFIX4K_F0000 : u32 = 0x0000026e; +const MSR_MTRRFIX4K_F8000 : u32 = 0x0000026f; + +const MSR_OFFCORE_RSP_0 : u32 = 0x000001a6; +const MSR_OFFCORE_RSP_1 : u32 = 0x000001a7; +const MSR_NHM_TURBO_RATIO_LIMIT : u32 = 0x000001ad; +const MSR_IVT_TURBO_RATIO_LIMIT : u32 = 0x000001ae; +const MSR_TURBO_RATIO_LIMIT : u32 = 0x000001ad; +const MSR_TURBO_RATIO_LIMIT1 : u32 = 0x000001ae; +const MSR_TURBO_RATIO_LIMIT2 : u32 = 0x000001af; + +// MSR EFER bits +const EFER_SCE : u32 = (1 << 0); +const EFER_LME : u32 = (1 << 8); +const EFER_LMA : u32 = (1 << 10); +const EFER_NXE : u32 = (1 << 11); +const EFER_SVME : u32 = (1 << 12); +const EFER_LMSLE : u32 = (1 << 13); +const EFER_FFXSR : u32 = (1 << 14); +const EFER_TCE : u32 = (1 << 15); + +pub struct CpuInfo { + feature1 : u32, + feature2 : u32, + feature3 : u32, + feature4 : u32, + addr_width : u32 +} + +/// Execute CPUID instruction with eax, ebx, ecx and edx register set. +/// Note: This is a low-level function to query cpuid directly. +#[warn(unused_assignments)] +fn cpuid4(mut eax: u32, mut ebx: u32, mut ecx: u32, mut edx: u32) -> CpuIdResult { + unsafe { + asm!("cpuid" : "+{eax}"(eax) "+{ebx}"(ebx) "+{ecx}"(ecx) "+{edx}"(edx) ::: "volatile"); + } + + CpuIdResult { eax: eax, ebx: ebx, ecx: ecx, edx: edx } +} + +impl CpuInfo { + fn new() -> Self { + let mut cpuid: CpuIdResult = cpuid4(0, 0, 0, 0); + let level: u32 = cpuid.ebx; + + cpuid = cpuid4(1, 0, 0, 0); + let mut f1: u32 = cpuid.edx; + let f2: u32 = cpuid.ecx; + let family: u32 = (cpuid.eax & 0x00000F00u32) >> 8; + let model: u32 = (cpuid.eax & 0x000000F0u32) >> 4; + let stepping: u32 = cpuid.eax & 0x0000000Fu32; + if (family == 6) && (model < 3) && (stepping < 3) { + f1 &= 0 ^ CPU_FEATURE_SEP; + } + + cpuid = cpuid4(0x80000000u32, 0, 0, 0); + let extended: u32 = cpuid.eax; + + let mut f3: u32 = 0; + if extended >= 0x80000001u32 { + cpuid = cpuid4(0x80000001u32, 0, 0, 0); + f3 = cpuid.edx; + } + + let mut width: u32 = 0; + if extended >= 0x80000008u32 { + cpuid = cpuid4(0x80000008u32, 0, 0, 0); + width = cpuid.eax; + } + + let mut f4: u32 = 0; + /* Additional Intel-defined flags: level 0x00000007 */ + if level >= 0x00000007u32 { + cpuid = cpuid4(0x7u32, 0, 0, 0); + f4 = cpuid.ebx; + } + + CpuInfo{ + feature1 : f1, + feature2 : f2, + feature3 : f3, + feature4 : f4, + addr_width : width + } + } + + #[inline(always)] + pub const fn has_fpu(&self) -> bool { + (self.feature1 & CPU_FEATURE_FPU) != 0 + } + + #[inline(always)] + pub const fn has_msr(&self) -> bool { + (self.feature1 & CPU_FEATURE_MSR) != 0 + } + + #[inline(always)] + pub const fn has_apic(&self) -> bool { + (self.feature1 & CPU_FEATURE_APIC) != 0 + } + + #[inline(always)] + pub const fn has_fxsr(&self) -> bool { + (self.feature1 & CPU_FEATURE_FXSR) != 0 + } + + #[inline(always)] + pub const fn has_clflush(&self) -> bool { + (self.feature1 & CPU_FEATURE_CLFLUSH) != 0 + } + + #[inline(always)] + pub const fn has_sse(&self) -> bool { + (self.feature1 & CPU_FEATURE_SSE) != 0 + } + + #[inline(always)] + pub const fn has_pat(&self) -> bool { + (self.feature1 & CPU_FEATURE_PAT) != 0 + } + + #[inline(always)] + pub const fn has_sse2(&self) -> bool { + (self.feature1 & CPU_FEATURE_SSE2) != 0 + } + + #[inline(always)] + pub const fn has_pge(&self) -> bool { + (self.feature1 & CPU_FEATURE_PGE) != 0 + } + + #[inline(always)] + pub const fn has_sep(&self) -> bool { + (self.feature1 & CPU_FEATURE_SEP) != 0 + } + + #[inline(always)] + pub const fn has_movbe(&self) -> bool { + (self.feature2 & CPU_FEATURE_MOVBE) != 0 + } + + #[inline(always)] + pub const fn has_fma(&self) -> bool { + (self.feature2 & CPU_FEATURE_FMA) != 0 + } + + #[inline(always)] + pub const fn has_mwait(&self) -> bool { + (self.feature2 & CPU_FEATURE_MWAIT) != 0 + } + + #[inline(always)] + pub const fn has_vmx(&self) -> bool { + (self.feature2 & CPU_FEATURE_VMX) != 0 + } + + #[inline(always)] + pub const fn has_est(&self) -> bool { + (self.feature2 & CPU_FEATURE_EST) != 0 + } + + #[inline(always)] + pub const fn has_sse3(&self) -> bool { + (self.feature2 & CPU_FEATURE_SSE3) != 0 + } + + #[inline(always)] + pub const fn has_dca(&self) -> bool { + (self.feature2 & CPU_FEATURE_DCA) != 0 + } + + #[inline(always)] + pub const fn has_sse4_1(&self) -> bool { + (self.feature2 & CPU_FEATURE_SSE4_1) != 0 + } + + #[inline(always)] + pub const fn has_sse4_2(&self) -> bool { + (self.feature2 & CPU_FEATURE_SSE4_2) != 0 + } + + #[inline(always)] + pub const fn has_x2apic(&self) -> bool { + (self.feature2 & CPU_FEATURE_X2APIC) != 0 + } + + #[inline(always)] + pub const fn has_xsave(&self) -> bool { + (self.feature2 & CPU_FEATURE_XSAVE) != 0 + } + + #[inline(always)] + pub const fn has_osxsave(&self) -> bool { + (self.feature2 & CPU_FEATURE_OSXSAVE) != 0 + } + + #[inline(always)] + pub const fn has_avx(&self) -> bool { + (self.feature2 & CPU_FEATURE_AVX) != 0 + } + + #[inline(always)] + pub const fn has_rdrand(&self) -> bool { + (self.feature2 & CPU_FEATURE_RDRAND) != 0 + } + + #[inline(always)] + pub const fn on_hypervisor(&self) -> bool { + (self.feature2 & CPU_FEATURE_HYPERVISOR) != 0 + } + + #[inline(always)] + pub const fn has_nx(&self) -> bool { + (self.feature3 & CPU_FEATURE_NX) != 0 + } + + #[inline(always)] + pub const fn has_fsgsbase(&self) -> bool { + (self.feature4 & CPU_FEATURE_FSGSBASE) != 0 + } + + #[inline(always)] + pub const fn has_avx2(&self) -> bool { + (self.feature4 & CPU_FEATURE_AVX2) != 0 + } + + #[inline(always)] + pub const fn has_bmi1(&self) -> bool { + (self.feature4 & CPU_FEATURE_BMI1) != 0 + } + + #[inline(always)] + pub const fn has_bmi2(&self) -> bool { + (self.feature4 & CPU_FEATURE_BMI2) != 0 + } + + #[inline(always)] + pub const fn has_hle(&self) -> bool { + (self.feature4 & CPU_FEATURE_HLE) != 0 + } + + #[inline(always)] + pub const fn has_cqm(&self) -> bool { + (self.feature4 & CPU_FEATURE_CQM) != 0 + } + + #[inline(always)] + pub const fn has_rtm(&self) -> bool { + (self.feature4 & CPU_FEATURE_RTM) != 0 + } + + #[inline(always)] + pub const fn has_avx512f(&self) -> bool { + (self.feature4 & CPU_FEATURE_AVX512F) != 0 + } + + #[inline(always)] + pub const fn has_avx512pf(&self) -> bool { + (self.feature4 & CPU_FEATURE_AVX512PF) != 0 + } + + #[inline(always)] + pub const fn has_avx512er(&self) -> bool { + (self.feature4 & CPU_FEATURE_AVX512ER) != 0 + } + + #[inline(always)] + pub const fn has_avx512cd(&self) -> bool { + (self.feature4 & CPU_FEATURE_AVX512CD) != 0 + } + + #[inline(always)] + pub const fn has_rdtscp(&self) -> bool { + (self.feature3 & CPU_FEATURE_RDTSCP) != 0 + } + + fn print_infos(&self) { + info!("CPU features: {}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", + if self.has_sse() { "SSE " } else { "" }, + if self.has_sse2() { "SSE2 " } else { "" }, + if self.has_sse3() { "SSE3 " } else { "" }, + if self.has_sse4_1() { "SSE4.1 " } else { "" }, + if self.has_sse4_2() { "SSE4.2 " } else { "" }, + if self.has_avx() { "AVX " } else { "" }, + if self.has_avx2() { "AVX2 " } else { "" }, + if self.has_rdrand() { "RDRAND " } else { "" }, + if self.has_fma() { "FMA " } else { "" }, + if self.has_movbe() { "MOVBE " } else { "" }, + if self.has_x2apic() { "X2APIC " } else { "" }, + if self.has_fpu() { "FPU " } else { "" }, + if self.has_fxsr() { "FXSR " } else { "" }, + if self.has_xsave() { "XSAVE " } else { "" }, + if self.has_osxsave() { "OSXSAVE " } else { "" }, + if self.has_vmx() { "VMX " } else { "" }, + if self.has_rdtscp() { "RDTSCP " } else { "" }, + if self.has_fsgsbase() { "FSGSBASE " } else { "" }, + if self.has_mwait() { "MWAIT " } else { "" }, + if self.has_clflush() { "CLFLUSH " } else { "" }, + if self.has_bmi1() { "BMI1 " } else { "" }, + if self.has_bmi2() { "BMI2 " } else { "" }, + if self.has_dca() { "DCA " } else { "" }, + if self.has_rtm() { "RTM " } else { "" }, + if self.has_hle() { "HLE " } else { "" }, + if self.has_cqm() { "CQM " } else { "" }, + if self.has_avx512f() { "AVX512F " } else { "" }, + if self.has_avx512cd() { "AVX512CD " } else { "" }, + if self.has_avx512pf() { "AVX512PF " } else { "" }, + if self.has_avx512er() == true { "AVX512ER " } else { "" }); + + info!("Paging features: {}{}{}{}{}{}{}{}", + if (self.feature1 & CPU_FEATURE_PSE) != 0 { "PSE (2/4Mb) " } else { "" }, + if (self.feature1 & CPU_FEATURE_PAE) != 0 { "PAE " } else { "" }, + if (self.feature1 & CPU_FEATURE_PGE) != 0 { "PGE " } else { "" }, + if (self.feature1 & CPU_FEATURE_PAT) != 0 { "PAT " } else { "" }, + if (self.feature1 & CPU_FEATURE_PSE36) != 0 { "PSE36 " } else { "" }, + if (self.feature3 & CPU_FEATURE_NX) != 0 { "NX " } else { "" }, + if (self.feature3 & CPU_FEATURE_1GBHP) != 0 { "PSE (1Gb) " } else { "" }, + if (self.feature3 & CPU_FEATURE_LM) != 0 { "LM" } else { "" }); + + info!("Physical adress-width: {} bits", self.addr_width & 0xff); + info!("Linear adress-width: {} bits", (self.addr_width >> 8) & 0xff); + info!("Sysenter instruction: {}", if (self.feature1 & CPU_FEATURE_SEP) != 0 { "available" } else { "unavailable" }); + info!("Syscall instruction: {}", if (self.feature3 & CPU_FEATURE_SYSCALL) != 0 { "available" } else { "unavailable" }); + } +} + +static mut CPU_INFO : CpuInfo = CpuInfo { + feature1 : 0, + feature2 : 0, + feature3 : 0, + feature4 : 0, + addr_width : 0 +}; +static CPU_INIT: spin::Once<()> = spin::Once::new(); + +/// Returns a reference to CpuInfo, which describes all CPU features. +/// The return value is only valid if cpu_detection is already called an initialized +/// the system. +pub fn get_cpuinfo() -> &'static CpuInfo { + unsafe { + &CPU_INFO + } +} + +/// Determine CPU features and activates all by HermitCore supported features +pub fn cpu_detection() { + // A synchronization primitive which can be used to run a one-time global initialization. + CPU_INIT.call_once(|| { + unsafe { + CPU_INFO = CpuInfo::new(); + } + }); + + let cpu_info = get_cpuinfo(); + cpu_info.print_infos(); +} diff --git a/librs/src/console.rs b/librs/src/console.rs new file mode 100644 index 000000000..90398b900 --- /dev/null +++ b/librs/src/console.rs @@ -0,0 +1,56 @@ +// Copyright (c) 2017, 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. + +use core::fmt; +use spin::Mutex; + +extern { + pub fn kputchar(c: u8) -> i32; +} + +pub struct Console; + +/// A collection of methods that are required to format +/// a message to HermitCore's console. +impl fmt::Write for Console { + /// print character to the screen + fn write_char(&mut self, c: char) -> fmt::Result { + let out: u8 = c as u8; + unsafe { + kputchar(out); + } + Ok(()) + } + + /// print string as kernel message. + fn write_str(&mut self, s: &str) -> fmt::Result { + for chars in s.chars() { + self.write_char(chars).unwrap(); + } + Ok(()) + } +} + +pub static CONSOLE: Mutex = Mutex::new(Console); diff --git a/librs/src/consts.rs b/librs/src/consts.rs new file mode 100644 index 000000000..7b6fc28e4 --- /dev/null +++ b/librs/src/consts.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#![allow(dead_code)] + +pub const MAX_CORES : usize = 512; +pub const KERNEL_STACK_SIZE : usize = 8192; + +#[cfg(target_arch="x86_64")] +pub const PAGE_SIZE : usize = 4096; diff --git a/librs/src/lib.rs b/librs/src/lib.rs new file mode 100644 index 000000000..395a57dac --- /dev/null +++ b/librs/src/lib.rs @@ -0,0 +1,65 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +/* + * First version is derived and adapted for HermitCore from + * Philipp Oppermann's excellent series of blog posts (http://blog.phil-opp.com/) + * and Eric Kidd's toy OS (https://github.com/emk/toyos-rs). + */ + +#![feature(asm, const_fn, lang_items, repr_align, attr_literals)] +#![no_std] + +extern crate rlibc; +extern crate spin; +extern crate x86; +extern crate raw_cpuid; + +// These need to be visible to the linker, so we need to export them. +pub use runtime_glue::*; +pub use logging::*; +pub use consts::*; + +#[cfg(target_arch="x86_64")] +pub use arch::gdt::*; + +#[macro_use] +mod macros; +#[macro_use] +mod logging; +mod runtime_glue; +mod console; +mod arch; +mod consts; + +const VERSION: &'static str = env!("CARGO_PKG_VERSION"); + +#[no_mangle] +pub extern "C" fn rust_init() { + info!("HermitCore's Rust runtime! v{}", VERSION); +} + +#[no_mangle] +pub extern "C" fn rust_main() { + arch::processor::cpu_detection(); +} diff --git a/librs/src/logging.rs b/librs/src/logging.rs new file mode 100644 index 000000000..4eb81e04d --- /dev/null +++ b/librs/src/logging.rs @@ -0,0 +1,137 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#![allow(unused_macros)] + +/// An enum representing the available verbosity levels of the logger. +#[derive(Copy, Clone)] +pub enum LogLevel { + /// Disable all our put messages + /// + /// Designates without information + DISABLED = 0, + /// The "error" level. + /// + /// Designates very serious errors. + ERROR, + /// The "warn" level. + /// + /// Designates hazardous situations. + WARNING, + /// The "info" level. + /// + /// Designates useful information. + INFO, + // The "debug" level. + /// + /// Designates lower priority information. + DEBUG +} + +/// Data structures to filter kernel messages +pub struct KernelLogger { + pub log_level: LogLevel, +} + +/// default logger to handle kernel messages +pub static LOGGER: KernelLogger = KernelLogger { log_level: LogLevel::INFO }; + +/// Print formatted info text to our console, followed by a newline. +macro_rules! info { + ($fmt:expr) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::INFO as u8; + + if current_level >= cmp_level { + println!(concat!("[INFO] ", $fmt)); + } + }); + ($fmt:expr, $($arg:tt)*) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::INFO as u8; + + if current_level >= cmp_level { + println!(concat!("[INFO] ", $fmt), $($arg)*); + } + }); +} + +/// Print formatted warnings to our console, followed by a newline. +macro_rules! warn { + ($fmt:expr) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::WARNING as u8; + + if current_level >= cmp_level { + println!(concat!("[WARNING] ", $fmt)); + } + }); + ($fmt:expr, $($arg:tt)*) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::WARNING as u8; + + if current_level >= cmp_level { + println!(concat!("[WARNING] ", $fmt), $($arg)*); + } + }); +} + +/// Print formatted warnings to our console, followed by a newline. +macro_rules! error { + ($fmt:expr) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::ERROR as u8; + + if current_level >= cmp_level { + println!(concat!("[ERROR] ", $fmt)); + } + }); + ($fmt:expr, $($arg:tt)*) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::ERROR as u8; + + if current_level >= cmp_level { + println!(concat!("[ERROR] ", $fmt), $($arg)*); + } + }); +} + +/// Print formatted debuf messages to our console, followed by a newline. +macro_rules! debug { + ($fmt:expr) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::DEBUG as u8; + + if current_level >= cmp_level { + println!(concat!("[DEBUG] ", $fmt)); + } + }); + ($fmt:expr, $($arg:tt)*) => ({ + let current_level = LOGGER.log_level as u8; + let cmp_level = LogLevel::DEBUG as u8; + + if current_level >= cmp_level { + println!(concat!("[DEBUG] ", $fmt), $($arg)*); + } + }); +} diff --git a/librs/src/macros.rs b/librs/src/macros.rs new file mode 100644 index 000000000..20173db35 --- /dev/null +++ b/librs/src/macros.rs @@ -0,0 +1,46 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +/// Determin the Id of the current CPU +macro_rules! core_id { + () => ( 0 ); +} + +/// Print formatted text to our console. +/// +/// From http://blog.phil-opp.com/rust-os/printing-to-screen.html, but tweaked +/// for HermitCore. +macro_rules! print { + ($($arg:tt)*) => ({ + use core::fmt::Write; + $crate::console::CONSOLE.lock().write_fmt(format_args!($($arg)*)).unwrap(); + }); +} + +/// Print formatted text to our console, followed by a newline. +/// +/// From https://doc.rust-lang.org/nightly/std/macro.println!.html +macro_rules! println { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} diff --git a/librs/src/runtime_glue.rs b/librs/src/runtime_glue.rs new file mode 100644 index 000000000..9e397d13f --- /dev/null +++ b/librs/src/runtime_glue.rs @@ -0,0 +1,46 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +//! Minor functions that Rust really expects to be defined by the compiler, +//! but which we need to provide manually because we're on bare metal. + +#![allow(private_no_mangle_fns)] + +#[lang = "eh_personality"] + extern "C" fn eh_personality() { +} + +#[lang = "panic_fmt"] #[no_mangle] +extern "C" fn panic_fmt(args: ::core::fmt::Arguments, file: &str, line: usize) -> ! +{ + println!("PANIC: {}:{}: {}", file, line, args); + loop {} +} + +#[no_mangle] +#[allow(non_snake_case)] +pub fn _Unwind_Resume() +{ + println!("UNWIND!"); + loop {} +} diff --git a/librs/x86_64-hermit.json b/librs/x86_64-hermit.json new file mode 100644 index 000000000..ab26c4db9 --- /dev/null +++ b/librs/x86_64-hermit.json @@ -0,0 +1,20 @@ +{ + "llvm-target": "x86_64-unknown-none-gnu", + "linker-flavor": "gcc", + "target-endian": "little", + "target-pointer-width": "64", + "os": "none", + "arch": "x86_64", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "pre-link-args": [ "-m64" ], + "cpu": "x86-64", + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", + "disable-redzone": true, + "eliminate-frame-pointer": true, + "linker-is-gnu": true, + "no-compiler-rt": true, + "archive-format": "gnu", + "code-model": "kernel", + "relocation-model": "static", + "panic-strategy": "abort" +} diff --git a/objmv/.gitignore b/objmv/.gitignore new file mode 100644 index 000000000..a9d37c560 --- /dev/null +++ b/objmv/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/objmv/Cargo.toml b/objmv/Cargo.toml new file mode 100644 index 000000000..d4bf86e60 --- /dev/null +++ b/objmv/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "objmv" +version = "0.1.0" +authors = [ + "Stefan Lankes ", +] + +[dependencies] +regex = "0.*" diff --git a/objmv/src/main.rs b/objmv/src/main.rs new file mode 100644 index 000000000..4b58e1080 --- /dev/null +++ b/objmv/src/main.rs @@ -0,0 +1,92 @@ +// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#![feature(rustc_private)] + +extern crate regex; +#[macro_use] +extern crate log; + +use regex::RegexSet; +use std::str; +use std::env; +use std::process::Command; +use std::vec::Vec; + +fn rename_sections(fname: String) +{ + let output = Command::new("objdump") + .arg("-h") + .arg(fname.to_string()) + .output() + .expect("objdump failed to start"); + + if output.status.success() { + let mut args: Vec = Vec::new(); + let re = RegexSet::new(&[r"^.text", r"^.data", r"^.bss"]).unwrap(); + let output_string = String::from_utf8_lossy(&output.stdout); + let substrings = output_string.split_whitespace(); + + for old_name in substrings { + if re.is_match(old_name) { + let mut new_name: String = ".k".to_owned(); + new_name.push_str(old_name.trim_left_matches('.')); + //println!("{} {}", old_name, new_name); + + let mut cmd: String = String::new(); + cmd.push_str(old_name); + cmd.push('='); + cmd.push_str(&new_name); + //println!("{}", cmd); + + args.push("--rename-section".to_string()); + args.push(cmd); + } + } + + if args.len() > 0 { + let status = Command::new("objcopy") + .args(args) + .arg(fname.to_string()) + .status() + .expect("objcopy failed to start"); + + if !status.success() { + warn!("Unable to rename sections in {}", fname); + } + } + } else { + warn!("Unable to determine section names in {}", fname); + } +} + +fn main() { + let mut arguments: Vec = env::args().collect(); + + // remove unneeded programm name + arguments.remove(0); + + for arg in arguments { + rename_sections(arg); + } +} diff --git a/tests.sh b/tests.sh index a4e8f0639..2c8cd6a22 100755 --- a/tests.sh +++ b/tests.sh @@ -9,7 +9,7 @@ PROXY=build/local_prefix/opt/hermit/bin/proxy for f in $FILES; do echo "check $f..."; HERMIT_ISLE=qemu HERMIT_CPUS=1 HERMIT_KVM=0 HERMIT_VERBOSE=1 timeout --kill-after=5m 5m $PROXY $f || exit 1; done -for f in $FILES; do echo "check $f..."; HERMIT_ISLE=qemu HERMIT_CPUS=2 HERMIT_KVM=0 HERMIT_VERBOSE=1 timeout --kill-after=5m 5m $PROXY $f || exit 1; done +#for f in $FILES; do echo "check $f..."; HERMIT_ISLE=qemu HERMIT_CPUS=2 HERMIT_KVM=0 HERMIT_VERBOSE=1 timeout --kill-after=5m 5m $PROXY $f || exit 1; done # test echo server at port 8000 HERMIT_ISLE=qemu HERMIT_CPUS=1 HERMIT_KVM=0 HERMIT_VERBOSE=1 HERMIT_APP_PORT=8000 $PROXY $TDIR/tests/server & diff --git a/tools/uhyve.c b/tools/uhyve.c index 64298e1bf..eb3f1dac3 100644 --- a/tools/uhyve.c +++ b/tools/uhyve.c @@ -100,8 +100,8 @@ #define PAGE_MASK ((~0L) << PAGE_BITS) #define PAGE_2M_MASK (~0L) << PAGE_2M_BITS) #else -#define PAGE_MASK (((~0L) << PAGE_BITS) & ~PG_XD) -#define PAGE_2M_MASK (((~0L) << PAGE_2M_BITS) & ~PG_XD) +#define PAGE_MASK (((~0UL) << PAGE_BITS) & ~PG_XD) +#define PAGE_2M_MASK (((~0UL) << PAGE_2M_BITS) & ~PG_XD) #endif // Page is present @@ -517,6 +517,17 @@ static int load_checkpoint(uint8_t* mem, char* path) return 0; } +static size_t virt2phys(size_t addr) +{ + struct kvm_translation trans; + + // determine guest physical address of the current rsp + trans.linear_address = addr; + kvm_ioctl(vcpufd, KVM_TRANSLATE, &trans); + + return trans.physical_address; +} + static inline void show_dtable(const char *name, struct kvm_dtable *dtable) { fprintf(stderr, " %s %016zx %08hx\n", name, (size_t) dtable->base, (uint16_t) dtable->limit); @@ -589,6 +600,29 @@ static void show_registers(int id, struct kvm_regs* regs, struct kvm_sregs* sreg for (i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; i++) fprintf(stderr, " %016zx", (size_t) sregs->interrupt_bitmap[i]); fprintf(stderr, "\n"); + + fprintf(stderr, "\n Last values on the stack:\n"); + + // determine guest physical address of the current rsp + size_t rsp_phys = virt2phys(regs->rsp); + + for (i=7; i>=0; i--) + fprintf(stderr, " [0x%llx] = 0x%zx\n", regs->rsp+i*sizeof(size_t), + *((size_t*)(guest_mem+rsp_phys+i*sizeof(size_t)))); + + size_t tr_phys = virt2phys(sregs->tr.base); + for(i=0; i<7; i++) { + size_t vaddr = *((size_t*) (guest_mem+tr_phys+9*4+i*sizeof(size_t))); + + if (vaddr) { + fprintf(stderr, "\n Last values on IST%d (at 0x%zx):\n", i, vaddr); + + size_t paddr = virt2phys(vaddr); + for(int j=0; j<8; j++) + fprintf(stderr, " [0x%zx] = 0x%zx\n", vaddr-j*sizeof(size_t), + *((size_t*) (guest_mem+paddr-j*sizeof(size_t)))); + } + } } static void print_registers(void) @@ -836,11 +870,13 @@ static int vcpu_loop(void) break; case KVM_EXIT_SHUTDOWN: + print_registers(); err(1, "KVM: receive shutdown command\n"); break; case KVM_EXIT_DEBUG: print_registers(); + default: fprintf(stderr, "KVM: unhandled exit: exit_reason = 0x%x\n", run->exit_reason); exit(EXIT_FAILURE);