add some preliminary bits for the loader to detect suspend/resume

This commit is contained in:
bunnie 2021-04-29 00:22:38 +08:00
parent 2df2e654dd
commit 805d7c79a2
3 changed files with 145 additions and 2 deletions

View file

@ -6,6 +6,7 @@ edition = "2018"
description = "Initial kernel loader for Xous"
[dependencies]
utralib = {path = "../utralib"}
[dev-dependencies]
lazy_static = "1.4.0"

View file

@ -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

87
loader/src/murmur3.rs Normal file
View file

@ -0,0 +1,87 @@
// Copyright (c) 2020 Stu Small
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
);
}
}
}