Automatically round address ranges requested from physmap_autocleanup() to page boundaries. Other physmap() variants were not changed so this is safe regarding unmapping.
This patch also changes the display width of all addresses in physmap.c to 16 hex characters.
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- physmap.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-)
diff --git a/physmap.c b/physmap.c index a9445d5..e6d9a30 100644 --- a/physmap.c +++ b/physmap.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#include <inttypes.h> #include <unistd.h> #include <stdbool.h> #include <stdio.h> @@ -215,6 +216,27 @@ void physunmap(void *virt_addr, size_t len) } #endif
+/* Round start to nearest page boundary below and set len so that the resulting + * address range ends at the lowest possible page boundary where the original + * address range is still entirely contained. It returns the difference between + * the rounded start address and the original start address. */ +static unsigned long round_to_page_boundaries(unsigned long *start, size_t *len) +{ + unsigned long page_size = getpagesize(); + unsigned long page_mask = ~(page_size-1); + unsigned long end = *start + *len; + unsigned long old_start = *start; + msg_gspew("page_size=%lu\n", page_size); + msg_gspew("pre-rounding: start=0x%016" PRIx64 ", len=0x%0zx, end=0x%016" PRIx64 "\n", + *start, *len, end); + *start = *start & page_mask; + end = (end + page_size - 1) & page_mask; + *len = end - *start; + msg_gspew("post-rounding: start=0x%016" PRIx64 ", len=0x%0zx, end=0x%016" PRIx64 "\n", + *start, *len, *start + *len); + return old_start - *start; +} + struct physmap_stutdown_data { void *addr; size_t len; @@ -233,25 +255,18 @@ static int physmap_shutdown(void *data) }
static void *physmap_common(const char *descr, unsigned long phys_addr, size_t len, bool mayfail, - bool readonly, bool autocleanup) + bool readonly, bool autocleanup, bool round) { void *virt_addr; + unsigned long offset = 0;
if (len == 0) { - msg_pspew("Not mapping %s, zero size at 0x%08lx.\n", - descr, phys_addr); + msg_pspew("Not mapping %s, zero size at 0x%016" PRIx64 ".\n", descr, phys_addr); return ERROR_PTR; }
- if ((getpagesize() - 1) & len) { - msg_perr("Mapping %s at 0x%08lx, unaligned size 0x%lx.\n", - descr, phys_addr, (unsigned long)len); - } - - if ((getpagesize() - 1) & phys_addr) { - msg_perr("Mapping %s, 0x%lx bytes at unaligned 0x%08lx.\n", - descr, (unsigned long)len, phys_addr); - } + if (round) + offset = round_to_page_boundaries(&phys_addr, &len);
if (readonly) virt_addr = sys_physmap_ro_cached(phys_addr, len); @@ -261,8 +276,7 @@ static void *physmap_common(const char *descr, unsigned long phys_addr, size_t l if (ERROR_PTR == virt_addr) { if (NULL == descr) descr = "memory"; - msg_perr("Error accessing %s, 0x%lx bytes at 0x%08lx\n", descr, - (unsigned long)len, phys_addr); + msg_perr("Error accessing %s, 0x%0zx bytes at 0x%016" PRIx64 "\n", descr, len, phys_addr); perror(MEM_DEV " mmap failed"); #ifdef __linux__ if (EINVAL == errno) { @@ -277,7 +291,9 @@ static void *physmap_common(const char *descr, unsigned long phys_addr, size_t l "and reboot, or reboot into\n" "single user mode.\n"); #endif - if (!mayfail) + if (mayfail) + return ERROR_PTR; + else exit(3); }
@@ -296,7 +312,7 @@ static void *physmap_common(const char *descr, unsigned long phys_addr, size_t l } }
- return virt_addr; + return virt_addr + offset; unmap_out: physunmap(virt_addr, len); return ERROR_PTR; @@ -304,17 +320,17 @@ unmap_out:
void *physmap(const char *descr, unsigned long phys_addr, size_t len) { - return physmap_common(descr, phys_addr, len, false, false, false); + return physmap_common(descr, phys_addr, len, false, false, false, false); }
void *physmap_autocleanup(const char *descr, unsigned long phys_addr, size_t len) { - return physmap_common(descr, phys_addr, len, false, false, true); + return physmap_common(descr, phys_addr, len, false, false, true, true); }
void *physmap_try_ro(const char *descr, unsigned long phys_addr, size_t len) { - return physmap_common(descr, phys_addr, len, true, true, false); + return physmap_common(descr, phys_addr, len, true, true, false, false); }
#if defined(__i386__) || defined(__x86_64__)