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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
|
// SPDX-License-Identifier: GPL-2.0
#define boot_fmt(fmt) "startup: " fmt
#include <linux/string.h>
#include <linux/elf.h>
#include <asm/page-states.h>
#include <asm/boot_data.h>
#include <asm/extmem.h>
#include <asm/sections.h>
#include <asm/diag288.h>
#include <asm/maccess.h>
#include <asm/machine.h>
#include <asm/sysinfo.h>
#include <asm/cpu_mf.h>
#include <asm/setup.h>
#include <asm/timex.h>
#include <asm/kasan.h>
#include <asm/kexec.h>
#include <asm/sclp.h>
#include <asm/diag.h>
#include <asm/uv.h>
#include <asm/abs_lowcore.h>
#include <asm/physmem_info.h>
#include "decompressor.h"
#include "boot.h"
#include "uv.h"
struct vm_layout __bootdata_preserved(vm_layout);
unsigned long __bootdata_preserved(__abs_lowcore);
unsigned long __bootdata_preserved(__memcpy_real_area);
pte_t *__bootdata_preserved(memcpy_real_ptep);
unsigned long __bootdata_preserved(VMALLOC_START);
unsigned long __bootdata_preserved(VMALLOC_END);
struct page *__bootdata_preserved(vmemmap);
unsigned long __bootdata_preserved(vmemmap_size);
unsigned long __bootdata_preserved(MODULES_VADDR);
unsigned long __bootdata_preserved(MODULES_END);
unsigned long __bootdata_preserved(max_mappable);
unsigned long __bootdata_preserved(page_noexec_mask);
unsigned long __bootdata_preserved(segment_noexec_mask);
unsigned long __bootdata_preserved(region_noexec_mask);
union tod_clock __bootdata_preserved(tod_clock_base);
u64 __bootdata_preserved(clock_comparator_max) = -1UL;
u64 __bootdata_preserved(stfle_fac_list[16]);
struct oldmem_data __bootdata_preserved(oldmem_data);
void error(char *x)
{
boot_emerg("%s\n", x);
boot_emerg(" -- System halted\n");
disabled_wait();
}
static char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE);
static void detect_machine_type(void)
{
struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page;
/* Check current-configuration-level */
if (stsi(NULL, 0, 0, 0) <= 2) {
set_machine_feature(MFEATURE_LPAR);
return;
}
/* Get virtual-machine cpu information. */
if (stsi(vmms, 3, 2, 2) || !vmms->count)
return;
/* Detect known hypervisors */
if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3))
set_machine_feature(MFEATURE_KVM);
else if (!memcmp(vmms->vm[0].cpi, "\xa9\x61\xe5\xd4", 4))
set_machine_feature(MFEATURE_VM);
}
static void detect_diag288(void)
{
/* "BEGIN" in EBCDIC character set */
static const char cmd[] = "\xc2\xc5\xc7\xc9\xd5";
unsigned long action, len;
action = machine_is_vm() ? (unsigned long)cmd : LPARWDT_RESTART;
len = machine_is_vm() ? sizeof(cmd) : 0;
if (__diag288(WDT_FUNC_INIT, MIN_INTERVAL, action, len))
return;
__diag288(WDT_FUNC_CANCEL, 0, 0, 0);
set_machine_feature(MFEATURE_DIAG288);
}
static void detect_diag9c(void)
{
unsigned int cpu;
int rc = 1;
cpu = stap();
asm_inline volatile(
" diag %[cpu],%%r0,0x9c\n"
"0: lhi %[rc],0\n"
"1:\n"
EX_TABLE(0b, 1b)
: [rc] "+d" (rc)
: [cpu] "d" (cpu)
: "cc", "memory");
if (!rc)
set_machine_feature(MFEATURE_DIAG9C);
}
static void reset_tod_clock(void)
{
union tod_clock clk;
if (store_tod_clock_ext_cc(&clk) == 0)
return;
/* TOD clock not running. Set the clock to Unix Epoch. */
if (set_tod_clock(TOD_UNIX_EPOCH) || store_tod_clock_ext_cc(&clk))
disabled_wait();
memset(&tod_clock_base, 0, sizeof(tod_clock_base));
tod_clock_base.tod = TOD_UNIX_EPOCH;
get_lowcore()->last_update_clock = TOD_UNIX_EPOCH;
}
static void detect_facilities(void)
{
if (cpu_has_edat1())
local_ctl_set_bit(0, CR0_EDAT_BIT);
page_noexec_mask = -1UL;
segment_noexec_mask = -1UL;
region_noexec_mask = -1UL;
if (!cpu_has_nx()) {
page_noexec_mask &= ~_PAGE_NOEXEC;
segment_noexec_mask &= ~_SEGMENT_ENTRY_NOEXEC;
region_noexec_mask &= ~_REGION_ENTRY_NOEXEC;
}
if (IS_ENABLED(CONFIG_PCI) && test_facility(153))
set_machine_feature(MFEATURE_PCI_MIO);
reset_tod_clock();
if (test_facility(139) && (tod_clock_base.tod >> 63)) {
/* Enable signed clock comparator comparisons */
set_machine_feature(MFEATURE_SCC);
clock_comparator_max = -1UL >> 1;
local_ctl_set_bit(0, CR0_CLOCK_COMPARATOR_SIGN_BIT);
}
if (test_facility(50) && test_facility(73)) {
set_machine_feature(MFEATURE_TX);
local_ctl_set_bit(0, CR0_TRANSACTIONAL_EXECUTION_BIT);
}
if (cpu_has_vx())
local_ctl_set_bit(0, CR0_VECTOR_BIT);
}
static int cmma_test_essa(void)
{
unsigned long tmp = 0;
int rc = 1;
/* Test ESSA_GET_STATE */
asm_inline volatile(
" .insn rrf,0xb9ab0000,%[tmp],%[tmp],%[cmd],0\n"
"0: lhi %[rc],0\n"
"1:\n"
EX_TABLE(0b, 1b)
: [rc] "+d" (rc), [tmp] "+d" (tmp)
: [cmd] "i" (ESSA_GET_STATE)
: "cc", "memory");
return rc;
}
static void cmma_init(void)
{
if (!cmma_flag)
return;
if (cmma_test_essa()) {
cmma_flag = 0;
return;
}
if (test_facility(147))
cmma_flag = 2;
}
static void setup_lpp(void)
{
get_lowcore()->current_pid = 0;
get_lowcore()->lpp = LPP_MAGIC;
if (test_facility(40))
lpp(&get_lowcore()->lpp);
}
#ifdef CONFIG_KERNEL_UNCOMPRESSED
static unsigned long mem_safe_offset(void)
{
return (unsigned long)_compressed_start;
}
static void deploy_kernel(void *output)
{
void *uncompressed_start = (void *)_compressed_start;
if (output == uncompressed_start)
return;
memmove(output, uncompressed_start, vmlinux.image_size);
memset(uncompressed_start, 0, vmlinux.image_size);
}
#endif
static void rescue_initrd(unsigned long min, unsigned long max)
{
unsigned long old_addr, addr, size;
if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD))
return;
if (!get_physmem_reserved(RR_INITRD, &addr, &size))
return;
if (addr >= min && addr + size <= max)
return;
old_addr = addr;
physmem_free(RR_INITRD);
addr = physmem_alloc_or_die(RR_INITRD, size, 0);
memmove((void *)addr, (void *)old_addr, size);
}
static void copy_bootdata(void)
{
if (__boot_data_end - __boot_data_start != vmlinux.bootdata_size)
error(".boot.data section size mismatch");
memcpy((void *)vmlinux.bootdata_off, __boot_data_start, vmlinux.bootdata_size);
if (__boot_data_preserved_end - __boot_data_preserved_start != vmlinux.bootdata_preserved_size)
error(".boot.preserved.data section size mismatch");
memcpy((void *)vmlinux.bootdata_preserved_off, __boot_data_preserved_start, vmlinux.bootdata_preserved_size);
}
static void kaslr_adjust_relocs(unsigned long min_addr, unsigned long max_addr,
unsigned long offset, unsigned long phys_offset)
{
int *reloc;
long loc;
/* Adjust R_390_64 relocations */
for (reloc = (int *)__vmlinux_relocs_64_start; reloc < (int *)__vmlinux_relocs_64_end; reloc++) {
loc = (long)*reloc + phys_offset;
if (loc < min_addr || loc > max_addr)
error("64-bit relocation outside of kernel!\n");
*(u64 *)loc += offset;
}
}
static void kaslr_adjust_got(unsigned long offset)
{
u64 *entry;
/*
* Adjust GOT entries, except for ones for undefined weak symbols
* that resolved to zero. This also skips the first three reserved
* entries on s390x that are zero.
*/
for (entry = (u64 *)vmlinux.got_start; entry < (u64 *)vmlinux.got_end; entry++) {
if (*entry)
*entry += offset;
}
}
/*
* Merge information from several sources into a single ident_map_size value.
* "ident_map_size" represents the upper limit of physical memory we may ever
* reach. It might not be all online memory, but also include standby (offline)
* memory or memory areas reserved for other means (e.g., memory devices such as
* virtio-mem).
*
* "ident_map_size" could be lower then actual standby/reserved or even online
* memory present, due to limiting factors. We should never go above this limit.
* It is the size of our identity mapping.
*
* Consider the following factors:
* 1. max_physmem_end - end of physical memory online, standby or reserved.
* Always >= end of the last online memory range (get_physmem_online_end()).
* 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the
* kernel is able to support.
* 3. "mem=" kernel command line option which limits physical memory usage.
* 4. OLDMEM_BASE which is a kdump memory limit when the kernel is executed as
* crash kernel.
* 5. "hsa" size which is a memory limit when the kernel is executed during
* zfcp/nvme dump.
*/
static void setup_ident_map_size(unsigned long max_physmem_end)
{
unsigned long hsa_size;
ident_map_size = max_physmem_end;
if (memory_limit)
ident_map_size = min(ident_map_size, memory_limit);
ident_map_size = min(ident_map_size, 1UL << MAX_PHYSMEM_BITS);
#ifdef CONFIG_CRASH_DUMP
if (oldmem_data.start) {
__kaslr_enabled = 0;
ident_map_size = min(ident_map_size, oldmem_data.size);
boot_debug("kdump memory limit: 0x%016lx\n", oldmem_data.size);
} else if (ipl_block_valid && is_ipl_block_dump()) {
__kaslr_enabled = 0;
if (!sclp_early_get_hsa_size(&hsa_size) && hsa_size) {
ident_map_size = min(ident_map_size, hsa_size);
boot_debug("Stand-alone dump limit: 0x%016lx\n", hsa_size);
}
}
#endif
boot_debug("Identity map size: 0x%016lx\n", ident_map_size);
}
#define FIXMAP_SIZE round_up(MEMCPY_REAL_SIZE + ABS_LOWCORE_MAP_SIZE, sizeof(struct lowcore))
static unsigned long get_vmem_size(unsigned long identity_size,
unsigned long vmemmap_size,
unsigned long vmalloc_size,
unsigned long rte_size)
{
unsigned long max_mappable, vsize;
max_mappable = max(identity_size, MAX_DCSS_ADDR);
vsize = round_up(SZ_2G + max_mappable, rte_size) +
round_up(vmemmap_size, rte_size) +
FIXMAP_SIZE + MODULES_LEN + KASLR_LEN;
if (IS_ENABLED(CONFIG_KMSAN))
vsize += MODULES_LEN * 2;
return size_add(vsize, vmalloc_size);
}
static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
{
unsigned long vmemmap_start;
unsigned long kernel_start;
unsigned long asce_limit;
unsigned long rte_size;
unsigned long pages;
unsigned long vsize;
unsigned long vmax;
pages = ident_map_size / PAGE_SIZE;
/* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */
vmemmap_size = SECTION_ALIGN_UP(pages) * sizeof(struct page);
/* choose kernel address space layout: 4 or 3 levels. */
BUILD_BUG_ON(!IS_ALIGNED(TEXT_OFFSET, THREAD_SIZE));
BUILD_BUG_ON(!IS_ALIGNED(__NO_KASLR_START_KERNEL, THREAD_SIZE));
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > _REGION1_SIZE);
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION3_SIZE);
boot_debug("vmem size estimated: 0x%016lx\n", vsize);
if (IS_ENABLED(CONFIG_KASAN) || __NO_KASLR_END_KERNEL > _REGION2_SIZE ||
(vsize > _REGION2_SIZE && kaslr_enabled())) {
asce_limit = _REGION1_SIZE;
if (__NO_KASLR_END_KERNEL > _REGION2_SIZE) {
rte_size = _REGION2_SIZE;
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION2_SIZE);
} else {
rte_size = _REGION3_SIZE;
}
} else {
asce_limit = _REGION2_SIZE;
rte_size = _REGION3_SIZE;
}
/*
* Forcing modules and vmalloc area under the ultravisor
* secure storage limit, so that any vmalloc allocation
* we do could be used to back secure guest storage.
*
* Assume the secure storage limit always exceeds _REGION2_SIZE,
* otherwise asce_limit and rte_size would have been adjusted.
*/
vmax = adjust_to_uv_max(asce_limit);
boot_debug("%d level paging 0x%016lx vmax\n", vmax == _REGION1_SIZE ? 4 : 3, vmax);
#ifdef CONFIG_KASAN
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > KASAN_SHADOW_START);
boot_debug("KASAN shadow area: 0x%016lx-0x%016lx\n", KASAN_SHADOW_START, KASAN_SHADOW_END);
/* force vmalloc and modules below kasan shadow */
vmax = min(vmax, KASAN_SHADOW_START);
#endif
vsize = min(vsize, vmax);
if (kaslr_enabled()) {
unsigned long kernel_end, kaslr_len, slots, pos;
kaslr_len = max(KASLR_LEN, vmax - vsize);
slots = DIV_ROUND_UP(kaslr_len - kernel_size, THREAD_SIZE);
if (get_random(slots, &pos))
pos = 0;
kernel_end = vmax - pos * THREAD_SIZE;
kernel_start = round_down(kernel_end - kernel_size, THREAD_SIZE);
boot_debug("Randomization range: 0x%016lx-0x%016lx\n", vmax - kaslr_len, vmax);
boot_debug("kernel image: 0x%016lx-0x%016lx (kaslr)\n", kernel_start,
kernel_start + kernel_size);
} else if (vmax < __NO_KASLR_END_KERNEL || vsize > __NO_KASLR_END_KERNEL) {
kernel_start = round_down(vmax - kernel_size, THREAD_SIZE);
boot_debug("kernel image: 0x%016lx-0x%016lx (constrained)\n", kernel_start,
kernel_start + kernel_size);
} else {
kernel_start = __NO_KASLR_START_KERNEL;
boot_debug("kernel image: 0x%016lx-0x%016lx (nokaslr)\n", kernel_start,
kernel_start + kernel_size);
}
__kaslr_offset = kernel_start;
boot_debug("__kaslr_offset: 0x%016lx\n", __kaslr_offset);
MODULES_END = round_down(kernel_start, _SEGMENT_SIZE);
MODULES_VADDR = MODULES_END - MODULES_LEN;
VMALLOC_END = MODULES_VADDR;
if (IS_ENABLED(CONFIG_KMSAN))
VMALLOC_END -= MODULES_LEN * 2;
boot_debug("modules area: 0x%016lx-0x%016lx\n", MODULES_VADDR, MODULES_END);
/* allow vmalloc area to occupy up to about 1/2 of the rest virtual space left */
vsize = (VMALLOC_END - FIXMAP_SIZE) / 2;
vsize = round_down(vsize, _SEGMENT_SIZE);
vmalloc_size = min(vmalloc_size, vsize);
if (IS_ENABLED(CONFIG_KMSAN)) {
/* take 2/3 of vmalloc area for KMSAN shadow and origins */
vmalloc_size = round_down(vmalloc_size / 3, _SEGMENT_SIZE);
VMALLOC_END -= vmalloc_size * 2;
}
VMALLOC_START = VMALLOC_END - vmalloc_size;
boot_debug("vmalloc area: 0x%016lx-0x%016lx\n", VMALLOC_START, VMALLOC_END);
__memcpy_real_area = round_down(VMALLOC_START - MEMCPY_REAL_SIZE, PAGE_SIZE);
boot_debug("memcpy real area: 0x%016lx-0x%016lx\n", __memcpy_real_area,
__memcpy_real_area + MEMCPY_REAL_SIZE);
__abs_lowcore = round_down(__memcpy_real_area - ABS_LOWCORE_MAP_SIZE,
sizeof(struct lowcore));
boot_debug("abs lowcore: 0x%016lx-0x%016lx\n", __abs_lowcore,
__abs_lowcore + ABS_LOWCORE_MAP_SIZE);
/* split remaining virtual space between 1:1 mapping & vmemmap array */
pages = __abs_lowcore / (PAGE_SIZE + sizeof(struct page));
pages = SECTION_ALIGN_UP(pages);
/* keep vmemmap_start aligned to a top level region table entry */
vmemmap_start = round_down(__abs_lowcore - pages * sizeof(struct page), rte_size);
/* make sure identity map doesn't overlay with vmemmap */
ident_map_size = min(ident_map_size, vmemmap_start);
vmemmap_size = SECTION_ALIGN_UP(ident_map_size / PAGE_SIZE) * sizeof(struct page);
/* make sure vmemmap doesn't overlay with absolute lowcore area */
if (vmemmap_start + vmemmap_size > __abs_lowcore) {
vmemmap_size = SECTION_ALIGN_DOWN(ident_map_size / PAGE_SIZE) * sizeof(struct page);
ident_map_size = vmemmap_size / sizeof(struct page) * PAGE_SIZE;
}
vmemmap = (struct page *)vmemmap_start;
/* maximum address for which linear mapping could be created (DCSS, memory) */
BUILD_BUG_ON(MAX_DCSS_ADDR > (1UL << MAX_PHYSMEM_BITS));
max_mappable = max(ident_map_size, MAX_DCSS_ADDR);
max_mappable = min(max_mappable, vmemmap_start);
#ifdef CONFIG_RANDOMIZE_IDENTITY_BASE
__identity_base = round_down(vmemmap_start - max_mappable, rte_size);
#endif
boot_debug("identity map: 0x%016lx-0x%016lx\n", __identity_base,
__identity_base + ident_map_size);
return asce_limit;
}
/*
* This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's.
*/
static void clear_bss_section(unsigned long kernel_start)
{
memset((void *)kernel_start + vmlinux.image_size, 0, vmlinux.bss_size);
}
/*
* Set vmalloc area size to an 8th of (potential) physical memory
* size, unless size has been set by kernel command line parameter.
*/
static void setup_vmalloc_size(void)
{
unsigned long size;
if (vmalloc_size_set)
return;
size = round_up(ident_map_size / 8, _SEGMENT_SIZE);
vmalloc_size = max(size, vmalloc_size);
}
static void kaslr_adjust_vmlinux_info(long offset)
{
vmlinux.bootdata_off += offset;
vmlinux.bootdata_preserved_off += offset;
vmlinux.got_start += offset;
vmlinux.got_end += offset;
vmlinux.init_mm_off += offset;
vmlinux.swapper_pg_dir_off += offset;
vmlinux.invalid_pg_dir_off += offset;
vmlinux.alt_instructions += offset;
vmlinux.alt_instructions_end += offset;
#ifdef CONFIG_KASAN
vmlinux.kasan_early_shadow_page_off += offset;
vmlinux.kasan_early_shadow_pte_off += offset;
vmlinux.kasan_early_shadow_pmd_off += offset;
vmlinux.kasan_early_shadow_pud_off += offset;
vmlinux.kasan_early_shadow_p4d_off += offset;
#endif
}
void startup_kernel(void)
{
unsigned long vmlinux_size = vmlinux.image_size + vmlinux.bss_size;
unsigned long nokaslr_text_lma, text_lma = 0, amode31_lma = 0;
unsigned long kernel_size = TEXT_OFFSET + vmlinux_size;
unsigned long kaslr_large_page_offset;
unsigned long max_physmem_end;
unsigned long asce_limit;
unsigned long safe_addr;
psw_t psw;
setup_lpp();
store_ipl_parmblock();
uv_query_info();
setup_boot_command_line();
parse_boot_command_line();
/*
* Non-randomized kernel physical start address must be _SEGMENT_SIZE
* aligned (see blow).
*/
nokaslr_text_lma = ALIGN(mem_safe_offset(), _SEGMENT_SIZE);
safe_addr = PAGE_ALIGN(nokaslr_text_lma + vmlinux_size);
/*
* Reserve decompressor memory together with decompression heap,
* buffer and memory which might be occupied by uncompressed kernel
* (if KASLR is off or failed).
*/
physmem_reserve(RR_DECOMPRESSOR, 0, safe_addr);
if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && parmarea.initrd_size)
physmem_reserve(RR_INITRD, parmarea.initrd_start, parmarea.initrd_size);
oldmem_data.start = parmarea.oldmem_base;
oldmem_data.size = parmarea.oldmem_size;
read_ipl_report();
sclp_early_read_info();
sclp_early_detect_machine_features();
detect_facilities();
detect_diag9c();
detect_machine_type();
/* detect_diag288() needs machine type */
detect_diag288();
cmma_init();
sanitize_prot_virt_host();
max_physmem_end = detect_max_physmem_end();
setup_ident_map_size(max_physmem_end);
setup_vmalloc_size();
asce_limit = setup_kernel_memory_layout(kernel_size);
/* got final ident_map_size, physmem allocations could be performed now */
physmem_set_usable_limit(ident_map_size);
detect_physmem_online_ranges(max_physmem_end);
save_ipl_cert_comp_list();
rescue_initrd(safe_addr, ident_map_size);
/*
* __kaslr_offset_phys must be _SEGMENT_SIZE aligned, so the lower
* 20 bits (the offset within a large page) are zero. Copy the last
* 20 bits of __kaslr_offset, which is THREAD_SIZE aligned, to
* __kaslr_offset_phys.
*
* With this the last 20 bits of __kaslr_offset_phys and __kaslr_offset
* are identical, which is required to allow for large mappings of the
* kernel image.
*/
kaslr_large_page_offset = __kaslr_offset & ~_SEGMENT_MASK;
if (kaslr_enabled()) {
unsigned long size = vmlinux_size + kaslr_large_page_offset;
text_lma = randomize_within_range(size, _SEGMENT_SIZE, TEXT_OFFSET, ident_map_size);
}
if (!text_lma)
text_lma = nokaslr_text_lma;
text_lma |= kaslr_large_page_offset;
/*
* [__kaslr_offset_phys..__kaslr_offset_phys + TEXT_OFFSET] region is
* never accessed via the kernel image mapping as per the linker script:
*
* . = TEXT_OFFSET;
*
* Therefore, this region could be used for something else and does
* not need to be reserved. See how it is skipped in setup_vmem().
*/
__kaslr_offset_phys = text_lma - TEXT_OFFSET;
kaslr_adjust_vmlinux_info(__kaslr_offset_phys);
physmem_reserve(RR_VMLINUX, text_lma, vmlinux_size);
deploy_kernel((void *)text_lma);
/* vmlinux decompression is done, shrink reserved low memory */
physmem_reserve(RR_DECOMPRESSOR, 0, (unsigned long)_decompressor_end);
/*
* In case KASLR is enabled the randomized location of .amode31
* section might overlap with .vmlinux.relocs section. To avoid that
* the below randomize_within_range() could have been called with
* __vmlinux_relocs_64_end as the lower range address. However,
* .amode31 section is written to by the decompressed kernel - at
* that time the contents of .vmlinux.relocs is not needed anymore.
* Conversely, .vmlinux.relocs is read only by the decompressor, even
* before the kernel started. Therefore, in case the two sections
* overlap there is no risk of corrupting any data.
*/
if (kaslr_enabled()) {
unsigned long amode31_min;
amode31_min = (unsigned long)_decompressor_end;
amode31_lma = randomize_within_range(vmlinux.amode31_size, PAGE_SIZE, amode31_min, SZ_2G);
}
if (!amode31_lma)
amode31_lma = text_lma - vmlinux.amode31_size;
physmem_reserve(RR_AMODE31, amode31_lma, vmlinux.amode31_size);
/*
* The order of the following operations is important:
*
* - kaslr_adjust_relocs() must follow clear_bss_section() to establish
* static memory references to data in .bss to be used by setup_vmem()
* (i.e init_mm.pgd)
*
* - setup_vmem() must follow kaslr_adjust_relocs() to be able using
* static memory references to data in .bss (i.e init_mm.pgd)
*
* - copy_bootdata() must follow setup_vmem() to propagate changes
* to bootdata made by setup_vmem()
*/
clear_bss_section(text_lma);
kaslr_adjust_relocs(text_lma, text_lma + vmlinux.image_size,
__kaslr_offset, __kaslr_offset_phys);
kaslr_adjust_got(__kaslr_offset);
setup_vmem(__kaslr_offset, __kaslr_offset + kernel_size, asce_limit);
dump_physmem_reserved();
copy_bootdata();
__apply_alternatives((struct alt_instr *)_vmlinux_info.alt_instructions,
(struct alt_instr *)_vmlinux_info.alt_instructions_end,
ALT_CTX_EARLY);
/*
* Save KASLR offset for early dumps, before vmcore_info is set.
* Mark as uneven to distinguish from real vmcore_info pointer.
*/
get_lowcore()->vmcore_info = __kaslr_offset_phys ? __kaslr_offset_phys | 0x1UL : 0;
/*
* Jump to the decompressed kernel entry point and switch DAT mode on.
*/
psw.addr = __kaslr_offset + vmlinux.entry;
psw.mask = PSW_KERNEL_BITS;
boot_debug("Starting kernel at: 0x%016lx\n", psw.addr);
__load_psw(psw);
}
|