From 61314a9c33176a11decbe175d8e593bc8950815f Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Wed, 10 May 2017 06:59:48 +0100 Subject: [PATCH] Define memory Size and implement optimized memset --- kernel/mem/constants_amd64.go | 13 +++++++++++++ kernel/mem/memset.go | 29 +++++++++++++++++++++++++++++ kernel/mem/memset_test.go | 27 +++++++++++++++++++++++++++ kernel/mem/size.go | 12 ++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 kernel/mem/constants_amd64.go create mode 100644 kernel/mem/memset.go create mode 100644 kernel/mem/memset_test.go create mode 100644 kernel/mem/size.go diff --git a/kernel/mem/constants_amd64.go b/kernel/mem/constants_amd64.go new file mode 100644 index 0000000..aea2911 --- /dev/null +++ b/kernel/mem/constants_amd64.go @@ -0,0 +1,13 @@ +// +build amd64 + +package mem + +const ( + // 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) + // and vice-versa. + PageShift = 12 + + // PageSize defines the system's page size in bytes. + PageSize = Size(1 << PageShift) +) diff --git a/kernel/mem/memset.go b/kernel/mem/memset.go new file mode 100644 index 0000000..6041487 --- /dev/null +++ b/kernel/mem/memset.go @@ -0,0 +1,29 @@ +package mem + +import ( + "reflect" + "unsafe" +) + +// Memset sets size bytes at the given address to the supplied value. The implementation +// is based on bytes.Repeat; instead of using a for loop, this function uses +// log2(size) copy calls which should give us a speed boost as page addresses +// are always aligned. +func Memset(addr uintptr, value byte, size Size) { + if size == 0 { + return + } + + // overlay a slice on top of this address region + target := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ + Len: int(size), + Cap: int(size), + Data: addr, + })) + + // Set first element and make log2(size) optimized copies + target[0] = value + for index := Size(1); index < size; index *= 2 { + copy(target[index:], target[:index]) + } +} diff --git a/kernel/mem/memset_test.go b/kernel/mem/memset_test.go new file mode 100644 index 0000000..c4af743 --- /dev/null +++ b/kernel/mem/memset_test.go @@ -0,0 +1,27 @@ +package mem + +import ( + "testing" + "unsafe" +) + +func TestMemset(t *testing.T) { + // memset with a 0 size should be a no-op + Memset(uintptr(0), 0x00, 0) + + for pageCount := uint32(1); pageCount <= 10; pageCount++ { + buf := make([]byte, PageSize<