commit 9efe950b7b95d6be90879b62020aab169c5f7fb2 Author: iDunnoDev Date: Sat Nov 5 11:14:32 2022 +0000 Initial Commit diff --git a/stage1/.vscode/tasks.json b/stage1/.vscode/tasks.json new file mode 100644 index 0000000..51722d9 --- /dev/null +++ b/stage1/.vscode/tasks.json @@ -0,0 +1,13 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build and QEMU", + "type": "shell", + "command": "make qemu", + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/stage1/Makefile b/stage1/Makefile new file mode 100644 index 0000000..e409242 --- /dev/null +++ b/stage1/Makefile @@ -0,0 +1,102 @@ +# Try to infer the correct TOOLPREFIX if not set +ifndef TOOLPREFIX +TOOLPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \ + then echo 'i386-jos-elf-'; \ + elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \ + then echo ''; \ + else echo "***" 1>&2; \ + echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \ + echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \ + echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \ + echo "*** prefix other than 'i386-jos-elf-', set your TOOLPREFIX" 1>&2; \ + echo "*** environment variable to that prefix and run 'make' again." 1>&2; \ + echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \ + echo "***" 1>&2; exit 1; fi) +endif + +# If the makefile can't find QEMU, specify its path here +# QEMU = qemu-system-i386 + +# Try to infer the correct QEMU +ifndef QEMU +QEMU = $(shell if which qemu > /dev/null; \ + then echo qemu; exit; \ + elif which qemu-system-i386 > /dev/null; \ + then echo qemu-system-i386; exit; \ + elif which qemu-system-x86_64 > /dev/null; \ + then echo qemu-system-x86_64; exit; \ + else \ + qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \ + if test -x $$qemu; then echo $$qemu; exit; fi; fi; \ + echo "***" 1>&2; \ + echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \ + echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \ + echo "*** or have you tried setting the QEMU variable in Makefile?" 1>&2; \ + echo "***" 1>&2; exit 1) +endif + +CC = $(TOOLPREFIX)gcc +AS = $(TOOLPREFIX)gas +LD = $(TOOLPREFIX)ld +OBJCOPY = $(TOOLPREFIX)objcopy +OBJDUMP = $(TOOLPREFIX)objdump +CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer +CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) +ASFLAGS = -m32 -gdwarf-2 -Wa,-divide +# FreeBSD ld wants ``elf_i386_fbsd'' +LDFLAGS += -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1) + +# Disable PIE when possible (for Ubuntu 16.10 toolchain) +ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),) +CFLAGS += -fno-pie -no-pie +endif +ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]nopie'),) +CFLAGS += -fno-pie -nopie +endif + +xv6.img: bootblock bootblock2 + dd if=/dev/zero of=xv6.img count=10000 + dd if=bootblock of=xv6.img conv=notrunc + dd if=bootblock2 of=xv6.img seek=1 conv=notrunc + +bootblock: bootasm.S + $(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S + $(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o + $(OBJCOPY) -S -O binary -j .text bootblock.o bootblock + ./sign.pl bootblock + +bootblock2: bootasm2.S + $(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm2.S + $(LD) $(LDFLAGS) -N -e start -Ttext 0x9000 -o bootblock2.o bootasm2.o + $(OBJCOPY) -S -O binary -j .text bootblock2.o bootblock2 + + +.PRECIOUS: %.o + +clean: + rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \ + *.o *.d *.asm *.sym vectors.S bootblock bootblock2 entryother \ + initcode initcode.out kernel xv6.img fs.img kernelmemfs \ + xv6memfs.img mkfs \ + syscall.h syscalltable.h usys.S + +# run in emulators + +# try to generate a unique GDB port +GDBPORT = $(shell expr `id -u` % 5000 + 25000) +# QEMU's gdb stub command line changed in 0.11 +QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \ + then echo "-gdb tcp::$(GDBPORT)"; \ + else echo "-s -p $(GDBPORT)"; fi) +ifndef CPUS +CPUS := 1 +endif +QEMUOPTS = -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA) + +qemu: xv6.img + $(QEMU) -vga std -serial mon:stdio $(QEMUOPTS) + +qemu-gdb: xv6.img + @echo "*** Now run 'gdb'." 1>&2 + $(QEMU) -vga std -serial mon:stdio $(QEMUOPTS) -S -gdb tcp::1234 + diff --git a/stage1/bootasm.S b/stage1/bootasm.S new file mode 100644 index 0000000..ebfa7da --- /dev/null +++ b/stage1/bootasm.S @@ -0,0 +1,101 @@ +# When the PC starts, the processor is essentially emulating an 8086 processor, i.e. +# a 16-bit processor. So our initial boot loader code is 16-bit code that will +# eventually switch the processor into 32-bit mode. + +# This code is linked to assume a starting address of 0x7C00 which is where the BIOS +# will load a boot segment. + +.code16 # Assemble for 16-bit mode +.globl start +start: + jmp real_start + +# Write to the console using BIOS. +# +# Input: SI contains the address of the null-terminated string to be displayed + +cons_write: + movb $0x0e, %ah # 0x0e is the INT 10h BIOS call to output the value contained in AL to screen + +cons_write_rpt: + movb (%si), %al # Load the byte at the location contained in the SI register into AL + inc %si # Add 1 to the value in SI + cmp $0, %al # Compare the value in AL with 0 + jz cons_write_done # If it is zero, then we are done + int $0x10 # Output the character in AL to the screen + jmp cons_write_rpt # and continue + +cons_write_done: # Something that is called will never return + ret # until a 'ret' instruction is encountered. Labels do + # not give a program any structure. They just give a + # memory location a name that we can use in our code. + +cons_write_crlf: + movb $0x0e, %ah # Output CR + movb $0x0d, %al + int $0x10 + movb $0x0a, %al # Output LF + int $0x10 + ret + +cons_writeline: + call cons_write + call cons_write_crlf + ret + +real_start: + cli # BIOS enabled interrupts; disable + + # Zero data segment registers DS, ES, and SS. + xorw %ax, %ax # Set %ax to zero + movw %ax, %ds # -> Data Segment + movw %ax, %es # -> Extra Segment + movw %ax, %ss # -> Stack Segment + movw $0, %sp # Set the stack to the top of the segment + + movb %dl, (boot_device) # Boot device number is passed in DL from BIOS. Save it hear since DL might get trashed + + movw $boot_message, %si # Display our boot message + call cons_writeline + + movb $2, %ah # BIOS function 13h, sub-function 2 is read sectors + movb $7, %al # Number of sectors to read = 7 + movw $0x9000, %bx # The 7 sectors will be loaded into memory at ES:BX (0000:9000h) + movb $0, %ch # Use cylinder 0 + movb $0, %dh # Use head 0 + movb (boot_device), %dl # Retrieve the ID of our boot device + movb $2, %cl # Start reading at sector 2 (i.e. one after the boot sector) + int $0x13 + cmpb $7, %al # AL returns the number of sectors read. If this is not 7, report an error + jne read_failed + + movb (0x9000), %al # Check that what we loaded is not empty + cmpb $0, %al + je read_failed + + movb (boot_device), %dl # Pass boot device ID to second stage + movw $0x9000, %ax # Jump to stage 2 + jmp *%ax + +read_failed: # Display error messages + movw $read_failed_msg, %si + call cons_writeline + + mov $cannot_continue, %si + call cons_writeline + +endless_loop: # Loop forever more + jmp endless_loop + +# Program data + +boot_device: + .byte 0 + +boot_message: + .string "Boot Loader V1.0" +read_failed_msg: + .string "Unable to read stage 2 of the boot process" +cannot_continue: + .string "Cannot continue boot process" + diff --git a/stage1/bootasm.d b/stage1/bootasm.d new file mode 100644 index 0000000..59e6ae8 --- /dev/null +++ b/stage1/bootasm.d @@ -0,0 +1 @@ +bootasm.o: bootasm.S diff --git a/stage1/bootasm.o b/stage1/bootasm.o new file mode 100644 index 0000000..4f7fa1e Binary files /dev/null and b/stage1/bootasm.o differ diff --git a/stage1/bootasm2.S b/stage1/bootasm2.S new file mode 100644 index 0000000..bac0b9c --- /dev/null +++ b/stage1/bootasm2.S @@ -0,0 +1,224 @@ +# Second stage of the boot loader + +.code16 # Assemble for 16-bit mode +.globl start +start: + jmp real_start + +# Write to the console using BIOS. +# +# Input: SI contains the address of the null-terminated string to be displayed + +cons_write: + movb $0x0e, %ah # 0x0e is the INT 10h BIOS call to output the value contained in AL to screen + +cons_write_rpt: + movb (%si), %al # Load the byte at the location contained in the SI register into AL + inc %si # Add 1 to the value in SI + cmp $0, %al # Compare the value in AL with 0 + jz cons_write_done # If it is zero, then we are done + int $0x10 # Output the character in AL to the screen + jmp cons_write_rpt # and continue + +cons_write_done: # Something that is called will never return + ret # until a 'ret' instruction is encountered. Labels do + # not give a program any structure. They just give a + # memory location a name that we can use in our code. + +cons_write_crlf: + movb $0x0e, %ah # Output CR + movb $0x0d, %al + int $0x10 + movb $0x0a, %al # Output LF + int $0x10 + ret + +cons_writeline: + call cons_write + call cons_write_crlf + ret + +HexChars: .ascii "0123456789ABCDEF" + +cons_write_hex: + movw $4, %cx + movb $0x0E, %ah + +hexloop: + rol $4, %bx + movw %bx, %si + and $0x000F, %si + movb HexChars(%si), %al + int $0x10 + loop hexloop + ret + +cons_write_int: + movw $IntBuffer + 4, %si + movw %bx, %ax + + cmpw $0, %ax + jge getdigit + + xor %ax, %ax + movb $0x0E, %ah + movb $0x2D, %al + int $0x10 + + movw %bx, %ax + negw %ax + +getdigit: + xor %dx, %dx + movw $10, %cx + idiv %cx + addb $48, %dl + movb %dl, (%si) + dec %si + cmp $0, %ax + jne getdigit + inc %si + call cons_write + ret + +IntBuffer: .string " " + +cons_draw_line: + movw $0, err + movw x1, %cx + movw y1, %dx + sub x0, %cx + sub y0, %dx + movw %cx, (deltax) + movw %dx, (deltay) + +cons_line_check_x: + movw x0, %cx + movw $1, (sx) + cmp x1, %cx + jl cons_line_check_y + negw sx + negw deltax + +cons_line_check_y: + movw y0, %dx + movw $1, (sy) + cmpw y1, %dx + jl cons_line_prep_loop + negw sy + negw deltay + +cons_line_prep_loop: + movw deltax, %ax + sub deltay, %ax + movw %ax, (err) + +cons_line_loop_start: + xor %ax, %ax + xor %bx, %bx + movb $0x0c, %ah + movb $0, %bh + movb (color), %al + int $0x10 + + cmpw x1, %cx + jne cons_line_loop_next_point + cmpw y1, %dx + jne cons_line_loop_next_point + jmp cons_line_loop_end + +cons_line_loop_next_point: + movw err, %ax + add %ax, %ax + +cons_line_loop_move_y_point: + movw deltay, %bx + negw %bx + cmpw %bx, %ax + jle cons_line_loop_move_x_point + negw %bx + subw %bx, err + addw sx, %cx + +cons_line_loop_move_x_point: + movw deltax, %bx + cmpw %bx, %ax + jge cons_line_loop_start + addw %bx, err + addw sy, %dx + jmp cons_line_loop_start + +cons_line_loop_end: + ret + +real_start: + movw $boot_message, %si # Display our boot message + call cons_writeline + +draw_start: + # Set the Video mode to VGA 320 x 200 x 8 + movb $0, %ah + movb $0x13, %al + int $0x10 + xor %ax, %ax + + movw $50, x0 + movw $50, y0 + movw $160, x1 + movw $55, y1 + movb $12, color + call cons_draw_line + + movw $150, x0 + movw $150, y0 + movw $50, x1 + movw $50, y1 + movb $10, color + call cons_draw_line + + movw $150, x0 + movw $150, y0 + movw $160, x1 + movw $55, y1 + movb $11, color + call cons_draw_line + + movw $10, x0 + movw $10, y0 + movw $310, x1 + movw $190, y1 + movb $9, color + call cons_draw_line + + movw $310, x0 + movw $190, y0 + movw $10, x1 + movw $95, y1 + movb $8, color + call cons_draw_line + + movw $10, x0 + movw $95, y0 + movw $10, x1 + movw $10, y1 + movb $7, color + call cons_draw_line + +endless_loop: # Loop forever more + jmp endless_loop + +# Program data +boot_message: + .string "Boot Loader Stage 2 loaded" + +x0: .int 0 +y0: .int 0 +x1: .int 0 +y1: .int 0 +deltax: .int 0 +deltay: .int 0 +sx: .int 0 +sy: .int 0 +err: .int 0 +e2: .int 0 +color: .byte 0 \ No newline at end of file diff --git a/stage1/bootasm2.d b/stage1/bootasm2.d new file mode 100644 index 0000000..74df401 --- /dev/null +++ b/stage1/bootasm2.d @@ -0,0 +1 @@ +bootasm2.o: bootasm2.S diff --git a/stage1/bootasm2.o b/stage1/bootasm2.o new file mode 100644 index 0000000..7c0db55 Binary files /dev/null and b/stage1/bootasm2.o differ diff --git a/stage1/bootblock b/stage1/bootblock new file mode 100644 index 0000000..95937cb Binary files /dev/null and b/stage1/bootblock differ diff --git a/stage1/bootblock.o b/stage1/bootblock.o new file mode 100644 index 0000000..8b514c9 Binary files /dev/null and b/stage1/bootblock.o differ diff --git a/stage1/bootblock2 b/stage1/bootblock2 new file mode 100644 index 0000000..dcb7aed Binary files /dev/null and b/stage1/bootblock2 differ diff --git a/stage1/bootblock2.o b/stage1/bootblock2.o new file mode 100644 index 0000000..72cf732 Binary files /dev/null and b/stage1/bootblock2.o differ diff --git a/stage1/sign.pl b/stage1/sign.pl new file mode 100644 index 0000000..d793035 --- /dev/null +++ b/stage1/sign.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl + +open(SIG, $ARGV[0]) || die "open $ARGV[0]: $!"; + +$n = sysread(SIG, $buf, 1000); + +if($n > 510){ + print STDERR "boot block too large: $n bytes (max 510)\n"; + exit 1; +} + +print STDERR "boot block is $n bytes (max 510)\n"; + +$buf .= "\0" x (510-$n); +$buf .= "\x55\xAA"; + +open(SIG, ">$ARGV[0]") || die "open >$ARGV[0]: $!"; +print SIG $buf; +close SIG; diff --git a/stage1/xv6.img b/stage1/xv6.img new file mode 100644 index 0000000..df182a2 Binary files /dev/null and b/stage1/xv6.img differ