diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9368ff6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.vscode +.idea +*.o +*.swp +*.objdump +*~ +tags +hello diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e9ca35e --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +ENDIAN := EL + +QEMU := qemu-system-mipsel +CROSS_COMPILE := mips-linux-gnu- +CC := $(CROSS_COMPILE)gcc +CFLAGS += --std=gnu99 -$(ENDIAN) -G 0 -mno-abicalls -fno-pic \ + -ffreestanding -fno-stack-protector -fno-builtin \ + -Wa,-xgot -Wall -mxgot -mno-fix-r4000 -march=4kc -g -ggdb +LD := $(CROSS_COMPILE)ld +LDFLAGS += -EL -G 0 -static -n -nostdlib --fatal-warnings +INCLUDES := -I./include/ +target := hello +objects := hello.o output.o start.o +qemu_files += hello +qemu_flags += -cpu 4Kc -m 64 -nographic -M malta -no-reboot + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +%.o: %.S + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +.PHONY: all clean dbg + +all: hello + +hello: linker.lds $(objects) + $(LD) $(LDFLAGS) -o hello -N -T linker.lds $(objects) + +clean: + rm -rf *~ *.o hello *.objdump + +dbg_run: qemu_flags += -s -S +dbg_run: run + +dbg: + make dbg_run >/dev/null 2>&1 & + gdb-multiarch $(target) -ex "target remote localhost:1234" + killall $(QEMU) + +run: + $(QEMU) $(qemu_flags) -kernel $(qemu_files) + +objdump: + $(CROSS_COMPILE)objdump $(target) -aldS > hello.objdump diff --git a/hello.c b/hello.c new file mode 100644 index 0000000..eb0ae9c --- /dev/null +++ b/hello.c @@ -0,0 +1,18 @@ +#include "output.h" +#include + +void hello(int a, int b, int c, int d, int e, int f) { + print_num(a); + print_str("\n"); + print_num(b); + print_str("\n"); + print_num(c); + print_str("\n"); + print_num(d); + print_str("\n"); + print_num(e); + print_str("\n"); + print_num(f); + print_str("\n"); + halt(); +} diff --git a/include/asm/asm.h b/include/asm/asm.h new file mode 100644 index 0000000..e6a4e17 --- /dev/null +++ b/include/asm/asm.h @@ -0,0 +1,40 @@ +#include +#include + +/* + * LEAF - declare leaf routine + */ +#define LEAF(symbol) \ + .globl symbol; \ + .align 2; \ + .type symbol, @function; \ + .ent symbol; \ + symbol: \ + .frame sp, 0, ra + +/* + * NESTED - declare nested routine entry point + */ +#define NESTED(symbol, framesize, rpc) \ + .globl symbol; \ + .align 2; \ + .type symbol, @function; \ + .ent symbol; \ + symbol: \ + .frame sp, framesize, rpc + +/* + * END - mark end of function + */ +#define END(function) \ + .end function; \ + .size function, .- function + +#define EXPORT(symbol) \ + .globl symbol; \ + symbol: + +#define FEXPORT(symbol) \ + .globl symbol; \ + .type symbol, @function; \ + symbol: diff --git a/include/asm/cp0regdef.h b/include/asm/cp0regdef.h new file mode 100644 index 0000000..53a76a3 --- /dev/null +++ b/include/asm/cp0regdef.h @@ -0,0 +1,39 @@ +#ifndef _cp0regdef_h_ +#define _cp0regdef_h_ + +#define CP0_INDEX $0 +#define CP0_RANDOM $1 +#define CP0_ENTRYLO0 $2 +#define CP0_ENTRYLO1 $3 +#define CP0_CONTEXT $4 +#define CP0_PAGEMASK $5 +#define CP0_WIRED $6 +#define CP0_BADVADDR $8 +#define CP0_COUNT $9 +#define CP0_ENTRYHI $10 +#define CP0_COMPARE $11 +#define CP0_STATUS $12 +#define CP0_CAUSE $13 +#define CP0_EPC $14 +#define CP0_PRID $15 +#define CP0_CONFIG $16 +#define CP0_LLADDR $17 +#define CP0_WATCHLO $18 +#define CP0_WATCHHI $19 +#define CP0_XCONTEXT $20 +#define CP0_FRAMEMASK $21 +#define CP0_DIAGNOSTIC $22 +#define CP0_PERFORMANCE $25 +#define CP0_ECC $26 +#define CP0_CACHEERR $27 +#define CP0_TAGLO $28 +#define CP0_TAGHI $29 +#define CP0_ERROREPC $30 + +#define STATUS_CU0 0x10000000 +#define STATUS_IM4 0x1000 +#define STATUS_KUp 0x8 +#define STATUS_IEp 0x4 +#define STATUS_KUc 0x2 +#define STATUS_IEc 0x1 +#endif diff --git a/include/asm/readme.md b/include/asm/readme.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include/asm/readme.md @@ -0,0 +1 @@ + diff --git a/include/asm/regdef.h b/include/asm/regdef.h new file mode 100644 index 0000000..9188ffa --- /dev/null +++ b/include/asm/regdef.h @@ -0,0 +1,42 @@ +#ifndef __ASM_MIPS_REGDEF_H +#define __ASM_MIPS_REGDEF_H + +/* + * Symbolic register names for 32 bit ABI + */ +#define zero $0 /* wired zero */ +#define AT $1 /* assembler temp - uppercase because of ".set at" */ +#define v0 $2 /* return value */ +#define v1 $3 +#define a0 $4 /* argument registers */ +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 /* caller saved */ +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 /* callee saved */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* caller saved */ +#define t9 $25 +#define jp $25 /* PIC jump register */ +#define k0 $26 /* kernel scratch */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define fp $30 /* frame pointer */ +#define s8 $30 /* same like fp! */ +#define ra $31 /* return address */ + +#endif /* __ASM_MIPS_REGDEF_H */ diff --git a/include/machine.h b/include/machine.h new file mode 100644 index 0000000..f197cf9 --- /dev/null +++ b/include/machine.h @@ -0,0 +1,56 @@ +#ifndef _MACHINE_H +#define _MACHINE_H + +// Memory segments (32-bit kernel mode addresses) +#define KUSEG 0x00000000U +#define KSEG0 0x80000000U +#define KSEG1 0xA0000000U +#define KSEG2 0xC0000000U + +/* + * QEMU MMIO address definitions. + */ +#define MALTA_PCIIO_BASE 0x18000000 +#define MALTA_FPGA_BASE 0x1f000000 + +/* + * 16550 Serial UART device definitions. + */ +#define MALTA_SERIAL_BASE (MALTA_PCIIO_BASE + 0x3f8) +#define MALTA_SERIAL_DATA (MALTA_SERIAL_BASE + 0x0) +#define MALTA_SERIAL_LSR (MALTA_SERIAL_BASE + 0x5) +#define MALTA_SERIAL_DATA_READY 0x1 +#define MALTA_SERIAL_THR_EMPTY 0x20 + +/* + * Intel PIIX4 IDE Controller device definitions. + * Hardware documentation available at + * https://www.intel.com/Assets/PDF/datasheet/290562.pdf + */ +#define MALTA_IDE_BASE (MALTA_PCIIO_BASE + 0x01f0) +#define MALTA_IDE_DATA (MALTA_IDE_BASE + 0x00) +#define MALTA_IDE_ERR (MALTA_IDE_BASE + 0x01) +#define MALTA_IDE_NSECT (MALTA_IDE_BASE + 0x02) +#define MALTA_IDE_LBAL (MALTA_IDE_BASE + 0x03) +#define MALTA_IDE_LBAM (MALTA_IDE_BASE + 0x04) +#define MALTA_IDE_LBAH (MALTA_IDE_BASE + 0x05) +#define MALTA_IDE_DEVICE (MALTA_IDE_BASE + 0x06) +#define MALTA_IDE_STATUS (MALTA_IDE_BASE + 0x07) +#define MALTA_IDE_LBA 0xE0 +#define MALTA_IDE_BUSY 0x80 +#define MALTA_IDE_CMD_PIO_READ 0x20 /* Read sectors with retry */ +#define MALTA_IDE_CMD_PIO_WRITE 0x30 /* write sectors with retry */ + +/* + * MALTA Power Management device definitions. + */ +#define MALTA_FPGA_HALT (MALTA_FPGA_BASE + 0x500) + + +/* IO function */ +void m_putch(char ch); +char m_getch(void); +/* when call this func, gxemul will quit */ +void m_halt(void); + +#endif diff --git a/include/output.h b/include/output.h new file mode 100644 index 0000000..bfedb6c --- /dev/null +++ b/include/output.h @@ -0,0 +1,9 @@ +#ifndef _OUTPUT_H_ +#define _OUTPUT_H_ + +void print_str(const char *buf); +void printcharc(char ch); +void print_num(unsigned long u); +void halt(void); + +#endif diff --git a/linker.lds b/linker.lds new file mode 100644 index 0000000..d9239a1 --- /dev/null +++ b/linker.lds @@ -0,0 +1,29 @@ +/* + * Set the architecture to mips. + */ +OUTPUT_ARCH(mips) + +/* + * Set the ENTRY point of the program to _start_mips. + */ +ENTRY(_start_mips) + +SECTIONS { + + . = 0x80020000; + + .text : { + *(.text) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0x80400000; + end = . ; +} diff --git a/output.c b/output.c new file mode 100644 index 0000000..aac1fb4 --- /dev/null +++ b/output.c @@ -0,0 +1,32 @@ +#include +#include +#include + +void printcharc(char ch) { + while (!(*((volatile char *)(KSEG1 + MALTA_SERIAL_LSR)) & MALTA_SERIAL_THR_EMPTY)) { + } + *((volatile char *)(KSEG1 + MALTA_SERIAL_DATA)) = ch; +} + +void halt(void) { + *(volatile char *)(KSEG1 + MALTA_FPGA_HALT) = 0x42; +} + +void print_str(const char *buf) { + for (int i = 0; buf[i]; i++) { + printcharc(buf[i]); + } +} + +void print_num(unsigned long u) { + if (u < 0) { + printcharc('-'); + u = -u; + } + char digit = '0' + u % 10; + u /= 10; + if (u != 0) { + print_num(u); + } + printcharc(digit); +} diff --git a/start.S b/start.S new file mode 100644 index 0000000..ba4ffcb --- /dev/null +++ b/start.S @@ -0,0 +1,50 @@ +#include +.data +str: +.asciiz "Hello World\n" # Null-terminated string "Hello World" stored at label 'str' +.align 2 # align to 4-byte boundary (2^2) +var: +.byte 3 # correctly aligned byte: 3 +/* '' in the comments is the part to be replaced. */ +/* use '.align ' to align the following words to 1-byte boundary (disabling word-alignment) */ +/* so that the byte 3 and word 7 is "connected" */ +/* Your code here. (1/6) */ +.align 0 +.word 7, 8, 9 + +.text +/* We define '_start_mips' here as the entry of our program. */ +EXPORT(_start_mips) +.set at +.set reorder + mtc0 zero, CP0_STATUS + li sp, 0x84000000 + /* Load the address of the string 'str' into the first parameter register. */ + la a0, str + /* use 'addiu sp, sp, ' to push a proper-sized frame onto the stack for Nonleaf function 'print_str'. */ + /* Your code here. (2/6) */ + addiu sp, sp,-4 + jal print_str + /* use 'addiu sp, sp, ' to restore stack pointer. */ + /* Your code here. (3/6) */ + addiu sp, sp,4 + /* Set the first four parameters. */ + li a0, 0 + li a1, 1 + li a2, 2 + li a3, 3 + /* use 'addiu sp, sp, ' to push a proper-sized frame onto the stack for Nonleaf function 'hello'. */ + /* Your code here. (4/6) */ + addiu sp, sp, -24 + lw t1, var + li t2, 5 + /* use 'sw t1, (sp)' to store t1 at the proper place of the stack */ + /* so that t1 is 5th argument of function hello. */ + /* Your code here. (5/6) */ + sw t1, 16(sp) + /* use 'sw t2, (sp)' to store t2 at the proper place of the stack */ + /* so that t2 is 6th argument of function hello. */ + /* Your code here. (6/6) */ + sw t2, 20(sp) + /* use 'j' to call the function 'hello', we use 'j' instead of 'jal' because 'hello' is 'noreturn' */ + j hello