blob: 959d9b8d48454885f2e43c83742f648c13669378 [file] [log] [blame]
Mark Salter3c7f2552014-04-15 22:47:52 -04001/*
2 * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
3 *
4 * This file implements the EFI boot stub for the arm64 kernel.
5 * Adapted from ARM version by Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
Ard Biesheuvel94c47d42017-08-18 20:49:36 +010012
13/*
14 * To prevent the compiler from emitting GOT-indirected (and thus absolute)
15 * references to the section markers, override their visibility as 'hidden'
16 */
17#pragma GCC visibility push(hidden)
18#include <asm/sections.h>
19#pragma GCC visibility pop
20
Mark Salter3c7f2552014-04-15 22:47:52 -040021#include <linux/efi.h>
Ard Biesheuvela13b0072014-07-02 14:54:41 +020022#include <asm/efi.h>
Ard Biesheuvel42b55732016-02-17 12:36:02 +000023#include <asm/sysreg.h>
Mark Salter3c7f2552014-04-15 22:47:52 -040024
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +010025#include "efistub.h"
26
27extern bool __nokaslr;
28
Ard Biesheuvel42b55732016-02-17 12:36:02 +000029efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)
30{
31 u64 tg;
32
33 /* UEFI mandates support for 4 KB granularity, no need to check */
34 if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
35 return EFI_SUCCESS;
36
37 tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf;
38 if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) {
39 if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
40 pr_efi_err(sys_table_arg, "This 64 KB granular kernel is not supported by your CPU\n");
41 else
42 pr_efi_err(sys_table_arg, "This 16 KB granular kernel is not supported by your CPU\n");
43 return EFI_UNSUPPORTED;
44 }
45 return EFI_SUCCESS;
46}
Mark Salter3c7f2552014-04-15 22:47:52 -040047
Ard Biesheuveldae31fd2016-02-17 12:35:57 +000048efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,
49 unsigned long *image_addr,
50 unsigned long *image_size,
51 unsigned long *reserve_addr,
52 unsigned long *reserve_size,
53 unsigned long dram_base,
54 efi_loaded_image_t *image)
Mark Salter3c7f2552014-04-15 22:47:52 -040055{
56 efi_status_t status;
57 unsigned long kernel_size, kernel_memsize = 0;
Ard Biesheuvele38457c2015-07-24 12:38:27 +010058 void *old_image_addr = (void *)*image_addr;
Ard Biesheuvel73effcc2015-10-29 15:07:25 +010059 unsigned long preferred_offset;
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +010060 u64 phys_seed = 0;
61
62 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
63 if (!__nokaslr) {
64 status = efi_get_random_bytes(sys_table_arg,
65 sizeof(phys_seed),
66 (u8 *)&phys_seed);
67 if (status == EFI_NOT_FOUND) {
68 pr_efi(sys_table_arg, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
69 } else if (status != EFI_SUCCESS) {
70 pr_efi_err(sys_table_arg, "efi_get_random_bytes() failed\n");
71 return status;
72 }
73 } else {
74 pr_efi(sys_table_arg, "KASLR disabled on kernel command line\n");
75 }
76 }
Ard Biesheuvel73effcc2015-10-29 15:07:25 +010077
78 /*
79 * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond
80 * a 2 MB aligned base, which itself may be lower than dram_base, as
81 * long as the resulting offset equals or exceeds it.
82 */
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +010083 preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET;
Ard Biesheuvel73effcc2015-10-29 15:07:25 +010084 if (preferred_offset < dram_base)
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +010085 preferred_offset += MIN_KIMG_ALIGN;
Mark Salter3c7f2552014-04-15 22:47:52 -040086
Mark Salter3c7f2552014-04-15 22:47:52 -040087 kernel_size = _edata - _text;
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +010088 kernel_memsize = kernel_size + (_end - _edata);
Ard Biesheuvele38457c2015-07-24 12:38:27 +010089
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +010090 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
Ard Biesheuvele38457c2015-07-24 12:38:27 +010091 /*
Ard Biesheuvel6f26b362016-04-18 17:09:48 +020092 * If CONFIG_DEBUG_ALIGN_RODATA is not set, produce a
93 * displacement in the interval [0, MIN_KIMG_ALIGN) that
94 * is a multiple of the minimal segment alignment (SZ_64K)
95 */
96 u32 mask = (MIN_KIMG_ALIGN - 1) & ~(SZ_64K - 1);
97 u32 offset = !IS_ENABLED(CONFIG_DEBUG_ALIGN_RODATA) ?
98 (phys_seed >> 32) & mask : TEXT_OFFSET;
99
100 /*
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100101 * If KASLR is enabled, and we have some randomness available,
102 * locate the kernel at a randomized offset in physical memory.
103 */
Ard Biesheuvel6f26b362016-04-18 17:09:48 +0200104 *reserve_size = kernel_memsize + offset;
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100105 status = efi_random_alloc(sys_table_arg, *reserve_size,
106 MIN_KIMG_ALIGN, reserve_addr,
Ard Biesheuvel6f26b362016-04-18 17:09:48 +0200107 (u32)phys_seed);
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100108
Ard Biesheuvel6f26b362016-04-18 17:09:48 +0200109 *image_addr = *reserve_addr + offset;
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100110 } else {
111 /*
112 * Else, try a straight allocation at the preferred offset.
Ard Biesheuvele38457c2015-07-24 12:38:27 +0100113 * This will work around the issue where, if dram_base == 0x0,
114 * efi_low_alloc() refuses to allocate at 0x0 (to prevent the
115 * address of the allocation to be mistaken for a FAIL return
116 * value or a NULL pointer). It will also ensure that, on
117 * platforms where the [dram_base, dram_base + TEXT_OFFSET)
118 * interval is partially occupied by the firmware (like on APM
119 * Mustang), we can still place the kernel at the address
120 * 'dram_base + TEXT_OFFSET'.
121 */
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100122 if (*image_addr == preferred_offset)
123 return EFI_SUCCESS;
Ard Biesheuvele38457c2015-07-24 12:38:27 +0100124
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100125 *image_addr = *reserve_addr = preferred_offset;
126 *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN);
127
128 status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS,
129 EFI_LOADER_DATA,
130 *reserve_size / EFI_PAGE_SIZE,
131 (efi_physical_addr_t *)reserve_addr);
Mark Salter3c7f2552014-04-15 22:47:52 -0400132 }
133
Ard Biesheuvel2b5fe072016-01-26 14:48:29 +0100134 if (status != EFI_SUCCESS) {
135 *reserve_size = kernel_memsize + TEXT_OFFSET;
136 status = efi_low_alloc(sys_table_arg, *reserve_size,
137 MIN_KIMG_ALIGN, reserve_addr);
138
139 if (status != EFI_SUCCESS) {
140 pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
141 *reserve_size = 0;
142 return status;
143 }
144 *image_addr = *reserve_addr + TEXT_OFFSET;
145 }
146 memcpy((void *)*image_addr, old_image_addr, kernel_size);
Mark Salter3c7f2552014-04-15 22:47:52 -0400147
148 return EFI_SUCCESS;
149}