diff --git a/.gitignore b/.gitignore index c795b05..7012c23 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -build \ No newline at end of file +.build.env +build +cross diff --git a/Makefile b/Makefile index be85c52..a99cafe 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ AS = nasm ASFLAGS = -f elf32 -g -F dwarf -CC = gcc -LD = ld +CC = i386-elf-gcc +LD = i386-elf-ld QEMU= qemu-system-i386 +OBJCOPY = i386-elf-objcopy BUILD_DIR = build DISK_IMG = $(BUILD_DIR)/disk.img @@ -19,7 +20,7 @@ all: $(DISK_IMG) stage1: $(BUILD_DIR) $(AS) $(ASFLAGS) -o $(BUILD_DIR)/$@.o bootloader/$@.asm $(LD) -Ttext=0x7c00 -melf_i386 -o $(BUILD_DIR)/$@.elf $(BUILD_DIR)/$@.o - objcopy -O binary $(BUILD_DIR)/$@.elf $(BUILD_DIR)/$@.bin + $(OBJCOPY) -O binary $(BUILD_DIR)/$@.elf $(BUILD_DIR)/$@.bin # NOTE: Stage2 final size should be checked against `$(STAGE2_SIZE)` by the build system to avoid an overflow. # Alternatively, convey the final stage2 size through other means to stage1. @@ -27,7 +28,7 @@ stage2: $(BUILD_DIR) $(AS) $(ASFLAGS) -o $(BUILD_DIR)/stage2.o bootloader/stage2.asm $(CC) -std=c11 -ffreestanding -nostdlib -fno-stack-protector -m32 -g -c -o $(BUILD_DIR)/stage2_load.o bootloader/stage2_load.c $(LD) -Tbootloader/stage2.ld -melf_i386 -o $(BUILD_DIR)/$@.elf $(BUILD_DIR)/stage2.o $(BUILD_DIR)/stage2_load.o - objcopy -O binary $(BUILD_DIR)/$@.elf $(BUILD_DIR)/$@.bin + $(OBJCOPY) -O binary $(BUILD_DIR)/$@.elf $(BUILD_DIR)/$@.bin truncate -s $(STAGE2_SIZE) $(BUILD_DIR)/$@.bin $(BUILD_DIR)/asm_%.o: kernel/%.asm @@ -56,3 +57,4 @@ gdb: clean: rm -rf $(BUILD_DIR) + rm -rf $(CROSS_DIR) diff --git a/README.md b/README.md index 2232bcf..791f89f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Platform](https://img.shields.io/badge/platform-x86_IA32-lightgrey?style=flat-square)](https://en.wikipedia.org/wiki/IA-32) [![Made with](https://img.shields.io/badge/made%20with-C%20%26%20NASM-9cf?style=flat-square)](#) -> **ClassicOS** is a 32-bit Intel x86 operating system built from scratch using C, NASM, and GCC. +> **ClassicOS** is a 32-bit Intel x86 operating system built from scratch using C, NASM, and GCC. > Designed for 386, 486, and Pentium-class CPUs, it runs in protected mode, outputs to VGA text mode and serial ports, and supports floppy/HDD boot with basic FAT support. --- @@ -35,6 +35,7 @@ You’ll need the following tools installed: - `qemu-system-i386` Optional: + - `gdb` - `vncviewer` (TigerVNC or similar) @@ -42,13 +43,27 @@ Optional: ## 🛠️ Building ClassicOS -Clone and build: +Clone repository: -```bash +```sh git clone https://github.com/gbowne1/ClassicOS.git cd ClassicOS -make ``` -build kernel -for %f in (*.c) do gcc -m32 -O0 -Wall -Wextra -Werror -pedantic -ffreestanding -nostdlib -fno-pic -fno-stack-protector -fno-pie -march=i386 -mtune=i386 -c "%f" -o "%f.o" +Run `configure` script to build a cross-compiler toolchain for `i386-elf`: + +```sh +./configure +``` + +Source the `.build.env` file to add the cross-compiler toolchain to your PATH: + +```sh +source .build.env +``` + +Build the kernel: + +```sh +make +``` diff --git a/configure b/configure new file mode 100755 index 0000000..2ba63c2 --- /dev/null +++ b/configure @@ -0,0 +1,169 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Configuration +TARGET="i386-elf" +BINUTILS_VERSION="2.45" +GCC_VERSION="15.2.0" + +# Paths +SCRIPT_PATH="$(realpath "${BASH_SOURCE[0]}")" +SCRIPT_DIR="$(dirname "$SCRIPT_PATH")" +PREFIX="$SCRIPT_DIR/cross" +SRC_DIR="$PREFIX/src" + +BINUTILS_SRC="$SRC_DIR/binutils-$BINUTILS_VERSION" +BINUTILS_BUILD="$PREFIX/build-binutils" +GCC_SRC="$SRC_DIR/gcc-$GCC_VERSION" +GCC_BUILD="$PREFIX/build-gcc" + +# Flags +DEBUG=0 +HELP=0 + +# Parse arguments +for arg in "$@"; do + case "$arg" in + -h|--help) + HELP=1 + ;; + -d|--debug) + DEBUG=1 + ;; + *) + echo "Unknown option: $arg" + echo "Use -h or --help for usage information" + exit 1 + ;; + esac +done + +# Show help +if [[ "$HELP" -eq 1 ]]; then + cat << EOF +Usage: $0 [OPTIONS] + +Build a cross-compiler toolchain for $TARGET. + +OPTIONS: + -h, --help Show this help message + -d, --debug Enable debug mode (set -x) + +This script will: + 1. Download binutils $BINUTILS_VERSION and GCC $GCC_VERSION + 2. Build and install them to: $PREFIX + +EOF + exit 0 +fi + +# Enable debug mode +if [[ "$DEBUG" -eq 1 ]]; then + set -x +fi + +# Print configuration +cat << EOF + +=== Build Configuration === +Target : $TARGET +Prefix : $PREFIX +Binutils : $BINUTILS_VERSION +GCC : $GCC_VERSION +=========================== + +EOF + +# Create directory structure +echo "Setting up directories..." +mkdir -p "$SRC_DIR" + +# Download sources +cd "$SRC_DIR" + +if [[ ! -d "$BINUTILS_SRC" ]]; then + echo "Downloading binutils $BINUTILS_VERSION..." + wget "https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.gz" + echo "Extracting binutils..." + tar xf "binutils-$BINUTILS_VERSION.tar.gz" + rm "binutils-$BINUTILS_VERSION.tar.gz" +else + echo "Binutils source already exists, skipping download" +fi + +if [[ ! -d "$GCC_SRC" ]]; then + echo "Downloading GCC $GCC_VERSION..." + wget "https://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.gz" + echo "Extracting GCC..." + tar xf "gcc-$GCC_VERSION.tar.gz" + rm "gcc-$GCC_VERSION.tar.gz" +else + echo "GCC source already exists, skipping download" +fi + +# Download GCC prerequisites +if [[ ! -d "$GCC_SRC/gmp" ]]; then + echo "Downloading GCC prerequisites..." + cd "$GCC_SRC" + ./contrib/download_prerequisites + cd "$SRC_DIR" +else + echo "GCC prerequisites already downloaded, skipping" +fi + +# Build binutils +if [[ ! -f "$PREFIX/bin/$TARGET-ld" ]]; then + echo "Building binutils..." + mkdir -p "$BINUTILS_BUILD" + cd "$BINUTILS_BUILD" + + "$BINUTILS_SRC/configure" \ + --target="$TARGET" \ + --prefix="$PREFIX" \ + --with-sysroot \ + --disable-nls \ + --disable-werror + + make -j"$(nproc)" + make install +else + echo "Binutils already installed, skipping build" +fi + +# Build GCC +if [[ ! -f "$PREFIX/bin/$TARGET-gcc" ]]; then + echo "Building GCC..." + mkdir -p "$GCC_BUILD" + cd "$GCC_BUILD" + + "$GCC_SRC/configure" \ + --target="$TARGET" \ + --prefix="$PREFIX" \ + --disable-nls \ + --enable-languages=c \ + --without-headers + + make all-gcc -j"$(nproc)" + make all-target-libgcc -j"$(nproc)" + make install-gcc + make install-target-libgcc +else + echo "GCC already installed, skipping build" +fi + +cd "$SCRIPT_DIR" + +# Generate .build.env file +cat > .build.env << EOF +# Generated by configure on $(date) +# Source this file to add the cross-compiler toolchain to your PATH +export PATH="$PREFIX/bin:\$PATH" +EOF + +echo "" +echo "=== Build Complete ===" +echo "Toolchain installed to: $PREFIX" +echo "" +echo "To use the toolchain, run:" +echo " source .build.env" +echo "======================"