Приветствую, %username%.
Перед вами вторая статья из цикла о разработке ОС на Go + asm.
Part 0x00
Part 0x01
Изначально я планировал, что вторая статья будет про обработку прерываний, но Go накладывает свои корректировки — сейчас будет описано простое выделение памяти и часть рантайма Go, которая нам пригодится, но будет переписано. На самом деле это подготовка к третьей статье — куче и допиливанию рантайма.
Кода к этой статье на гитхабе не будет (забыл вовремя сделать коммит, а теперь банально лень специально восстанавливать, если кто пришлет пулл реквест — буду благодарен).
Слабонервным просьба закрыть статью — все, что может быть написанно на Go будет написанно на нем!
Помните в multiboot.s были функции заглушки для компилятора? Перенесите их в файл runtime.s (создайте его).
Для начала давайте научимся выделять память — создадим файл memory.go:
Приступим к рантайму. Создаем файл runtime.go
Читатель, изучивший комментарии к предыдущей статье, задаст вопрос: «Как же так, new() это __go_new, а не go.runtime.New?»
Ответ в файле runtime.s (помните я просил перенести функции из multiboot.s в него?):
Теперь приведем файл kernel.go к следующему виду:
После компиляции и запуска мы увидим надпись «Habrahabr».
ПРЕДУПРЕЖДЕНИЕ: На самом деле пока не стоит создавать вектора на слайсы, строки и другие типы переменной длинны, иначе возможно наложение.
_____________________________________
Обсуждение на osdev.ru:
http://osdev.ru/viewtopic.php?f=4&t=1100
Чат в слаке (в golang-ru):
https://golang-ru.slack.com/messages/daria/
Перед вами вторая статья из цикла о разработке ОС на Go + asm.
Part 0x00
Part 0x01
Изначально я планировал, что вторая статья будет про обработку прерываний, но Go накладывает свои корректировки — сейчас будет описано простое выделение памяти и часть рантайма Go, которая нам пригодится, но будет переписано. На самом деле это подготовка к третьей статье — куче и допиливанию рантайма.
Кода к этой статье на гитхабе не будет (забыл вовремя сделать коммит, а теперь банально лень специально восстанавливать, если кто пришлет пулл реквест — буду благодарен).
Слабонервным просьба закрыть статью — все, что может быть написанно на Go будет написанно на нем!
Помните в multiboot.s были функции заглушки для компилятора? Перенесите их в файл runtime.s (создайте его).
Step 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)
}
Step 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_new, а не go.runtime.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/
t0pep0 Автор
Не буду дописывать в статью, но принимаются Ваши версии memset, memcmp и memcpu, как указанно в статье — мои слишком примитивны
t0pep0 Автор
memcpy*
StrangerInRed
В стандартных реализация они всего лишь буферезированы по size_t. Вот вам memset только на С.
typedef uint8_t byte; #define forAll(iterator, count) for(iterator = 0; iterator < (count); ++iterator) byte* flushAllToByte(pointer array, size_t size, byte symbol) { size_t iterator; forAll(iterator, size / sizeof(size_t)) { ((size_t*) array)[iterator] = symbol; } for(iterator *= sizeof(size_t); iterator < size; ++iterator){ ((byte*) array)[iterator] = symbol; } return array; }
К сожалению форматирование кода недоступно при отрицательной карме.
t0pep0 Автор
Спасибо, несколько позже изучу
Вроде правильно отформатировал
Gorthauer87
А что мешает утащить какую-нибудь реализацию хипа для bare metal? Из newlib, например.
StrangerInRed
Я бы еще рекомендовал исходники Apple.
www.opensource.apple.com/source/ntp/ntp-13/ntp/libntp/memmove.c
www.opensource.apple.com/source/xnu/xnu-2050.18.24/libsyscall/wrappers/memcpy.c
www.opensource.apple.com/source/Libc/Libc-167/string.subproj/memset.c
t0pep0 Автор
А здесь еще и нет хипа, по большому счету, так, выделение памяти и только. Но будет, скоро