Go + asmでのOS開発に関するシリーズの2番目の記事を次に示します。
パート0x00
パート0x01
当初、2番目の記事は割り込みの処理に関するものになることを計画していましたが、Goは独自の修正を課します-メモリの単純な割り当てとGoランタイムの一部について説明します。 実際、これは3番目の記事-ヒープおよび終了ランタイムの準備です。
githubにはこの記事のコードはありません(時間内にコミットするのを忘れていましたが、特別に復元するのが面倒なので、誰もがプルリクエストを送信した場合は感謝します)。
気弱な人のために、記事を閉じてください-Goで書けることはすべて書かれています!
multiboot.sには、コンパイラ用のスタブ関数があったことを覚えていますか? これらをruntime.sファイルに転送します(作成します)。
ステップ0x00
まず、メモリを割り当てる方法を学びましょう-memory.goファイルを作成します:
package memory //extern end var end uint32 // link.ld var placement_address uint32 // //extern __unsafe_get_addr func pointer2uint32(pointer *uint32) uint32 // , , func Init() { placement_address = pointer2uint32(&end) // } func kmalloc(size uint32, align int, phys *uint32) uint32 { // if align == 1 && (placement_address&0xFFFFF000) != uint32(0) { // - . placement_address &= 0xFFFFF000 placement_address += 0x1000 } if phys != nil { // - *phys = placement_address } res := placement_address // placement_address += size // return res } func Kmalloc(size uint32) uint32 { // return kmalloc(size, 0, nil) }
ステップ0x01
ランタイムに取りかかりましょう。 runtime.goファイルを作成します
package runtime import ( "memory" ) //extern __unsafe_get_addr func pointer2byteSlice(ptr uint32) *[]byte //extern __unsafe_get_addr func pointer2uint32(ptr interface{}) uint32 func memset(buf_ptr uint32, value byte, count uint32) { // memset var buf *[]byte buf = pointer2byteSlice(buf_ptr) for i := uint32(0); i < count; i++ { (*buf)[i] = value } } func memcpy(dst, src uint32, size uint32) { // memcpy var dest, source *[]byte dest = pointer2byteSlice(dst) source = pointer2byteSlice(src) for i := uint32(0); i < size; i++ { (*dest)[i] = (*source)[i] } } func New(typeDescriptor uint32, size uint32) uint32 { // new() // typeDescriptor buf_ptr := memory.Kmalloc(size) // memset(buf_ptr, 0, size) // return buf_ptr // }
前の記事のコメントを読んだ読者は、「どのようにnew()はgo.runtime.Newではなく__go_newですか?」という質問をします。
答えはruntime.sファイルにあります(multiboot.sから関数を転送するように要求したことを思い出してください)
;gccgo compability global __go_runtime_error global __go_register_gc_roots __go_register_gc_roots: __go_runtime_error: ret global __unsafe_get_addr ;convert uint32 to pointer __unsafe_get_addr: push ebp mov ebp, esp mov eax, [ebp+8] mov esp, ebp pop ebp ret extern go.runtime.New global __go_new global __go_new_nopointers __go_new: ; go.runtime.New __go_new __go_new_nopointers: call go.runtime.New ret
kernel.goファイルを次の形式にします。
package kernel import ( "memory" "screen" ) func Load() { memory.Init() screen.Init() screen.Clear() str := new(string) *str = "Habrahabr" screen.PrintStr(*str) }
コンパイルと起動後、「Habrahabr」という碑文が表示されます。
警告:実際には、スライス、ライン、および他のタイプの変数に長いベクトルを作成する価値はありません。そうしないと重複する可能性があります。
_____________________________________
osdev.ruに関する議論:
http://osdev.ru/viewtopic.php?f=4&t=1100
スラックでチャット(golang-ruで):
https://golang-ru.slack.com/messages/daria/