aboutsummaryrefslogtreecommitdiffstats
path: root/Lesson_01/README.md
blob: 2f7d3ce853eea4f6e7dfbeebf3b658464721c92e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
In last lesson we've built an app that was already included in the TianoCore sources.

Let's work our way through to our own app.
We will be working on UEFI app that can be run in UEFI shell.

Create directory for our app:
```
mkdir SimplestApp
```

Then create *.c source file for our app with the folowing content:
```
$ cat SimplestApp/SimplestApp.c

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  return EFI_SUCCESS;
}
```

Then we need to create edk2 app configuration file. This configuration in edk2 is represented in the *.inf format.
INF file can have several sections:
- Defines
- Sources
- Packages
- LibraryClasses
- Guids
- Ppis
- Protocols
- FeaturePcd
- Pcd
- ...

But right now for our minimal example we're interested in the 3 of those:
- Defines - this section contatins some basic module description. In this section:

BASE_NAME - our app name

FILE_GUID - as was said earlier UEFI uses GUID numbers for identification of the components. You could use free online GUID generator to get random GUID https://www.guidgenerator.com/ or simply use `uuidgen` command line utility:
```
$ uuidgen
e7218aab-998e-4d88-af9b-9573a5bf90ea
```
MODULE_TYPE - we want to build an application that can be run from the UEFI shell, so we use `UEFI_APPLICATION` here. UEFI application is like a simple program that you can run from shell. It is getting loaded to some memory address, executes and returns something, after that app memory would be freed again. For example other possible value here is UEFI_DRIVER - the difference is when you load a driver it keeps staying in memory even after its execution.
Other values are listed here: https://edk2-docs.gitbook.io/edk-ii-inf-specification/appendix_f_module_types

ENTRY_POINT - name of the main function in our *.c source file. As it was `UefiMain` this is the value that we write here.

- Sources - source files for our edk2 module
- LibraryClasses - we need to include `UefiApplicationEntryPoint` library class for our minimal example
- Packages - `MdePkg/MdePkg.dec` is edk2 package with basic UEFI services. It includes `UefiApplicationEntryPoint` that we need to compile our package.

vi SimplestApp/SimplestApp.inf
```
[Defines]
  INF_VERSION                    = 1.25
  BASE_NAME                      = SimplestApp
  FILE_GUID                      = 4a298956-fbe0-47fb-ae3a-2d5a0a959a26
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

[Sources]
  SimplestApp.c

[Packages]
  MdePkg/MdePkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
```
Full specification for the "Module Information (INF) File" can be found under https://edk2-docs.gitbook.io/edk-ii-inf-specification/

After the creation of the INF file we need to include our app to some package so we could build it.

We don't have our own package, so let's include it to `OvmfPkg/OvmfPkgX64.dsc` that we've compiled earlier.
Add a path to our app *.inf file in the components section.
```
 ################################################################################
 [Components]
+  SimplestApp/SimplestApp.inf
   OvmfPkg/ResetVector/ResetVector.inf

```

Then build OVMF:
```
build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
```

Our compiled app would be in a directory `Build/OvmfX64/RELEASE_GCC5/X64`:
```
$ ls -lh Build/OvmfX64/RELEASE_GCC5/X64/SimplestApp.efi
-rw-r--r-- 1 kostr kostr 832 Jun 13 10:14 Build/OvmfX64/RELEASE_GCC5/X64/SimplestApp.efi
```

Create a folder that we would populate to UEFI shell and copy our app into it:
```
mkdir ~/UEFI_disk
cp Build/OvmfX64/RELEASE_GCC5/X64/SimplestApp.efi ~/UEFI_disk
```

Now lets run OVMF with this folder included:
```
$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
                     -drive format=raw,file=fat:rw:~/UEFI_disk \
                     -nographic \
                     -net none
```

Hopefully you'll see something like this:
```
UEFI Interactive Shell v2.2
EDK II
UEFI v2.70 (EDK II, 0x00010000)
Mapping table
      FS0: Alias(s):HD0a1:;BLK1:
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Press ESC in 3 seconds to skip startup.nsh or any other key to continue.
```

As you can see we have new rows in our mapping table. Our app would be under `FS0`. Lets `mount` this filesystem and execute our app.
```
Shell> fs0:
FS0:\> SimplestApp.efi
FS0:\>
```