iPXE
virt_offset.h
Go to the documentation of this file.
1#ifndef _IPXE_VIRT_OFFSET_H
2#define _IPXE_VIRT_OFFSET_H
3
4/**
5 * @file
6 *
7 * Virtual offset memory model
8 *
9 * No currently supported machine provides a full 64 bits of physical
10 * address space. When we have ownership of the page tables (or
11 * segmentation mechanism), we can therefore use the following model:
12 *
13 * - For 32-bit builds: set up a circular map so that all 32-bit
14 * virtual addresses are at a fixed offset from the 32-bit
15 * physical addresses.
16 *
17 * - For 64-bit builds: identity-map the required portion of the
18 * physical address space, place iPXE within the 32-bit physical
19 * address space, map iPXE using virtual addresses in the top part
20 * of the negative (kernel) address space, and optionally map the
21 * 32-bit physical address space with attributes suitable for
22 * coherent DMA accesses.
23 *
24 * In both cases, we can define "virt_offset" as "the value to be
25 * added to an address within iPXE's own image in order to obtain its
26 * physical address". With this definition:
27 *
28 * - For 32-bit builds: conversion between physical and virtual
29 * addresses is a straightforward addition or subtraction of
30 * virt_offset, since the whole 32-bit address space is circular.
31 *
32 * - For 64-bit builds: conversion from any valid physical address
33 * is a no-op (since all physical addresses are identity-mapped),
34 * and conversion from a virtual address to a physical address
35 * requires an addition of virt_offset if and only if the virtual
36 * address lies in the high negative portion of the address space
37 * (i.e. has the MSB set, but has the MSB clear after adding
38 * virt_offset).
39 *
40 * For x86_64-pcbios, we identity-map the low 4GB of address space
41 * since the only accesses required above 4GB are for MMIO (typically
42 * PCI devices with large memory BARs).
43 *
44 * For riscv64-sbi, we identity-map as much of the physical address
45 * space as can be mapped by the paging model (Sv39, Sv48, or Sv57)
46 * and create a coherent DMA mapping of the low 4GB.
47 */
48
49FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
50FILE_SECBOOT ( PERMITTED );
51
52#ifdef UACCESS_OFFSET
53#define UACCESS_PREFIX_offset
54#else
55#define UACCESS_PREFIX_offset __offset_
56#endif
57
58/** Virtual address offset
59 *
60 * This is defined to be the value to be added to an address within
61 * iPXE's own image in order to obtain its physical address, as
62 * described above.
63 */
64extern const unsigned long virt_offset;
65
66/** Allow for architecture-specific overrides of virt_offset */
67#include <bits/virt_offset.h>
68
69/**
70 * Convert physical address to virtual address
71 *
72 * @v phys Physical address
73 * @ret virt Virtual address
74 */
75static inline __always_inline void *
76UACCESS_INLINE ( offset, phys_to_virt ) ( unsigned long phys ) {
77
78 /* In a 64-bit build, any valid physical address is directly
79 * usable as a virtual address, since physical addresses are
80 * identity-mapped.
81 */
82 if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
83 return ( ( void * ) phys );
84
85 /* In a 32-bit build: subtract virt_offset */
86 return ( ( void * ) ( phys - virt_offset ) );
87}
88
89/**
90 * Convert virtual address to physical address
91 *
92 * @v virt Virtual address
93 * @ret phys Physical address
94 */
95static inline __always_inline physaddr_t
96UACCESS_INLINE ( offset, virt_to_phys ) ( volatile const void *virt ) {
97 const physaddr_t msb = ( 1ULL << ( 8 * sizeof ( physaddr_t ) - 1 ) );
98 physaddr_t addr = ( ( physaddr_t ) virt );
99
100 /* In a 64-bit build, any valid virtual address with the MSB
101 * clear is directly usable as a physical address, since it
102 * must lie within the identity-mapped portion.
103 *
104 * This test will typically reduce to a single "branch if less
105 * than zero" instruction.
106 */
107 if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
108 ( ! ( addr & msb ) ) ) {
109 return addr;
110 }
111
112 /* In a 32-bit build or in a 64-bit build with a virtual
113 * address with the MSB set: add virt_offset
114 */
115 addr += virt_offset;
116
117 /* In a 64-bit build with an address that still has the MSB
118 * set after adding virt_offset: truncate the original virtual
119 * address to form a 32-bit physical address.
120 *
121 * This test will also typically reduce to a single "branch if
122 * less than zero" instruction.
123 */
124 if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
125 ( addr & msb ) ) {
126 return ( ( uint32_t ) ( physaddr_t ) virt );
127 }
128
129 return addr;
130}
131
132#endif /* _IPXE_VIRT_OFFSET_H */
unsigned int uint32_t
Definition stdint.h:12
unsigned long physaddr_t
Definition stdint.h:20
Dummy architecture-specific virtual address offset.
uint16_t offset
Offset to command line.
Definition bzimage.h:3
uint32_t addr
Buffer address.
Definition dwmac.h:9
static signed char phys[4]
Definition epic100.c:88
#define __always_inline
Declare a function to be always inline.
Definition compiler.h:611
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define UACCESS_INLINE(_subsys, _api_func)
Calculate static inline user access API function name.
Definition uaccess.h:31
const unsigned long virt_offset
Virtual address offset.