mgba panic handler 100% safe, justrelease only tho

This commit is contained in:
Lokathor 2018-12-23 15:52:42 -07:00
parent 7ab96c35f2
commit 7d8c82ddbc
3 changed files with 97 additions and 97 deletions

View file

@ -1,109 +1,30 @@
#![no_std]
#![feature(start)]
#![forbid(unsafe_code)]
#[no_mangle]
pub unsafe extern "C" fn __clzsi2(mut x: usize) -> usize {
let mut y: usize;
let mut n: usize = 32;
y = x >> 16;
if y != 0 {
n = n - 16;
x = y;
}
y = x >> 8;
if y != 0 {
n = n - 8;
x = y;
}
y = x >> 4;
if y != 0 {
n = n - 4;
x = y;
}
y = x >> 2;
if y != 0 {
n = n - 2;
x = y;
}
y = x >> 1;
if y != 0 {
n - 2
} else {
n - x
}
}
use gba::{
io::display::{DisplayControlMode, DisplayControlSetting, DISPCNT},
video::Mode3,
Color,
};
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
unsafe {
const DEBUG_ENABLE_MGBA: *mut u16 = 0x4fff780 as *mut u16;
const DEBUG_OUTPUT_BASE: *mut u8 = 0x4fff600 as *mut u8;
const DEBUG_SEND_MGBA: *mut u16 = 0x4fff700 as *mut u16;
const DEBUG_SEND_FLAG: u16 = 0x100;
const DEBUG_FATAL: u16 = 0;
const DEBUG_ERROR: u16 = 1;
DEBUG_ENABLE_MGBA.write_volatile(0xC0DE);
if DEBUG_ENABLE_MGBA.read_volatile() == 0x1DEA {
// Give the location
if let Some(location) = info.location() {
let mut out_ptr = DEBUG_OUTPUT_BASE;
let line = location.line();
let mut line_bytes = [
(line / 10000) as u8,
((line / 1000) % 10) as u8,
((line / 1000) % 10) as u8,
((line / 10) % 10) as u8,
(line % 10) as u8,
];
for line_bytes_mut in line_bytes.iter_mut() {
*line_bytes_mut += b'0';
}
for b in "Panic: "
.bytes()
.chain(location.file().bytes())
.chain(", Line ".bytes())
.chain(line_bytes.iter().cloned())
.take(255)
{
out_ptr.write_volatile(b);
out_ptr = out_ptr.offset(1);
}
} else {
let mut out_ptr = DEBUG_OUTPUT_BASE;
for b in "Panic with no location info:".bytes().take(255) {
out_ptr.write_volatile(b);
out_ptr = out_ptr.offset(1);
}
}
DEBUG_SEND_MGBA.write_volatile(DEBUG_SEND_FLAG + DEBUG_ERROR);
// Give the payload
if let Some(payload) = info.payload().downcast_ref::<&str>() {
let mut out_ptr = DEBUG_OUTPUT_BASE;
for b in payload.bytes().take(255) {
out_ptr.write_volatile(b);
out_ptr = out_ptr.offset(1);
}
} else {
let mut out_ptr = DEBUG_OUTPUT_BASE;
for b in "no payload".bytes().take(255) {
out_ptr.write_volatile(b);
out_ptr = out_ptr.offset(1);
}
}
DEBUG_SEND_MGBA.write_volatile(DEBUG_SEND_FLAG + DEBUG_ERROR);
DEBUG_SEND_MGBA.write_volatile(DEBUG_SEND_FLAG + DEBUG_FATAL);
}
use core::fmt::Write;
use gba::mgba::{MGBADebug, MGBADebugLevel};
if let Some(mut mgba) = MGBADebug::new() {
let _ = write!(mgba, "{}", info);
mgba.send(MGBADebugLevel::Fatal);
}
loop {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
unsafe {
(0x400_0000 as *mut u16).write_volatile(0x0403);
(0x600_0000 as *mut u16).offset(120 + 80 * 240).write_volatile(0x001F);
(0x600_0000 as *mut u16).offset(136 + 80 * 240).write_volatile(0x03E0);
(0x600_0000 as *mut u16).offset(120 + 96 * 240).write_volatile(0x7C00);
panic!("fumoffu!");
}
const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayControlMode::Bitmap3).with_display_bg2(true);
DISPCNT.write(SETTING);
Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0));
Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0));
Mode3::write_pixel(120, 96, Color::from_rgb(0, 0, 31));
panic!("fumoffu!");
}

View file

@ -62,7 +62,7 @@ pub mod base;
pub(crate) use self::base::*;
pub mod bios;
pub mod io;
pub mod mgba;
pub mod video;
newtype! {

79
src/mgba.rs Normal file
View file

@ -0,0 +1,79 @@
//! Special utils for if you're running on the mGBA emulator.
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
#[allow(missing_docs)]
pub enum MGBADebugLevel {
Fatal = 0,
Error = 1,
Warning = 2,
Info = 3,
Debug = 4,
}
/// Allows writing to the `mGBA` debug output.
#[derive(Debug, PartialEq, Eq)]
pub struct MGBADebug {
bytes_written: u8,
}
impl MGBADebug {
const ENABLE_ADDRESS: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x4fff780) };
const ENABLE_ADDRESS_INPUT: u16 = 0xC0DE;
const ENABLE_ADDRESS_OUTPUT: u16 = 0x1DEA;
const OUTPUT_BASE: VolAddress<u8> = unsafe { VolAddress::new_unchecked(0x4fff600) };
const SEND_ADDRESS: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x4fff700) };
const SEND_FLAG: u16 = 0x100;
/// Gives a new MGBADebug, if running within `mGBA`
///
/// # Fails
///
/// If you're not running in the `mGBA` emulator.
pub fn new() -> Option<Self> {
Self::ENABLE_ADDRESS.write(Self::ENABLE_ADDRESS_INPUT);
if Self::ENABLE_ADDRESS.read() == Self::ENABLE_ADDRESS_OUTPUT {
Some(MGBADebug { bytes_written: 0 })
} else {
None
}
}
/// Once output is buffered you must send it out with a level.
///
/// If the `Fatal` level is selected, the buffer is sent out as `Error`
/// followed by a blank message being sent as `Error`. This is done because
/// the `Fatal` message appears in a popup without showing up in the log, so
/// it might accidentally be discarded.
pub fn send(&mut self, level: MGBADebugLevel) {
if level == MGBADebugLevel::Fatal {
Self::SEND_ADDRESS.write(Self::SEND_FLAG | MGBADebugLevel::Error as u16);
Self::SEND_ADDRESS.write(Self::SEND_FLAG | MGBADebugLevel::Fatal as u16);
} else {
Self::SEND_ADDRESS.write(Self::SEND_FLAG | level as u16);
}
}
}
impl core::fmt::Write for MGBADebug {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
unsafe {
let mut current = Self::OUTPUT_BASE.offset(self.bytes_written as isize);
let mut str_iter = s.bytes();
while self.bytes_written < 255 {
match str_iter.next() {
Some(byte) => {
current.write(byte);
current = current.offset(1);
self.bytes_written += 1;
}
None => return Ok(()),
}
}
Err(core::fmt::Error)
}
}
}