From 652d5f6347ae220645c66f1ab1f3ef691f8b7dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sun, 20 Nov 2022 18:15:55 +0100 Subject: [PATCH] ccp: driver for the RNG part of CCP on AMD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the entropy source is read every second and pushed to the PRNG. the PCI device is tested, not the ACPI. Change-Id: I9bb6b21c7189b28a1d8a624d83b33ff6682152dc Reviewed-on: https://review.haiku-os.org/c/haiku/+/5825 Tested-by: Commit checker robot Reviewed-by: Jérôme Duval --- build/jam/packages/Haiku | 2 +- headers/os/drivers/PCI.h | 7 + src/add-ons/kernel/busses/random/Jamfile | 4 + src/add-ons/kernel/busses/random/ccp/Jamfile | 14 ++ src/add-ons/kernel/busses/random/ccp/ccp.cpp | 159 ++++++++++++++++ src/add-ons/kernel/busses/random/ccp/ccp.h | 59 ++++++ .../kernel/busses/random/ccp/ccp_acpi.cpp | 180 ++++++++++++++++++ .../kernel/busses/random/ccp/ccp_pci.cpp | 159 ++++++++++++++++ .../kernel/device_manager/device_manager.cpp | 19 +- 9 files changed, 601 insertions(+), 2 deletions(-) create mode 100644 src/add-ons/kernel/busses/random/ccp/Jamfile create mode 100644 src/add-ons/kernel/busses/random/ccp/ccp.cpp create mode 100644 src/add-ons/kernel/busses/random/ccp/ccp.h create mode 100644 src/add-ons/kernel/busses/random/ccp/ccp_acpi.cpp create mode 100644 src/add-ons/kernel/busses/random/ccp/ccp_pci.cpp diff --git a/build/jam/packages/Haiku b/build/jam/packages/Haiku index 4aaf992b3a..86f7c5c749 100644 --- a/build/jam/packages/Haiku +++ b/build/jam/packages/Haiku @@ -30,7 +30,7 @@ AddFilesToPackage add-ons kernel busses ata AddFilesToPackage add-ons kernel busses i2c : pch_i2c@x86,x86_64 ; AddFilesToPackage add-ons kernel busses mmc : sdhci_pci ; -AddFilesToPackage add-ons kernel busses random : virtio_rng ; +AddFilesToPackage add-ons kernel busses random : ccp_rng@x86,x86_64 virtio_rng ; AddFilesToPackage add-ons kernel busses scsi : ahci virtio_scsi ; AddFilesToPackage add-ons kernel busses usb : uhci ohci ehci xhci ; diff --git a/headers/os/drivers/PCI.h b/headers/os/drivers/PCI.h index a692dd8c47..a999ec2595 100644 --- a/headers/os/drivers/PCI.h +++ b/headers/os/drivers/PCI.h @@ -620,6 +620,13 @@ struct pci_module_info { #define PCI_wireless_cellular_ethernet 0x41 #define PCI_wireless_other 0x80 +/* --- + values for the class_sub field for class_base = 0x10 (encryption decryption) +--- */ +#define PCI_encryption_decryption_network_computing 0x00 +#define PCI_encryption_decryption_entertainment 0x10 +#define PCI_encryption_decryption_other 0x80 + /* --- values for the class_sub field for class_base = 0x11 (data acquisition) --- */ diff --git a/src/add-ons/kernel/busses/random/Jamfile b/src/add-ons/kernel/busses/random/Jamfile index d1d610b9a6..c7577d9ac0 100644 --- a/src/add-ons/kernel/busses/random/Jamfile +++ b/src/add-ons/kernel/busses/random/Jamfile @@ -7,3 +7,7 @@ KernelAddon virtio_rng : virtio_rng.cpp VirtioRNGDevice.cpp ; + + +SubInclude HAIKU_TOP src add-ons kernel busses random ccp ; + diff --git a/src/add-ons/kernel/busses/random/ccp/Jamfile b/src/add-ons/kernel/busses/random/ccp/Jamfile new file mode 100644 index 0000000000..35ac77ac38 --- /dev/null +++ b/src/add-ons/kernel/busses/random/ccp/Jamfile @@ -0,0 +1,14 @@ +SubDir HAIKU_TOP src add-ons kernel busses random ccp ; + +UsePrivateHeaders drivers ; +UsePrivateKernelHeaders ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) bus_managers acpi acpica include ] ; +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) bus_managers acpi acpica include platform ] ; + + +KernelAddon ccp_rng : + ccp.cpp + ccp_acpi.cpp + ccp_pci.cpp +; diff --git a/src/add-ons/kernel/busses/random/ccp/ccp.cpp b/src/add-ons/kernel/busses/random/ccp/ccp.cpp new file mode 100644 index 0000000000..08b27e6ffc --- /dev/null +++ b/src/add-ons/kernel/busses/random/ccp/ccp.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2022, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include +#include + +#include "random.h" + +#include "ccp.h" + + +#define CCP_REG_TRNG 0xc + + +device_manager_info* gDeviceManager; +random_for_controller_interface *gRandom; +dpc_module_info *gDPC; + + +static void +handleDPC(void *arg) +{ + CALLED(); + ccp_device_info* bus = reinterpret_cast(arg); + + uint32 lowValue = read32(bus->registers + CCP_REG_TRNG); + uint32 highValue = read32(bus->registers + CCP_REG_TRNG); + if (lowValue == 0 || highValue == 0) + return; + gRandom->queue_randomness((uint64)lowValue | ((uint64)highValue << 32)); +} + + +static int32 +handleTimerHook(struct timer* timer) +{ + ccp_device_info* bus = reinterpret_cast(timer->user_data); + + gDPC->queue_dpc(bus->dpcHandle, handleDPC, bus); + return B_HANDLED_INTERRUPT; +} + + +// #pragma mark - + + +static status_t +register_device(device_node* parent) +{ + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "CCP device"}}, + {B_DEVICE_BUS, B_STRING_TYPE, {string: "CCP"}}, + {} + }; + + return gDeviceManager->register_node(parent, + CCP_DEVICE_MODULE_NAME, attrs, NULL, NULL); +} + + +static status_t +init_bus(device_node* node, void** bus_cookie) +{ + CALLED(); + + driver_module_info* driver; + ccp_device_info* bus; + device_node* parent = gDeviceManager->get_parent_node(node); + gDeviceManager->get_driver(parent, &driver, (void**)&bus); + gDeviceManager->put_node(parent); + + TRACE_ALWAYS("init_bus() addr 0x%" B_PRIxPHYSADDR " size 0x%" B_PRIx64 + " \n", bus->base_addr, bus->map_size); + + bus->registersArea = map_physical_memory("CCP memory mapped registers", + bus->base_addr, bus->map_size, B_ANY_KERNEL_ADDRESS, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, + (void **)&bus->registers); + if (bus->registersArea < 0) + return bus->registersArea; + + status_t status = gDPC->new_dpc_queue(&bus->dpcHandle, "ccp timer", + B_LOW_PRIORITY); + if (status != B_OK) { + ERROR("dpc setup failed (%s)\n", strerror(status)); + return status; + } + + bus->extractTimer.user_data = bus; + status = add_timer(&bus->extractTimer, &handleTimerHook, 1 * 1000 * 1000, B_PERIODIC_TIMER); + if (status != B_OK) { + ERROR("timer setup failed (%s)\n", strerror(status)); + return status; + } + + // trigger also now + gDPC->queue_dpc(bus->dpcHandle, handleDPC, bus); + + *bus_cookie = bus; + return B_OK; + +} + + +static void +uninit_bus(void* bus_cookie) +{ + ccp_device_info* bus = (ccp_device_info*)bus_cookie; + + cancel_timer(&bus->extractTimer); + gDPC->delete_dpc_queue(&bus->dpcHandle); + + if (bus->registersArea >= 0) + delete_area(bus->registersArea); + +} + + +// #pragma mark - + + +module_dependency module_dependencies[] = { + { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, + { RANDOM_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gRandom }, + { B_DPC_MODULE_NAME, (module_info **)&gDPC }, + {} +}; + + +static driver_module_info sCcpDeviceModule = { + { + CCP_DEVICE_MODULE_NAME, + 0, + NULL + }, + + NULL, // supports device + register_device, + init_bus, + uninit_bus, + NULL, // register child devices + NULL, // rescan + NULL, // device removed +}; + + +module_info* modules[] = { + (module_info* )&gCcpAcpiDevice, + (module_info* )&sCcpDeviceModule, + (module_info* )&gCcpPciDevice, + NULL +}; diff --git a/src/add-ons/kernel/busses/random/ccp/ccp.h b/src/add-ons/kernel/busses/random/ccp/ccp.h new file mode 100644 index 0000000000..08a351b16b --- /dev/null +++ b/src/add-ons/kernel/busses/random/ccp/ccp.h @@ -0,0 +1,59 @@ +/* + * Copyright 2022, Jérôme Duval, jerome.duval@gmail.com. + * + * Distributed under the terms of the MIT License. + */ +#ifndef _CCP_H +#define _CCP_H + + +#include + +#include + + +//#define TRACE_CCP_RNG +#ifndef DRIVER_NAME +# define DRIVER_NAME "ccp_rng" +#endif +#ifdef TRACE_CCP_RNG +# define TRACE(x...) dprintf("\33[33m" DRIVER_NAME ":\33[0m " x) +#else +# define TRACE(x...) ; +#endif +#define TRACE_ALWAYS(x...) dprintf("\33[33m" DRIVER_NAME ":\33[0m " x) +#define ERROR(x...) dprintf("\33[33m" DRIVER_NAME ":\33[0m " x) +#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) + + +#define CCP_ACPI_DEVICE_MODULE_NAME "busses/random/ccp_rng/acpi/driver_v1" +#define CCP_PCI_DEVICE_MODULE_NAME "busses/random/ccp_rng/pci/driver_v1" +#define CCP_DEVICE_MODULE_NAME "busses/random/ccp_rng/device/v1" + + +#define read32(address) \ + (*((volatile uint32*)(address))) + + + +extern device_manager_info* gDeviceManager; +extern driver_module_info gCcpAcpiDevice; +extern driver_module_info gCcpPciDevice; + + +typedef struct { + phys_addr_t base_addr; + uint64 map_size; + + device_node* node; + device_node* driver_node; + + area_id registersArea; + addr_t registers; + + timer extractTimer; + void* dpcHandle; +} ccp_device_info; + + +#endif // _CCP_H diff --git a/src/add-ons/kernel/busses/random/ccp/ccp_acpi.cpp b/src/add-ons/kernel/busses/random/ccp/ccp_acpi.cpp new file mode 100644 index 0000000000..3796aad448 --- /dev/null +++ b/src/add-ons/kernel/busses/random/ccp/ccp_acpi.cpp @@ -0,0 +1,180 @@ +/* + * Copyright 2022, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include +#include +#include + +extern "C" { +# include "acpi.h" +} + + +#define DRIVER_NAME "ccp_rng_acpi" +#include "ccp.h" + + +typedef struct { + ccp_device_info info; + acpi_device_module_info* acpi; + acpi_device device; + +} ccp_acpi_sim_info; + + +struct ccp_crs { + uint32 addr_bas; + uint32 addr_len; +}; + + +static acpi_status +ccp_scan_parse_callback(ACPI_RESOURCE *res, void *context) +{ + struct ccp_crs* crs = (struct ccp_crs*)context; + + if (res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { + crs->addr_bas = res->Data.FixedMemory32.Address; + crs->addr_len = res->Data.FixedMemory32.AddressLength; + } + + return B_OK; +} + + +// #pragma mark - + + +static status_t +init_device(device_node* node, void** device_cookie) +{ + CALLED(); + status_t status = B_OK; + + ccp_acpi_sim_info* bus = (ccp_acpi_sim_info*)calloc(1, + sizeof(ccp_acpi_sim_info)); + if (bus == NULL) + return B_NO_MEMORY; + + acpi_device_module_info* acpi; + acpi_device device; + { + device_node* acpiParent = gDeviceManager->get_parent_node(node); + gDeviceManager->get_driver(acpiParent, (driver_module_info**)&acpi, + (void**)&device); + gDeviceManager->put_node(acpiParent); + } + + bus->acpi = acpi; + bus->device = device; + + struct ccp_crs crs; + status = acpi->walk_resources(device, (ACPI_STRING)"_CRS", + ccp_scan_parse_callback, &crs); + if (status != B_OK) { + ERROR("Error while getting resouces\n"); + free(bus); + return status; + } + if (crs.addr_bas == 0 || crs.addr_len == 0) { + TRACE("skipping non configured CCP devices\n"); + free(bus); + return B_BAD_VALUE; + } + + bus->info.base_addr = crs.addr_bas; + bus->info.map_size = crs.addr_len; + + *device_cookie = bus; + return B_OK; +} + + +static void +uninit_device(void* device_cookie) +{ + ccp_acpi_sim_info* bus = (ccp_acpi_sim_info*)device_cookie; + free(bus); +} + + +static status_t +register_device(device_node* parent) +{ + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "CCP ACPI"}}, + {B_DEVICE_BUS, B_STRING_TYPE, {string: "CCP"}}, + {B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {string: CCP_DEVICE_MODULE_NAME}}, + {} + }; + + return gDeviceManager->register_node(parent, + CCP_ACPI_DEVICE_MODULE_NAME, attrs, NULL, NULL); +} + + +static float +supports_device(device_node* parent) +{ + const char* bus; + + // make sure parent is a CCP ACPI device node + if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) + < B_OK) { + return -1; + } + + if (strcmp(bus, "acpi") != 0) + return 0.0f; + + // check whether it's really a device + uint32 device_type; + if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, + &device_type, false) != B_OK + || device_type != ACPI_TYPE_DEVICE) { + return 0.0; + } + + // check whether it's a CCP device + const char *name; + if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name, + false) != B_OK) { + return 0.0; + } + + if (strcmp(name, "AMDI0C00") == 0) { + TRACE("CCP device found! name %s\n", name); + return 0.6f; + } + + return 0.0f; +} + + +// #pragma mark - + + +driver_module_info gCcpAcpiDevice = { + { + CCP_ACPI_DEVICE_MODULE_NAME, + 0, + NULL + }, + + supports_device, + register_device, + init_device, + uninit_device, + NULL, // register_child_devices, + NULL, // rescan + NULL, // device removed +}; + + diff --git a/src/add-ons/kernel/busses/random/ccp/ccp_pci.cpp b/src/add-ons/kernel/busses/random/ccp/ccp_pci.cpp new file mode 100644 index 0000000000..663da0f916 --- /dev/null +++ b/src/add-ons/kernel/busses/random/ccp/ccp_pci.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2022, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include +#include +#include + +#define DRIVER_NAME "ccp_rng_pci" +#include "ccp.h" + + +typedef struct { + ccp_device_info info; + pci_device_module_info* pci; + pci_device* device; + + pci_info pciinfo; +} ccp_pci_sim_info; + + +// #pragma mark - + + +static status_t +init_device(device_node* node, void** device_cookie) +{ + CALLED(); + ccp_pci_sim_info* bus = (ccp_pci_sim_info*)calloc(1, + sizeof(ccp_pci_sim_info)); + if (bus == NULL) + return B_NO_MEMORY; + + pci_device_module_info* pci; + pci_device* device; + { + device_node* pciParent = gDeviceManager->get_parent_node(node); + gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci, + (void**)&device); + gDeviceManager->put_node(pciParent); + } + + bus->pci = pci; + bus->device = device; + + pci_info *pciInfo = &bus->pciinfo; + pci->get_pci_info(device, pciInfo); + +#define BAR_INDEX 2 + bus->info.base_addr = pciInfo->u.h0.base_registers[BAR_INDEX]; + bus->info.map_size = pciInfo->u.h0.base_register_sizes[BAR_INDEX]; + if ((pciInfo->u.h0.base_register_flags[BAR_INDEX] & PCI_address_type) + == PCI_address_type_64) { + bus->info.base_addr |= (uint64)pciInfo->u.h0.base_registers[BAR_INDEX + 1] << 32; + bus->info.map_size |= (uint64)pciInfo->u.h0.base_register_sizes[BAR_INDEX + 1] << 32; + } + + if (bus->info.base_addr == 0) { + ERROR("PCI BAR not assigned\n"); + free(bus); + return B_ERROR; + } + + // enable bus master and memory + uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2); + pcicmd |= PCI_command_master | PCI_command_memory; + pci->write_pci_config(device, PCI_command, 2, pcicmd); + + *device_cookie = bus; + return B_OK; +} + + +static void +uninit_device(void* device_cookie) +{ + ccp_pci_sim_info* bus = (ccp_pci_sim_info*)device_cookie; + free(bus); +} + + +static status_t +register_device(device_node* parent) +{ + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "CCP PCI"}}, + {B_DEVICE_BUS, B_STRING_TYPE, {string: "CCP"}}, + {B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {string: CCP_DEVICE_MODULE_NAME}}, + {} + }; + + return gDeviceManager->register_node(parent, + CCP_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL); +} + + +static float +supports_device(device_node* parent) +{ + const char* bus; + uint16 vendorID, deviceID; + + // make sure parent is a CCP PCI device node + if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) + < B_OK || gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, + &vendorID, false) < B_OK + || gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID, + false) < B_OK) { + return -1; + } + + if (strcmp(bus, "pci") != 0) + return 0.0f; + + if (vendorID != 0x1022) + return 0.0f; + + switch (deviceID) { + case 0x1456: + case 0x1468: + case 0x1486: + case 0x1537: + case 0x15df: + break; + default: + return 0.0f; + } +#ifdef TRACE_CCP_RNG + TRACE("CCP RNG device found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID); +#endif + return 0.8f; +} + + +// #pragma mark - + + +driver_module_info gCcpPciDevice = { + { + CCP_PCI_DEVICE_MODULE_NAME, + 0, + NULL + }, + + supports_device, + register_device, + init_device, + uninit_device, + NULL, // register_child_devices, + NULL, // rescan + NULL, // device removed +}; + diff --git a/src/system/kernel/device_manager/device_manager.cpp b/src/system/kernel/device_manager/device_manager.cpp index a5b99712f6..b3c23ee117 100644 --- a/src/system/kernel/device_manager/device_manager.cpp +++ b/src/system/kernel/device_manager/device_manager.cpp @@ -1727,6 +1727,16 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path) break; } break; + case PCI_encryption_decryption: + switch (subType) { + case PCI_encryption_decryption_other: + _AddPath(*stack, "busses", "random"); + break; + default: + _AddPath(*stack, "drivers"); + break; + } + break; case PCI_data_acquisition: switch (subType) { case PCI_data_acquisition_other: @@ -1874,7 +1884,14 @@ device_node::_AlwaysRegisterDynamic() get_attr_uint16(this, B_DEVICE_TYPE, &type, false); get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false); - return type == PCI_serial_bus || type == PCI_bridge || type == 0; + switch (type) { + case PCI_serial_bus: + case PCI_bridge: + case PCI_encryption_decryption: + case 0: + return true; + } + return false; // TODO: we may want to be a bit more specific in the future }