From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from ma1-aaemail-dr-lapp01.apple.com (ma1-aaemail-dr-lapp01.apple.com [17.171.2.60]) by mx.groups.io with SMTP id smtpd.web11.24430.1655421662344069967 for ; Thu, 16 Jun 2022 16:21:02 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@apple.com header.s=20180706 header.b=L9dAWsNT; spf=pass (domain: apple.com, ip: 17.171.2.60, mailfrom: afish@apple.com) Received: from pps.filterd (ma1-aaemail-dr-lapp01.apple.com [127.0.0.1]) by ma1-aaemail-dr-lapp01.apple.com (8.16.0.42/8.16.0.42) with SMTP id 25GNEBdf013142; Thu, 16 Jun 2022 16:21:01 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=apple.com; h=from : content-type : mime-version : subject : date : references : to : in-reply-to : message-id; s=20180706; bh=vBRTj6q6LCZDAIvbYp6S1QALHkJF9gH/EKYxWWmpmEs=; b=L9dAWsNTJpiQnOnA/RcCes9M/EojnXSUbTscE9En/ugo6dVFf8KiN+V3oE/BpOkPY8IP gE7/BOzqkj49SgMniCHUIwIZYS3Ea0xXux7L1bMCTs/XZTZDio4vqYhpnUJi9FVgYdN6 QdsIRUnNXiOSlR42kizM8sRtf2xhGV3Z8UBuSGzPY83b8Hu5D3sCuml5jGyLUf0Yvs0J cZkv4Y9DFI0MGfsdeuqXd3mJxoy0VgU0iHZJDsw4WV9UwZTPonYZF+fl3ktXVIdVjeQC VSDVmsw5IM+q/13eDst9eJVsJKV1ipMWHKk4WE5UERGMWtr3IGTMSdeIP7/T//bzeQ3v dA== Received: from rn-mailsvcp-mta-lapp02.rno.apple.com (rn-mailsvcp-mta-lapp02.rno.apple.com [10.225.203.150]) by ma1-aaemail-dr-lapp01.apple.com with ESMTP id 3gmsq41125-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Thu, 16 Jun 2022 16:21:01 -0700 Received: from rn-mailsvcp-mmp-lapp03.rno.apple.com (rn-mailsvcp-mmp-lapp03.rno.apple.com [17.179.253.16]) by rn-mailsvcp-mta-lapp02.rno.apple.com (Oracle Communications Messaging Server 8.1.0.18.20220407 64bit (built Apr 7 2022)) with ESMTPS id <0RDL00RJZFJ0QL10@rn-mailsvcp-mta-lapp02.rno.apple.com>; Thu, 16 Jun 2022 16:21:00 -0700 (PDT) Received: from process_milters-daemon.rn-mailsvcp-mmp-lapp03.rno.apple.com by rn-mailsvcp-mmp-lapp03.rno.apple.com (Oracle Communications Messaging Server 8.1.0.18.20220407 64bit (built Apr 7 2022)) id <0RDL00000ETXYG00@rn-mailsvcp-mmp-lapp03.rno.apple.com>; Thu, 16 Jun 2022 16:21:00 -0700 (PDT) X-Va-A: X-Va-T-CD: c365ff6c1366ae51b74a8a4e717d3d9d X-Va-E-CD: 07ba2202c586c806bd3aca93ad666991 X-Va-R-CD: 2cd2a22f053b06b4740d8d347a76b2c3 X-Va-CD: 0 X-Va-ID: c1bba1b9-5e23-40a4-95d9-6f8b8cfcaf82 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.517,18.0.883 definitions=2022-06-16_16:2022-06-16,2022-06-16 signatures=0 Received: from smtpclient.apple (unknown [17.235.40.218]) by rn-mailsvcp-mmp-lapp03.rno.apple.com (Oracle Communications Messaging Server 8.1.0.18.20220407 64bit (built Apr 7 2022)) with ESMTPSA id <0RDL00ESQF43MJ00@rn-mailsvcp-mmp-lapp03.rno.apple.com>; Thu, 16 Jun 2022 16:12:04 -0700 (PDT) From: "Andrew Fish" MIME-version: 1.0 (Mac OS X Mail 15.0 \(3693.20.0.1.32\)) Subject: Re: [edk2-devel] Does edk2 also link to crt0-efi like GNU-EFI * Date: Thu, 16 Jun 2022 16:12:03 -0700 References: <4410FE99-43C7-4331-AB96-42ADB294AE30@apple.com> To: devel@edk2.groups.io, ayushdevel1325@gmail.com In-reply-to: Message-id: <57AF5203-22DB-49C8-987B-A889FA36CE03@apple.com> X-Mailer: Apple Mail (2.3693.20.0.1.32) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.517,18.0.883 definitions=2022-06-16_16:2022-06-16,2022-06-16 signatures=0 Content-type: multipart/alternative; boundary="Apple-Mail=_8AF8E525-F13F-4247-AEEC-8B0C80034F6F" --Apple-Mail=_8AF8E525-F13F-4247-AEEC-8B0C80034F6F Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On Jun 16, 2022, at 1:17 PM, Ayush Singh wrote= : >=20 > Thanks for the great answer. After some discussion in the zulip [1], I > have some approaches that I will try first. >=20 > 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. >=20 > 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. >=20 For the C builds the tools_def.txt file uses $(IMAGE_ENTRY_POINT). The bui= ld maps that over to the _ModelEntryPoint label I mentioned. It would proba= bly be good to sue the same symbol.=20 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 >=20 > In UEFI, I would have to do something like this: efi_main -> rust > lang_start -> rust lang_start_internal -> rust main >=20 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 _ModelE= ntryPoint. I=E2=80=99m not 100% clear on all the dependencies but the big picture is f= or C edk2 injects code between the entry point and the main function. I thi= nk you will want that in your Rust world. The other thing you need to manage is the entry point hands-off the only w= ay to bind to all the EFI Services so that needs to make it into your Rust = world.=20 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 ImageHan= dle lets them get access to args and info on how the driver/app was loaded.= =20 We have different flavors of these entry point libs as the handoff, and som= etimes entry exit behavior are different: $ git grep 'EntryPoint|' -- \*.inf | grep LIBRARY_CLASS MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf:18: LIBRARY_CLASS = =3D DxeCoreEntryPoint|DXE_CORE MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf:18: LIBRARY_CLASS = =3D PeiCoreEntryPoint|PEI_CORE MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf:18: LIBRARY_CLASS = =3D PeimEntryPoint|PEIM MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.in= f:21: LIBRARY_CLASS =3D StandaloneMmDriverEntryPoint|MM_S= TANDALONE MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf:18: = LIBRARY_CLASS =3D UefiApplicationEntryPoint|UEFI_APPLICAT= ION MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf:18: LIBRARY_C= LASS =3D UefiDriverEntryPoint|DXE_DRIVER DXE_RUNTIME_DRIVE= R UEFI_DRIVER SMM_CORE DXE_SMM_DRIVER StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoi= nt.inf:18: LIBRARY_CLASS =3D StandaloneMmCoreEntryPoint|M= M_CORE_STANDALONE I think what this means from a practical point after reading your Rust thre= ad is: 1) Have some custom code, per driver type, to maybe convert the EFI/PEI/edk= 2 define entry point arguments maybe into standard Rust args.=20 argc =3D 2 argv[0] =3D ImageHandle argv[1] =3D *SystemTable 2) Then you can call the common Rust init flow from your link.=20 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 ge= nerated lib constructor functions, call the auto generated entry point func= tion that calls the function in the users Rust code. Call the lib destructo= r. Also provide support for the Exit function.=20 You can kind of hard code bits to get started, but If you think about it th= is way I think it will be easier to layer in edk2 like build features as we= grow the Rust support.=20 You could get really fancy and pass the mode BASE/PEIM/DXE in argv[0], and = the args in args[1], =E2=80=A6. By doing that you might need small stubs th= at 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/UefiApplic= ationEntryPoint/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. >=20 > Ayush Singh >=20 > [1]: (https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2F= help/topic/Run.20a.20function.20before.20.60lang_start.60/near/286376012) >=20 > On Fri, Jun 17, 2022 at 12:06 AM Andrew Fish wrote: >>=20 >>=20 >>=20 >>> On Jun 16, 2022, at 7:20 AM, Ayush Singh wro= te: >>>=20 >>> Hello everyone, I wanted to ask if the edk2 build system also links to >>> crt0-efi, like GNU-EFI? >>>=20 >>> 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, >>>=20 >>=20 >> The general answer for edk2 is and library that a `CONSTRUCTOR =3D` stat= ement in its INF that lib constructor will get called when the Driver/App i= s started. >>=20 >> The actually entry point for a Driver/App is _ModuleEntryPoint(). The ty= pical 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 th= e build: ProcessLibraryConstructorList(), ProcessModuleEntryPointList(), an= d ProcessLibraryDestructorList(). The library constructor/destructors funct= ions call the lib constructor/destructors function based in the sequence o= f the dependency graph of the libraries that get pulled in. >>=20 >>> 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. >>>=20 >>=20 >> 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 autogene= rated to glue everything together. It manages gluing in the libs, abstracti= ng the PCD implementation, and adding C constants for EFI_GUID values. >>=20 >> Sorry I don=E2=80=99t know Rust yet. Is it possible to call C, EFIABI, f= rom Rust code? If yes maybe what you need is a Rust ModuleEntryPoint that c= an call the C library constructor and a C EFIABI entry function for your Ru= st. I=E2=80=99m not sure how you manage dealing with C includes in Rust? Wi= th C++ you can just decorate them. >>=20 >> 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 >>=20 >>> My blog post [1] shows how we currently use the `efi_main` function. >>>=20 >>> Yours sincerely, >>> Ayush Singh >>>=20 >>> [1]: (https://www.programmershideaway.xyz/post5/) >>>=20 >>>=20 >>=20 >> [1] https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiApp= licationEntryPoint/ApplicationEntryPoint.c >>=20 >> Thanks, >>=20 >> Andrew Fish >>=20 >>=20 >>>=20 >>>=20 >>>=20 >>=20 >=20 >=20 >=20 >=20 >=20 --Apple-Mail=_8AF8E525-F13F-4247-AEEC-8B0C80034F6F Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8

On Jun 16, 20= 22, at 1:17 PM, Ayush Singh <ayushdevel1325@gmail.com> wrote:

Thanks for the great = answer. After some discussion in the zulip [1], I
have some a= pproaches that I will try first.

As for callin= g 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 defi= ne 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 bui= ld maps that over to the _ModelEntryPoint label I mentioned. It would proba= bly 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 Ru= st, the control flow is somewhat like this: crt0 -> libc
m= ain -> 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_interna= l -> rust main


The edk2 way to do this seems to me is to creat= e an edk2 RustEntryPoint lib that models the edk2 *EntryPointLib [1]. The e= ntry point would be  _ModelEntryPoint.

=
I=E2=80=99m 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 &nb= sp;the only way to bind to all the EFI Services so that needs to make it in= to your Rust world. 

EFIAPIThe Apps need access to SystemTable to do just about anything. The ImageH= andle lets them get access to args and info on how the driver/app was loade= d. 

We have different flavors of t= hese entry point libs as the handoff, and sometimes entry exit behavior are= different:
$ git grep 'E= ntryPoint|' -- \*.inf | grep LIBRARY_CLASS
MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf:= 18:  LIBRARY_CLASS              &nb= sp;   =3D DxeCoreEntryPoint|DXE_CORE
MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf:1= 8:  LIBRARY_CLASS              &nbs= p;   =3D PeiCoreEntryPoint|PEI_CORE
MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf:18: = ; LIBRARY_CLASS                &nbs= p; =3D PeimEntryPoint|PEIM
MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPo= int.inf:21:  LIBRARY_CLASS            &n= bsp;     =3D StandaloneMmDriverEntryPoint|MM_STANDALONE
MdePkg/Library/UefiApplicationEn= tryPoint/UefiApplicationEntryPoint.inf:18:  LIBRARY_CLASS   =               =3D UefiApplicationEntryP= oint|UEFI_APPLICATION
M= dePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf:18:  LIBRA= RY_CLASS                  =3D = UefiDriverEntryPoint|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER SMM_CORE DXE= _SMM_DRIVER
StandaloneM= mPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf:18:&= nbsp; LIBRARY_CLASS                =   =3D 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/e= dk2 define entry point arguments maybe into standard Rust args. 
  argc =3D 2
  argv[0= ] =3D ImageHandle
  argv[1] =3D  *SystemTabl= e

2) Then you can= call the common Rust init flow from your link. 
=
3) rt_entry() is custom for edk2. It w= ould basically do the same things as the edk2 C *EntryPoint libs _ModuleEnt= ryPoint() functions. Call the auto generated lib constructor functions, cal= l the auto generated entry point function that calls the function in the us= ers Rust code. Call the lib destructor. Also provide support for the Exit f= unction. 

Yo= u 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 g= row the Rust support. 

You could get really fancy and pass the mode BASE/PEIM/DXE in ar= gv[0], and the args in args[1], =E2=80=A6. By doing that you might need sma= ll 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.
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 th= at happens before
`rust lang_start`. Still, I do have some id= ea now, so will see how it
goes.

Ayush Singh

[1]: (https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fh= elp/topic/Run.20a.20function.20before.20.60lang_start.60/near/286376012= )

On Fri, Jun 17, 2022 at 12:06 AM Andrew Fish= <afish@apple.com> = wrote:


On Jun 16,= 2022, at 7:20 AM, Ayush Singh <ayushdevel1325@gmail.com> wrote:

Hello everyone, I wanted to ask if the edk2 build system also link= s 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 wit= h
llvm backend but I am not sure how it is done in GCC and am= curious,


The gene= ral answer for edk2 is and library that a `CONSTRUCTOR =3D` statement in it= s INF that lib constructor will get called when the Driver/App is started.<= br class=3D"">
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 function= s that got generated by the build: ProcessLibraryConstructorList(), Process= ModuleEntryPointList(), and ProcessLibraryDestructorList(). The library con= structor/destructors functions call the lib  constructor/destructors f= unction 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_sta= rt` from it.
This way, the user will be able to call the norm= al `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 everythi= ng together. It manages gluing in the libs, abstracting the PCD implementat= ion, and adding C constants for EFI_GUID values.

Sorry I don=E2=80=99t know Rust yet. Is it possible to call C, EFIABI, f= rom Rust code? If yes maybe what you need is a Rust ModuleEntryPoint that c= an call the C library constructor and a C EFIABI entry function for your Ru= st. I=E2=80=99m not sure how you manage dealing with C includes in Rust? Wi= th 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` funct= ion.

Yours sincerely,
Ayush Sing= h

[1]: (https://www.programmershideaway.xyz/post5/)=



[1= ] https://github= .com/tianocore/edk2/blob/master/MdePkg/Library/UefiApplicationEntryPoint/Ap= plicationEntryPoint.c

Thanks,

Andrew Fish












--Apple-Mail=_8AF8E525-F13F-4247-AEEC-8B0C80034F6F--
EFI_STATUS
_ModuleEntry= Point (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *Syst= emTable
)