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 
49 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
50 FILE_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  */
64 extern 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  */
75 static inline __always_inline void *
76 UACCESS_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  */
95 static inline __always_inline physaddr_t
96 UACCESS_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 */
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static signed char phys[4]
Definition: epic100.c:88
Dummy architecture-specific virtual address offset.
#define __always_inline
Declare a function to be always inline.
Definition: compiler.h:611
uint32_t addr
Buffer address.
Definition: dwmac.h:20
const unsigned long virt_offset
Virtual address offset.
unsigned int uint32_t
Definition: stdint.h:12
unsigned long physaddr_t
Definition: stdint.h:20
FILE_SECBOOT(PERMITTED)
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
static __always_inline void * UACCESS_INLINE(offset, phys_to_virt)(unsigned long phys)
Allow for architecture-specific overrides of virt_offset.
Definition: virt_offset.h:76