diff --git a/debian/control b/debian/control index 33f05d8..703443f 100644 --- a/debian/control +++ b/debian/control @@ -15,11 +15,9 @@ Architecture: all Depends: coreutils, curl, - gdisk, genisoimage, jq, mesa-utils, - mtools, pciutils, procps, python3-minimal, diff --git a/devshell.nix b/devshell.nix index 45890f1..4b07a9d 100644 --- a/devshell.nix +++ b/devshell.nix @@ -16,9 +16,7 @@ mkShell { gawk gnugrep gnused - gptfdisk jq - mtools pciutils procps python3 diff --git a/package.nix b/package.nix index f511020..638bc24 100644 --- a/package.nix +++ b/package.nix @@ -10,10 +10,8 @@ gawk, gnugrep, gnused, - gptfdisk, jq, mesa-demos, - mtools, pciutils, procps, python3, @@ -38,9 +36,7 @@ let gawk gnugrep gnused - gptfdisk jq - mtools pciutils procps python3 diff --git a/quickemu b/quickemu index 96097ca..bc125d6 100755 --- a/quickemu +++ b/quickemu @@ -915,20 +915,13 @@ function configure_bios() { fi # Check for OpenCore bootloader - # Backwards compatibility: If OpenCore.qcow2 exists, use legacy two-disk boot method - # If OpenCore.qcow2 is absent, assume OpenCore is integrated in the main disk if [ -e "${VMDIR}/OpenCore.qcow2" ]; then MAC_BOOTLOADER="${VMDIR}/OpenCore.qcow2" - MAC_BOOT_MODE="legacy" elif [ -e "${VMDIR}/ESP.qcow2" ]; then # Backwards compatibility for Clover MAC_BOOTLOADER="${VMDIR}/ESP.qcow2" - MAC_BOOT_MODE="legacy" else - # New method: OpenCore is integrated in the main disk's EFI partition - # No separate bootloader file needed - MAC_BOOTLOADER="" - MAC_BOOT_MODE="integrated" + MAC_MISSING="Bootloader" fi if [ -n "${MAC_MISSING}" ]; then @@ -936,11 +929,7 @@ function configure_bios() { echo " Use 'quickget' to download the required files." exit 1 fi - if [ "${MAC_BOOT_MODE}" == "integrated" ]; then - BOOT_STATUS="EFI (macOS), OVMF ($(basename "${EFI_CODE}")), OpenCore (integrated), SecureBoot (${secureboot})." - else - BOOT_STATUS="EFI (macOS), OVMF ($(basename "${EFI_CODE}")), SecureBoot (${secureboot})." - fi + BOOT_STATUS="EFI (macOS), OVMF ($(basename "${EFI_CODE}")), SecureBoot (${secureboot})." elif [[ "${boot}" == *"efi"* ]]; then EFI_VARS="${VMDIR}/OVMF_VARS.fd" @@ -1182,15 +1171,7 @@ function configure_storage() { # Only check disk image size if preallocation is off if [ "${preallocation}" == "off" ]; then DISK_CURR_SIZE=$(${STAT} -c%s "${disk_img}") - # For macOS with integrated OpenCore, the disk is pre-created with an EFI - # partition containing OpenCore (~500MB). Use a higher threshold (1GB) to - # distinguish between "just EFI" and "EFI + installed macOS". - if [ "${guest_os}" == "macos" ] && [ "${MAC_BOOT_MODE}" == "integrated" ]; then - DISK_MIN_SIZE_CHECK=$((1024 * 1024 * 1024)) - else - DISK_MIN_SIZE_CHECK="${DISK_MIN_SIZE}" - fi - if [ "${DISK_CURR_SIZE}" -le "${DISK_MIN_SIZE_CHECK}" ]; then + if [ "${DISK_CURR_SIZE}" -le "${DISK_MIN_SIZE}" ]; then echo " Looks unused, booting from ${iso}${img}" if [ -z "${iso}" ] && [ -z "${img}" ]; then echo "ERROR! You haven't specified a .iso or .img image to boot from." @@ -1608,7 +1589,6 @@ function vm_boot() { OS_RELEASE="Unknown OS" MACHINE_TYPE="${MACHINE_TYPE:-q35}" MAC_BOOTLOADER="" - MAC_BOOT_MODE="" MAC_MISSING="" MAC_DISK_DEV="${MAC_DISK_DEV:-ide-hd,bus=ahci.2}" NET_DEVICE="${NET_DEVICE:-virtio-net-pci}" @@ -1973,36 +1953,19 @@ function vm_boot() { if [ "${guest_os}" == "macos" ]; then # shellcheck disable=SC2054 - args+=(-device ahci,id=ahci) + args+=(-device ahci,id=ahci + -device ide-hd,bus=ahci.0,drive=BootLoader,bootindex=0 + -drive id=BootLoader,if=none,format=qcow2,file="${MAC_BOOTLOADER}") - if [ -n "${MAC_BOOTLOADER}" ]; then - # Legacy mode: boot from separate OpenCore.qcow2 + if [ -n "${img}" ]; then # shellcheck disable=SC2054 - args+=(-device ide-hd,bus=ahci.0,drive=BootLoader,bootindex=0 - -drive id=BootLoader,if=none,format=qcow2,file="${MAC_BOOTLOADER}") - - if [ -n "${img}" ]; then - # shellcheck disable=SC2054 - args+=(-device ide-hd,bus=ahci.1,drive=RecoveryImage - -drive id=RecoveryImage,if=none,format=raw,file="${img}") - fi - - # shellcheck disable=SC2054,SC2206 - args+=(-device ${MAC_DISK_DEV},drive=SystemDisk - -drive id=SystemDisk,if=none,format=qcow2,file="${disk_img}",${DRIVE_OPTIMISATIONS} ${STATUS_QUO}) - else - # Integrated mode: OpenCore is in the main disk's EFI partition - # Boot directly from the main disk - # shellcheck disable=SC2054,SC2206 - args+=(-device ${MAC_DISK_DEV},drive=SystemDisk,bootindex=0 - -drive id=SystemDisk,if=none,format=qcow2,file="${disk_img}",${DRIVE_OPTIMISATIONS} ${STATUS_QUO}) - - if [ -n "${img}" ]; then - # shellcheck disable=SC2054 - args+=(-device ide-hd,bus=ahci.0,drive=RecoveryImage - -drive id=RecoveryImage,if=none,format=raw,file="${img}") - fi + args+=(-device ide-hd,bus=ahci.1,drive=RecoveryImage + -drive id=RecoveryImage,if=none,format=raw,file="${img}") fi + + # shellcheck disable=SC2054,SC2206 + args+=(-device ${MAC_DISK_DEV},drive=SystemDisk + -drive id=SystemDisk,if=none,format=qcow2,file="${disk_img}",${DRIVE_OPTIMISATIONS} ${STATUS_QUO}) elif [ "${guest_os}" == "kolibrios" ]; then # shellcheck disable=SC2054,SC2206 args+=(-device ahci,id=ahci diff --git a/quickget b/quickget index 7bf122e..d553092 100755 --- a/quickget +++ b/quickget @@ -237,192 +237,6 @@ function require_qemu_img() { fi } -function require_mtools() { - local MFORMAT="" - local MCOPY="" - local MMD="" - MFORMAT=$(command -v mformat) - MCOPY=$(command -v mcopy) - MMD=$(command -v mmd) - if [ ! -x "${MFORMAT}" ] || [ ! -x "${MCOPY}" ] || [ ! -x "${MMD}" ]; then - echo "ERROR! mtools not found. Please install mtools (mformat, mcopy, mmd)." - exit 1 - fi -} - -function require_sgdisk() { - local SGDISK="" - SGDISK=$(command -v sgdisk) - if [ ! -x "${SGDISK}" ]; then - echo "ERROR! sgdisk not found. Please install gptfdisk (gdisk package)." - exit 1 - fi -} - -# Create a raw disk image with GPT partition table and EFI partition containing OpenCore -# Usage: create_macos_disk_with_opencore -# The disk will have: -# - Partition 1: EFI System Partition (200MB FAT32) containing OpenCore -# - Remaining space: unallocated (macOS will create its partitions during install) -function create_macos_disk_with_opencore() { - local DISK_PATH="${1}" - local DISK_SIZE="${2}" - local OPENCORE_DIR="${3}" - local TEMP_DISK="" - local EFI_OFFSET_BYTES="" - local SGDISK="" - local MFORMAT="" - local MMD="" - local MCOPY="" - - require_sgdisk - require_mtools - require_qemu_img - - SGDISK=$(command -v sgdisk) - MFORMAT=$(command -v mformat) - MMD=$(command -v mmd) - MCOPY=$(command -v mcopy) - - echo " - Creating macOS disk with integrated OpenCore..." - - # Create a temporary raw disk image - TEMP_DISK="${DISK_PATH}.raw" - - # Create the raw disk image - if ! ${QEMU_IMG} create -f raw "${TEMP_DISK}" "${DISK_SIZE}" >/dev/null 2>&1; then - echo "ERROR! Failed to create raw disk image." - rm -f "${TEMP_DISK}" - return 1 - fi - - # Create GPT partition table with EFI partition - # Partition 1: EFI System Partition, 200MB starting at sector 2048 (1MiB offset) - # Using type EF00 (EFI System) - if ! ${SGDISK} --clear \ - --new=1:2048:+200M --typecode=1:EF00 --change-name=1:"EFI" \ - "${TEMP_DISK}" >/dev/null 2>&1; then - echo "ERROR! Failed to create GPT partition table." - rm -f "${TEMP_DISK}" - return 1 - fi - - # Calculate EFI partition offset in bytes (sector 2048 * 512 bytes/sector = 1MiB) - EFI_OFFSET_BYTES=$((2048 * 512)) - - # Format the EFI partition as FAT32 using mtools - # The -i option with @@offset allows operating on a partition within an image - if ! ${MFORMAT} -i "${TEMP_DISK}@@${EFI_OFFSET_BYTES}" -F -v "EFI" :: 2>/dev/null; then - echo "ERROR! Failed to format EFI partition." - rm -f "${TEMP_DISK}" - return 1 - fi - - # Create the EFI directory structure - ${MMD} -i "${TEMP_DISK}@@${EFI_OFFSET_BYTES}" ::/EFI 2>/dev/null - # Note: Only create the top-level EFI directory; mcopy -s will create subdirectories - - # Copy OpenCore files to the EFI partition - # mcopy -s recursively copies directories including their contents - # This preserves .kext bundle structure (directories with Contents/Info.plist) - if [ -d "${OPENCORE_DIR}/EFI/BOOT" ]; then - if ! LC_ALL='' ${MCOPY} -i "${TEMP_DISK}@@${EFI_OFFSET_BYTES}" -s "${OPENCORE_DIR}/EFI/BOOT" ::/EFI/; then - echo "ERROR! Failed to copy EFI/BOOT to disk." - rm -f "${TEMP_DISK}" - return 1 - fi - fi - if [ -d "${OPENCORE_DIR}/EFI/OC" ]; then - if ! LC_ALL='' ${MCOPY} -i "${TEMP_DISK}@@${EFI_OFFSET_BYTES}" -s "${OPENCORE_DIR}/EFI/OC" ::/EFI/; then - echo "ERROR! Failed to copy EFI/OC to disk." - rm -f "${TEMP_DISK}" - return 1 - fi - fi - - # Convert the raw image to qcow2 format - if ! ${QEMU_IMG} convert -f raw -O qcow2 "${TEMP_DISK}" "${DISK_PATH}" >/dev/null 2>&1; then - echo "ERROR! Failed to convert disk to qcow2 format." - rm -f "${TEMP_DISK}" - return 1 - fi - - # Clean up temporary raw image - rm -f "${TEMP_DISK}" - - echo " - macOS disk with integrated OpenCore created successfully." - return 0 -} - -# Download and extract OpenCore files from OSX-KVM repository -# Usage: download_opencore -function download_opencore() { - local DEST_DIR="${1}" - local OPENCORE_URL="https://github.com/kholia/OSX-KVM/raw/master/OpenCore/OpenCore.qcow2" - local TEMP_QCOW2="" - local TEMP_RAW="" - local MCOPY="" - - require_qemu_img - require_mtools - - MCOPY=$(command -v mcopy) - TEMP_QCOW2="${DEST_DIR}/OpenCore_temp.qcow2" - TEMP_RAW="${DEST_DIR}/OpenCore_temp.raw" - - echo " - Downloading OpenCore bootloader..." - if ! web_get "${OPENCORE_URL}" "${DEST_DIR}" "OpenCore_temp.qcow2"; then - echo "ERROR! Failed to download OpenCore." - return 1 - fi - - # Convert qcow2 to raw so we can extract files with mtools - echo " - Extracting OpenCore files..." - if ! ${QEMU_IMG} convert -f qcow2 -O raw "${TEMP_QCOW2}" "${TEMP_RAW}" >/dev/null 2>&1; then - echo "ERROR! Failed to convert OpenCore image." - rm -f "${TEMP_QCOW2}" - return 1 - fi - - # Create destination directory (mcopy will create BOOT and OC subdirs) - mkdir -p "${DEST_DIR}/EFI" - - # The OpenCore.qcow2 from OSX-KVM is a disk image with an EFI partition - # The EFI partition starts at sector 2048 (1MiB offset) - local EFI_OFFSET=$((2048 * 512)) - - # Extract files using mtools - # Note: mcopy -s recursively copies directories, preserving the full structure - # including .kext bundles (which are directories containing Contents/Info.plist) - # LC_ALL='' prevents mtools from mangling directory names (BOOT -> BOOT_) - if ! LC_ALL='' ${MCOPY} -i "${TEMP_RAW}@@${EFI_OFFSET}" -s ::/EFI/BOOT "${DEST_DIR}/EFI/"; then - echo "ERROR! Failed to extract EFI/BOOT from OpenCore image." - rm -f "${TEMP_QCOW2}" "${TEMP_RAW}" - return 1 - fi - if ! LC_ALL='' ${MCOPY} -i "${TEMP_RAW}@@${EFI_OFFSET}" -s ::/EFI/OC "${DEST_DIR}/EFI/"; then - echo "ERROR! Failed to extract EFI/OC from OpenCore image." - rm -f "${TEMP_QCOW2}" "${TEMP_RAW}" - return 1 - fi - - # Clean up temporary files - rm -f "${TEMP_QCOW2}" "${TEMP_RAW}" - - # Verify extraction was successful - check both boot file and a kext plist - if [ ! -f "${DEST_DIR}/EFI/BOOT/BOOTx64.efi" ]; then - echo "ERROR! Failed to extract OpenCore boot file." - return 1 - fi - if [ ! -f "${DEST_DIR}/EFI/OC/Kexts/Lilu.kext/Contents/Info.plist" ]; then - echo "ERROR! Failed to extract OpenCore kexts (Lilu.kext/Contents/Info.plist missing)." - return 1 - fi - - echo " - OpenCore files extracted successfully." - return 0 -} - function is_valid_language() { local I18N="" local PASSED_I18N="${1}" @@ -2481,9 +2295,6 @@ function get_macos() { local CHUNKCHECK="" local MLB="00000000000000000" local OS_TYPE="default" - local USE_INTEGRATED_OPENCORE=1 - local OPENCORE_TEMP_DIR="" - local MCOPY="" case ${RELEASE} in lion|10.7) @@ -2539,13 +2350,6 @@ function get_macos() { CHUNKCHECK="$(command -v chunkcheck)" fi - # Check if mtools and sgdisk are available for integrated OpenCore - MCOPY=$(command -v mcopy) - if [ ! -x "${MCOPY}" ] || [ ! -x "$(command -v mformat)" ] || [ ! -x "$(command -v mmd)" ] || [ ! -x "$(command -v sgdisk)" ]; then - echo " - NOTE: mtools or sgdisk not found, using legacy OpenCore.qcow2 method." - USE_INTEGRATED_OPENCORE=0 - fi - appleSession=$(curl --disable -v -H "Host: osrecovery.apple.com" \ -H "Connection: close" \ -A "InternetRecovery/1.0" https://osrecovery.apple.com/ 2>&1 | tr ';' '\n' | awk -F'session=|;' '{print $2}' | grep 1) @@ -2595,44 +2399,12 @@ function get_macos() { echo " - RecoveryImage.img is ready." fi - echo "Downloading UEFI firmware" + echo "Downloading OpenCore & UEFI firmware" + web_get "https://github.com/kholia/OSX-KVM/raw/master/OpenCore/OpenCore.qcow2" "${VM_PATH}" web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_CODE.fd" "${VM_PATH}" if [ ! -e "${VM_PATH}/OVMF_VARS-1920x1080.fd" ]; then web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_VARS-1920x1080.fd" "${VM_PATH}" fi - - if [ "${USE_INTEGRATED_OPENCORE}" -eq 1 ]; then - # Create disk with integrated OpenCore (new method) - echo "Creating disk with integrated OpenCore bootloader" - - # Create temporary directory for OpenCore extraction - OPENCORE_TEMP_DIR="${VM_PATH}/.opencore_temp" - mkdir -p "${OPENCORE_TEMP_DIR}" - - # Download and extract OpenCore files - if download_opencore "${OPENCORE_TEMP_DIR}"; then - # Create the main disk with integrated OpenCore EFI partition - # Default size is 128G (can be overridden in config) - if create_macos_disk_with_opencore "${VM_PATH}/disk.qcow2" "128G" "${OPENCORE_TEMP_DIR}"; then - echo " - Integrated OpenCore disk created successfully." - else - echo " - WARNING: Failed to create integrated OpenCore disk, falling back to legacy method." - USE_INTEGRATED_OPENCORE=0 - fi - else - echo " - WARNING: Failed to download OpenCore, falling back to legacy method." - USE_INTEGRATED_OPENCORE=0 - fi - - # Clean up temporary directory - rm -rf "${OPENCORE_TEMP_DIR}" - fi - - if [ "${USE_INTEGRATED_OPENCORE}" -eq 0 ]; then - # Legacy method: separate OpenCore.qcow2 file - echo "Downloading OpenCore bootloader (legacy method)" - web_get "https://github.com/kholia/OSX-KVM/raw/master/OpenCore/OpenCore.qcow2" "${VM_PATH}" - fi fi make_vm_config RecoveryImage.img }