From 35058781769d36fc6931b3ec56a90b7c037a39b0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 14:51:20 +0000 Subject: [PATCH] bootloader: add basic network support. --- artiq/firmware/Cargo.lock | 10 +-- artiq/firmware/bootloader/Cargo.toml | 14 ++++- artiq/firmware/bootloader/bootloader.ld | 2 +- artiq/firmware/bootloader/main.rs | 82 ++++++++++++++++++++----- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index a3a9dfd79..60bc1d727 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -29,6 +29,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] [[package]] @@ -49,8 +50,9 @@ dependencies = [ "board 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", - "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] [[package]] @@ -199,11 +201,6 @@ dependencies = [ "std_artiq 0.0.0", ] -[[package]] -name = "rlibc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "runtime" version = "0.0.0" @@ -307,7 +304,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" -"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 26521a87e..465905e7e 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -13,7 +13,17 @@ path = "main.rs" build_misoc = { path = "../libbuild_misoc" } [dependencies] -rlibc = "1.0" byteorder = { version = "1.0", default-features = false } crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } -board = { path = "../libboard", features = ["uart_console"] } +board = { path = "../libboard", features = ["uart_console", "smoltcp"] } + +[dependencies.compiler_builtins] +git = "https://github.com/m-labs/compiler-builtins" +rev = "97916b1" +features = ["mem"] + +[dependencies.smoltcp] +git = "https://github.com/m-labs/smoltcp" +rev = "507d2fe" +default-features = false +features = ["proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld index 8fe809a49..6331f920e 100644 --- a/artiq/firmware/bootloader/bootloader.ld +++ b/artiq/firmware/bootloader/bootloader.ld @@ -28,7 +28,7 @@ SECTIONS . += 4; } - .bss ALIGN(4) : + .bss : { _fbss = .; *(.bss .bss.*) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 61ae7a48d..2c06953a6 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -1,16 +1,18 @@ #![no_std] -#![feature(lang_items)] +#![feature(lang_items, compiler_builtins_lib)] -extern crate rlibc; +extern crate compiler_builtins; extern crate crc; extern crate byteorder; +extern crate smoltcp; #[macro_use] extern crate board; use core::{ptr, slice}; use crc::crc32; use byteorder::{ByteOrder, BigEndian}; -use board::{boot, cache}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; +use board::{boot, cache, clock, config, ethmac}; use board::uart_console::Console; fn check_integrity() -> bool { @@ -28,7 +30,7 @@ fn check_integrity() -> bool { } } -unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { +fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { const MEMORY: *mut u32 = board::mem::MAIN_RAM_BASE as *mut u32; *total = 0; @@ -43,7 +45,7 @@ unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { ) => ({ $prepare; for $i in $range { - ptr::write_volatile(MEMORY.offset($index as isize), $data); + unsafe { ptr::write_volatile(MEMORY.offset($index as isize), $data) }; *total += 1; } @@ -52,7 +54,7 @@ unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { $prepare; for $i in $range { - if ptr::read_volatile(MEMORY.offset($index as isize)) != $data { + if unsafe { ptr::read_volatile(MEMORY.offset($index as isize)) } != $data { *wrong += 1; } } @@ -95,7 +97,7 @@ fn startup() -> bool { } let (mut total, mut wrong) = (0, 0); - if unsafe { memory_test(&mut total, &mut wrong) } { + if memory_test(&mut total, &mut wrong) { println!("Memory test passed"); } else { println!("Memory test failed ({}/{} words incorrect)", wrong, total); @@ -105,36 +107,81 @@ fn startup() -> bool { true } -unsafe fn flash_boot() { +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 header = unsafe { 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 + } else if length > 4 * 1024 * 1024 { + println!("Firmware too large (is it corrupted?)"); + return } - let firmware_in_flash = slice::from_raw_parts(FIRMWARE.offset(8), length); + let firmware_in_flash = unsafe { 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); + let firmware_in_sdram = unsafe { 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); + unsafe { boot::jump(MAIN_RAM as usize) } } else { - println!("Firmware CRC failed (actual {:08x}, expected {:08x}", + println!("Firmware CRC failed (actual {:08x}, expected {:08x})", actual_crc, expected_crc); } } +fn network_boot() { + println!("Initializing network..."); + + let eth_addr = match config::read_str("mac", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => addr, + _ => EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]) + }; + + let ip_addr = match config::read_str("ip", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => addr, + _ => IpAddress::v4(192, 168, 1, 50) + }; + + println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); + + let net_device = unsafe { ethmac::EthernetDevice::new() }; + let mut neighbor_cache_storage = [None; 2]; + let neighbor_cache = + smoltcp::iface::NeighborCache::new(&mut neighbor_cache_storage[..]); + let mut ip_addrs = [IpCidr::new(ip_addr, 0)]; + let mut interface = + smoltcp::iface::EthernetInterfaceBuilder::new(net_device) + .neighbor_cache(neighbor_cache) + .ethernet_addr(eth_addr) + .ip_addrs(&mut ip_addrs[..]) + .finalize(); + + let mut socket_set_storage = []; + let mut sockets = + smoltcp::socket::SocketSet::new(&mut socket_set_storage[..]); + + println!("Waiting for connections..."); + + loop { + match interface.poll(&mut sockets, clock::get_ms()) { + Ok(_) => (), + Err(smoltcp::Error::Unrecognized) => (), + Err(err) => println!("Network error: {}", err) + } + } +} + #[no_mangle] pub extern fn main() -> i32 { println!(""); @@ -150,7 +197,8 @@ pub extern fn main() -> i32 { if startup() { println!(""); - unsafe { flash_boot() }; + flash_boot(); + network_boot(); } else { println!("Halting."); } @@ -163,6 +211,12 @@ 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] +pub extern fn abort() { + println!("aborted"); + loop {} +} + #[no_mangle] #[lang = "panic_fmt"] pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {