From 805d7c79a294535d1c53fa64d2e9b0e06495e24b Mon Sep 17 00:00:00 2001 From: bunnie Date: Thu, 29 Apr 2021 00:22:38 +0800 Subject: [PATCH] add some preliminary bits for the loader to detect suspend/resume --- loader/Cargo.toml | 1 + loader/src/main.rs | 59 ++++++++++++++++++++++++++++- loader/src/murmur3.rs | 87 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 loader/src/murmur3.rs diff --git a/loader/Cargo.toml b/loader/Cargo.toml index c33ab911f..e00c26420 100644 --- a/loader/Cargo.toml +++ b/loader/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" description = "Initial kernel loader for Xous" [dependencies] +utralib = {path = "../utralib"} [dev-dependencies] lazy_static = "1.4.0" diff --git a/loader/src/main.rs b/loader/src/main.rs index 84b407262..f5b215e25 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -5,6 +5,8 @@ mod args; use args::{KernelArgument, KernelArguments}; +mod murmur3; + use core::num::NonZeroUsize; use core::{mem, ptr, slice}; @@ -1072,8 +1074,22 @@ fn boot_sequence(args: KernelArguments, _signature: u32) -> ! { }; read_initial_config(&mut cfg); - phase_1(&mut cfg); - phase_2(&mut cfg); + if !check_resume(&mut cfg) { + phase_1(&mut cfg); + phase_2(&mut cfg); + } else { + use utralib::generated::*; + // setup for a resume + let mut resume_csr = CSR::new(utra::susres::HW_SUSRES_BASE as *mut u32); + // set the resume marker for the SUSRES server + resume_csr.wfo(utra::susres::STATE_RESUME, 1); + resume_csr.wfo(utra::susres::CONTROL_PAUSE, 1); // ensure that the ticktimer is paused before resuming + + // set the resume marker for the early kernel init + ///////////TODO + + // SATP restore is handled by the `start_kernel` assembly pre-amble + } println!("Font maps located as follows:"); println!(" Hanzi @ {:08x}", fonts::hanzi::DATA_HANZI.as_ptr() as u32); @@ -1110,6 +1126,45 @@ fn boot_sequence(args: KernelArguments, _signature: u32) -> ! { } } +fn check_resume(cfg: &mut BootConfig) -> bool { + use utralib::generated::*; + const WORDS_PER_SECTOR: usize = 127; + const NUM_SECTORS: usize = 8; + const WORDS_PER_PAGE: usize = PAGE_SIZE / 4; + + let suspend_marker = cfg.sram_start as usize + cfg.sram_size - PAGE_SIZE * 2; + let marker: *mut[u32; WORDS_PER_PAGE] = suspend_marker as *mut[u32; WORDS_PER_PAGE]; + + let boot_seed = CSR::new(utra::seed::HW_SEED_BASE as *mut u32); + let seed0 = boot_seed.r(utra::seed::SEED0); + let seed1 = boot_seed.r(utra::seed::SEED1); + let was_forced_suspend: bool = if unsafe{(*marker)[0]} != 0 { true } else { false }; + + let mut clean = true; + let mut hashbuf: [u32; WORDS_PER_SECTOR] = [0; WORDS_PER_SECTOR]; + let mut index: usize = 0; + for sector in 0..NUM_SECTORS { + for i in 0..hashbuf.len() { + hashbuf[i] = unsafe{(*marker)[index * (WORDS_PER_SECTOR + 1) + i]}; + } + // sector 0 contains the boot seeds, which we replace with our own as read out from our FPGA before computing the hash + if sector == 0 { + hashbuf[1] = seed0; + hashbuf[2] = seed1; + } + let hash = crate::murmur3::murmur3_32(&hashbuf, 0); + if hash != unsafe{(*marker)[index * (WORDS_PER_SECTOR) + 1]} { + clean = false; + } + } + // zero out the clean suspend marker, so if something goes wrong during resume we don't try to resume again + for i in 0..WORDS_PER_PAGE { + unsafe{(*marker)[i] = 0;} + } + + clean +} + fn phase_1(cfg: &mut BootConfig) { // Allocate space for the stack pointer. // The bootloader should have placed the stack pointer at the end of RAM diff --git a/loader/src/murmur3.rs b/loader/src/murmur3.rs new file mode 100644 index 000000000..f1831eb0a --- /dev/null +++ b/loader/src/murmur3.rs @@ -0,0 +1,87 @@ +// Copyright (c) 2020 Stu Small +// +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , at your +// option. All files in the project carrying such notice may not be copied, +// modified, or distributed except according to those terms. + + +// This murmur3 code was vendored in on April 28, 2021. We choose to vendor the code for this simple +// non-cryptographic hash in to reduce the number of crate dependencies in the build system. See +// https://github.com/betrusted-io/xous-core/issues/54 for more details on why. +// It also allowed us to adapt the code for our specific no_std needs. + +const C1: u32 = 0x85eb_ca6b; +const C2: u32 = 0xc2b2_ae35; +const R1: u32 = 16; +const R2: u32 = 13; +const M: u32 = 5; +const N: u32 = 0xe654_6b64; + +pub fn murmur3_32(source: &[u32], seed: u32) -> u32 { + let mut processed = 0; + let mut state = seed; + + for &k in source.iter() { + processed += 4; + state ^= calc_k(k); + state = state.rotate_left(R2); + state = (state.wrapping_mul(M)).wrapping_add(N); + } + finish(state, processed) +} + +fn finish(state: u32, processed: u32) -> u32 { + let mut hash = state; + hash ^= processed as u32; + hash ^= hash.wrapping_shr(R1); + hash = hash.wrapping_mul(C1); + hash ^= hash.wrapping_shr(R2); + hash = hash.wrapping_mul(C2); + hash ^= hash.wrapping_shr(R1); + hash +} + +fn calc_k(k: u32) -> u32 { + const C1: u32 = 0xcc9e_2d51; + const C2: u32 = 0x1b87_3593; + const R1: u32 = 15; + k.wrapping_mul(C1).rotate_left(R1).wrapping_mul(C2) +} + + +#[cfg(test)] +mod tests { + use super::*; + struct Result { + slice: &'static [u32], + hash_32: u32, + } + + #[test] + fn test_static_slices() { + let tests = [ + Result { + slice: &[0x34333231], //"1234", + hash_32: 0x721c5dc3, + }, + Result { + slice: &[0x34333231, 0x38373635], // "12345678", + hash_32: 0x91b313ce, + }, + Result { + slice: &[], + hash_32: 0, + }, + ]; + + for test in &tests { + assert_eq!( + murmur3_32(test.slice, 0), + test.hash_32, + "Failed on slice {:x?}", test.slice + ); + } + } +}