mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Merge pull request #13 from achilleasa/boot-allocator-tweaks
Boot allocator tweaks
This commit is contained in:
commit
ff8aabe51f
2
Makefile
2
Makefile
@ -52,7 +52,7 @@ go.o:
|
|||||||
@# with slashes we create a global symbol alias for kernel.Kmain
|
@# with slashes we create a global symbol alias for kernel.Kmain
|
||||||
@echo "[objcopy] creating global symbol alias 'kernel.Kmain' for 'github.com/achilleasa/gopher-os/kernel.Kmain' in go.o"
|
@echo "[objcopy] creating global symbol alias 'kernel.Kmain' for 'github.com/achilleasa/gopher-os/kernel.Kmain' in go.o"
|
||||||
@objcopy \
|
@objcopy \
|
||||||
--add-symbol kernel.Kmain=.text:0x`nm $(BUILD_DIR)/go.o | grep "kernel.Kmain$$" | cut -d' ' -f1` \
|
--add-symbol kernel.Kmain=.text:0x`nm $(BUILD_DIR)/go.o | grep "kmain.Kmain$$" | cut -d' ' -f1` \
|
||||||
$(BUILD_DIR)/go.o $(BUILD_DIR)/go.o
|
$(BUILD_DIR)/go.o $(BUILD_DIR)/go.o
|
||||||
|
|
||||||
binutils_version_check:
|
binutils_version_check:
|
||||||
|
18
kernel/error.go
Normal file
18
kernel/error.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package kernel
|
||||||
|
|
||||||
|
// Error describes a kernel kerror. All kernel errors must be defined as global
|
||||||
|
// variables that are pointers to the Error structure. This requirement stems
|
||||||
|
// from the fact that the Go allocator is not available to us so we cannot use
|
||||||
|
// errors.New.
|
||||||
|
type Error struct {
|
||||||
|
// The module where the error occurred.
|
||||||
|
Module string
|
||||||
|
|
||||||
|
// The error message
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
14
kernel/error_test.go
Normal file
14
kernel/error_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package kernel
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestKernelError(t *testing.T) {
|
||||||
|
err := &Error{
|
||||||
|
Module: "foo",
|
||||||
|
Message: "error message",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err.Error() != err.Message {
|
||||||
|
t.Fatalf("expected to err.Error() to return %q; got %q", err.Message, err.Error())
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package kernel
|
package kmain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/achilleasa/gopher-os/kernel/hal"
|
"github.com/achilleasa/gopher-os/kernel/hal"
|
@ -3,6 +3,10 @@
|
|||||||
package mem
|
package mem
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// PointerShift is equal to log2(unsafe.Sizeof(uintptr)). The pointer
|
||||||
|
// size for this architecture is defined as (1 << PointerShift).
|
||||||
|
PointerShift = 3
|
||||||
|
|
||||||
// PageShift is equal to log2(PageSize). This constant is used when
|
// PageShift is equal to log2(PageSize). This constant is used when
|
||||||
// we need to convert a physical address to a page number (shift right by PageShift)
|
// we need to convert a physical address to a page number (shift right by PageShift)
|
||||||
// and vice-versa.
|
// and vice-versa.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package pmm
|
package pmm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/achilleasa/gopher-os/kernel"
|
||||||
"github.com/achilleasa/gopher-os/kernel/hal/multiboot"
|
"github.com/achilleasa/gopher-os/kernel/hal/multiboot"
|
||||||
"github.com/achilleasa/gopher-os/kernel/kfmt/early"
|
"github.com/achilleasa/gopher-os/kernel/kfmt/early"
|
||||||
"github.com/achilleasa/gopher-os/kernel/mem"
|
"github.com/achilleasa/gopher-os/kernel/mem"
|
||||||
@ -11,6 +12,9 @@ var (
|
|||||||
// which is used to bootstrap the kernel before initializing a more
|
// which is used to bootstrap the kernel before initializing a more
|
||||||
// advanced memory allocator.
|
// advanced memory allocator.
|
||||||
EarlyAllocator BootMemAllocator
|
EarlyAllocator BootMemAllocator
|
||||||
|
|
||||||
|
errBootAllocUnsupportedPageSize = &kernel.Error{Module: "pmm.BootMemAllocator", Message: "allocator only support allocation requests of order(0)"}
|
||||||
|
errBootAllocOutOfMemory = &kernel.Error{Module: "pmm.BootMemAllocator", Message: "out of memory"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// BootMemAllocator implements a rudimentary physical memory allocator which is used
|
// BootMemAllocator implements a rudimentary physical memory allocator which is used
|
||||||
@ -56,18 +60,13 @@ func (alloc *BootMemAllocator) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AllocFrame scans the system memory regions reported by the bootloader and
|
// AllocFrame scans the system memory regions reported by the bootloader and
|
||||||
// reseves the next available free frame. AllocFrame returns false if no more
|
// reserves the next available free frame.
|
||||||
// memory can be allocated.
|
|
||||||
//
|
//
|
||||||
// The allocator only supports allocating blocks equal to the page size.
|
// AllocFrame returns an error if no more memory can be allocated or when the
|
||||||
// Requests for a page order > 0 will cause the allocator to return false.
|
// requested page order is > 0.
|
||||||
//
|
func (alloc *BootMemAllocator) AllocFrame(order mem.PageOrder) (Frame, *kernel.Error) {
|
||||||
// The use of a bool return value is intentional; if this method returned an
|
|
||||||
// error then the compiler would call runtime.convT2I which in turn invokes the
|
|
||||||
// yet uninitialized Go allocator.
|
|
||||||
func (alloc *BootMemAllocator) AllocFrame(order mem.PageOrder) (Frame, bool) {
|
|
||||||
if order > 0 {
|
if order > 0 {
|
||||||
return InvalidFrame, false
|
return InvalidFrame, errBootAllocUnsupportedPageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -103,11 +102,11 @@ func (alloc *BootMemAllocator) AllocFrame(order mem.PageOrder) (Frame, bool) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if foundPageIndex == -1 {
|
if foundPageIndex == -1 {
|
||||||
return InvalidFrame, false
|
return InvalidFrame, errBootAllocOutOfMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc.allocCount++
|
alloc.allocCount++
|
||||||
alloc.lastAllocIndex = foundPageIndex
|
alloc.lastAllocIndex = foundPageIndex
|
||||||
|
|
||||||
return Frame(foundPageIndex), true
|
return Frame(foundPageIndex), nil
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,13 @@ func TestBootMemoryAllocator(t *testing.T) {
|
|||||||
allocFrameCount uint64
|
allocFrameCount uint64
|
||||||
)
|
)
|
||||||
for alloc.Init(); ; allocFrameCount++ {
|
for alloc.Init(); ; allocFrameCount++ {
|
||||||
frame, ok := alloc.AllocFrame(mem.PageOrder(0))
|
frame, err := alloc.AllocFrame(mem.PageOrder(0))
|
||||||
if !ok {
|
if err != nil {
|
||||||
|
if err == errBootAllocOutOfMemory {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
t.Fatalf("[frame %d] unexpected allocator error: %v", allocFrameCount, err)
|
||||||
|
}
|
||||||
|
|
||||||
expAddress := uintptr(uint64(alloc.lastAllocIndex) * uint64(mem.PageSize))
|
expAddress := uintptr(uint64(alloc.lastAllocIndex) * uint64(mem.PageSize))
|
||||||
if got := frame.Address(); got != expAddress {
|
if got := frame.Address(); got != expAddress {
|
||||||
@ -49,14 +52,6 @@ func TestBootMemoryAllocator(t *testing.T) {
|
|||||||
if !frame.IsValid() {
|
if !frame.IsValid() {
|
||||||
t.Errorf("[frame %d] expected IsValid() to return true", allocFrameCount)
|
t.Errorf("[frame %d] expected IsValid() to return true", allocFrameCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
if got := frame.PageOrder(); got != mem.PageOrder(0) {
|
|
||||||
t.Errorf("[frame %d] expected allocated frame page order to be 0; got %d", allocFrameCount, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := frame.Size(); got != mem.PageSize {
|
|
||||||
t.Errorf("[frame %d] expected allocated frame size to be %d; got %d", allocFrameCount, mem.PageSize, got)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if allocFrameCount != totalFreeFrames {
|
if allocFrameCount != totalFreeFrames {
|
||||||
@ -64,8 +59,8 @@ func TestBootMemoryAllocator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This allocator only works with order(0) blocks
|
// This allocator only works with order(0) blocks
|
||||||
if frame, ok := alloc.AllocFrame(mem.PageOrder(1)); ok || frame.IsValid() {
|
if frame, err := alloc.AllocFrame(mem.PageOrder(1)); err != errBootAllocUnsupportedPageSize || frame.IsValid() {
|
||||||
t.Fatalf("expected allocator to return false and an invalid frame when requested to allocate a block with order > 0; got %t, %v", ok, frame)
|
t.Fatalf("expected allocator to return errBootAllocUnsupportedPageSize and an invalid frame when requested to allocate a block with order > 0; got %v, %v", err, frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Frame describes a physical memory page index.
|
// Frame describes a physical memory page index.
|
||||||
type Frame uint64
|
type Frame uintptr
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// InvalidFrame is returned by page allocators when
|
// InvalidFrame is returned by page allocators when
|
||||||
@ -25,14 +25,3 @@ func (f Frame) IsValid() bool {
|
|||||||
func (f Frame) Address() uintptr {
|
func (f Frame) Address() uintptr {
|
||||||
return uintptr(f << mem.PageShift)
|
return uintptr(f << mem.PageShift)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageOrder returns the page order of this frame. The page order is encoded in the
|
|
||||||
// 8 MSB of the frame number.
|
|
||||||
func (f Frame) PageOrder() mem.PageOrder {
|
|
||||||
return mem.PageOrder((f >> 56) & 0xFF)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the size of this frame.
|
|
||||||
func (f Frame) Size() mem.Size {
|
|
||||||
return mem.PageSize << ((f >> 56) & 0xFF)
|
|
||||||
}
|
|
||||||
|
@ -15,17 +15,9 @@ func TestFrameMethods(t *testing.T) {
|
|||||||
t.Errorf("[order %d] expected frame %d to be valid", order, frameIndex)
|
t.Errorf("[order %d] expected frame %d to be valid", order, frameIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
if got := frame.PageOrder(); got != order {
|
|
||||||
t.Errorf("[order %d] expected frame (%d, index: %d) call to PageOrder() to return %d; got %d", order, frame, frameIndex, order, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp, got := uintptr(frameIndex<<mem.PageShift), frame.Address(); got != exp {
|
if exp, got := uintptr(frameIndex<<mem.PageShift), frame.Address(); got != exp {
|
||||||
t.Errorf("[order %d] expected frame (%d, index: %d) call to Address() to return %x; got %x", order, frame, frameIndex, exp, got)
|
t.Errorf("[order %d] expected frame (%d, index: %d) call to Address() to return %x; got %x", order, frame, frameIndex, exp, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
if exp, got := mem.Size(mem.PageSize<<order), frame.Size(); got != exp {
|
|
||||||
t.Errorf("[order %d] expected frame (%d, index: %d) call to Size() to return %d; got %d", order, frame, frameIndex, exp, got)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
stub.go
4
stub.go
@ -1,6 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/achilleasa/gopher-os/kernel"
|
import "github.com/achilleasa/gopher-os/kernel/kmain"
|
||||||
|
|
||||||
var multibootInfoPtr uintptr
|
var multibootInfoPtr uintptr
|
||||||
|
|
||||||
@ -11,5 +11,5 @@ var multibootInfoPtr uintptr
|
|||||||
// A global variable is passed as an argument to Kmain to prevent the compiler
|
// A global variable is passed as an argument to Kmain to prevent the compiler
|
||||||
// from inlining the actual call and removing Kmain from the generated .o file.
|
// from inlining the actual call and removing Kmain from the generated .o file.
|
||||||
func main() {
|
func main() {
|
||||||
kernel.Kmain(multibootInfoPtr)
|
kmain.Kmain(multibootInfoPtr)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user