This commit is contained in:
xyou
2026-07-29 10:26:25 +08:00
parent 2774c10d0c
commit 5ea84fac97
32 changed files with 6385 additions and 35 deletions
+76 -2
View File
@@ -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.
+68
View File
@@ -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"
+4 -2
View File
@@ -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;
}
+19
View File
@@ -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 */