1 /*
2  * Copyright (C) 2019-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /* cmos io device
8  * - nvram 0x10 ~ 0x1F is used for android device reboot to bootloader or
9  *   recovery or normal boot usage
10  * - vrpmb 0x20 ~ 0x9F is used to store vrpmb for guest, read to clear
11  */
12 
13 #include <stdio.h>
14 #include <stdbool.h>
15 
16 #include "inout.h"
17 #include "vmmapi.h"
18 #include "vrpmb.h"
19 #include "log.h"
20 
21 #define CMOS_ADDR		0x74
22 #define CMOS_DATA		0x75
23 
24 #define CMOS_NAME		"cmos_io"
25 #define CMOS_VRPMB_START	0x20
26 #define CMOS_VRPMB_END		0x9F
27 
28 /* cmos buffer used to store write/read contents,
29  * and it should not be cleared when reboot
30  */
31 static	uint8_t cmos_buffer[CMOS_BUF_SIZE];
32 
33 /* #define CMOS_DEBUG */
34 #ifdef CMOS_DEBUG
35 static FILE * dbg_file;
36 #define DPRINTF(format, args...) \
37 do { fprintf(dbg_file, format, args); fflush(dbg_file); } while (0)
38 #else
39 #define DPRINTF(format, arg...)
40 #endif
41 
42 static int
cmos_io_handler(struct vmctx * ctx,int vcpu,int in,int port,int bytes,uint32_t * eax,void * arg)43 cmos_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
44 				uint32_t *eax, void *arg)
45 {
46 	static int buf_offset;
47 	static int next_ops;  /* 0 for addr, 1 for data, in pair (addr,data)*/
48 
49 #ifdef CMOS_DEBUG
50 	if (!dbg_file)
51 		dbg_file = fopen("/tmp/cmos_log", "a+");
52 #endif
53 
54 	DPRINTF("%s port =0x%x, in=%d, size=%d, val=0x%x, ops=%d\n",
55 		__func__, port, in, bytes, (uint8_t)*eax, next_ops);
56 
57 	if (port == CMOS_ADDR) {
58 
59 		/* if port is addr, ops should be 0 */
60 		if (next_ops != 0) {
61 			next_ops = 0;
62 			return -1;
63 		}
64 
65 		buf_offset = (uint8_t)(*eax);
66 		next_ops = 1;
67 
68 	} else if (port == CMOS_DATA) {
69 
70 		if (next_ops != 1) {
71 			next_ops = 0;
72 			return -1;
73 		}
74 
75 		if (in) {
76 			*eax = cmos_buffer[buf_offset];
77 			/* read to clear for Key range */
78 			if ((buf_offset >= CMOS_VRPMB_START) &&
79 			    (buf_offset <= CMOS_VRPMB_END))
80 				cmos_buffer[buf_offset] = 0;
81 		}
82 		else
83 			cmos_buffer[buf_offset] = (uint8_t)*eax;
84 
85 		next_ops = 0;
86 	}
87 
88 	return 0;
89 }
90 
91 INOUT_PORT(cmos_io, CMOS_ADDR, IOPORT_F_INOUT, cmos_io_handler);
92 INOUT_PORT(cmos_io, CMOS_DATA, IOPORT_F_INOUT, cmos_io_handler);
93 
init_cmos_vrpmb(struct vmctx * ctx)94 int init_cmos_vrpmb(struct vmctx *ctx)
95 {
96 	uint8_t *vrpmb_buffer = &cmos_buffer[CMOS_VRPMB_START];
97 
98 	/* get vrpmb key, and store it to cmos buffer */
99 	if (!get_vrpmb_key(vrpmb_buffer, RPMB_KEY_LEN)) {
100 		pr_err("SW_LOAD: failed to get vrpmb key\n");
101 		return -1;
102 	}
103 	return 0;
104 }
105