Skip to content

Commit f8a7ef6

Browse files
committed
[docs] updates paging docs
In hyperlight-dev#297, we make the base address of guest memory 0x0 instead of 0x200_000 and remove statically defined memory regions. This commit updates documentation in accordance to these changes. Signed-off-by: danbugs <[email protected]>
1 parent 310d970 commit f8a7ef6

File tree

1 file changed

+55
-32
lines changed

1 file changed

+55
-32
lines changed

Diff for: docs/paging-development-notes.md

+55-32
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,103 @@
11
# Paging in Hyperlight
22

3-
Hyperlight uses paging, which means the all addresses inside a Hyperlight VM are treated as virtual addresses by the processor. Specifically, Hyperlight uses (ordinary) 4-level paging. 4-level paging is used because we set the following control registers on logical cores inside a VM: `CR0.PG = 1, CR4.PAE = 1, IA32_EFER.LME = 1, and CR4.LA57 = 0`. A Hyperlight VM is limited to 1GB of addressable memory, see below for more details. These control register settings have the following effects:
3+
Hyperlight uses paging, which means the all addresses inside a Hyperlight VM are
4+
treated as virtual addresses by the processor. Specifically, Hyperlight uses
5+
(ordinary) 4-level paging. 4-level paging is used because we set the following
6+
control registers on logical cores inside a VM: `CR0.PG = 1, CR4.PAE = 1, IA32_EFER,
7+
LME = 1, and CR4.LA57 = 0`. A Hyperlight VM is limited to 1GB of addressable memory,
8+
see below for more details. These control register settings have the following
9+
effects:
410

511
- `CR0.PG = 1`: Enables paging
6-
- `CR4.PAE = 1`: Enables Physical Address Extension (PAE) mode (this is required for 4-level paging)
12+
- `CR4.PAE = 1`: Enables Physical Address Extension (PAE) mode (this is required for
13+
4-level paging)
714
- `IA32_EFER.LME = 1`: Enables Long Mode (64-bit mode)
815
- `CR4.LA57 = 0`: Makes sure 5-level paging is disabled
916

1017
## Host-to-Guest memory mapping
1118

12-
Into each Hyperlight VM, memory from the host is mapped into the VM as physical memory. The physical memory inside the VM starts at address `0x200_000` and extends linearly to however much memory was mapped into the VM (depends on various parameters).
19+
Into each Hyperlight VM, memory from the host is mapped into the VM as physical
20+
memory. The physical memory inside the VM starts at address `0x0` and extends
21+
linearly to however much memory was mapped into the VM (depends on various
22+
parameters).
1323

1424
## Page table setup
1525

16-
The following page table structs are set up in memory before running a Hyperlight VM (See [Access Flags](#access-flags) for details on access flags that are also set on each entry)
26+
The following page table structs are set up in memory before running a Hyperlight VM
27+
(See [Access Flags](#access-flags) for details on access flags that are also set on each entry)
1728

1829
### PML4 (Page Map Level 4) Table
1930

20-
The PML4 table is located at physical address specified in CR3. In Hyperlight we set `CR3=0x200_000`, which means the PML4 table is located at physical address `0x200_000`. The PML4 table comprises 512 64-bit entries.
31+
The PML4 table is located at physical address specified in CR3. In Hyperlight we set
32+
`CR3=pml4_address`. The PML4 table comprises 512 64-bit entries.
2133

22-
In Hyperlight, we only initialize the first entry (at address `0x200_000`), with value `0x201_000`, implying that we only have a single PDPT.
34+
In Hyperlight, we only initialize the first entry, with value `0x1_000`, implying that
35+
we only have a single PDPT.
2336

2437
### PDPT (Page-directory-pointer Table)
2538

26-
The first and only PDPT is located at physical address `0x201_000`. The PDPT comprises 512 64-bit entries. In Hyperlight, we only initialize the first entry of the PDPT (at address `0x201_000`), with the value `0x202_000`, implying that we only have a single PD.
39+
The first and only PDPT is located at physical address `0x1_000`. The PDPT comprises
40+
512 64-bit entries. In Hyperlight, we only initialize the first entry of the PDPT
41+
(at address `0x1_000`), with the value `0x2_000`, implying that we only have a
42+
single PD.
2743

2844
### PD (Page Directory)
2945

30-
The first and only PD is located at physical address `0x202_000`. The PD comprises 512 64-bit entries, each entry `i` is set to the value `(i * 0x1000) + 0x203_000`. Thus, the first entry is `0x203_000`, the second entry is `0x204_000` and so on.
46+
The first and only PD is located at physical address `0x2_000`. The PD comprises 512
47+
64-bit entries, each entry `i` is set to the value `(i * 0x1000) + 0x3_000`. Thus,
48+
the first entry is `0x3_000`, the second entry is `0x4_000` and so on.
3149

3250
### PT (Page Table)
3351

34-
The page tables start at physical address `0x203_000`. Each page table has 512 64-bit entries. Each entry is set to the value `p << 21|i << 12` where `p` is the page table number and `i` is the index of the entry in the page table. Thus, the first entry of the first page table is `0x000_000`, the second entry is `0x000_000 + 0x1000`, and so on. The first entry of the second page table is `0x200_000 + 0x1000`, the second entry is `0x200_000 + 0x2000`, and so on. Enough page tables are created to cover the size of memory mapped into the VM.
52+
The page tables start at physical address `0x3_000`. Each page table has 512 64-bit
53+
entries. Each entry is set to the value `p << 21|i << 12` where `p` is the page
54+
table number and `i` is the index of the entry in the page table. Thus, the first
55+
entry of the first page table is `0x000_000`, the second entry is `0x000_000 +
56+
0x1000`, and so on. The first entry of the second page table is `0x200_000 +
57+
0x1000`, the second entry is `0x200_000 + 0x2000`, and so on. Enough page tables are
58+
created to cover the size of memory mapped into the VM.
3559

3660
## Address Translation
3761

38-
Given a 64-bit virtual address X, the corresponding physical address is obtained as follows:
62+
Given a 64-bit virtual address X, the corresponding physical address is obtained as
63+
follows:
3964

40-
1. PML4 table's physical address is located using CR3 (CR3 is `0x200_000`).
65+
1. PML4 table's physical address is located using CR3.
4166
2. Bits 47:39 of X are used to index into PML4, giving us the address of the PDPT.
4267
3. Bits 38:30 of X are used to index into PDPT, giving us the address of the PD.
4368
4. Bits 29:21 of X are used to index into PD, giving us the address of the PT.
4469
5. Bits 20:12 of X are used to index into PT, giving us a base address of a 4K page.
4570
6. Bits 11:0 of X are treated as an offset.
4671
7. The final physical address is the base address + the offset.
4772

48-
However, because we have only one PDPT4E and only one PDPT4E, bits 47:30 must always be zero. Each PDE points to a PT, and because each PTE with index `p,i` (where p is the page table number of i is the entry within that page) has value `p << 21|i << 12`, the base address received in step 5 above is always just bits 29:12 of X itself. **As bits 11:0 are an offset this means that translating a virtual address to a physical address is essentially a NO-OP**.
73+
However, because we have only one PDPT4E and only one PDPT4E, bits 47:30 must always
74+
be zero. Each PDE points to a PT, and because each PTE with index `p,i` (where p i
75+
the page table number of i is the entry within that page) has value `p << 21|i <<
76+
12`, the base address received in step 5 above is always just bits 29:12 of X
77+
itself. **As bits 11:0 are an offset this means that translating a virtual address
78+
to a physical address is essentially a NO-OP**.
4979

50-
A diagram to describe how a linear (virtual) address is translated to physical address inside a Hyperlight VM:
80+
A diagram to describe how a linear (virtual) address is translated to physical
81+
address inside a Hyperlight VM:
5182

5283
![A diagram to describe how a linear (virtual) address is translated to physical](assets/linear-address-translation.png)
5384

54-
Diagram is taken from "The Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide"
85+
Diagram is taken from "The Intel® 64 and IA-32 Architectures Software Developer’s
86+
Manual, Volume 3A: System Programming Guide"
5587

5688
### Limitations
5789

58-
Since we only have 1 PML4E and only 1 PDPTE, bits 47:30 of a linear address must be zero. Thus, we have only 30 bits (bit 29:0) to work with, giving us access to (1 << 30) bytes of memory (1GB).
90+
Since we only have 1 PML4E and only 1 PDPTE, bits 47:30 of a linear address must be
91+
zero. Thus, we have only 30 bits (bit 29:0) to work with, giving us access to (1 <<
92+
30) bytes of memory (1GB).
5993

6094
## Access Flags
6195

62-
In addition to providing addresses, page table entries also contain access flags that describe how memory can be accessed, and whether it is present or not. The following access flags are set on each entry:
96+
In addition to providing addresses, page table entries also contain access flags
97+
that describe how memory can be accessed, and whether it is present or not. The
98+
following access flags are set on each entry:
6399

64-
PML4E, PDPTE, and PD Entries have the present flag set to 1, and the rest of the flags are not set.
100+
PML4E, PDPTE, and PD Entries have the present flag set to 1, and the rest of the
101+
flags are not set.
65102

66-
PTE Entries all have the present flag set to 1, apart from those for the address range `0x000_000` to `0x1FF_000` which have the present flag set to 0 as we do not map memory below physical address `0x200_000`.
67-
68-
In addition, the following flags are set according to the type of memory being mapped:
69-
70-
For `Host Function Definitions` and `Host Exception Data` the NX flag is set to 1 meaning that the memory is not executable in the guest and is not accessible to guest code (ring 3) and is also read only even in ring 0.
71-
72-
For `Input/Output Data`, `Page Table Data`, `PEB`, `PanicContext` and `GuestErrorData` the NX flag is set to 1 meaning that the memory is not executable in the guest and the RW flag is set to 1 meaning that the memory is read/write in ring 0, this means that this data is not accessible to guest code unless accessed via the Hyperlight Guest API (which will be in ring 0).
73-
74-
For `Code` the NX flag is not set meaning that the memory is executable in the guest and the RW flag is set to 1 meaning the data is read/write, as the user/supervisor flag is set then the memory is also read/write accessible to user code. (The code section contains both code and data, so it is marked as read/write. In a future update we will parse the layout of the code and set the access flags accordingly).
75-
76-
For `Stack` the NX flag is set to 1 meaning that the memory is not executable in the guest, the RW flag is set to 1 meaning the data is read/write, as the user/supervisor flag is set then the memory is also read/write accessible to user code.
77-
78-
For `Heap` the RW flag is set to 1 meaning the data is read/write, as the user/supervisor flag is set then the memory is also read/write accessible to user code. The NX flag is not set if the feature `executable_heap` is enabled, otherwise the NX flag is set to 1 meaning that the memory is not executable in the guest. The `executable_heap` feature is disabled by default. It is required to allow data in the heap to be executable to when guests dynamically load or generate code, e.g. `hyperlight-wasm` supports loading of AOT compiled WebAssembly modules, these are loaded dynamically by the Wasm runtime and end up in the heap, therefore for this scenario the `executable_heap` feature must be enabled. In a future update we will implement a mechanism to allow the guest to request memory to be executable at runtime via the Hyperlight Guest API.
79-
80-
For `Guard Pages` the NX flag is set to 1 meaning that the memory is not executable in the guest. The RW flag is set to 1 meaning the data is read/write, as the user/supervisor flag is set then the memory is also read/write accessible to user code. **Note that neither of these flags should really be set as the purpose of the guard pages is to cause a fault if accessed, however, as we deal with this fault in the host not in the guest we need to make the memory accessible to the guest, in a future update we will implement exception and interrupt handling in the guest and then change these flags.**
103+
PTE Entries all have the present flag set to 1.

0 commit comments

Comments
 (0)