diff options
Diffstat (limited to '')
| -rwxr-xr-x | tools/boot-image.sh | 62 | ||||
| -rwxr-xr-x | tools/debug-kernel.py | 64 | ||||
| -rwxr-xr-x | tools/qemu.sh | 96 |
3 files changed, 222 insertions, 0 deletions
diff --git a/tools/boot-image.sh b/tools/boot-image.sh new file mode 100755 index 0000000..2592afa --- /dev/null +++ b/tools/boot-image.sh | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # ============================================================================= | ||
| 3 | # tools/boot-image.sh — Create a bootable disk image from the ESP directory | ||
| 4 | # | ||
| 5 | # Produces a raw disk image (bootable via UEFI) for dd-ing to a USB stick | ||
| 6 | # or attaching to QEMU as a hard disk. | ||
| 7 | # | ||
| 8 | # Usage: | ||
| 9 | # ./tools/boot-image.sh [output.img] | ||
| 10 | # | ||
| 11 | # Default output: raisernics.img | ||
| 12 | # ============================================================================= | ||
| 13 | set -euo pipefail | ||
| 14 | |||
| 15 | SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" | ||
| 16 | cd "$SCRIPT_DIR" | ||
| 17 | |||
| 18 | OUTPUT="${1:-raisernics.img}" | ||
| 19 | ESP_DIR="${ESP_DIR:-esp}" | ||
| 20 | MBR_SZ=1 # 1 MB reserved at start for GPT/pmbr | ||
| 21 | SECTOR_SZ=512 | ||
| 22 | |||
| 23 | # Rebuild ESP if stale | ||
| 24 | make all | ||
| 25 | |||
| 26 | if [ ! -d "$ESP_DIR" ]; then | ||
| 27 | echo "ERROR: ESP directory '$ESP_DIR' not found. Run 'make all' first." | ||
| 28 | exit 1 | ||
| 29 | fi | ||
| 30 | |||
| 31 | # Calculate required size: ESP contents + MBR gap + some slack | ||
| 32 | ESP_SIZE_MB=$(du -sm "$ESP_DIR" 2>/dev/null | cut -f1 || echo 1) | ||
| 33 | TOTAL_MB=$((ESP_SIZE_MB + MBR_SZ + 1)) # +1 MB slack | ||
| 34 | |||
| 35 | echo "Creating ${TOTAL_MB} MB disk image: ${OUTPUT}" | ||
| 36 | |||
| 37 | # Create empty image with MBR gap | ||
| 38 | dd if=/dev/zero of="$OUTPUT" bs=1M count="$TOTAL_MB" status=none 2>/dev/null | ||
| 39 | |||
| 40 | # Partition table: single GPT partition, type EFI System (C12A7328-F81F-11D2-BA4B-00A0C93EC93B) | ||
| 41 | sgdisk --clear \ | ||
| 42 | --new=1:${MBR_SZ}M:0 \ | ||
| 43 | --typecode=1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \ | ||
| 44 | --change-name=1:"raisernics" \ | ||
| 45 | "$OUTPUT" >/dev/null | ||
| 46 | |||
| 47 | # Find partition offset | ||
| 48 | PART_START=$(sgdisk --info=1 "$OUTPUT" 2>/dev/null | grep "Partition start sector" | awk '{print $NF}') | ||
| 49 | if [ -z "$PART_START" ]; then | ||
| 50 | PART_START=$((MBR_SZ * 1024 * 1024 / SECTOR_SZ)) | ||
| 51 | fi | ||
| 52 | |||
| 53 | # Format as FAT32 | ||
| 54 | mformat -i "$OUTPUT"@$((PART_START * SECTOR_SZ)) -h 32 -s 32 -t "$((TOTAL_MB * 2))" >/dev/null 2>&1 || true | ||
| 55 | |||
| 56 | # Copy the ESP contents onto the partition | ||
| 57 | mcopy -i "$OUTPUT"@$((PART_START * SECTOR_SZ)) -s "$ESP_DIR"/* ::/ 2>/dev/null | ||
| 58 | |||
| 59 | echo " -> ${OUTPUT} ($(ls -lh "$OUTPUT" | awk '{print $5}'))" | ||
| 60 | echo "" | ||
| 61 | echo "To write to USB: sudo dd if=${OUTPUT} of=/dev/sdX bs=4M status=progress" | ||
| 62 | echo "To test with QEMU: qemu-system-x86_64 -bios <OVMF> -drive file=${OUTPUT},format=raw" | ||
diff --git a/tools/debug-kernel.py b/tools/debug-kernel.py new file mode 100755 index 0000000..c794ad6 --- /dev/null +++ b/tools/debug-kernel.py | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | """ | ||
| 2 | GDB Python script for debugging raisernics under QEMU. | ||
| 3 | |||
| 4 | Usage: | ||
| 5 | 1. Terminal 1: ./tools/qemu.sh --debug | ||
| 6 | 2. Terminal 2: gdb -x tools/debug-kernel.py target/x86_64-unknown-uefi/debug/raisernics.efi | ||
| 7 | """ | ||
| 8 | |||
| 9 | import gdb | ||
| 10 | import os | ||
| 11 | |||
| 12 | # Find the kernel binary | ||
| 13 | script_dir = os.path.dirname(os.path.abspath(__file__)) | ||
| 14 | project_root = os.path.dirname(script_dir) | ||
| 15 | binary = os.path.join( | ||
| 16 | project_root, | ||
| 17 | "target/x86_64-unknown-uefi/debug/raisernics.efi" | ||
| 18 | ) | ||
| 19 | |||
| 20 | # Connect to QEMU's GDB stub | ||
| 21 | gdb.execute("target remote :1234") | ||
| 22 | |||
| 23 | # Load the binary (add symbol table) | ||
| 24 | if os.path.exists(binary): | ||
| 25 | gdb.execute(f"symbol-file {binary}") | ||
| 26 | print(f"Loaded symbols from {binary}") | ||
| 27 | else: | ||
| 28 | print(f"WARNING: {binary} not found. Build with debug symbols first.") | ||
| 29 | |||
| 30 | gdb.execute("set breakpoint pending on") | ||
| 31 | |||
| 32 | |||
| 33 | # Helper commands | ||
| 34 | class DumpBootServices(gdb.Command): | ||
| 35 | """Dump EFI boot services signature and key pointers""" | ||
| 36 | |||
| 37 | def __init__(self): | ||
| 38 | super().__init__("dump-bs", gdb.COMMAND_USER) | ||
| 39 | |||
| 40 | def invoke(self, argument, from_tty): | ||
| 41 | del argument, from_tty | ||
| 42 | gdb.execute("printf \"SystemTable, BootServices, and key function pointers\\n\"") | ||
| 43 | gdb.execute("info functions efi_main") | ||
| 44 | |||
| 45 | |||
| 46 | class DumpGop(gdb.Command): | ||
| 47 | """Dump GOP framebuffer info""" | ||
| 48 | |||
| 49 | def __init__(self): | ||
| 50 | super().__init__("dump-gop", gdb.COMMAND_USER) | ||
| 51 | |||
| 52 | def invoke(self, argument, from_tty): | ||
| 53 | del argument, from_tty | ||
| 54 | gdb.execute("printf \"Check the gop::Framebuffer static\\n\"") | ||
| 55 | |||
| 56 | |||
| 57 | DumpBootServices() | ||
| 58 | DumpGop() | ||
| 59 | |||
| 60 | print("") | ||
| 61 | print("raisernics GDB session ready.") | ||
| 62 | print(" target remote :1234 (connected)") | ||
| 63 | print(" Commands: continue, stepi, bt, info registers, etc.") | ||
| 64 | print(" Custom: dump-bs, dump-gop") | ||
diff --git a/tools/qemu.sh b/tools/qemu.sh new file mode 100755 index 0000000..428954f --- /dev/null +++ b/tools/qemu.sh | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # ============================================================================= | ||
| 3 | # tools/qemu.sh — Run raisernics in QEMU with various options | ||
| 4 | # | ||
| 5 | # Usage: | ||
| 6 | # ./tools/qemu.sh # serial console (no graphics) | ||
| 7 | # ./tools/qemu.sh --gui # graphical window | ||
| 8 | # ./tools/qemu.sh --debug # GDB stub on :1234 | ||
| 9 | # ./tools/qemu.sh --image foo.img # boot from raw disk image | ||
| 10 | # ./tools/qemu.sh --bios /path/to.fd # custom OVMF | ||
| 11 | # ./tools/qemu.sh --mem 512M # memory size | ||
| 12 | # ./tools/qemu.sh --smp 2 # SMP cores | ||
| 13 | # ============================================================================= | ||
| 14 | set -euo pipefail | ||
| 15 | |||
| 16 | SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" | ||
| 17 | cd "$SCRIPT_DIR" | ||
| 18 | |||
| 19 | # Defaults | ||
| 20 | GUI_FLAG="" | ||
| 21 | DEBUG_FLAG="" | ||
| 22 | DRIVE_ARGS=(-drive file=fat:rw:esp,format=raw) | ||
| 23 | OVMF="${OVMF:-/usr/share/edk2/x64/OVMF.4m.fd}" | ||
| 24 | MEM="${MEM:-256M}" | ||
| 25 | SMP="${SMP:-1}" | ||
| 26 | |||
| 27 | # Pre-build | ||
| 28 | make all | ||
| 29 | |||
| 30 | # Parse args | ||
| 31 | while [ $# -gt 0 ]; do | ||
| 32 | case "$1" in | ||
| 33 | --gui | -g) | ||
| 34 | GUI_FLAG="-vga std" | ||
| 35 | shift | ||
| 36 | ;; | ||
| 37 | --debug | -d) | ||
| 38 | DEBUG_FLAG="-s -S" | ||
| 39 | shift | ||
| 40 | ;; | ||
| 41 | --image | -i) | ||
| 42 | _img_file="$(printf -- '-drive file=%s,format=raw,if=none,id=hd' "$2")" | ||
| 43 | DRIVE_ARGS=("$_img_file" '-device' 'ide-hd,drive=hd') | ||
| 44 | shift 2 | ||
| 45 | ;; | ||
| 46 | --bios | -b) | ||
| 47 | OVMF="$2" | ||
| 48 | shift 2 | ||
| 49 | ;; | ||
| 50 | --mem) | ||
| 51 | MEM="$2" | ||
| 52 | shift 2 | ||
| 53 | ;; | ||
| 54 | --smp) | ||
| 55 | SMP="$2" | ||
| 56 | shift 2 | ||
| 57 | ;; | ||
| 58 | --help | -h) | ||
| 59 | head -20 "$0" | grep "^# " | sed 's/^# //' | ||
| 60 | exit 0 | ||
| 61 | ;; | ||
| 62 | *) | ||
| 63 | echo "Unknown option: $1" | ||
| 64 | exit 1 | ||
| 65 | ;; | ||
| 66 | esac | ||
| 67 | done | ||
| 68 | |||
| 69 | QEMU_CMD=( | ||
| 70 | qemu-system-x86_64 | ||
| 71 | -bios "$OVMF" | ||
| 72 | "${DRIVE_ARGS[@]}" | ||
| 73 | -serial stdio | ||
| 74 | -m "$MEM" | ||
| 75 | -machine q35 | ||
| 76 | -cpu qemu64 | ||
| 77 | -no-reboot | ||
| 78 | -smp "$SMP" | ||
| 79 | ) | ||
| 80 | |||
| 81 | [ -n "$GUI_FLAG" ] && QEMU_CMD+=("$GUI_FLAG") | ||
| 82 | if [ -n "$DEBUG_FLAG" ]; then | ||
| 83 | # Split the flag string safely into words | ||
| 84 | read -ra dbg <<< "$DEBUG_FLAG" | ||
| 85 | QEMU_CMD+=("${dbg[@]}") | ||
| 86 | fi | ||
| 87 | |||
| 88 | echo " OVMF : $OVMF" | ||
| 89 | echo " Drive : ${DRIVE_ARGS[*]}" | ||
| 90 | echo " Mem : $MEM" | ||
| 91 | echo " SMP : $SMP" | ||
| 92 | echo " GDB : $([ -n "$DEBUG_FLAG" ] && echo ':1234' || echo 'off')" | ||
| 93 | echo " GUI : $([ -n "$GUI_FLAG" ] && echo 'yes' || echo 'no')" | ||
| 94 | echo "" | ||
| 95 | |||
| 96 | exec "${QEMU_CMD[@]}" | ||
