|
@@ -23,6 +23,7 @@
|
|
#include <asm/current.h>
|
|
#include <asm/current.h>
|
|
#include <asm/machdep.h>
|
|
#include <asm/machdep.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cacheflush.h>
|
|
|
|
+#include <asm/firmware.h>
|
|
#include <asm/paca.h>
|
|
#include <asm/paca.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/sections.h> /* _end */
|
|
#include <asm/sections.h> /* _end */
|
|
@@ -64,31 +65,6 @@ int default_machine_kexec_prepare(struct kimage *image)
|
|
if (image->segment[i].mem < __pa(_end))
|
|
if (image->segment[i].mem < __pa(_end))
|
|
return -ETXTBSY;
|
|
return -ETXTBSY;
|
|
|
|
|
|
- /*
|
|
|
|
- * For non-LPAR, we absolutely can not overwrite the mmu hash
|
|
|
|
- * table, since we are still using the bolted entries in it to
|
|
|
|
- * do the copy. Check that here.
|
|
|
|
- *
|
|
|
|
- * It is safe if the end is below the start of the blocked
|
|
|
|
- * region (end <= low), or if the beginning is after the
|
|
|
|
- * end of the blocked region (begin >= high). Use the
|
|
|
|
- * boolean identity !(a || b) === (!a && !b).
|
|
|
|
- */
|
|
|
|
-#ifdef CONFIG_PPC_STD_MMU_64
|
|
|
|
- if (htab_address) {
|
|
|
|
- low = __pa(htab_address);
|
|
|
|
- high = low + htab_size_bytes;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < image->nr_segments; i++) {
|
|
|
|
- begin = image->segment[i].mem;
|
|
|
|
- end = begin + image->segment[i].memsz;
|
|
|
|
-
|
|
|
|
- if ((begin < high) && (end > low))
|
|
|
|
- return -ETXTBSY;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-#endif /* CONFIG_PPC_STD_MMU_64 */
|
|
|
|
-
|
|
|
|
/* We also should not overwrite the tce tables */
|
|
/* We also should not overwrite the tce tables */
|
|
for_each_node_by_type(node, "pci") {
|
|
for_each_node_by_type(node, "pci") {
|
|
basep = of_get_property(node, "linux,tce-base", NULL);
|
|
basep = of_get_property(node, "linux,tce-base", NULL);
|
|
@@ -329,11 +305,14 @@ struct paca_struct kexec_paca;
|
|
/* Our assembly helper, in misc_64.S */
|
|
/* Our assembly helper, in misc_64.S */
|
|
extern void kexec_sequence(void *newstack, unsigned long start,
|
|
extern void kexec_sequence(void *newstack, unsigned long start,
|
|
void *image, void *control,
|
|
void *image, void *control,
|
|
- void (*clear_all)(void)) __noreturn;
|
|
|
|
|
|
+ void (*clear_all)(void),
|
|
|
|
+ bool copy_with_mmu_off) __noreturn;
|
|
|
|
|
|
/* too late to fail here */
|
|
/* too late to fail here */
|
|
void default_machine_kexec(struct kimage *image)
|
|
void default_machine_kexec(struct kimage *image)
|
|
{
|
|
{
|
|
|
|
+ bool copy_with_mmu_off;
|
|
|
|
+
|
|
/* prepare control code if any */
|
|
/* prepare control code if any */
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -371,13 +350,29 @@ void default_machine_kexec(struct kimage *image)
|
|
/* XXX: If anyone does 'dynamic lppacas' this will also need to be
|
|
/* XXX: If anyone does 'dynamic lppacas' this will also need to be
|
|
* switched to a static version!
|
|
* switched to a static version!
|
|
*/
|
|
*/
|
|
|
|
+ /*
|
|
|
|
+ * On Book3S, the copy must happen with the MMU off if we are either
|
|
|
|
+ * using Radix page tables or we are not in an LPAR since we can
|
|
|
|
+ * overwrite the page tables while copying.
|
|
|
|
+ *
|
|
|
|
+ * In an LPAR, we keep the MMU on otherwise we can't access beyond
|
|
|
|
+ * the RMA. On BookE there is no real MMU off mode, so we have to
|
|
|
|
+ * keep it enabled as well (but then we have bolted TLB entries).
|
|
|
|
+ */
|
|
|
|
+#ifdef CONFIG_PPC_BOOK3E
|
|
|
|
+ copy_with_mmu_off = false;
|
|
|
|
+#else
|
|
|
|
+ copy_with_mmu_off = radix_enabled() ||
|
|
|
|
+ !(firmware_has_feature(FW_FEATURE_LPAR) ||
|
|
|
|
+ firmware_has_feature(FW_FEATURE_PS3_LV1));
|
|
|
|
+#endif
|
|
|
|
|
|
/* Some things are best done in assembly. Finding globals with
|
|
/* Some things are best done in assembly. Finding globals with
|
|
* a toc is easier in C, so pass in what we can.
|
|
* a toc is easier in C, so pass in what we can.
|
|
*/
|
|
*/
|
|
kexec_sequence(&kexec_stack, image->start, image,
|
|
kexec_sequence(&kexec_stack, image->start, image,
|
|
page_address(image->control_code_page),
|
|
page_address(image->control_code_page),
|
|
- mmu_cleanup_all);
|
|
|
|
|
|
+ mmu_cleanup_all, copy_with_mmu_off);
|
|
/* NOTREACHED */
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
|