Commit 568c3d2b authored by Stefan Lankes's avatar Stefan Lankes
Browse files

replace C by Rust code to intialize the GDT

parent 163c4351
......@@ -13,7 +13,7 @@
},
"version": {
"name": "0.2.1",
"name": "0.2.2",
"desc": "HermitCore's kernel as libOS",
"gpgSign": false
},
......
......@@ -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
......@@ -2,6 +2,9 @@ sudo: required
dist: trusty
git:
submodules: true
env:
global:
- PATH=$PATH:~/.cargo/bin
language: c
compiler: gcc
before_install:
......@@ -9,10 +12,9 @@ before_install:
- 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
- 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
script:
- curl -s https://static.rust-lang.org/rustup.sh | sh -s -- --channel=nightly
- curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly
- source cmake/local-cmake.sh
- mkdir build
- cd build
......
......@@ -68,30 +68,40 @@ add_dependencies(hermit-bootstrap ${X86_KERNEL_TARGET})
# add external project hermit-rs
ExternalProject_Add(
hermit-rs
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
# convert rust library to hermitcore's osabi
# rename sections in rust library
COMMAND
${CMAKE_ELFEDIT} --output-osabi HermitCore ${CMAKE_SOURCE_DIR}/librs/target/release/libhermit_rs.a
${CMAKE_SOURCE_DIR}/objmv/target/release/objmv
${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a
# rename sections in rust library
# convert rust library to hermitcore's osabi
COMMAND
${CMAKE_OBJCOPY} --rename-section .bss=.kbss
--rename-section .text=.ktext
--rename-section .data=.kdata
${CMAKE_SOURCE_DIR}/librs/target/release/libhermit_rs.a
${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
......@@ -100,7 +110,7 @@ add_custom_command(
${CMAKE_COMMAND} -E make_directory ${LOCAL_PREFIX_ARCH_LIB_DIR}
COMMAND
${CMAKE_COMMAND} -E copy_if_different
${CMAKE_SOURCE_DIR}/librs/target/release/libhermit_rs.a
${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a
${LOCAL_PREFIX_ARCH_LIB_DIR}/)
add_custom_command(
......@@ -115,7 +125,7 @@ add_custom_command(
# merge libhermit.a and libhermit_rs.a
COMMAND
${CMAKE_AR} x ${CMAKE_SOURCE_DIR}/librs/target/release/libhermit_rs.a
${CMAKE_AR} x ${CMAKE_SOURCE_DIR}/librs/target/x86_64-hermit/release/libhermit_rs.a
COMMAND
${CMAKE_AR} rcs $<TARGET_FILE:hermit-bootstrap> *.o
COMMAND
......@@ -248,7 +258,7 @@ set(CPACK_SYSTEM_NAME all)
set(CPACK_PACKAGE_VERSION_MAJOR 0)
set(CPACK_PACKAGE_VERSION_MINOR 2)
set(CPACK_PACKAGE_VERSION_PATCH 1)
set(CPACK_PACKAGE_VERSION_PATCH 2)
set(CPACK_PACKAGE_CONTACT "Stefan Lankes <slankes@eonerc.rwth-aachen.de>")
......
......@@ -140,6 +140,7 @@ start64:
; store pointer to the multiboot information
mov [mb_info], QWORD rdx
;
; relocate page tables
mov rdi, boot_pml4
mov rax, QWORD [rdi]
......@@ -255,15 +256,15 @@ Lsmp_main:
jmp $
%endif
ALIGN 64
global gdt_flush
;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]
ret
;gdt_flush:
; lgdt [gp]
; ret
; 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
......
......@@ -35,6 +35,7 @@
#include <asm/tss.h>
#include <asm/page.h>
#if 0
#define MAX_IST 3
gdt_ptr_t gp;
......@@ -160,3 +161,4 @@ void gdt_install(void)
/* Flush out the old GDT and install the new changes! */
gdt_flush();
}
#endif
set(PACKAGE_VERSION "0.2.1" CACHE STRING
set(PACKAGE_VERSION "0.2.2" CACHE STRING
"HermitCore current version")
set(MAX_CORES "512" CACHE STRING
......
......@@ -100,6 +100,7 @@ rcce_mpb_t* rcce_mpb = NULL;
extern void signal_init(void);
extern void rust_main(void);
extern void rust_init(void);
static int hermit_init(void)
{
......@@ -114,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();
......
[package]
name = "hermit-rs"
version = "0.2.0"
version = "0.2.2"
authors = [
"Stefan Lankes <slankes@eonerc.rwth-aachen.de>",
]
......
# 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)
Subproject commit ed16b0a1de57bac50477ad83e35d648688cc0ded
......@@ -23,7 +23,7 @@
// Export our platform-specific modules.
#[cfg(target_arch="x86_64")]
pub use self::x86_64::{processor};
pub use self::x86_64::{processor, gdt};
// Implementations for x86_64.
#[cfg(target_arch="x86_64")]
......
// 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 x86::dtables::*;
use core::mem::size_of;
// 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 = (6+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, //x((size_of::<GdtEntry>() * GDT_ENTRIES) - 1) as u16,
base: 0 //GDT.as_ptr() as u64
};
static mut TSS_BUFFER: TssBuffer = TssBuffer::new();
static STACK_TABLE: [[IrqStack; MAX_IST]; MAX_CORES] = [[IrqStack::new(); MAX_IST]; MAX_CORES];
extern "C" {
static boot_stack: [u8; MAX_CORES*KERNEL_STACK_SIZE*MAX_IST];
}
#[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
}
}
}
/// definition of the tast state segment structure
#[derive(Copy, Clone)]
#[repr(C, packed)]
struct TaskStateSegment {
res0: u16, // reserved entries
res1: u16, // reserved entries
rsp0: u64,
rsp1: u64,
rsp2: u64,
res2: u32, // reserved entries
res3: u32, // reserved entries
ist1: u64,
ist2: u64,
ist3: u64,
ist4: u64,
ist5: u64,
ist6: u64,
ist7: u64,
res4: u32, // reserved entries
res5: u32, // reserved entries
res6: u16,
bitmap: u16,
}
impl TaskStateSegment {
/// Creates a new TSS with zeroed privilege and interrupt stack table and a zero
/// `iomap_base`.
pub const fn new() -> TaskStateSegment {
TaskStateSegment {
res0: 0, // reserved entries
res1: 0, // reserved entries
rsp0: 0,
rsp1: 0,
rsp2: 0,
res2: 0, // reserved entries
res3: 0, // reserved entries
ist1: 0,
ist2: 0,
ist3: 0,
ist4: 0,
ist5: 0,
ist6: 0,
ist7: 0,
res4: 0, // reserved entries
res5: 0, // reserved entries
res6: 0,
bitmap: 0,
}
}
}
// workaround to use th enew repr(align) feature
// currently, it is only supported by structs
// => map all TSS in a struct
#[repr(C, align(4096))]
struct TssBuffer {
tss: [TaskStateSegment; MAX_CORES],
}
impl TssBuffer {
pub 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 extern fn gdt_install()
{
unsafe {
// Setup the GDT pointer and limit
GDTR.limit = ((size_of::<GdtEntry>() * GDT_ENTRIES) - 1) as u16;
GDTR.base = (&GDT as *const _) as u64;
let mut num: usize = 0;
/* 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, 0);
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, 0);
num += 1;
/*
* Create TSS for each core (we use these segments for task switching)
*/
for i in 0..MAX_CORES {
TSS_BUFFER.tss[i].rsp0 = (&(boot_stack[0]) as *const _) as u64;
TSS_BUFFER.tss[i].rsp0 += ((i+1) * KERNEL_STACK_SIZE - 0x10) as u64;
TSS_BUFFER.tss[i].ist1 = 0; // ist will created per task
TSS_BUFFER.tss[i].ist2 = (&(STACK_TABLE[i][2 /*IST number */ - 2]) as *const _) as u64;
TSS_BUFFER.tss[i].ist2 += (KERNEL_STACK_SIZE - 0x10) as u64;
TSS_BUFFER.tss[i].ist3 = (&(STACK_TABLE[i][3 /*IST number */ - 2]) as *const _) as u64;
TSS_BUFFER.tss[i].ist3 += (KERNEL_STACK_SIZE - 0x10) as u64;
TSS_BUFFER.tss[i].ist4 = (&(STACK_TABLE[i][4 /*IST number */ - 2]) as *const _) as u64;
TSS_BUFFER.tss[i].ist4 += (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::<TaskStateSegment>()-1) as u32,
GDT_FLAG_PRESENT | GDT_FLAG_TSS | GDT_FLAG_RING0, 0);
}
lgdt(&GDTR);
}
}
#[no_mangle]
pub extern fn set_tss(rsp0: u64, ist1: u64)
{
unsafe {
TSS_BUFFER.tss[core_id!()].rsp0 = rsp0;
TSS_BUFFER.tss[core_id!()].ist1 = ist1;
}
}
#[no_mangle]
pub extern fn gdt_flush()
{
unsafe { lgdt(&GDTR); }
}
......@@ -22,3 +22,4 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pub mod processor;
pub mod gdt;
......@@ -21,7 +21,6 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#![cfg(target_arch = "x86_64")]
#![allow(dead_code)]
use logging::*;
......
// 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;
......@@ -22,12 +22,12 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/*
* Derived and adapted for HermitCore from
* 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)]
#![feature(asm, const_fn, lang_items, repr_align, attr_literals)]
#![no_std]
extern crate rlibc;
......@@ -38,6 +38,10 @@ 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;
......@@ -46,17 +50,16 @@ mod logging;