summaryrefslogtreecommitdiff
path: root/arch/loongarch/kernel/relocate.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/loongarch/kernel/relocate.c')
-rw-r--r--arch/loongarch/kernel/relocate.c91
1 files changed, 81 insertions, 10 deletions
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
index 50c469067f3a..4b61a9632a98 100644
--- a/arch/loongarch/kernel/relocate.c
+++ b/arch/loongarch/kernel/relocate.c
@@ -68,18 +68,25 @@ static inline void __init relocate_absolute(long random_offset)
for (p = begin; (void *)p < end; p++) {
long v = p->symvalue;
- uint32_t lu12iw, ori, lu32id, lu52id;
+ uint32_t lu12iw, ori;
+#ifdef CONFIG_64BIT
+ uint32_t lu32id, lu52id;
+#endif
union loongarch_instruction *insn = (void *)p->pc;
lu12iw = (v >> 12) & 0xfffff;
ori = v & 0xfff;
+#ifdef CONFIG_64BIT
lu32id = (v >> 32) & 0xfffff;
lu52id = v >> 52;
+#endif
insn[0].reg1i20_format.immediate = lu12iw;
insn[1].reg2i12_format.immediate = ori;
+#ifdef CONFIG_64BIT
insn[2].reg1i20_format.immediate = lu32id;
insn[3].reg2i12_format.immediate = lu52id;
+#endif
}
}
@@ -121,24 +128,40 @@ static inline __init unsigned long get_random_boot(void)
static int __init nokaslr(char *p)
{
- pr_info("KASLR is disabled.\n");
-
- return 0; /* Print a notice and silence the boot warning */
+ return 0; /* Just silence the boot warning */
}
early_param("nokaslr", nokaslr);
+#define KASLR_DISABLED_MESSAGE "KASLR is disabled by %s in %s cmdline.\n"
+
+/*
+ * Note: strictly-defined KASLR means the kernel's final runtime address
+ * has a random offset from the kernel's load address, which is implemented
+ * in relocate.c; broadly-defined KALSR means the kernel's final runtime
+ * address has a random offset from the kernel's link address (a.k.a.
+ * VMLINUX_LOAD_ADDRESS), which also include the efistlub implementation,
+ * kexec_file implementation and QEMU direct kernel boot. kaslr_disabled()
+ * return true only means strictly-defined KASLR is disabled.
+ */
static inline __init bool kaslr_disabled(void)
{
char *str;
const char *builtin_cmdline = CONFIG_CMDLINE;
+ if (kaslr_offset())
+ return true; /* KASLR is performed during early boot. */
+
str = strstr(builtin_cmdline, "nokaslr");
- if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
+ if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) {
+ pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "built-in");
return true;
+ }
str = strstr(boot_command_line, "nokaslr");
- if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
+ if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) {
+ pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "bootloader");
return true;
+ }
#ifdef CONFIG_HIBERNATION
str = strstr(builtin_cmdline, "nohibernate");
@@ -158,14 +181,24 @@ static inline __init bool kaslr_disabled(void)
return false;
str = strstr(builtin_cmdline, "resume=");
- if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
+ if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) {
+ pr_info(KASLR_DISABLED_MESSAGE, "\'resume=\'", "built-in");
return true;
+ }
str = strstr(boot_command_line, "resume=");
- if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
+ if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) {
+ pr_info(KASLR_DISABLED_MESSAGE, "\'resume=\'", "bootloader");
return true;
+ }
#endif
+ str = strstr(boot_command_line, "kexec_file");
+ if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) {
+ pr_info(KASLR_DISABLED_MESSAGE, "\'kexec_file\'", "bootloader");
+ return true;
+ }
+
return false;
}
@@ -179,7 +212,7 @@ static inline void __init *determine_relocation_address(void)
if (kaslr_disabled())
return destination;
- kernel_length = (long)_end - (long)_text;
+ kernel_length = (unsigned long)_end - (unsigned long)_text;
random_offset = get_random_boot() << 16;
random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
@@ -189,14 +222,52 @@ static inline void __init *determine_relocation_address(void)
return RELOCATED_KASLR(destination);
}
+static unsigned long __init determine_initrd_address(unsigned long *size)
+{
+ unsigned long start = 0;
+ unsigned long key_length;
+ char *p, *endp, *key = "initrd=";
+
+ key_length = strlen(key);
+ p = strstr(boot_command_line, key);
+
+ if (!p) {
+ key = "initrdmem=";
+ key_length = strlen(key);
+ p = strstr(boot_command_line, key);
+ }
+
+ if (p == boot_command_line || (p > boot_command_line && *(p - 1) == ' ')) {
+ p += key_length;
+ start = memparse(p, &endp);
+ if (*endp == ',')
+ *size = memparse(endp + 1, NULL);
+ }
+
+ return start;
+}
+
static inline int __init relocation_addr_valid(void *location_new)
{
+ unsigned long kernel_start, kernel_size;
+ unsigned long initrd_start, initrd_size = 0;
+
if ((unsigned long)location_new & 0x00000ffff)
return 0; /* Inappropriately aligned new location */
if ((unsigned long)location_new < (unsigned long)_end)
return 0; /* New location overlaps original kernel */
+ initrd_start = determine_initrd_address(&initrd_size);
+ if (initrd_start && initrd_size) {
+ kernel_start = PHYSADDR(location_new);
+ kernel_size = (unsigned long)_end - (unsigned long)_text;
+
+ if (kernel_start < (initrd_start + initrd_size) &&
+ initrd_start < (kernel_start + kernel_size))
+ return 0; /* initrd/initramfs overlaps kernel */
+ }
+
return 1;
}
#endif
@@ -228,7 +299,7 @@ unsigned long __init relocate_kernel(void)
early_memunmap(cmdline, COMMAND_LINE_SIZE);
if (random_offset) {
- kernel_length = (long)(_end) - (long)(_text);
+ kernel_length = (unsigned long)(_end) - (unsigned long)(_text);
/* Copy the kernel to it's new location */
memcpy(location_new, _text, kernel_length);