pmem

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2017 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package pmem implements handling of physical memory for user space programs.

To make things confusing, a modern computer has many view of the memory:

  • user mode memory is the virtual address space that an application runs in. It is generally a tad less than half the addressable memory, so on a 32 bits system, the addressable range is 1.9Gb. For 64 bits OS, it depends but it usually at least 4Gb. The memory is virtual and can be flushed to disk in the swap file unless individual pages are locked.
  • kernel memory is the virtual address space the kernel sees. It often can see the currently active user space program on the current CPU core in addition to all the memory the kernel sees. The kernel memory pages that were not mlock()'ed is 'virtual' and can be flushed to disk in the swap file when there's not enough RAM available. On linux systems, the kernel addressed memory can be mapped in user space via `/dev/kmem`.
  • physical memory is the actual address of each page in the DRAM chip and anything connected to the memory controller. The mapping may be different depending on what controller looks at the bus. So a peripheral (GPU, DMA controller) may have a different view of the physical memory than the host CPU. On linux systems, this memory can be mapped in user space via `/dev/mem`.
  • The CPU may memory map registers (for example, to control GPIO pins, clock speed, etc). This is not "real" memory, this is a view of registers but it still follows "mostly" the same semantic as DRAM backed physical memory.
  • CPU memory accesses are layered with multiple caches, usually named L1, L2 and optionally L3. Some controllers (DMA) can see some cache levels (L2) but not others (L1) on some CPU architecture (bcm283x). This means that a user space program writing data to a memory page and immediately asking the DMA controller to read it may cause stale data to be read!
  • Hypervisor can change the complete memory mapping as seen by the kernel. This is outside the scope of this project. :)

In practice, the semantics change between CPU manufacturers (Broadcom vs Allwinner) and between architectures (ARM vs x86). The most tricky one is to understand cached memory and how it affects coherence and performance. Uncached memory is extremely slow so it must only be used when necessary.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MapStruct

func MapStruct(base uint64, v reflect.Value) error

MapStruct is a shorthand to call Map(base, sizeof(v)) then Struct(v).

Example
// Let's say the CPU has 4 x 32 bits memory mapped registers at the address
// 0xDEADBEEF.
var reg *[4]uint32
if err := MapStruct(0xDEADBEAF, reflect.ValueOf(reg)); err != nil {
	log.Fatal(err)
}
// reg now points to physical memory.
Output:

func ReadPageMap

func ReadPageMap(virtAddr uintptr) (uint64, error)

ReadPageMap reads a physical address mapping for a virtual page address from /proc/self/pagemap.

It returns the physical address that corresponds to the start of the virtual page within which the virtual address virtAddr is located.

The meaning of the return value is documented at https://www.kernel.org/doc/Documentation/vm/pagemap.txt

func TestCopy

func TestCopy(size, holeSize int, alloc func(size int) (Mem, error), copyMem func(pDst, pSrc uint64) error) error

TestCopy is used by CPU drivers to verify that the DMA engine works correctly.

It is not meant to be used by end users.

TestCopy allocates two buffer via `alloc`, once as the source and one as the destination. It fills the source with random data and the destination with 0x11.

`copyMem` is expected to copy the memory from pSrc to pDst, with an offset of `hole` and size `size-2*hole`.

The function `copyMem` being tested is only given the buffer physical addresses and must copy the data without other help. It is expected to

This confirm misaligned DMA copying works. leverage the host's DMA engine.

Types

type Mem

type Mem interface {
	io.Closer
	// Bytes returns the user space memory mapped buffer address as a slice of
	// bytes.
	//
	// It is the raw view of the memory from this process.
	Bytes() []byte
	// Struct initializes a pointer to a struct or array to point to the memory
	// mapped region.
	//
	// pp must be a pointer to a pointer to a struct and the pointer to struct
	// must be nil. Returns an error otherwise.
	//
	// The pointer initialized points to the same address as Bytes().
	Struct(pp reflect.Value) error
	// PhysAddr is the physical address. It can be either 32 bits or 64 bits,
	// depending on the bitness of the OS kernel, not on the user mode build,
	// e.g. you could have compiled on a 32 bits Go toolchain but running on a
	// 64 bits kernel.
	PhysAddr() uint64
}

Mem represents a section of memory that is usable by the DMA controller.

Since this is physically allocated memory, that could potentially have been allocated in spite of OS consent, for example by asking the GPU directly, it is important to call Close() before process exit.

type MemAlloc

type MemAlloc struct {
	View
}

MemAlloc represents contiguous physically locked memory that was allocated.

The memory is mapped in user space.

MemAlloc implements Mem.

func Alloc

func Alloc(size int) (*MemAlloc, error)

Alloc allocates a continuous chunk of physical memory.

Size must be rounded to 4Kb. Allocations of 4Kb will normally succeed. Allocations larger than 64Kb will likely fail due to kernel memory fragmentation; rebooting the host or reducing the number of running programs may help.

The allocated memory is uncached.

func (*MemAlloc) Close

func (m *MemAlloc) Close() error

Close unmaps the physical memory allocation.

type Slice

type Slice []byte

Slice can be transparently viewed as []byte, []uint32 or a struct.

func (*Slice) Bytes

func (s *Slice) Bytes() []byte

Bytes implements Mem.

func (*Slice) Struct

func (s *Slice) Struct(pp reflect.Value) error

Struct implements Mem.

func (*Slice) Uint32

func (s *Slice) Uint32() []uint32

Uint32 returns a view of the byte slice as a []uint32.

type View

type View struct {
	Slice
	// contains filtered or unexported fields
}

View represents a view of physical memory memory mapped into user space.

It is usually used to map CPU registers into user space, usually I/O registers and the likes.

It is not required to call Close(), the kernel will clean up on process shutdown.

func Map

func Map(base uint64, size int) (*View, error)

Map returns a memory mapped view of arbitrary physical memory range using OS provided functionality.

Maps size of memory, rounded on a 4kb window.

This function is dangerous and should be used wisely. It normally requires super privileges (root). On Linux, it leverages /dev/mem.

func MapGPIO

func MapGPIO() (*View, error)

MapGPIO returns a CPU specific memory mapping of the CPU I/O registers using /dev/gpiomem.

At the moment, /dev/gpiomem is only supported on Raspbian Jessie via a specific kernel driver.

func (*View) Close

func (v *View) Close() error

Close unmaps the memory from the user address space.

This is done naturally by the OS on process teardown (when the process exits) so this is not a hard requirement to call this function.

func (*View) PhysAddr

func (v *View) PhysAddr() uint64

PhysAddr implements Mem.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL