2
2
/*
3
3
* Copyright (C) 2022 Jason A. Donenfeld <[email protected] >. All Rights Reserved.
4
4
*
5
- * The "Virtual Machine Generation ID" is exposed via ACPI and changes when a
5
+ * The "Virtual Machine Generation ID" is exposed via ACPI or DT and changes when a
6
6
* virtual machine forks or is cloned. This driver exists for shepherding that
7
7
* information to random.c.
8
8
*/
9
9
10
+ #include <linux/acpi.h>
11
+ #include <linux/interrupt.h>
10
12
#include <linux/kernel.h>
11
13
#include <linux/module.h>
12
- #include <linux/acpi .h>
14
+ #include <linux/platform_device .h>
13
15
#include <linux/random.h>
14
16
15
17
ACPI_MODULE_NAME ("vmgenid" );
@@ -21,19 +23,42 @@ struct vmgenid_state {
21
23
u8 this_id [VMGENID_SIZE ];
22
24
};
23
25
24
- static int vmgenid_add (struct acpi_device * device )
26
+ static void vmgenid_notify (struct device * device )
27
+ {
28
+ struct vmgenid_state * state = device -> driver_data ;
29
+ u8 old_id [VMGENID_SIZE ];
30
+
31
+ memcpy (old_id , state -> this_id , sizeof (old_id ));
32
+ memcpy (state -> this_id , state -> next_id , sizeof (state -> this_id ));
33
+ if (!memcmp (old_id , state -> this_id , sizeof (old_id )))
34
+ return ;
35
+ add_vmfork_randomness (state -> this_id , sizeof (state -> this_id ));
36
+ }
37
+
38
+ static void setup_vmgenid_state (struct vmgenid_state * state , void * virt_addr )
39
+ {
40
+ state -> next_id = virt_addr ;
41
+ memcpy (state -> this_id , state -> next_id , sizeof (state -> this_id ));
42
+ add_device_randomness (state -> this_id , sizeof (state -> this_id ));
43
+ }
44
+
45
+ #ifdef CONFIG_ACPI
46
+ static void vmgenid_acpi_handler (acpi_handle __always_unused handle ,
47
+ u32 __always_unused event , void * dev )
48
+ {
49
+ vmgenid_notify (dev );
50
+ }
51
+
52
+ static int vmgenid_add_acpi (struct device * dev , struct vmgenid_state * state )
25
53
{
54
+ struct acpi_device * device = ACPI_COMPANION (dev );
26
55
struct acpi_buffer parsed = { ACPI_ALLOCATE_BUFFER };
27
- struct vmgenid_state * state ;
28
56
union acpi_object * obj ;
29
57
phys_addr_t phys_addr ;
30
58
acpi_status status ;
59
+ void * virt_addr ;
31
60
int ret = 0 ;
32
61
33
- state = devm_kmalloc (& device -> dev , sizeof (* state ), GFP_KERNEL );
34
- if (!state )
35
- return - ENOMEM ;
36
-
37
62
status = acpi_evaluate_object (device -> handle , "ADDR" , NULL , & parsed );
38
63
if (ACPI_FAILURE (status )) {
39
64
ACPI_EXCEPTION ((AE_INFO , status , "Evaluating ADDR" ));
@@ -49,52 +74,108 @@ static int vmgenid_add(struct acpi_device *device)
49
74
50
75
phys_addr = (obj -> package .elements [0 ].integer .value << 0 ) |
51
76
(obj -> package .elements [1 ].integer .value << 32 );
52
- state -> next_id = devm_memremap (& device -> dev , phys_addr , VMGENID_SIZE , MEMREMAP_WB );
53
- if (IS_ERR (state -> next_id )) {
54
- ret = PTR_ERR (state -> next_id );
77
+
78
+ virt_addr = devm_memremap (& device -> dev , phys_addr , VMGENID_SIZE , MEMREMAP_WB );
79
+ if (IS_ERR (virt_addr )) {
80
+ ret = PTR_ERR (virt_addr );
55
81
goto out ;
56
82
}
83
+ setup_vmgenid_state (state , virt_addr );
57
84
58
- memcpy (state -> this_id , state -> next_id , sizeof (state -> this_id ));
59
- add_device_randomness (state -> this_id , sizeof (state -> this_id ));
60
-
61
- device -> driver_data = state ;
85
+ status = acpi_install_notify_handler (device -> handle , ACPI_DEVICE_NOTIFY ,
86
+ vmgenid_acpi_handler , dev );
87
+ if (ACPI_FAILURE (status )) {
88
+ ret = - ENODEV ;
89
+ goto out ;
90
+ }
62
91
92
+ dev -> driver_data = state ;
63
93
out :
64
94
ACPI_FREE (parsed .pointer );
65
95
return ret ;
66
96
}
97
+ #else
98
+ static int vmgenid_add_acpi (struct device * dev , struct vmgenid_state * state )
99
+ {
100
+ return - EINVAL ;
101
+ }
102
+ #endif
67
103
68
- static void vmgenid_notify ( struct acpi_device * device , u32 event )
104
+ static irqreturn_t vmgenid_of_irq_handler ( int __always_unused irq , void * dev )
69
105
{
70
- struct vmgenid_state * state = acpi_driver_data (device );
71
- u8 old_id [VMGENID_SIZE ];
106
+ vmgenid_notify (dev );
107
+ return IRQ_HANDLED ;
108
+ }
72
109
73
- memcpy (old_id , state -> this_id , sizeof (old_id ));
74
- memcpy (state -> this_id , state -> next_id , sizeof (state -> this_id ));
75
- if (!memcmp (old_id , state -> this_id , sizeof (old_id )))
76
- return ;
77
- add_vmfork_randomness (state -> this_id , sizeof (state -> this_id ));
110
+ static int vmgenid_add_of (struct platform_device * pdev ,
111
+ struct vmgenid_state * state )
112
+ {
113
+ void * virt_addr ;
114
+ int ret ;
115
+
116
+ virt_addr = devm_platform_get_and_ioremap_resource (pdev , 0 , NULL );
117
+ if (IS_ERR (virt_addr ))
118
+ return PTR_ERR (virt_addr );
119
+
120
+ setup_vmgenid_state (state , virt_addr );
121
+
122
+ ret = platform_get_irq (pdev , 0 );
123
+ if (ret < 0 )
124
+ return ret ;
125
+
126
+ ret = devm_request_irq (& pdev -> dev , ret , vmgenid_of_irq_handler ,
127
+ IRQF_SHARED , "vmgenid" , & pdev -> dev );
128
+ if (ret < 0 )
129
+ return ret ;
130
+
131
+ pdev -> dev .driver_data = state ;
132
+ return 0 ;
78
133
}
79
134
80
- static const struct acpi_device_id vmgenid_ids [] = {
135
+ static int vmgenid_add (struct platform_device * pdev )
136
+ {
137
+ struct device * dev = & pdev -> dev ;
138
+ struct vmgenid_state * state ;
139
+ int ret ;
140
+
141
+ state = devm_kmalloc (dev , sizeof (* state ), GFP_KERNEL );
142
+ if (!state )
143
+ return - ENOMEM ;
144
+
145
+ if (dev -> of_node )
146
+ ret = vmgenid_add_of (pdev , state );
147
+ else
148
+ ret = vmgenid_add_acpi (dev , state );
149
+
150
+ if (ret < 0 )
151
+ devm_kfree (dev , state );
152
+ return ret ;
153
+ }
154
+
155
+ static const struct of_device_id vmgenid_of_ids [] = {
156
+ { .compatible = "microsoft,vmgenid" , },
157
+ { },
158
+ };
159
+ MODULE_DEVICE_TABLE (of , vmgenid_of_ids );
160
+
161
+ static const struct acpi_device_id vmgenid_acpi_ids [] = {
81
162
{ "VMGENCTR" , 0 },
82
163
{ "VM_GEN_COUNTER" , 0 },
83
164
{ }
84
165
};
85
-
86
- static struct acpi_driver vmgenid_driver = {
87
- .name = "vmgenid" ,
88
- .ids = vmgenid_ids ,
89
- .ops = {
90
- .add = vmgenid_add ,
91
- .notify = vmgenid_notify
92
- }
166
+ MODULE_DEVICE_TABLE (acpi , vmgenid_acpi_ids );
167
+
168
+ static struct platform_driver vmgenid_plaform_driver = {
169
+ .probe = vmgenid_add ,
170
+ .driver = {
171
+ .name = "vmgenid" ,
172
+ .acpi_match_table = vmgenid_acpi_ids ,
173
+ .of_match_table = vmgenid_of_ids ,
174
+ },
93
175
};
94
176
95
- module_acpi_driver ( vmgenid_driver );
177
+ module_platform_driver ( vmgenid_plaform_driver )
96
178
97
- MODULE_DEVICE_TABLE (acpi , vmgenid_ids );
98
179
MODULE_DESCRIPTION ("Virtual Machine Generation ID" );
99
180
MODULE_LICENSE ("GPL v2" );
100
181
MODULE_AUTHOR (
"Jason A. Donenfeld <[email protected] >" );
0 commit comments