summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/nohash/kaslr_booke.c
blob: 29c1567d8d407c94c13098f6557fcc3bfaa54c4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright (C) 2019 Jason Yan <yanaijie@huawei.com>

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/memblock.h>
#include <asm/pgalloc.h>
#include <asm/prom.h>
#include <mm/mmu_decl.h>

static unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size,
						  unsigned long kernel_sz)
{
	/* return a fixed offset of 64M for now */
	return SZ_64M;
}

/*
 * To see if we need to relocate the kernel to a random offset
 * void *dt_ptr - address of the device tree
 * phys_addr_t size - size of the first memory block
 */
notrace void __init kaslr_early_init(void *dt_ptr, phys_addr_t size)
{
	unsigned long tlb_virt;
	phys_addr_t tlb_phys;
	unsigned long offset;
	unsigned long kernel_sz;

	kernel_sz = (unsigned long)_end - (unsigned long)_stext;

	offset = kaslr_choose_location(dt_ptr, size, kernel_sz);
	if (offset == 0)
		return;

	kernstart_virt_addr += offset;
	kernstart_addr += offset;

	is_second_reloc = 1;

	if (offset >= SZ_64M) {
		tlb_virt = round_down(kernstart_virt_addr, SZ_64M);
		tlb_phys = round_down(kernstart_addr, SZ_64M);

		/* Create kernel map to relocate in */
		create_kaslr_tlb_entry(1, tlb_virt, tlb_phys);
	}

	/* Copy the kernel to it's new location and run */
	memcpy((void *)kernstart_virt_addr, (void *)_stext, kernel_sz);
	flush_icache_range(kernstart_virt_addr, kernstart_virt_addr + kernel_sz);

	reloc_kernel_entry(dt_ptr, kernstart_virt_addr);
}