diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 21fe42c2cb8e7e2e49f7e0ecd0dc5c1ae196ea72..38c3b419f2309f0e12e33736af51f233110dea49 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -206,6 +206,10 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
 		loaded_image_info.device_handle = nethandle;
 #endif
 
+	/* Initialize EFI runtime services */
+	efi_reset_system_init();
+	efi_get_time_init();
+
 	/* Call our payload! */
 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
 
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 94397af483e495d7428d03eb6c5b47402c4aaa85..1e4eb46a9c17e00f330efb8e5740d9f42068aafb 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -155,11 +155,29 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii)
 #define EFI_RUNTIME_DATA __attribute__ ((section ("efi_runtime_data")))
 #define EFI_RUNTIME_TEXT __attribute__ ((section ("efi_runtime_text")))
 
+/* Call this with mmio_ptr as the _pointer_ to a pointer to an MMIO region
+ * to make it available at runtime */
+void efi_add_runtime_mmio(void *mmio_ptr, u64 len);
+
+/* Boards may provide the functions below to implement RTS functionality */
+
+void EFI_RUNTIME_TEXT EFIAPI efi_reset_system(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data);
+void efi_reset_system_init(void);
+
+efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_get_time(
+			struct efi_time *time,
+			struct efi_time_cap *capabilities);
+void efi_get_time_init(void);
+
 #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
 #define EFI_RUNTIME_DATA
 #define EFI_RUNTIME_TEXT
+static inline void efi_add_runtime_mmio(void **mmio_ptr, u64 len) { }
 
 /* No loader configured, stub out EFI_ENTRY */
 static inline void efi_restore_gd(void) { }
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 99b5ef11c2e9740a7f916fc3bd04ebefc5b9d7dd..f73e6d97cbc359a482be0140cca3d096d810dcc6 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -16,6 +16,16 @@
 /* For manual relocation support */
 DECLARE_GLOBAL_DATA_PTR;
 
+struct efi_runtime_mmio_list {
+	struct list_head link;
+	void **ptr;
+	u64 paddr;
+	u64 len;
+};
+
+/* This list contains all runtime available mmio regions */
+LIST_HEAD(efi_runtime_mmio);
+
 static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void);
 static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void);
 static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void);
@@ -55,9 +65,10 @@ struct elf_rela {
  * handle a good number of runtime callbacks
  */
 
-static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
-				    efi_status_t reset_status,
-				    unsigned long data_size, void *reset_data)
+static void EFIAPI efi_reset_system_boottime(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data)
 {
 	EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
 		  reset_data);
@@ -72,11 +83,12 @@ static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
 		break;
 	}
 
-	EFI_EXIT(EFI_SUCCESS);
+	while (1) { }
 }
 
-static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
-					struct efi_time_cap *capabilities)
+static efi_status_t EFIAPI efi_get_time_boottime(
+			struct efi_time *time,
+			struct efi_time_cap *capabilities)
 {
 #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
 	struct rtc_time tm;
@@ -107,6 +119,33 @@ static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
 #endif
 }
 
+/* Boards may override the helpers below to implement RTS functionality */
+
+void __weak EFI_RUNTIME_TEXT EFIAPI efi_reset_system(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data)
+{
+	/* Nothing we can do */
+	while (1) { }
+}
+
+void __weak efi_reset_system_init(void)
+{
+}
+
+efi_status_t __weak EFI_RUNTIME_TEXT EFIAPI efi_get_time(
+			struct efi_time *time,
+			struct efi_time_cap *capabilities)
+{
+	/* Nothing we can do */
+	return EFI_DEVICE_ERROR;
+}
+
+void __weak efi_get_time_init(void)
+{
+}
+
 struct efi_runtime_detach_list_struct {
 	void *ptr;
 	void *patchto;
@@ -116,7 +155,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
 	{
 		/* do_reset is gone */
 		.ptr = &efi_runtime_services.reset_system,
-		.patchto = NULL,
+		.patchto = efi_reset_system,
 	}, {
 		/* invalidate_*cache_all are gone */
 		.ptr = &efi_runtime_services.set_virtual_address_map,
@@ -124,7 +163,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
 	}, {
 		/* RTC accessors are gone */
 		.ptr = &efi_runtime_services.get_time,
-		.patchto = &efi_device_error,
+		.patchto = &efi_get_time,
 	}, {
 		/* Clean up system table */
 		.ptr = &systab.con_in,
@@ -233,12 +272,39 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
 	EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
 		  descriptor_version, virtmap);
 
+	/* Rebind mmio pointers */
+	for (i = 0; i < n; i++) {
+		struct efi_mem_desc *map = (void*)virtmap +
+					   (descriptor_size * i);
+		struct list_head *lhandle;
+		efi_physical_addr_t map_start = map->physical_start;
+		efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
+		efi_physical_addr_t map_end = map_start + map_len;
+
+		/* Adjust all mmio pointers in this region */
+		list_for_each(lhandle, &efi_runtime_mmio) {
+			struct efi_runtime_mmio_list *lmmio;
+
+			lmmio = list_entry(lhandle,
+					   struct efi_runtime_mmio_list,
+					   link);
+			if ((map_start <= lmmio->paddr) &&
+			    (map_end >= lmmio->paddr)) {
+				u64 off = map->virtual_start - map_start;
+				uintptr_t new_addr = lmmio->paddr + off;
+				*lmmio->ptr = (void *)new_addr;
+			}
+		}
+	}
+
+	/* Move the actual runtime code over */
 	for (i = 0; i < n; i++) {
 		struct efi_mem_desc *map;
 
 		map = (void*)virtmap + (descriptor_size * i);
 		if (map->type == EFI_RUNTIME_SERVICES_CODE) {
-			ulong new_offset = map->virtual_start - (runtime_start - gd->relocaddr);
+			ulong new_offset = map->virtual_start -
+					   (runtime_start - gd->relocaddr);
 
 			efi_runtime_relocate(new_offset, map);
 			/* Once we're virtual, we can no longer handle
@@ -251,6 +317,20 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
 	return EFI_EXIT(EFI_INVALID_PARAMETER);
 }
 
+void efi_add_runtime_mmio(void *mmio_ptr, u64 len)
+{
+	struct efi_runtime_mmio_list *newmmio;
+
+	u64 pages = (len + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT;
+	efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false);
+
+	newmmio = calloc(1, sizeof(*newmmio));
+	newmmio->ptr = mmio_ptr;
+	newmmio->paddr = *(uintptr_t *)mmio_ptr;
+	newmmio->len = len;
+	list_add_tail(&newmmio->link, &efi_runtime_mmio);
+}
+
 /*
  * In the second stage, U-Boot has disappeared. To isolate our runtime code
  * that at this point still exists from the rest, we put it into a special
@@ -292,7 +372,7 @@ struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
 		.revision = EFI_RUNTIME_SERVICES_REVISION,
 		.headersize = sizeof(struct efi_table_hdr),
 	},
-	.get_time = &efi_get_time,
+	.get_time = &efi_get_time_boottime,
 	.set_time = (void *)&efi_device_error,
 	.get_wakeup_time = (void *)&efi_unimplemented,
 	.set_wakeup_time = (void *)&efi_unimplemented,
@@ -302,5 +382,5 @@ struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
 	.get_next_variable = (void *)&efi_device_error,
 	.set_variable = (void *)&efi_device_error,
 	.get_next_high_mono_count = (void *)&efi_device_error,
-	.reset_system = &efi_reset_system,
+	.reset_system = &efi_reset_system_boottime,
 };