Go + asmパート0x00でのOS開発

おはようございます%ユーザー名%。

異常なものをおしっこしたかった。 その選択はOSにかかったので、最終的には、たとえプログラマーが1人だけであっても、各プログラマーは独自のOSを作成する必要があります。

一部の人々が知っているように、私はGoが大好きで、それについて書くことを決めました。 それから来たもの-habrakatの下で。

パート0x00
パート0x01


ステップ0x00


私はブートローダーを書きません。頭のいい人が仕様のマルチブートを思いついたからではありません。

最初に、ブートコード(multiboot.sファイル)を記述します
MBOOT_PAGE_ALIGN equ 1<<0 MBOOT_MEM_INFO equ 1<<1 MBOOT_HEADER_MAGIC equ 0x1BADB002 MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS) [BITS 32] [GLOBAL mboot] [EXTERN code] [EXTERN bss] [EXTERN end] mboot: dd MBOOT_HEADER_MAGIC dd MBOOT_HEADER_FLAGS dd MBOOT_CHECKSUM dd mboot dd code dd bss dd end dd start [GLOBAL start] extern go.kernel.Load ;  ,        Go start: push ebx cli call go.kernel.Load ;  ,      jmp $ 


次に、次の内容のkernel.goファイルを作成します。
 package kernel func Load(){ //        } 


link.ldファイルを作成します
 ENTRY(start) SECTIONS { .text 0x100000 : { code = .; _code = .; __code = .; *(.text) . = ALIGN(4096); } .data : { data = .; _data = .; __data = .; *(.data) *(.rodata) . = ALIGN(4096); } .bss : { bss = .; _bss = .; __bss = .; *(.bss) . = ALIGN(4096); } end = .; _end = .; __end = .; } 


メイクファイル
 SOURCES=multiboot.o kernel.go.o GOFLAGS= -nostdlib -nostdinc -fno-stack-protector -fno-split-stack -static -m32 -g -I. GO=gccgo ASFLAGS= -felf NASM= nasm $(ASFLAGS) OBJCOPY=objcopy LDFLAGS=-T link.ld -m elf_i386 all: $(SOURCES) link clean: rm *.o kernel link: ld $(LDFLAGS) -o kernel $(SOURCES) %.go.o: %.go $(GO) $(GOFLAGS) -o $@ -c $< %.o: %.s $(NASM) $< 


ここで、プロジェクトディレクトリにmakeを作成すると、qemuを使用してダウンロードできるカーネルファイルが取得されます。

qemu-system-i386 -kernel ./kernel

カーネルは正常に起動し、何もしません)

ステップ0x01



世界に挨拶する時が来ました。

まず、multiboot.sに次の行を追加します。
 global __go_runtime_error global __go_register_gc_roots global __unsafe_get_addr __unsafe_get_addr: push ebp mov ebp, esp mov eax, [ebp+8] mov esp, ebp pop ebp ret __go_register_gc_roots: __go_runtime_error: ret 


__unsafe_get_addr関数は、uint32をGo内のポインターに変換できるようにするために必要です。

他の2つの関数は、コンパイラーの単なるギャグです

次に、screen.goファイルを作成します
 package screen var ( frameBuffer *[totalMax]uint16 // 8  - ,  -   cursorX, cursorY uint8 ) const ( frameBufferAddr = 0xB8000 maxX = 80 maxY = 25 totalMax = maxX * maxY whiteOnBlack = 0x07 ) //     Go    __unsafe_get_addr //extern __unsafe_get_addr func getAddr(addr uint32) *[totalMax]uint16 func Init() { cursorX = 0 cursorY = 0 frameBuffer = getAddr(frameBufferAddr) //    } // ,      func Clear() { for i := 0; i < totalMax; i++ { frameBuffer[i] = 0 } cursorX = 0 cursorY = 0 } //   func SetCursor(x, y uint8) { cursorX = x cursorY = y } //     func scroll() { if cursorY >= maxY { for i := 0; i < 24*maxX; i++ { frameBuffer[i] = frameBuffer[i+80] //      } for i := 24 * 80; i < totalMax; i++ { //   frameBuffer[i] = 0x20 | (((0 << 4) | (15 & 0x0F)) << 8) frameBuffer[i] = 0 } cursorY = 24 cursorX = 0 } } //  func putChar(c byte) { switch c { case 0x08: //backspace if cursorX > 0 { cursorX-- } case 0x09: //tab cursorX = (cursorX + 8) & (8 - 1) case '\r': //return cursorX = 0 case '\n': //new line cursorX = 0 cursorY++ default: if c >= 0x20 { //   frameBuffer[cursorY*80+cursorX] = uint16(c) | (((0 << 4) | (15 & 0x0F)) << 8) cursorX++ } } if cursorX >= 80 { //    cursorX = 0 cursorY++ } scroll() } //  func PrintStr(s string) { for i := 0; i < len(s); i++ { putChar(s[i]) } } 


次に、スクリーンモジュールをカーネルに接続する必要があります。同じ場所で、「スクリーン」インポートをkernel.goに追加し、Load()関数に記述します。
  screen.Init() screen.Clear() screen.PrintStr("Hello Habrahar!") 


ここで、コンパイラーにこの全体をアセンブルする方法を指示する必要があります; Makefileに次の行を追加する必要があります。
 %.gox: %.go.o $(OBJCOPY) -j .go_export $< $@ 

同じ場所で、multiboot.oとkernel.go.oの間のSOURCES変数にscreen.go.oとscreen.goxを追加します

すべての操作の後、makeコマンドを呼び出し、カーネルでqemuを実行します。 ダウンロードを待って楽しんでいます

PS誤植がある場合はご容赦ください。 私はそれを修正することを約束します。
PPS最近のコードはgithubに投稿されます
github.com/t0pep0/Daria/tree/Part0x00

_____________________________________

osdev.ruに関する議論:
http://osdev.ru/viewtopic.php?f=4&t=1100
スラックでチャット(golang-ruで):
https://golang-ru.slack.com/messages/daria/

Source: https://habr.com/ru/post/J259719/


All Articles