Linux-libre 5.7.3-gnu
[librecmc/linux-libre.git] / arch / powerpc / platforms / powernv / opal-secvar.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PowerNV code for secure variables
4  *
5  * Copyright (C) 2019 IBM Corporation
6  * Author: Claudio Carvalho
7  *         Nayna Jain
8  *
9  * APIs to access secure variables managed by OPAL.
10  */
11
12 #define pr_fmt(fmt) "secvar: "fmt
13
14 #include <linux/types.h>
15 #include <linux/platform_device.h>
16 #include <linux/of_platform.h>
17 #include <asm/opal.h>
18 #include <asm/secvar.h>
19 #include <asm/secure_boot.h>
20
21 static int opal_status_to_err(int rc)
22 {
23         int err;
24
25         switch (rc) {
26         case OPAL_SUCCESS:
27                 err = 0;
28                 break;
29         case OPAL_UNSUPPORTED:
30                 err = -ENXIO;
31                 break;
32         case OPAL_PARAMETER:
33                 err = -EINVAL;
34                 break;
35         case OPAL_RESOURCE:
36                 err = -ENOSPC;
37                 break;
38         case OPAL_HARDWARE:
39                 err = -EIO;
40                 break;
41         case OPAL_NO_MEM:
42                 err = -ENOMEM;
43                 break;
44         case OPAL_EMPTY:
45                 err = -ENOENT;
46                 break;
47         case OPAL_PARTIAL:
48                 err = -EFBIG;
49                 break;
50         default:
51                 err = -EINVAL;
52         }
53
54         return err;
55 }
56
57 static int opal_get_variable(const char *key, uint64_t ksize,
58                              u8 *data, uint64_t *dsize)
59 {
60         int rc;
61
62         if (!key || !dsize)
63                 return -EINVAL;
64
65         *dsize = cpu_to_be64(*dsize);
66
67         rc = opal_secvar_get(key, ksize, data, dsize);
68
69         *dsize = be64_to_cpu(*dsize);
70
71         return opal_status_to_err(rc);
72 }
73
74 static int opal_get_next_variable(const char *key, uint64_t *keylen,
75                                   uint64_t keybufsize)
76 {
77         int rc;
78
79         if (!key || !keylen)
80                 return -EINVAL;
81
82         *keylen = cpu_to_be64(*keylen);
83
84         rc = opal_secvar_get_next(key, keylen, keybufsize);
85
86         *keylen = be64_to_cpu(*keylen);
87
88         return opal_status_to_err(rc);
89 }
90
91 static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
92                              uint64_t dsize)
93 {
94         int rc;
95
96         if (!key || !data)
97                 return -EINVAL;
98
99         rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
100
101         return opal_status_to_err(rc);
102 }
103
104 static const struct secvar_operations opal_secvar_ops = {
105         .get = opal_get_variable,
106         .get_next = opal_get_next_variable,
107         .set = opal_set_variable,
108 };
109
110 static int opal_secvar_probe(struct platform_device *pdev)
111 {
112         if (!opal_check_token(OPAL_SECVAR_GET)
113                         || !opal_check_token(OPAL_SECVAR_GET_NEXT)
114                         || !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
115                 pr_err("OPAL doesn't support secure variables\n");
116                 return -ENODEV;
117         }
118
119         set_secvar_ops(&opal_secvar_ops);
120
121         return 0;
122 }
123
124 static const struct of_device_id opal_secvar_match[] = {
125         { .compatible = "ibm,secvar-backend",},
126         {},
127 };
128
129 static struct platform_driver opal_secvar_driver = {
130         .driver = {
131                 .name = "secvar",
132                 .of_match_table = opal_secvar_match,
133         },
134 };
135
136 static int __init opal_secvar_init(void)
137 {
138         return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
139 }
140 device_initcall(opal_secvar_init);