Commit 0fc98b95 authored by Stefan Lankes's avatar Stefan Lankes
Browse files

first step to support aarch64

- remove only compiler errors
- kernel doesn't work
parent b287b20d
......@@ -2,6 +2,13 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aarch64"
version = "0.0.4"
dependencies = [
"cortex-a",
]
[[package]]
name = "autocfg"
version = "1.0.1"
......@@ -35,6 +42,15 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "cortex-a"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6922a40af4d1a2deac8c963b9f3e57311b8912490740234f1ad182425c547f80"
dependencies = [
"register",
]
[[package]]
name = "float-cmp"
version = "0.9.0"
......@@ -167,12 +183,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "929f54e29691d4e6a9cc558479de70db7aa3d98cd6fe7ab86d7507aa2886b9d2"
dependencies = [
"bitflags",
"cc",
"rustc_version",
]
[[package]]
name = "register"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deaba5b0e477d21f61a57504bb5cef4a1e86de30300b457d38971c1cfc98b815"
dependencies = [
"tock-registers",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "rusty-hermit"
version = "0.3.52"
dependencies = [
"aarch64",
"bitflags",
"crossbeam-utils",
"float-cmp",
......@@ -202,6 +239,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tock-registers"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70323afdb8082186c0986da0e10f6e4ed103d681c921c00597e98d9806dac20f"
[[package]]
name = "unicode-xid"
version = "0.2.2"
......
......@@ -67,6 +67,10 @@ float-cmp = "0.9"
num-traits = { version = "0.2", default-features = false }
x86 = { version = "0.41", default-features = false }
[target.'cfg(target_arch = "aarch64")'.dependencies.aarch64]
path = "/Users/stefan/share/rust-aarch64"
default-features = false
# The development profile, used for `cargo build`.
[profile.dev]
opt-level = 1 # controls the `--opt-level` the compiler builds with
......
......@@ -83,7 +83,7 @@
ALIGN; \
name:
.section .mboot
.section .text
.global _start
_start:
......@@ -251,8 +251,6 @@ halt:
wfe
b halt
.section .text
_setup_cpu:
ic iallu
tlbi vmalle1is
......
......@@ -13,7 +13,7 @@ const IRQ_FLAG_A: usize = 1 << 8;
#[inline]
pub fn enable() {
unsafe {
asm!("msr daifclr, 0b111" ::: "memory" : "volatile");
llvm_asm!("msr daifclr, 0b111" ::: "memory" : "volatile");
}
}
......@@ -24,14 +24,14 @@ pub fn enable() {
#[inline]
pub fn enable_and_wait() {
// TODO
unsafe { asm!("msr daifclr, 0b111; wfi" :::: "volatile") };
unsafe { llvm_asm!("msr daifclr, 0b111; wfi" :::: "volatile") };
}
/// Disable Interrupts
#[inline]
pub fn disable() {
unsafe {
asm!("msr daifset, 0b111" ::: "memory" : "volatile");
llvm_asm!("msr daifset, 0b111" ::: "memory" : "volatile");
}
}
......@@ -45,7 +45,7 @@ pub fn disable() {
pub fn nested_disable() -> bool {
let flags: usize;
unsafe {
asm!("mrs $0, daif" : "=r"(flags) :: "memory" : "volatile");
llvm_asm!("mrs $0, daif" : "=r"(flags) :: "memory" : "volatile");
}
let mut was_enabled = true;
......
// Copyright (c) 2018 Stefan Lankes, RWTH Aachen University
// Colin Finck, RWTH Aachen University
// Copyright (c) 2018-2020 Stefan Lankes, RWTH Aachen University
// 2018 Colin Finck, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
include!(concat!(env!("CARGO_TARGET_DIR"), "/config.rs"));
pub mod irq;
pub mod pci;
pub mod percore;
pub mod processor;
pub mod scheduler;
pub mod serial;
pub mod start;
pub mod stubs;
pub mod systemtime;
......@@ -20,18 +20,17 @@ use crate::arch::aarch64::kernel::percore::*;
use crate::arch::aarch64::kernel::serial::SerialPort;
pub use crate::arch::aarch64::kernel::stubs::*;
pub use crate::arch::aarch64::kernel::systemtime::get_boot_time;
use crate::arch::aarch64::mm::{PhysAddr, VirtAddr};
use crate::environment;
use crate::kernel_message_buffer;
use crate::synch::spinlock::Spinlock;
use crate::config::*;
use core::ptr;
const SERIAL_PORT_BAUDRATE: u32 = 115200;
lazy_static! {
static ref COM1: SerialPort = SerialPort::new(unsafe { BOOT_INFO.uartport });
static ref CPU_ONLINE: Spinlock<&'static mut u32> =
Spinlock::new(unsafe { &mut BOOT_INFO.cpu_online });
}
static mut COM1: SerialPort = SerialPort::new(0x9000000);
static CPU_ONLINE: Spinlock<u32> = Spinlock::new(0);
#[repr(C)]
struct BootInfo {
......@@ -93,37 +92,53 @@ static mut BOOT_INFO: BootInfo = BootInfo {
// FUNCTIONS
pub fn get_image_size() -> usize {
unsafe { volatile_load(&BOOT_INFO.image_size) as usize }
unsafe { core::ptr::read_volatile(&BOOT_INFO.image_size) as usize }
}
pub fn get_limit() -> usize {
unsafe { volatile_load(&BOOT_INFO.limit) as usize }
unsafe { core::ptr::read_volatile(&BOOT_INFO.limit) as usize }
}
pub fn get_mbinfo() -> usize {
unsafe { volatile_load(&BOOT_INFO.mb_info) as usize }
unsafe { core::ptr::read_volatile(&BOOT_INFO.mb_info) as usize }
}
pub fn get_processor_count() -> usize {
unsafe { volatile_load(&BOOT_INFO.cpu_online) as usize }
pub fn get_processor_count() -> u32 {
unsafe { core::ptr::read_volatile(&BOOT_INFO.cpu_online) }
}
pub fn get_base_address() -> VirtAddr {
VirtAddr::zero()
}
pub fn get_tls_start() -> VirtAddr {
VirtAddr::zero()
}
pub fn get_tls_filesz() -> usize {
0
}
pub fn get_tls_memsz() -> usize {
0
}
/// Whether HermitCore is running under the "uhyve" hypervisor.
pub fn is_uhyve() -> bool {
unsafe { volatile_load(&BOOT_INFO.uhyve) != 0 }
unsafe { core::ptr::read_volatile(&BOOT_INFO.uhyve) != 0 }
}
/// Whether HermitCore is running alone (true) or side-by-side to Linux in Multi-Kernel mode (false).
pub fn is_single_kernel() -> bool {
unsafe { volatile_load(&BOOT_INFO.single_kernel) != 0 }
unsafe { core::ptr::read_volatile(&BOOT_INFO.single_kernel) != 0 }
}
pub fn get_cmdsize() -> usize {
unsafe { volatile_load(&BOOT_INFO.cmdsize) as usize }
unsafe { core::ptr::read_volatile(&BOOT_INFO.cmdsize) as usize }
}
pub fn get_cmdline() -> usize {
unsafe { volatile_load(&BOOT_INFO.cmdline) as usize }
pub fn get_cmdline() -> VirtAddr {
VirtAddr(unsafe { core::ptr::read_volatile(&BOOT_INFO.cmdline)})
}
/// Earliest initialization function called by the Boot Processor.
......@@ -133,24 +148,30 @@ pub fn message_output_init() {
if environment::is_single_kernel() {
// We can only initialize the serial port here, because VGA requires processor
// configuration first.
COM1.init(SERIAL_PORT_BAUDRATE);
unsafe { COM1.init(SERIAL_PORT_BAUDRATE); }
}
}
pub fn output_message_byte(byte: u8) {
if environment::is_single_kernel() {
// Output messages to the serial port and VGA screen in unikernel mode.
COM1.write_byte(byte);
unsafe { COM1.write_byte(byte); }
} else {
// Output messages to the kernel message buffer in multi-kernel mode.
kernel_message_buffer::write_byte(byte);
}
}
pub fn output_message_buf(buf: &[u8]) {
for byte in buf {
output_message_byte(*byte);
}
}
/// Real Boot Processor initialization as soon as we have put the first Welcome message on the screen.
pub fn boot_processor_init() {
::mm::init();
::mm::print_information();
crate::mm::init();
crate::mm::print_information();
environment::init();
/*processor::detect_features();
......@@ -190,24 +211,24 @@ pub fn boot_processor_init() {
// TODO: Setting PMUSERENR_EL0 is probably not required, but find out about that
// when reading PMCCNTR_EL0 works at all.
let pmuserenr_el0: u32 = 1 << 0 | 1 << 2 | 1 << 3;
asm!("msr pmuserenr_el0, $0" :: "r"(pmuserenr_el0) :: "volatile");
llvm_asm!("msr pmuserenr_el0, $0" :: "r"(pmuserenr_el0) :: "volatile");
debug!("pmuserenr_el0");
// TODO: Setting PMCNTENSET_EL0 is probably not required, but find out about that
// when reading PMCCNTR_EL0 works at all.
let pmcntenset_el0: u32 = 1 << 31;
asm!("msr pmcntenset_el0, $0" :: "r"(pmcntenset_el0) :: "volatile");
llvm_asm!("msr pmcntenset_el0, $0" :: "r"(pmcntenset_el0) :: "volatile");
debug!("pmcntenset_el0");
// Enable PMCCNTR_EL0 using PMCR_EL0.
let mut pmcr_el0: u32 = 0;
asm!("mrs $0, pmcr_el0" : "=r"(pmcr_el0) :: "memory" : "volatile");
llvm_asm!("mrs $0, pmcr_el0" : "=r"(pmcr_el0) :: "memory" : "volatile");
debug!(
"PMCR_EL0 (has RES1 bits and therefore musn't be zero): {:#X}",
pmcr_el0
);
pmcr_el0 |= 1 << 0 | 1 << 2 | 1 << 6;
asm!("msr pmcr_el0, $0" :: "r"(pmcr_el0) :: "volatile");
llvm_asm!("msr pmcr_el0, $0" :: "r"(pmcr_el0) :: "volatile");
}
// Read out PMCCNTR_EL0 in an infinite loop.
......@@ -215,7 +236,7 @@ pub fn boot_processor_init() {
loop {
unsafe {
let pmccntr: u64;
asm!("mrs $0, pmccntr_el0" : "=r"(pmccntr) ::: "volatile");
llvm_asm!("mrs $0, pmccntr_el0" : "=r"(pmccntr) ::: "volatile");
println!("Count: {}", pmccntr);
}
}
......@@ -258,10 +279,13 @@ fn finish_processor_init() {
// This triggers apic::boot_application_processors (bare-metal/QEMU) or uhyve
// to initialize the next processor.
**CPU_ONLINE.lock() += 1;
*CPU_ONLINE.lock() += 1;
}
pub fn network_adapter_init() -> i32 {
// AArch64 supports no network adapters on bare-metal/QEMU, so return a failure code.
-1
}
pub fn print_statistics() {
}
use alloc::rc::Rc;
use core::cell::RefCell;
// Currently, onbly a dummy implementation
pub struct VirtioNetDriver;
impl VirtioNetDriver {
pub fn init_vqs(&mut self) {
}
pub fn set_polling_mode(&mut self, value: bool) {
//(self.vqueues.as_deref_mut().unwrap())[VIRTIO_NET_RX_QUEUE].set_polling_mode(value);
}
pub fn get_mac_address(&self) -> [u8; 6] {
[0; 6]
}
pub fn get_mtu(&self) -> u16 {
1500 //self.device_cfg.mtu
}
pub fn get_tx_buffer(&mut self, len: usize) -> Result<(*mut u8, usize), ()> {
Err(())
}
pub fn send_tx_buffer(&mut self, index: usize, len: usize) -> Result<(), ()> {
Err(())
}
pub fn has_packet(&self) -> bool {
false
}
pub fn receive_rx_buffer(&self) -> Result<&'static [u8], ()> {
Err(())
}
pub fn rx_buffer_consumed(&mut self) {
}
}
pub fn get_network_driver() -> Option<Rc<RefCell<VirtioNetDriver>>> {
None
}
......@@ -5,21 +5,21 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use crate::scheduler::PerCoreScheduler;
use crate::scheduler::{CoreId, PerCoreScheduler};
use core::ptr;
#[no_mangle]
pub static mut PERCORE: PerCoreVariables = PerCoreVariables::new(0);
pub struct PerCoreVariables {
/// APIC ID of this CPU Core.
core_id: PerCoreVariable<usize>,
/// Scheduler for this CPU Core.
/// ID of the current Core.
core_id: PerCoreVariable<CoreId>,
/// Scheduler of the current Core.
scheduler: PerCoreVariable<*mut PerCoreScheduler>,
}
impl PerCoreVariables {
pub const fn new(core_id: usize) -> Self {
pub const fn new(core_id: CoreId) -> Self {
Self {
core_id: PerCoreVariable::new(core_id),
scheduler: PerCoreVariable::new(0 as *mut PerCoreScheduler),
......@@ -62,7 +62,7 @@ where
}
#[inline]
pub fn core_id() -> usize {
pub fn core_id() -> CoreId {
unsafe { PERCORE.core_id.get() }
}
......
......@@ -33,10 +33,29 @@ pub fn generate_random_number() -> Option<u32> {
None
}
pub fn run_on_hypervisor() -> bool {
true
}
/// Search the most significant bit
#[inline(always)]
pub fn msb(value: u64) -> Option<u64> {
if value > 0 {
let ret: u64;
let u64_bits = 64;
unsafe {
llvm_asm!("clz $0, $1; sub $0, $2, $0" : "=r"(ret) : "r"(value), "r"(u64_bits - 1) : "cc" : "volatile");
}
Some(ret)
} else {
None
}
}
/// The halt function stops the processor until the next interrupt arrives
pub fn halt() {
unsafe {
asm!("wfi" :::: "volatile");
llvm_asm!("wfi" :::: "volatile");
}
}
......@@ -64,6 +83,10 @@ pub fn get_timestamp() -> u64 {
0
}
pub fn supports_1gib_pages() -> bool {
false
}
/// Delay execution by the given number of microseconds using busy-waiting.
#[inline]
pub fn udelay(usecs: u64) {
......
// Copyright (c) 2018 Stefan Lankes, RWTH Aachen University
// Copyright (c) 2018-2020 Stefan Lankes, RWTH Aachen University
// 2018 Colin Finck, 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.
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Architecture dependent interface to initialize a task
use alloc::rc::Rc;
use core::cell::RefCell;
use core::{mem, ptr};
use crate::arch::aarch64::kernel::percore::*;
use crate::arch::aarch64::kernel::processor;
use crate::scheduler::task::{Task, TaskFrame, TaskTLS};
include!(concat!(env!("CARGO_TARGET_DIR"), "/config.rs"));
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE};
use crate::arch::aarch64::mm::{PhysAddr, VirtAddr};
use crate::arch::aarch64::mm::paging::{PageSize,BasePageSize,PageTableEntryFlags};
use core::cell::RefCell;
use core::{mem, ptr};
use crate::scheduler::task::{Task, TaskFrame};
use crate::environment;
extern "C" {
static tls_start: u8;
static tls_end: u8;
}
pub struct TaskStacks {
is_boot_stack: bool,
stack: usize,
pub struct BootStack {
/// stack for kernel tasks
stack: VirtAddr,
/// stack to handle interrupts
ist0: VirtAddr,
}
pub struct CommonStack {
/// start address of allocated virtual memory region
virt_addr: VirtAddr,
/// start address of allocated virtual memory region
phys_addr: PhysAddr,
/// total size of all stacks
total_size: usize,
}
pub enum TaskStacks {
Boot(BootStack),
Common(CommonStack),
}
impl TaskStacks {
pub fn new() -> Self {
// TODO: Allocate
Self {
is_boot_stack: false,
stack: 0,
pub fn new(size: usize) -> Self {
let user_stack_size = if size < KERNEL_STACK_SIZE {
KERNEL_STACK_SIZE
} else {
align_up!(size, BasePageSize::SIZE)
};
let total_size = user_stack_size + DEFAULT_STACK_SIZE + KERNEL_STACK_SIZE;
let virt_addr = crate::arch::mm::virtualmem::allocate(total_size + 4 * BasePageSize::SIZE)
.expect("Failed to allocate Virtual Memory for TaskStacks");
let phys_addr = crate::arch::mm::physicalmem::allocate(total_size)
.expect("Failed to allocate Physical Memory for TaskStacks");
debug!(
"Create stacks at {:#X} with a size of {} KB",
virt_addr,
total_size >> 10
);
let mut flags = PageTableEntryFlags::empty();
flags.normal().writable().execute_disable();
// map IST0 into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + BasePageSize::SIZE,
phys_addr,
KERNEL_STACK_SIZE / BasePageSize::SIZE,
flags,
);
// map kernel stack into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + KERNEL_STACK_SIZE + 2 * BasePageSize::SIZE,
phys_addr + KERNEL_STACK_SIZE,
DEFAULT_STACK_SIZE / BasePageSize::SIZE,
flags,
);
// map user stack into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + KERNEL_STACK_SIZE + DEFAULT_STACK_SIZE + 3 * BasePageSize::SIZE,
phys_addr + KERNEL_STACK_SIZE + DEFAULT_STACK_SIZE,
user_stack_size / BasePageSize::SIZE,
flags,
);
// clear user stack
unsafe {
ptr::write_bytes(
(virt_addr + KERNEL_STACK_SIZE + DEFAULT_STACK_SIZE + 3 * BasePageSize::SIZE)
.as_mut_ptr::<u8>(),
0xAC,
user_stack_size,
);
}
TaskStacks::Common(CommonStack {
virt_addr,
phys_addr,
total_size,
})
}
pub fn from_boot_stacks() -> TaskStacks {
//let tss = unsafe { &(*PERCORE.tss.get()) };
/*let stack = VirtAddr::from_usize(tss.rsp[0] as usize + 0x10 - KERNEL_STACK_SIZE);
debug!("Using boot stack {:#X}", stack);
let ist0 = VirtAddr::from_usize(tss.ist[0] as usize + 0x10 - KERNEL_STACK_SIZE);
debug!("IST0 is located at {:#X}", ist0);*/
let stack = VirtAddr::zero();
let ist0 = VirtAddr::zero();
TaskStacks::Boot(BootStack { stack, ist0 })
}