mirror of https://github.com/m-labs/artiq.git
172 lines
4.6 KiB
Rust
172 lines
4.6 KiB
Rust
|
#![no_std]
|
||
|
#![feature(lang_items)]
|
||
|
|
||
|
extern crate rlibc;
|
||
|
extern crate crc;
|
||
|
extern crate byteorder;
|
||
|
#[macro_use]
|
||
|
extern crate board;
|
||
|
|
||
|
use core::{ptr, slice};
|
||
|
use crc::crc32;
|
||
|
use byteorder::{ByteOrder, BigEndian};
|
||
|
use board::{boot, cache};
|
||
|
use board::uart_console::Console;
|
||
|
|
||
|
fn check_integrity() -> bool {
|
||
|
extern {
|
||
|
static _begin: u8;
|
||
|
static _end: u8;
|
||
|
static _crc: u32;
|
||
|
}
|
||
|
|
||
|
unsafe {
|
||
|
let length = &_end as *const u8 as usize -
|
||
|
&_begin as *const u8 as usize;
|
||
|
let bootloader = slice::from_raw_parts(&_begin as *const u8, length);
|
||
|
crc32::checksum_ieee(bootloader) == _crc
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool {
|
||
|
const MEMORY: *mut u32 = board::mem::MAIN_RAM_BASE as *mut u32;
|
||
|
|
||
|
*total = 0;
|
||
|
*wrong = 0;
|
||
|
|
||
|
macro_rules! test {
|
||
|
(
|
||
|
$prepare:stmt;
|
||
|
for $i:ident in ($range:expr) {
|
||
|
MEMORY[$index:expr] = $data:expr
|
||
|
}
|
||
|
) => ({
|
||
|
$prepare;
|
||
|
for $i in $range {
|
||
|
ptr::write_volatile(MEMORY.offset($index as isize), $data);
|
||
|
*total += 1;
|
||
|
}
|
||
|
|
||
|
cache::flush_cpu_dcache();
|
||
|
cache::flush_l2_cache();
|
||
|
|
||
|
$prepare;
|
||
|
for $i in $range {
|
||
|
if ptr::read_volatile(MEMORY.offset($index as isize)) != $data {
|
||
|
*wrong += 1;
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
fn prng32(seed: &mut u32) -> u32 { *seed = 1664525 * *seed + 1013904223; *seed }
|
||
|
fn prng16(seed: &mut u16) -> u16 { *seed = 25173 * *seed + 13849; *seed }
|
||
|
|
||
|
// Test data bus
|
||
|
test!((); for i in (0..0x100) { MEMORY[i] = 0xAAAAAAAA });
|
||
|
test!((); for i in (0..0x100) { MEMORY[i] = 0x55555555 });
|
||
|
|
||
|
// Test counter addressing with random data
|
||
|
test!(let mut seed = 0;
|
||
|
for i in (0..0x100000) { MEMORY[i] = prng32(&mut seed) });
|
||
|
|
||
|
// Test random addressing with counter data
|
||
|
test!(let mut seed = 0;
|
||
|
for i in (0..0x10000) { MEMORY[prng16(&mut seed)] = i });
|
||
|
|
||
|
*wrong == 0
|
||
|
}
|
||
|
|
||
|
fn startup() -> bool {
|
||
|
if check_integrity() {
|
||
|
println!("Bootloader CRC passed");
|
||
|
} else {
|
||
|
println!("Bootloader CRC failed");
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
println!("Initializing SDRAM...");
|
||
|
|
||
|
if unsafe { board::sdram::init(Some(&mut Console)) } {
|
||
|
println!("SDRAM initialized");
|
||
|
} else {
|
||
|
println!("SDRAM initialization failed");
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
let (mut total, mut wrong) = (0, 0);
|
||
|
if unsafe { memory_test(&mut total, &mut wrong) } {
|
||
|
println!("Memory test passed");
|
||
|
} else {
|
||
|
println!("Memory test failed ({}/{} words incorrect)", wrong, total);
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
true
|
||
|
}
|
||
|
|
||
|
unsafe fn flash_boot() {
|
||
|
const FIRMWARE: *mut u8 = board::mem::FLASH_BOOT_ADDRESS as *mut u8;
|
||
|
const MAIN_RAM: *mut u8 = board::mem::MAIN_RAM_BASE as *mut u8;
|
||
|
|
||
|
println!("Booting from flash...");
|
||
|
|
||
|
let header = slice::from_raw_parts(FIRMWARE, 8);
|
||
|
let length = BigEndian::read_u32(&header[0..]) as usize;
|
||
|
let expected_crc = BigEndian::read_u32(&header[4..]);
|
||
|
|
||
|
if length == 0xffffffff {
|
||
|
println!("No firmware present");
|
||
|
return
|
||
|
}
|
||
|
|
||
|
let firmware_in_flash = slice::from_raw_parts(FIRMWARE.offset(8), length);
|
||
|
let actual_crc = crc32::checksum_ieee(firmware_in_flash);
|
||
|
|
||
|
if actual_crc == expected_crc {
|
||
|
let firmware_in_sdram = slice::from_raw_parts_mut(MAIN_RAM, length);
|
||
|
firmware_in_sdram.copy_from_slice(firmware_in_flash);
|
||
|
|
||
|
println!("Starting firmware.");
|
||
|
boot::jump(MAIN_RAM as usize);
|
||
|
} else {
|
||
|
println!("Firmware CRC failed (actual {:08x}, expected {:08x}",
|
||
|
actual_crc, expected_crc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[no_mangle]
|
||
|
pub extern fn main() -> i32 {
|
||
|
println!("");
|
||
|
println!(r" __ __ _ ____ ____ ");
|
||
|
println!(r"| \/ (_) ___| ___ / ___|");
|
||
|
println!(r"| |\/| | \___ \ / _ \| | ");
|
||
|
println!(r"| | | | |___) | (_) | |___ ");
|
||
|
println!(r"|_| |_|_|____/ \___/ \____|");
|
||
|
println!("");
|
||
|
println!("MiSoC Bootloader");
|
||
|
println!("Copyright (c) 2017 M-Labs Limited");
|
||
|
println!("");
|
||
|
|
||
|
if startup() {
|
||
|
println!("");
|
||
|
unsafe { flash_boot() };
|
||
|
} else {
|
||
|
println!("Halting.");
|
||
|
}
|
||
|
|
||
|
loop {}
|
||
|
}
|
||
|
|
||
|
#[no_mangle]
|
||
|
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
||
|
panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea)
|
||
|
}
|
||
|
|
||
|
#[no_mangle]
|
||
|
#[lang = "panic_fmt"]
|
||
|
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||
|
println!("panic at {}:{}: {}", file, line, args);
|
||
|
loop {}
|
||
|
}
|