1# 2# Copyright (c) 2010-2024 Antmicro 3# 4# This file is licensed under the MIT License. 5# Full license text is available in 'licenses/MIT.txt'. 6# 7 8from array import array 9import ctypes 10 11from Antmicro.Renode.Peripherals.CPU import RegisterValue 12 13try: 14 # The additional CLR reference is required on dotnet 15 clr.AddReference("System.Security.Cryptography.Algorithms") 16except: 17 pass 18 19from System.Security.Cryptography import SHA256, SHA384, SHA512 20 21 22def register_bootrom_hook(addr, func): 23 self["sysbus.cpu"].AddHook(addr, func) 24 # Fill the bootrom's function pointer entry with the address that the hook is registered to. 25 # For simplicity hooks are added on function pointer locations, no the actual function addresses. 26 self.SystemBus.WriteDoubleWord(addr, addr) 27 self.InfoLog("Registering bootrom function at 0x{0:X}", addr) 28 29 30# Based on: https://chromium.googlesource.com/chromiumos/platform/ec/+/6898a6542ed0238cc182948f56e3811534db1a38/chip/npcx/header.c#43 31def register_bootloader(): 32 class FirmwareHeader(ctypes.LittleEndianStructure): 33 _pack_ = 1 34 _fields_ = [ 35 ("anchor", ctypes.c_uint32), 36 ("ext_anchor", ctypes.c_uint16), 37 ("spi_max_freq", ctypes.c_uint8), 38 ("spi_read_mode", ctypes.c_uint8), 39 ("cfg_err_detect", ctypes.c_uint8), 40 ("fw_load_addr", ctypes.c_uint32), 41 ("fw_entry", ctypes.c_uint32), 42 ("err_detect_start_addr", ctypes.c_uint32), 43 ("err_detect_end_addr", ctypes.c_uint32), 44 ("fw_length", ctypes.c_uint32), 45 ("flash_size", ctypes.c_uint8), 46 ("reserved", ctypes.c_uint8 * 26), 47 ("sig_header", ctypes.c_uint32), 48 ("sig_fw_image", ctypes.c_uint32), 49 ] 50 51 HEADER_SIZE = ctypes.sizeof(FirmwareHeader) 52 flash = self["sysbus.internal_flash"] 53 54 def bootloader(cpu, addr): 55 header_data = flash.ReadBytes(0x0, HEADER_SIZE) 56 header = FirmwareHeader.from_buffer(array("B", header_data)) 57 58 firmware = flash.ReadBytes(HEADER_SIZE, header.fw_length) 59 self.SystemBus.WriteBytes(firmware, header.fw_load_addr) 60 61 cpu.PC = RegisterValue.Create(header.fw_entry, 32) 62 63 self.InfoLog( 64 "Firmware loaded at: 0x{0:X} ({1} bytes). PC = 0x{2:X}", 65 header.fw_load_addr, 66 header.fw_length, 67 header.fw_entry, 68 ) 69 70 register_bootrom_hook(0x0, bootloader) 71 72 73# Based on: 74# - https://chromium.googlesource.com/chromiumos/platform/ec/+/6898a6542ed0238cc182948f56e3811534db1a38/chip/npcx/trng.c 75# - https://chromium.googlesource.com/chromiumos/platform/ec/+/6898a6542ed0238cc182948f56e3811534db1a38/chip/npcx/sha256_chip.c 76def register_ncl_functions(): 77 DRGB_BASE_ADDRESS = 0x00000110 78 SHA_BASE_ADDRESS = 0x0000013C 79 80 POINTER_SIZE = 0x4 81 82 DRBG_CONTEXT_SIZE = 240 83 SHA_CONTEXT_SIZE = 212 84 85 NCL_STATUS_OK = 0xA5A5 86 NCL_STATUS_FAIL = 0x5A5A 87 NCL_STATUS_INVALID_PARAM = 0x02 88 89 NCL_SHA_TYPE_2_256 = 0 90 NCL_SHA_TYPE_2_384 = 1 91 NCL_SHA_TYPE_2_512 = 2 92 93 def create_hook(name, return_value=NCL_STATUS_OK): 94 def hook(cpu, addr): 95 cpu.NoisyLog( 96 "Entering '{0}' hook that returns 0x{1:X}", name, return_value 97 ) 98 cpu.SetRegister(0, RegisterValue.Create(return_value, 32)) 99 cpu.PC = cpu.LR 100 101 return hook 102 103 rng = Antmicro.Renode.Core.PseudorandomNumberGenerator() 104 105 def trng_generate(cpu, addr): 106 out_buff = cpu.GetRegister(3).RawValue 107 out_buff_len = self.SystemBus.ReadDoubleWord(cpu.SP.RawValue) 108 109 data = System.Array[System.Byte](range(out_buff_len)) 110 rng.NextBytes(data) 111 self.SystemBus.WriteBytes(data, out_buff) 112 113 cpu.SetRegister(0, RegisterValue.Create(NCL_STATUS_OK, 32)) 114 cpu.PC = cpu.LR 115 116 DRGB_FUNCTIONS = [ 117 create_hook("get_context_size", DRBG_CONTEXT_SIZE), 118 create_hook("init_context"), 119 create_hook("power"), 120 create_hook("finalize_context"), 121 create_hook("init"), 122 create_hook("config"), 123 create_hook("instantiate"), 124 create_hook("uninstantiate"), 125 create_hook("reseed"), 126 trng_generate, 127 create_hook("clear"), 128 ] 129 130 class SHAContext: 131 sha_buffer = System.Collections.Generic.List[System.Byte]() 132 sha_type = None 133 134 def sha_start(cpu, addr): 135 status = NCL_STATUS_OK 136 sha_type = cpu.GetRegister(1).RawValue 137 if sha_type in [ 138 NCL_SHA_TYPE_2_256, 139 NCL_SHA_TYPE_2_384, 140 NCL_SHA_TYPE_2_512, 141 ]: 142 SHAContext.sha_type = sha_type 143 else: 144 status = NCL_STATUS_INVALID_PARAM 145 cpu.SetRegister(0, RegisterValue.Create(status, 32)) 146 cpu.PC = cpu.LR 147 148 def sha_finish(cpu, addr): 149 try: 150 if SHAContext.sha_type == NCL_SHA_TYPE_2_256: 151 sha_instance = SHA256.Create() 152 elif SHAContext.sha_type == NCL_SHA_TYPE_2_384: 153 sha_instance = SHA384.Create() 154 elif SHAContext.sha_type == NCL_SHA_TYPE_2_512: 155 sha_instance = SHA512.Create() 156 else: 157 cpu.SetRegister( 158 0, RegisterValue.Create(NCL_STATUS_FAIL, 32) 159 ) 160 cpu.PC = cpu.LR 161 return 162 163 hash = sha_instance.ComputeHash(SHAContext.sha_buffer.ToArray()) 164 SHAContext.sha_buffer.Clear() 165 166 data_addr = cpu.GetRegister(1).RawValue 167 self.SystemBus.WriteBytes(hash, data_addr) 168 169 cpu.SetRegister(0, RegisterValue.Create(NCL_STATUS_OK, 32)) 170 cpu.PC = cpu.LR 171 finally: 172 if sha_instance is not None: 173 sha_instance.Dispose() 174 175 def sha_update(cpu, addr): 176 data_addr = cpu.GetRegister(1).RawValue 177 length = cpu.GetRegister(2).RawValue 178 data = self.SystemBus.ReadBytes(data_addr, length) 179 180 SHAContext.sha_buffer.AddRange(data) 181 182 cpu.SetRegister(0, RegisterValue.Create(NCL_STATUS_OK, 32)) 183 cpu.PC = cpu.LR 184 185 SHA_FUNCTIONS = [ 186 create_hook("get_context_size", SHA_CONTEXT_SIZE), 187 create_hook("init_context"), 188 create_hook("finalize_context"), 189 create_hook("init"), 190 sha_start, 191 sha_update, 192 sha_finish, 193 create_hook("calc"), 194 create_hook("power"), 195 create_hook("reset"), 196 ] 197 198 for base, collection in [ 199 (DRGB_BASE_ADDRESS, DRGB_FUNCTIONS), 200 (SHA_BASE_ADDRESS, SHA_FUNCTIONS), 201 ]: 202 for i, func in enumerate(collection): 203 register_bootrom_hook(base + i * POINTER_SIZE, func) 204 205 206# Based on: https://chromium.googlesource.com/chromiumos/platform/ec/+/6898a6542ed0238cc182948f56e3811534db1a38/chip/npcx/rom_chip.h 207def register_download_from_flash(): 208 def download_from_flash(cpu, addr): 209 src_offset = cpu.GetRegister(0).RawValue 210 dest_addr = cpu.GetRegister(1).RawValue 211 size = cpu.GetRegister(2).RawValue 212 exe_addr = self.SystemBus.ReadDoubleWord(cpu.SP.RawValue) 213 214 data = self["sysbus.internal_flash"].ReadBytes(src_offset, size) 215 self.SystemBus.WriteBytes(data, dest_addr) 216 217 cpu.PC = RegisterValue.Create(exe_addr, 32) 218 219 cpu.InfoLog( 220 "Downloading from flash offset 0x{0:X} to 0x{1:X} ({2} bytes) and jumping to 0x{3:X}", 221 src_offset, 222 dest_addr, 223 size, 224 exe_addr, 225 ) 226 227 register_bootrom_hook(0x40, download_from_flash) 228 229 230register_bootloader() 231register_ncl_functions() 232register_download_from_flash() 233