Приветствую, %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 Автор
А здесь еще и нет хипа, по большому счету, так, выделение памяти и только. Но будет, скоро