| /* |
| * Copyright (c) 2020 ARM Limited |
| * All rights reserved |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "dev/arm/css/scmi_protocols.hh" |
| |
| #include "debug/SCMI.hh" |
| #include "dev/arm/css/scmi_platform.hh" |
| |
| namespace gem5 |
| { |
| |
| using namespace scmi; |
| |
| const std::string |
| Protocol::name() const |
| { |
| return platform.name(); |
| } |
| |
| BaseProtocol::BaseProtocol(Platform &_platform) |
| : Protocol(_platform), |
| vendor(platform.params().base_vendor), |
| subvendor(platform.params().base_subvendor), |
| implementationVersion(platform.params().base_impl_version) |
| { |
| fatal_if(vendor.length() > MAX_STRING_SIZE, |
| "Invalid BASE_PROTOCOL VENDOR size\n"); |
| fatal_if(subvendor.length() > MAX_STRING_SIZE, |
| "Invalid BASE_PROTOCOL SUBVENDOR size\n"); |
| } |
| |
| void |
| BaseProtocol::handleMessage(Message &msg) |
| { |
| auto message_id = Platform::messageID(msg); |
| |
| DPRINTF(SCMI, "Handling SCMI message:\n"); |
| DPRINTF(SCMI, "# Message Protocol = BASE_PROTOCOL\n"); |
| DPRINTF(SCMI, "# Message ID = %u\n", message_id); |
| |
| switch (static_cast<Commands>(message_id)) { |
| case Commands::VERSION: |
| version(msg); |
| break; |
| case Commands::ATTRIBUTES: |
| attributes(msg); |
| break; |
| case Commands::MESSAGE_ATTRIBUTES: |
| messageAttributes(msg); |
| break; |
| case Commands::DISCOVER_VENDOR: |
| discoverVendor(msg); |
| break; |
| case Commands::DISCOVER_SUB_VENDOR: |
| discoverSubVendor(msg); |
| break; |
| case Commands::DISCOVER_IMPLEMENTATION_VERSION: |
| discoverImplVersion(msg); |
| break; |
| case Commands::DISCOVER_LIST_PROTOCOLS: |
| discoverListProtocols(msg); |
| break; |
| case Commands::DISCOVER_AGENT: |
| discoverAgent(msg); |
| break; |
| case Commands::NOTIFY_ERRORS: |
| case Commands::SET_DEVICE_PERMISSIONS: |
| case Commands::SET_PROTOCOL_PERMISSIONS: |
| case Commands::RESET_AGENT_CONFIGURATION: |
| default: |
| invalidCommand(msg); |
| warn("Unimplemented SCMI command: %u\n", message_id); |
| } |
| } |
| |
| void |
| BaseProtocol::version(Message &msg) |
| { |
| auto& payload = msg.payload.baseProtocolVersion; |
| payload.status = SUCCESS; |
| payload.version = PROTOCOL_VERSION; |
| |
| // header + status + return |
| msg.length = sizeof(uint32_t) * 3; |
| } |
| |
| void |
| BaseProtocol::attributes(Message &msg) |
| { |
| uint32_t _attributes = 0; |
| |
| replaceBits(_attributes, 15, 8, platform.numAgents()); |
| replaceBits(_attributes, 7, 0, platform.numProtocols()); |
| |
| auto& payload = msg.payload.baseProtocolAttributes; |
| payload.status = SUCCESS; |
| payload.attributes = _attributes; |
| |
| // header + status + return |
| msg.length = sizeof(uint32_t) * 3; |
| } |
| |
| bool |
| BaseProtocol::implementedProtocol(Commands message_id) const |
| { |
| switch (message_id) { |
| case Commands::VERSION: |
| case Commands::ATTRIBUTES: |
| case Commands::MESSAGE_ATTRIBUTES: |
| case Commands::DISCOVER_VENDOR: |
| case Commands::DISCOVER_SUB_VENDOR: |
| case Commands::DISCOVER_IMPLEMENTATION_VERSION: |
| case Commands::DISCOVER_LIST_PROTOCOLS: |
| case Commands::DISCOVER_AGENT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| void |
| BaseProtocol::messageAttributes(Message &msg) |
| { |
| auto& payload = msg.payload.baseProtocolMessageAttributes; |
| const auto message_id = static_cast<Commands>( |
| payload.messageId); |
| |
| if (!implementedProtocol(message_id)) { |
| payload.status = NOT_FOUND; |
| } else { |
| payload.status = SUCCESS; |
| } |
| |
| // For all messages in the Base protocol, 0 must be returned |
| payload.attributes = 0; |
| |
| // header + status + return |
| msg.length = sizeof(uint32_t) * 3; |
| } |
| |
| void |
| BaseProtocol::discoverVendor(Message &msg) |
| { |
| auto& payload = msg.payload.baseDiscoverVendor; |
| payload.status = SUCCESS; |
| |
| auto vendor_size = vendor.copy( |
| (char*)&payload.vendorIdentifier, MAX_STRING_SIZE); |
| |
| // header + status + payload |
| msg.length = sizeof(uint32_t) * 2 + vendor_size; |
| } |
| |
| void |
| BaseProtocol::discoverSubVendor(Message &msg) |
| { |
| auto& payload = msg.payload.baseDiscoverSubVendor; |
| payload.status = SUCCESS; |
| |
| auto subvendor_size = subvendor.copy( |
| (char*)&payload.vendorIdentifier, MAX_STRING_SIZE); |
| |
| // header + status + payload |
| msg.length = sizeof(uint32_t) * 2 + subvendor_size; |
| } |
| |
| void |
| BaseProtocol::discoverImplVersion(Message &msg) |
| { |
| auto& payload = msg.payload.baseDiscoverImplementationVersion; |
| payload.status = SUCCESS; |
| payload.implementationVersion = implementationVersion; |
| |
| // header + status + return |
| msg.length = sizeof(uint32_t) * 3; |
| } |
| |
| void |
| BaseProtocol::discoverListProtocols(Message &msg) |
| { |
| auto& payload = msg.payload.baseDiscoverListProtocols; |
| const uint32_t skip = payload.skip; |
| const auto num_protocols = platform.numProtocols(); |
| |
| if (skip > num_protocols) { |
| payload.status = INVALID_PARAMETERS; |
| msg.length = sizeof(uint32_t) * 2; |
| |
| } else { |
| const auto& protocol_list = platform.protocolList(); |
| auto *protocols = (uint8_t*)payload.protocols; |
| uint32_t num_implemented = 0; |
| |
| for (auto protoc_id = START + skip; protoc_id <= END; protoc_id++) { |
| auto it = protocol_list.find(protoc_id); |
| if (it != protocol_list.end()) { |
| num_implemented++; |
| |
| *protocols = it->first; |
| protocols++; |
| } |
| } |
| |
| payload.status = SUCCESS; |
| payload.numProtocols = num_implemented; |
| |
| // header + status + return |
| msg.length = sizeof(uint32_t) * 3; |
| } |
| } |
| |
| void |
| BaseProtocol::discoverAgent(Message &msg) |
| { |
| auto& payload = msg.payload.baseDiscoverAgent; |
| const uint32_t agent_id = payload.agentId; |
| |
| if (agent_id > platform.numAgents()) { |
| payload.status = NOT_FOUND; |
| msg.length = sizeof(uint32_t) * 2; |
| |
| } else { |
| auto agent_size = 0; |
| auto agent_name = std::string(); |
| |
| if (agent_id) { |
| // Subtracting one to the agent_id, since agent_id 0 is reserved |
| // for the platform. |
| agent_name = platform.getAgent(agent_id - 1); |
| } else { |
| agent_name = "platform"; |
| } |
| |
| agent_size = agent_name.length(); |
| |
| strncpy((char *)&payload.name, |
| agent_name.c_str(), agent_size); |
| |
| payload.status = SUCCESS; |
| // header + status + payload |
| msg.length = sizeof(uint32_t) * 2 + agent_size; |
| } |
| } |
| |
| void |
| BaseProtocol::invalidCommand(Message &msg) |
| { |
| auto& payload = msg.payload.invalidCommand; |
| payload.status = NOT_FOUND; |
| msg.length = sizeof(uint32_t) * 2; |
| } |
| |
| } // namespace gem5 |