@@ -23,6 +23,9 @@ mod vgaconsole;
2323/// The OS version string
2424const OS_VERSION : & str = concat ! ( "Neotron OS, version " , env!( "OS_VERSION" ) ) ;
2525
26+ /// Used to convert between POSIX epoch (for `chrono`) and Neotron epoch (for BIOS APIs).
27+ const SECONDS_BETWEEN_UNIX_AND_NEOTRON_EPOCH : i64 = 946684800 ;
28+
2629/// We store the API object supplied by the BIOS here
2730static API : Api = Api :: new ( ) ;
2831
@@ -72,25 +75,55 @@ macro_rules! println {
7275// Local types
7376// ===========================================================================
7477
78+ /// Represents the API supplied by the BIOS
79+ struct Api {
80+ bios : core:: sync:: atomic:: AtomicPtr < bios:: Api > ,
81+ }
82+
7583impl Api {
84+ /// Create a new object with a null pointer for the BIOS API.
7685 const fn new ( ) -> Api {
7786 Api {
7887 bios : core:: sync:: atomic:: AtomicPtr :: new ( core:: ptr:: null_mut ( ) ) ,
7988 }
8089 }
8190
82- fn store ( & self , api : * const bios:: Api ) {
91+ /// Change the stored BIOS API pointer.
92+ ///
93+ /// The pointed-at object must have static lifetime.
94+ unsafe fn store ( & self , api : * const bios:: Api ) {
8395 self . bios
8496 . store ( api as * mut bios:: Api , core:: sync:: atomic:: Ordering :: SeqCst )
8597 }
8698
99+ /// Get the BIOS API as a reference.
100+ ///
101+ /// Will panic if the stored pointer is null.
87102 fn get ( & self ) -> & ' static bios:: Api {
88- unsafe { & * ( self . bios . load ( core:: sync:: atomic:: Ordering :: SeqCst ) as * const bios:: Api ) }
103+ let ptr = self . bios . load ( core:: sync:: atomic:: Ordering :: SeqCst ) as * const bios:: Api ;
104+ let api_ref = unsafe { ptr. as_ref ( ) } . expect ( "BIOS API should be non-null" ) ;
105+ api_ref
89106 }
90- }
91107
92- struct Api {
93- bios : core:: sync:: atomic:: AtomicPtr < bios:: Api > ,
108+ /// Get the current time
109+ fn get_time ( & self ) -> chrono:: NaiveDateTime {
110+ let api = self . get ( ) ;
111+ let bios_time = ( api. time_clock_get ) ( ) ;
112+ let secs = i64:: from ( bios_time. secs ) + SECONDS_BETWEEN_UNIX_AND_NEOTRON_EPOCH ;
113+ let nsecs = bios_time. nsecs ;
114+ chrono:: NaiveDateTime :: from_timestamp_opt ( secs, nsecs) . unwrap ( )
115+ }
116+
117+ /// Set the current time
118+ fn set_time ( & self , timestamp : chrono:: NaiveDateTime ) {
119+ let api = self . get ( ) ;
120+ let nanos = timestamp. timestamp_nanos ( ) ;
121+ let bios_time = bios:: Time {
122+ secs : ( ( nanos / 1_000_000_000 ) - SECONDS_BETWEEN_UNIX_AND_NEOTRON_EPOCH ) as u32 ,
123+ nsecs : ( nanos % 1_000_000_000 ) as u32 ,
124+ } ;
125+ ( api. time_clock_set ) ( bios_time) ;
126+ }
94127}
95128
96129/// Represents the serial port we can use as a text input/output device.
0 commit comments