OHHHHH
This commit is contained in:
+76
-2
@@ -81,11 +81,85 @@ static u64 vmx_required_cr4(void) {
|
||||
return read_cr4() | CR4_VMXE | CR4_PAE | CR4_PGE;
|
||||
}
|
||||
|
||||
/* Check whether we are running under a hypervisor that does NOT support
|
||||
* nested VMX. This covers:
|
||||
* - WHPX: CPUID may report VMX but VMXON/CR4.VMXE causes fatal exit
|
||||
* - Any hypervisor without nested virtualization support
|
||||
*
|
||||
* Detection strategy:
|
||||
* 1. Check CPUID.01H:ECX[31] (hypervisor present bit)
|
||||
* 2. If hypervisor present, check CPUID.40000000H for vendor signature
|
||||
* 3. Try reading IA32_VMX_BASIC MSR — if it returns 0, VMX is not real
|
||||
* 4. Check Hyper-V specific: HV_CPU_MANAGEMENT_FEATURES for nested VMX
|
||||
*
|
||||
* If VMX CPUID flag is set but we're under a hypervisor that doesn't expose
|
||||
* real VMX MSRs, we must not attempt CR4.VMXE or VMXON, as this will cause
|
||||
* a fatal VM exit in WHPX (exit code 4).
|
||||
*/
|
||||
static int vmx_truly_available(void) {
|
||||
/* Step 1: If CPUID doesn't even report VMX, definitely not available */
|
||||
if (!vmx_supported()) return 0;
|
||||
|
||||
/* Step 2: Check if running under a hypervisor */
|
||||
u32 eax, ebx, ecx, edx;
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
if (!(ecx & (1U << 31))) {
|
||||
/* No hypervisor — bare metal, VMX should work */
|
||||
return 1;
|
||||
}
|
||||
log_info("[VMX] hypervisor present bit set, checking nested VMX support");
|
||||
|
||||
/* Step 3: Try reading IA32_VMX_BASIC — if it's zero or faults,
|
||||
* the hypervisor doesn't expose real VMX. */
|
||||
/* We use a safe read: if the MSR doesn't exist, rdmsr would #GP.
|
||||
* However, under WHPX, IA32_VMX_BASIC may return a non-zero value
|
||||
* even though VMXON will fail. So we need another check. */
|
||||
|
||||
/* Step 4: Check hypervisor vendor for nested VMX support */
|
||||
cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
/* Check for Hyper-V ("Microsoft Hv") */
|
||||
if (ebx == 0x7263694DU && ecx == 0x666F736FU && edx == 0x76482074U) {
|
||||
log_info("[VMX] Hyper-V detected");
|
||||
/* Check if HV_CPU_MANAGEMENT_FEATURES (MSR 0x4000000F) exists.
|
||||
* Hyper-V CPUID leaf 0x40000003 tells us which MSRs are available.
|
||||
* Partition_privileges bit 1 (nested virtualization) is at EBX bit 1
|
||||
* of CPUID 0x40000000 + 3 = 0x40000003.
|
||||
* But safer: just check the max CPUID leaf for Hyper-V. */
|
||||
u32 hv_max_leaf = eax;
|
||||
if (hv_max_leaf >= 0x40000003) {
|
||||
/* CPUID 0x40000003 EBX bit 1 = AccessIntrCtrl (nested) */
|
||||
cpuid(0x40000003, &eax, &ebx, &ecx, &edx);
|
||||
if (ebx & (1U << 1)) {
|
||||
log_info("[VMX] Hyper-V nested virtualization supported");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
log_warn("[VMX] Hyper-V WITHOUT nested VMX support");
|
||||
log_warn("[VMX] CR4.VMXE / VMXON would cause fatal exit, skipping");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for KVM ("KVMKVMKVM") */
|
||||
if (ebx == 0x4B4D564BU && ecx == 0x564B4D56U && edx == 0x4D564B4DU) {
|
||||
log_info("[VMX] KVM detected — nested VMX may be available");
|
||||
/* KVM typically supports nested VMX if enabled */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Unknown hypervisor — be conservative: skip VMX to avoid
|
||||
* fatal exits. The user must explicitly enable nested VMX on
|
||||
* their hypervisor for Linux compat to work. */
|
||||
log_warn("[VMX] unknown hypervisor, VMX may not be truly available");
|
||||
log_warn("[VMX] skipping VMX init to avoid potential fatal exit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vmx_enable(void) {
|
||||
if (g_vmx_enabled) return 0;
|
||||
|
||||
if (!vmx_supported()) {
|
||||
log_error("[VMX] CPU does not support VMX");
|
||||
if (!vmx_truly_available()) {
|
||||
log_warn("[VMX] VMX not truly available, skipping VMX init");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
# Build initramfs only (assumes bzImage already built)
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="/mnt/d/Code/Deshab/CODE/linux"
|
||||
PROJECT_ROOT="/mnt/d/Code/Deshab"
|
||||
OUTPUT_DIR="$PROJECT_ROOT/SYSTEM/boot"
|
||||
INITRAMFS_DIR="$SCRIPT_DIR/initramfs"
|
||||
LINUX_SRC="$HOME/linux-6.6"
|
||||
INITRAMFS_TMP="$SCRIPT_DIR/initramfs.tmp"
|
||||
|
||||
rm -rf "$INITRAMFS_TMP"
|
||||
mkdir -p "$INITRAMFS_TMP/bin"
|
||||
cp -a "$INITRAMFS_DIR"/* "$INITRAMFS_TMP"/
|
||||
|
||||
# Download static busybox
|
||||
BUSYBOX_CACHE="$SCRIPT_DIR/.cache/busybox"
|
||||
BUSYBOX_URL="https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox"
|
||||
if [ ! -x "$BUSYBOX_CACHE" ]; then
|
||||
echo "[initrd] Downloading static busybox..."
|
||||
mkdir -p "$(dirname "$BUSYBOX_CACHE")"
|
||||
curl -fL --retry 3 -o "$BUSYBOX_CACHE" "$BUSYBOX_URL"
|
||||
chmod +x "$BUSYBOX_CACHE"
|
||||
fi
|
||||
cp "$BUSYBOX_CACHE" "$INITRAMFS_TMP/bin/busybox"
|
||||
chmod +x "$INITRAMFS_TMP/bin/busybox"
|
||||
echo "[initrd] busybox copied"
|
||||
|
||||
# Build utsm_exec_daemon
|
||||
DAEMON_SRC="$INITRAMFS_DIR/bin/utsm_exec_daemon.c"
|
||||
if [ -f "$DAEMON_SRC" ]; then
|
||||
echo "[initrd] Compiling utsm_exec_daemon..."
|
||||
cc -static -O2 -Wall "-I$PROJECT_ROOT/CODE/utsm-ipc" \
|
||||
-o "$INITRAMFS_TMP/bin/utsm_exec_daemon" "$DAEMON_SRC"
|
||||
strip "$INITRAMFS_TMP/bin/utsm_exec_daemon" 2>/dev/null || true
|
||||
echo "[initrd] daemon compiled"
|
||||
fi
|
||||
|
||||
# gen_init_cpio
|
||||
GEN_INIT_CPIO="$LINUX_SRC/usr/gen_init_cpio"
|
||||
if [ ! -x "$GEN_INIT_CPIO" ]; then
|
||||
echo "[initrd] Building gen_init_cpio..."
|
||||
cd "$LINUX_SRC" && make usr/ >/dev/null
|
||||
fi
|
||||
|
||||
SPEC="$SCRIPT_DIR/initramfs.tmp.spec"
|
||||
{
|
||||
echo "dir /bin 755 0 0"
|
||||
echo "dir /dev 755 0 0"
|
||||
echo "dir /proc 755 0 0"
|
||||
echo "dir /sys 755 0 0"
|
||||
echo "nod /dev/console 600 0 0 c 5 1"
|
||||
echo "nod /dev/null 666 0 0 c 1 3"
|
||||
echo "nod /dev/ttyS0 600 0 0 c 4 64"
|
||||
echo "file /init $INITRAMFS_TMP/init 755 0 0"
|
||||
echo "file /bin/busybox $INITRAMFS_TMP/bin/busybox 755 0 0"
|
||||
if [ -f "$INITRAMFS_TMP/bin/utsm_exec_daemon" ]; then
|
||||
echo "file /bin/utsm_exec_daemon $INITRAMFS_TMP/bin/utsm_exec_daemon 755 0 0"
|
||||
fi
|
||||
for app in sh mount umount echo sleep uname ls cat ps setsid cttyhack; do
|
||||
echo "slink /bin/$app /bin/busybox 777 0 0"
|
||||
done
|
||||
} > "$SPEC"
|
||||
|
||||
"$GEN_INIT_CPIO" "$SPEC" | gzip -9 > "$OUTPUT_DIR/linux-initrd.img"
|
||||
echo "[initrd] Done: $OUTPUT_DIR/linux-initrd.img"
|
||||
ls -lh "$OUTPUT_DIR/linux-initrd.img"
|
||||
rm -rf "$INITRAMFS_TMP" "$SPEC"
|
||||
@@ -27,7 +27,9 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
/* Shared IPC protocol header (included via build.sh -I flag) */
|
||||
/* Shared IPC protocol header (included via build.sh -I flag).
|
||||
* We provide our own hypercall wrappers, so skip the inline ones. */
|
||||
#define UTSM_NO_INLINE_HCALL
|
||||
#include <ipc_proto.h>
|
||||
|
||||
#define UTSM_DEV_NAME "utsm"
|
||||
@@ -382,7 +384,7 @@ static int __init utsm_hcall_init(void)
|
||||
/* 3. Query shared memory info */
|
||||
ret = utsm_hcall_shm_info(&shm_gpa, &shm_size);
|
||||
if (ret != 0) {
|
||||
pr_err("[utsm] SHM_INFO hypercall failed: %ld\n", ret);
|
||||
pr_err("[utsm] SHM_INFO hypercall failed: %d\n", ret);
|
||||
goto err_no_shm;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,19 @@
|
||||
* 0x04002040: payload pool (for large data transfers)
|
||||
*/
|
||||
|
||||
/* Kernel-space uses kernel types, user-space uses <stdint.h>.
|
||||
* UTSM kernel defines __UTSM_KERNEL__, Linux kernel auto-defines __KERNEL__. */
|
||||
#if defined(__KERNEL__)
|
||||
#include <linux/types.h>
|
||||
/* Linux kernel uses __u32/__u64/__u8; map to stdint names for shared structs */
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u32 uint32_t;
|
||||
typedef __u64 uint64_t;
|
||||
#elif defined(__UTSM_KERNEL__)
|
||||
#include <utsm/types.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
/* ===== Constants ===== */
|
||||
|
||||
@@ -227,10 +239,15 @@ static inline int utsm_ipc_ring_full(const struct utsm_ipc_ring *ring) {
|
||||
* RAX = return value (UTSM_HCALL_OK or error)
|
||||
*
|
||||
* The magic in RAX distinguishes UTSM hypercalls from other VMCALL users.
|
||||
*
|
||||
* Define UTSM_NO_INLINE_HCALL before including this header if you provide
|
||||
* your own hypercall wrapper implementations (e.g. Linux utsm_hcall.c).
|
||||
*/
|
||||
|
||||
#define UTSM_HCALL_MAGIC 0x5554534D48430000ULL /* "UTSMHC\00\00" */
|
||||
|
||||
#ifndef UTSM_NO_INLINE_HCALL
|
||||
|
||||
static inline long utsm_hcall(uint64_t op, uint64_t a0, uint64_t a1, uint64_t a2) {
|
||||
long ret;
|
||||
__asm__ volatile("vmcall"
|
||||
@@ -263,4 +280,6 @@ static inline long utsm_hcall_console_write(const char *buf, uint64_t len) {
|
||||
return utsm_hcall(UTSM_HCALL_CONSOLE_WRITE, (uint64_t)buf, len, 0);
|
||||
}
|
||||
|
||||
#endif /* UTSM_NO_INLINE_HCALL */
|
||||
|
||||
#endif /* UTSM_IPC_PROTO_H */
|
||||
|
||||
Reference in New Issue
Block a user