1#!/usr/bin/env python3 2# © 2021 Qualcomm Innovation Center, Inc. All rights reserved. 3# 4# SPDX-License-Identifier: BSD-3-Clause 5 6import abc 7 8 9class CType: 10 def __init__(self, name, is_signed, size, align=None, bitsize=None): 11 self.name = name 12 self.is_signed = is_signed 13 self.size = size 14 self.align = size if align is None else align 15 self.bitsize = bitsize 16 17 18class ABI(metaclass=abc.ABCMeta): 19 """ 20 Abstract base class for ABI definitions. 21 """ 22 23 def __init__(self): 24 basic_ctypes = ( 25 CType('bool', False, 1, bitsize=1), 26 CType('uint8_t', False, 1), 27 CType('uint16_t', False, 2), 28 CType('uint32_t', False, 4), 29 CType('uint64_t', False, 8), 30 CType('uintptr_t', False, self.pointer_size, 31 align=self.pointer_align), 32 CType('int8_t', True, 1), 33 CType('int16_t', True, 2), 34 CType('int32_t', True, 4), 35 CType('int64_t', True, 8), 36 CType('intptr_t', True, self.pointer_size, 37 align=self.pointer_align), 38 CType('char', self.signed_char, 1), 39 CType('size_t', False, self.pointer_size, 40 align=self.pointer_align), 41 CType('uregister_t', False, self.register_size, 42 align=self.register_align), 43 ) 44 self.c_types = {t.name: t for t in basic_ctypes} 45 46 @staticmethod 47 def is_power2(val): 48 """Returns true if number is a power of two""" 49 return ((val & (val - 1)) == 0) and (val > 0) 50 51 @abc.abstractproperty 52 def pointer_size(self): 53 """The size of a pointer, in bytes.""" 54 raise NotImplementedError 55 56 @property 57 def pointer_align(self): 58 """The alignment of a pointer, in bytes.""" 59 return self.pointer_size 60 61 @abc.abstractproperty 62 def register_size(self): 63 """The size of a register, in bytes.""" 64 raise NotImplementedError 65 66 @property 67 def register_align(self): 68 """The alignment of a register, in bytes.""" 69 return self.pointer_size 70 71 @abc.abstractproperty 72 def signed_char(self): 73 """True if the char type is signed.""" 74 raise NotImplementedError 75 76 def get_c_type(self, type_name): 77 return self.c_types[type_name] 78 79 @abc.abstractmethod 80 def get_c_type_name(self, abi_type_name): 81 """Return the c name for the abi type name.""" 82 raise NotImplementedError 83 84 def layout_struct_member(self, current_offset, current_alignment, 85 next_size, next_alignment): 86 """ 87 Return the offset at which a new struct member should be placed. 88 89 In principle this is entirely implementation-defined, but nearly all 90 implementations use the same algorithm: add enough padding bytes to 91 align the next member, and no more. Any ABI that does something 92 different can override this. 93 94 The current_offset argument is the size of the structure in bytes up 95 to the end of the last member. This is always nonzero, because 96 structures are not allowed to be padded at the start, so this function 97 is only called for the second member onwards. 98 99 The current_align argument is the largest alignment that has been seen 100 in the members added to the struct so far. 101 102 If next_size is not None, the next_size and next_alignment arguments 103 are the size and alignment of the member that is being added to the 104 struct. The return value in this case is the offset of the new member. 105 106 If next_size is None, all members have been added and this function 107 should determine the amount of padding at the end of the structure. 108 The return value in this case is the final size of the structure. 109 110 The return value in any case should be an integer that is not less 111 than current_offset. 112 """ 113 if next_size is not None: 114 alignment = next_alignment 115 else: 116 alignment = current_alignment 117 assert (self.is_power2(alignment)) 118 119 align_mask = alignment - 1 120 return (current_offset + align_mask) & ~align_mask 121 122 @abc.abstractmethod 123 def get_enum_properties(self, e_min, e_max): 124 """ 125 Returns the size, alignment and signedness of the enum. 126 127 Calculates the underlying type properties that the ABI will use for 128 an enum with the given enumerator value range. 129 """ 130 raise NotImplementedError 131 132 133class AArch64ABI(ABI): 134 abi_type_map = { 135 'uregister_t': 'uint64_t', 136 'sregister_t': 'int64_t', 137 } 138 139 @property 140 def pointer_size(self): 141 """The size of a pointer, in bytes.""" 142 return 8 143 144 @property 145 def register_size(self): 146 """The size of a register, in bytes.""" 147 return 8 148 149 @property 150 def signed_char(self): 151 """True if the char type is signed.""" 152 return True 153 154 def get_c_type_name(self, abi_type_name): 155 """Return the c name for the abi type name.""" 156 assert (abi_type_name in self.abi_type_map) 157 return self.abi_type_map[abi_type_name] 158 159 def get_enum_properties(self, e_min, e_max): 160 """ 161 Returns the size, alignment and signedness of the enum. 162 163 Calculates the underlying type properties that the ABI will use for 164 an enum with the given enumerator value range. 165 """ 166 167 min_bits = e_min.bit_length() 168 max_bits = e_max.bit_length() 169 170 signed = e_min < 0 171 172 if not signed and max_bits <= 32: 173 return (4, 4, False) 174 elif signed and max_bits <= 31 and min_bits <= 32: 175 return (4, 4, True) 176 elif not signed and max_bits <= 64: 177 return (8, 8, False) 178 elif signed and max_bits <= 63 and min_bits <= 64: 179 return (8, 8, True) 180 else: 181 raise NotImplementedError 182