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 
51 #ifdef UACCESS_OFFSET
52 #define UACCESS_PREFIX_offset
53 #else
54 #define UACCESS_PREFIX_offset __offset_
55 #endif
56 
57 /** Virtual address offset
58  *
59  * This is defined to be the value to be added to an address within
60  * iPXE's own image in order to obtain its physical address, as
61  * described above.
62  */
63 extern const unsigned long virt_offset;
64 
65 /** Allow for architecture-specific overrides of virt_offset */
66 #include <bits/virt_offset.h>
67 
68 /**
69  * Convert physical address to virtual address
70  *
71  * @v phys Physical address
72  * @ret virt Virtual address
73  */
74 static inline __always_inline void *
75 UACCESS_INLINE ( offset, phys_to_virt ) ( unsigned long phys ) {
76 
77  /* In a 64-bit build, any valid physical address is directly
78  * usable as a virtual address, since physical addresses are
79  * identity-mapped.
80  */
81  if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
82  return ( ( void * ) phys );
83 
84  /* In a 32-bit build: subtract virt_offset */
85  return ( ( void * ) ( phys - virt_offset ) );
86 }
87 
88 /**
89  * Convert virtual address to physical address
90  *
91  * @v virt Virtual address
92  * @ret phys Physical address
93  */
94 static inline __always_inline physaddr_t
95 UACCESS_INLINE ( offset, virt_to_phys ) ( volatile const void *virt ) {
96  const physaddr_t msb = ( 1ULL << ( 8 * sizeof ( physaddr_t ) - 1 ) );
97  physaddr_t addr = ( ( physaddr_t ) virt );
98 
99  /* In a 64-bit build, any valid virtual address with the MSB
100  * clear is directly usable as a physical address, since it
101  * must lie within the identity-mapped portion.
102  *
103  * This test will typically reduce to a single "branch if less
104  * than zero" instruction.
105  */
106  if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
107  ( ! ( addr & msb ) ) ) {
108  return addr;
109  }
110 
111  /* In a 32-bit build or in a 64-bit build with a virtual
112  * address with the MSB set: add virt_offset
113  */
114  addr += virt_offset;
115 
116  /* In a 64-bit build with an address that still has the MSB
117  * set after adding virt_offset: truncate the original virtual
118  * address to form a 32-bit physical address.
119  *
120  * This test will also typically reduce to a single "branch if
121  * less than zero" instruction.
122  */
123  if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
124  ( addr & msb ) ) {
125  return ( ( uint32_t ) ( physaddr_t ) virt );
126  }
127 
128  return addr;
129 }
130 
131 #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
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:75