Skip to content

Commit f0cd69b

Browse files
committed
Merge tag 'random-6.10-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random
Pull random number generator updates from Jason Donenfeld: - The vmgenid driver can now be bound using device tree, rather than just ACPI. The improvement, from Sudan Landge, lets Amazon's Firecracker VMM make use of the virtual device without having to expose an otherwise unused ACPI stack in their "micro VM". * tag 'random-6.10-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random: virt: vmgenid: add support for devicetree bindings dt-bindings: rng: Add vmgenid support virt: vmgenid: change implementation to use a platform driver
2 parents 2fc0e78 + 7b1bcd6 commit f0cd69b

File tree

4 files changed

+165
-35
lines changed

4 files changed

+165
-35
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/rng/microsoft,vmgenid.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Virtual Machine Generation ID
8+
9+
maintainers:
10+
- Jason A. Donenfeld <[email protected]>
11+
12+
description:
13+
Firmwares or hypervisors can use this devicetree to describe an
14+
interrupt and a shared resource to inject a Virtual Machine Generation ID.
15+
Virtual Machine Generation ID is a globally unique identifier (GUID) and
16+
the devicetree binding follows VMGenID specification defined in
17+
http://go.microsoft.com/fwlink/?LinkId=260709.
18+
19+
properties:
20+
compatible:
21+
const: microsoft,vmgenid
22+
23+
reg:
24+
description:
25+
Specifies a 16-byte VMGenID in endianness-agnostic hexadecimal format.
26+
maxItems: 1
27+
28+
interrupts:
29+
description:
30+
Interrupt used to notify that a new VMGenID is available.
31+
maxItems: 1
32+
33+
required:
34+
- compatible
35+
- reg
36+
- interrupts
37+
38+
additionalProperties: false
39+
40+
examples:
41+
- |
42+
#include <dt-bindings/interrupt-controller/arm-gic.h>
43+
rng@80000000 {
44+
compatible = "microsoft,vmgenid";
45+
reg = <0x80000000 0x1000>;
46+
interrupts = <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>;
47+
};
48+
49+
...

MAINTAINERS

+1
Original file line numberDiff line numberDiff line change
@@ -18669,6 +18669,7 @@ M: "Theodore Ts'o" <[email protected]>
1866918669
M: Jason A. Donenfeld <[email protected]>
1867018670
S: Maintained
1867118671
T: git https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git
18672+
F: Documentation/devicetree/bindings/rng/microsoft,vmgenid.yaml
1867218673
F: drivers/char/random.c
1867318674
F: drivers/virt/vmgenid.c
1867418675

drivers/virt/Kconfig

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ if VIRT_DRIVERS
1616
config VMGENID
1717
tristate "Virtual Machine Generation ID driver"
1818
default y
19-
depends on ACPI
2019
help
2120
Say Y here to use the hypervisor-provided Virtual Machine Generation ID
2221
to reseed the RNG when the VM is cloned. This is highly recommended if

drivers/virt/vmgenid.c

+115-34
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
/*
33
* Copyright (C) 2022 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
44
*
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
66
* virtual machine forks or is cloned. This driver exists for shepherding that
77
* information to random.c.
88
*/
99

10+
#include <linux/acpi.h>
11+
#include <linux/interrupt.h>
1012
#include <linux/kernel.h>
1113
#include <linux/module.h>
12-
#include <linux/acpi.h>
14+
#include <linux/platform_device.h>
1315
#include <linux/random.h>
1416

1517
ACPI_MODULE_NAME("vmgenid");
@@ -21,19 +23,42 @@ struct vmgenid_state {
2123
u8 this_id[VMGENID_SIZE];
2224
};
2325

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)
2553
{
54+
struct acpi_device *device = ACPI_COMPANION(dev);
2655
struct acpi_buffer parsed = { ACPI_ALLOCATE_BUFFER };
27-
struct vmgenid_state *state;
2856
union acpi_object *obj;
2957
phys_addr_t phys_addr;
3058
acpi_status status;
59+
void *virt_addr;
3160
int ret = 0;
3261

33-
state = devm_kmalloc(&device->dev, sizeof(*state), GFP_KERNEL);
34-
if (!state)
35-
return -ENOMEM;
36-
3762
status = acpi_evaluate_object(device->handle, "ADDR", NULL, &parsed);
3863
if (ACPI_FAILURE(status)) {
3964
ACPI_EXCEPTION((AE_INFO, status, "Evaluating ADDR"));
@@ -49,52 +74,108 @@ static int vmgenid_add(struct acpi_device *device)
4974

5075
phys_addr = (obj->package.elements[0].integer.value << 0) |
5176
(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);
5581
goto out;
5682
}
83+
setup_vmgenid_state(state, virt_addr);
5784

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+
}
6291

92+
dev->driver_data = state;
6393
out:
6494
ACPI_FREE(parsed.pointer);
6595
return ret;
6696
}
97+
#else
98+
static int vmgenid_add_acpi(struct device *dev, struct vmgenid_state *state)
99+
{
100+
return -EINVAL;
101+
}
102+
#endif
67103

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)
69105
{
70-
struct vmgenid_state *state = acpi_driver_data(device);
71-
u8 old_id[VMGENID_SIZE];
106+
vmgenid_notify(dev);
107+
return IRQ_HANDLED;
108+
}
72109

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;
78133
}
79134

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[] = {
81162
{ "VMGENCTR", 0 },
82163
{ "VM_GEN_COUNTER", 0 },
83164
{ }
84165
};
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+
},
93175
};
94176

95-
module_acpi_driver(vmgenid_driver);
177+
module_platform_driver(vmgenid_plaform_driver)
96178

97-
MODULE_DEVICE_TABLE(acpi, vmgenid_ids);
98179
MODULE_DESCRIPTION("Virtual Machine Generation ID");
99180
MODULE_LICENSE("GPL v2");
100181
MODULE_AUTHOR("Jason A. Donenfeld <[email protected]>");

0 commit comments

Comments
 (0)