diff --git a/sys/arch/i386/i386/genassym.cf b/sys/arch/i386/i386/genassym.cf index 3e5eac33336..fc9211990b1 100644 --- a/sys/arch/i386/i386/genassym.cf +++ b/sys/arch/i386/i386/genassym.cf @@ -377,6 +377,7 @@ define L2_FRAME L2_FRAME define VM_GUEST_XENPV VM_GUEST_XENPV define VM_GUEST_XENPVH VM_GUEST_XENPVH +define VM_GUEST_GENPVH VM_GUEST_GENPVH ifdef XEN define CPU_INFO_VCPU offsetof(struct cpu_info, ci_vcpu) @@ -391,7 +392,12 @@ define START_INFO_STORE_MFN offsetof(struct start_info, store_mfn) define SIF_INITDOMAIN SIF_INITDOMAIN define EVTCHN_UPCALL_PENDING offsetof(struct vcpu_info, evtchn_upcall_pending) define EVTCHN_UPCALL_MASK offsetof(struct vcpu_info, evtchn_upcall_mask) - +define HVM_START_INFO_SIZE sizeof(struct hvm_start_info) +define START_INFO_VERSION offsetof(struct hvm_start_info, version) +define MMAP_PADDR offsetof(struct hvm_start_info, memmap_paddr) +define MMAP_ENTRIES offsetof(struct hvm_start_info, memmap_entries) +define MMAP_ENTRY_SIZE sizeof(struct hvm_memmap_table_entry) +define CMDLINE_PADDR offsetof(struct hvm_start_info, cmdline_paddr) define HYPERVISOR_sched_op __HYPERVISOR_sched_op define SCHEDOP_yield SCHEDOP_yield endif /* XEN */ diff --git a/sys/arch/i386/i386/locore.S b/sys/arch/i386/i386/locore.S index 06a4ba41a81..9ba754f8d6d 100644 --- a/sys/arch/i386/i386/locore.S +++ b/sys/arch/i386/i386/locore.S @@ -244,11 +244,12 @@ __KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.198 2024/07/31 20:05:28 andvar Exp $"); #ifdef XEN #define __ASSEMBLY__ +#include <xen/include/public/arch-x86/cpuid.h> #include <xen/include/public/elfnote.h> #include <xen/include/public/xen.h> #define ELFNOTE(name, type, desctype, descdata...) \ -.pushsection .note.name ; \ +.pushsection .note.name, "a", @note ; \ .align 4 ; \ .long 2f - 1f /* namesz */ ; \ .long 4f - 3f /* descsz */ ; \ @@ -272,7 +273,7 @@ __KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.198 2024/07/31 20:05:28 andvar Exp $"); ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long, start) #else ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, 0) - ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long, RELOC(start_xenpvh)) + ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long, RELOC(start_pvh)) #endif /* XENPV */ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long, hypercall_page) ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long, HYPERVISOR_VIRT_START) @@ -1193,7 +1194,7 @@ END(start) #if defined(XEN) #ifndef XENPV /* entry point for Xen PVH */ -ENTRY(start_xenpvh) +ENTRY(start_pvh) /* Xen doesn't start us with a valid gdt */ movl $RELOC(gdtdesc_xenpvh), %eax lgdt (%eax) @@ -1216,6 +1217,93 @@ ENTRY(start_xenpvh) rep stosb + /* + * Here, we have 2 cases : + * + * 1) We have been started by Xen + * 2) We have been started by another VMM (Qemu, Firecracker, ...) + * + * The main difference is that, when we are started by Xen, + * %ebx (addr of the hvm_start_info structure) is pointing to a + * location that will be mapped correctly later. + * + * In the second case, we have to copy this structure (and all + * the information contained in it) to a location that will be + * mapped later : __kernel_end + * + * To distinguish between the 2 cases, we'll use the 'cpuid' instruction + */ + + push %ebx + xorl %eax, %eax + cpuid + cmpl $0x1, %eax /* Check if we can call CPUID with eax=1 */ + jb .start_genpvh + xorl %eax, %eax + inc %eax + cpuid + shr $31, %ecx + testb $1, %cl /* Check if bit 31 of ECX (hypervisor) is set */ + jz .start_genpvh + xorl %eax, %eax + inc %eax + shl $30, %eax + cpuid /* Calling cpuid with eax=0x40000000 */ + cmp $XEN_CPUID_SIGNATURE_EBX, %ebx /* "VneX" */ + je .start_xen + + /* We have been started by a VMM that is *not* Xen */ + +.start_genpvh: + + /* First, copy the hvm_start_info structure to __kernel_end */ + pop %ebx + movl %ebx, %esi + movl $RELOC(__kernel_end), %edi + movl $HVM_START_INFO_SIZE, %ecx + shrl $2, %ecx + rep movsl + + /* Copy cmdline_paddr after hvm_start_info */ + movl CMDLINE_PADDR(%ebx), %esi + movl $RELOC(__kernel_end), %ecx + movl %edi, CMDLINE_PADDR(%ecx) /* Set new cmdline_paddr in hvm_start_info */ + .cmdline_copy: + movb (%esi), %al + movsb + cmp $0, %al + jne .cmdline_copy + + /* Copy memmap_paddr after cmdline (only if hvm_start_info->version != 0) */ + xorl %eax, %eax + cmpl START_INFO_VERSION(%ebx), %eax + je .reload_ebx + movl MMAP_PADDR(%ebx), %esi + movl $RELOC(__kernel_end), %ecx + movl %edi, MMAP_PADDR(%ecx) /* Set new memmap_paddr in hvm_start_info */ + movl MMAP_ENTRIES(%ebx), %eax /* Get memmap_entries */ + movl $MMAP_ENTRY_SIZE, %ebx + mull %ebx /* eax * ebx => edx:eax */ + movl %eax, %ecx + shrl $2, %ecx + rep movsl + +.reload_ebx: + movl $RELOC(__kernel_end), %ebx + + /* announce ourself */ + movl $VM_GUEST_GENPVH, RELOC(vm_guest) + + jmp .save_hvm_start_paddr + +.start_xen: + pop %ebx + movl $VM_GUEST_XENPVH, RELOC(vm_guest) + +.save_hvm_start_paddr: + /* + * save addr of the hvm_start_info structure. This is also the end + * of the symbol table /* * save addr of the hvm_start_info structure. This is also the end * of the symbol table @@ -1226,22 +1314,25 @@ ENTRY(start_xenpvh) movl $RELOC(esym),%ebp movl %eax,(%ebp) /* get a page for HYPERVISOR_shared_info */ + /* this is only needed if we are running on Xen */ + cmpl $VM_GUEST_XENPVH, RELOC(vm_guest) + jne .add_hvm_start_info_page addl $PAGE_SIZE, %ebx addl $PGOFSET,%ebx andl $~PGOFSET,%ebx movl $RELOC(HYPERVISOR_shared_info_pa),%ebp movl %ebx,(%ebp) /* XXX assume hvm_start_info+dependant structure fits in a single page */ +.add_hvm_start_info_page: addl $PAGE_SIZE, %ebx addl $PGOFSET,%ebx andl $~PGOFSET,%ebx addl $KERNBASE,%ebx movl $RELOC(eblob),%ebp movl %ebx,(%ebp) - /* announce ourself */ - movl $VM_GUEST_XENPVH, RELOC(vm_guest) + jmp .Lstart_common -END(start_xenpvh) +END(start_pvh) .align 8 gdtdesc_xenpvh: .word gdt_xenpvhend - gdt_xenpvh diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 8a0d395421b..6366a533133 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1105,6 +1105,11 @@ init386_ksyms(void) return; #endif + if (vm_guest == VM_GUEST_GENPVH) { + ksyms_addsyms_elf(0, ((int *)&end) + 1, esym); + return; + } + if ((symtab = lookup_bootinfo(BTINFO_SYMTAB)) == NULL) { ksyms_addsyms_elf(*(int *)&end, ((int *)&end) + 1, esym); return; @@ -1184,7 +1189,7 @@ init386(paddr_t first_avail) #endif #ifdef XEN - if (vm_guest == VM_GUEST_XENPVH) + if (vm_guest == VM_GUEST_XENPVH || vm_guest == VM_GUEST_GENPVH) xen_parse_cmdline(XEN_PARSE_BOOTFLAGS, NULL); #endif