1# Copyright (C) 2021-2022 Intel Corporation. 2# 3# SPDX-License-Identifier: BSD-3-Clause 4# 5 6import sys 7import mmap 8import logging 9from math import floor, ceil 10 11from .exception import * 12 13class Object: 14 def get(self): 15 raise NotImplementedError(self.__class__.__name__) 16 17 def set(self, obj): 18 raise NotImplementedError(self.__class__.__name__) 19 20 def to_buffer(self): 21 raise NotImplementedError(self.__class__.__name__) 22 23 def to_decimal_string(self): 24 raise NotImplementedError(self.__class__.__name__) 25 26 def to_hex_string(self): 27 raise NotImplementedError(self.__class__.__name__) 28 29 def to_integer(self): 30 raise NotImplementedError(self.__class__.__name__) 31 32 def to_string(self): 33 raise NotImplementedError(self.__class__.__name__) 34 35 def get_obj(self): 36 return self 37 38class UninitializedObject(Object): 39 def to_string(self): 40 return "Uninitialized Object" 41 42class BufferBase(Object): 43 @staticmethod 44 def bitmask(to, frm): 45 return ((1 << (to + 1)) - 1) - ((1 << frm) - 1) 46 47 def __init__(self, length): 48 self.__length = length 49 self.__fields = {} # name -> (offset, bitwidth, access_width) 50 51 def read(self, byte_idx, bit_width): 52 return NotImplementedError(self.__class__.__name__) 53 54 def write(self, byte_idx, value, bit_width): 55 return NotImplementedError(self.__class__.__name__) 56 57 def create_field(self, name, offset, bitwidth, access_width): 58 self.__fields[name] = (offset, bitwidth, access_width) 59 60 def field_bitwidth(self, name): 61 return self.__fields[name][1] 62 63 def read_field(self, name): 64 offset, bitwidth, access_width = self.__fields[name] 65 acc = 0 66 acc_bit_count = 0 67 bit_idx = offset 68 bit_remaining = bitwidth 69 70 assert offset + bitwidth <= self.__length * 8, \ 71 f"Buffer overflow: attempt to access field {name} at bit {offset + bitwidth} while the buffer has only {len(self.__data) * 8} bits" 72 73 # Bits out of byte boundary 74 if bit_idx % access_width > 0: 75 # byte_idx shall be (access_width // 8)-byte aligned 76 byte_idx = (bit_idx // access_width) * (access_width // 8) 77 bit_count = (access_width - bit_idx % access_width) 78 if bit_count > bit_remaining: 79 bit_count = bit_remaining 80 81 mask = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width) 82 acc = (self.read(byte_idx, access_width) & mask) >> (bit_idx % access_width) 83 acc_bit_count += bit_count 84 bit_idx += bit_count 85 bit_remaining -= bit_count 86 87 while bit_remaining > 0: 88 byte_idx = bit_idx // 8 89 bit_count = min(access_width, bit_remaining) 90 91 mask = self.bitmask(bit_count - 1, 0) 92 acc |= (self.read(byte_idx, access_width) & mask) << acc_bit_count 93 acc_bit_count += bit_count 94 bit_idx += bit_count 95 bit_remaining -= bit_count 96 97 return acc 98 99 def write_field(self, name, value): 100 offset, bitwidth, access_width = self.__fields[name] 101 bit_idx = offset 102 bit_remaining = bitwidth 103 104 assert offset + bitwidth <= self.__length * 8, \ 105 f"Buffer overflow: attempt to access field {name} at bit {offset + bitwidth} while the buffer has only {len(self.__data) * 8} bits" 106 107 # Bits out of access_width boundary 108 if bit_idx % access_width > 0: 109 byte_idx = (bit_idx // access_width) * (access_width // 8) 110 bit_count = (access_width - bit_idx % access_width) 111 if bit_count > bit_remaining: 112 bit_count = bit_remaining 113 114 mask_of_write = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width) 115 mask_of_keep = ((1 << access_width) - 1) - mask_of_write 116 v = (value & ((1 << bit_count) - 1)) << (bit_idx % access_width) 117 self.write(byte_idx, (v & mask_of_write) | (self.read(byte_idx, access_width) & mask_of_keep), access_width) 118 119 value >>= bit_count 120 bit_idx += bit_count 121 bit_remaining -= bit_count 122 123 while bit_remaining > 0: 124 byte_idx = bit_idx // 8 125 bit_count = min(access_width, bit_remaining) 126 127 mask_of_write = self.bitmask(bit_count - 1, 0) 128 mask_of_keep = ((1 << access_width) - 1) - mask_of_write 129 v = (value & ((1 << bit_count) - 1)) 130 self.write(byte_idx, (v & mask_of_write) | (self.read(byte_idx, access_width) & mask_of_keep), access_width) 131 132 value >>= bit_count 133 bit_idx += bit_count 134 bit_remaining -= bit_count 135 136 def to_buffer(self): 137 return self 138 139class Buffer(BufferBase): 140 def __init__(self, data): 141 assert len(data) > 0 142 super().__init__(len(data)) 143 self.__data = bytearray(data) 144 145 @property 146 def data(self): 147 return bytes(self.__data) 148 149 def read(self, byte_idx, bit_width): 150 acc = 0 151 byte_width = min(bit_width // 8, len(self.__data) - byte_idx) 152 return int.from_bytes(self.__data[byte_idx : (byte_idx + byte_width)], sys.byteorder) 153 154 def write(self, byte_idx, value, bit_width): 155 byte_width = min(bit_width // 8, len(self.__data) - byte_idx) 156 self.__data[byte_idx : (byte_idx + byte_width)] = value.to_bytes(byte_width, sys.byteorder) 157 158 def get(self): 159 return self.__data 160 161 def set(self, value): 162 data = value.to_buffer().get() 163 copy_length = min(len(data), len(self.__data)) 164 self.__data[:copy_length] = data[:copy_length] 165 166 def to_hex_string(self): 167 result = ",".join(map(lambda x:hex(x)[2:], self.__data)) 168 return String(result) 169 170 def to_integer(self): 171 acc = 0 172 i = min(len(self.__data), 8) - 1 173 while i >= 0: 174 acc <<= 8 175 acc |= self.__data[i] 176 i -= 1 177 return Integer(acc) 178 179class StreamIOBuffer(BufferBase): 180 def __init__(self, stream, base, length): 181 super().__init__(length) 182 self.__stream = stream 183 self.__base = base 184 185 def read(self, byte_idx, bit_width): 186 byte_width = bit_width // 8 187 self.__stream.seek(self.__base + byte_idx) 188 data = self.__stream.read(byte_width) 189 return int.from_bytes(data, sys.byteorder) 190 191 def write(self, byte_idx, value, bit_width): 192 byte_width = bit_width // 8 193 self.__stream.seek(self.__base + byte_idx) 194 self.__stream.write(value.to_bytes(byte_width, sys.byteorder)) 195 196class IndexedIOBuffer(BufferBase): 197 def __init__(self, index_register, data_register): 198 # FIXME: Get the real size of an indexed I/O region 199 super().__init__(256) 200 self.__index_register = index_register 201 self.__data_register = data_register 202 203 def read(self, byte_idx, bit_width): 204 assert bit_width == 8, f"Indexed I/O buffers can only be read one byte at a time" 205 self.__index_register.set(Integer(byte_idx, 8)) 206 return self.__data_register.get() 207 208 def write(self, byte_idx, value, bit_width): 209 # Do not allow writes to indexed I/O buffer 210 assert False, "Cannot write to indexed I/O buffers" 211 212class BufferField(Object): 213 def __init__(self, buf, field): 214 self.__buf = buf 215 self.__field = field 216 217 def get(self): 218 return self.__buf.read_field(self.__field) 219 220 def set(self, obj): 221 self.__buf.write_field(self.__field, obj.get()) 222 223 def set_writable(self): 224 self.__buf.set_field_writable(self.__field) 225 226 def to_integer(self): 227 return Integer(self.get()) 228 229 def to_buffer(self): 230 bitwidth = self.__buf.field_bitwidth(self.__field) 231 return Buffer(self.get().to_bytes((bitwidth + 7) // 8, sys.byteorder)) 232 233 def to_string(self): 234 return f"BufferField({self.__field})" 235 236 def to_hex_string(self): 237 return String(hex(self.get())[2:]) 238 239# DebugObject 240 241class Device(Object): 242 def __init__(self, sym): 243 self.__sym = sym 244 245 def get_sym(self): 246 return self.__sym 247 248# Event 249 250class FieldUnit(BufferField): 251 def to_string(self): 252 return "Field" 253 254class Integer(Object): 255 def __init__(self, value, width=64): 256 self.__value = value 257 self.__width = width 258 259 def get(self): 260 return self.__value 261 262 def set(self, obj): 263 self.__value = obj.get() 264 265 def to_buffer(self): 266 assert self.__width % 8 == 0 267 data = bytearray() 268 i = 0 269 v = self.__value 270 while i < self.__width: 271 data.append(v & 0xff) 272 v >>= 8 273 i += 8 274 return Buffer(data) 275 276 def to_decimal_string(self): 277 return String(str(self.__value)) 278 279 def to_hex_string(self): 280 return String(hex(self.__value)[2:]) 281 282 def to_integer(self): 283 return self 284 285class Method(Object): 286 def __init__(self, tree): 287 self.tree = tree 288 self.name = tree.children[1].value 289 self.body = tree.children[3] 290 291class PredefinedMethod(Object): 292 def __init__(self, fn): 293 self.fn = fn 294 295# Mutex 296 297class ObjectReference(Object): 298 def __init__(self, obj, index=None): 299 self.__obj = obj 300 self.__index = index 301 302 def get(self): 303 if self.__index is not None: 304 if isinstance(self.__obj, Package): 305 return self.__obj.elements[self.__index] 306 elif isinstance(self.__obj, Buffer): 307 name = f"byte_{hex(self.__index)[2:]}" 308 self.__obj.create_field(name, self.__index * 8, 8, 8) 309 return BufferField(self.__obj, name) 310 else: 311 raise NotImplementedError(self.__obj.__class__.__name__) 312 else: 313 return self.__obj 314 315 def set(self, obj, index=None): 316 self.__obj = obj 317 self.__index = index 318 319class OperationRegion(Object): 320 devmem = None 321 devport = None 322 opened_indexed_regions = {} 323 324 @classmethod 325 def open_system_memory(cls, name, offset, length): 326 if not cls.devmem: 327 cls.devmem = open("/dev/mem", "rb", buffering=0) 328 329 logging.debug(f"Open system memory space {name}: [{hex(offset)}, {hex(offset + length - 1)}]") 330 offset_page_aligned = (offset >> 12) << 12 331 length_page_aligned = ceil(((offset & 0xFFF) + length) / 0x1000) * 0x1000 332 try: 333 mm = mmap.mmap(cls.devmem.fileno(), length_page_aligned, flags=mmap.MAP_PRIVATE, prot=mmap.PROT_READ, offset=offset_page_aligned) 334 except PermissionError as e: 335 logging.debug(f"Do not have permission to access [{hex(offset_page_aligned)}, {hex(offset_page_aligned + length_page_aligned)}] by /dev/mem.") 336 logging.debug(f"You may need to add `iomem=relaxed` to the Linux kernel command line in your bootloader configuration file.") 337 raise 338 iobuf = StreamIOBuffer(mm, offset & 0xFFF, length) 339 return OperationRegion(iobuf) 340 341 @classmethod 342 def open_system_io(cls, name, offset, length): 343 if not cls.devport: 344 cls.devport = open("/dev/port", "w+b", buffering=0) 345 346 logging.debug(f"Open system I/O space {name}: [{hex(offset)}, {hex(offset + length - 1)}]") 347 iobuf = StreamIOBuffer(cls.devport, offset, length) 348 return OperationRegion(iobuf) 349 350 @classmethod 351 def open_pci_configuration_space(cls, bus_number, device_adr, offset, length): 352 assert offset <= 0xFF and (offset + length) <= 0x100 353 # Assume bus is 0 for now 354 bus = bus_number 355 device = device_adr >> 16 356 function = device_adr & 0xFF 357 sysfs_path = "/sys/devices/pci0000:%02x/0000:%02x:%02x.%d/config" % (bus, bus, device, function) 358 try: 359 f = open(sysfs_path, "rb", buffering=0) 360 iobuf = StreamIOBuffer(f, offset, length) 361 return OperationRegion(iobuf) 362 except FileNotFoundError: 363 logging.debug(f"Cannot read the configuration space of %02x:%02x.%d from {sysfs_path}. Assume the PCI device does not exist." % (bus, device, function)) 364 data = bytearray([0xff]) * length 365 buf = Buffer(data) 366 return OperationRegion(buf) 367 368 @classmethod 369 def open_indexed_region(cls, index_register, data_register): 370 logging.debug(f"Open I/O region indexed by index register {index_register.to_string()} and data register {data_register.to_string()}.") 371 k = (str(index_register), str(data_register)) 372 if k not in cls.opened_indexed_regions.keys(): 373 iobuf = IndexedIOBuffer(index_register, data_register) 374 region = OperationRegion(iobuf) 375 cls.opened_indexed_regions[k] = region 376 377 # Mark the index register as writable 378 index_register.set_writable() 379 380 return region 381 else: 382 return cls.opened_indexed_regions[k] 383 384 def __init__(self, iobuf): 385 self.__iobuf = iobuf 386 self.__writable_fields = set() 387 388 def create_field(self, name, offset, bitwidth, access_width): 389 self.__iobuf.create_field(name, offset, bitwidth, access_width) 390 391 def read_field(self, name): 392 return self.__iobuf.read_field(name) 393 394 def field_bitwidth(self, name): 395 return self.__iobuf.field_bitwidth(name) 396 397 def write_field(self, name, value): 398 # Do not allow writes to stream I/O buffer unless the base is explicitly marked as writable 399 if name in self.__writable_fields: 400 self.__iobuf.write_field(name, value) 401 else: 402 if isinstance(value, int): 403 logging.debug(f"Skip writing 0x{value:0X} to I/O field {name}") 404 else: 405 logging.debug(f"Skip writing {value} to I/O field {name}") 406 407 def set_field_writable(self, name): 408 self.__writable_fields.add(name) 409 410 def to_string(self): 411 return "Operation Region" 412 413class Package(Object): 414 def __init__(self, elements): 415 self.__elements = elements 416 417 @property 418 def elements(self): 419 return self.__elements 420 421 def to_string(self): 422 return "Package" 423 424class PowerResource(Object): 425 def __init__(self, name): 426 self.name = name 427 428# Processor 429 430class RawDataBuffer(Object): 431 def __init__(self, data): 432 self.__data = data 433 434 def get(self): 435 return self.__data 436 437class String(Object): 438 def __init__(self, s): 439 self.__s = s 440 441 def get(self): 442 return self.__s 443 444 def set(self, obj): 445 self.__s = obj.get() 446 447 def to_decimal_string(self): 448 return self 449 450 def to_hex_string(self): 451 return self 452 453 def to_integer(self): 454 return Integer(int(self.__s, base=16)) 455 456 def to_string(self): 457 return self 458 459# ThermalZone 460