summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
authorMichael Brown2016-02-21 12:37:37 +0100
committerMichael Brown2016-02-21 12:37:37 +0100
commit4c1f2486e664e9c88164cfff917a99bfe6beed52 (patch)
treea87dfb2423a808d7121fe3dd1c51efa5349976b0 /src/arch
parent[librm] Mark virt_offset, text16, data16, rm_cs, and rm_ds as constant (diff)
downloadipxe-4c1f2486e664e9c88164cfff917a99bfe6beed52.tar.gz
ipxe-4c1f2486e664e9c88164cfff917a99bfe6beed52.tar.xz
ipxe-4c1f2486e664e9c88164cfff917a99bfe6beed52.zip
[librm] Support userptr_t in 64-bit builds
In a 64-bit build, the entirety of the 32-bit address space is identity-mapped and so any valid physical address may immediately be used as a virtual address. Conversely, a virtual address that is already within the 32-bit address space may immediately be used as a physical address. A valid virtual address that lies outside the 32-bit address space must be an address within .textdata, and so can be converted to a physical address by adding virt_offset. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/x86/include/librm.h24
1 files changed, 23 insertions, 1 deletions
diff --git a/src/arch/x86/include/librm.h b/src/arch/x86/include/librm.h
index efc8b114..d6214ac8 100644
--- a/src/arch/x86/include/librm.h
+++ b/src/arch/x86/include/librm.h
@@ -89,6 +89,15 @@ extern const unsigned long virt_offset;
*/
static inline __always_inline userptr_t
UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
+
+ /* In a 64-bit build, any valid physical address is directly
+ * usable as a virtual address, since the low 4GB is
+ * identity-mapped.
+ */
+ if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
+ return phys_addr;
+
+ /* In a 32-bit build, subtract virt_offset */
return ( phys_addr - virt_offset );
}
@@ -101,7 +110,20 @@ UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
*/
static inline __always_inline unsigned long
UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
- return ( userptr + offset + virt_offset );
+ unsigned long addr = ( userptr + offset );
+
+ /* In a 64-bit build, any virtual address in the low 4GB is
+ * directly usable as a physical address, since the low 4GB is
+ * identity-mapped.
+ */
+ if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
+ ( addr <= 0xffffffffUL ) )
+ return addr;
+
+ /* In a 32-bit build or in a 64-bit build with a virtual
+ * address above 4GB: add virt_offset
+ */
+ return ( addr + virt_offset );
}
static inline __always_inline userptr_t