github.com/platinasystems/nvram@v1.0.1-0.20190709235807-51a23abd5aec/cmos_hw.go (about) 1 // Copyright © 2019 Platina Systems, Inc. All rights reserved. 2 // Use of this source code is governed by the GPL-2 license described in the 3 // LICENSE file. 4 5 package nvram 6 7 import ( 8 "fmt" 9 "github.com/platinasystems/nvram/debug" 10 "os" 11 "syscall" 12 ) 13 14 const ( 15 sys_iopl = 172 //amd64 16 sys_ioperm = 173 //amd64 17 ) 18 19 type CMOSHW struct { 20 port_file *os.File 21 } 22 23 func (c *CMOSHW) Open() (err error) { 24 // Close in case it is already opened 25 c.Close() 26 27 // Close on any error 28 defer func() { 29 if err != nil { 30 c.Close() 31 } 32 }() 33 34 debug.Trace(debug.LevelMSG1, "Opening CMOS HW\n") 35 36 // Set IO privilege level to 3. 37 if _, _, errno := syscall.Syscall(sys_iopl, 38 uintptr(3), 0, 0); errno != 0 { 39 return errno 40 } 41 42 // Open device ports for access to CMOS NVRAM 43 c.port_file, err = os.OpenFile("/dev/port", os.O_RDWR|os.O_SYNC, 0755) 44 if err != nil { 45 return 46 } 47 48 return 49 } 50 51 func (c *CMOSHW) Close() error { 52 53 debug.Trace(debug.LevelMSG1, "Closing CMOS HW\n") 54 55 // Set IO privilege level to normal 56 if _, _, errno := syscall.Syscall(sys_iopl, 57 uintptr(0), 0, 0); errno != 0 { 58 return errno 59 } 60 61 // Close port file if opened 62 if c.port_file != nil { 63 c.port_file.Close() 64 c.port_file = nil 65 } 66 67 return nil 68 } 69 70 func (c *CMOSHW) ReadByte(off uint) (byte, error) { 71 if c.port_file == nil { 72 return 0, ErrCMOSNotOpen 73 } 74 if !verifyCMOSByteIndex(off) { 75 return 0, ErrInvalidCMOSIndex 76 } 77 78 // Find port0 and 1 to set CMOS data offset 79 var port_0, port_1 int64 80 if off < 128 { 81 port_0 = 0x70 82 port_1 = 0x71 83 } else { 84 port_0 = 0x72 85 port_1 = 0x73 86 } 87 88 // Set offset 89 if err := c.ioWriteReg8(port_0, byte(off)); err != nil { 90 return 0, err 91 } 92 93 // Read data from NVRAM at offset 94 return c.ioReadReg8(port_1) 95 } 96 97 func (c *CMOSHW) WriteByte(off uint, b byte) error { 98 if c.port_file == nil { 99 return ErrCMOSNotOpen 100 } 101 102 if !verifyCMOSByteIndex(off) { 103 return ErrInvalidCMOSIndex 104 } 105 106 // Find port0 and 1 to set CMOS data offset 107 var port_0, port_1 int64 108 if off < 128 { 109 port_0 = 0x70 110 port_1 = 0x71 111 } else { 112 port_0 = 0x72 113 port_1 = 0x73 114 } 115 116 // Set offset 117 if err := c.ioWriteReg8(port_0, byte(off)); err != nil { 118 return err 119 } 120 121 // Write data to NVRAM at offset 122 if err := c.ioWriteReg8(port_1, b); err != nil { 123 return err 124 } 125 126 return nil 127 } 128 129 func (c *CMOSHW) ioReadReg8(addr int64) (b byte, err error) { 130 // Seek to port address 131 if _, err = c.port_file.Seek(addr, 0); err != nil { 132 return 133 } 134 135 // Read data from port into buffer 136 buf := make([]byte, 1) 137 n, err := c.port_file.Read(buf) 138 if err != nil { 139 return 140 } 141 142 if n != 1 { 143 err = fmt.Errorf("nvram: Unable to read port.") 144 return 145 } 146 147 // Return data read 148 b = buf[0] 149 return 150 } 151 152 func (c *CMOSHW) ioWriteReg8(addr int64, b byte) (err error) { 153 // Prepare write buffer 154 buf := make([]byte, 1) 155 buf[0] = b 156 157 // Seek to port address 158 if _, err = c.port_file.Seek(addr, 0); err != nil { 159 return err 160 } 161 162 // Write data to port 163 n, err := c.port_file.Write(buf) 164 if err != nil { 165 return err 166 } 167 168 // Sync write 169 c.port_file.Sync() 170 171 if n != 1 { 172 return fmt.Errorf("nvram: Unable to write port.") 173 } 174 175 return 176 }