diff --git a/.bochsrc b/.bochsrc new file mode 100644 index 0000000..1757d33 --- /dev/null +++ b/.bochsrc @@ -0,0 +1,12 @@ +megs: 1024 +ata0-master: type=disk, path=builddbg/disk.img, mode=flat, cylinders=512, heads=16, spt=50 +display_library: sdl2, options="gui_debug" +boot: disk +com1: enabled=1, mode=file, dev=serial.out, baud=9600, parity=none, bits=8, stopbits=1 +cpu: model=corei7_sandy_bridge_2600k +pci: enabled=1, chipset=i440bx +log: bochs.log +# TODO: Make this portable, by building bochs locally. +romimage: file=/home/drew/opt/bochs/share/bochs/BIOS-bochs-latest +vgaromimage: file=/home/drew/opt/bochs/share/bochs/VGABIOS-lgpl-latest.bin +vga: extension=vbe diff --git a/.gitignore b/.gitignore index a74dbf9..7e2de93 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ __pycache__/ .ccls-cache/ compile_commands.json +bochs.log +serial.out + sysroot/bin sysroot/usr sysroot/.crates.toml diff --git a/scripts/bochs.sh b/scripts/bochs.sh new file mode 100755 index 0000000..9a0d982 --- /dev/null +++ b/scripts/bochs.sh @@ -0,0 +1,19 @@ +#! /bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +BUILD_DIR="${DIR}/../builddbg" + +bash ${DIR}/build.sh +sudo sh ${DIR}/build_image.sh ${BUILD_DIR}/disk.img + +BOCHS_ARGS= +if [[ $1 == "debug" ]]; then + BOCHS_ARGS+="--dbg" +fi + +# TODO Make this portable, build bochs as a part of toolchain? +~/opt/bochs/bin/bochs + diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..9b64905 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,32 @@ +#! /bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo $DIR + +BUILD_DIR="${DIR}/../builddbg" + +pushd $BUILD_DIR +ninja +ninja install + +CARGO_USR_ROOT="${DIR}/../sysroot/usr/" +CARGO_SYS_ROOT="${DIR}/../sysroot/" + +# Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml +pushd "${DIR}/../rust" + +for BIN in ${DIR}/../rust/usr/*/; do + cargo install --force --path "${BIN}" --root $CARGO_USR_ROOT +done + +for BIN in ${DIR}/../rust/sys/*/; do + cargo install --all-features --force --path "${BIN}" --root $CARGO_SYS_ROOT +done +popd + +popd + + diff --git a/scripts/build_image.sh b/scripts/build_image.sh index 8500427..2fd5867 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -1,7 +1,11 @@ -#!/us +#! /bin/bash set -e +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +REPO_ROOT="$SCRIPT_DIR/.." +BUILD_DIR="$REPO_ROOT/builddbg" + if [[ $# -ne 1 ]]; then echo "Must specify disk image name." fi @@ -15,11 +19,14 @@ if [ -z "$dev" ]; then fi echo "Loopback device: ${dev}" +EFI_DIR="$BUILD_DIR/efi" +SYSROOT="$BUILD_DIR/sysroot" + cleanup() { - umount efi - rm -rf efi - umount sysroot - rm -rf sysroot + umount $EFI_DIR + rm -rf $EFI_DIR + umount $SYSROOT + rm -rf $SYSROOT losetup -d $dev } trap cleanup EXIT @@ -30,22 +37,23 @@ mke2fs "${dev}p2" limine bios-install "${dev}" -mkdir -p efi/ -mount "${dev}p1" efi/ -mkdir -p efi/EFI/BOOT -cp /usr/share/limine/BOOTX64.EFI efi/EFI/BOOT -cp /usr/share/limine/limine-bios.sys efi/ -cp ../zion/boot/limine.conf efi/ -cp zion/zion efi/ -mkdir -p efi/sys -cp ../sysroot/bin/yellowstone efi/sys/yellowstone -cp ../sysroot/bin/denali efi/sys/denali -cp ../sysroot/bin/victoriafalls efi/sys/victoriafalls +mkdir -p $EFI_DIR +mount "${dev}p1" $EFI_DIR -mkdir -p sysroot -mount "${dev}p2" sysroot/ -rsync -a ../sysroot . -ls sysroot/ +mkdir -p $EFI_DIR/EFI/BOOT +cp /usr/share/limine/BOOTX64.EFI $EFI_DIR/EFI/BOOT +cp /usr/share/limine/limine-bios.sys $EFI_DIR +cp $REPO_ROOT/zion/boot/limine.conf $EFI_DIR/ +cp $BUILD_DIR/zion/zion $EFI_DIR/ +mkdir -p $EFI_DIR/sys +cp $REPO_ROOT/sysroot/bin/yellowstone $EFI_DIR/sys/yellowstone +cp $REPO_ROOT/sysroot/bin/denali $EFI_DIR/sys/denali +cp $REPO_ROOT/sysroot/bin/victoriafalls $EFI_DIR/sys/victoriafalls + +mkdir -p $SYSROOT +mount "${dev}p2" $SYSROOT +rsync -a "$REPO_ROOT/sysroot" $BUILD_DIR +ls $SYSROOT chown drew:drew $1 diff --git a/scripts/qemu.sh b/scripts/qemu.sh index 40bf1c7..22d6f98 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -8,26 +8,9 @@ echo $DIR BUILD_DIR="${DIR}/../builddbg" -pushd $BUILD_DIR -ninja -ninja install -CARGO_USR_ROOT="${DIR}/../sysroot/usr/" -CARGO_SYS_ROOT="${DIR}/../sysroot/" - -# Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml -pushd "${DIR}/../rust" - -for BIN in ${DIR}/../rust/usr/*/; do - cargo install --force --path "${BIN}" --root $CARGO_USR_ROOT -done - -for BIN in ${DIR}/../rust/sys/*/; do - cargo install --all-features --force --path "${BIN}" --root $CARGO_SYS_ROOT -done -popd - -sudo sh ${DIR}/build_image.sh disk.img +bash ${DIR}/build.sh +sudo sh ${DIR}/build_image.sh ${BUILD_DIR}/disk.img QEMU_ARGS= if [[ $1 == "debug" ]]; then @@ -35,7 +18,7 @@ if [[ $1 == "debug" ]]; then fi # Use machine q35 to access PCI devices. -qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 +qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda ${BUILD_DIR}/disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 popd # Extra options to add to this script in the future. diff --git a/zion/debug/debug.cpp b/zion/debug/debug.cpp index a2929d9..096443a 100644 --- a/zion/debug/debug.cpp +++ b/zion/debug/debug.cpp @@ -39,3 +39,52 @@ void dbgln(const glcr::StringView& str) { dbg(str); dbg("\n"); } + +namespace { + +// Helper function to write a byte to a specified COM1 register offset +void write_serial_port(uint16_t offset, uint8_t value) { + outb(COM1 + offset, value); +} + +// Helper function to read a byte from a specified COM1 register offset +uint8_t read_serial_port(uint16_t offset) { return inb(COM1 + offset); } + +} // namespace + +namespace serial { + +// Function to initialize the serial port with a given baud rate +void initialize(uint32_t baud_rate) { + // Disable interrupts + write_serial_port(1, 0x00); + + // Enable DLAB (Divisor Latch Access Bit) in Line Control Register (LCR) + write_serial_port(3, read_serial_port(3) | 0x80); + + // Calculate the divisor + // Baud rate = 115200 / divisor (approximately) + uint16_t divisor = 115200 / baud_rate; + + // Set the low byte of the divisor + write_serial_port(0, divisor & 0xFF); + + // Set the high byte of the divisor + write_serial_port(1, (divisor >> 8) & 0xFF); + + // Clear DLAB and set data bits, stop bits, and parity + // 8 data bits, 1 stop bit, no parity + write_serial_port(3, 0x03); // 00000011b + + // Enable FIFO, clear buffers, set trigger level (e.g., 1 byte) + write_serial_port(2, 0xC7); // 11000111b + + // Enable IRQs (optional, for interrupt-driven communication) + // write_serial_port(1, 0x01); + + // Set Modem Control Register (MCR) + // Enable RTS, DTR, OUT1, OUT2, loopback off, IRQs enabled + write_serial_port(4, 0x0B); // 00001011b +} + +} // namespace serial diff --git a/zion/debug/debug.h b/zion/debug/debug.h index 63b0d0e..d3a6fd4 100644 --- a/zion/debug/debug.h +++ b/zion/debug/debug.h @@ -37,3 +37,9 @@ void panic(const char* str, Args&&... args) { #define UNREACHABLE \ panic("Unreachable {}, {}", glcr::StringView(__FILE__), __LINE__); \ __builtin_unreachable(); + +namespace serial { + +void initialize(uint32_t baud_rate); + +} diff --git a/zion/zion.cpp b/zion/zion.cpp index fe9e497..b2ee2e7 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -20,6 +20,7 @@ #include "syscall/syscall.h" extern "C" void zion() { + serial::initialize(9600); dbgln("[boot] Init GDT & IDT."); InitGdt(); InitIdt();