aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_17/README.md
blob: 6dd3ed6412dbfbb693f457800ccbb92beb899299 (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
In the last lesson we've added our own boot option.

Let's boot it.

Type `exit` in the UEFI shell to go to the BIOS menu:
```
Shell> exit
```
Navigate to the `Boot Manager` window. Our `HelloWorld` option would be present here:
![Boot Manager](BootManager.png?raw=true "Boot manager")

If you'll try to boot it, app would print its strings and immediately return.

Let's fix it. Let's add wait for a key input from user in our app code.
To do it we will need `WaitForEvent` blocking function:

```
EFI_BOOT_SERVICES.WaitForEvent()

Summary
Stops execution until an event is signaled.

Prototype
typedef

EFI_STATUS
(EFIAPI *EFI_WAIT_FOR_EVENT) (
 IN UINTN NumberOfEvents,
 IN EFI_EVENT *Event,
 OUT UINTN *Index
);

Parameters
NumberOfEvents 	The number of events in the Event array.
Event 		An array of EFI_EVENT.
Index 		Pointer to the index of the event which satisfied the wait condition.
```

To our task we should use `EFI_EVENT WaitForKey` from the `EFI_SIMPLE_TEXT_INPUT_PROTOCOL` (which is placed in a `gST->ConIn`)
```
typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
 EFI_INPUT_RESET Reset;
 EFI_INPUT_READ_KEY ReadKeyStroke;
 EFI_EVENT WaitForKey;
} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
```

Now when we now all this API add this code to the end of the `HelloWorld` app main function:
```
UINTN Index;
gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
```

Compile OVMF again and try to boot our `HelloWorld` boot option through the `Boot Manager` BIOS menu.
Now output of the app stops and waits for the user keystroke.

Everything works fine except a fact that if we choose `Enter` as our keystroke, `HelloWorld` app would be immediately launched again.

This happens because we didn't read or clear the input buffer. As we don't need keystroke information let's simply reset it with a `Reset` function:
```
EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset()

Summary:
Resets the input device hardware.

Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_INPUT_RESET) (
 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
 IN BOOLEAN ExtendedVerification
 );

Parameters:
This 			A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
ExtendedVerification	Indicates that the driver may perform a more exhaustive verification
			operation of the device during reset.

Description:
The Reset() function resets the input device hardware.
The implementation of Reset is required to clear the contents of any input queues resident in memory
used for buffering keystroke data and put the input stream in a known empty state
```

Add this to the end of our app:
```
gST->ConIn->Reset(gST->ConIn, FALSE);
```

Now if we boot our app from the `Boot Manager` BIOS menu it would work correctly for any keystroke.