From 40859201e4ab633e792f10b5cda2d2a61c582047 Mon Sep 17 00:00:00 2001 From: Nav Date: Sun, 15 Dec 2024 17:32:58 +0000 Subject: [PATCH] Target driver passthrough commands Added `pm` commands to manage the program mode of WCH targets --- .../Gdb/CommandPackets/Monitor.cpp | 13 +++ src/Services/TargetControllerService.cpp | 11 +++ src/Services/TargetControllerService.hpp | 6 ++ .../Commands/CommandTypes.hpp | 1 + .../InvokeTargetPassthroughCommand.hpp | 31 +++++++ .../Responses/ResponseTypes.hpp | 1 + .../Responses/TargetPassthroughResponse.hpp | 26 ++++++ .../TargetControllerComponent.cpp | 12 +++ .../TargetControllerComponent.hpp | 5 + src/Targets/Microchip/AVR8/Avr8.cpp | 13 +++ src/Targets/Microchip/AVR8/Avr8.hpp | 4 +- src/Targets/PassthroughCommand.hpp | 12 +++ src/Targets/PassthroughResponse.hpp | 11 +++ src/Targets/RiscV/Wch/WchRiscV.cpp | 92 ++++++++++++++++++- src/Targets/RiscV/Wch/WchRiscV.hpp | 2 + src/Targets/Target.hpp | 6 ++ 16 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 src/TargetController/Commands/InvokeTargetPassthroughCommand.hpp create mode 100644 src/TargetController/Responses/TargetPassthroughResponse.hpp create mode 100644 src/Targets/PassthroughCommand.hpp create mode 100644 src/Targets/PassthroughResponse.hpp diff --git a/src/DebugServer/Gdb/CommandPackets/Monitor.cpp b/src/DebugServer/Gdb/CommandPackets/Monitor.cpp index 91a92d08..9de11663 100644 --- a/src/DebugServer/Gdb/CommandPackets/Monitor.cpp +++ b/src/DebugServer/Gdb/CommandPackets/Monitor.cpp @@ -1,5 +1,6 @@ #include "Monitor.hpp" +#include "src/DebugServer/Gdb/ResponsePackets/ResponsePacket.hpp" #include "src/DebugServer/Gdb/ResponsePackets/EmptyResponsePacket.hpp" #include "src/Services/StringService.hpp" @@ -9,6 +10,7 @@ namespace DebugServer::Gdb::CommandPackets { using Services::TargetControllerService; + using ResponsePackets::ResponsePacket; using ResponsePackets::EmptyResponsePacket; Monitor::Monitor(const RawPacket& rawPacket) @@ -34,6 +36,17 @@ namespace DebugServer::Gdb::CommandPackets const Targets::TargetDescriptor&, TargetControllerService& targetControllerService ) { + const auto passthroughResponse = targetControllerService.invokeTargetPassthroughCommand( + Targets::PassthroughCommand{.arguments = this->commandArguments} + ); + + if (passthroughResponse.has_value()) { + debugSession.connection.writePacket(ResponsePacket{ + Services::StringService::toHex(passthroughResponse->output) + }); + return; + } + Logger::error("Unknown custom GDB command (\"" + this->command + "\") received."); debugSession.connection.writePacket(EmptyResponsePacket{}); } diff --git a/src/Services/TargetControllerService.cpp b/src/Services/TargetControllerService.cpp index 4c07300f..c029a51d 100644 --- a/src/Services/TargetControllerService.cpp +++ b/src/Services/TargetControllerService.cpp @@ -54,6 +54,7 @@ namespace Services using TargetController::Commands::EnableProgrammingMode; using TargetController::Commands::DisableProgrammingMode; using TargetController::Commands::Shutdown; + using TargetController::Commands::InvokeTargetPassthroughCommand; using Targets::TargetDescriptor; using Targets::TargetState; @@ -345,6 +346,16 @@ namespace Services ); } + std::optional TargetControllerService::invokeTargetPassthroughCommand( + Targets::PassthroughCommand&& command + ) const { + return this->commandManager.sendCommandAndWaitForResponse( + std::make_unique(std::move(command)), + this->defaultTimeout, + this->activeAtomicSessionId + )->response; + } + TargetControllerService::AtomicSession TargetControllerService::makeAtomicSession() { return AtomicSession{*this}; } diff --git a/src/Services/TargetControllerService.hpp b/src/Services/TargetControllerService.hpp index 008f8e7a..58348650 100644 --- a/src/Services/TargetControllerService.hpp +++ b/src/Services/TargetControllerService.hpp @@ -20,6 +20,8 @@ #include "src/Targets/TargetGpioPadState.hpp" #include "src/Targets/TargetMemory.hpp" #include "src/Targets/TargetBreakpoint.hpp" +#include "src/Targets/PassthroughCommand.hpp" +#include "src/Targets/PassthroughResponse.hpp" #include "src/Exceptions/Exception.hpp" @@ -266,6 +268,10 @@ namespace Services */ void shutdown() const; + std::optional invokeTargetPassthroughCommand( + Targets::PassthroughCommand&& command + ) const; + /** * Starts a new atomic session with the TC, via an TargetControllerService::AtomicSession RAII object. * The session will end when the object is destroyed. diff --git a/src/TargetController/Commands/CommandTypes.hpp b/src/TargetController/Commands/CommandTypes.hpp index 99d2bf0a..344eaee0 100644 --- a/src/TargetController/Commands/CommandTypes.hpp +++ b/src/TargetController/Commands/CommandTypes.hpp @@ -31,5 +31,6 @@ namespace TargetController::Commands GET_TARGET_PROGRAM_COUNTER, ENABLE_PROGRAMMING_MODE, DISABLE_PROGRAMMING_MODE, + INVOKE_TARGET_PASSTHROUGH_COMMAND, }; } diff --git a/src/TargetController/Commands/InvokeTargetPassthroughCommand.hpp b/src/TargetController/Commands/InvokeTargetPassthroughCommand.hpp new file mode 100644 index 00000000..ae2dc103 --- /dev/null +++ b/src/TargetController/Commands/InvokeTargetPassthroughCommand.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "Command.hpp" +#include "src/TargetController/Responses/TargetPassthroughResponse.hpp" + +#include "src/Targets/PassthroughCommand.hpp" + +namespace TargetController::Commands +{ + class InvokeTargetPassthroughCommand: public Command + { + public: + using SuccessResponseType = Responses::TargetPassthroughResponse; + static constexpr CommandType type = CommandType::INVOKE_TARGET_PASSTHROUGH_COMMAND; + static const inline std::string name = "InvokeTargetPassthroughCommand"; + + Targets::PassthroughCommand command; + + explicit InvokeTargetPassthroughCommand(Targets::PassthroughCommand&& command) + : command(std::move(command)) + {}; + + [[nodiscard]] CommandType getType() const override { + return InvokeTargetPassthroughCommand::type; + } + + [[nodiscard]] bool requiresStoppedTargetState() const override { + return true; + } + }; +} diff --git a/src/TargetController/Responses/ResponseTypes.hpp b/src/TargetController/Responses/ResponseTypes.hpp index 28645649..6a13957b 100644 --- a/src/TargetController/Responses/ResponseTypes.hpp +++ b/src/TargetController/Responses/ResponseTypes.hpp @@ -17,5 +17,6 @@ namespace TargetController::Responses TARGET_STACK_POINTER, TARGET_PROGRAM_COUNTER, PROGRAM_BREAKPOINT, + TARGET_PASSTHROUGH_RESPONSE, }; } diff --git a/src/TargetController/Responses/TargetPassthroughResponse.hpp b/src/TargetController/Responses/TargetPassthroughResponse.hpp new file mode 100644 index 00000000..fafbb8c4 --- /dev/null +++ b/src/TargetController/Responses/TargetPassthroughResponse.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "Response.hpp" + +#include "src/Targets/PassthroughResponse.hpp" + +namespace TargetController::Responses +{ + class TargetPassthroughResponse: public Response + { + public: + static constexpr ResponseType type = ResponseType::TARGET_PASSTHROUGH_RESPONSE; + + std::optional response; + + explicit TargetPassthroughResponse(std::optional&& response) + : response(std::move(response)) + {} + + [[nodiscard]] ResponseType getType() const override { + return TargetPassthroughResponse::type; + } + }; +} diff --git a/src/TargetController/TargetControllerComponent.cpp b/src/TargetController/TargetControllerComponent.cpp index fa8335d0..947254f0 100644 --- a/src/TargetController/TargetControllerComponent.cpp +++ b/src/TargetController/TargetControllerComponent.cpp @@ -51,6 +51,7 @@ namespace TargetController using Commands::GetTargetProgramCounter; using Commands::EnableProgrammingMode; using Commands::DisableProgrammingMode; + using Commands::InvokeTargetPassthroughCommand; using Responses::Response; using Responses::AtomicSessionId; @@ -60,6 +61,7 @@ namespace TargetController using Responses::TargetStackPointer; using Responses::TargetProgramCounter; using Responses::ProgramBreakpoint; + using Responses::TargetPassthroughResponse; TargetControllerComponent::TargetControllerComponent( const ProjectConfig& projectConfig, @@ -262,6 +264,10 @@ namespace TargetController std::bind(&TargetControllerComponent::handleDisableProgrammingMode, this, std::placeholders::_1) ); + this->registerCommandHandler( + std::bind(&TargetControllerComponent::handleTargetPassthroughCommand, this, std::placeholders::_1) + ); + // Register event handlers this->eventListener->registerCallbackForEventType( std::bind(&TargetControllerComponent::onShutdownTargetControllerEvent, this, std::placeholders::_1) @@ -1173,4 +1179,10 @@ namespace TargetController return std::make_unique(); } + + std::unique_ptr TargetControllerComponent::handleTargetPassthroughCommand( + InvokeTargetPassthroughCommand& command + ) { + return std::make_unique(this->target->invokePassthroughCommand(command.command)); + } } diff --git a/src/TargetController/TargetControllerComponent.hpp b/src/TargetController/TargetControllerComponent.hpp index 5cc2e30d..74e529c8 100644 --- a/src/TargetController/TargetControllerComponent.hpp +++ b/src/TargetController/TargetControllerComponent.hpp @@ -45,6 +45,7 @@ #include "Commands/GetTargetProgramCounter.hpp" #include "Commands/EnableProgrammingMode.hpp" #include "Commands/DisableProgrammingMode.hpp" +#include "Commands/InvokeTargetPassthroughCommand.hpp" // Responses #include "Responses/Response.hpp" @@ -57,6 +58,7 @@ #include "Responses/TargetStackPointer.hpp" #include "Responses/TargetProgramCounter.hpp" #include "Responses/ProgramBreakpoint.hpp" +#include "Responses/TargetPassthroughResponse.hpp" #include "src/DebugToolDrivers/DebugTools.hpp" #include "src/Targets/BriefTargetDescriptor.hpp" @@ -379,5 +381,8 @@ namespace TargetController ); std::unique_ptr handleEnableProgrammingMode(Commands::EnableProgrammingMode& command); std::unique_ptr handleDisableProgrammingMode(Commands::DisableProgrammingMode& command); + std::unique_ptr handleTargetPassthroughCommand( + Commands::InvokeTargetPassthroughCommand& command + ); }; } diff --git a/src/Targets/Microchip/AVR8/Avr8.cpp b/src/Targets/Microchip/AVR8/Avr8.cpp index c56b92bd..3f8cac68 100644 --- a/src/Targets/Microchip/AVR8/Avr8.cpp +++ b/src/Targets/Microchip/AVR8/Avr8.cpp @@ -335,6 +335,14 @@ namespace Targets::Microchip::Avr8 } } + // Make RAM, FLASH and EEPROM available for inspection the Insight GUI. + descriptor.getMemorySegmentDescriptor("data", "internal_ram").inspectionEnabled = true; + descriptor.getMemorySegmentDescriptor("prog", "internal_program_memory").inspectionEnabled = true; + descriptor.getMemorySegmentDescriptor( + descriptor.getFirstAddressSpaceDescriptorContainingMemorySegment("internal_eeprom").key, + "internal_eeprom" + ).inspectionEnabled = true; + return descriptor; } @@ -683,6 +691,11 @@ namespace Targets::Microchip::Avr8 return this->activeProgrammingSession.has_value(); } + std::optional Avr8::invokePassthroughCommand(const PassthroughCommand& command) { + // AVR targets do not currently support any passthrough commands + return std::nullopt; + } + std::map Avr8::generateGpioPadDescriptorMapping( const std::vector& portPeripheralDescriptors ) { diff --git a/src/Targets/Microchip/AVR8/Avr8.hpp b/src/Targets/Microchip/AVR8/Avr8.hpp index a190e6c0..5329e60e 100644 --- a/src/Targets/Microchip/AVR8/Avr8.hpp +++ b/src/Targets/Microchip/AVR8/Avr8.hpp @@ -105,11 +105,11 @@ namespace Targets::Microchip::Avr8 void setGpioPadState(const TargetPadDescriptor& padDescriptor, const TargetGpioPadState& state) override; void enableProgrammingMode() override; - void disableProgrammingMode() override; - bool programmingModeEnabled() override; + std::optional invokePassthroughCommand(const PassthroughCommand& command) override; + protected: DebugToolDrivers::TargetInterfaces::TargetPowerManagementInterface* targetPowerManagementInterface = nullptr; DebugToolDrivers::TargetInterfaces::Microchip::Avr8::Avr8DebugInterface* avr8DebugInterface = nullptr; diff --git a/src/Targets/PassthroughCommand.hpp b/src/Targets/PassthroughCommand.hpp new file mode 100644 index 00000000..d7ab62b1 --- /dev/null +++ b/src/Targets/PassthroughCommand.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +namespace Targets +{ + struct PassthroughCommand + { + std::vector arguments; + }; +} diff --git a/src/Targets/PassthroughResponse.hpp b/src/Targets/PassthroughResponse.hpp new file mode 100644 index 00000000..09396484 --- /dev/null +++ b/src/Targets/PassthroughResponse.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace Targets +{ + struct PassthroughResponse + { + std::string output; + }; +} diff --git a/src/Targets/RiscV/Wch/WchRiscV.cpp b/src/Targets/RiscV/Wch/WchRiscV.cpp index cb2ee4a5..1c7fe14a 100644 --- a/src/Targets/RiscV/Wch/WchRiscV.cpp +++ b/src/Targets/RiscV/Wch/WchRiscV.cpp @@ -3,12 +3,13 @@ #include #include - #include "src/Targets/DynamicRegisterValue.hpp" #include "src/Exceptions/InvalidConfig.hpp" #include "src/Exceptions/Exception.hpp" +#include "src/EventManager/EventManager.hpp" + #include "src/Services/StringService.hpp" #include "src/Logger/Logger.hpp" @@ -350,6 +351,95 @@ namespace Targets::RiscV::Wch return programCounter; } + std::optional WchRiscV::invokePassthroughCommand(const PassthroughCommand& command) { + using Services::StringService; + + const auto& arguments = command.arguments; + if (arguments.empty()) { + return std::nullopt; + } + + auto response = PassthroughResponse{}; + + try { + if (arguments[0] == "pm") { + const auto &actualAliasedSegment = this->resolveAliasedMemorySegment(); + + if (arguments.size() == 1) { + response.output = "Program mode: \"" + StringService::applyTerminalColor( + actualAliasedSegment == this->bootProgramSegmentDescriptor ? "boot mode" : "user mode", + StringService::TerminalColor::DARK_YELLOW + ) + "\"\n"; + response.output += "Aliased memory segment key: \"" + + StringService::applyTerminalColor( + actualAliasedSegment.key, + StringService::TerminalColor::DARK_YELLOW + ) + "\"\n"; + response.output += "Mapped address -> aliased address: " + StringService::applyTerminalColor( + "0x" + StringService::asciiToUpper( + StringService::toHex(this->mappedSegmentDescriptor.addressRange.startAddress) + ), + StringService::TerminalColor::BLUE + ) + " -> " + StringService::applyTerminalColor( + "0x" + StringService::asciiToUpper( + StringService::toHex(actualAliasedSegment.addressRange.startAddress) + ), + StringService::TerminalColor::BLUE + ) + "\n"; + response.output += "Program counter: " + StringService::applyTerminalColor( + "0x" + StringService::asciiToUpper(StringService::toHex(this->getProgramCounter())), + StringService::TerminalColor::BLUE + ) + "\n"; + + return response; + } + + if (arguments[1] == "boot") { + if (actualAliasedSegment == this->bootProgramSegmentDescriptor) { + response.output += "Target is already in \"boot mode\"\n"; + response.output += "Proceeding, anyway...\n\n"; + } + + this->enableBootMode(); + EventManager::triggerEvent(std::make_shared()); + + response.output += "Boot mode has been enabled\n"; + response.output += "Program counter: " + StringService::applyTerminalColor( + "0x" + StringService::asciiToUpper(StringService::toHex(this->getProgramCounter())), + StringService::TerminalColor::BLUE + ) + "\n"; + + return response; + } + + if (arguments[1] == "user") { + if (actualAliasedSegment == this->mainProgramSegmentDescriptor) { + response.output += "Target is already in \"user mode\"\n"; + response.output += "Proceeding, anyway...\n\n"; + } + + this->enableUserMode(); + EventManager::triggerEvent(std::make_shared()); + + response.output += "User mode has been enabled\n"; + response.output += "Program counter: " + StringService::applyTerminalColor( + "0x" + StringService::asciiToUpper(StringService::toHex(this->getProgramCounter())), + StringService::TerminalColor::BLUE + ) + "\n"; + + return response; + } + } + + } catch (const Exceptions::Exception& exception) { + Logger::error("Passthrough command error: " + exception.getMessage()); + response.output = "Error: " + exception.getMessage(); + return response; + } + + return std::nullopt; + } + const TargetMemorySegmentDescriptor& WchRiscV::resolveAliasedMemorySegment() { /* * To determine the aliased segment, we probe the boundary of the boot segment via the mapped segment. diff --git a/src/Targets/RiscV/Wch/WchRiscV.hpp b/src/Targets/RiscV/Wch/WchRiscV.hpp index 86dfa06c..5fa75291 100644 --- a/src/Targets/RiscV/Wch/WchRiscV.hpp +++ b/src/Targets/RiscV/Wch/WchRiscV.hpp @@ -43,6 +43,8 @@ namespace Targets::RiscV::Wch TargetMemoryAddress getProgramCounter() override; + std::optional invokePassthroughCommand(const PassthroughCommand& command) override; + protected: WchRiscVTargetConfig targetConfig; TargetDescriptionFile targetDescriptionFile; diff --git a/src/Targets/Target.hpp b/src/Targets/Target.hpp index d69cca6f..6c39f0c5 100644 --- a/src/Targets/Target.hpp +++ b/src/Targets/Target.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "src/ProjectConfig.hpp" @@ -19,6 +20,9 @@ #include "TargetPadDescriptor.hpp" #include "TargetGpioPadState.hpp" +#include "PassthroughCommand.hpp" +#include "PassthroughResponse.hpp" + #include "src/DebugToolDrivers/DebugTool.hpp" namespace Targets @@ -150,5 +154,7 @@ namespace Targets virtual void enableProgrammingMode() = 0; virtual void disableProgrammingMode() = 0; virtual bool programmingModeEnabled() = 0; + + virtual std::optional invokePassthroughCommand(const PassthroughCommand& command) = 0; }; }