1*b29b4195SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 2*b29b4195SJens Wiklander /* Copyright (c) 2018, Linaro Limited */ 3*b29b4195SJens Wiklander 4*b29b4195SJens Wiklander #include <ta_avb.h> 5*b29b4195SJens Wiklander #include <tee_internal_api.h> 6*b29b4195SJens Wiklander #include <tee_internal_api_extensions.h> 7*b29b4195SJens Wiklander 8*b29b4195SJens Wiklander #define DEFAULT_LOCK_STATE 0 9*b29b4195SJens Wiklander 10*b29b4195SJens Wiklander static const uint32_t storageid = TEE_STORAGE_PRIVATE_RPMB; 11*b29b4195SJens Wiklander static const char obj_name[] = "rb_state"; 12*b29b4195SJens Wiklander 13*b29b4195SJens Wiklander static TEE_Result get_slot_offset(size_t slot, size_t *offset) 14*b29b4195SJens Wiklander { 15*b29b4195SJens Wiklander if (slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS) 16*b29b4195SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 17*b29b4195SJens Wiklander 18*b29b4195SJens Wiklander *offset = sizeof(uint32_t) /* lock_state */ + slot * sizeof(uint64_t); 19*b29b4195SJens Wiklander return TEE_SUCCESS; 20*b29b4195SJens Wiklander } 21*b29b4195SJens Wiklander 22*b29b4195SJens Wiklander static TEE_Result create_state(uint32_t lock_state, TEE_ObjectHandle *h) 23*b29b4195SJens Wiklander { 24*b29b4195SJens Wiklander const uint32_t flags = TEE_DATA_FLAG_ACCESS_READ | 25*b29b4195SJens Wiklander TEE_DATA_FLAG_ACCESS_WRITE | 26*b29b4195SJens Wiklander TEE_DATA_FLAG_OVERWRITE; 27*b29b4195SJens Wiklander 28*b29b4195SJens Wiklander return TEE_CreatePersistentObject(storageid, obj_name, sizeof(obj_name), 29*b29b4195SJens Wiklander flags, NULL, &lock_state, 30*b29b4195SJens Wiklander sizeof(lock_state), h); 31*b29b4195SJens Wiklander } 32*b29b4195SJens Wiklander 33*b29b4195SJens Wiklander static TEE_Result open_state(uint32_t default_lock_state, TEE_ObjectHandle *h) 34*b29b4195SJens Wiklander { 35*b29b4195SJens Wiklander uint32_t flags = TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE; 36*b29b4195SJens Wiklander TEE_Result res; 37*b29b4195SJens Wiklander 38*b29b4195SJens Wiklander res = TEE_OpenPersistentObject(storageid, obj_name, 39*b29b4195SJens Wiklander sizeof(obj_name), flags, h); 40*b29b4195SJens Wiklander if (!res) 41*b29b4195SJens Wiklander return TEE_SUCCESS; 42*b29b4195SJens Wiklander 43*b29b4195SJens Wiklander return create_state(default_lock_state, h); 44*b29b4195SJens Wiklander } 45*b29b4195SJens Wiklander 46*b29b4195SJens Wiklander static TEE_Result read_rb_idx(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) 47*b29b4195SJens Wiklander { 48*b29b4195SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 49*b29b4195SJens Wiklander TEE_PARAM_TYPE_VALUE_OUTPUT, 50*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE, 51*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE); 52*b29b4195SJens Wiklander size_t slot_offset; 53*b29b4195SJens Wiklander uint64_t idx; 54*b29b4195SJens Wiklander uint32_t count; 55*b29b4195SJens Wiklander TEE_Result res; 56*b29b4195SJens Wiklander TEE_ObjectHandle h; 57*b29b4195SJens Wiklander 58*b29b4195SJens Wiklander if (pt != exp_pt) 59*b29b4195SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 60*b29b4195SJens Wiklander 61*b29b4195SJens Wiklander res = get_slot_offset(params[0].value.a, &slot_offset); 62*b29b4195SJens Wiklander if (res) 63*b29b4195SJens Wiklander return res; 64*b29b4195SJens Wiklander 65*b29b4195SJens Wiklander res = open_state(DEFAULT_LOCK_STATE, &h); 66*b29b4195SJens Wiklander if (res) 67*b29b4195SJens Wiklander return res; 68*b29b4195SJens Wiklander 69*b29b4195SJens Wiklander res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET); 70*b29b4195SJens Wiklander if (res) 71*b29b4195SJens Wiklander goto out; 72*b29b4195SJens Wiklander 73*b29b4195SJens Wiklander res = TEE_ReadObjectData(h, &idx, sizeof(idx), &count); 74*b29b4195SJens Wiklander if (res) 75*b29b4195SJens Wiklander goto out; 76*b29b4195SJens Wiklander if (count != sizeof(idx)) { 77*b29b4195SJens Wiklander idx = 0; /* Not yet written slots are reported as 0 */ 78*b29b4195SJens Wiklander 79*b29b4195SJens Wiklander if (count) { 80*b29b4195SJens Wiklander /* 81*b29b4195SJens Wiklander * Somehow the file didn't even hold a complete 82*b29b4195SJens Wiklander * slot index entry. Write it as 0. 83*b29b4195SJens Wiklander */ 84*b29b4195SJens Wiklander res = TEE_SeekObjectData(h, slot_offset, 85*b29b4195SJens Wiklander TEE_DATA_SEEK_SET); 86*b29b4195SJens Wiklander if (res) 87*b29b4195SJens Wiklander goto out; 88*b29b4195SJens Wiklander res = TEE_WriteObjectData(h, &idx, sizeof(idx)); 89*b29b4195SJens Wiklander if (res) 90*b29b4195SJens Wiklander goto out; 91*b29b4195SJens Wiklander } 92*b29b4195SJens Wiklander } 93*b29b4195SJens Wiklander 94*b29b4195SJens Wiklander params[1].value.a = idx >> 32; 95*b29b4195SJens Wiklander params[1].value.b = idx; 96*b29b4195SJens Wiklander out: 97*b29b4195SJens Wiklander TEE_CloseObject(h); 98*b29b4195SJens Wiklander return res; 99*b29b4195SJens Wiklander } 100*b29b4195SJens Wiklander 101*b29b4195SJens Wiklander static TEE_Result write_rb_idx(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) 102*b29b4195SJens Wiklander { 103*b29b4195SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 104*b29b4195SJens Wiklander TEE_PARAM_TYPE_VALUE_INPUT, 105*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE, 106*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE); 107*b29b4195SJens Wiklander size_t slot_offset; 108*b29b4195SJens Wiklander uint64_t widx; 109*b29b4195SJens Wiklander uint64_t idx; 110*b29b4195SJens Wiklander uint32_t count; 111*b29b4195SJens Wiklander TEE_Result res; 112*b29b4195SJens Wiklander TEE_ObjectHandle h; 113*b29b4195SJens Wiklander 114*b29b4195SJens Wiklander if (pt != exp_pt) 115*b29b4195SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 116*b29b4195SJens Wiklander 117*b29b4195SJens Wiklander res = get_slot_offset(params[0].value.a, &slot_offset); 118*b29b4195SJens Wiklander if (res) 119*b29b4195SJens Wiklander return res; 120*b29b4195SJens Wiklander widx = ((uint64_t)params[1].value.a << 32) | params[1].value.b; 121*b29b4195SJens Wiklander 122*b29b4195SJens Wiklander res = open_state(DEFAULT_LOCK_STATE, &h); 123*b29b4195SJens Wiklander if (res) 124*b29b4195SJens Wiklander return res; 125*b29b4195SJens Wiklander 126*b29b4195SJens Wiklander res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET); 127*b29b4195SJens Wiklander if (res) 128*b29b4195SJens Wiklander goto out; 129*b29b4195SJens Wiklander 130*b29b4195SJens Wiklander res = TEE_ReadObjectData(h, &idx, sizeof(idx), &count); 131*b29b4195SJens Wiklander if (res) 132*b29b4195SJens Wiklander goto out; 133*b29b4195SJens Wiklander if (count != sizeof(idx)) 134*b29b4195SJens Wiklander idx = 0; /* Not yet written slots are reported as 0 */ 135*b29b4195SJens Wiklander 136*b29b4195SJens Wiklander if (widx < idx) { 137*b29b4195SJens Wiklander res = TEE_ERROR_SECURITY; 138*b29b4195SJens Wiklander goto out; 139*b29b4195SJens Wiklander } 140*b29b4195SJens Wiklander 141*b29b4195SJens Wiklander res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET); 142*b29b4195SJens Wiklander if (res) 143*b29b4195SJens Wiklander goto out; 144*b29b4195SJens Wiklander 145*b29b4195SJens Wiklander res = TEE_WriteObjectData(h, &widx, sizeof(widx)); 146*b29b4195SJens Wiklander out: 147*b29b4195SJens Wiklander TEE_CloseObject(h); 148*b29b4195SJens Wiklander return res; 149*b29b4195SJens Wiklander } 150*b29b4195SJens Wiklander 151*b29b4195SJens Wiklander static TEE_Result read_lock_state(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) 152*b29b4195SJens Wiklander { 153*b29b4195SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT, 154*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE, 155*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE, 156*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE); 157*b29b4195SJens Wiklander uint32_t lock_state; 158*b29b4195SJens Wiklander uint32_t count; 159*b29b4195SJens Wiklander TEE_Result res; 160*b29b4195SJens Wiklander TEE_ObjectHandle h; 161*b29b4195SJens Wiklander 162*b29b4195SJens Wiklander if (pt != exp_pt) 163*b29b4195SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 164*b29b4195SJens Wiklander 165*b29b4195SJens Wiklander res = open_state(DEFAULT_LOCK_STATE, &h); 166*b29b4195SJens Wiklander if (res) 167*b29b4195SJens Wiklander return res; 168*b29b4195SJens Wiklander 169*b29b4195SJens Wiklander res = TEE_ReadObjectData(h, &lock_state, sizeof(lock_state), &count); 170*b29b4195SJens Wiklander if (res) 171*b29b4195SJens Wiklander goto out; 172*b29b4195SJens Wiklander if (count != sizeof(lock_state)) { 173*b29b4195SJens Wiklander /* 174*b29b4195SJens Wiklander * Client need write the lock state to recover, this can 175*b29b4195SJens Wiklander * normally not happen. 176*b29b4195SJens Wiklander */ 177*b29b4195SJens Wiklander res = TEE_ERROR_CORRUPT_OBJECT; 178*b29b4195SJens Wiklander goto out; 179*b29b4195SJens Wiklander } 180*b29b4195SJens Wiklander 181*b29b4195SJens Wiklander params[0].value.a = lock_state; 182*b29b4195SJens Wiklander out: 183*b29b4195SJens Wiklander TEE_CloseObject(h); 184*b29b4195SJens Wiklander return res; 185*b29b4195SJens Wiklander } 186*b29b4195SJens Wiklander 187*b29b4195SJens Wiklander static TEE_Result write_lock_state(uint32_t pt, 188*b29b4195SJens Wiklander TEE_Param params[TEE_NUM_PARAMS]) 189*b29b4195SJens Wiklander { 190*b29b4195SJens Wiklander const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 191*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE, 192*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE, 193*b29b4195SJens Wiklander TEE_PARAM_TYPE_NONE); 194*b29b4195SJens Wiklander uint32_t wlock_state; 195*b29b4195SJens Wiklander uint32_t lock_state; 196*b29b4195SJens Wiklander uint32_t count; 197*b29b4195SJens Wiklander TEE_Result res; 198*b29b4195SJens Wiklander TEE_ObjectHandle h; 199*b29b4195SJens Wiklander 200*b29b4195SJens Wiklander if (pt != exp_pt) 201*b29b4195SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 202*b29b4195SJens Wiklander 203*b29b4195SJens Wiklander wlock_state = params[0].value.a; 204*b29b4195SJens Wiklander 205*b29b4195SJens Wiklander res = open_state(wlock_state, &h); 206*b29b4195SJens Wiklander if (res) 207*b29b4195SJens Wiklander return res; 208*b29b4195SJens Wiklander 209*b29b4195SJens Wiklander res = TEE_ReadObjectData(h, &lock_state, sizeof(lock_state), &count); 210*b29b4195SJens Wiklander if (res) 211*b29b4195SJens Wiklander goto out; 212*b29b4195SJens Wiklander if (count == sizeof(lock_state) && lock_state == wlock_state) 213*b29b4195SJens Wiklander goto out; 214*b29b4195SJens Wiklander 215*b29b4195SJens Wiklander res = create_state(wlock_state, &h); 216*b29b4195SJens Wiklander out: 217*b29b4195SJens Wiklander TEE_CloseObject(h); 218*b29b4195SJens Wiklander return res; 219*b29b4195SJens Wiklander } 220*b29b4195SJens Wiklander 221*b29b4195SJens Wiklander TEE_Result TA_CreateEntryPoint(void) 222*b29b4195SJens Wiklander { 223*b29b4195SJens Wiklander return TEE_SUCCESS; 224*b29b4195SJens Wiklander } 225*b29b4195SJens Wiklander 226*b29b4195SJens Wiklander void TA_DestroyEntryPoint(void) 227*b29b4195SJens Wiklander { 228*b29b4195SJens Wiklander } 229*b29b4195SJens Wiklander 230*b29b4195SJens Wiklander TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused, 231*b29b4195SJens Wiklander TEE_Param params[4] __unused, 232*b29b4195SJens Wiklander void **session __unused) 233*b29b4195SJens Wiklander { 234*b29b4195SJens Wiklander return TEE_SUCCESS; 235*b29b4195SJens Wiklander } 236*b29b4195SJens Wiklander 237*b29b4195SJens Wiklander void TA_CloseSessionEntryPoint(void *sess __unused) 238*b29b4195SJens Wiklander { 239*b29b4195SJens Wiklander } 240*b29b4195SJens Wiklander 241*b29b4195SJens Wiklander TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd, 242*b29b4195SJens Wiklander uint32_t pt, 243*b29b4195SJens Wiklander TEE_Param params[TEE_NUM_PARAMS]) 244*b29b4195SJens Wiklander { 245*b29b4195SJens Wiklander switch (cmd) { 246*b29b4195SJens Wiklander case TA_AVB_CMD_READ_ROLLBACK_INDEX: 247*b29b4195SJens Wiklander return read_rb_idx(pt, params); 248*b29b4195SJens Wiklander case TA_AVB_CMD_WRITE_ROLLBACK_INDEX: 249*b29b4195SJens Wiklander return write_rb_idx(pt, params); 250*b29b4195SJens Wiklander case TA_AVB_CMD_READ_LOCK_STATE: 251*b29b4195SJens Wiklander return read_lock_state(pt, params); 252*b29b4195SJens Wiklander case TA_AVB_CMD_WRITE_LOCK_STATE: 253*b29b4195SJens Wiklander return write_lock_state(pt, params); 254*b29b4195SJens Wiklander default: 255*b29b4195SJens Wiklander EMSG("Command ID 0x%x is not supported", cmd); 256*b29b4195SJens Wiklander return TEE_ERROR_NOT_SUPPORTED; 257*b29b4195SJens Wiklander } 258*b29b4195SJens Wiklander } 259