diff --git a/.gitignore b/.gitignore index e361b2d..f521063 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,4 @@ mnt/ **/bin/ **/build/ .venv/ -external/ - -pushTags.sh \ No newline at end of file +external/ \ No newline at end of file diff --git a/Makefile b/Makefile index 9ddf7e0..ca20630 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,3 @@ - - -# Object files grouped by functionality FILES = \ ./build/kernel.asm.o \ ./build/kernel.o \ @@ -72,7 +69,7 @@ prepare_dirs: all: build install -build: prepare_dirs fonts ./bin/boot_with_size.bin user_programs ./bin/os.bin +build: prepare_dirs fonts ./bin/boot_with_size.bin ./bin/kernel.bin user_programs ./bin/os.bin @echo "Build complete! User programs built but not installed to disk image." @echo "To install user programs to disk image, run: make install" @@ -82,82 +79,75 @@ fonts: install: ./bin/os.bin ifeq ($(UNAME_S),Linux) @echo "Installing user programs and assets to disk image (Linux)..." - @# Create mount point if it doesn't exist @sudo mkdir -p /mnt/d - @# Unmount if already mounted @sudo umount /mnt/d 2>/dev/null || true - @# Mount the disk image - @sudo mount -t vfat ./bin/os.bin /mnt/d - @# Copy all assets recursively - @sudo cp -r ./assets/* /mnt/d/ 2>/dev/null || true - @# Find and copy all .elf files from programs directory - @find ./assets/etc/default/user/programs -name '*.elf' -exec sudo cp {} /mnt/d/ \; - @# Unmount the disk image + @sudo mount -t vfat ./bin/os.bin /mnt/d || { echo "Failed to mount disk image"; exit 1; } + @if [ -d "./assets" ]; then sudo cp -r ./assets/* /mnt/d/ || { echo "Failed to copy assets"; sudo umount /mnt/d; exit 1; }; fi + @if [ -d "./assets/etc/default/user/programs" ]; then find ./assets/etc/default/user/programs -name '*.elf' -exec sudo cp {} /mnt/d/ \; || { echo "Failed to copy .elf files"; sudo umount /mnt/d; exit 1; }; fi @sudo umount /mnt/d @echo "User programs and assets installed to disk image!" else ifeq ($(UNAME_S),Darwin) - @echo "Attaching disk image (macOS)..." - @bash -c '\ - DISK_ID=$$(hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount ./bin/os.bin | awk "/\\/dev\\// {print \$$1}"); \ - echo "diskutil list output for $$DISK_ID:"; \ - diskutil list $$DISK_ID; \ - PART_DEV=$$(ls /dev/$$(basename $$DISK_ID)s1); \ - echo "Partition device: $$PART_DEV"; \ - sudo mkdir -p /Volumes/viosmnt; \ - sudo mount -t msdos $$PART_DEV /Volumes/viosmnt || { echo "Failed to mount $$PART_DEV"; hdiutil detach $$DISK_ID; exit 1; }; \ - echo "Copying files..."; \ - sudo cp -r ./assets/* /Volumes/viosmnt/ 2>/dev/null || true; \ - find ./assets/etc/default/user/programs -name "*.elf" -exec sudo cp {} /Volumes/viosmnt/ \; ; \ + @echo "Preparing disk image for macOS..." + @bash -c "\ + set -e; \ + echo 'Attaching disk image...'; \ + ATTACH_OUTPUT=\$$(hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount ./bin/os.bin 2>/dev/null); \ + DISK_ID=\$$(echo \"\$$ATTACH_OUTPUT\" | grep -o '/dev/disk[0-9]*' | head -1); \ + PARTITION_ID=\"\$${DISK_ID}s1\"; \ + if [ -z \"\$$DISK_ID\" ]; then echo 'Failed to attach disk image'; exit 1; fi; \ + echo \"Attached as \$$DISK_ID, partition \$$PARTITION_ID\"; \ + echo 'Formatting partition as FAT32...'; \ + diskutil eraseVolume MS-DOS VIOSFAT32 \"\$$PARTITION_ID\" >/dev/null 2>&1 || { echo 'Failed to format partition'; hdiutil detach \"\$$DISK_ID\" 2>/dev/null; exit 1; }; \ + echo 'Copying files...'; \ + if [ -d './assets' ]; then \ + echo 'Copying assets...'; \ + cp -r ./assets/* /Volumes/VIOSFAT32/ || { echo 'Failed to copy assets'; diskutil unmount \"\$$PARTITION_ID\"; hdiutil detach \"\$$DISK_ID\" 2>/dev/null; exit 1; }; \ + else \ + echo 'No assets directory found, skipping...'; \ + fi; \ + if [ -d './assets/etc/default/user/programs' ]; then \ + echo 'Copying .elf files...'; \ + find ./assets/etc/default/user/programs -name '*.elf' -exec cp {} /Volumes/VIOSFAT32/ \; || { echo 'Failed to copy .elf files'; diskutil unmount \"\$$PARTITION_ID\"; hdiutil detach \"\$$DISK_ID\" 2>/dev/null; exit 1; }; \ + else \ + echo 'No programs directory found, skipping...'; \ + fi; \ sync; \ - echo "Unmounting..."; \ - sudo umount /Volumes/viosmnt; \ - hdiutil detach $$DISK_ID; \ - echo "User programs and assets installed to disk image!"; \ - ' + echo 'Unmounting for boot sector update...'; \ + diskutil unmount \"\$$PARTITION_ID\" >/dev/null 2>&1 || echo 'Unmount failed, continuing...'; \ + echo 'Installing custom boot sector...'; \ + dd if=./bin/vbr.bin of=\"\$$PARTITION_ID\" bs=512 count=1 conv=notrunc 2>/dev/null || echo 'Warning: Failed to install custom boot sector'; \ + hdiutil detach \"\$$DISK_ID\" >/dev/null 2>&1 || echo 'Detach failed, continuing...'; \ + echo 'User programs and assets installed to disk image!'; \ + " endif + ./bin/kernel.bin: prepare_dirs $(FILES) i686-elf-gcc $(FLAGS) -T ./src/linker.ld -o ./bin/kernel.bin -ffreestanding -O0 -nostdlib $(FILES) -./bin/mbr.bin: prepare_dirs ./src/boot/mbr.asm +./bin/boot.bin: prepare_dirs ./src/boot/mbr.asm ./src/boot/vbrEntry.asm ./src/boot/vbrMain.asm ./src/boot/fsinfo.asm nasm -f bin ./src/boot/mbr.asm -o ./bin/mbr.bin - -./bin/vbr.bin: prepare_dirs ./src/boot/vbr.asm - nasm -f bin ./src/boot/vbr.asm -o ./bin/vbr.bin + nasm -f bin ./src/boot/vbrEntry.asm -o ./bin/vbrEntry.bin + nasm -f bin ./src/boot/vbrMain.asm -o ./bin/vbrMain.bin + nasm -f bin ./src/boot/fsinfo.asm -o ./bin/fsinfo.bin + dd if=./bin/vbrEntry.bin of=./bin/vbr.bin bs=512 count=1 conv=notrunc status=none + dd if=./bin/vbrMain.bin of=./bin/vbr.bin bs=512 seek=1 count=2 conv=notrunc status=none + dd if=./bin/mbr.bin of=$@ bs=512 count=1 conv=notrunc status=none + dd if=./bin/vbr.bin of=$@ bs=512 seek=2050 count=3 conv=notrunc status=none + dd if=./bin/fsinfo.bin of=$@ bs=512 seek=2060 count=1 conv=notrunc status=none # Calculate kernel size and update boot sector -./bin/boot_with_size.bin: ./bin/mbr.bin ./bin/vbr.bin ./bin/kernel.bin - @echo "Calculating kernel size and updating VBR..." - # ./updateBoot.sh ./bin/vbr.bin ./bin/kernel.bin - @echo "Combining MBR + VBR into boot image..." - dd if=./bin/mbr.bin of=./bin/boot_with_size.bin bs=512 count=1 conv=notrunc - dd if=./bin/vbr.bin of=./bin/boot_with_size.bin bs=512 seek=2048 conv=notrunc - -./bin/os.bin: - python3 utilities/make_mbr_partition.py ./bin/os.bin --size 128 --start 2048 --type 0x0C - @bash -c " \ - set -e; \ - ATTACH_OUTPUT=$$(hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount ./bin/os.bin); \ - echo 'hdiutil attach output:'; \ - echo "$$ATTACH_OUTPUT"; \ - DISK_ID=$$(echo "$$ATTACH_OUTPUT" | awk '/\/dev\// {print $$1; exit}'); \ - if [ -z "$$DISK_ID" ]; then \ - echo 'ERROR: No device found. hdiutil did not recognize the image as a disk.'; \ - exit 1; \ - fi; \ - echo "DISK_ID is $$DISK_ID"; \ - PART_DEV=$$(ls /dev/$$(basename $$DISK_ID)s1 2>/dev/null || true); \ - if [ -z "$$PART_DEV" ]; then \ - echo 'ERROR: Partition device not found. Check the image partition table.'; \ - hdiutil detach $$DISK_ID; \ - exit 1; \ - fi; \ - echo "Formatting partition $$PART_DEV as FAT32..."; \ - sudo newfs_msdos -F 32 -v VIOS_BOOT $$PART_DEV; \ - hdiutil detach $$DISK_ID; \ - " - @sudo dd if=./bin/vbr.bin of=./bin/os.bin bs=512 seek=2048 conv=notrunc - +./bin/boot_with_size.bin: ./bin/boot.bin ./bin/kernel.bin + @echo "Calculating kernel size and updating boot sector..." + cp ./bin/boot.bin ./bin/boot_with_size.bin + + +./bin/os.bin: ./bin/boot_with_size.bin + rm -rf ./bin/os.bin + dd if=./bin/boot_with_size.bin of=./bin/os.bin bs=512 conv=notrunc + dd if=./bin/kernel.bin of=./bin/os.bin bs=512 seek=2070 conv=notrunc + dd if=/dev/zero bs=1048576 count=128 >> ./bin/os.bin + # Generic C and ASM file rules ./build/%.o: ./src/%.c mkdir -p $(dir $@) @@ -168,12 +158,14 @@ endif nasm -f elf -g $< -o $@ user_programs: - @{ \ - for dir in $(shell find ./assets/etc/default/user/programs -mindepth 1 -maxdepth 1 -type d); do \ + @if [ -d "./assets/etc/default/user/programs" ]; then \ + for dir in $$(find ./assets/etc/default/user/programs -mindepth 1 -maxdepth 1 -type d 2>/dev/null); do \ echo "Building user program $$dir..."; \ $(MAKE) -C $$dir all || exit 1; \ done; \ - } + else \ + echo "No user programs directory found (./assets/etc/default/user/programs), skipping..."; \ + fi user_programs_clean: @for dir in ./assets/etc/default/user/programs/*/ ; do \ diff --git a/README.md b/README.md index cc826fa..95dc91e 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ ___________ │   └── .keep ├── build.sh ├── buildExternal.sh +├── debug.log ├── docs │   └── api │   ├── copy_string_from_task.md @@ -200,8 +201,11 @@ ___________ │   │   ├── sb16.c │   │   └── sb16.h │   ├── boot +│   │   ├── fsinfo.asm │   │   ├── mbr.asm -│   │   └── vbr.asm +│   │   ├── vbrEntry.asm +│   │   ├── vbrMain.asm +│   │   └── vbrOld.asm │   ├── config.h │   ├── debug │   │   ├── simple_serial.c @@ -316,7 +320,6 @@ ___________ │   └── utils │   ├── utils.c │   └── utils.h -├── updateBoot.sh ├── updateREADME.sh ├── utilities │   ├── fonts @@ -325,11 +328,10 @@ ___________ │   │   ├── Brightly.otf │   │   ├── Cheri.ttf │   │   └── RobotoThin.ttf -│   ├── generateFonts.py -│   └── make_mbr_partition.py +│   └── generateFonts.py └── ViOS_LOGO_PNG.png -53 directories, 165 files +53 directories, 167 files ``` ___________ diff --git a/debug.log b/debug.log new file mode 100644 index 0000000..e5693fe Binary files /dev/null and b/debug.log differ diff --git a/src/boot/fsinfo.asm b/src/boot/fsinfo.asm new file mode 100644 index 0000000..7c3a901 --- /dev/null +++ b/src/boot/fsinfo.asm @@ -0,0 +1,17 @@ +; FAT32 FSInfo Sector +; This sector provides information about the filesystem state + +ORG 0x0000 +BITS 16 + +; FSInfo sector structure +FSInfo_LeadSig dd 0x41615252 ; Lead signature "RRaA" +FSInfo_Reserved1 times 480 db 0 ; Reserved bytes +FSInfo_StrucSig dd 0x61417272 ; Structure signature "rrAa" +FSInfo_Free_Count dd 0xFFFFFFFF ; Free cluster count (unknown) +FSInfo_Nxt_Free dd 0xFFFFFFFF ; Next free cluster (unknown) +FSInfo_Reserved2 times 12 db 0 ; Reserved bytes +FSInfo_TrailSig dd 0xAA550000 ; Trail signature + +; Pad to 512 bytes +times 512-($-$$) db 0 diff --git a/src/boot/mbr.asm b/src/boot/mbr.asm index 8002df4..5cc4376 100644 --- a/src/boot/mbr.asm +++ b/src/boot/mbr.asm @@ -1,63 +1,61 @@ -; MBR FAT32 Bootloader - loads first cluster of BOOT file -BITS 16 ORG 0x7C00 +BITS 16 start: cli xor ax, ax mov ds, ax mov es, ax - mov ss, ax - mov sp, 0x7C00 - sti - - ; Save boot drive - mov [boot_drive], dl - - ; Set text mode - mov ax, 0x03 - int 0x10 - ; Load first sector of partition at LBA 2048 - mov eax, 2048 ; Sector number to load - mov [dap_lba], eax - mov [dap_mem], word 0x8000 ; Destination segment:offset - mov [dap_mem + 2], word 0x0000 + mov si, load_msg + call print - ; INT 13h Extended Read (0x42) - mov si, disk_address_packet - mov dl, [boot_drive] + ; Setup Disk Address Packet (DAP) for partition start (LBA 2048) + mov si, dap mov ah, 0x42 + mov dl, 0x80 ; First hard disk int 0x13 jc disk_error - - ; Jump to loaded VBR/Stage2 - jmp 0:0x8000 + ; Far jump to loaded VBR at 0x0000:0x7E00 + jmp 0x0000:0x7E00 disk_error: - mov si, err_msg -.print_err: - lodsb - or al, al - jz $ + mov si, error_msg + call print + jmp $ + +print: mov ah, 0x0E +.next_char: + lodsb + cmp al, 0 + je .done int 0x10 - jmp .print_err - -; --- Disk Address Packet --- -disk_address_packet: - db 0x10 ; Size - db 0x00 ; Reserved - dw 1 ; Sectors to read -dap_mem: - dw 0x8000 ; Offset - dw 0x0000 ; Segment -dap_lba: - dd 0x00000800 ; LBA = 2048 - dd 0x00000000 ; LBA high dword - -boot_drive: db 0 -err_msg db "Disk Error", 0 - -times 510 - ($ - $$) db 0 -dw 0xAA55 \ No newline at end of file + jmp .next_char +.done: + ret + +load_msg db "MBR: Loading VBR...", 0 +error_msg db "MBR: Disk read error!", 0 + +; --- Disk Address Packet (DAP) --- +dap: + db 0x10 ; size of DAP + db 0x00 ; reserved + dw 0x0003 ; number of sectors to read + dw 0x7E00 ; offset + dw 0x0000 ; segment + dq 2050 ; LBA - VBR location + +times 446 - ($ - $$) db 0 ; Pad to partition table + +; === Partition Table === +db 0x80 ; Bootable +db 0x01, 0x01, 0x00 ; CHS start — dummy +db 0x0C ; FAT32 (LBA) +db 0xFE, 0xFF, 0xFF ; CHS end — dummy +dd 3000 ; LBA of first sector of partition +dd 260096 ; Number of sectors in partition (262144 - 2048) + +times 3*16 db 0 ; Empty partitions +dw 0xAA55 ; Boot signature diff --git a/src/boot/vbr.asm b/src/boot/vbr.asm deleted file mode 100644 index 4526310..0000000 --- a/src/boot/vbr.asm +++ /dev/null @@ -1,228 +0,0 @@ -[BITS 16] -[ORG 0x7C00] - -jmp short start -nop - -; === GDT === -gdt_start: -gdt_null: dq 0 -gdt_code: dw 0xFFFF, 0x0000, 0x9A00, 0x00CF -gdt_data: dw 0xFFFF, 0x0000, 0x9200, 0x00CF -gdt_end: - -gdtr: dw 0 - dd 0 - -CODE_SEG equ 0x08 -DATA_SEG equ 0x10 - -; --- BIOS Parameter Block (FAT32) --- -OEMLabel: db 'VIOS ' -BytesPerSector: dw 512 -SectorsPerCluster: db 8 -ReservedSectors: dw 32 -NumberOfFATs: db 2 -RootEntries: dw 0 -TotalSectors16: dw 0 -MediaDescriptor: db 0xF8 -SectorsPerFAT16: dw 0 -SectorsPerTrack: dw 63 -NumberOfHeads: dw 255 -HiddenSectors: dd 2048 -TotalSectors32: dd 274432 - -SectorsPerFAT32: dd 256 -ExtFlags: dw 0 -FSVersion: dw 0 -RootCluster: dd 2 -FSInfo: dw 1 -BackupBootSector: dw 6 -Reserved: db 12 dup(0) - -DriveNumber: db 0x80 -Reserved1: db 0 -BootSignature: db 0x29 -VolumeID: dd 0x12345678 -VolumeLabel: db 'VIOS BOOT ' -FileSystemType: db 'FAT32 ' - -; === Kernel Information === -boot_drive: db 0 -kernel_start_sector: dd 2049 -kernel_size_sectors: dw 4 ; patch as needed - -; === Code begins === -start: - lea si, msg_start - call serial_send_string - ; Save drive - mov [boot_drive], dl - - ; Setup stack - xor ax, ax - mov ss, ax - mov sp, 0x7C00 - - call init_serial - call serial_send_R - - lea si, msg_before_kernel - call serial_send_string - call load_kernel - lea si, msg_after_kernel - call serial_send_string - - call serial_send_L - - lea si, msg_before_prot - call serial_send_string - call enter_protected - -; === Serial routines === -init_serial: - mov dx, 0x3FB - mov al, 0x80 - out dx, al - mov dx, 0x3F8 - mov al, 0x03 - out dx, al - mov dx, 0x3F9 - mov al, 0x00 - out dx, al - mov dx, 0x3FB - mov al, 0x03 - out dx, al - ret - -serial_wait: - mov dx, 0x3FD - in al, dx - test al, 0x20 - jz serial_wait - ret - -serial_send: - call serial_wait - mov dx, 0x3F8 - out dx, al - ret - -serial_send_R: - mov al, 'R' - call serial_send - ret - -serial_send_L: - mov al, 'L' - call serial_send - ret - -serial_send_G: - mov al, 'G' - call serial_send - ret - -serial_send_P: - mov al, 'P' - call serial_send - ret - -serial_send_J: - mov al, 'J' - call serial_send - ret - -serial_send_string: - pusha -.next_char: - lodsb - or al, al - jz .done - call serial_send - jmp .next_char -.done: - popa - ret - -; === Kernel loading with INT 13h Extensions === -load_kernel: - mov edi, 0x100000 - mov eax, [kernel_start_sector] - mov cx, [kernel_size_sectors] - -.read: - pusha - mov si, dap - mov dl, [boot_drive] - mov [dap+4], di - mov [dap+6], word 0 - mov [dap+8], eax - mov [dap+2], word 1 - mov ah, 0x42 - int 0x13 - popa - add edi, 512 - inc eax - dec cx - jnz .read - ret - -; === Enter protected mode === -enter_protected: - cli - - ; Copy GDT to known address (0x0500) - lea si, [gdt_start] - mov di, 0x0500 - mov cx, gdt_end - gdt_start - rep movsb - - ; Setup descriptor - mov word [gdtr], gdt_end - gdt_start - 1 - mov dword [gdtr + 2], 0x00000500 - - lgdt [gdtr] - - call serial_send_G - - ; Enable protected mode - mov eax, cr0 - or eax, 1 - mov cr0, eax - - jmp 0x08:protected_entry ; far jump - -; === 32-bit code starts here === -[bits 32] -protected_entry: - mov ax, DATA_SEG - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - mov esp, 0x200000 - - call serial_send_P - - ; Jump to kernel - call serial_send_J - jmp CODE_SEG:0x100000 - -; === DAP === -[bits 16] -dap: - db 0x10, 0 - dw 1 - dw 0, 0 - dd 0, 0 - -; Pad to 510 bytes -times 510-($-$$) db 0 -dw 0xAA55 - -msg_start: db 'VBR: start', 0 -msg_before_kernel: db 'VBR: before kernel', 0 -msg_after_kernel: db 'VBR: after kernel', 0 -msg_before_prot: db 'VBR: before prot', 0 diff --git a/src/boot/vbrEntry.asm b/src/boot/vbrEntry.asm new file mode 100644 index 0000000..804ea09 --- /dev/null +++ b/src/boot/vbrEntry.asm @@ -0,0 +1,63 @@ +ORG 0x7E00 +BITS 16 + +jmp short load_stage2 +nop + +; === BIOS Parameter Block === +OEMIdentifier db 'MSWIN4.1' +BytesPerSector dw 512 +SectorsPerCluster db 8 +ReservedSectors dw 32 +FATCopies db 2 +RootDirEntries dw 0 +NumSectors dw 0 +MediaType db 0xF8 +SectorsPerFat dw 0 +SectorsPerTrack dw 63 +NumberOfHeads dw 255 +HiddenSectors dd 2048 +SectorsBig dd 262144 + +; === FAT32 Extended BPB === +SectorsPerFat32 dd 2048 +ExtFlags dw 0 +FSVersion dw 0 +RootCluster dd 2 +FSInfoSector dw 1 +BackupBootSector dw 6 +ReservedEx times 12 db 0 +DriveNumber db 0x80 +Reserved1 db 0 +BootSignature db 0x29 +VolumeID dd 0x12345678 +VolumeLabel db 'VIOS BOOT ' +SystemIDString db 'FAT32 ' + +load_stage2: + ; Debug: Print VBR Entry message + mov si, vbr_entry_msg + call print_entry_msg + + jmp 0x0000:0x7F00 + +print_entry_msg: + mov ah, 0x0E +.next_char: + lodsb + test al, al + jz .done + int 0x10 + jmp .next_char +.done: + ret + +vbr_entry_msg db "VBR Entry: Loading stage2...", 0 + +hang: + cli + hlt + jmp hang + +times 510-($-$$) db 0 +dw 0xAA55 diff --git a/src/boot/vbrMain.asm b/src/boot/vbrMain.asm new file mode 100644 index 0000000..582d560 --- /dev/null +++ b/src/boot/vbrMain.asm @@ -0,0 +1,391 @@ +ORG 0x7F00 +BITS 16 + +jmp start + +; === Custom kernel info === +KernelStartSector dd 2070 +KernelSizeSectors dw 230 + +vbe_error_msg db "VBE mode failed", 0 +msg_hello db 'BOOTLOADER OK', 13, 10, 0 + +init_serial: + mov dx, 0x3F8 ; COM1 base port + mov al, 0x00 ; Disable interrupts + out dx, al + + mov dx, 0x3FB ; Line Control Register (LCR) + mov al, 0x80 ; Enable DLAB (set baud rate divisor) + out dx, al + + mov dx, 0x3F8 ; Set divisor to 3 (38400 baud) + mov al, 0x03 + out dx, al + mov dx, 0x3F9 + mov al, 0x00 + out dx, al + + mov dx, 0x3FB ; 8 bits, no parity, one stop bit + mov al, 0x03 + out dx, al + + mov dx, 0x3FC ; FIFO control register + mov al, 0xC7 ; Enable FIFO, clear them, 14-byte threshold + out dx, al + + mov dx, 0x3FE ; Modem control + mov al, 0x0B ; IRQs enabled, RTS/DSR set + out dx, al + ret + +serial_write_char: + mov dx, 0x3FD ; LSR +.wait: + in al, dx + test al, 0x20 ; Bit 5 = Transmit Holding Register Empty (THRE) + jz .wait + mov dx, 0x3F8 ; Transmit buffer + mov al, bl + out dx, al + ret + +serial_print: + pusha +.next_char: + lodsb + test al, al + jz .done + mov bl, al + call serial_write_char + jmp .next_char +.done: + popa + ret + +; === VBE Error Message === +vbe_error: + mov ax, 0xB800 + mov es, ax + xor di, di + mov si, vbe_error_msg +.print_loop: + lodsb + cmp al, 0 + je .done + mov ah, 0x07 + mov [es:di], ax + add di, 2 + jmp .print_loop +.done: + jmp $ + +; === Entry Point === +start: + call init_serial + + ; Try VBE Mode 0x17E + mov ax, 0x4F01 + mov cx, 0x17E + mov bx, 0x090 + mov es, bx + xor di, di + int 0x10 + cmp ax, 0x004F + jne try_117_query + + mov ax, 0x4F02 + mov bx, 0x17E + int 0x10 + cmp ax, 0x004F + jne try_117_query + + jmp vbe_success + +try_117_query: + ; Fallback to VBE Mode 0x117 + mov ax, 0x4F01 + mov cx, 0x117 + mov bx, 0x090 + mov es, bx + xor di, di + int 0x10 + cmp ax, 0x004F + jne vbe_error + + mov ax, 0x4F02 + mov bx, 0x117 + int 0x10 + cmp ax, 0x004F + jne vbe_error + +vbe_success: + call clear + + xor ax, ax + mov ds, ax + mov es, ax + jmp step2 + +; === Print Message Function === +print_msg: + mov ah, 0x0E +.next_char: + lodsb + test al, al + jz .done + int 0x10 + jmp .next_char +.done: + ret + +; === Clear Screen === +clear: + mov ax, 0xB800 + mov es, ax + xor di, di + mov cx, 80 * 25 +.clear_loop: + mov word [es:di], 0x0720 + add di, 2 + loop .clear_loop + ret + +; === Enter Protected Mode === +step2: + ; Debug: Send VBE success marker + mov bl, 'O' + call serial_write_char + mov bl, 'K' + call serial_write_char + mov bl, 10 + call serial_write_char + + ; === Enable protected mode === + cli + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + mov sp, 0x7C00 + sti + +.load_protected: + cli + + ; Debug: Send GDT loading marker + mov bl, 'G' + call serial_write_char + mov bl, 'D' + call serial_write_char + mov bl, 'T' + call serial_write_char + mov bl, 10 + call serial_write_char + + lgdt [gdt_descriptor] + mov eax, cr0 + or eax, 1 + mov cr0, eax + + ; Debug: Send marker before jump + mov bl, 'J' + call serial_write_char + mov bl, 'M' + call serial_write_char + mov bl, 'P' + call serial_write_char + mov bl, 10 + call serial_write_char + + ; Manual far jump with inline target + db 0xEA ; Far jump opcode + dw protected_mode_start ; Jump to code right after this + dw 0x08 ; Code segment (CODE_SEG = 8) + +; === Protected Mode Entry Point === +[BITS 32] +protected_mode_start: + mov ax, DATA_SEG + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, 0x90000 + + ; Debug: Send protected mode success marker + mov bl, '3' + call serial_write_char_32 + mov bl, '2' + call serial_write_char_32 + mov bl, 10 + call serial_write_char_32 + + ; Enable A20 + in al, 0x92 + or al, 2 + out 0x92, al + + ; Read kernel sectors from disk + mov eax, KernelStartSector ; LBA start + movzx ecx, word [KernelSizeSectors] + mov edi, 0x100000 ; Kernel load address (1 MB) + call ata_lba_read + + ; Jump to kernel + jmp 0x8:0x100000 + +; === GDT === +gdt_start: +gdt_null: + dq 0x0 + +gdt_code: + dw 0xFFFF ; Limit low + dw 0x0000 ; Base low + db 0x00 ; Base middle + db 0x9A ; Access + db 0xCF ; Flags + Limit high nibble + db 0x00 ; Base high + +gdt_data: + dw 0xFFFF ; Limit low + dw 0x0000 ; Base low + db 0x00 ; Base middle + db 0x92 ; Access (read/write, accessed = 0) + db 0xCF ; Flags + Limit high nibble + db 0x00 ; Base high + +gdt_end: + +gdt_descriptor: + dw gdt_end - gdt_start - 1 + dd gdt_start + +CODE_SEG equ gdt_code - gdt_start +DATA_SEG equ gdt_data - gdt_start + +; === Protected Mode (32-bit) === +[BITS 32] +serial_write_char_32: + mov dx, 0x3FD ; LSR +.wait: + in al, dx + test al, 0x20 ; Bit 5 = Transmit Holding Register Empty (THRE) + jz .wait + mov dx, 0x3F8 ; Transmit buffer + mov al, bl + out dx, al + ret + +load32_real: + mov ax, DATA_SEG + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, 0x90000 + + ; Debug: Send protected mode success marker + mov bl, '3' + call serial_write_char_32 + mov bl, '2' + call serial_write_char_32 + mov bl, 10 + call serial_write_char_32 + + ; Enable A20 + in al, 0x92 + or al, 2 + out 0x92, al + + ; Read kernel sectors from disk + mov eax, KernelStartSector ; LBA start + movzx ecx, word [KernelSizeSectors] + mov edi, 0x100000 ; Kernel load address (1 MB) + call ata_lba_read + + ; Jump to kernel + jmp 0x8:0x100000 + +; === ATA LBA Sector Read === +ata_lba_read: + pushad + mov esi, ecx ; Save sector count in ESI + +.next_sector: + mov ebx, eax ; Save LBA + + ; Select drive and set LBA mode + mov al, bl + shr eax, 24 + and eax, 0x0F + or eax, 0xE0 ; LBA mode, master drive + mov dx, 0x1F6 + out dx, al + + ; Set sector count + mov al, 1 ; Read 1 sector at a time + mov dx, 0x1F2 + out dx, al + + ; Set LBA address + mov eax, ebx + mov dx, 0x1F3 + out dx, al ; LBA[7:0] + + mov dx, 0x1F4 + shr eax, 8 + out dx, al ; LBA[15:8] + + mov dx, 0x1F5 + shr eax, 8 + out dx, al ; LBA[23:16] + + ; Issue READ command + mov dx, 0x1F7 + mov al, 0x20 + out dx, al + + ; Wait for BSY to clear and DRQ to set +.wait_ready: + mov dx, 0x1F7 +.wait: + in al, dx + test al, 0x80 ; BSY bit + jnz .wait ; Wait while busy + test al, 0x08 ; DRQ bit + jz .wait ; Wait for data ready + test al, 0x01 ; ERR bit + jnz .disk_error ; Check for error + +.read_data: + mov ecx, 256 ; 256 words = 512 bytes + mov dx, 0x1F0 + rep insw + + ; Move to next sector + add edi, 512 + inc ebx + mov eax, ebx + dec esi + jnz .next_sector + + popad + ret + +.disk_error: + ; Send error message over serial + mov bl, 'E' + call serial_write_char_32 + mov bl, 'R' + call serial_write_char_32 + mov bl, 'R' + call serial_write_char_32 + mov bl, 10 + call serial_write_char_32 + jmp $ ; Hang diff --git a/src/boot/vbrOld.asm b/src/boot/vbrOld.asm new file mode 100644 index 0000000..7ea739a --- /dev/null +++ b/src/boot/vbrOld.asm @@ -0,0 +1,293 @@ +ORG 0x7E00 +BITS 16 + +jmp near start +nop + +; FAT32 BPB (BIOS Parameter Block) +OEMIdentifier db 'MSWIN4.1' ; 0x03 - 8 bytes (standard OEM ID) +BytesPerSector dw 512 ; 0x0B - bytes per sector +SectorsPerCluster db 8 ; 0x0D - sectors per cluster +ReservedSectors dw 32 ; 0x0E - reserved sectors +FATCopies db 2 ; 0x10 - number of FATs +RootDirEntries dw 0 ; 0x11 - root dir entries (0 for FAT32) +NumSectors dw 0 ; 0x13 - total sectors (0 for FAT32) +MediaType db 0xF8 ; 0x15 - media descriptor +SectorsPerFat dw 0 ; 0x16 - sectors per FAT (0 for FAT32) +SectorsPerTrack dw 63 ; 0x18 - sectors per track +NumberOfHeads dw 255 ; 0x1A - number of heads +HiddenSectors dd 2048 ; 0x1C - hidden sectors +SectorsBig dd 262144 ; 0x20 - large sector count (128MB) + +; FAT32 Extended BPB +SectorsPerFat32 dd 2048 ; 0x24 - sectors per FAT32 +ExtFlags dw 0 ; 0x28 - extension flags +FSVersion dw 0 ; 0x2A - filesystem version +RootCluster dd 2 ; 0x2C - root directory cluster +FSInfoSector dw 1 ; 0x30 - FSInfo sector +BackupBootSector dw 6 ; 0x32 - backup boot sector +ReservedEx times 12 db 0 ; 0x34 - reserved + +DriveNumber db 0x80 ; 0x40 - drive number +Reserved1 db 0 ; 0x41 - reserved +BootSignature db 0x29 ; 0x42 - boot signature +VolumeID dd 0x12345678 ; 0x43 - volume ID +VolumeLabel db 'VIOS BOOT ' ; 0x47 - volume label (11 bytes) +SystemIDString db 'FAT32 ' ; 0x52 - system identifier (8 bytes) + +; === Kernel Metadata === +KernelStartSector dd 2050 +KernelSizeSectors dw 230 + +; === VBE Error Message === +vbe_error: + mov ax, 0xB800 + mov es, ax + xor di, di + mov si, vbe_error_msg +.print_loop: + lodsb + cmp al, 0 + je .done + mov ah, 0x07 + mov [es:di], ax + add di, 2 + jmp .print_loop +.done: + jmp $ + +vbe_error_msg db "VBE mode failed", 0 + +; === Entry Point === +start: + ; Try VBE Mode 0x17E + mov ax, 0x4F01 + mov cx, 0x17E + mov bx, 0x090 + mov es, bx + xor di, di + int 0x10 + cmp ax, 0x004F + jne try_117_query + + mov ax, 0x4F02 + mov bx, 0x17E + int 0x10 + cmp ax, 0x004F + jne try_117_query + + jmp vbe_success + +try_117_query: + ; Fallback to VBE Mode 0x117 + mov ax, 0x4F01 + mov cx, 0x117 + mov bx, 0x090 + mov es, bx + xor di, di + int 0x10 + cmp ax, 0x004F + jne vbe_error + + mov ax, 0x4F02 + mov bx, 0x117 + int 0x10 + cmp ax, 0x004F + jne vbe_error + +vbe_success: + call clear + + xor ax, ax + mov ds, ax + mov es, ax + jmp 0:step2 + +; === Clear Screen === +clear: + mov ax, 0xB800 + mov es, ax + xor di, di + mov cx, 80 * 25 +.clear_loop: + mov word [es:di], 0x0720 + add di, 2 + loop .clear_loop + ret + +; === Protected Mode Setup === +step2: + cli + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + mov sp, 0x7C00 + sti + +.load_protected: + cli + lgdt [gdt_descriptor] + mov eax, cr0 + or eax, 1 + mov cr0, eax + jmp CODE_SEG:load32 + +; === GDT Setup === +gdt_start: +gdt_null: dq 0 + +gdt_code: + dw 0xFFFF + dw 0x0000 + db 0x00 + db 0x9A + db 0xCF + db 0x00 + +gdt_data: + dw 0xFFFF + dw 0x0000 + db 0x00 + db 0x92 + db 0xCF + db 0x00 + +gdt_end: + +gdt_descriptor: + dw gdt_end - gdt_start - 1 + dd gdt_start + +CODE_SEG equ gdt_code - gdt_start +DATA_SEG equ gdt_data - gdt_start + +; === 32-bit Protected Mode Code === +[BITS 32] +load32: + mov ax, DATA_SEG + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; Enable A20 + in al, 0x92 + or al, 2 + out 0x92, al + + ; Move temp kernel sector (VBR data) + mov esi, 0x90000 + mov edi, 0x20000 + mov ecx, 512 + cld + rep movsb + + ; Read kernel + mov eax, 10 ; LBA start (absolute - kernel is at LBA 2050) + movzx ecx, word [KernelSizeSectors] ; Sector count + mov edi, 0x0100000 ; Load to 1 MB + call ata_lba_read + + jmp CODE_SEG:0x0100000 + +; === ATA LBA Sector Read === +ata_lba_read: + mov ebx, eax + + shr eax, 24 + or eax, 0xE0 + mov dx, 0x1F6 + out dx, al + + mov eax, ecx + mov dx, 0x1F2 + out dx, al + + mov eax, ebx + mov dx, 0x1F3 + out dx, al + + mov dx, 0x1F4 + shr eax, 8 + out dx, al + + mov dx, 0x1F5 + shr eax, 8 + out dx, al + + mov dx, 0x1F7 + mov al, 0x20 + out dx, al + +.next_sector: + push ecx + mov ebx, 0x10000 ; Timeout counter +.try_again: + mov dx, 0x1F7 + in al, dx + test al, 8 + jz .check_timeout + jmp .data_ready +.check_timeout: + dec ebx + jnz .try_again + ; Timeout expired – add real error handling if desired + jmp $ ; Hang for now on timeout +.data_ready: + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + mov ecx, 256 + mov dx, 0x1F0 + rep insw + + pop ecx + loop .next_sector + ret + +; === Boot Signature === +times 510-($ - $$) db 0 +dw 0xAA55 \ No newline at end of file diff --git a/src/fs/fat/fat32.c b/src/fs/fat/fat32.c index ed6eb6d..e9fc7d4 100644 --- a/src/fs/fat/fat32.c +++ b/src/fs/fat/fat32.c @@ -143,18 +143,42 @@ int fat32_resolve(struct disk *disk) goto out; } + // Seek to partition start (LBA 2048) instead of disk start (LBA 0) + // The partition starts at LBA 2048 according to the MBR + simple_serial_puts("DEBUG: Seeking to partition start at LBA 2048\n"); + if (diskstreamer_seek(stream, 2048 * 512) != VIOS_ALL_OK) + { + simple_serial_puts("DEBUG: Failed to seek to partition start\n"); + res = -EIO; + goto out; + } + + simple_serial_puts("DEBUG: Reading FAT32 header from partition start\n"); if (diskstreamer_read(stream, &fat_private->header, sizeof(fat_private->header)) != VIOS_ALL_OK) { + simple_serial_puts("DEBUG: Failed to read FAT32 header\n"); res = -EIO; goto out; } + simple_serial_puts("DEBUG: Checking FAT32 signature\n"); + simple_serial_puts("DEBUG: Found signature: 0x"); + // Simple hex output for signature + uint8_t sig = fat_private->header.extended.signature; + char hex_digits[] = "0123456789ABCDEF"; + char hex_str[3] = { hex_digits[sig >> 4], hex_digits[sig & 0xF], 0 }; + simple_serial_puts(hex_str); + simple_serial_puts(" (expected 0x29)\n"); + if (fat_private->header.extended.signature != VIOS_FAT32_SIGNATURE) { + simple_serial_puts("DEBUG: FAT32 signature mismatch\n"); res = -EFSNOTUS; goto out; } + simple_serial_puts("DEBUG: FAT32 filesystem recognized successfully\n"); + out: if (stream) { diff --git a/src/kernel.asm b/src/kernel.asm index 5c59b20..a941287 100644 --- a/src/kernel.asm +++ b/src/kernel.asm @@ -19,6 +19,12 @@ _start: mov ebp, 0x00200000 mov esp, ebp + ; Clear screen to red color for debugging - if we see red, we reached kernel + mov edi, 0xb8000 ; VGA text buffer + mov ecx, 80 * 25 ; 80 columns * 25 rows + mov ax, 0x4f20 ; Red background (0x4f) + space character (0x20) + rep stosw ; Fill screen with red spaces + ; Remap the master PIC mov al, 00010001b out 0x20, al ; Tell master PIC diff --git a/src/linker.ld b/src/linker.ld index 7f84431..12c879a 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -5,6 +5,7 @@ SECTIONS . = 1M; .text : ALIGN(4096) { + *(.text.start) *(.text) } diff --git a/src/task/task.asm b/src/task/task.asm index 7b5a033..e8a8cda 100644 --- a/src/task/task.asm +++ b/src/task/task.asm @@ -9,10 +9,15 @@ global user_registers task_return: ; Debug: Print that we entered task_return push eax - mov eax, 0x3F8 ; COM1 port - mov byte [eax], 'T' - mov byte [eax], 'R' - mov byte [eax], '\n' + push edx + mov dx, 0x3F8 ; COM1 port + mov al, 'T' + out dx, al + mov al, 'R' + out dx, al + mov al, 10 ; newline + out dx, al + pop edx pop eax mov ebp, esp @@ -53,10 +58,15 @@ task_return: ; Debug: Print that we're about to do iretd push eax - mov eax, 0x3F8 ; COM1 port - mov byte [eax], 'I' - mov byte [eax], 'R' - mov byte [eax], '\n' + push edx + mov dx, 0x3F8 ; COM1 port + mov al, 'I' + out dx, al + mov al, 'R' + out dx, al + mov al, 10 ; newline + out dx, al + pop edx pop eax ; Let's leave kernel land and execute in user land! diff --git a/updateBoot.sh b/updateBoot.sh deleted file mode 100755 index 67d549e..0000000 --- a/updateBoot.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -e - -VBR_BIN="$1" -KERNEL_BIN="$2" - -if [[ ! -f "$VBR_BIN" || ! -f "$KERNEL_BIN" ]]; then - echo "Usage: $0 " - exit 1 -fi - -KERNEL_SIZE_BYTES=$(wc -c < "$KERNEL_BIN") -KERNEL_SIZE_SECTORS=$(( (KERNEL_SIZE_BYTES + 511) / 512 )) - -SECTOR0=$((KERNEL_SIZE_SECTORS & 0xFF)) # low byte -SECTOR1=$(((KERNEL_SIZE_SECTORS >> 8) & 0xFF)) # high byte - -echo "Kernel size: $KERNEL_SIZE_BYTES bytes = $KERNEL_SIZE_SECTORS sectors" -echo "Patch bytes: $SECTOR0 (0x$(printf '%02X' $SECTOR0)) $SECTOR1 (0x$(printf '%02X' $SECTOR1))" - -# Patch offset 95 and 96 (zero-based) -printf "\\$(printf '%03o' $SECTOR0)" | dd of="$VBR_BIN" bs=1 seek=95 conv=notrunc 2>/dev/null -printf "\\$(printf '%03o' $SECTOR1)" | dd of="$VBR_BIN" bs=1 seek=96 conv=notrunc 2>/dev/null - -echo "✅ VBR updated with kernel size at offset 0x5F (decimal 95)" diff --git a/utilities/make_mbr_partition.py b/utilities/make_mbr_partition.py deleted file mode 100644 index 41f5cb2..0000000 --- a/utilities/make_mbr_partition.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -import sys -import struct -import os - -# Constants -SECTOR_SIZE = 512 -DEFAULT_PARTITION_START = 2048 -DEFAULT_PARTITION_TYPE = 0x0C # FAT32 LBA -DEFAULT_IMAGE_SIZE_MB = 128 - - -def write_blank_image(path, size_mb): - size_bytes = size_mb * 1024 * 1024 - with open(path, 'wb') as f: - f.truncate(size_bytes) - print(f"Created blank image: {path} ({size_mb} MB)") - -def create_mbr(partition_start, partition_size, partition_type): - mbr = bytearray([0x90] * SECTOR_SIZE) # Fill with NOPs for minimal boot code - part_offset = 446 - # CHS start: head=0, sector=2, cylinder=0 => 0x00 0x02 0x00 - chs_start = b'\x00\x02\x00' - # CHS end: head=254, sector=63, cylinder=1023 => 0xFE 0xFF 0xFF - chs_end = b'\xFE\xFF\xFF' - entry = struct.pack('