You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue is a tour of some scaffolding I wrote for being able to safely access a SystemTable<Boot> as a global variable. Incorporating this would make it possible to turn Logger::new into a safe call and eliminate any requirement to disable it before exiting boot services. Give this a look and let me know if you'd like me to turn it into a PR.
This code uses a couple nightly features but they're not especially needed:
Just like the Rc and Arc types in the standard library, the inc_refcnt helper method checks for overflow in order to be safe in the ridiculous case that code calls mem::forget a whole bunch in order to make it overflow without first running out of memory. This is the only use feature(core_intrinsics), so if this ever becomes the last blocker to being able to compile uefi on stable then just replace it with an infinite loop or whatnot, because it's just a stupid pathological case that never happens and nobody cares about.
We use relaxed memory ordering, because since we're single-threaded we don't really need an atomic at all and a Cell<usize> would be fine, but AtomicUsize provides more convenient methods.
fninc_refcnt(&self){let old = self.refcnt.fetch_add(1,Ordering::Relaxed);if old == usize::MAX{
core::intrinsics::abort()}}
The borrow method returns a Guard object which implements Deref and will decrement the reference count when dropped.
The stdin/stdout/stderr methods similarly return guard objects which implement DerefMut and whose Drop implementation clears the stdfoo_borrowed bit as well as decrementing the reference count. You can one stdin borrow, one stdout borrow, one stderr borrow, and N immutable borrows out all at once. This should be safe because these all operate on pairwise-disjoint sets of fields of the underlying SystemTable structure.
Another good thing to add if you merge this code would be a #[gentry] attribute macro, which you can put on a main function which takes no arguments. It would initialize GLOBAL_SYSTEM_TABLE as well as another global GLOBAL_IMAGE_HANDLE which would be a OnceCell<Handle>.
The text was updated successfully, but these errors were encountered:
This issue is a tour of some scaffolding I wrote for being able to safely access a
SystemTable<Boot>
as a global variable. Incorporating this would make it possible to turnLogger::new
into a safe call and eliminate any requirement to disable it before exiting boot services. Give this a look and let me know if you'd like me to turn it into a PR.This code uses a couple nightly features but they're not especially needed:
GlobalSystemTable
stores aSystemTable<Boot>
plus some bookkeeping entries for reference counting:We exploit the knowledge that the boot-services environment is single-threaded in order to implement
Sync
so we can keep it as a global.The first thing the EFI entry point should do is initialize it:
Just like the
Rc
andArc
types in the standard library, theinc_refcnt
helper method checks for overflow in order to be safe in the ridiculous case that code callsmem::forget
a whole bunch in order to make it overflow without first running out of memory. This is the only usefeature(core_intrinsics)
, so if this ever becomes the last blocker to being able to compileuefi
on stable then just replace it with an infinite loop or whatnot, because it's just a stupid pathological case that never happens and nobody cares about.We use relaxed memory ordering, because since we're single-threaded we don't really need an atomic at all and a
Cell<usize>
would be fine, butAtomicUsize
provides more convenient methods.The
borrow
method returns aGuard
object which implementsDeref
and will decrement the reference count when dropped.The
stdin
/stdout
/stderr
methods similarly return guard objects which implementDerefMut
and whose Drop implementation clears thestdfoo_borrowed
bit as well as decrementing the reference count. You can one stdin borrow, one stdout borrow, one stderr borrow, and N immutable borrows out all at once. This should be safe because these all operate on pairwise-disjoint sets of fields of the underlyingSystemTable
structure.The
deinit
method checks that the reference count is zero, and then deinitializes the global and hands back an ownedSystemTable<Boot>
.For completeness, here are the (unremarkable) implementations of
Guard
,IoGuard
, andGlobalSystemTableError
:Finally, as an example, here's how I used this code to implement a completely safe panic handler.
Logger
could be written the same way.Another good thing to add if you merge this code would be a
#[gentry]
attribute macro, which you can put on a main function which takes no arguments. It would initializeGLOBAL_SYSTEM_TABLE
as well as another globalGLOBAL_IMAGE_HANDLE
which would be aOnceCell<Handle>
.The text was updated successfully, but these errors were encountered: