github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/pkg/memio/mmap.go (about)

     1  // Copyright 2012-2019 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  	memPath  = "/dev/mem"
    19  )
    20  
    21  // mmap aligns the address and maps multiple pages when needed.
    22  func mmap(f *os.File, addr int64, size int64, prot int) (mem []byte, offset int64, err error) {
    23  	if addr+size <= addr {
    24  		return nil, 0, fmt.Errorf("invalid address for size %#x", size)
    25  	}
    26  	page := addr &^ (pageSize - 1)
    27  	offset = addr - page
    28  	mapSize := offset + size
    29  	mem, err = syscall.Mmap(int(f.Fd()), int64(page), int(mapSize), prot, syscall.MAP_SHARED)
    30  	return
    31  }
    32  
    33  // Read reads data from physical memory at address addr. On x86 platforms,
    34  // this uses the seek+read syscalls. On arm platforms, this uses mmap.
    35  func Read(addr int64, data UintN) error {
    36  	f, err := os.OpenFile(memPath, os.O_RDONLY, 0)
    37  	if err != nil {
    38  		return err
    39  	}
    40  	defer f.Close()
    41  
    42  	mem, offset, err := mmap(f, addr, data.Size(), syscall.PROT_READ)
    43  	if err != nil {
    44  		return fmt.Errorf("Reading %#x/%d: %v", addr, data.Size(), err)
    45  	}
    46  	defer syscall.Munmap(mem)
    47  
    48  	// MMIO makes this a bit tricky. Reads must be conducted in one load
    49  	// operation. Review the generated assembly to make sure.
    50  	if err := data.read(unsafe.Pointer(&mem[offset])); err != nil {
    51  		return fmt.Errorf("Reading %#x/%d: %v", addr, data.Size(), err)
    52  	}
    53  	return nil
    54  }
    55  
    56  // Write writes data to physical memory at address addr. On x86 platforms, this
    57  // uses the seek+read syscalls. On arm platforms, this uses mmap.
    58  func Write(addr int64, data UintN) error {
    59  	f, err := os.OpenFile(memPath, os.O_RDWR, 0)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	defer f.Close()
    64  
    65  	mem, offset, err := mmap(f, addr, data.Size(), syscall.PROT_WRITE)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	defer syscall.Munmap(mem)
    70  
    71  	// MMIO makes this a bit tricky. Writes must be conducted in one store
    72  	// operation. Review the generated assembly to make sure.
    73  	return data.write(unsafe.Pointer(&mem[offset]))
    74  }