github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/memio/archport_linux.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  //go:build (linux && amd64) || (linux && 386)
     6  // +build linux,amd64 linux,386
     7  
     8  package memio
     9  
    10  import (
    11  	"fmt"
    12  	"sync"
    13  	"syscall"
    14  )
    15  
    16  // ArchPort is used for architectural access to a port, instead of file system
    17  // level access. On the x86, this means direct, in-line in[bwl]/out[bwl]
    18  // instructions, requiring an iopl system call. On other architectures,
    19  // it may require special mmap setup.
    20  type ArchPort struct{}
    21  
    22  var ioplError struct {
    23  	sync.Once
    24  	err error
    25  }
    26  
    27  func iopl() error {
    28  	ioplError.Do(func() {
    29  		ioplError.err = syscall.Iopl(3)
    30  	})
    31  	return ioplError.err
    32  }
    33  
    34  func archInl(uint16) uint32
    35  func archInw(uint16) uint16
    36  func archInb(uint16) uint8
    37  
    38  // In reads data from the x86 port at address addr. Data must be Uint8, Uint16,
    39  // Uint32, but not Uint64.
    40  func (a *ArchPort) In(addr uint16, data UintN) error {
    41  	if err := iopl(); err != nil {
    42  		return err
    43  	}
    44  
    45  	switch p := data.(type) {
    46  	case *Uint32:
    47  		*p = Uint32(archInl(addr))
    48  	case *Uint16:
    49  		*p = Uint16(archInw(addr))
    50  	case *Uint8:
    51  		*p = Uint8(archInb(addr))
    52  	default:
    53  		return fmt.Errorf("port data must be 8, 16 or 32 bits")
    54  	}
    55  	return nil
    56  }
    57  
    58  func archOutl(uint16, uint32)
    59  func archOutw(uint16, uint16)
    60  func archOutb(uint16, uint8)
    61  
    62  // Out writes data to the x86 port at address addr. data must be Uint8, Uint16
    63  // uint32, but not Uint64.
    64  func (a *ArchPort) Out(addr uint16, data UintN) error {
    65  	if err := iopl(); err != nil {
    66  		return err
    67  	}
    68  
    69  	switch p := data.(type) {
    70  	case *Uint32:
    71  		archOutl(addr, uint32(*p))
    72  	case *Uint16:
    73  		archOutw(addr, uint16(*p))
    74  	case *Uint8:
    75  		archOutb(addr, uint8(*p))
    76  	default:
    77  		return fmt.Errorf("port data must be 8, 16 or 32 bits")
    78  	}
    79  	return nil
    80  }
    81  
    82  // Close implements close
    83  func (a *ArchPort) Close() error {
    84  	return nil
    85  }
    86  
    87  // ArchIn is deprecated. Only here to keep compatibility
    88  func ArchIn(addr uint16, data UintN) error {
    89  	archport := &ArchPort{}
    90  	return archport.In(addr, data)
    91  }
    92  
    93  // ArchOut is deprecated. Only here to keep compatibility
    94  func ArchOut(addr uint16, data UintN) error {
    95  	archport := &ArchPort{}
    96  	return archport.Out(addr, data)
    97  }