Automatically unmap physmap()s
Similarly to the previous PCI self-clean up patch this one allows to get rid
of a huge number of programmer shutdown functions and makes introducing
bugs harder. It adds a new function rphysmap() that takes care of unmapping
at shutdown. Callers are changed where it makes sense.
Corresponding to flashrom svn r1714.
Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/physmap.c b/physmap.c
index 932fe75..ba259b9 100644
--- a/physmap.c
+++ b/physmap.c
@@ -21,6 +21,7 @@
*/
#include <unistd.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -204,13 +205,32 @@
}
#endif
-#define PHYSMAP_NOFAIL 0
-#define PHYSMAP_MAYFAIL 1
-#define PHYSMAP_RW 0
-#define PHYSMAP_RO 1
+#define PHYSMAP_NOFAIL 0
+#define PHYSMAP_MAYFAIL 1
+#define PHYSMAP_RW 0
+#define PHYSMAP_RO 1
+#define PHYSMAP_NOCLEANUP 0
+#define PHYSMAP_CLEANUP 1
-static void *physmap_common(const char *descr, uintptr_t phys_addr,
- size_t len, int mayfail, int readonly)
+struct undo_physmap_data {
+ void *virt_addr;
+ size_t len;
+};
+
+static int undo_physmap(void *data)
+{
+ if (data == NULL) {
+ msg_perr("%s: tried to physunmap without valid data!\n", __func__);
+ return 1;
+ }
+ struct undo_physmap_data *d = data;
+ physunmap(d->virt_addr, d->len);
+ free(data);
+ return 0;
+}
+
+static void *physmap_common(const char *descr, uintptr_t phys_addr, size_t len, bool mayfail,
+ bool readonly, bool autocleanup)
{
void *virt_addr;
@@ -257,19 +277,42 @@
exit(3);
}
+ if (autocleanup) {
+ struct undo_physmap_data *d = malloc(sizeof(struct undo_physmap_data));
+ if (d == NULL) {
+ msg_perr("%s: Out of memory!\n", __func__);
+ goto unmap_out;
+ }
+
+ d->virt_addr = virt_addr;
+ d->len = len;
+ if (register_shutdown(undo_physmap, d) != 0) {
+ msg_perr("%s: Could not register shutdown function!\n", __func__);
+ goto unmap_out;
+ }
+ }
+
return virt_addr;
+unmap_out:
+ physunmap(virt_addr, len);
+ if (!mayfail)
+ exit(3);
+ return ERROR_PTR;
}
void *physmap(const char *descr, uintptr_t phys_addr, size_t len)
{
- return physmap_common(descr, phys_addr, len, PHYSMAP_NOFAIL,
- PHYSMAP_RW);
+ return physmap_common(descr, phys_addr, len, PHYSMAP_NOFAIL, PHYSMAP_RW, PHYSMAP_NOCLEANUP);
+}
+
+void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len)
+{
+ return physmap_common(descr, phys_addr, len, PHYSMAP_NOFAIL, PHYSMAP_RW, PHYSMAP_CLEANUP);
}
void *physmap_try_ro(const char *descr, uintptr_t phys_addr, size_t len)
{
- return physmap_common(descr, phys_addr, len, PHYSMAP_MAYFAIL,
- PHYSMAP_RO);
+ return physmap_common(descr, phys_addr, len, PHYSMAP_MAYFAIL, PHYSMAP_RO, PHYSMAP_NOCLEANUP);
}
/* MSR abstraction implementations for Linux, OpenBSD, FreeBSD/Dragonfly, OSX, libpayload