├── .gitignore ├── Makefile ├── kernel.go ├── link.ld ├── multiboot.s └── screen.go /.gitignore: -------------------------------------------------------------------------------- 1 | kernel 2 | *.o 3 | *.gox 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCES=multiboot.o screen.go.o screen.gox kernel.go.o 2 | 3 | GOFLAGS= -nostdlib -nostdinc -fno-stack-protector -fno-split-stack -static -m32 -g -I. 4 | GO=gccgo 5 | ASFLAGS= -felf 6 | NASM= nasm $(ASFLAGS) 7 | OBJCOPY=objcopy 8 | 9 | LDFLAGS=-T link.ld -m elf_i386 10 | 11 | 12 | all: $(SOURCES) link 13 | 14 | clean: 15 | rm *.o *.gox kernel 16 | 17 | link: 18 | ld $(LDFLAGS) -o kernel $(SOURCES) 19 | 20 | qemu: 21 | qemu-system-i386 -kernel ./kernel 22 | 23 | %.gox: %.go.o 24 | $(OBJCOPY) -j .go_export $< $@ 25 | 26 | %.go.o: %.go 27 | $(GO) $(GOFLAGS) -o $@ -c $< 28 | 29 | %.o: %.s 30 | $(NASM) $< 31 | -------------------------------------------------------------------------------- /kernel.go: -------------------------------------------------------------------------------- 1 | package kernel 2 | 3 | import ( 4 | "screen" 5 | ) 6 | 7 | func Load() { 8 | screen.Init() 9 | screen.Clear() 10 | screen.PrintStr("Hello world!") 11 | } 12 | -------------------------------------------------------------------------------- /link.ld: -------------------------------------------------------------------------------- 1 | /* Link.ld -- Linker script for the kernel - ensure everything goes in the */ 2 | /* Correct place. */ 3 | /* Original file taken from Bran's Kernel Development */ 4 | /* tutorials: http://www.osdever.net/bkerndev/index.php. */ 5 | 6 | ENTRY(start) 7 | SECTIONS 8 | { 9 | 10 | .text 0x100000 : 11 | { 12 | code = .; _code = .; __code = .; 13 | *(.text) 14 | . = ALIGN(4096); 15 | } 16 | 17 | .data : 18 | { 19 | data = .; _data = .; __data = .; 20 | *(.data) 21 | *(.rodata) 22 | . = ALIGN(4096); 23 | } 24 | 25 | .bss : 26 | { 27 | bss = .; _bss = .; __bss = .; 28 | *(.bss) 29 | . = ALIGN(4096); 30 | } 31 | 32 | end = .; _end = .; __end = .; 33 | } 34 | -------------------------------------------------------------------------------- /multiboot.s: -------------------------------------------------------------------------------- 1 | MBOOT_PAGE_ALIGN equ 1<<0 2 | MBOOT_MEM_INFO equ 1<<1 3 | MBOOT_HEADER_MAGIC equ 0x1BADB002 4 | MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO 5 | MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS) 6 | 7 | [BITS 32] 8 | 9 | [GLOBAL mboot] 10 | [EXTERN code] 11 | [EXTERN bss] 12 | [EXTERN end] 13 | 14 | mboot: 15 | dd MBOOT_HEADER_MAGIC 16 | dd MBOOT_HEADER_FLAGS 17 | dd MBOOT_CHECKSUM 18 | dd mboot 19 | dd code 20 | dd bss 21 | dd end 22 | dd start 23 | 24 | [GLOBAL start] 25 | extern go.kernel.Load 26 | 27 | global __go_runtime_error ;gccgo compability 28 | global __go_register_gc_roots ;gccgo compability 29 | global __unsafe_get_addr ;convert uint32 to pointer 30 | 31 | __unsafe_get_addr: 32 | push ebp 33 | mov ebp, esp 34 | mov eax, [ebp+8] 35 | mov esp, ebp 36 | pop ebp 37 | ret 38 | 39 | start: 40 | push ebx 41 | cli 42 | call go.kernel.Load 43 | jmp $ 44 | 45 | __go_register_gc_roots: 46 | __go_runtime_error: 47 | ret 48 | -------------------------------------------------------------------------------- /screen.go: -------------------------------------------------------------------------------- 1 | package screen 2 | 3 | var ( 4 | frameBuffer *[totalMax]uint16 5 | cursorX, cursorY uint8 6 | ) 7 | 8 | const ( 9 | frameBufferAddr = 0xB8000 10 | maxX = 80 11 | maxY = 25 12 | totalMax = maxX * maxY 13 | whiteOnBlack = 0x07 14 | ) 15 | 16 | //extern __unsafe_get_addr 17 | func getAddr(addr uint32) *[totalMax]uint16 18 | 19 | func Init() { 20 | cursorX = 0 21 | cursorY = 0 22 | //Get video memory 23 | frameBuffer = getAddr(frameBufferAddr) 24 | } 25 | 26 | //Clear screen 27 | func Clear() { 28 | for i := 0; i < totalMax; i++ { 29 | frameBuffer[i] = 0 30 | } 31 | cursorX = 0 32 | cursorY = 0 33 | } 34 | 35 | func SetCursor(x, y uint8) { 36 | cursorX = x 37 | cursorY = y 38 | } 39 | 40 | func scroll() { 41 | if cursorY >= maxY { 42 | for i := 0; i < 24*maxX; i++ { 43 | frameBuffer[i] = frameBuffer[i+80] 44 | } 45 | for i := 24 * 80; i < totalMax; i++ { 46 | frameBuffer[i] = 0x20 | (((0 << 4) | (15 & 0x0F)) << 8) 47 | frameBuffer[i] = 0 48 | } 49 | cursorY = 24 50 | cursorX = 0 51 | } 52 | } 53 | 54 | func putChar(c byte) { 55 | switch c { 56 | case 0x08: 57 | if cursorX > 0 { 58 | cursorX-- 59 | } 60 | case 0x09: 61 | cursorX = (cursorX + 8) & (8 - 1) 62 | case '\r': 63 | cursorX = 0 64 | case '\n': 65 | cursorX = 0 66 | cursorY++ 67 | default: 68 | if c >= 0x20 { 69 | frameBuffer[cursorY*80+cursorX] = uint16(c) | (((0 << 4) | (15 & 0x0F)) << 8) 70 | cursorX++ 71 | } 72 | } 73 | if cursorX >= 80 { 74 | cursorX = 0 75 | cursorY++ 76 | } 77 | scroll() 78 | } 79 | 80 | func PrintStr(s string) { 81 | for i := 0; i < len(s); i++ { 82 | putChar(s[i]) 83 | } 84 | } 85 | --------------------------------------------------------------------------------