2828// ===========================================================================
2929
3030use std:: io:: prelude:: * ;
31- use std:: sync:: atomic:: { AtomicU32 , AtomicU8 , Ordering } ;
31+ use std:: path:: PathBuf ;
32+ use std:: sync:: {
33+ atomic:: { AtomicU32 , AtomicU8 , Ordering } ,
34+ mpsc, Mutex ,
35+ } ;
3236
3337use clap:: Parser ;
3438use common:: video:: RGBColour ;
@@ -47,7 +51,7 @@ struct MyApp {
4751 mode : common:: video:: Mode ,
4852 font8x16 : Vec < TextureId > ,
4953 font8x8 : Vec < TextureId > ,
50- sender : std :: sync :: mpsc:: Sender < AppEvent > ,
54+ sender : mpsc:: Sender < AppEvent > ,
5155}
5256
5357#[ derive( Debug , PartialEq , Eq ) ]
@@ -68,10 +72,13 @@ struct Framebuffer<const N: usize> {
6872struct Args {
6973 /// Path to the OS library
7074 #[ arg( long) ]
71- os : std :: path :: PathBuf ,
75+ os : PathBuf ,
7276 /// Path to a file to use as a disk image
7377 #[ arg( long) ]
74- disk : Option < std:: path:: PathBuf > ,
78+ disk : Option < PathBuf > ,
79+ /// Path to NVRAM file
80+ #[ arg( long) ]
81+ nvram : Option < PathBuf > ,
7582}
7683
7784/// All our emulated hardware
@@ -99,7 +106,7 @@ static FRAMEBUFFER: Framebuffer<{ 640 * 480 }> = Framebuffer::new();
99106const SCALE_FACTOR : f32 = 2.0 ;
100107
101108/// When we booted up
102- static HARDWARE : std :: sync :: Mutex < Option < Hardware > > = std :: sync :: Mutex :: new ( None ) ;
109+ static HARDWARE : Mutex < Option < Hardware > > = Mutex :: new ( None ) ;
103110
104111/// The functions we export to the OS
105112static BIOS_API : common:: Api = common:: Api {
@@ -673,8 +680,11 @@ static PALETTE: [AtomicU32; 256] = [
673680
674681static VIDEO_MODE : AtomicU8 = AtomicU8 :: new ( 0 ) ;
675682
676- static EV_QUEUE : std:: sync:: Mutex < Option < std:: sync:: mpsc:: Receiver < AppEvent > > > =
677- std:: sync:: Mutex :: new ( None ) ;
683+ /// HID events come from here
684+ static EV_QUEUE : Mutex < Option < mpsc:: Receiver < AppEvent > > > = Mutex :: new ( None ) ;
685+
686+ /// Where the OS config is read from or written to.
687+ static CONFIG_FILE_PATH : Mutex < Option < PathBuf > > = Mutex :: new ( None ) ;
678688
679689// ===========================================================================
680690// Macros
@@ -722,15 +732,14 @@ fn main() {
722732 }
723733
724734 // Process args
725- let mut lib = None ;
726- for arg in std :: env :: args ( ) {
727- if let Some ( os_path ) = arg . strip_prefix ( "--os=" ) {
728- info ! ( "Loading OS from {:?}" , os_path ) ;
729- lib = unsafe { Some ( libloading :: Library :: new ( os_path ) . expect ( "library to load" ) ) } ;
730- println ! ( "Loaded!" ) ;
731- }
735+ info ! ( "Loading OS from: {}" , args . os . display ( ) ) ;
736+ let lib = unsafe { libloading :: Library :: new ( args. os ) . expect ( "library to load" ) } ;
737+ println ! ( "Loaded!" ) ;
738+
739+ if let Some ( config_path ) = args . nvram {
740+ info ! ( "Loading OS config from: {}" , config_path . display ( ) ) ;
741+ * CONFIG_FILE_PATH . lock ( ) . unwrap ( ) = Some ( config_path ) ;
732742 }
733- let lib = lib. expect ( "Fetching --os=filename from args" ) ;
734743
735744 // Make a window
736745 let mut engine = Engine :: builder ( )
@@ -740,7 +749,7 @@ fn main() {
740749 . target_frame_rate ( 60 )
741750 . build ( )
742751 . unwrap ( ) ;
743- let ( sender, receiver) = std :: sync :: mpsc:: channel ( ) ;
752+ let ( sender, receiver) = mpsc:: channel ( ) ;
744753 let mut app = MyApp {
745754 mode : unsafe { common:: video:: Mode :: from_u8 ( 0 ) } ,
746755 font8x16 : Vec :: new ( ) ,
@@ -883,17 +892,43 @@ extern "C" fn time_clock_set(time: common::Time) {
883892/// Configuration data is, to the BIOS, just a block of bytes of a given
884893/// length. How it stores them is up to the BIOS - it could be EEPROM, or
885894/// battery-backed SRAM.
886- extern "C" fn configuration_get ( _buffer : common:: FfiBuffer ) -> common:: ApiResult < usize > {
887- debug ! ( "configuration_get()" ) ;
888- Err ( common:: Error :: Unimplemented ) . into ( )
895+ extern "C" fn configuration_get ( mut os_buffer : common:: FfiBuffer ) -> common:: ApiResult < usize > {
896+ let file_path = CONFIG_FILE_PATH . lock ( ) . unwrap ( ) . clone ( ) ;
897+ let Some ( os_buffer) = os_buffer. as_mut_slice ( ) else {
898+ return common:: ApiResult :: Err ( common:: Error :: DeviceError ( 0 ) ) ;
899+ } ;
900+ match file_path. as_ref ( ) {
901+ Some ( path) => match std:: fs:: read ( path) {
902+ Ok ( read_data) => {
903+ for ( src, dest) in read_data. iter ( ) . zip ( os_buffer. iter_mut ( ) ) {
904+ * dest = * src;
905+ }
906+ common:: ApiResult :: Ok ( read_data. len ( ) )
907+ }
908+ Err ( _e) => {
909+ println ! ( "Failed to get config from {:?}" , path) ;
910+ common:: ApiResult :: Err ( common:: Error :: DeviceError ( 0 ) )
911+ }
912+ } ,
913+ None => common:: ApiResult :: Err ( common:: Error :: Unimplemented ) ,
914+ }
889915}
890916
891917/// Set the configuration data block.
892918///
893919/// See `configuration_get`.
894- extern "C" fn configuration_set ( _buffer : common:: FfiByteSlice ) -> common:: ApiResult < ( ) > {
895- debug ! ( "configuration_set()" ) ;
896- Err ( common:: Error :: Unimplemented ) . into ( )
920+ extern "C" fn configuration_set ( buffer : common:: FfiByteSlice ) -> common:: ApiResult < ( ) > {
921+ let file_path = CONFIG_FILE_PATH . lock ( ) . unwrap ( ) . clone ( ) ;
922+ match file_path. as_ref ( ) {
923+ Some ( path) => match std:: fs:: write ( path, buffer. as_slice ( ) ) {
924+ Ok ( _) => common:: ApiResult :: Ok ( ( ) ) ,
925+ Err ( _e) => {
926+ println ! ( "Failed to write config to {:?}" , path) ;
927+ common:: ApiResult :: Err ( common:: Error :: DeviceError ( 0 ) )
928+ }
929+ } ,
930+ None => common:: ApiResult :: Err ( common:: Error :: Unimplemented ) ,
931+ }
897932}
898933
899934/// Does this Neotron BIOS support this video mode?
0 commit comments