mirror of
				https://github.com/projectacrn/acrn-hypervisor.git
				synced 2025-11-03 19:15:23 +00:00 
			
		
		
		
	Previously the min load_addr for HV image is hard coded to 0x10000000 when CONFIG_RELOC is enabled, now use CONFIG_HV_RAM_START as its prefer minimum address like setting of CONFIG_PHYSICAL_START do in Linux kernel. With this patch, we can offload the CONFIG_HV_RAM_START algorithm to acrn-config or manually set it in scenario XML on some special boards. Tracked-On: #5275 Signed-off-by: Victor Sun <victor.sun@intel.com>
		
			
				
	
	
		
			342 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2018 Intel Corporation. All rights reserved.
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: BSD-3-Clause
 | 
						|
 */
 | 
						|
 | 
						|
/* NOTE:
 | 
						|
 *
 | 
						|
 * MISRA C requires that all unsigned constants should have the suffix 'U'
 | 
						|
 * (e.g. 0xffU), but the assembler may not accept such C-style constants. For
 | 
						|
 * example, binutils 2.26 fails to compile assembly in that case. To work this
 | 
						|
 * around, all unsigned constants must be explicitly spells out in assembly
 | 
						|
 * with a comment tracking the original expression from which the magic
 | 
						|
 * number is calculated. As an example:
 | 
						|
 *
 | 
						|
 *    /* 0x00000668 =
 | 
						|
 *     *    (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) *\/
 | 
						|
 *    movl    $0x00000668, %eax
 | 
						|
 *
 | 
						|
 * Make sure that these numbers are updated accordingly if the definition of
 | 
						|
 * the macros involved are changed.
 | 
						|
 */
 | 
						|
 | 
						|
#include <config.h>
 | 
						|
#include <multiboot.h>
 | 
						|
#ifdef CONFIG_MULTIBOOT2
 | 
						|
#include <multiboot2.h>
 | 
						|
#endif
 | 
						|
 | 
						|
/* MULTIBOOT HEADER */
 | 
						|
#define MULTIBOOT_HEADER_FLAGS	MULTIBOOT_HEADER_NEED_MEMINFO
 | 
						|
 | 
						|
    .extern cpu_primary_save32
 | 
						|
    .extern cpu_primary_save64
 | 
						|
    .section    multiboot_header, "a"
 | 
						|
 | 
						|
    .align     4
 | 
						|
 | 
						|
    /* header magic */
 | 
						|
    .long   MULTIBOOT_HEADER_MAGIC
 | 
						|
    /* header flags - flags bit 6 : enable mmap_* */
 | 
						|
    .long   MULTIBOOT_HEADER_FLAGS
 | 
						|
    /* header checksum = -(magic + flags) */
 | 
						|
    .long   -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
 | 
						|
 | 
						|
#ifdef CONFIG_MULTIBOOT2
 | 
						|
    .align     MULTIBOOT2_HEADER_ALIGN
 | 
						|
mb2_header_start:
 | 
						|
    /* Magic number indicating a Multiboot2 header. */
 | 
						|
    .long   MULTIBOOT2_HEADER_MAGIC
 | 
						|
    /* Architecture: i386. */
 | 
						|
    .long   MULTIBOOT2_ARCHITECTURE_I386
 | 
						|
    /* Multiboot2 header length. */
 | 
						|
    .long   mb2_header_end - mb2_header_start
 | 
						|
    /* Multiboot2 header checksum. */
 | 
						|
    .long   -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386 + (mb2_header_end - mb2_header_start))
 | 
						|
 | 
						|
    /* please be aware that each tag should be 8 bytes aligned */
 | 
						|
    .align     MULTIBOOT2_TAG_ALIGN
 | 
						|
    /*
 | 
						|
     * Request infomation from boot loader, which is supposed to provide th relevant information
 | 
						|
     * specified in the following tags to the image through the MBI if it is available
 | 
						|
     */
 | 
						|
info_req_tag_start:
 | 
						|
    .short  MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST
 | 
						|
    .short  0
 | 
						|
    .long   info_req_tag_end - info_req_tag_start
 | 
						|
    .long   MULTIBOOT2_TAG_TYPE_MMAP        /* memory map */
 | 
						|
    .long   MULTIBOOT2_TAG_TYPE_MODULE      /* boot modules infomation */
 | 
						|
    .long   MULTIBOOT2_TAG_TYPE_ACPI_NEW    /* a copy of RSDP as defined per ACPI 2.0 or later specification */
 | 
						|
    .long   MULTIBOOT2_TAG_TYPE_EFI64       /* EFI system table, to be passed to guest Linux  */
 | 
						|
    .long   MULTIBOOT2_TAG_TYPE_EFI_MMAP    /* EFI memory map, to be passed to guest Linux */
 | 
						|
info_req_tag_end:
 | 
						|
 | 
						|
#ifdef CONFIG_RELOC
 | 
						|
    .align  MULTIBOOT2_TAG_ALIGN
 | 
						|
address_tag_start:
 | 
						|
    .short  MULTIBOOT2_HEADER_TAG_ADDRESS
 | 
						|
    .short  0
 | 
						|
    .long   address_tag_end - address_tag_start
 | 
						|
    .long   mb2_header_start  /* address corresponding to the beginning of the Multiboot2 header */
 | 
						|
    .long   _ld_ram_start     /* load_addr: load from the binary's beginning */
 | 
						|
    /*
 | 
						|
     * load_end_addr: this includes .bss so that boot loader could reserve the
 | 
						|
     * memory that .bss occupies to avoid placing boot modules or other data in that area.
 | 
						|
     *
 | 
						|
     * However, the boot loader is supposed not to actually load the .bss section because
 | 
						|
     * it's beyond the scope of acrn.bin
 | 
						|
     */
 | 
						|
    .long   _ld_ram_end
 | 
						|
    .long   0   /* bss_end_addr, don't ask boot loader to clear .bss */
 | 
						|
address_tag_end:
 | 
						|
 | 
						|
    .align  MULTIBOOT2_TAG_ALIGN
 | 
						|
entry_address_tag_start:
 | 
						|
    .short  MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS
 | 
						|
    .short  0
 | 
						|
    .long   entry_address_tag_end - entry_address_tag_start
 | 
						|
    .long   cpu_primary_start_32  /* The address to which the boot loader should jump to start hypervisor */
 | 
						|
entry_address_tag_end:
 | 
						|
 | 
						|
    .align  MULTIBOOT2_TAG_ALIGN
 | 
						|
relocatable_tag_start:
 | 
						|
    .short  MULTIBOOT2_HEADER_TAG_RELOCATABLE
 | 
						|
    .short  0
 | 
						|
    .long   relocatable_tag_end - relocatable_tag_start
 | 
						|
    .long   CONFIG_HV_RAM_START   /* min_addr */
 | 
						|
    .long   0x80000000   /* max_addr */
 | 
						|
    .long   0x200000     /* image alignment */
 | 
						|
    .long   1            /* preference: lowest possible address */
 | 
						|
relocatable_tag_end:
 | 
						|
#endif	/* CONFIG_RELOC */
 | 
						|
 | 
						|
    .align     MULTIBOOT2_TAG_ALIGN
 | 
						|
    .short  MULTIBOOT2_HEADER_TAG_END
 | 
						|
    .short  0
 | 
						|
    .long   8
 | 
						|
mb2_header_end:
 | 
						|
#endif	/* CONFIG_MULTIBOOT2 */
 | 
						|
 | 
						|
    /*
 | 
						|
     * The page tables are aligned to 4KB, which implicitly aligns this section at
 | 
						|
     * 4KB boundary. Put an extra .align here to explicitly state that regardless
 | 
						|
     * the actual length of the multiboot header section, this section will be linked
 | 
						|
     * at offset 0x1000 to the beginning of the target executable.
 | 
						|
     */
 | 
						|
    .align      0x1000
 | 
						|
    .section    entry, "ax"
 | 
						|
    .align      8
 | 
						|
    .code32
 | 
						|
 | 
						|
    .global     cpu_primary_start_32
 | 
						|
cpu_primary_start_32:
 | 
						|
 | 
						|
  /*
 | 
						|
   * Calculate the relocation delta between where we were compiled to run
 | 
						|
   * at and where we were actually loaded at.
 | 
						|
   */
 | 
						|
    call    0f
 | 
						|
0:  pop     %esi
 | 
						|
    sub     $0b, %esi
 | 
						|
 | 
						|
    /* save the MULTBOOT magic number & MBI */
 | 
						|
    movl    %eax, boot_regs(%esi)
 | 
						|
    movl    %ebx, (boot_regs+4)(%esi)
 | 
						|
 | 
						|
    /* Disable interrupts */
 | 
						|
    cli
 | 
						|
 | 
						|
    /* Clear direction flag */
 | 
						|
    cld
 | 
						|
 | 
						|
    /* detect whether it is in long mode
 | 
						|
     *
 | 
						|
     *     0xc0000080 = MSR_IA32_EFER
 | 
						|
     */
 | 
						|
    movl    $0xc0000080, %ecx
 | 
						|
    rdmsr
 | 
						|
    /* 0x400 = MSR_IA32_EFER_LMA_BIT */
 | 
						|
    test     $0x400, %eax
 | 
						|
 | 
						|
    /* jump to 64bit entry if it is already in long mode */
 | 
						|
    jne      cpu_primary_start_64
 | 
						|
 | 
						|
    /* Disable paging */
 | 
						|
    mov     %cr0, %ebx
 | 
						|
    /* 0x7fffffff = ~CR0_PG */
 | 
						|
    andl    $0x7fffffff, %ebx
 | 
						|
    mov     %ebx, %cr0
 | 
						|
 | 
						|
    /* Set DE, PAE, MCE and OS support bits in CR4
 | 
						|
     * 0x00000668 =
 | 
						|
     *    (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) */
 | 
						|
    movl    $0x00000668, %eax
 | 
						|
    mov     %eax, %cr4
 | 
						|
 | 
						|
    /* fixup page table pointers with relocation delta */
 | 
						|
    addl    %esi, cpu_primary32_pdpt_addr(%esi)
 | 
						|
    addl    %esi, (cpu_primary32_pdpt_addr+8)(%esi)
 | 
						|
    addl    %esi, (cpu_primary32_pdpt_addr+16)(%esi)
 | 
						|
    addl    %esi, (cpu_primary32_pdpt_addr+24)(%esi)
 | 
						|
 | 
						|
    /* Set CR3 to PML4 table address */
 | 
						|
    movl    $cpu_boot32_page_tables_start, %edi
 | 
						|
    addl    %esi, %edi
 | 
						|
    addl    %esi, (%edi)
 | 
						|
    mov     %edi, %cr3
 | 
						|
 | 
						|
    /* Set LME bit in EFER */
 | 
						|
 | 
						|
    /* 0xc0000080 = MSR_IA32_EFER */
 | 
						|
    movl    $0xc0000080, %ecx
 | 
						|
    rdmsr
 | 
						|
    /* 0x00000100 = MSR_IA32_EFER_LME_BIT */
 | 
						|
    orl     $0x00000100, %eax
 | 
						|
    wrmsr
 | 
						|
 | 
						|
    /* Enable paging, protection, numeric error and co-processor
 | 
						|
       monitoring in CR0 to enter long mode */
 | 
						|
    mov     %cr0, %ebx
 | 
						|
    /* 0x80000023 = (CR0_PG | CR0_PE | CR0_MP | CR0_NE) */
 | 
						|
    orl     $0x80000023, %ebx
 | 
						|
    mov     %ebx, %cr0
 | 
						|
 | 
						|
    /* Load temportary GDT pointer value */
 | 
						|
    mov     $cpu_primary32_gdt_ptr, %ebx
 | 
						|
    addl    %esi, %ebx
 | 
						|
    addl    %esi, 2(%ebx)
 | 
						|
    lgdt    (%ebx)
 | 
						|
 | 
						|
    /* Perform a long jump based to start executing in 64-bit mode */
 | 
						|
    movl    $jmpbuf_32, %eax
 | 
						|
    addl    %esi, %eax
 | 
						|
    addl    %esi, (%eax)
 | 
						|
    ljmp    *(%eax)
 | 
						|
 | 
						|
jmpbuf_32:
 | 
						|
    .long   primary_start_long_mode
 | 
						|
    /* 0x0008 = HOST_GDT_RING0_CODE_SEL */
 | 
						|
    .word 0x0008
 | 
						|
 | 
						|
    /*
 | 
						|
     * Offset from the beginning of the entry section.
 | 
						|
     * This is to make sure that cpu_primary_start_64 is linked to a known address
 | 
						|
     * so that efi-stub knows where to pass control to hypervisor.
 | 
						|
     */
 | 
						|
    .org 0x200
 | 
						|
    .code64
 | 
						|
    .global     cpu_primary_start_64
 | 
						|
cpu_primary_start_64:
 | 
						|
    /* save the MULTBOOT magic number & MBI */
 | 
						|
    lea     boot_regs(%rip), %rax
 | 
						|
    movl    %edi, (%rax)
 | 
						|
    movl    %esi, 4(%rax)
 | 
						|
 | 
						|
    /* Save boot context from 64bit mode */
 | 
						|
    call cpu_primary_save_64
 | 
						|
 | 
						|
primary_start_long_mode:
 | 
						|
 | 
						|
    /* Initialize temporary stack pointer, size = 0x1000 */
 | 
						|
    lea     stack_for_boot(%rip), %rsp
 | 
						|
    /* 16 = CPU_STACK_ALIGN */
 | 
						|
    and     $(~(16 - 1)),%rsp
 | 
						|
 | 
						|
    /*
 | 
						|
     * Fix up the .rela sections
 | 
						|
     * Notes: this includes the fixup to IDT tables and temporary
 | 
						|
     *     page tables
 | 
						|
     */
 | 
						|
    call relocate
 | 
						|
 | 
						|
    call    0f
 | 
						|
0:  pop     %rsi
 | 
						|
    sub     $0b, %rsi    /* relocation delta */
 | 
						|
 | 
						|
    /* Load temportary GDT pointer value */
 | 
						|
    lea     cpu_primary64_gdt_ptr(%rip), %rbx
 | 
						|
    addq    %rsi, 2(%rbx)
 | 
						|
    lgdt    (%ebx)
 | 
						|
 | 
						|
    /* Set the correct long jump address */
 | 
						|
    lea     jmpbuf_64(%rip), %rax
 | 
						|
    lea     after(%rip), %rbx
 | 
						|
    mov     %rbx, (%rax)
 | 
						|
    rex.w ljmp  *(%rax)
 | 
						|
jmpbuf_64: .quad 0
 | 
						|
	/* 0x0008 = HOST_GDT_RING0_CODE_SEL */
 | 
						|
        .word 0x0008
 | 
						|
 | 
						|
after:
 | 
						|
    /* 0x10 = HOST_GDT_RING0_DATA_SEL*/
 | 
						|
    movl    $0x10,%eax
 | 
						|
    mov     %eax,%ss  // Was 32bit POC Stack
 | 
						|
    mov     %eax,%ds  // Was 32bit POC Data
 | 
						|
    mov     %eax,%es  // Was 32bit POC Data
 | 
						|
    mov     %eax,%fs  // Was 32bit POC Data
 | 
						|
    mov     %eax,%gs  // Was 32bit POC CLS
 | 
						|
 | 
						|
   /* continue with chipset level initialization */
 | 
						|
   call     init_primary_pcpu
 | 
						|
 | 
						|
loop:
 | 
						|
    jmp loop
 | 
						|
 | 
						|
    .align  4
 | 
						|
    .global boot_regs
 | 
						|
boot_regs:
 | 
						|
    .long   0x00000000
 | 
						|
    .long   0x00000000
 | 
						|
 | 
						|
    /* GDT table */
 | 
						|
    .align  4
 | 
						|
cpu_primary32_gdt:
 | 
						|
    .quad   0x0000000000000000
 | 
						|
    .quad   0x00af9b000000ffff
 | 
						|
    .quad   0x00cf93000000ffff
 | 
						|
cpu_primary32_gdt_end:
 | 
						|
 | 
						|
/* GDT pointer */
 | 
						|
    .align  2
 | 
						|
cpu_primary32_gdt_ptr:
 | 
						|
    .short  (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1
 | 
						|
    .quad   cpu_primary32_gdt
 | 
						|
 | 
						|
cpu_primary64_gdt_ptr:
 | 
						|
    .short  (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1
 | 
						|
    .quad   cpu_primary32_gdt
 | 
						|
 | 
						|
/* PML4, PDPT, and PD tables initialized to map first 4 GBytes of memory */
 | 
						|
    /*0x1000 = PAGE_SIZE*/
 | 
						|
    .align  0x1000
 | 
						|
    .global cpu_boot32_page_tables_start
 | 
						|
cpu_boot32_page_tables_start:
 | 
						|
    /* 0x3 = (PAGE_PRESENT | PAGE_RW) */
 | 
						|
    .quad   cpu_primary32_pdpt_addr + 0x3
 | 
						|
    /*0x1000 = PAGE_SIZE*/
 | 
						|
    .align  0x1000
 | 
						|
cpu_primary32_pdpt_addr:
 | 
						|
    address = 0
 | 
						|
    .rept   4
 | 
						|
    /* 0x3 = (PAGE_PRESENT | PAGE_RW) */
 | 
						|
    .quad   cpu_primary32_pdt_addr + address + 0x3
 | 
						|
    /*0x1000 = PAGE_SIZE*/
 | 
						|
    address = address + 0x1000
 | 
						|
    .endr
 | 
						|
    /*0x1000 = PAGE_SIZE*/
 | 
						|
    .align  0x1000
 | 
						|
cpu_primary32_pdt_addr:
 | 
						|
    address = 0
 | 
						|
    .rept  2048
 | 
						|
    /* 0x83 = (PAGE_PSE | PAGE_PRESENT | PAGE_RW) */
 | 
						|
    .quad  address + 0x83
 | 
						|
    address = address + 0x200000
 | 
						|
    .endr
 | 
						|
 | 
						|
#ifdef CONFIG_MULTIBOOT2
 | 
						|
    .global efiloader_sig
 | 
						|
efiloader_sig:
 | 
						|
    .asciz    "EL64"
 | 
						|
#endif
 |