github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/memio/mmap.go (about)

     1  // Copyright 2012-2020 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build linux,arm linux,arm64
     6  
     7  package memio
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"syscall"
    13  	"unsafe"
    14  )
    15  
    16  var (
    17  	pageSize = int64(syscall.Getpagesize())
    18  )
    19  
    20  // mmap aligns the address and maps multiple pages when needed.
    21  func mmap(f *os.File, addr int64, size int64, prot int) (mem []byte, offset int64, err error) {
    22  	if addr+size <= addr {
    23  		return nil, 0, fmt.Errorf("invalid address for size %#x", size)
    24  	}
    25  	page := addr &^ (pageSize - 1)
    26  	offset = addr - page
    27  	mapSize := offset + size
    28  	mem, err = syscall.Mmap(int(f.Fd()), int64(page), int(mapSize), prot, syscall.MAP_SHARED)
    29  	return
    30  }
    31  
    32  // Read reads data from physical memory at address addr. On x86 platforms,
    33  // this uses the seek+read syscalls. On arm platforms, this uses mmap.
    34  func Read(addr int64, data UintN) error {
    35  	f, err := os.OpenFile(memPath, os.O_RDONLY, 0)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	defer f.Close()
    40  
    41  	mem, offset, err := mmap(f, addr, data.Size(), syscall.PROT_READ)
    42  	if err != nil {
    43  		return fmt.Errorf("Reading %#x/%d: %v", addr, data.Size(), err)
    44  	}
    45  	defer syscall.Munmap(mem)
    46  
    47  	// MMIO makes this a bit tricky. Reads must be conducted in one load
    48  	// operation. Review the generated assembly to make sure.
    49  	if err := data.read(unsafe.Pointer(&mem[offset])); err != nil {
    50  		return fmt.Errorf("Reading %#x/%d: %v", addr, data.Size(), err)
    51  	}
    52  	return nil
    53  }
    54  
    55  // Write writes data to physical memory at address addr. On x86 platforms, this
    56  // uses the seek+read syscalls. On arm platforms, this uses mmap.
    57  func Write(addr int64, data UintN) error {
    58  	f, err := os.OpenFile(memPath, os.O_RDWR, 0)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	defer f.Close()
    63  
    64  	mem, offset, err := mmap(f, addr, data.Size(), syscall.PROT_WRITE)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	defer syscall.Munmap(mem)
    69  
    70  	// MMIO makes this a bit tricky. Writes must be conducted in one store
    71  	// operation. Review the generated assembly to make sure.
    72  	return data.write(unsafe.Pointer(&mem[offset]))
    73  }