Blame kaslr_helper.c

Packit Service 501009
/*
Packit Service 501009
 * kaslr_helper - helper for kaslr offset calculation
Packit Service 501009
 *
Packit Service 501009
 * Copyright (c) 2011 FUJITSU LIMITED
Packit Service 501009
 * Copyright (c) 2018 Red Hat Inc.
Packit Service 501009
 *
Packit Service 501009
 * This program is free software; you can redistribute it and/or modify
Packit Service 501009
 * it under the terms of the GNU General Public License as published by
Packit Service 501009
 * the Free Software Foundation; either version 2 of the License, or
Packit Service 501009
 * (at your option) any later version.
Packit Service 501009
 *
Packit Service 501009
 * This program is distributed in the hope that it will be useful,
Packit Service 501009
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 501009
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 501009
 * GNU General Public License for more details.
Packit Service 501009
 *
Packit Service 501009
 * Authors: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Packit Service 501009
 *          INDOH Takao <indou.takao@jp.fujitsu.com>
Packit Service 501009
 *          Sergio Lopez <slp@redhat.com>
Packit Service 501009
 */
Packit Service 501009
Packit Service 501009
#include "defs.h"
Packit Service 501009
#include <elf.h>
Packit Service 501009
#include <inttypes.h>
Packit Service 501009
Packit Service 501009
#ifdef X86_64
Packit Service 501009
/*
Packit Service 501009
 * Get address of vector0 interrupt handler (Devide Error) from Interrupt
Packit Service 501009
 * Descriptor Table.
Packit Service 501009
 */
Packit Service 501009
static ulong
Packit Service 501009
get_vec0_addr(ulong idtr)
Packit Service 501009
{
Packit Service 501009
	struct gate_struct64 {
Packit Service 501009
		uint16_t offset_low;
Packit Service 501009
		uint16_t segment;
Packit Service 501009
		uint32_t ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
Packit Service 501009
		uint16_t offset_middle;
Packit Service 501009
		uint32_t offset_high;
Packit Service 501009
		uint32_t zero1;
Packit Service 501009
	} __attribute__((packed)) gate;
Packit Service 501009
Packit Service 501009
	readmem(idtr, PHYSADDR, &gate, sizeof(gate), "idt_table", FAULT_ON_ERROR);
Packit Service 501009
Packit Service 501009
	return ((ulong)gate.offset_high << 32)
Packit Service 501009
		+ ((ulong)gate.offset_middle << 16)
Packit Service 501009
		+ gate.offset_low;
Packit Service 501009
}
Packit Service 501009
Packit Service 501009
/*
Packit Service 501009
 * Parse a string of [size[KMG] ]offset[KMG]
Packit Service 501009
 * Import from Linux kernel(lib/cmdline.c)
Packit Service 501009
 */
Packit Service 501009
static ulong
Packit Service 501009
memparse(char *ptr, char **retptr)
Packit Service 501009
{
Packit Service 501009
	char *endptr;
Packit Service 501009
Packit Service 501009
	unsigned long long ret = strtoull(ptr, &endptr, 0);
Packit Service 501009
Packit Service 501009
	switch (*endptr) {
Packit Service 501009
	case 'E':
Packit Service 501009
	case 'e':
Packit Service 501009
		ret <<= 10;
Packit Service 501009
	case 'P':
Packit Service 501009
	case 'p':
Packit Service 501009
		ret <<= 10;
Packit Service 501009
	case 'T':
Packit Service 501009
	case 't':
Packit Service 501009
		ret <<= 10;
Packit Service 501009
	case 'G':
Packit Service 501009
	case 'g':
Packit Service 501009
		ret <<= 10;
Packit Service 501009
	case 'M':
Packit Service 501009
	case 'm':
Packit Service 501009
		ret <<= 10;
Packit Service 501009
	case 'K':
Packit Service 501009
	case 'k':
Packit Service 501009
		ret <<= 10;
Packit Service 501009
		endptr++;
Packit Service 501009
	default:
Packit Service 501009
		break;
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (retptr)
Packit Service 501009
		*retptr = endptr;
Packit Service 501009
Packit Service 501009
	return ret;
Packit Service 501009
}
Packit Service 501009
Packit Service 501009
/*
Packit Service 501009
 * Find "elfcorehdr=" in the boot parameter of kernel and return the address
Packit Service 501009
 * of elfcorehdr.
Packit Service 501009
 */
Packit Service 501009
static ulong
Packit Service 501009
get_elfcorehdr(ulong kaslr_offset)
Packit Service 501009
{
Packit Service 501009
	char cmdline[BUFSIZE], *ptr;
Packit Service 501009
	ulong cmdline_vaddr;
Packit Service 501009
	ulong cmdline_paddr;
Packit Service 501009
	ulong buf_vaddr, buf_paddr;
Packit Service 501009
	char *end;
Packit Service 501009
	ulong elfcorehdr_addr = 0, elfcorehdr_size = 0;
Packit Service 501009
	int verbose = CRASHDEBUG(1)? 1: 0;
Packit Service 501009
Packit Service 501009
	cmdline_vaddr = st->saved_command_line_vmlinux + kaslr_offset;
Packit Service 501009
	if (!kvtop(NULL, cmdline_vaddr, &cmdline_paddr, verbose))
Packit Service 501009
		return 0;
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "cmdline vaddr=%lx\n", cmdline_vaddr);
Packit Service 501009
		fprintf(fp, "cmdline paddr=%lx\n", cmdline_paddr);
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (!readmem(cmdline_paddr, PHYSADDR, &buf_vaddr, sizeof(ulong),
Packit Service 501009
		     "saved_command_line", RETURN_ON_ERROR))
Packit Service 501009
		return 0;
Packit Service 501009
Packit Service 501009
	if (!kvtop(NULL, buf_vaddr, &buf_paddr, verbose))
Packit Service 501009
		return 0;
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "cmdline buffer vaddr=%lx\n", buf_vaddr);
Packit Service 501009
		fprintf(fp, "cmdline buffer paddr=%lx\n", buf_paddr);
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	memset(cmdline, 0, BUFSIZE);
Packit Service 501009
	if (!readmem(buf_paddr, PHYSADDR, cmdline, BUFSIZE,
Packit Service 501009
		     "saved_command_line", RETURN_ON_ERROR))
Packit Service 501009
		return 0;
Packit Service 501009
Packit Service 501009
	ptr = strstr(cmdline, "elfcorehdr=");
Packit Service 501009
	if (!ptr)
Packit Service 501009
		return 0;
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1))
Packit Service 501009
		fprintf(fp, "2nd kernel detected\n");
Packit Service 501009
Packit Service 501009
	ptr += strlen("elfcorehdr=");
Packit Service 501009
	elfcorehdr_addr = memparse(ptr, &end;;
Packit Service 501009
	if (*end == '@') {
Packit Service 501009
		elfcorehdr_size = elfcorehdr_addr;
Packit Service 501009
		elfcorehdr_addr = memparse(end + 1, &end;;
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "elfcorehdr_addr=%lx\n", elfcorehdr_addr);
Packit Service 501009
		fprintf(fp, "elfcorehdr_size=%lx\n", elfcorehdr_size);
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	return elfcorehdr_addr;
Packit Service 501009
}
Packit Service 501009
Packit Service 501009
 /*
Packit Service 501009
  * Get vmcoreinfo from elfcorehdr.
Packit Service 501009
  * Some codes are imported from Linux kernel(fs/proc/vmcore.c)
Packit Service 501009
  */
Packit Service 501009
static int
Packit Service 501009
get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len)
Packit Service 501009
{
Packit Service 501009
	unsigned char e_ident[EI_NIDENT];
Packit Service 501009
	Elf64_Ehdr ehdr;
Packit Service 501009
	Elf64_Phdr phdr;
Packit Service 501009
	Elf64_Nhdr nhdr;
Packit Service 501009
	ulong ptr;
Packit Service 501009
	ulong nhdr_offset = 0;
Packit Service 501009
	int i;
Packit Service 501009
Packit Service 501009
	if (!readmem(elfcorehdr, PHYSADDR, e_ident, EI_NIDENT,
Packit Service 501009
		     "EI_NIDENT", RETURN_ON_ERROR))
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	if (e_ident[EI_CLASS] != ELFCLASS64) {
Packit Service 501009
		error(INFO, "Only ELFCLASS64 is supportd\n");
Packit Service 501009
		return FALSE;
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (!readmem(elfcorehdr, PHYSADDR, &ehdr, sizeof(ehdr),
Packit Service 501009
			"Elf64_Ehdr", RETURN_ON_ERROR))
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	/* Sanity Check */
Packit Service 501009
	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
Packit Service 501009
		(ehdr.e_type != ET_CORE) ||
Packit Service 501009
		ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
Packit Service 501009
		ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
Packit Service 501009
		ehdr.e_version != EV_CURRENT ||
Packit Service 501009
		ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
Packit Service 501009
		ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
Packit Service 501009
		ehdr.e_phnum == 0) {
Packit Service 501009
		error(INFO, "Invalid elf header\n");
Packit Service 501009
		return FALSE;
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	ptr = elfcorehdr + ehdr.e_phoff;
Packit Service 501009
	for (i = 0; i < ehdr.e_phnum; i++) {
Packit Service 501009
		ulong offset;
Packit Service 501009
		char name[16];
Packit Service 501009
Packit Service 501009
		if (!readmem(ptr, PHYSADDR, &phdr, sizeof(phdr),
Packit Service 501009
				"Elf64_Phdr", RETURN_ON_ERROR))
Packit Service 501009
			return FALSE;
Packit Service 501009
Packit Service 501009
		ptr += sizeof(phdr);
Packit Service 501009
		if (phdr.p_type != PT_NOTE)
Packit Service 501009
			continue;
Packit Service 501009
Packit Service 501009
		offset = phdr.p_offset;
Packit Service 501009
		if (!readmem(offset, PHYSADDR, &nhdr, sizeof(nhdr),
Packit Service 501009
				"Elf64_Nhdr", RETURN_ON_ERROR))
Packit Service 501009
			return FALSE;
Packit Service 501009
Packit Service 501009
		offset += DIV_ROUND_UP(sizeof(Elf64_Nhdr), sizeof(Elf64_Word))*
Packit Service 501009
			  sizeof(Elf64_Word);
Packit Service 501009
		memset(name, 0, sizeof(name));
Packit Service 501009
		if (!readmem(offset, PHYSADDR, name, sizeof(name),
Packit Service 501009
				"Elf64_Nhdr name", RETURN_ON_ERROR))
Packit Service 501009
			return FALSE;
Packit Service 501009
Packit Service 501009
		if(!strcmp(name, "VMCOREINFO")) {
Packit Service 501009
			nhdr_offset = offset;
Packit Service 501009
			break;
Packit Service 501009
		}
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (!nhdr_offset)
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	*addr = nhdr_offset +
Packit Service 501009
		DIV_ROUND_UP(nhdr.n_namesz, sizeof(Elf64_Word))*
Packit Service 501009
		sizeof(Elf64_Word);
Packit Service 501009
	*len = nhdr.n_descsz;
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "vmcoreinfo addr=%lx\n", *addr);
Packit Service 501009
		fprintf(fp, "vmcoreinfo len=%d\n", *len);
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	return TRUE;
Packit Service 501009
}
Packit Service 501009
Packit Service 501009
static int
Packit Service 501009
qemu_get_cr3_idtr(ulong *cr3, ulong *idtr)
Packit Service 501009
{
Packit Service 501009
	QEMUCPUState *cpustat;
Packit Service 501009
Packit Service 501009
	if (DISKDUMP_DUMPFILE()) {
Packit Service 501009
		cpustat = diskdump_get_qemucpustate(0);
Packit Service 501009
	} else if (KDUMP_DUMPFILE()) {
Packit Service 501009
		cpustat = kdump_get_qemucpustate(0);
Packit Service 501009
	} else {
Packit Service 501009
		return FALSE;
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (!cpustat) {
Packit Service 501009
		return FALSE;
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	*cr3 = cpustat->cr[3];
Packit Service 501009
	*idtr = cpustat->idt.base;
Packit Service 501009
Packit Service 501009
	return TRUE;
Packit Service 501009
}
Packit Service 501009
Packit Service 501009
/*
Packit Service 501009
 * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd kernel.
Packit Service 501009
 * If we are in 2nd kernel, get kaslr_offset/phys_base from vmcoreinfo.
Packit Service 501009
 *
Packit Service 501009
 * 1. Get command line and try to retrieve "elfcorehdr=" boot parameter
Packit Service 501009
 * 2. If "elfcorehdr=" is not found in command line, we are in 1st kernel.
Packit Service 501009
 *    There is nothing to do.
Packit Service 501009
 * 3. If "elfcorehdr=" is found, we are in 2nd kernel. Find vmcoreinfo
Packit Service 501009
 *    using "elfcorehdr=" and retrieve kaslr_offset/phys_base from vmcoreinfo.
Packit Service 501009
 */
Packit Service 501009
static int
Packit Service 501009
get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset,
Packit Service 501009
		                 ulong *kaslr_offset, ulong *phys_base)
Packit Service 501009
{
Packit Service 501009
	ulong elfcorehdr_addr = 0;
Packit Service 501009
	ulong vmcoreinfo_addr;
Packit Service 501009
	int vmcoreinfo_len;
Packit Service 501009
	char *buf, *pos;
Packit Service 501009
	int ret = FALSE;
Packit Service 501009
Packit Service 501009
	/* Find "elfcorehdr=" in the kernel boot parameter */
Packit Service 501009
	elfcorehdr_addr = get_elfcorehdr(orig_kaslr_offset);
Packit Service 501009
	if (!elfcorehdr_addr)
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	/* Get vmcoreinfo from the address of "elfcorehdr=" */
Packit Service 501009
	if (!get_vmcoreinfo(elfcorehdr_addr, &vmcoreinfo_addr, &vmcoreinfo_len))
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	if (!vmcoreinfo_len)
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1))
Packit Service 501009
		fprintf(fp, "Find vmcoreinfo in kdump memory\n");
Packit Service 501009
Packit Service 501009
	buf = GETBUF(vmcoreinfo_len);
Packit Service 501009
	if (!readmem(vmcoreinfo_addr, PHYSADDR, buf, vmcoreinfo_len,
Packit Service 501009
			"vmcoreinfo", RETURN_ON_ERROR))
Packit Service 501009
		goto quit;
Packit Service 501009
Packit Service 501009
	/* Get phys_base form vmcoreinfo */
Packit Service 501009
	pos = strstr(buf, "NUMBER(phys_base)=");
Packit Service 501009
	if (!pos)
Packit Service 501009
		goto quit;
Packit Service 501009
	*phys_base  = strtoull(pos + strlen("NUMBER(phys_base)="), NULL, 0);
Packit Service 501009
Packit Service 501009
	/* Get kaslr_offset form vmcoreinfo */
Packit Service 501009
	pos = strstr(buf, "KERNELOFFSET=");
Packit Service 501009
	if (!pos)
Packit Service 501009
		goto quit;
Packit Service 501009
	*kaslr_offset = strtoull(pos + strlen("KERNELOFFSET="), NULL, 16);
Packit Service 501009
Packit Service 501009
	ret = TRUE;
Packit Service 501009
Packit Service 501009
quit:
Packit Service 501009
	FREEBUF(buf);
Packit Service 501009
	return ret;
Packit Service 501009
}
Packit Service 501009
Packit Service 501009
/*
Packit Service 501009
 * Calculate kaslr_offset and phys_base
Packit Service 501009
 *
Packit Service 501009
 * kaslr_offset:
Packit Service 501009
 *   The difference between original address in System.map or vmlinux and
Packit Service 501009
 *   actual address placed randomly by kaslr feature. To be more accurate,
Packit Service 501009
 *   kaslr_offset = actual address  - original address
Packit Service 501009
 *
Packit Service 501009
 * phys_base:
Packit Service 501009
 *   Physical address where the kerenel is placed. In other words, it's a
Packit Service 501009
 *   physical address of __START_KERNEL_map. This is also decided randomly by
Packit Service 501009
 *   kaslr.
Packit Service 501009
 *
Packit Service 501009
 * kaslr offset and phys_base are calculated as follows:
Packit Service 501009
 *
Packit Service 501009
 * kaslr_offset:
Packit Service 501009
 * 1) Get IDTR and CR3 value from the dump header.
Packit Service 501009
 * 2) Get a virtual address of IDT from IDTR value
Packit Service 501009
 *    --- (A)
Packit Service 501009
 * 3) Translate (A) to physical address using CR3, the upper 52 bits
Packit Service 501009
 *    of which points a top of page table.
Packit Service 501009
 *    --- (B)
Packit Service 501009
 * 4) Get an address of vector0 (Devide Error) interrupt handler from
Packit Service 501009
 *    IDT, which are pointed by (B).
Packit Service 501009
 *    --- (C)
Packit Service 501009
 * 5) Get an address of symbol "divide_error" form vmlinux
Packit Service 501009
 *    --- (D)
Packit Service 501009
 *
Packit Service 501009
 * Now we have two addresses:
Packit Service 501009
 * (C)-> Actual address of "divide_error"
Packit Service 501009
 * (D)-> Original address of "divide_error" in the vmlinux
Packit Service 501009
 *
Packit Service 501009
 * kaslr_offset can be calculated by the difference between these two
Packit Service 501009
 * value.
Packit Service 501009
 *
Packit Service 501009
 * phys_base;
Packit Service 501009
 * 1) Get IDT virtual address from vmlinux
Packit Service 501009
 *    --- (E)
Packit Service 501009
 *
Packit Service 501009
 * So phys_base can be calculated using relationship of directly mapped
Packit Service 501009
 * address.
Packit Service 501009
 *
Packit Service 501009
 * phys_base =
Packit Service 501009
 *   Physical address(B) -
Packit Service 501009
 *   (Virtual address(E) + kaslr_offset - __START_KERNEL_map)
Packit Service 501009
 *
Packit Service 501009
 * Note that the address (A) cannot be used instead of (E) because (A) is
Packit Service 501009
 * not direct map address, it's a fixed map address.
Packit Service 501009
 *
Packit Service 501009
 * This solution works in most every case, but does not work in the
Packit Service 501009
 * following case.
Packit Service 501009
 *
Packit Service 501009
 * 1) If the dump is captured on early stage of kernel boot, IDTR points
Packit Service 501009
 *    early IDT table(early_idts) instead of normal IDT(idt_table).
Packit Service 501009
 * 2) If the dump is captured whle kdump is working, IDTR points
Packit Service 501009
 *    IDT table of 2nd kernel, not 1st kernel.
Packit Service 501009
 *
Packit Service 501009
 * Current implementation does not support the case 1), need
Packit Service 501009
 * enhancement in the future. For the case 2), get kaslr_offset and
Packit Service 501009
 * phys_base as follows.
Packit Service 501009
 *
Packit Service 501009
 * 1) Get kaslr_offset and phys_base using the above solution.
Packit Service 501009
 * 2) Get kernel boot parameter from "saved_command_line"
Packit Service 501009
 * 3) If "elfcorehdr=" is not included in boot parameter, we are in the
Packit Service 501009
 *    first kernel, nothing to do any more.
Packit Service 501009
 * 4) If "elfcorehdr=" is included in boot parameter, we are in the 2nd
Packit Service 501009
 *    kernel. Retrieve vmcoreinfo from address of "elfcorehdr=" and
Packit Service 501009
 *    get kaslr_offset and phys_base from vmcoreinfo.
Packit Service 501009
 */
Packit Service 501009
#define PTI_USER_PGTABLE_BIT	PAGE_SHIFT
Packit Service 501009
#define PTI_USER_PGTABLE_MASK	(1 << PTI_USER_PGTABLE_BIT)
Packit Service 501009
#define CR3_PCID_MASK		0xFFFull
Packit Service 501009
int
Packit Service 501009
calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base)
Packit Service 501009
{
Packit Service 501009
	uint64_t cr3 = 0, idtr = 0, pgd = 0, idtr_paddr;
Packit Service 501009
	ulong divide_error_vmcore;
Packit Service 501009
	ulong kaslr_offset_kdump, phys_base_kdump;
Packit Service 501009
	int ret = FALSE;
Packit Service 501009
	int verbose = CRASHDEBUG(1)? 1: 0;
Packit Service 501009
Packit Service 501009
	if (!machine_type("X86_64"))
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	if (SADUMP_DUMPFILE()) {
Packit Service 501009
		if (!sadump_get_cr3_idtr(&cr3, &idtr))
Packit Service 501009
			return FALSE;
Packit Service 501009
	} else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) {
Packit Service 501009
		if (!qemu_get_cr3_idtr(&cr3, &idtr))
Packit Service 501009
			return FALSE;
Packit Service 501009
	} else if (VMSS_DUMPFILE()) {
Packit Service 501009
		if (!vmware_vmss_get_cr3_idtr(&cr3, &idtr))
Packit Service 501009
			return FALSE;
Packit Service 501009
	} else
Packit Service 501009
		return FALSE;
Packit Service 501009
Packit Service 501009
	if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)
Packit Service 501009
		pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
Packit Service 501009
	else
Packit Service 501009
		pgd = cr3 & ~CR3_PCID_MASK;
Packit Service 501009
Packit Service 501009
	/*
Packit Service 501009
	 * Set up for kvtop.
Packit Service 501009
	 *
Packit Service 501009
	 * calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some
Packit Service 501009
	 * variables are not initialized yet. Set up them here to call kvtop().
Packit Service 501009
	 *
Packit Service 501009
	 * TODO: XEN and 5-level is not supported
Packit Service 501009
	 */
Packit Service 501009
	vt->kernel_pgd[0] = pgd;
Packit Service 501009
	machdep->last_pgd_read = vt->kernel_pgd[0];
Packit Service 501009
	machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6;
Packit Service 501009
	machdep->machspec->pgdir_shift = PGDIR_SHIFT;
Packit Service 501009
	machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
Packit Service 501009
	if (!readmem(pgd, PHYSADDR, machdep->pgd, PAGESIZE(),
Packit Service 501009
			"pgd", RETURN_ON_ERROR))
Packit Service 501009
		goto quit;
Packit Service 501009
Packit Service 501009
	/* Convert virtual address of IDT table to physical address */
Packit Service 501009
	if (!kvtop(NULL, idtr, &idtr_paddr, verbose))
Packit Service 501009
		goto quit;
Packit Service 501009
Packit Service 501009
	/* Now we can calculate kaslr_offset and phys_base */
Packit Service 501009
	divide_error_vmcore = get_vec0_addr(idtr_paddr);
Packit Service 501009
	*kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux;
Packit Service 501009
	*phys_base = idtr_paddr -
Packit Service 501009
		(st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map);
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd);
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n", idtr_paddr);
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: divide_error(vmlinux): %lx\n",
Packit Service 501009
			st->divide_error_vmlinux);
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: divide_error(vmcore): %lx\n",
Packit Service 501009
			divide_error_vmcore);
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	/*
Packit Service 501009
	 * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd
Packit Service 501009
	 * kernel. If we are in 2nd kernel, get kaslr_offset/phys_base
Packit Service 501009
	 * from vmcoreinfo
Packit Service 501009
	 */
Packit Service 501009
	if (get_kaslr_offset_from_vmcoreinfo(
Packit Service 501009
		*kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) {
Packit Service 501009
		*kaslr_offset =  kaslr_offset_kdump;
Packit Service 501009
		*phys_base =  phys_base_kdump;
Packit Service 501009
	} else if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "kaslr_helper: failed to determine which kernel was running at crash,\n");
Packit Service 501009
		fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n");
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	if (CRASHDEBUG(1)) {
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n",
Packit Service 501009
			*kaslr_offset);
Packit Service 501009
		fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", *phys_base);
Packit Service 501009
	}
Packit Service 501009
Packit Service 501009
	ret = TRUE;
Packit Service 501009
quit:
Packit Service 501009
	vt->kernel_pgd[0] = 0;
Packit Service 501009
	machdep->last_pgd_read = 0;
Packit Service 501009
	return ret;
Packit Service 501009
}
Packit Service 501009
#else
Packit Service 501009
int
Packit Service 501009
calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_page)
Packit Service 501009
{
Packit Service 501009
	return FALSE;
Packit Service 501009
}
Packit Service 501009
#endif /* X86_64 */