1#!/usr/bin/env python3 2COPYRIGHT = """\ 3/* 4 * Copyright 2024 Intel Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26""" 27 28import hashlib 29import os 30import sys 31 32from mako.template import Template 33from mako import exceptions 34 35from intel_device_info import TYPES, TYPES_BY_NAME, FUNDAMENTAL_TYPES, Enum 36 37template = COPYRIGHT + """ 38 39/* DO NOT EDIT - This file generated automatically by intel_device_serialize_c.py script */ 40 41#include "dev/intel_device_info_serialize.h" 42#include "util/parson.h" 43<%! import intel_device_info %> 44% for decl in TYPES: 45% if isinstance(decl, intel_device_info.Enum): 46static JSON_Value * 47dump_${decl.name}(enum ${decl.name} arg) { 48 switch (arg) { 49% for value in decl.values: 50 case ${value}: 51 return json_value_init_string("${value}"); 52% endfor 53 default: 54 unreachable("invalid ${decl.name} value"); 55 } 56} 57 58static enum ${decl.name} 59load_${decl.name}(const char * val) { 60% for value in decl.values: 61 if (strcmp("${value}", val) == 0) 62 return ${value}; 63% endfor 64 assert(false); 65 return (enum ${decl.name}) -1; 66} 67 68% endif 69% if isinstance(decl, intel_device_info.Struct): 70static JSON_Value * 71dump_${decl.name}(const struct ${decl.name} *arg) { 72 JSON_Value *val = json_value_init_object(); 73 JSON_Object *json = json_object(val); 74% for member in decl.members: 75% if member.member_type in intel_device_info.INT_TYPES: 76% if member.array: 77 { 78 JSON_Value *jtmp = json_value_init_array(); 79 JSON_Array *jarray = json_array(jtmp); 80 for (unsigned i = 0; i < sizeof(arg->${member.name}) / sizeof(*arg->${member.name}); ++i) 81 json_array_append_number(jarray, arg->${member.name}[i]); 82 json_object_set_value(json, "${member.name}", jtmp); 83 } 84% else: 85 json_object_set_number(json, "${member.name}", arg->${member.name}); 86% endif 87% elif member.member_type == "char": 88 json_object_set_string(json, "${member.name}", arg->${member.name}); 89% elif member.member_type == "bool": 90 json_object_set_boolean(json, "${member.name}", arg->${member.name}); 91% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Enum): 92 json_object_set_value(json, "${member.name}", dump_${member.member_type}(arg->${member.name})); 93% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Struct): 94% if member.array: 95 { 96 JSON_Value *jtmp = json_value_init_array(); 97 JSON_Array *jarray = json_array(jtmp); 98 for (unsigned i = 0; i < sizeof(arg->${member.name}) / sizeof(*arg->${member.name}); ++i) 99 json_array_append_value(jarray, dump_${member.member_type}(&arg->${member.name}[i])); 100 json_object_set_value(json, "${member.name}", jtmp); 101 } 102% else: 103 json_object_set_value(json, "${member.name}", dump_${member.member_type}(&arg->${member.name})); 104% endif 105% endif 106% endfor 107 return val; 108} 109 110static void 111load_${decl.name}(JSON_Object *json, struct ${decl.name} *target) { 112% for member in decl.members: 113% if member.member_type in intel_device_info.INT_TYPES: 114% if member.array: 115 { 116 JSON_Array *array = json_object_get_array(json, "${member.name}"); 117 for (unsigned i = 0; i < json_array_get_count(array); ++i) 118 target->${member.name}[i] = json_array_get_number(array, i); 119 } 120% else: 121 target->${member.name} = json_object_get_number(json, "${member.name}"); 122% endif 123% elif member.member_type == "char": 124 strncpy(target->${member.name}, 125 json_object_get_string(json, "${member.name}"), 126 sizeof(target->${member.name}) - 1); 127% elif member.member_type == "bool": 128 target->${member.name} = json_object_get_boolean(json, "${member.name}"); 129% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Enum): 130 target->${member.name} = load_${member.member_type}(json_object_get_string(json, "${member.name}")); 131% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Struct): 132% if member.array: 133 { 134 JSON_Array *array = json_object_get_array(json, "${member.name}"); 135 for (unsigned i = 0; i < json_array_get_count(array); ++i) 136 load_${member.member_type}(json_array_get_object(array, i), target->${member.name} + i); 137 } 138% else: 139 load_${member.member_type}(json_object_get_object(json, "${member.name}"), &target->${member.name}); 140% endif 141% endif 142% endfor 143} 144 145% endif 146% endfor 147bool 148intel_device_info_from_json(const char *path, 149 struct intel_device_info *devinfo) { 150 JSON_Value *root = json_parse_file(path); 151 JSON_Object *obj = json_object(root); 152 const char *devinfo_type_sha1 = "${checksum}"; 153 154 /* verify that json was generated with a compatible driver */ 155 if (strncmp(devinfo_type_sha1, 156 json_object_get_string(obj, "devinfo_type_sha1"), 157 strlen(devinfo_type_sha1))) 158 return false; 159 load_intel_device_info(obj, devinfo); 160 161 /* override no_hw to indicate that the GPU has been stubbed */ 162 devinfo->no_hw = true; 163 164 json_value_free(root); 165 intel_device_info_init_was(devinfo); 166 return true; 167} 168 169JSON_Value * 170intel_device_info_dump_json(const struct intel_device_info *devinfo) { 171 JSON_Value * root = dump_intel_device_info(devinfo); 172 173 /* record a hash of the structure type declaration, to prevent loading with 174 * an incompatible driver 175 */ 176 JSON_Object *obj = json_object(root); 177 json_object_set_string(obj, "devinfo_type_sha1", "${checksum}"); 178 179 return root; 180} 181 182""" 183 184def declaration_checksum(typename): 185 """Calculate a stable checksum for the struct that will change whenever any 186 of the members change. We will refer to this value as the 'type declaration hash'""" 187 h = hashlib.new('sha1') 188 struct_description = TYPES_BY_NAME[typename] 189 for member in struct_description.members: 190 h.update(member.name.encode(encoding="utf-8")) 191 h.update(f"{member.array}".encode(encoding="utf-8")) 192 member_type = member.member_type 193 if member_type in FUNDAMENTAL_TYPES: 194 h.update(member_type.encode(encoding="utf-8")) 195 elif isinstance(TYPES_BY_NAME[member_type], Enum): 196 h.update(member_type.encode(encoding="utf-8")) 197 else: 198 # encode the type declaration hash for the nested struct 199 h.update(declaration_checksum(member_type).encode(encoding="utf-8")) 200 return h.hexdigest() 201 202def main(): 203 """print intel_device_serialize.c at the specified path""" 204 if len(sys.argv) > 1: 205 outf = open(sys.argv[1], 'w', encoding='utf-8') 206 else: 207 outf = sys.stdout 208 try: 209 outf.write(Template(template).render(TYPES=TYPES, 210 checksum=declaration_checksum("intel_device_info"))) 211 except: 212 print(exceptions.text_error_template().render( 213 TYPES=TYPES, 214 checksum=declaration_checksum("intel_device_info"))) 215 sys.exit(1) 216 outf.close() 217 218if __name__ == "__main__": 219 main() 220