Add x86_64 kernel bring-up with build-selected platform adapters
This commit is contained in:
1 parent
e8e4061564
commit
6a1eb5e2ac
69 files changed
+4981
-1502
No files matched your search
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2026 Aaron Hance
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Prevent shared Pascal units from selecting architecture implementations."""
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
cpu_directive = re.compile(r"\{\$\s*if(?:def|ndef)?\b[^}]*\bCPU\w*", re.I)
|
||||
arch_import = re.compile(r"\barch\.(?:x86|x86_64)\.", re.I)
|
||||
errors = []
|
||||
for path in sorted(Path("src").rglob("*")):
|
||||
if path.suffix not in (".pas", ".inc"):
|
||||
continue
|
||||
if path.parts[1] == "arch" and path.parts[2] != "common":
|
||||
continue
|
||||
source = path.read_text(encoding="utf-8")
|
||||
# Ignore prose comments but retain compiler directives.
|
||||
source = re.sub(r"\{(?!\$).*?\}|\(\*.*?\*\)|//[^\n]*", "", source, flags=re.S)
|
||||
if cpu_directive.search(source):
|
||||
errors.append(f"{path}: CPU conditional belongs in build selection")
|
||||
# Existing i386-only services outside the port still import their drivers.
|
||||
# The migrated units must depend on stable platform names instead.
|
||||
migrated = path.as_posix() in {
|
||||
"src/core/core.util.pas", "src/core/strings/core.strings.pas",
|
||||
"src/io/io.stdio.pas", "src/proc/proc.mgr.pas",
|
||||
"src/memory/memory.heap.pas", "src/memory/memory.raw.pas",
|
||||
} or path.parts[1:3] == ("arch", "common")
|
||||
if migrated and arch_import.search(source):
|
||||
errors.append(f"{path}: shared unit imports an architecture implementation")
|
||||
if errors:
|
||||
print("\n".join(errors), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print("Shared architecture boundaries verified.")
|
||||
+22
-5
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
|
||||
ERRCOUNT=0
|
||||
echo " "
|
||||
echo "======================="
|
||||
@@ -6,8 +7,11 @@ echo " "
|
||||
echo "Asuro Compilation"
|
||||
echo " "
|
||||
|
||||
#Compile Stub.asm
|
||||
rm -f lib/*
|
||||
TOOLCHAIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$TOOLCHAIN_DIR/target.sh"
|
||||
mkdir -p "$OBJ_DIR" "$BIN_DIR"
|
||||
# Clean only this target's generated objects; preserve other architectures.
|
||||
find "$OBJ_DIR" -maxdepth 1 -type f \( -name '*.o' -o -name '*.ppu' -o -name '*.a' \) -delete
|
||||
|
||||
runOrFail() {
|
||||
local binary=$1
|
||||
@@ -20,8 +24,6 @@ runOrFail() {
|
||||
fi
|
||||
}
|
||||
|
||||
TOOLCHAIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
declare -a run_steps=(
|
||||
"compile_stub.sh" "Failed to compile stub!"
|
||||
"compile_vergen.sh" "Versions failed to compile"
|
||||
@@ -35,6 +37,16 @@ declare -a run_steps=(
|
||||
"compile_docs.sh" "Failed to generate documentation!"
|
||||
)
|
||||
|
||||
if [ "$ASURO_ARCH" = x86_64 ]; then
|
||||
# Bootstrap milestone: no desktop/runtime dependencies until they are ported.
|
||||
run_steps=(
|
||||
"compile_stub.sh" "Failed to compile stub!"
|
||||
"compile_sources.sh" "Failed to compile FPC Sources!"
|
||||
"compile_link.sh" "Failed linking!"
|
||||
"compile_isogen.sh" "Failed to create ISO!"
|
||||
)
|
||||
fi
|
||||
|
||||
for ((i=0; i<${#run_steps[@]}; i+=2))
|
||||
do
|
||||
if [ "$ERRCOUNT" -eq "0" ]
|
||||
@@ -46,6 +58,11 @@ do
|
||||
done
|
||||
|
||||
#Call generate final artifacts based on failure or success of the above.
|
||||
if [ "$ASURO_ARCH" = x86_64 ]; then
|
||||
if [ "$ERRCOUNT" -ne 0 ]; then exit 1; fi
|
||||
echo "No errors. Bootstrap image: $ISO_FILE"
|
||||
exit 0
|
||||
fi
|
||||
if [ "$ERRCOUNT" -ne "0" ]
|
||||
then
|
||||
. "${TOOLCHAIN_DIR}/compile_finish.sh" "failed"
|
||||
@@ -53,4 +70,4 @@ else
|
||||
. "${TOOLCHAIN_DIR}/compile_finish.sh" "success"
|
||||
fi
|
||||
|
||||
cd ..
|
||||
cd ..
|
||||
@@ -1,8 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
|
||||
set -e
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
|
||||
echo " "
|
||||
echo "======================="
|
||||
echo " "
|
||||
echo "Creating ISO..."
|
||||
echo " "
|
||||
cp bin/kernel.bin iso/boot/asuro.bin
|
||||
grub-mkrescue -o Asuro.iso iso
|
||||
mkdir -p "$ISO_ROOT/boot/grub"
|
||||
if [ "$ASURO_ARCH" != x86 ]; then
|
||||
cp iso/boot/grub/grub.cfg "$ISO_ROOT/boot/grub/grub.cfg"
|
||||
fi
|
||||
cp "$BIN_DIR/kernel.bin" "$ISO_ROOT/boot/asuro.bin"
|
||||
grub-mkrescue -o "$ISO_FILE" "$ISO_ROOT"
|
||||
@@ -1,11 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
|
||||
set -e
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
|
||||
echo " "
|
||||
echo "======================="
|
||||
echo " "
|
||||
echo "Linking..."
|
||||
echo " "
|
||||
if [ "$ASURO_ARCH" = x86_64 ]; then
|
||||
ld -m "$LD_FORMAT" --gc-sections --no-warn-execstack \
|
||||
-T"$LINKER_SCRIPT" -o "$BIN_DIR/kernel.bin" "$OBJ_DIR/"*.o
|
||||
grub-file --is-x86-multiboot "$BIN_DIR/kernel.bin"
|
||||
exit
|
||||
fi
|
||||
objstring="";
|
||||
for object in `find lib/ -name "*.o"`; do
|
||||
for object in `find lib/ -maxdepth 1 -name "*.o"`; do
|
||||
if [ "$object" != "lib/stub.o" ]
|
||||
then
|
||||
objstring=$objstring$object" ";
|
||||
@@ -19,4 +28,4 @@ echo " "
|
||||
LIBGCC=$(gcc -m32 -print-libgcc-file-name)
|
||||
echo "libgcc: ${LIBGCC}"
|
||||
|
||||
ld -m elf_i386 -s --gc-sections --no-warn-execstack -Ttoolchain/linker.script -o bin/kernel.bin $objstring --start-group lib/liblvgl.a ${LIBGCC} --end-group
|
||||
ld -m elf_i386 -s --gc-sections --no-warn-execstack -Ttoolchain/linker.script -o bin/kernel.bin $objstring --start-group lib/liblvgl.a ${LIBGCC} --end-group
|
||||
@@ -1,13 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
|
||||
set -e
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
|
||||
echo " "
|
||||
echo "======================="
|
||||
echo " "
|
||||
echo "Compiling FPC Sources..."
|
||||
echo " "
|
||||
# Build -Fu flags for all directories under src/, wasuro/ and compat/
|
||||
FU_PATHS="-Fusrc -Fuwasuro -Fucompat"
|
||||
for dir in $(find src wasuro compat -type d 2>/dev/null); do
|
||||
# The build selects one platform implementation; shared units cannot select CPUs.
|
||||
python3 toolchain/check_arch_boundaries.py
|
||||
# Build -Fu flags for the selected architecture and shared sources.
|
||||
if [ "$ASURO_ARCH" = x86_64 ]; then
|
||||
test_flags=()
|
||||
case "${ASURO_BOOT_TEST:-none}" in
|
||||
none) ;;
|
||||
ud) test_flags=(-dASURO_TEST_UD) ;;
|
||||
pf) test_flags=(-dASURO_TEST_PF) ;;
|
||||
df) test_flags=(-dASURO_TEST_DF) ;;
|
||||
*) echo "Unknown ASURO_BOOT_TEST" >&2; exit 1 ;;
|
||||
esac
|
||||
# Restrict search paths: never accidentally select the i386 system unit.
|
||||
exec ppcx64 -n -O2 -Si -Sc -Sg -Xd -CX -Rintel -Tlinux \
|
||||
-Fu"src/arch/$ASURO_ARCH/platform" -Fusrc/core -Fusrc/core/strings -Fusrc/driver/storage -Fusrc/arch/x86_64/proc -Fusrc/core/ds -Fusrc/proc -Fusrc/io -Fusrc/arch/common -Fusrc/debug -Fusrc/boot -Fusrc/memory -Fusrc/arch/x86_64/memory -Fu"src/arch/x86_64" -FU"$OBJ_DIR" -FE"$BIN_DIR" "${test_flags[@]}" \
|
||||
src/arch/x86_64/arch.x86_64.boot.pas
|
||||
fi
|
||||
FU_PATHS="-Fusrc/arch/$ASURO_ARCH/platform -Fusrc -Fuwasuro -Fucompat"
|
||||
for dir in $(find src wasuro compat -type d -not -path 'src/arch/*' 2>/dev/null) \
|
||||
$(find "src/arch/$ASURO_ARCH" src/arch/common -type d -not -path '*/platform*'); do
|
||||
FU_PATHS="$FU_PATHS -Fu$dir"
|
||||
done
|
||||
|
||||
fpc -Aelf -gw -g -gl -n -v0e -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/asuro.pas
|
||||
fpc -Aelf -gw -g -gl -n -v0e -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/asuro.pas
|
||||
@@ -1,8 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
|
||||
set -e
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
|
||||
echo " "
|
||||
echo "======================="
|
||||
echo " "
|
||||
echo "Compiling Stub..."
|
||||
echo " "
|
||||
nasm -f elf src/arch/x86/boot/stub.asm -o lib/stub.o
|
||||
nasm -f elf src/boot/splash_tga.asm -o lib/splash_tga.o
|
||||
nasm -f "$NASM_FORMAT" "src/arch/$ASURO_ARCH/boot/stub.asm" -o "$OBJ_DIR/stub.o"
|
||||
if [ "$ASURO_ARCH" = x86 ]; then
|
||||
nasm -f "$NASM_FORMAT" src/boot/splash_tga.asm -o "$OBJ_DIR/splash_tga.o"
|
||||
else
|
||||
nasm -f "$NASM_FORMAT" src/arch/x86_64/isr/entry.asm -o "$OBJ_DIR/isr_entry.o"
|
||||
fi
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2026 Aaron Hance
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# Shared target selection. Source this file from build steps.
|
||||
ASURO_ARCH="${ASURO_ARCH:-x86}"
|
||||
case "$ASURO_ARCH" in
|
||||
x86)
|
||||
OBJ_DIR=lib
|
||||
BIN_DIR=bin
|
||||
ISO_ROOT=iso
|
||||
ISO_FILE=Asuro.iso
|
||||
NASM_FORMAT=elf
|
||||
LD_FORMAT=elf_i386
|
||||
LINKER_SCRIPT=toolchain/linker.script
|
||||
;;
|
||||
x86_64)
|
||||
OBJ_DIR=lib/x86_64
|
||||
BIN_DIR=bin/x86_64
|
||||
ISO_ROOT=bin/x86_64/iso
|
||||
ISO_FILE=Asuro-x86_64.iso
|
||||
NASM_FORMAT=elf64
|
||||
LD_FORMAT=elf_x86_64
|
||||
LINKER_SCRIPT=toolchain/x86_64/linker.script
|
||||
;;
|
||||
*) echo "Unsupported ASURO_ARCH: $ASURO_ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
export ASURO_ARCH OBJ_DIR BIN_DIR ISO_ROOT ISO_FILE NASM_FORMAT LD_FORMAT LINKER_SCRIPT
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Copyright 2026 Aaron Hance
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
ENTRY(loader)
|
||||
SECTIONS
|
||||
{
|
||||
/* Bootstrap-only low mapping. Final kernel address-space policy is a
|
||||
separate milestone; do not inherit the i386 0xC0000000 offset. */
|
||||
. = 0x100000;
|
||||
kernel_start = .;
|
||||
.multiboot : { KEEP(*(.multiboot)) }
|
||||
.text ALIGN(4096) : { *(.text .text.*) }
|
||||
.rodata ALIGN(4096) : { *(.rodata .rodata.*) }
|
||||
.data ALIGN(4096) : { *(.data .data.*) }
|
||||
load_end = .;
|
||||
.bss ALIGN(4096) (NOLOAD) : { *(COMMON) *(.bss .bss.*) }
|
||||
. = ALIGN(4096);
|
||||
kernel_end = .;
|
||||
ASSERT(kernel_end < 0x100000000, "Bootstrap must fit below 4 GiB")
|
||||
/DISCARD/ : { *(.comment) *(.note*) *(.eh_frame*) }
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
# Copyright 2026 Aaron Hance
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Run from the workspace root after building the selected ASURO_BOOT_TEST.
|
||||
# Restore temporary optical medium and optional RAM changes after the test.
|
||||
param(
|
||||
[ValidateSet('none', 'ud', 'pf', 'df')][string]$Test = 'none',
|
||||
[ValidateRange(0, 8192)][int]$MemoryMB = 0,
|
||||
[string]$Controller = 'AHCI',
|
||||
[int]$Port = 1,
|
||||
[int]$Device = 0,
|
||||
[ValidateRange(5, 45)][int]$TimeoutSeconds = 35
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$config = Get-Content -LiteralPath .\localenv.json -Raw | ConvertFrom-Json
|
||||
$vm = $config.virtualbox.MachineName
|
||||
$serialPath = $config.virtualbox.LogLocation
|
||||
if (-not $serialPath) { throw 'VirtualBox serial LogLocation is required.' }
|
||||
$isoPath = (Resolve-Path -LiteralPath .\Asuro-x86_64.iso).Path
|
||||
$state = & VBoxManage.exe showvminfo $vm --machinereadable
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect VirtualBox VM.' }
|
||||
if ($state -notcontains 'VMState="poweroff"') {
|
||||
throw 'The configured VM must already be powered off before boot validation.'
|
||||
}
|
||||
$mediumKey = '"{0}-{1}-{2}"=' -f $Controller, $Port, $Device
|
||||
$mediumLine = @($state | Where-Object { $_.StartsWith($mediumKey) })
|
||||
if ($mediumLine.Count -ne 1) { throw 'Cannot identify original optical medium.' }
|
||||
$originalMedium = $mediumLine[0].Substring($mediumKey.Length).Trim('"').Replace('\\', '\')
|
||||
if ($originalMedium -notin @('none', 'emptydrive') -and $originalMedium -notmatch '(?i)\.iso$') {
|
||||
throw 'Selected port is not an ISO/empty optical drive; refusing to replace it.'
|
||||
}
|
||||
if ($originalMedium -eq 'none') { $originalMedium = 'emptydrive' }
|
||||
$evidence = Join-Path (Get-Location) 'bin\x86_64'
|
||||
New-Item -ItemType Directory -Path $evidence -Force | Out-Null
|
||||
$originalMemory = [int](($state | Where-Object { $_ -match '^memory=' }) -replace '^memory=', '')
|
||||
if ($originalMemory -le 0) { throw 'Cannot identify original VM RAM size.' }
|
||||
$started = $false
|
||||
try {
|
||||
if ($MemoryMB -ne 0) {
|
||||
& VBoxManage.exe modifyvm $vm --memory $MemoryMB
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot set test RAM size.' }
|
||||
}
|
||||
& VBoxManage.exe storageattach $vm --storagectl $Controller --port $Port --device $Device --type dvddrive --medium $isoPath
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot attach bootstrap ISO.' }
|
||||
& .\virtualbox-wrapper.ps1 -command up -Headless -NoMonitor
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot start test VM.' }
|
||||
$started = $true
|
||||
$deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds)
|
||||
$output = ''
|
||||
$marker = if ($Test -eq 'none') { 'bootstrap complete; interrupts disabled' } else { 'HALTED: exception diagnostics complete' }
|
||||
do {
|
||||
if (Test-Path -LiteralPath $serialPath) {
|
||||
$output = Get-Content -LiteralPath $serialPath -Raw
|
||||
}
|
||||
if ($output -and ($output.Contains($marker) -or $output.Contains('FAIL:'))) { break }
|
||||
Start-Sleep -Milliseconds 200
|
||||
} while ([DateTime]::UtcNow -lt $deadline)
|
||||
$output | Set-Content -LiteralPath (Join-Path $evidence "boot-$Test-$MemoryMB.log")
|
||||
& VBoxManage.exe debugvm $vm getregisters rip rsp cs cr0 cr2 cr3 cr4 efer tr |
|
||||
Set-Content -LiteralPath (Join-Path $evidence "registers-$Test-$MemoryMB.log")
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot capture CPU registers.' }
|
||||
Write-Output $output
|
||||
if (-not $output -or -not $output.Contains($marker) -or $output.Contains('FAIL:')) {
|
||||
throw 'Boot did not reach its expected completion marker.'
|
||||
}
|
||||
foreach ($required in @('EXCEPTION_TESTS_PASSED=0000000000000002', 'EXCEPTION_TESTS_FAILED=0000000000000000',
|
||||
'PMM_TESTS_FAILED=0000000000000000', 'VMM_TESTS_FAILED=0000000000000000',
|
||||
'HEAP_TESTS_FAILED=0000000000000000', 'IRQ_TESTS_FAILED=0000000000000000', 'CONTEXT_TESTS_FAILED=0000000000000000', 'PROCESS_TESTS_FAILED=0000000000000000', 'FD_TESTS_FAILED=0000000000000000', 'STRINGS_TESTS_FAILED=0000000000000000', 'STDIO_TESTS_FAILED=0000000000000000')) {
|
||||
if (-not $output.Contains($required)) { throw "Missing check: $required" }
|
||||
}
|
||||
if ($MemoryMB -gt 4096 -and $output.Contains('SKIP: no available physical RAM above 4 GiB')) {
|
||||
throw 'High physical memory test was skipped.'
|
||||
}
|
||||
if ($Test -ne 'none') {
|
||||
$vector = @{ud = '6'; pf = 'E'; df = '8'}[$Test]
|
||||
$errorCode = if ($Test -eq 'pf') { '2' } else { '0' }
|
||||
foreach ($required in @("VECTOR=000000000000000$vector", "ERROR=000000000000000$errorCode", 'CS=0000000000000018')) {
|
||||
if (-not $output.Contains($required)) { throw "Missing diagnostic: $required" }
|
||||
}
|
||||
if ($Test -eq 'pf' -and -not $output.Contains('CR2=0000000100000000')) {
|
||||
throw 'Page fault did not preserve the expected CR2.'
|
||||
}
|
||||
if ($Test -eq 'df' -and (-not $output.Contains('STACK=double-fault IST1') -or
|
||||
-not $output.Contains('RSP=0000000100001000'))) {
|
||||
throw 'Double fault did not switch from the broken stack to IST1.'
|
||||
}
|
||||
}
|
||||
Write-Output "PASS: VirtualBox x86_64 boot test '$Test'"
|
||||
} finally {
|
||||
try {
|
||||
if ($started) {
|
||||
& .\virtualbox-wrapper.ps1 -command down
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot stop test VM.' }
|
||||
}
|
||||
} finally {
|
||||
& VBoxManage.exe storageattach $vm --storagectl $Controller --port $Port --device $Device --type dvddrive --medium $originalMedium
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original optical medium.' }
|
||||
if ($MemoryMB -ne 0) {
|
||||
& VBoxManage.exe modifyvm $vm --memory $originalMemory
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original VM RAM size.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user