I was studying about bootloaders when exactly came upon the term UEFI. I can understand some things about UEFI. But still, In what mode(Real,Protected,Long) does a system with UEFI start? If normal boot loaders cant work with UEFI, Then what is the alternate of boot loader while dealing with UEFI? And do I need any other programming to create one, than assembly?
5 Answers
UEFI firmware runs in 64 bit long mode for 64 bit platforms and flat mode for 32 bit platforms; Unlike BIOS, UEFI features its own architecture, independent of the CPU, and its own device drivers. UEFI can mount partitions and read certain file systems.
When an x86 computer equipped with UEFI, the interface searches the system storage for a partition labeled with a specific globally unique identifier (GUID) that marks it as the EFI System Partition (ESP). BTW Windows doesn't mount this partition and you cannot see it in the OS. But there is a trick, you simply change the partition type (using HexWorkshop) in VBR to regular FAT32 code and it will be mounted into the OS.
This partition contains applications compiled for the EFI architecture. In general you don't have to deal with assembler to write a UEFI application/loader, it's just a regular C code. By the default it is located at "EFI/BOOT/BOOTX64.EFI". When a bootloader is selected, manually or automatically, UEFI reads it into the memory and yields control of the boot process to it.

- 942
- 1
- 6
- 17
-
I heard that "CPUs start in 16bit mode. UEFI runs in 32bit or 64bit. " So in that case what runs before the UEFI? – barlop Jun 19 '19 at 14:53
-
@barlop bootloader , usually it’s quite primitive piece of software that might not even use 32 bit memory addresses – Alex D Jun 27 '19 at 00:34
-
4from what I understand, the UEFI starts in 16bit https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm#L52 and here is where it transitions from 16bit real mode to 32bit protected mode https://github.com/tianocore/edk2/blob/master/IntelFsp2Pkg/FspSecCore/SecMain.c#L52 – barlop Jun 27 '19 at 14:06
-
1also when I asked "what runs before the UEFI? " you said "bootloader". But the bootloader is not before the UEFI !! Grub is a bootloader, it runs after the UEFI . (perhaps bootloader is an ambiguous term in some way) – barlop Jun 27 '19 at 14:08
-
@barlop yes you're right, bootloader, in this regard, is a bit ambiguous. But grab is a very high-level bootloader, I was talking about the code inside flash nonvolatile memory chip soldered on the motherboard, code that actually does hardware initialization, like setting up MMU, virtual memory controllers, any external peripherals, and who knows what else... – Alex D Jun 28 '19 at 23:22
-
5@barlop: the first instruction that executes after power-up is fetched from a physical address hard-wired into the CPU (the reset vector). The CPU is in "unreal" mode at this point, with the CS segment base outside of the low 1MiB, but otherwise the same as 16-bit real mode. The system designer makes sure that address is mapped to a flash ROM. That code will eventually switch to 64-bit mode before reading anything from disk. But before that it has to configure the DRAM controllers and stuff like that! It will usually be using cache-as-RAM (no fill) mode for some of that time... – Peter Cordes May 03 '20 at 02:26
-
@Alex could you help me on this topic https://stackoverflow.com/questions/66949166/how-to-perform-some-security-verification-before-booting-operating-system – hamed Apr 05 '21 at 12:11
-
On linux, you can simply find the ESP (EFI System Partition) with `fdisk -l`. On my box it is `/dev/nvme0n1p1`. And then mount it as usual `sudo mount /dev/nvme0n1p1 ~/esp`. And then you can check the content within `~/esp`. – smwikipedia Nov 19 '22 at 09:22
In the following, some sentences are a copy, amalgamation and wording improvement of the best sources I've seen, and then I improve on and correct their unknowns / errors by using my own hardware case study.
Boot Guard
Intel Boot Guard is a technology introduced by Intel in the 4th Intel Core generation (Haswell) to verify the boot process. This is accomplished by flashing the public key of the BIOS signature into the field programmable fuses (FPFs), a one-time programmable memory inside Intel ME (in the PCH), during the manufacturing process; in this way it has the public key of the BIOS and it can verify the correct signature during every subsequent boot. Once enabled by the manufacturer, Intel Boot Guard can't be disabled anymore.
Boot Guard has two separate modes, according to Intel. Typical PC OEMs configure it to “Verified Boot” mode. The PC manufacturer fuses their public key into the hardware itself. If the UEFI firmware isn’t signed by the OEM—i.e., created by the OEM—the computer will halt and refuse to boot. That’s why you can’t modify the UEFI firmware. There’s also a second option: “Measured Boot” mode, where the hardware uses Intel TXT to secure stores information about the boot process (in a trusted platform module (TPM)) or Intel Platform Trust Technology (PTT) with the aid of SMX. The operating system could then examine this information, and—if there was a problem—present an error to the user.
Secure Boot
When enabled and fully configured, Secure Boot helps a computer resist attacks and infection from malware. Secure Boot detects tampering with boot loaders, key operating system files, and unauthorized option ROMs by validating their digital signatures. Detections are blocked from running before they can attack or infect the system. UEFI Secure Boot assumes the OEM platform firmware is a Trusted Computing Base (TCB) (i.e. that it's been initialised with BootGuard technologies and trusts it implicitly).
Verified Boot Process
Pre-UEFI stage
When the OEM receives the PCH, the ME is still in "Manufacturing Mode" and runs a special part of the firmware that will copy the "OEM Public Key Hash" and "Boot Guard Profile Configuration" policy values from its section of the flash ROM into the field programable fuses (FPFs) so that they are permanent and unchangable. It then sets a fuse to indicate that it has exited from manufacturing mode so that this portion of the firmware will not run again. These values can be adjusted in the flash image with the Intel Flash Image Tool (FITC), but unless you have a way to force the ME into manufacturing mode then the values in the flash image are ignored.
The Bootguard profile is as follows:
Protect BIOS Environment Enabled: if set, this possibly means that the ACM will copy the IBB segments into the CPU cache so that it runs in a cache-as-RAM (CAR) mode and has all DMA disabled to prevent devices from being able to modify it.
As soon as power is available, the ME CPU boots up from its on-die boot ROM, checks some straps and fuses to determine its configuration, and typically then copies the flash partition table (FPT) from the ME region of the SPI flash (which is typically below the BIOS region) to its on-die SRAM. It locates the ME region by using the flash descriptor at the lowest address of the SPI flash.
The boot ROM locates the FTPR partition using the FPT and copies it from the SPI flash into the on-die SRAM. It then checks that the SHA-1 hash of the key stored in the partition manifest matches the one in its on-die ROM and validates the RSA signature on the rest of the partition manifest. The partition table contains hashes of each of the modules in the partition, allowing the modules to be validated after they are copied into the on-die SRAM for execution.
When the ME boots the x86 CPU, possibly in bup.met
. The BIST and then the BSP MP Initialisation algorithm takes place. The legacy reset vector at CS:FFF0 (where CS is 0xF000 and the segment descriptor cache contains the base 0xFFFF0000) is no longer the first instruction the x86 CPU executes on reset. Instead, on-die microcode fetches the FIT pointer at 0xFFFFFFC0 (using 0xF000:FFC0 with the unreal mode segment descriptor hack – because this is the initial state of the registers), which points to the FIT table somewhere in the SPI flash BIOS region.

This image shows the 16 byte FIT entries with their modes 3 bytes from the end.
#pragma pack (1)
typedef struct {
UINT64 Address;
UINT8 Size[3];
UINT8 Rsvd;
UINT16 Version;
UINT8 Type:7;
UINT8 C_V:1;
UINT8 Checksum;
} FIRMWARE_INTERFACE_TABLE_ENTRY;

On my system, there is a FIT pointer at FFFFFFC0 to FFD90100

The FIT table points to microcode updates, ACMs, the BootGuard Boot Policy Manifest (which contains an IBBS) and BootGuard Key manifest etc.
My FIT does not contain any 0x7 entries. Record Types 7 is used by legacy Intel® TXT FIT boot only and is not needed, if latter is not used.
The BootGuard Boot Policy (IBBM) contains:
Intel BootGuard Boot Policy Manifest found at base FD3C00h
Tag: ACBP Version: 10h HeaderVersion: 01h
PMBPMVersion: 10h PBSVN: 00h ACMSVN: 02h NEMDataStack: 0010h
Initial Boot Block Element found at base FD3C28h
Tag: IBBS Version: 10h Unknown: 0Fh
Flags: 00000000h IbbMchBar: FED10000h VtdBar: 00000000h
PmrlBase: FED90000h PmrlLimit: 00000000h EntryPoint: 00100000h
Post IBB Hash:
0000000000000000000000000000000000000000000000000000000000000000
IBB Digest:
B9CCC06B77AEACC51768981D07CBE9E43D34DB6795752C4B998312241B26F874
IBB Segments:
Flags: 0000h Address: FFE10000h Size: 001C3C00h
Flags: 0000h Address: FFFD4C00h Size: 00000080h
Flags: 0000h Address: FFFD5C80h Size: 0000A380h
Flags: 0000h Address: FFFE8000h Size: 00018000h
Boot Policy Signature Element found at base FD3CDDh
Tag: PMSG Version: 10h
Boot Policy RSA Public Key (Exponent: 10001h):
....
Boot Policy RSA Public Key Hash:
....
Boot Policy RSA Signature:
....
The Key Manifest contains:
Intel BootGuard Key Manifest (KEYM) found at base FD4C80h
Tag: KEYM Version: 10h KmVersion: 10h KmSvn: 00h KmId: 0Fh
Key Manifest RSA Public Key Hash:
...
Boot Policy RSA Public Key Hash:
...
Key Manifest RSA Public Key (Exponent: 10001h):
...
Key Manifest RSA Signature:
... //it does actually contain a signature, I just removed these for space
Cache as RAM (CAR) (aka. AC-RAM, No fill mode and No evict mode) is then set up by the microcode. The FIT is then searched for microcode updates that match the CPU ID. The current microcode copies them linearly from flash into L3 cache and decrypts with an on-die symmetric AES key, then validates with (on-die?) RSA key. It's likely that these microcode updates also contain the key hashes for the ACM. The microcode update is then applied by writing to the UCODE MSR and the CPU reads it out I assume through normal memory accesses. The FIT absolutely has to contain a microcode patch and it patches the microcode SRAM to complement the already existing microcode ROM. [1]
Next, the microcode goes back to the FIT to find the Startup ACM (aka BIOS or Bootguard ACM) and does an odd copy of it into L3 (looks like multiple hyperthreads are copying 4KB chunks? -- according to that source). The ACM contains an RSA public key; the microcode compares it against either an on-die key or one stored in the microcode update and halts the CPU if it does not match. The microcode then checks the signature on the ACM and again halts if it does not match.
The Startup ACM runs entirely out of L3. The ACM receives the OEM public key hash (the Key Hash that verifies the Key Manifest) and Bootguard Profile from the ME via MSR.
The ACM reads the BootGuard Key Manifest from the SPI flash (pointed to by the FIT and identified by __KEYM__
) into L3 and hashes the RSA public key stored in it. If it doesn't match the OEM public key hash or if the OEM public key signature on the Key Manifest or if the stored KmSvn isn't right, the ACM takes action based on the Bootguard Profile bits. If it does match, it locates the Bootguard Policy in the FIT (and identified by __ACBP__
) and copies it into L3. The ACM then computes the hash of the RSA public key in the Policy and compares it to the SHA256 hash stored in the Key Manifest. If that fails to match, or if the RSA signature on the Policy doesn't match, then the ACM again takes action based on the Profile settings.
The ACM uses the now validated Bootguard Policy structure to read the Initial Boot Block (IBB) segments into L3, hashing them as they are copied. If this computed hash doesn't match the "IBB Digest" in the Policy, the ACM takes action based on the Profile settings. The 4th IBB segment contains the reset vector, so it prevents that from being modified. It's unclear whether it leaves the CPU in CAR mode or whether it just leaves them cached in the L3 but without eviction disabled i.e. without CAR mode left enabled. SEC however needs to (disable) and set up a new CAR mode.
Taking a dump of physical memory using RwEverything, or downloading CSME System Tools for your ME version and then performing fptw64 -d -me -bios dump.bin
will dump the flash (and often you will only be able to dump the BIOS region and not the ME region). The dump is now analysable in UEFITool NE Alpha 58, and the FIT shows the EntryPoint of the ACM in the body. So if you right click, extract it and open it up in IDA as 32 bit, the entry point will be at 3BB1h + 18h = 3BC9h
3BC9 mov ax, ds
3BCC mov ss, ax
3BCF mov es, ax
3BD2 mov fs, ax
3BD5 mov gs, ax
3BD8 mov esp, ebp
3BDA add esp, 1000h
3BE0 mov eax, ebp
3BE2 add eax, 4C8h
3BE7 lidt fword ptr [eax]
3BEA push ebp
3BEB call sub_392A
3BF0 mov ebx, eax
3BF2 mov edx, 0
3BF7 mov eax, 3
3BFC getsec
The startup ACM is always the final ACM and it GETSEC[EXITAC]
s to the IBBS base + entry point address (0xFEE90000
, which falls in the first IBB) in the bootguard policy manifest, which appears to be in the ME region and presumably contains code to switch the CPU back to unreal mode and jump to the legacy reset vector in the 4th IBB segment. GETSEC
can only be executed in protected mode, so clearly the CPU is in protected mode in the startup ACM, so must be enabled by the microcode before entry. The legacy reset vector is at 0xFFFFFFF0, which on my system is a relative jump to FFFFFFF5 - 3BD = FFFFFC38, which is the SEC core entry point.
SEC
The SEC core is a Raw section from FFFFCA14 - FFFFCA17, a PE32 image from FFFFCA18 - FFFFFFBB, a raw section from FFFFFFBC - FFFFFFBF, and a raw section from FFFFFFC0-FFFFFFFF (which contains the reset vector).
The entry point of the PE32 Image in the SEC Core that is jumped to by the reset vector contains:
0x00: DB E3 fninit
0x02: 0F 6E C0 movd mm0, eax //move BIST value to mm0
0x05: 0F 31 rdtsc
0x07: 0F 6E EA movd mm5, edx
0x0a: 0F 6E F0 movd mm6, eax //save tsc
0x0d: 66 33 C0 xor eax, eax //clear eax
0x10: 8E C0 mov es, ax
0x12: 8C C8 mov ax, cs
0x14: 8E D8 mov ds, ax
0x16: B8 00 F0 mov ax, 0xf000
0x19: 8E C0 mov es, ax
0x1b: 67 26 A0 F0 FF 00 00 mov al, byte ptr es:[0xfff0]
0x22: 3C EA cmp al, 0xea
0x24: 74 0E je 0x34 //if ea is at ffff0h then jump to the 0xf000e05b check
0x26: BA F9 0C mov dx, 0xcf9
0x29: EC in al, dx //read port 0xcf9
0x2a: 3C 04 cmp al, 4
0x2c: 75 25 jne 0x53
0x2e: BA F9 0C mov dx, 0xcf9 //perform warm reset since if CPU only reset is issued not all MSRs are restored to their defaults
0x31: B0 06 mov al, 6
0x33: EE out dx, al
0x34: 67 66 26 A1 F1 FF 00 00 mov eax, dword ptr es:[0xfff1]
0x3c: 66 3D 5B E0 00 F0 cmp eax, 0xf000e05b
0x42: 75 0F jne 0x53 //if it isn't, move to notwarmstart
0x44: B9 1B 00 mov cx, 0x1b //if it is equal, read bsp bit from apic_base msr
0x47: 0F 32 rdmsr
0x49: F6 C4 01 test ah, 1
0x4c: 74 41 je 0x8f //if the and operation with 00000001b produces a zero result i.e. it's an AP then jump to cli, hlt
0x4e: EA F0 FF 00 F0 ljmp 0xf000:0xfff0 //if it's the BSP, exit unreal mode by far jumping to 0xffff0 which reloads the segment descriptor cache with a 0 base
notwarmstart:
0x53: B0 01 mov al, 1
0x55: E6 80 out 0x80, al //send 1 as a debug POST code
0x57: 66 BE 68 FF FF FF mov esi, 0xffffff68
0x5d: 66 2E 0F 01 14 lgdt cs:[si] //loads 32&16 GDT pointer (not 16&6, due to 66 prefix) at 16bit address fff68 in si into GDTR (base:ffffff28 limit:003f); will be accessing alias and not shadow ROM
//enter 16 bit protected mode//
0x62: 0F 20 C0 mov eax, cr0
0x65: 66 83 C8 03 or eax, 3 //Set PE bit (bit #0) & MP bit (bit #1)
0x69: 0F 22 C0 mov cr0, eax //Activate protected mode
0x6c: 0F 20 E0 mov eax, cr4
0x6f: 66 0D 00 06 00 00 or eax, 0x600 //Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
0x75: 0F 22 E0 mov cr4, eax
//set up selectors for 32 bit protected mode entry
0x78: B8 18 00 mov ax, 0x18 //segment descriptor at 0x18 in GDT is (raw): 00cf93000000ffff
0x7b: 8E D8 mov ds, ax
0x7d: 8E C0 mov es, ax
0x7f: 8E E0 mov fs, ax
0x81: 8E E8 mov gs, ax
0x83: 8E D0 mov ss, ax
0x85: 66 BE 6E FF FF FF mov esi, 0xffffff6e
0x8b: 66 2E FF 2C ljmp cs:[si] //transition to flat 32 bit protected mode and jump to address at 0x0:0xffffff6e aka. 0xffffff6e which is fffffcd8. CS contains 0 remember (it's the base that is 0xffff) so it will load the first entry. This address is also in the SEC Core PE32 Image
0x8f: FA cli
0x90: F4 hlt
.
.
.

- 4,129
- 1
- 32
- 42
-
According to this [source](https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/secure_boot_chain_in_uefi/intel_boot_guard), FPFs reside in the PCH, not the CPU. Another [source](https://link.springer.com/chapter/10.1007/978-1-4302-6572-6_6#Sec9) states: "Newer security and management engines shipped with select Intel platforms in and after 2013 support a feature called field programmable fuses". Since Intel ME resides in the PCH, this also seems to confirm that FPFs are located there. – wmjdgla Aug 29 '20 at 09:50
-
@wmjdgla they're in the PCH (or the CPU if the PCH is rolled into the CPU like it is on some of the newer laptop architectures). I'll get round to this answer one day. I got sidetracked – Lewis Kelsey Aug 29 '20 at 14:36
Here's a good answer to this question:
Other modern 64-bit machines have new EFI firmwares. These don't load a bootstrap program from sector #0 of a disc at all. They bootstrap by the EFI Boot Manager loading and running an EFI boot loader application. Such programs are run in protected mode. This is the EFI bootstrap process.
EFI firmwares in general switch to protected mode within a few instructions of exiting processor reset. Switching to protected mode is done early on in the so-called "SEC Phase" of EFI firmware initialization. Technically, 32-bit and greater x86 processors don't even start in real mode proper, but in what is colloquially known as unreal mode. (The initial segment descriptor for the CS register does not describe the conventional real mode mapping and is what makes this "unreal".)
As such, it could be said that those EFI systems never enter real mode proper at all, when bootstrapping natively to an EFI bootloader (i.e. when they don't employ a compatibility support module), since they switch from unreal mode directly to protected mode and stay in protected mode from then on.
-
1There is NO protected mode for UEFI! UEFI works in 64 bit long mode! Some platforms may use 32 bit flat mode. The terminology is wrong at first place that's why it confuses a lot of people. Back in the days everything that was not x86 mode was called protected mode. But that is not entirely correct. – Alex D Aug 27 '15 at 16:44
-
@Alex I did link you where UEFI starts in 16bit mode and moves to 32bit mode. You might seem to call that a boot loader of some sort, but the fact is that where it starts in 16bit mode is part of UEFI – barlop Jul 01 '19 at 15:13
-
4@barlop: I'd say that starting in 16-bit (un)real mode is part of x86 early booting. It isn't EFI / UEFI (or legacy BIOS) until the firmware is ready to load something from disk and provide a standardized config and boot API to the code that it loads. Before that the firmware has to get this specific system's memory controllers configured, and stuff like that, and that part is fully private and isn't governed by any standard. 16-bit isn't part of UEFI, so yes, a UEFI firmware has to have switched out of that mode before jumping to any code it loaded from disk, and provide that ABI. – Peter Cordes May 03 '20 at 02:32
When you asked "In what mode(Real,Protected,Long) does a system with UEFI start?", what do you mean? The processor starts executing in a mode that is similar to the mode of the 80386 of the past. But do you really care. Don't you really care about the mode of the processor when your OS loader code is given control? And you care about what services are provided to your OS loader code.
The environment is defined in the UEFI spec. Latest Versions of the UEFI Specifications
As for which language you use, assembly is good to start with. It's probably easier to use C or some other high level language after a bit.
Other background:
There are a lot of terms here that we are not always careful about using correctly.
The code that executes when the processor comes out of reset is system firmware that does a lot of initialization of various hardware in the system.
In the old days on a x86 PC system before the UEFI Forum existed, the system firmware was called BIOS. The BIOS in those days executed all of its initialization code, then loaded some code off of a floppy diskette or the hard drive and jumped into the code. The BIOS also provided some interfaces between the hardware and the operating system to help isolate the OS from hardware differences. Nothing was standardized though. The only standards were the OS and applications level software that used the BIOS interfaces.
If the OS and apps functioned correctly then the BIOS was considered correct. But you could only prove correctness by lack of failure. Thus new OSs or applications would work on one correct system yet fail on a different correct system.
Today we've tried to provide some actual standardization of those interfaces. They are defined by the UEFI Forum. Today I can prove that my system is correct according to meeting the UEFI specifications.
When people say things like the UEFI, they are usually referring to the actual system firmware installed on the system that is executed before the OS starts executing. But a lot of us still toss around these terms like we've spilled alphabet soup.
The boot loader is actually OS owned code that is loaded in memory by the system firmware and the system firmware gives control of the hardware to the boot loader. One could say that the end of the system firmware is the UEFI Boot Loader. Or you could just say BDS uses the system policy to find the OS. And you could still find someone that disagreed with the words.

- 21
- 2
-
1the term UEFI boot loader is not a good term. A boot loader e.g. GRUB, is not part of the UEFI.. It runs after the UEFI. There are boot loaders written for UEFI https://superuser.com/questions/1112090/what-is-a-uefi-bootloader – barlop Jun 30 '19 at 00:20
If you wish to know more about how UEFI works then the post UEFI boot: how does that actually work, then? by Adam Williamson is highly recommended.
He answers the questions you have and its a good read:
Now let’s look at how booting works on a UEFI system. Even if you don’t grasp the details of this post, grasp this: it is completely different. Completely and utterly different from how BIOS booting works. You cannot apply any of your understanding of BIOS booting to native UEFI booting. You cannot make a little tweak to a system designed for the world of BIOS booting and apply it to native UEFI booting. You need to understand that it is a completely different world.
The Wikipedia page Unified Extensible Firmware Interface is also a useful resource.

- 2,800
- 26
- 31