/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* cmos io device * - nvram 0x10 ~ 0x1F is used for android device reboot to bootloader or * recovery or normal boot usage * - vrpmb 0x20 ~ 0x9F is used to store vrpmb for guest, read to clear */ #include #include #include "inout.h" #include "vmmapi.h" #include "vrpmb.h" #include "log.h" #define CMOS_ADDR 0x74 #define CMOS_DATA 0x75 #define CMOS_NAME "cmos_io" #define CMOS_VRPMB_START 0x20 #define CMOS_VRPMB_END 0x9F /* cmos buffer used to store write/read contents, * and it should not be cleared when reboot */ static uint8_t cmos_buffer[CMOS_BUF_SIZE]; /* #define CMOS_DEBUG */ #ifdef CMOS_DEBUG static FILE * dbg_file; #define DPRINTF(format, args...) \ do { fprintf(dbg_file, format, args); fflush(dbg_file); } while (0) #else #define DPRINTF(format, arg...) #endif static int cmos_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { static int buf_offset; static int next_ops; /* 0 for addr, 1 for data, in pair (addr,data)*/ #ifdef CMOS_DEBUG if (!dbg_file) dbg_file = fopen("/tmp/cmos_log", "a+"); #endif DPRINTF("%s port =0x%x, in=%d, size=%d, val=0x%x, ops=%d\n", __func__, port, in, bytes, (uint8_t)*eax, next_ops); if (port == CMOS_ADDR) { /* if port is addr, ops should be 0 */ if (next_ops != 0) { next_ops = 0; return -1; } buf_offset = (uint8_t)(*eax); next_ops = 1; } else if (port == CMOS_DATA) { if (next_ops != 1) { next_ops = 0; return -1; } if (in) { *eax = cmos_buffer[buf_offset]; /* read to clear for Key range */ if ((buf_offset >= CMOS_VRPMB_START) && (buf_offset <= CMOS_VRPMB_END)) cmos_buffer[buf_offset] = 0; } else cmos_buffer[buf_offset] = (uint8_t)*eax; next_ops = 0; } return 0; } INOUT_PORT(cmos_io, CMOS_ADDR, IOPORT_F_INOUT, cmos_io_handler); INOUT_PORT(cmos_io, CMOS_DATA, IOPORT_F_INOUT, cmos_io_handler); int init_cmos_vrpmb(struct vmctx *ctx) { uint8_t *vrpmb_buffer = &cmos_buffer[CMOS_VRPMB_START]; /* get vrpmb key, and store it to cmos buffer */ if (!get_vrpmb_key(vrpmb_buffer, RPMB_KEY_LEN)) { pr_err("SW_LOAD: failed to get vrpmb key\n"); return -1; } return 0; }