github.com/platinasystems/nvram@v1.0.1-0.20190709235807-51a23abd5aec/cmos.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 ) 11 12 const ( 13 cmosSize uint = 256 14 cmosRTCAreaSize uint = 14 15 ) 16 17 func verifyCMOSByteIndex(index uint) bool { 18 return (index >= cmosRTCAreaSize) && (index < cmosSize) 19 } 20 21 type CMOSer interface { 22 Close() error 23 ReadByte(off uint) (byte, error) 24 WriteByte(off uint, b byte) error 25 } 26 27 type CMOS struct { 28 accessor CMOSer 29 checksum CMOSChecksum 30 } 31 32 func (c *CMOS) Open() (err error) { 33 // Close in case it is already opened. 34 c.Close() 35 36 // Open CMOS hardware accessor. 37 accessor := new(CMOSHW) 38 err = accessor.Open() 39 if err != nil { 40 return 41 } 42 43 c.accessor = accessor 44 return 45 } 46 47 func (c *CMOS) OpenMem(filename string) (err error) { 48 // Close in case it is already opened 49 c.Close() 50 51 // Open CMOS memory file accessor. 52 accessor := new(CMOSMem) 53 err = accessor.Open(filename) 54 if err != nil { 55 return 56 } 57 58 c.accessor = accessor 59 return 60 } 61 62 func (c *CMOS) Close() (err error) { 63 // Close any accessor if opened 64 if c.accessor != nil { 65 err = c.accessor.Close() 66 c.accessor = nil 67 } 68 return 69 } 70 71 func (c *CMOS) WriteEntry(e *CMOSEntry, v []byte) (err error) { 72 // Verify CMOS operation 73 err = verifyCMOSOp(e) 74 if err != nil { 75 return 76 } 77 78 // Calculate source size, bit offset and remaining bits for entry field. 79 src_size := uint(8) 80 src_bit := uint(0) 81 src_bit_remaining := e.length 82 if src_bit_remaining > uint(len(v)*8) { 83 src_bit_remaining = uint(len(v) * 8) 84 } 85 86 // Start at destination bit 87 dst_bit := e.bit 88 for src_bit_remaining > 0 { 89 // Get write value from source 90 wvalue := v[src_bit>>3] 91 92 debug.Trace(debug.LevelMSG3, "src_bit = %d dst_bit = %d src_size = %d wvalue = %X\n", 93 src_bit, dst_bit, src_size, wvalue) 94 95 // Update destination with partial byte data 96 if src_size > src_bit_remaining { 97 // Find Write value with partial data 98 src_size = src_bit_remaining 99 wvalue = (wvalue >> (src_bit & 0x7)) & (byte(1<<src_size) - 1) 100 101 // Read current value from destination 102 n := byte(0) 103 n, err = c.ReadByte(dst_bit >> 3) 104 if err != nil { 105 return 106 } 107 108 // Update destination with remaining bits to write 109 mask := (byte(1<<src_size) - 1) << (dst_bit & 0x07) 110 n = (n & ^mask) | ((wvalue << (dst_bit & 0x07)) & mask) 111 err = c.WriteByte(dst_bit>>3, n) 112 return 113 } else { 114 // Overwrite whole byte values 115 err = c.WriteByte(dst_bit>>3, wvalue) 116 if err != nil { 117 return 118 } 119 } 120 121 // Move to next byte 122 src_bit += src_size 123 src_bit_remaining -= src_size 124 dst_bit += src_size 125 } 126 127 return 128 } 129 130 func (c *CMOS) ReadEntry(e *CMOSEntry) (v []byte, err error) { 131 // Verify CMOS operation 132 err = verifyCMOSOp(e) 133 if err != nil { 134 return 135 } 136 137 // Calculate source size, bit offset and remaining bits for entry field. 138 src_size := uint(8) 139 src_bit := e.bit 140 src_bit_remaining := e.length 141 142 // Start at destination bit 143 dst_bit := uint(0) 144 145 // Create return value buffer. 146 if e.config == CMOSEntryString { 147 v = make([]byte, (e.length+7)/8) 148 } else { 149 v = make([]byte, 8) 150 } 151 152 for src_bit_remaining > 0 { 153 // Read source byte 154 n := byte(0) 155 n, err = c.ReadByte(src_bit >> 3) 156 if err != nil { 157 return 158 } 159 160 debug.Trace(debug.LevelMSG3, "src_bit = %d dst_bit = %d, src_size = %d n = %X\n", 161 src_bit, dst_bit, src_size, n) 162 163 // For last partial byte mask off extra bits 164 if src_size > src_bit_remaining { 165 src_size = src_bit_remaining 166 n = (n >> (src_bit & 0x7)) & (byte(1<<src_size) - 1) 167 } 168 169 // Copy byte read 170 v[dst_bit>>3] = n 171 172 // Move to next byte 173 src_bit += src_size 174 src_bit_remaining -= src_size 175 dst_bit += src_size 176 } 177 178 return 179 } 180 181 func (c *CMOS) ReadChecksum() (sum uint16, err error) { 182 var b0, b1 byte 183 184 // Read checksum b0 and b1 185 b0, err = c.ReadByte(c.checksum.index) 186 if err != nil { 187 return 188 } 189 b1, err = c.ReadByte(c.checksum.index + 1) 190 if err != nil { 191 return 192 } 193 // return in big endian format 194 sum = (uint16(b0) << 8) + uint16(b1) 195 return 196 } 197 198 func (c *CMOS) WriteChecksum(sum uint16) (err error) { 199 // Write checksum byte 0 200 err = c.WriteByte(c.checksum.index, byte(sum>>8)) 201 if err != nil { 202 return 203 } 204 // Write checksum byte 1 205 err = c.WriteByte(c.checksum.index+1, byte(sum&0xFF)) 206 if err != nil { 207 return 208 } 209 return 210 } 211 212 func (c *CMOS) ComputeChecksum() (sum uint16, err error) { 213 // Calculate checksum over chemsum area 214 for i := c.checksum.start; i <= c.checksum.end; i++ { 215 var b byte 216 b, err = c.ReadByte(i) 217 if err != nil { 218 return 219 } 220 sum += uint16(b) 221 } 222 return 223 } 224 225 func (c *CMOS) ReadAllMemory() (d []byte, err error) { 226 // Retrun buffer with all CMOS data bytes 227 // Ignore the RTC area. 228 d = make([]byte, cmosSize) 229 for i := cmosRTCAreaSize; i < cmosSize; i++ { 230 d[i], err = c.ReadByte(i) 231 if err != nil { 232 return 233 } 234 } 235 return 236 } 237 238 func (c *CMOS) WriteAllMemory(d []byte) (err error) { 239 if len(d) < int(cmosSize) { 240 return fmt.Errorf("nvram: Not enough data.") 241 } 242 // Write buffer to entire CMOS area. 243 // Ignore RTC area. 244 for i := cmosRTCAreaSize; i < cmosSize; i++ { 245 err = c.WriteByte(i, d[i]) 246 if err != nil { 247 return 248 } 249 } 250 return 251 } 252 253 func (c *CMOS) ReadByte(off uint) (byte, error) { 254 // Read byte using current accessor 255 if c.accessor == nil { 256 return 0, ErrCMOSNotOpen 257 } 258 return c.accessor.ReadByte(off) 259 } 260 261 func (c *CMOS) WriteByte(off uint, b byte) error { 262 // Write byte using current accessor 263 if c.accessor == nil { 264 return ErrCMOSNotOpen 265 } 266 return c.accessor.WriteByte(off, b) 267 }