@@ -2,6 +2,7 @@
#define _ARM_IDMAP_H
#include <asm/page.h>
+#include <asm/sections.h>
void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end);
@@ -11,6 +12,12 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end);
void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end) {};
#endif
+/* Modes understood from arm_machine_{restart,reset}. */
+#define MODE_REMAP_KERNEL 'k'
+
+/* Page reserved after the kernel image. */
+#define RESERVE_STACK_PAGE ALIGN((unsigned long)_end + PAGE_SIZE, PMD_SIZE)
+
void setup_mm_for_reboot(char mode);
#endif /* _ARM_IDMAP_H */
@@ -75,17 +75,29 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
#endif
/*
- * In order to soft-boot, we need to insert a 1:1 mapping in place of
- * the user-mode pages. This will then ensure that we have predictable
- * results when turning the mmu off
+ * In order to soft-boot, we need to insert a 1:1 mapping of memory.
+ * This will then ensure that we have predictable results when turning
+ * the mmu off.
*/
void setup_mm_for_reboot(char mode)
{
- /*
- * We need to access to user-mode page tables here. For kernel threads
- * we don't have any user-mode mappings so we use the context that we
- * "borrowed".
- */
- identity_mapping_add(current->active_mm->pgd, 0, TASK_SIZE);
+
+ identity_mapping_add(swapper_pg_dir, 0, TASK_SIZE);
+ if (mode == MODE_REMAP_KERNEL) {
+ /*
+ * Extend the flat mapping into kernelspace.
+ * We leave room for the kernel image and a `reboot stack'.
+ */
+ identity_mapping_add(swapper_pg_dir, TASK_SIZE, PAGE_OFFSET);
+ identity_mapping_add(swapper_pg_dir, RESERVE_STACK_PAGE, 0);
+ }
+
+ /* Clean and invalidate L1. */
+ flush_cache_all();
+
+ /* Switch exclusively to kernel mappings. */
+ cpu_switch_mm(swapper_pg_dir, &init_mm);
+
+ /* Flush the TLB. */
local_flush_tlb_all();
}