1Operation
2=========
3
4Run the "zefi.py" script, passing a path to a built zephyr.elf file
5(NOT a "zephyr.strip" intended for grub/multiboot loading -- we need
6the symbol table) for the target as its sole argument.  It will emit a
7"zephyr.efi" file in the current directory.  Copy this to your target
8device's EFI boot partition via whatever means you like and run it
9from the EFI shell.
10
11Theory
12======
13
14This works by creating a "zephyr.efi" EFI binary containing a zephyr
15image extracted from a built zephyr.elf file.  EFI applications are
16relocatable, and cannot be placed at specific locations in memory.
17Instead, the stub code will copy the embedded zephyr sections to the
18appropriate locations at startup, clear any zero-filled (BSS, etc...)
19areas, then jump into the 64 bit entry point.
20
21Arguably this is needlessly inefficient, having to load the whole
22binary into memory and copy it vs. a bootloader like grub that will
23load it from the EFI boot filesystem into its correct location with no
24copies.  But then, the biggest Zephyr application binaries we have on
25any platform top out at 200kb or so, and grub is at minimum about 5x
26that size, and potentially MUCH more if you start enabling the default
27modules.
28
29Source Code & Linkage
30=====================
31
32The code and link environment here is non-obvious.  The simple rules
33are:
34
351. All code must live in a single C file
362. All symbols must be declared static
37
38And if you forget this and use a global by mistake, the build will
39work fine and then fail inexplicably at runtime with a garbage
40address.  The sole exception is the "efi_entry()" function, whose
41address is not generated at runtime by the C code here (it's address
42goes into the PE file header instead).
43
44The reason is that we're building an EFI Application Binary with a
45Linux toolchain.  EFI binaries are relocatable PE-COFF files --
46basically Windows DLLs.  But our compiler only generates code for ELF
47targets.
48
49These environments differ in the way they implement position
50independent code.  Non-static global variables and function addresses
51in ELF get found via GOT and PLT tables that are populated at load
52time by a system binary (ld-linux.so).  But there is no ld-linux.so in
53EFI firmware, and the EFI loader only knows how to fill in the PE
54relocation fields, which are a different data structure.
55
56So we can only rely on the C file's internal linkage, which is done
57via the x86_64 RIP-relative addressing mode and doesn't rely on any
58support from the environment.  But that only works for symbols that
59the compiler (not the linker) knows a-priori will never be in
60externally linked shared libraries.  Which is to say: only static
61symbols work.
62
63You might ask: why build a position-independent executable in the
64first place?  Why not just link to a specific address?  The PE-COFF
65format certainly allows that, and the UEFI specification doesn't
66clearly rule it out.  But my experience with real EFI loaders is that
67they ignore the preferred load address and will put the image at
68arbitrary locations in memory.  I couldn't make it work, basically.
69
70Bugs
71====
72
73No support for 32 bit EFI environments.  This would be a very tall
74order given the linker constraints described above (i386 doesn't have
75a IP-relative addressing mode, so we'd have to do some kind of
76relocation of our own).  Will probably never happen unless we move to
77a proper PE-COFF toolchain.
78
79There is no protection against colliding mappings.  We just assume
80that the EFI environment will load our image at an address that
81doesn't overlap with the target Zephyr memory.  In practice on the
82systems I've tried, EFI uses memory near the top of 32-bit-accessible
83physical memory, while Zephyr prefers to load into the bottom of RAM
84at 0x10000.  Even given collisions, this is probably tolerable, as we
85could control the Zephyr mapping addresses per-platform if needed to
86sneak around EFI areas.  But the Zephyr loader should at least detect
87the overlap and warn about it.
88
89It runs completely standalone, writing output to the current
90directory, and uses the (x86_64 linux) host toolchain right now, when
91it should be integrated with the Zephyr toolchain and build system.
92