mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
AllocFrame now rounds up the region start address to the nearest page multiple and rounds down the region end address to the nearest page multiple. It also ignores memory regions with size smaller than a page. Instead of using frame indices and converting them to a pmm.Frame, the allocator now just keeps track of the last allocated pmm.Frame. As the allocator is now unexported, a package-exported Init() method is now provided whose purpose is to initialize the physical allocator sub-system.
103 lines
3.5 KiB
Go
103 lines
3.5 KiB
Go
package allocator
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"github.com/achilleasa/gopher-os/kernel/driver/video/console"
|
|
"github.com/achilleasa/gopher-os/kernel/hal"
|
|
"github.com/achilleasa/gopher-os/kernel/hal/multiboot"
|
|
)
|
|
|
|
func TestBootMemoryAllocator(t *testing.T) {
|
|
multiboot.SetInfoPtr(uintptr(unsafe.Pointer(&multibootMemoryMap[0])))
|
|
|
|
// region 1 extents get rounded to [0, 9f000] and provides 159 frames [0 to 158]
|
|
// region 1 uses the original extents [100000 - 7fe0000] and provides 32480 frames [256-32735]
|
|
var totalFreeFrames uint64 = 159 + 32480
|
|
|
|
var (
|
|
alloc bootMemAllocator
|
|
allocFrameCount uint64
|
|
)
|
|
for {
|
|
frame, err := alloc.AllocFrame()
|
|
if err != nil {
|
|
if err == errBootAllocOutOfMemory {
|
|
break
|
|
}
|
|
t.Fatalf("[frame %d] unexpected allocator error: %v", allocFrameCount, err)
|
|
}
|
|
allocFrameCount++
|
|
if frame != alloc.lastAllocFrame {
|
|
t.Errorf("[frame %d] expected allocated frame to be %d; got %d", allocFrameCount, alloc.lastAllocFrame, frame)
|
|
}
|
|
|
|
if !frame.Valid() {
|
|
t.Errorf("[frame %d] expected IsValid() to return true", allocFrameCount)
|
|
}
|
|
}
|
|
|
|
if allocFrameCount != totalFreeFrames {
|
|
t.Fatalf("expected allocator to allocate %d frames; allocated %d", totalFreeFrames, allocFrameCount)
|
|
}
|
|
}
|
|
|
|
func TestAllocatorPackageInit(t *testing.T) {
|
|
fb := mockTTY()
|
|
multiboot.SetInfoPtr(uintptr(unsafe.Pointer(&multibootMemoryMap[0])))
|
|
|
|
Init()
|
|
|
|
var buf bytes.Buffer
|
|
for i := 0; i < len(fb); i += 2 {
|
|
if fb[i] == 0x0 {
|
|
continue
|
|
}
|
|
buf.WriteByte(fb[i])
|
|
}
|
|
|
|
exp := "[boot_mem_alloc] system memory map: [0x0000000000 - 0x000009fc00], size: 654336, type: available [0x000009fc00 - 0x00000a0000], size: 1024, type: reserved [0x00000f0000 - 0x0000100000], size: 65536, type: reserved [0x0000100000 - 0x0007fe0000], size: 133038080, type: available [0x0007fe0000 - 0x0008000000], size: 131072, type: reserved [0x00fffc0000 - 0x0100000000], size: 262144, type: reserved[boot_mem_alloc] free memory: 130559Kb"
|
|
if got := buf.String(); got != exp {
|
|
t.Fatalf("expected printMemoryMap to generate the following output:\n%q\ngot:\n%q", exp, got)
|
|
}
|
|
}
|
|
|
|
var (
|
|
// A dump of multiboot data when running under qemu containing only the
|
|
// memory region tag. The dump encodes the following available memory
|
|
// regions:
|
|
// [ 0 - 9fc00] length: 654336
|
|
// [100000 - 7fe0000] length: 133038080
|
|
multibootMemoryMap = []byte{
|
|
72, 5, 0, 0, 0, 0, 0, 0,
|
|
6, 0, 0, 0, 160, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 9, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 0, 0, 0, 0, 0, 252, 9, 0, 0, 0, 0, 0,
|
|
0, 4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
|
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0,
|
|
0, 0, 238, 7, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 254, 7, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
|
|
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 0, 0, 0, 0,
|
|
0, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
|
|
9, 0, 0, 0, 212, 3, 0, 0, 24, 0, 0, 0, 40, 0, 0, 0,
|
|
21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0,
|
|
1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0,
|
|
24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
}
|
|
)
|
|
|
|
func mockTTY() []byte {
|
|
// Mock a tty to handle early.Printf output
|
|
mockConsoleFb := make([]byte, 160*25)
|
|
mockConsole := &console.Ega{}
|
|
mockConsole.Init(80, 25, uintptr(unsafe.Pointer(&mockConsoleFb[0])))
|
|
hal.ActiveTerminal.AttachTo(mockConsole)
|
|
|
|
return mockConsoleFb
|
|
}
|