From 1c3bfcd58d5e82588351a9766c2b0af574f9ab1e Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Wed, 14 Jun 2017 17:09:05 +0100 Subject: [PATCH] Implement early virtual address space reservation helper Function EarlyReserveRegion reserves contiguous virtual address space regions beginning at the end of the available kernel space and moving towards lower virtual addresses. The only state that is tracked by this function is the last allocated virtual page address which is adjusted after each reservation request. Starting at the end of the kernel address space ensures that we will not step on the virtual addresses used by the kernel code and data sections. --- kernel/mem/vmm/addr_space.go | 35 +++++++++++++++++++++++++++++++ kernel/mem/vmm/addr_space_test.go | 29 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 kernel/mem/vmm/addr_space.go create mode 100644 kernel/mem/vmm/addr_space_test.go diff --git a/kernel/mem/vmm/addr_space.go b/kernel/mem/vmm/addr_space.go new file mode 100644 index 0000000..695168c --- /dev/null +++ b/kernel/mem/vmm/addr_space.go @@ -0,0 +1,35 @@ +package vmm + +import ( + "github.com/achilleasa/gopher-os/kernel" + "github.com/achilleasa/gopher-os/kernel/mem" +) + +var ( + // earlyReserveLastUsed tracks the last reserved page address and is + // decreased after each allocation request. Initially, it points to + // tempMappingAddr which coincides with the end of the kernel address + // space. + earlyReserveLastUsed = tempMappingAddr + + errEarlyReserveNoSpace = &kernel.Error{Module: "early_reserve", Message: "remaining virtual address space not large enough to satisfy reservation request"} +) + +// EarlyReserveRegion reserves a page-aligned contiguous virtual memory region +// with the requested size in the kernel address space and returns its virtual +// address. If size is not a multiple of mem.PageSize it will be automatically +// rounded up. +// +// This function allocates regions starting at the end of the kernel address +// space. It should only be used during the early stages of kernel initialization. +func EarlyReserveRegion(size mem.Size) (uintptr, *kernel.Error) { + size = (size + (mem.PageSize - 1)) & ^(mem.PageSize - 1) + + // reserving a region of the requested size will cause an underflow + if uintptr(size) > earlyReserveLastUsed { + return 0, errEarlyReserveNoSpace + } + + earlyReserveLastUsed -= uintptr(size) + return earlyReserveLastUsed, nil +} diff --git a/kernel/mem/vmm/addr_space_test.go b/kernel/mem/vmm/addr_space_test.go new file mode 100644 index 0000000..e457381 --- /dev/null +++ b/kernel/mem/vmm/addr_space_test.go @@ -0,0 +1,29 @@ +package vmm + +import ( + "runtime" + "testing" +) + +func TestEarlyReserveAmd64(t *testing.T) { + if runtime.GOARCH != "amd64" { + t.Skip("test requires amd64 runtime; skipping") + } + + defer func(origLastUsed uintptr) { + earlyReserveLastUsed = origLastUsed + }(earlyReserveLastUsed) + + earlyReserveLastUsed = 4096 + next, err := EarlyReserveRegion(42) + if err != nil { + t.Fatal(err) + } + if exp := uintptr(0); next != exp { + t.Fatal("expected reservation request to be rounded to nearest page") + } + + if _, err = EarlyReserveRegion(1); err != errEarlyReserveNoSpace { + t.Fatalf("expected to get errEarlyReserveNoSpace; got %v", err) + } +}