1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 */
5
6#include <linux/proc_fs.h>
7
8#include "dsmm_developer.h"
9#include "xpm_log.h"
10
11#define DSMM_DIR "dsmm"
12#define DSMM_DEVELOPER_FILE "developer"
13#define DSMM_DEVELOPER_PARAM_NAME "const.security.developermode.state"
14
15static struct proc_dir_entry *g_dsmm_dir;
16static uint32_t developer_state = STATE_UNINT;
17
18static uint32_t g_state_table[BUILD_VARIANT_MAX][CMDLINE_DEV_STATE_MAX] = {
19	{ STATE_OFF, STATE_ON, STATE_OFF },
20	{ STATE_ON, STATE_ON, STATE_ON },
21};
22
23static int get_developer_status(uint32_t *status)
24{
25	if (!strstr(saved_command_line, "developer_mode=")) {
26		*status = CMDLINE_DEV_STATE_NA;
27	} else if (strstr(saved_command_line, "developer_mode=1")) {
28		*status = CMDLINE_DEV_STATE_ON;
29	} else if (strstr(saved_command_line, "developer_mode=0")) {
30		*status = CMDLINE_DEV_STATE_OFF;
31	} else {
32		xpm_log_error("invalid developer_mode value in cmdline");
33		return -EINVAL;
34	}
35
36	return 0;
37}
38
39static int get_build_variant(uint32_t *variant)
40{
41	if (strstr(saved_command_line, "buildvariant=user")) {
42		*variant = BUILD_VARIANT_USER;
43	} else if (strstr(saved_command_line, "buildvariant=eng")) {
44		*variant = BUILD_VARIANT_ENG;
45	} else {
46		xpm_log_error("invalid buildvariant value in cmdline");
47		return -EINVAL;
48	}
49
50	return 0;
51}
52
53int get_developer_mode_state(void)
54{
55	uint32_t variant, status;
56
57	if (developer_state != STATE_UNINT)
58		return developer_state;
59
60#ifdef CONFIG_DSMM_DEVELOPER_ENABLE
61	if (get_build_variant(&variant) || get_developer_status(&status)) {
62		xpm_log_error("get build variant or developer status failed");
63		developer_state = STATE_OFF;
64	} else {
65		developer_state = g_state_table[variant][status];
66	}
67#else
68	developer_state = STATE_ON;
69#endif
70
71	return developer_state;
72}
73
74#define PROC_DEVELOPER_LEN 50
75static ssize_t dsmm_read_developer_proc(struct file *file, char __user *buf,
76	size_t count, loff_t *pos)
77{
78	size_t len;
79	uint32_t state;
80	char proc_developer[PROC_DEVELOPER_LEN] = {0};
81
82	state = get_developer_mode_state();
83	len = snprintf(proc_developer, PROC_DEVELOPER_LEN - 1,
84		DSMM_DEVELOPER_PARAM_NAME"=%s",
85		state == STATE_ON ? "true" : "false");
86
87	return simple_read_from_buffer(buf, count, pos, proc_developer, len);
88}
89
90static const struct proc_ops dsmm_proc_fops_developer = {
91	.proc_read = dsmm_read_developer_proc,
92};
93
94void dsmm_developer_proc_create(void)
95{
96	g_dsmm_dir = proc_mkdir(DSMM_DIR, NULL);
97	if (!g_dsmm_dir) {
98		xpm_log_error("[%s] proc dir create failed", DSMM_DIR);
99		return;
100	}
101
102	if(!proc_create(DSMM_DEVELOPER_FILE, S_IRUGO, g_dsmm_dir,
103		&dsmm_proc_fops_developer)) {
104		xpm_log_error("[%s] proc file create failed",
105			DSMM_DEVELOPER_FILE);
106	}
107}
108
109void dsmm_developer_proc_clean(void)
110{
111	if (!g_dsmm_dir)
112		return;
113
114	remove_proc_entry(DSMM_DEVELOPER_FILE, g_dsmm_dir);
115	remove_proc_entry(DSMM_DIR, NULL);
116}
117