Latest updates

This commit is contained in:
Justin Moore 2021-05-22 15:43:19 -05:00
parent e64f5006ca
commit 91291912ae
17 changed files with 434 additions and 71 deletions

View File

@ -2,10 +2,11 @@
[build] [build]
target = "powerpc64-unknown-linux-gnu" target = "powerpc64-unknown-linux-gnu"
[profile] [profile.release]
incremental = false incremental = false
opt-level = "z" opt-level = "z"
lto = true lto = true
[target.powerpc64-unknown-linux-gnu] [target.powerpc64-unknown-linux-gnu]
linker = "rust-lld" linker = "rust-lld"
rustflags = ["-C", "relocation-model=static"]

1
.gitignore vendored
View File

@ -1 +1,2 @@
.vscode/
**/target **/target

15
.vscode/tasks.json vendored
View File

@ -1,15 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "cargo",
"command": "build",
"args": ["-Zextra-link-arg"],
"problemMatcher": [
"$rustc"
],
"group": "build",
"label": "rust: cargo build"
}
]
}

13
Cargo.lock generated
View File

@ -79,11 +79,24 @@ name = "stage1"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"core_reqs", "core_reqs",
"xenon-cpu",
] ]
[[package]]
name = "volatile"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0"
[[package]]
name = "xenon-cpu"
version = "0.1.0"
[[package]] [[package]]
name = "xenon-enet" name = "xenon-enet"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"smoltcp", "smoltcp",
"volatile",
"xenon-cpu",
] ]

View File

@ -5,6 +5,7 @@ members = [
"boot/stage1", "boot/stage1",
"shared/core_reqs", "shared/core_reqs",
"shared/display", "shared/display",
"shared/xenon-cpu",
"shared/xenon-enet", "shared/xenon-enet",
] ]

View File

@ -7,8 +7,13 @@ edition = "2018"
[dependencies] [dependencies]
core_reqs = { path = "../../shared/core_reqs" } core_reqs = { path = "../../shared/core_reqs" }
xenon-cpu = { path = "../../shared/xenon-cpu" }
[profile.dev]
panic = "abort"
[profile.release] [profile.release]
panic = "abort"
opt-level = "s" opt-level = "s"
lto = true lto = true

View File

@ -4,7 +4,7 @@ SECTIONS
{ {
. = 0x800000001c000000; . = 0x800000001c000000;
.text : { .text 0x800000001c000000 : {
KEEP(*(.text.startup)); KEEP(*(.text.startup));
*(.text .text.*); *(.text .text.*);
} }
@ -12,6 +12,15 @@ SECTIONS
.sdata : { *(.sdata) } .sdata : { *(.sdata) }
.rodata : { *(.rodata) } .rodata : { *(.rodata) }
.dynsym : { *(.dynsym) }
.gnu.hash : { *(.gnu.hash) }
.hash : { *(.hash) }
.dynstr : { *(.dynstr) }
.rela.dyn : { *(.rela.dyn) }
.rela.opd : { *(.rela.opd) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : { *(.eh_frame) }
.got : { .got : {
__toc_start = .; __toc_start = .;
@ -21,7 +30,7 @@ SECTIONS
. = ALIGN(256); . = ALIGN(256);
__bss_start = .; __bss_start = .;
.bss : { *(.bss .bss.*) } .bss (NOLOAD) : { *(.bss .bss.*) }
.sbss : { *(.sbss .sbss.*) } .sbss : { *(.sbss .sbss.*) }
__bss_end = .; __bss_end = .;
} }

189
boot/stage1/src/except.rs Normal file
View File

@ -0,0 +1,189 @@
//! This module defines exception handlers.
use crate::iic::Iic;
#[allow(dead_code)]
#[repr(u32)]
enum ExceptionType {
Reset = 1,
MachineCheck = 2,
Dsi = 3,
Isi = 4,
ExternalInterrupt = 5,
Alignment = 6,
Program = 7,
Decrementer = 9,
}
#[repr(C, align(4096))]
#[derive(Copy, Clone)]
struct CpuContext {
r: [u64; 32],
lr: u64,
ctr: u64,
srr0: u64,
srr1: u64,
}
impl CpuContext {
const fn new() -> Self {
Self {
r: [0u64; 32],
lr: 0,
ctr: 0,
srr0: 0,
srr1: 0,
}
}
}
#[no_mangle]
static mut EXCEPTION_SAVE_AREA: [CpuContext; 6] = [CpuContext::new(); 6];
#[no_mangle]
extern "C" fn except(id: ExceptionType, save_area: &mut CpuContext) {
match id {
ExceptionType::ExternalInterrupt => {
let iic = unsafe { Iic::local() };
}
_ => loop {}
}
load_context(save_area);
}
fn load_context(ctx: &CpuContext) -> ! {
unsafe {
asm!(
"ld %r0, 256(%r4)",
"mtlr %r0",
"ld %r0, 264(%r4)",
"mtctr %r0",
"ld %r0, 272(%r4)",
"mtsrr0 %r0",
"ld %r0, 280(%r4)",
"mtsrr1 %r0",
"ld %r0, 0(%r4)",
"ld %r1, 8(%r4)",
"ld %r2, 16(%r4)",
"ld %r3, 24(%r4)",
"ld %r4, 32(%r4)",
"ld %r5, 40(%r4)",
"ld %r6, 48(%r4)",
"ld %r7, 56(%r4)",
"ld %r8, 64(%r4)",
"ld %r9, 72(%r4)",
"ld %r10, 80(%r4)",
"ld %r11, 88(%r4)",
"ld %r12, 96(%r4)",
"ld %r13, 104(%r4)",
"ld %r14, 112(%r4)",
"ld %r15, 120(%r4)",
"ld %r16, 128(%r4)",
"ld %r17, 136(%r4)",
"ld %r18, 144(%r4)",
"ld %r19, 152(%r4)",
"ld %r20, 160(%r4)",
"ld %r21, 168(%r4)",
"ld %r22, 176(%r4)",
"ld %r23, 184(%r4)",
"ld %r24, 192(%r4)",
"ld %r25, 200(%r4)",
"ld %r26, 208(%r4)",
"ld %r27, 216(%r4)",
"ld %r28, 224(%r4)",
"ld %r29, 232(%r4)",
"ld %r30, 240(%r4)",
"ld %r31, 248(%r4)",
"rfid",
in("4") ctx,
options(noreturn),
);
}
}
#[naked]
unsafe extern "C" fn except_thunk() {
asm!(
"mtctr %r4", // Reload CTR with original value
"mfspr %r4, 1023", // r4 = PIR
"sldi %r4, %r4, 32 + 12",
"oris %r4, %r4, EXCEPTION_SAVE_AREA@highest",
"ori %r4, %r4, EXCEPTION_SAVE_AREA@higher",
"rldicr %r4, %r4, 32, 63",
"oris %r4, %r4, EXCEPTION_SAVE_AREA@high",
"ori %r4, %r4, EXCEPTION_SAVE_AREA@l",
// Now save registers.
"std %r0, 0(%r4)",
"std %r1, 8(%r4)",
"subi %r1, %r1, 0x100", // HACK: Subtract 0x100 bytes from r1 to reuse the stack.
"std %r2, 16(%r4)",
"mfspr %r0, 304", // Reload R3, which was saved in HPSRG0.
"std %r0, 24(%r4)",
"mfspr %r0, 305", // Reload R4, which was saved in HSPRG1.
"std %r0, 32(%r4)",
"std %r5, 40(%r4)",
"std %r6, 48(%r4)",
"std %r7, 56(%r4)",
"std %r8, 64(%r4)",
"std %r9, 72(%r4)",
"std %r10, 80(%r4)",
"std %r11, 88(%r4)",
"std %r12, 96(%r4)",
"std %r13, 104(%r4)",
"std %r14, 112(%r4)",
"std %r15, 120(%r4)",
"std %r16, 128(%r4)",
"std %r17, 136(%r4)",
"std %r18, 144(%r4)",
"std %r19, 152(%r4)",
"std %r20, 160(%r4)",
"std %r21, 168(%r4)",
"std %r22, 176(%r4)",
"std %r23, 184(%r4)",
"std %r24, 192(%r4)",
"std %r25, 200(%r4)",
"std %r26, 208(%r4)",
"std %r27, 212(%r4)",
"std %r28, 220(%r4)",
"std %r29, 228(%r4)",
"std %r30, 236(%r4)",
"std %r31, 244(%r4)",
"mflr %r0",
"std %r0, 252(%r4)",
"mfctr %r0",
"std %r0, 260(%r4)",
"mfsrr0 %r0",
"std %r0, 268(%r4)",
"mfsrr1 %r0",
"std %r0, 276(%r4)",
"bl except",
options(noreturn)
);
}
/// Create a longjmp for an exception vector.
/// This will preverse r3/r4 in HSPRG0 and HSPRG1, respectively.
/// r3 will be loaded with the constant specified in the `id` parameter.
/// r4 will be loaded with the value of CTR.
const fn make_longjmp_exc(id: u16, target: usize) -> [u32; 11] {
[
0x7C704BA6, // mtspr HSPRG0, %r3
0x7C914BA6, // mtspr HSPRG1, %r4
(0x3C600000 | ((target >> 48) & 0xFFFF)) as u32, // lis %r3, target[64:48]
(0x60630000 | ((target >> 32) & 0xFFFF)) as u32, // ori %r3, %r3, target[48:32]
0x786307C6, // rldicr %r3, %r3, 32, 31
(0x64630000 | ((target >> 16) & 0xFFFF)) as u32, // oris %r3, %r3, target[32:16]
(0x60630000 | ((target >> 00) & 0xFFFF)) as u32, // ori %r3, %r3, target[16:0]
0x7C8902A6, // mfctr %r4
(0x38600000 | (id as u32)), // li %r3, id
0x7C6903A6, // mtctr %r3
0x4E800420, // bctr
]
}
pub unsafe fn init_except() {
let buf = make_longjmp_exc(5, except_thunk as usize);
core::ptr::copy_nonoverlapping(buf.as_ptr(), 0x00000500 as *mut u32, buf.len());
}

View File

@ -1,6 +1,7 @@
const IIC_BASE: usize = 0x80000200_00050000;
//! Integrated Interrupt Controller (IIC) //! Integrated Interrupt Controller (IIC)
const IIC_BASE: u64 = 0x80000200_00050000;
#[repr(usize)] #[repr(usize)]
enum Register { enum Register {
WhoAmI = 0x00, WhoAmI = 0x00,
@ -14,3 +15,59 @@ enum Register {
Unk70 = 0x70, Unk70 = 0x70,
} }
#[repr(u8)]
enum Interrupt {
Ipi4 = 2,
Ipi3 = 4,
Smm = 5,
Sfcx = 6,
SataHdd = 8,
SataCdrom = 9,
Ohci0 = 11,
Ehci0 = 12,
Ohci1 = 13,
Ehci1 = 14,
Xma = 16,
Audio = 17,
Enet = 19,
Xps = 21,
Graphics = 22,
Profiler = 24,
Biu = 25,
Ioc = 26,
Fsb = 27,
Ipi2 = 28,
Clock = 29,
Ipi1 = 30,
None = 31,
}
pub struct Iic {
mmio: &'static mut [u8],
}
impl Iic {
pub fn local() -> Self {
let id = xenon_cpu::intrin::pir();
let base = IIC_BASE + (0x1000 * id);
// SAFETY: It should always be safe to get a pointer to the current CPU's
// interrupt controller.
Self {
mmio: unsafe { core::slice::from_raw_parts_mut(base as *mut _, 0x1000) },
}
}
fn write<T>(&self, reg: Register, val: T) {
unsafe { core::ptr::write_volatile(&self.mmio[reg as usize] as *const _ as *mut T, val); }
}
fn read<T>(&self, reg: Register) -> T {
unsafe { core::ptr::read_volatile(&self.mmio[reg as usize] as *const _ as *mut T) }
}
pub fn set_priority(&self, prio: Interrupt) {
self.write(Register::CurrentTaskPriority, ((prio as u64) << 2));
self.read::<u64>(Register::CurrentTaskPriority);
}
}

View File

@ -9,13 +9,16 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::{sync::atomic::{AtomicU32, AtomicUsize, Ordering}}; use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
global_asm!(include_str!("startup.s")); global_asm!(include_str!("startup.s"));
extern crate core_reqs; extern crate core_reqs;
mod except;
mod iic;
mod panic; mod panic;
mod smc;
extern "C" { extern "C" {
fn start_from_libxenon() -> !; fn start_from_libxenon() -> !;
@ -65,6 +68,8 @@ const fn make_reljump(address: usize, target: usize) -> u32 {
#[no_mangle] #[no_mangle]
#[link_section = ".text.startup"] #[link_section = ".text.startup"]
pub extern "C" fn __start_rust(pir: u32, _hrmor: u32, _pvr: u32, src: u32) -> ! { pub extern "C" fn __start_rust(pir: u32, _hrmor: u32, _pvr: u32, src: u32) -> ! {
unsafe { smc::set_led(1, 0xF0); }
PROCESSORS.fetch_or(1 << pir, Ordering::Relaxed); PROCESSORS.fetch_or(1 << pir, Ordering::Relaxed);
if pir != 0 { if pir != 0 {
loop { loop {
@ -91,7 +96,11 @@ pub extern "C" fn __start_rust(pir: u32, _hrmor: u32, _pvr: u32, src: u32) -> !
let jmpbuf = make_longjmp(start_from_libxenon as usize); let jmpbuf = make_longjmp(start_from_libxenon as usize);
// Copy the jump buffer to some unused bytes at the beginning of the hypervisor. // Copy the jump buffer to some unused bytes at the beginning of the hypervisor.
core::ptr::copy_nonoverlapping(jmpbuf.as_ptr(), 0x000000A0 as *mut u32, jmpbuf.len()); core::ptr::copy_nonoverlapping(
jmpbuf.as_ptr(),
0x000000A0 as *mut u32,
jmpbuf.len(),
);
// Ensure the compiler does not reorder instructions. // Ensure the compiler does not reorder instructions.
core::sync::atomic::compiler_fence(Ordering::SeqCst); core::sync::atomic::compiler_fence(Ordering::SeqCst);
@ -115,15 +124,20 @@ pub extern "C" fn __start_rust(pir: u32, _hrmor: u32, _pvr: u32, src: u32) -> !
}; };
// Loop... // Loop...
while PROCESSORS.load(Ordering::Relaxed) != 0x3F {} while PROCESSORS.load(Ordering::Relaxed) != 0x3F {
unsafe { smc::set_led(1, PROCESSORS.load(Ordering::Relaxed) as u8); }
}
} }
// Shouldn't hit this case. // Shouldn't hit this case.
_ => loop {} _ => loop {},
} }
// Now the system is in a defined state. All secondary processors are captured, // Now the system is in a defined state. All secondary processors are captured,
// and we are free to modify the system. // and we are free to modify the system.
unsafe { except::init_except() };
unsafe { smc::set_led(1, 0xF0) };
loop {} loop {}
} }

View File

@ -1,4 +1,4 @@
use core::panic::PanicInfo; use core::{ffi::c_void, panic::PanicInfo};
#[lang = "eh_personality"] #[lang = "eh_personality"]
extern fn rust_eh_personality() {} extern fn rust_eh_personality() {}
@ -8,3 +8,9 @@ extern fn rust_eh_personality() {}
pub fn panic(_info: &PanicInfo) -> ! { pub fn panic(_info: &PanicInfo) -> ! {
loop {} loop {}
} }
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume(_exception: *mut c_void) -> ! {
loop {}
}

24
boot/stage1/src/smc.rs Normal file
View File

@ -0,0 +1,24 @@
//! This file includes routines to communicate with the SMC.
const SMC_ADDRESS: *mut u32 = 0x8000_0200_EA00_1000 as *mut u32;
pub unsafe fn send_message(msg: &[u32; 4]) {
while (core::ptr::read_volatile(SMC_ADDRESS.offset(33)) & 0x04000000) == 0 {}
core::ptr::write_volatile::<u32>(SMC_ADDRESS.offset(33), 0x04000000);
core::ptr::write_volatile::<u32>(SMC_ADDRESS.offset(32), msg[0]);
core::ptr::write_volatile::<u32>(SMC_ADDRESS.offset(32), msg[1]);
core::ptr::write_volatile::<u32>(SMC_ADDRESS.offset(32), msg[2]);
core::ptr::write_volatile::<u32>(SMC_ADDRESS.offset(32), msg[3]);
core::ptr::write_volatile::<u32>(SMC_ADDRESS.offset(33), 0x00000000);
}
pub unsafe fn set_led(override_val: u8, value: u8) {
let buf: [u32; 4] = [
0x99000000 | ((override_val as u32) << 16) | ((value as u32) << 8),
0x00000000,
0x00000000,
0x00000000,
];
send_message(&buf);
}

View File

@ -4,6 +4,7 @@
#define ctrlrd 136 #define ctrlrd 136
#define ctrlwr 152 #define ctrlwr 152
#define pvr 287 #define pvr 287
#define sprg0 272
#define hsprg0 304 #define hsprg0 304
#define hsprg1 305 #define hsprg1 305
#define hdsisr 306 #define hdsisr 306
@ -124,60 +125,25 @@ start_common:
mtspr lpcr, %r10 mtspr lpcr, %r10
isync isync
// set stack
// R1 = 0x80000000_1E000000
li %r1, 0
oris %r1, %r1, 0x8000
rldicr %r1, %r1, 32,31
oris %r1, %r1, 0x1e00
1:
slwi %r3, %r3, 16 // 64k stack per thread
sub %r1, %r1, %r3
subi %r1, %r1, 0x80
// lis %r3, 0x8000 // lis %r3, 0x8000
// rldicr %r3, %r3, 32,31 // rldicr %r3, %r3, 32,31
// oris %r3, %r3, start@high // oris %r3, %r3, start@high
// ori %r3, %r3, start@l // ori %r3, %r3, start@l
// ld %r2, 8(%r3) // ld %r2, 8(%r3)
// Set the high bit for PC. bl branch_high
bl 1f
1:
mflr %r10
lis %r3, 0x8000
sldi %r3, %r3, 32
or %r3, %r3, %r10
addi %r3, %r3, (1f - 1b)
mtctr %r3
bctr
1:
bl load_toc bl load_toc
mfspr %r3, pir
bl load_stack
mfspr %r3, pir mfspr %r3, pir
cmplwi %r3, 0 cmplwi %r3, 0
bne 1f bne 1f
// Initialize BSS. // Initialize BSS on processor 0 only.
ld %r10, __bss_start@got(%r2) bl init_bss
ld %r11, __bss_end@got(%r2)
sub %r11, %r11, %r10
srdi %r11, %r11, 2
subi %r10, %r10, 1
cmplwi %r11, 0
beq 1f
mtctr %r11
li %r11, 0
.bss_loop:
stwu %r11, 4(%r10)
bdnz .bss_loop
1:
// Relocate startup source. // Relocate startup source.
mr %r6, %r4 mr %r6, %r4
@ -185,11 +151,7 @@ start_common:
mfspr %r4, hrmor mfspr %r4, hrmor
mfpvr %r5 mfpvr %r5
// Branch to start_rust via 64-bit ELF ABI. bl __start_rust
ld %r0, __start_rust@got(%r2)
ld %r0, 0(%r0)
mtctr %r0
bctrl
nop nop
b . b .
@ -297,6 +259,57 @@ init_regs:
blr blr
// Initialize BSS
// R10 = clobber
// R11 = clobber
// CTR = clobber
init_bss:
ld %r10, __bss_start@got(%r2)
ld %r11, __bss_end@got(%r2)
sub %r11, %r11, %r10
srdi %r11, %r11, 2
subi %r10, %r10, 1
cmplwi %r11, 0
beq 1f
mtctr %r11
li %r11, 0
.bss_loop:
stwu %r11, 4(%r10)
bdnz .bss_loop
1:
blr
// Sets the high bit in PC.
// R3 = clobber
// R10 = clobber
branch_high:
mflr %r10
lis %r3, 0x8000
sldi %r3, %r3, 32
or %r3, %r3, %r10
mtlr %r3
blr
// Sets up the stack.
// R1(out) = stack
// R3(in/out) = pir / clobber
load_stack:
// set stack
// R1 = 0x80000000_1E000000
lis %r1, 0x8000
rldicr %r1, %r1, 32,31
oris %r1, %r1, 0x1e00
slwi %r3, %r3, 16 // 64k stack per thread
sub %r1, %r1, %r3
subi %r1, %r1, 0x80
blr
// Loads the table of contents pointer into R2. // Loads the table of contents pointer into R2.
// R0 = clobber // R0 = clobber
// R2 = TOC // R2 = TOC

View File

@ -0,0 +1,8 @@
[package]
name = "xenon-cpu"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,19 @@
#[inline]
pub fn mftb() -> u64 {
let tb;
unsafe {
asm!("mftb {}", out(reg) tb);
}
tb
}
#[inline]
pub fn pir() -> u64 {
let pir;
unsafe {
asm!("mfspr {}, 1023", out(reg) pir);
}
pir
}

View File

@ -0,0 +1,5 @@
#![feature(asm)]
#![no_std]
pub mod intrin;
pub mod time;

View File

@ -0,0 +1,13 @@
const TIMEBASE_FREQ: u64 = 3192000000 / 64;
use crate::intrin::mftb;
use core::time::Duration;
fn tdelay(time: u128) {
let tgt = time.saturating_add(mftb() as u128) as u64;
while mftb() < tgt {}
}
pub fn delay(length: Duration) {
tdelay((length.as_micros() * TIMEBASE_FREQ as u128) / 1000000);
}