[edk2-devel] Does edk2 also link to crt0-efi like GNU-EFI *

Ayush Singh ayushdevel1325 at gmail.com
Fri Jun 17 05:42:17 UTC 2022


> The C we have is free standing so there is nothing that is set up for the
C language, other than libs the user asked for.

It is possible to have freestanding Rust as well, but the current goal of
the project is to make it possible to use the standard library for UEFI
applications. So, some setup is needed. If someone wants to use
freestanding Rust for UEFI, that is already quite possible.

> I’m not 100% clear on all the dependencies but the big picture is for C
edk2 injects code between the entry point and the main function. I think
you will want that in your Rust world.

Yes, that is exactly what I wish to do. But the code will be injected
before the `lang_start` function instead of just main. `lang_start`
basically is the actual entry point for Rust applications (I guess it is
like crt0 in a way since it is basically sets up Rust runtime)
. Instead of autogenerating this code though, I probably need to manually
write it.

> 1) Have some custom code, per driver type, to maybe convert the
EFI/PEI/edk2 define entry point arguments maybe into standard Rust args.
>  argc = 2
>  argv[0] = ImageHandle
>  argv[1] =  *SystemTable

This is possible. I was alternatively thinking of making SystemTable a
global static instead. As you said, Apps cannot do anything without the
SystemTable. similarly, the standard library cannot do much without having
access to the SystemTable.

> You could get really fancy and pass the mode BASE/PEIM/DXE in argv[0],
and the args in args[1], …. By doing that you might need small stubs that
are mode specific to capture the different entry point APIs, but all the
other lib infrastructure could be common. The little tiny entry stub libs
could depend on the common lib so the INF files would only need to specify
the entry point stub lib.

Currently, the entry point is defined by the `target.json` file. As such,
using a different entry point is as simple as using a different
`target.json` file to compile the project. As such, it can be taken care of
at the AutoGen stage instead of trying to put it into Rust itself. Or we
can just use Rust conditional compilation macros and just pass a feature
depending on which entry point we want to use.

The current focus isn't to get Rust integrated into edk2, but to make it
possible and actually worthwhile to even do the integration. The way we
currently use Rust in UEFI is not exactly great since the standard library
isn't available. There are raw pointers everywhere and a lot of unsafe code
is needed. It is mostly, just a slightly better C in this context, without
the amazing modules that edk2 and other projects have written in C.

Once that can be fixed, then we will start looking at the edk2 integration
(although that might be beyond the scope of the project)


On Fri, Jun 17, 2022 at 4:51 AM Andrew Fish <afish at apple.com> wrote:

>
>
> On Jun 16, 2022, at 1:17 PM, Ayush Singh <ayushdevel1325 at gmail.com> wrote:
>
> Thanks for the great answer. After some discussion in the zulip [1], I
> have some approaches that I will try first.
>
> As for calling C, EFIABI from Rust, yes, it is quite well supported.
> Rust also has a specific EFIABI now, since some EFI platforms don't
> use C calling conventions.
>
> As for the entry point, llvm has an `-entry:efi_main` that can be used
> to define the entry function for UEFI targets. I just was not sure I
> could integrate it with the actual `main()` function.
>
>
> For the C builds the tools_def.txt file uses  $(IMAGE_ENTRY_POINT). The
> build maps that over to the _ModelEntryPoint label I mentioned. It would
> probably be good to sue the same symbol.
>
> The C we have is free standing so there is nothing that is setup for the C
> language, other that libs the user asked for.
>
> In normal Rust, the control flow is somewhat like this: crt0 -> libc
> main -> rust lang_start -> rust lang_start_internal -> rust main
>
> In UEFI, I would have to do something like this: efi_main -> rust
> lang_start -> rust lang_start_internal -> rust main
>
>
> The edk2 way to do this seems to me is to create an edk2 RustEntryPoint
> lib that models the edk2 *EntryPointLib [1]. The entry point would be
>  _ModelEntryPoint.
>
> I’m not 100% clear on all the dependencies but the big picture is for C
> edk2 injects code between the entry point and the main function. I think
> you will want that in your Rust world.
>
> The other thing you need to manage is the entry point hands-off  the only
> way to bind to all the EFI Services so that needs to make it into your Rust
> world.
>
> EFI_STATUS
> EFIAPI
> _ModuleEntryPoint (
> IN EFI_HANDLE ImageHandle,
> IN EFI_SYSTEM_TABLE *SystemTable
> )
> The Apps need access to SystemTable to do just about anything. The
> ImageHandle lets them get access to args and info on how the driver/app was
> loaded.
>
> We have different flavors of these entry point libs as the handoff, and
> sometimes entry exit behavior are different:
> $ git grep 'EntryPoint|' -- \*.inf | grep LIBRARY_CLASS
> MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf:18:  LIBRARY_CLASS
>                 = DxeCoreEntryPoint|DXE_CORE
> MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf:18:  LIBRARY_CLASS
>                 = PeiCoreEntryPoint|PEI_CORE
> MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf:18:  LIBRARY_CLASS
>           = PeimEntryPoint|PEIM
> MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf:21:
> LIBRARY_CLASS                  = StandaloneMmDriverEntryPoint|MM_STANDALONE
> MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf:18:
> LIBRARY_CLASS                  = UefiApplicationEntryPoint|UEFI_APPLICATION
> MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf:18:
> LIBRARY_CLASS                  = UefiDriverEntryPoint|DXE_DRIVER
> DXE_RUNTIME_DRIVER UEFI_DRIVER SMM_CORE DXE_SMM_DRIVER
> StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf:18:
> LIBRARY_CLASS                  =
> StandaloneMmCoreEntryPoint|MM_CORE_STANDALONE
>
> I think what this means from a practical point after reading your Rust
> thread is:
> 1) Have some custom code, per driver type, to maybe convert the
> EFI/PEI/edk2 define entry point arguments maybe into standard Rust args.
>   argc = 2
>   argv[0] = ImageHandle
>   argv[1] =  *SystemTable
>
> 2) Then you can call the common Rust init flow from your link.
>
> 3) rt_entry() is custom for edk2. It would basically do the same things as
> the edk2 C *EntryPoint libs _ModuleEntryPoint() functions. Call the auto
> generated lib constructor functions, call the auto generated entry point
> function that calls the function in the users Rust code. Call the lib
> destructor. Also provide support for the Exit function.
>
> You can kind of hard code bits to get started, but If you think about it
> this way I think it will be easier to layer in edk2 like build features as
> we grow the Rust support.
>
> You could get really fancy and pass the mode BASE/PEIM/DXE in argv[0], and
> the args in args[1], …. By doing that you might need small stubs that are
> mode specific to capture the different entry point APIs, but all the other
> lib infrastructure could be common. The little tiny entry stub libs could
> depend on the common lib so the INF files would only need to specify the
> entry point stub lib.
>
> [1]
> https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiApplicationEntryPoint/ApplicationEntryPoint.c
>
> Thanks,
>
> Andrew Fish
>
> The problem was that I couldn't find a way to go from `efi_main ->
> rust lang_start` earlier. After all, it is such a low-level detail
> that there is almost no documentation for anything that happens before
> `rust lang_start`. Still, I do have some idea now, so will see how it
> goes.
>
> Ayush Singh
>
> [1]: (
> https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Run.20a.20function.20before.20.60lang_start.60/near/286376012
> )
>
> On Fri, Jun 17, 2022 at 12:06 AM Andrew Fish <afish at apple.com> wrote:
>
>
>
>
> On Jun 16, 2022, at 7:20 AM, Ayush Singh <ayushdevel1325 at gmail.com> wrote:
>
> Hello everyone, I wanted to ask if the edk2 build system also links to
> crt0-efi, like GNU-EFI?
>
> If yes, I would also like to see how that is actually implemented. If
> not, how does edk2 support custom entry functions? It is possible with
> llvm backend but I am not sure how it is done in GCC and am curious,
>
>
> The general answer for edk2 is and library that a `CONSTRUCTOR =`
> statement in its INF that lib constructor will get called when the
> Driver/App is started.
>
> The actually entry point for a Driver/App is _ModuleEntryPoint(). The
> typical way it is done is this is implemented in a phase specific
> library[1]. This phase specific basically calls 3 C functions that got
> generated by the build: ProcessLibraryConstructorList(),
> ProcessModuleEntryPointList(), and ProcessLibraryDestructorList(). The
> library constructor/destructors functions call the lib
>  constructor/destructors function based in the sequence of the dependency
> graph of the libraries that get pulled in.
>
> Currently, rust does not support the custom implementation of
> `lang_start` (which is started by crt0 in most platforms), so I was
> trying to find ways to be able to use custom crt0 which sets up
> `SystemTable` and `SystemHandler` and start the `lang_start` from it.
> This way, the user will be able to call the normal `main` function
> rather than using the `no_main` feature.
>
>
> If you look in the build output of an edk2 C driver/app you will see an
> AutoGen.h and AutoGen.c file. This was the C code the build system
> autogenerated to glue everything together. It manages gluing in the libs,
> abstracting the PCD implementation, and adding C constants for EFI_GUID
> values.
>
> Sorry I don’t know Rust yet. Is it possible to call C, EFIABI, from Rust
> code? If yes maybe what you need is a Rust ModuleEntryPoint that can call
> the C library constructor and a C EFIABI entry function for your Rust. I’m
> not sure how you manage dealing with C includes in Rust? With C++ you can
> just decorate them.
>
> I guess the other 100% Rust option is to know the INF is building Rust
> (INF has Code.rs files) and build Rust (or Rust compatible) AutoGen
>
> My blog post [1] shows how we currently use the `efi_main` function.
>
> Yours sincerely,
> Ayush Singh
>
> [1]: (https://www.programmershideaway.xyz/post5/)
>
>
>
> [1]
> https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiApplicationEntryPoint/ApplicationEntryPoint.c
>
> Thanks,
>
> Andrew Fish
>
>
>
>
>
>
>
>
> 
>
>
>
>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#90570): https://edk2.groups.io/g/devel/message/90570
Mute This Topic: https://groups.io/mt/91811487/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/edk2-devel-archive/attachments/20220617/3d94bd9b/attachment-0001.htm>


More information about the edk2-devel-archive mailing list