Difference between revisions of "Semihosting with Ozone"

From SEGGER Wiki
Jump to: navigation, search
(Input Operations)
(Unsafe Operations)
Line 186: Line 186:
 
=== Unsafe Operations ===
 
=== Unsafe Operations ===
   
[[File:UnsafeSemihostingRequest.png|frame|Unsafe semihosting request]]
+
[[File:UnsafeSemihostingRequest.png|frame|The debuggee has requested an unsafe host operation via semihosting]]
   
 
The following group of semihosting operations are classified to be unsafe:
 
The following group of semihosting operations are classified to be unsafe:

Revision as of 09:44, 12 August 2019

Overview

Semihosting is the name of a communication protocol which provides an embedded target access to Host-PC resources. This article assumes that the reader is familiar with the technical aspects of semihosting. The focus of this article lies on the configuration and usage of semihosting within Ozone.

Supported Architectures

Ozone supports semihosting on the following target architectures:

  • Cortex-M (<= v8)
  • Cortex-A/R (<= v8)
  • Legacy-ARM
  • RISC-V

Terminal Window

All semihosting communication between the target and Ozone is logged to Ozone's terminal window. Terminal window contents can be routed to a session log file using command Project.SetTerminalLogFile. Ozone will also inform about the status of the current semihosting operation within its status bar. A typical status text may read Performing semihosting operation SysRead....

Terminal Window. The input field can be used to respond to input requests by the debuggee.

Target-specific Semihosting

This section will provide a short background on how Ozone performs target-specific semihosting on the different architectures.

A rundown on target-specific semihosting

In general, the debuggee issues a semihosting request to the debugger by executing any of the target-specific semihosting trap instructions. Before the trap instruction is executed, the debuggee loads the semihosting operation type to function argument register 0, and the semihosting argument pointer to function argument register 1, where they are exposed to the debugger. Once the debugger has finished processing the request, the debugger will write the operation result code back to function argument register 0 and resume the debuggee.

The semihosting argument pointer points to an argument block within target memory. The argument block stores an unaligned sequence of arguments. All arguments are word-sized (4 bytes on 32-bit targets and 8 bytes on 64-bit targets).

The function argument registers which are used for semihosting are defined by the target architecture's function calling convention ABI. They are r0 and r1 on ARM and a0 and a1 on RISC-V.

Semihosting with Ozone on Cortex-M

The debuggee signals a semihosting request to Ozone by executing the semihosting trap instruction BKPT #0xAB with encoding 0xBABC.

A code example of a client function which triggers a semihosting operation on the Host-PC and returns its result code is shown below.

int ExecuteSemihostingOperation(int op, void* p1, void* p2) {
  register int r0 asm(r0);
  register int r1 asm(r1) __attribute__((unused));
  register int r2 asm(r2) __attribute__((unused));

  r0 = op;
  r1 = (int) p1;
  r2 = (int) p2;

  asm volatile(
       BKPT 0xAB \n
      : =r(r0) // out
      : // in
      : // clobber
  );
  return r0;
}

Semihosting with Ozone on Cortex-A/R

The debugeee signals a semihosting request to Ozone by executing any of the 5 semihosting trap instructions:

In A64 execution state:

  • HLT #0xF000 with encoding 0xD45E0000.

In A32 execution state:

  • SVC #0x123456 with encoding 0xEF123456.
  • HLT #0xF000 with encoding 0xE10F0070.

In T32 execution state:

  • SVC #0xAB with encoding 0xDFAB.
  • HLT #0x3C with encoding 0xBABC.

As executing SVC does not enter debug state, in order to catch the semihosting request via SVC, the debugger will set a vector catch on the SVC exception.

Semihosting with Ozone on Legacy-Arm

The debugeee signals a semihosting request to Ozone by executing any of the 2 semihosting trap instructions:

In A32 execution state:

  • SVC #0x123456 with encoding 0xEF123456.

In T32 execution state:

  • SVC #0xAB with encoding 0xDFAB.

Semihosting with Ozone on RISC-V

RISC-V does not (yet) define any architecure-specific semihosting trap instructions. For this reason, semihosting on RISC-V can only be performed using the generic semihosting mechanism described in the next section.

Generic Semihosting

SEGGER has defined the first instruction of function SEGGER_SEMIHOST_DebugHalt to be a universal semihosting trap which is available on all target architectures. In order to catch this trap, the debugger sets a hidden breakpoint on the function whenever it is implemented by the debuggee. In order to perform a semihosting request, the debuggee simply calls this function with the desired operation code as first parameter and the operation argument block pointer as second parameter.

/*********************************************************************
*
*       SEGGER_SEMIHOST_DebugHalt()
*
*  Function description
*    Generic semihosting request function.
*    The debugger may set a breakpoint on this function, handle the 
*    semihosting request, and return to the caller.
*
*  Parameters
*    a0: semihosting operation code
*    a1: semihosting operation argument pointer
*
*  Return value
*    a0 if debugger is not connected.
*    Semihosting operation result code if debugger is connected.
*/
int __attribute__((noinline)) SEGGER_SEMIHOST_DebugHalt(int a0, int a1) {
  (void)a1;   // Avoid unused parameter warning
  return a0;
}

Supported Operations

This section lists the semihosting operations supported by Ozone. These are the possible values that the debuggee can write to argument register 0 when issuing a semihosting request to Ozone.

Custom Operations

Ozone supports the following semihosting operations defined by SEGGER:

Operation Description
SysIsConnected (0x0) Returns the debugger connection status. When the debugger is connected to the target, it writes a value of 1 to the result register a0. Otherwise, the result register will be left unmodified. This operation has no arguments.
SysWritef (0x40) Outputs a formatted string on the debug terminal. The text formatting is performed by the debugger, i.e. on the host. The argument block for SysWritef (pointer to by a1) consists of two entries: the first entry is the format string. The second entry is a pointer to a variable argument list (va_list) which contains the format arguments. The format string and arguments must follow the C library rules for printf.

Legacy Operations

Ozone suppports the following legacy semihosting operations defined by Arm:

  • SysOpen
  • SysClose
  • SysWriteC
  • SysWrite0
  • SysWrite
  • SysRead
  • SysReadC
  • SysRemove
  • SysRename
  • SysIsError
  • SysIsTty
  • SysSeek
  • SysFlen
  • SysClock
  • SysTime
  • SysErrno
  • SysGetCmdLine
  • SysExit

The following legacy operations are currently not supported:

  • SysTmpNam
  • SysSystem
  • SysTickFreq
  • SysElapsed
  • SysHeapInfo

For further information on the legacy operations, including their opcode and parameter definitions, see references.

Unsafe Operations

The debuggee has requested an unsafe host operation via semihosting

The following group of semihosting operations are classified to be unsafe:

  • SysOpen
  • SysRemove
  • SysRename

These operations can potentially damage the host system. Each time an unsafe operation is requested by the debuggee, Ozone will ask the user for permission to perform the operations via a popup dialog.

Individual permission dialogs can be suppressed. As an example, operation SysRename can be suppressed via setting AllowRename=0, as described in section Semihosting Configuration.

Input Operations

Ozone supports the following semihosted user input operations:

The debuggee has requested user input via semihosting
  • SysReadC and
  • SysRead with IsTtyHandle(R1)==1

Users may serve input requests by:

  • entering text into the terminal window's input field and pressing enter or
  • by entering text into a popup dialog.

The input mode can be configured via setting InputViaTerminal=0/1, as described in section Semihosting Configuration.

Semihosting input operations will block the client task until a text was input. When a text was input for operation SysRead, Ozone returns the integer result code <NumBytesRequested> - <NumBytesInput> to the debuggee. When a text was input for operation SysReadC, the input character is returned as the result code.

Semihosting Configuration

Ozone's semihosting functionality can be configured in two ways:

The semihosting settings dialog is available from the Tools menu
  • using the semihosting settings dialog, accessible from the Tools menu.
  • using command Project.ConfigSemihosting.

Ozone automatically enables semihosting when the debug session is started. No user interaction is required. However, it is recommended to disable semihosting when it is not needed for performance reasons.

Project.ConfigSemihosting

Command Project.ConfigSemihosting has a single argument which is a settings string of the format setting1=value1,setting2=value2,....

The available settings for this command are:

  • AllowOpenRead
  • AllowOpenWrite
  • AllowRename
  • AllowRemove
  • ModeSVC
  • ModeBKPT
  • ModeBP
  • InputViaTerminal
  • Vector
  • BKPTNumber
  • SVCNumberARM
  • SVCNumberThumb
  • BPAddress
  • TargetCmdLine

The command can be employed from within script or plugin functions. The remainder of this section describes each of the above settings in detail. The default value for each setting is rendered in bold font.

AllowOpenRead

Sets the permission for semihosting operation SysOpen when file flag READ is set.

Value Description
0 (Ask) A popup dialog is shown which asks the user if the operation should be performed.
1 (Yes) The operation is always allowed
2 (No) The operation is never allowed

AllowOpenWrite

Sets the permission for semihosting operation SysOpen when file flag WRITE is set.

Value Description
0 (Ask) A popup dialog is shown which asks the user if the operation should be performed.
1 (Yes) The operation is always allowed
2 (No) The operation is never allowed

AllowRename

Sets the permission for semihosting operation SysRename.

Value Description
0 (Ask) A popup dialog is shown which asks the user if the operation should be performed.
1 (Yes) The operation is always allowed
2 (No) The operation is never allowed

AllowRemove

Sets the permission for semihosting operation SysRemove.

Value Description
0 (Ask) A popup dialog is shown which asks the user if the operation should be performed.
1 (Yes) The operation is always allowed
2 (No) The operation is never allowed

ModeSVC

Enables or disables semihosting via the SVC instruction.

Value Description
0 (Yes, ask on non-semihosting SVC) Semihosting via SVC enabled. A vector catch will be set on the SVC exception at debug session start. A popup dialog will be shown each time the program stops on the vector catch, but not due to a semihosting request (i.e. when a non-semihosting software interrupt was triggered).
1 (Yes) Semihosting via SVC enabled. A vector catch will be set on the SVC exception at debug session start.
2 (No) Semihosting via SVC disabled. No vector catch will be set for semihosting on debug session start.

ModeBKPT

Enables or disables semihosting via the BKPT instruction.

Value Description
0 (Yes) Semihosting via BKPT enabled.
1 (No and continue) Semihosting via BKPT disabled. When the debuggee halts on a BKPT semihosting trap instruction, it is automatically resumed by Ozone.
2 (No and halt) Semihosting via BKPT disabled. The debuggee halts on BKPT semihosting trap instructions.

ModeBP

Enables or disables semihosting via the generic trap instruction.

Value Description
0 (Yes) Semihosting on breakpoint enabled. A hidden breakpoint on address BPAddress will be set on debug session start.
1 (No) Semihosting on breakpoint disabled. No hidden breakpoint will be set on debug session start.

InputViaTerminal

Sets the user input mode.

Value Description
0 (No) User input is obtained via a popup dialog that is shown each time Ozone receives a semihosting input request from the debuggee.
1 (Yes) User input is obtained via the terminal prompt, which gets highlighted and focused each time Ozone receives a semihosting input request from the debuggee.

Vector

When semihosting is in its default configuration state and enabled, Ozone will set a vector catch on the SVC instruction at address 0x8 in order to catch semihosting requests. This default behavior can reduce the run-time performance of clients which make extensive use of software interrupts. In order to alleviate this problem, Ozone provides semihosting configuration setting Vector.

Setting Vector instructs Ozone to set a hidden breakpoint on arbitrary address Vector within the SVC handler instead of setting a vector catch on SVC. The breakpointed instruction then acts as the semihosting SVC trap instead of the vector catch. This way, developers get the chance to evaluate the SWI opcode within the SVC handler on the target side. The handler code is expected to execute the trap instruction only when the SWI opcode matches a semihosting SWI opcode. When this option is employed, developers have to make sure that the semihosting opcode and argument pointer registers R0, R1 and R2 are not modified within SVC handler code up to the point where the trap instruction is executed.

ThumbSVCNumber

Edits the SWI number definition of the 16-bit thumb SVC semihosting trap instruction. The default value for this setting is 0xAB. The valid range for this value is 0-0xFF. As an example, when SVC semihosting requests are to be performed via instruction SVC #0x10, then this setting should be set to value 0x10.

ARMSVCNumber

Edits the SWI number definition of the 32-bit ARM SVC semihosting trap instruction. The default value for this setting is 0x123456. The valid range for this value is 0-0xFFFFFF. As an example, when SVC semihosting requests are to be performed via instruction SVC #0x1234, then this setting should be set to value 0x1234.

BKPTNumber

Edits the software breakpoint number definition of the BKPT semihosting trap instruction. The default value for this setting is 0xAB. The valid range for this value is 0-0xFF. As an example, when SVC semihosting requests are to be performed via instruction BKPT #0x10, then this setting should be set to value 0x10.

BPAddress

Edits the address of the generic semihosting trap instruction. The default value for this setting is the base address of function SEGGER_SEMIHOST_DebugHalt. The valid value range for this setting is the address range of function SEGGER_SEMIHOST_DebugHalt. Depending on setting ModeBP, Ozone will or will not set a hidden breakpoint on the configured address in order to catch generic semihosting requests by the debuggee.

TargetCmdLine

Sets the command line text that Ozone is to transmit to the debuggee when it receives semihosting request SysGetCmdLine. This is the only setting that can not be edited via the settings dialog.

Settings Dialog

Semihosting Settings Dialog

The settings dialog can be opened from the tools menu or the terminal window's context menu. It allows users to conveniently edit any of the semihosting settings described in the previous section.

Disabling Semihosting

Since the debugger possibly sets a breakpoint or vector catch in order to support semihosting, it is recommended to explicitly disable semihosting when it is not needed. To disable semihosting, the settings ModeBP, ModeBKPT and ModeSVC must be set to No, i.e. their highest allowed value.

General Considerations When Using Semihosting

Avoiding Exceptions

Depending on the architecture, a target might produce an exception or go in to lockup if it executes a semihosting trap instruction while a debugger is not attached. It is therefore generally a good strategy to maintain the debugger connection status in a variable and only execute the trap when the debugger is connected. As an example, On Cortex-M the connection status can be read from system register DHCSR.

Avoiding Deadlocks

Client developers also have to be aware of the fact that a semihosting operation will block the requesting task for a possibly very long period of time. The debugger might even run into an error or disconnect while executing a semihosting operation, leaving the debuggee in a blocked state. To avoid a deadlock in this situations, a robust client implementation can set up a watchdog to resume itself from a semihosting trap on timeout.

References

Standard technical references on semihosting:

  • ARM info center, What is Semihosing?

Ozone-specific semihosting resources:

  • SEGGER Wiki article on Semihosting [[1]]
  • Ozone user guide, section Terminal IO