162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Copyright C 2016, Oracle and/or its affiliates. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci .code32 862306a36Sopenharmony_ci .text 962306a36Sopenharmony_ci#define _pa(x) ((x) - __START_KERNEL_map) 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/elfnote.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/linkage.h> 1462306a36Sopenharmony_ci#include <asm/segment.h> 1562306a36Sopenharmony_ci#include <asm/asm.h> 1662306a36Sopenharmony_ci#include <asm/boot.h> 1762306a36Sopenharmony_ci#include <asm/processor-flags.h> 1862306a36Sopenharmony_ci#include <asm/msr.h> 1962306a36Sopenharmony_ci#include <asm/nospec-branch.h> 2062306a36Sopenharmony_ci#include <xen/interface/elfnote.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci __HEAD 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Entry point for PVH guests. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Xen ABI specifies the following register state when we come here: 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * - `ebx`: contains the physical memory address where the loader has placed 3062306a36Sopenharmony_ci * the boot start info structure. 3162306a36Sopenharmony_ci * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared. 3262306a36Sopenharmony_ci * - `cr4`: all bits are cleared. 3362306a36Sopenharmony_ci * - `cs `: must be a 32-bit read/execute code segment with a base of `0` 3462306a36Sopenharmony_ci * and a limit of `0xFFFFFFFF`. The selector value is unspecified. 3562306a36Sopenharmony_ci * - `ds`, `es`: must be a 32-bit read/write data segment with a base of 3662306a36Sopenharmony_ci * `0` and a limit of `0xFFFFFFFF`. The selector values are all 3762306a36Sopenharmony_ci * unspecified. 3862306a36Sopenharmony_ci * - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit 3962306a36Sopenharmony_ci * of '0x67'. 4062306a36Sopenharmony_ci * - `eflags`: bit 17 (VM) must be cleared. Bit 9 (IF) must be cleared. 4162306a36Sopenharmony_ci * Bit 8 (TF) must be cleared. Other bits are all unspecified. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * All other processor registers and flag bits are unspecified. The OS is in 4462306a36Sopenharmony_ci * charge of setting up it's own stack, GDT and IDT. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define PVH_GDT_ENTRY_CS 1 4862306a36Sopenharmony_ci#define PVH_GDT_ENTRY_DS 2 4962306a36Sopenharmony_ci#define PVH_CS_SEL (PVH_GDT_ENTRY_CS * 8) 5062306a36Sopenharmony_ci#define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciSYM_CODE_START_LOCAL(pvh_start_xen) 5362306a36Sopenharmony_ci UNWIND_HINT_END_OF_STACK 5462306a36Sopenharmony_ci cld 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci lgdt (_pa(gdt)) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci mov $PVH_DS_SEL,%eax 5962306a36Sopenharmony_ci mov %eax,%ds 6062306a36Sopenharmony_ci mov %eax,%es 6162306a36Sopenharmony_ci mov %eax,%ss 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Stash hvm_start_info. */ 6462306a36Sopenharmony_ci mov $_pa(pvh_start_info), %edi 6562306a36Sopenharmony_ci mov %ebx, %esi 6662306a36Sopenharmony_ci mov _pa(pvh_start_info_sz), %ecx 6762306a36Sopenharmony_ci shr $2,%ecx 6862306a36Sopenharmony_ci rep 6962306a36Sopenharmony_ci movsl 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci mov $_pa(early_stack_end), %esp 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Enable PAE mode. */ 7462306a36Sopenharmony_ci mov %cr4, %eax 7562306a36Sopenharmony_ci orl $X86_CR4_PAE, %eax 7662306a36Sopenharmony_ci mov %eax, %cr4 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#ifdef CONFIG_X86_64 7962306a36Sopenharmony_ci /* Enable Long mode. */ 8062306a36Sopenharmony_ci mov $MSR_EFER, %ecx 8162306a36Sopenharmony_ci rdmsr 8262306a36Sopenharmony_ci btsl $_EFER_LME, %eax 8362306a36Sopenharmony_ci wrmsr 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Enable pre-constructed page tables. */ 8662306a36Sopenharmony_ci mov $_pa(init_top_pgt), %eax 8762306a36Sopenharmony_ci mov %eax, %cr3 8862306a36Sopenharmony_ci mov $(X86_CR0_PG | X86_CR0_PE), %eax 8962306a36Sopenharmony_ci mov %eax, %cr0 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Jump to 64-bit mode. */ 9262306a36Sopenharmony_ci ljmp $PVH_CS_SEL, $_pa(1f) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* 64-bit entry point. */ 9562306a36Sopenharmony_ci .code64 9662306a36Sopenharmony_ci1: 9762306a36Sopenharmony_ci /* Set base address in stack canary descriptor. */ 9862306a36Sopenharmony_ci mov $MSR_GS_BASE,%ecx 9962306a36Sopenharmony_ci mov $_pa(canary), %eax 10062306a36Sopenharmony_ci xor %edx, %edx 10162306a36Sopenharmony_ci wrmsr 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci call xen_prepare_pvh 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* startup_64 expects boot_params in %rsi. */ 10662306a36Sopenharmony_ci mov $_pa(pvh_bootparams), %rsi 10762306a36Sopenharmony_ci mov $_pa(startup_64), %rax 10862306a36Sopenharmony_ci ANNOTATE_RETPOLINE_SAFE 10962306a36Sopenharmony_ci jmp *%rax 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#else /* CONFIG_X86_64 */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci call mk_early_pgtbl_32 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci mov $_pa(initial_page_table), %eax 11662306a36Sopenharmony_ci mov %eax, %cr3 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci mov %cr0, %eax 11962306a36Sopenharmony_ci or $(X86_CR0_PG | X86_CR0_PE), %eax 12062306a36Sopenharmony_ci mov %eax, %cr0 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ljmp $PVH_CS_SEL, $1f 12362306a36Sopenharmony_ci1: 12462306a36Sopenharmony_ci call xen_prepare_pvh 12562306a36Sopenharmony_ci mov $_pa(pvh_bootparams), %esi 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* startup_32 doesn't expect paging and PAE to be on. */ 12862306a36Sopenharmony_ci ljmp $PVH_CS_SEL, $_pa(2f) 12962306a36Sopenharmony_ci2: 13062306a36Sopenharmony_ci mov %cr0, %eax 13162306a36Sopenharmony_ci and $~X86_CR0_PG, %eax 13262306a36Sopenharmony_ci mov %eax, %cr0 13362306a36Sopenharmony_ci mov %cr4, %eax 13462306a36Sopenharmony_ci and $~X86_CR4_PAE, %eax 13562306a36Sopenharmony_ci mov %eax, %cr4 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ljmp $PVH_CS_SEL, $_pa(startup_32) 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ciSYM_CODE_END(pvh_start_xen) 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci .section ".init.data","aw" 14262306a36Sopenharmony_ci .balign 8 14362306a36Sopenharmony_ciSYM_DATA_START_LOCAL(gdt) 14462306a36Sopenharmony_ci .word gdt_end - gdt_start 14562306a36Sopenharmony_ci .long _pa(gdt_start) 14662306a36Sopenharmony_ci .word 0 14762306a36Sopenharmony_ciSYM_DATA_END(gdt) 14862306a36Sopenharmony_ciSYM_DATA_START_LOCAL(gdt_start) 14962306a36Sopenharmony_ci .quad 0x0000000000000000 /* NULL descriptor */ 15062306a36Sopenharmony_ci#ifdef CONFIG_X86_64 15162306a36Sopenharmony_ci .quad GDT_ENTRY(0xa09a, 0, 0xfffff) /* PVH_CS_SEL */ 15262306a36Sopenharmony_ci#else 15362306a36Sopenharmony_ci .quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* PVH_CS_SEL */ 15462306a36Sopenharmony_ci#endif 15562306a36Sopenharmony_ci .quad GDT_ENTRY(0xc092, 0, 0xfffff) /* PVH_DS_SEL */ 15662306a36Sopenharmony_ciSYM_DATA_END_LABEL(gdt_start, SYM_L_LOCAL, gdt_end) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci .balign 16 15962306a36Sopenharmony_ciSYM_DATA_LOCAL(canary, .fill 48, 1, 0) 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciSYM_DATA_START_LOCAL(early_stack) 16262306a36Sopenharmony_ci .fill BOOT_STACK_SIZE, 1, 0 16362306a36Sopenharmony_ciSYM_DATA_END_LABEL(early_stack, SYM_L_LOCAL, early_stack_end) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, 16662306a36Sopenharmony_ci _ASM_PTR (pvh_start_xen - __START_KERNEL_map)) 167