Last active
March 11, 2024 12:05
-
-
Save xor-gate/91a506ef0127bca97aab to your computer and use it in GitHub Desktop.
Semhosting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.0) | |
project(semihosting) | |
set(SRC main.c semihosting.c startup.c) | |
add_executable(main ${SRC}) | |
SET_TARGET_PROPERTIES(main PROPERTIES LINK_FLAGS "-T ${CMAKE_SOURCE_DIR}/standalone.ld -nostartfiles -Wl,--gc-sections") | |
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T ${CMAKE_SOURCE_DIR}/standalone.ld -L ${CMAKE_SOURCE_DIR}" ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <limits.h> | |
#include <stdatomic.h> | |
#include "semihosting.h" | |
int main() | |
{ | |
int fd; | |
static atomic_flag cat = ATOMIC_FLAG_INIT; | |
static unsigned volatile counter= 0; | |
do {} while (atomic_flag_test_and_set(&cat)); | |
++counter; | |
atomic_flag_clear(&cat); | |
fd = semihosting_open("./semihosting.log"); | |
semihosting_write(fd, "Hello World!\n", sizeof("Hello World!\n")); | |
while (1) { | |
semihosting_write(1, "Hello World!\n", sizeof("Hello World!\n")); | |
for (int i = 0; i < 10000000; i++) | |
__asm__("nop"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# From: http://shukra.cedt.iisc.ernet.in/w/index.php?title=EmSys:Starting_Cortex-M3_Development_Using_the_GNU_Tool_Chain_-_Part_2 | |
all: | |
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -g -c semihosting.c -o semihosting.o | |
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -std=c11 -g -c main.c -o main.o | |
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -g -c startup.c -o startup.o | |
arm-none-eabi-ld -g -T standalone.ld semihosting.o startup.o main.o -o main.elf | |
arm-none-eabi-objcopy -O binary main.elf main.bin | |
qemu-system-arm -M lm3s6965evb --kernel main.bin --serial null -nographic -monitor null -semihosting | |
# target remote localhost:1234 | |
objdump: | |
arm-none-eabi-objdump -d ./main.elf | |
gdb: | |
arm-none-eabi-gdb main.elf | |
clean: | |
rm -f *.o *.elf *.bin *.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
#include <stdint.h> | |
#include "semihosting.h" | |
void *__semihosting(uint32_t op, void *arg) | |
{ | |
(void)op; | |
(void)arg; | |
#ifdef __thumb2__ | |
asm("push {LR}; bkpt 0xAB; pop {PC}"); | |
#else | |
asm("push {LR}; svc 0xAB; pop {PC}"); | |
#endif | |
} | |
int semihosting_open(void *name) | |
{ | |
uint32_t open_parms[3]; | |
int status; | |
open_parms[0] = (uint32_t)name; | |
open_parms[1] = 9; | |
// open_parms[2] = strlen(name); | |
status = (int)__semihosting(SYS_OPEN, open_parms); | |
if (status < 0) | |
return -1; | |
return status; | |
} | |
int semihosting_close(unsigned int fd) | |
{ | |
uint32_t close_parms[1]; | |
int status; | |
close_parms[0] = fd; | |
status = (int)__semihosting(SYS_CLOSE, close_parms); | |
if (status < 0) | |
return -1; | |
return 0; | |
} | |
int semihosting_read(unsigned int fd, void *buf, unsigned int count) | |
{ | |
uint32_t read_parms[3]; | |
int status; | |
read_parms[0] = fd; | |
read_parms[1] = (uint32_t)buf; | |
read_parms[2] = count; | |
status = (int)__semihosting(SYS_READ, read_parms); | |
if (status < 0) | |
return status; | |
return count - status; | |
} | |
int semihosting_write(unsigned int fd, const void *buf, unsigned int count) | |
{ | |
uint32_t write_parms[3]; | |
int status; | |
write_parms[0] = fd; | |
write_parms[1] = (uint32_t)buf; | |
write_parms[2] = count; | |
status = (int)__semihosting(SYS_WRITE, write_parms); | |
if (status < 0) | |
return status; | |
return count - status; | |
} | |
/* ADP_Stopped_ApplicationExit is used for exit(0), | |
* anything else is implemented as exit(1) */ | |
//http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473c/CEGFDGED.html | |
#define ADP_Stopped_ApplicationExit (0x20026) | |
void semihosting_exit(int ret) | |
{ | |
uint32_t write_parms[1]; | |
int status; | |
if (ret == 0) | |
ret = ADP_Stopped_ApplicationExit; | |
write_parms[0] = ret; | |
__semihosting(SYS_EXIT, write_parms); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Semi-hosting I/O services | |
// $Id$ | |
// Copyright (C)2013-2015, Philip Munts, President, Munts AM Corp. | |
// | |
// 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. | |
// | |
// 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 HOLDER 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. | |
// These services ONLY work in debug mode. If your program calls any of these, | |
// it will NOT work unless you are debugging. | |
// Be sure to issue "monitor arm semihosting enable" in gdb before starting | |
// your program. | |
// Semi-hosting operations -- From "ARM Compiler toolchain Developing | |
// Software for ARM Processors,Version 5.03" | |
#include <stdint.h> | |
#define SYS_OPEN 0x01 | |
#define SYS_CLOSE 0x02 | |
#define SYS_WRITEC 0x03 | |
#define SYS_WRITE0 0x04 | |
#define SYS_WRITE 0x05 | |
#define SYS_READ 0x06 | |
#define SYS_READC 0x07 | |
#define SYS_ISERROR 0x08 | |
#define SYS_ISTTY 0x09 | |
#define SYS_SEEK 0x0A | |
#define SYS_FLEN 0x0C | |
#define SYS_TMPNAM 0x0D | |
#define SYS_REMOVE 0x0E | |
#define SYS_CLOCK 0x10 | |
#define SYS_TIME 0x11 | |
#define SYS_SYSTEM 0x12 | |
#define SYS_ERRNO 0x13 | |
#define SYS_GET_CMDLINE 0x15 | |
#define SYS_HEAPINFO 0x16 | |
#define SYS_EXIT 0x18 | |
#define SYS_ELAPSED 0x30 | |
#define SYS_TICKFREQ 0x31 | |
// Function prototypes | |
void *__semihosting(uint32_t op, void *arg) __attribute__((naked)); | |
int semihosting_register(char *name); | |
int semihosting_stdio(char *name); | |
int semihosting_open(void *name); | |
int semihosting_close(unsigned int fd); | |
int semihosting_read(unsigned int fd, void *buf, unsigned int count); | |
int semihosting_write(unsigned int fd, const void *buf, unsigned int count); | |
int semihosting_read_ready(unsigned int fd); | |
int semihosting_write_ready(unsigned int fd); | |
void semihosting_exit(int ret); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ENTRY(ResetISR) | |
MEMORY | |
{ | |
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K | |
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K | |
} | |
SECTIONS | |
{ | |
.text : | |
{ | |
KEEP(*(.isr_vector)) | |
*(.text*) | |
*(.rodata*) | |
_etext = .; | |
} > FLASH | |
.data : AT (ADDR(.text) + SIZEOF(.text)) | |
{ | |
_data = .; | |
*(vtable) | |
*(.data*) | |
_edata = .; | |
} > SRAM | |
.bss : | |
{ | |
_bss = .; | |
*(.bss*) | |
*(COMMON) | |
_ebss = .; | |
} > SRAM | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void ResetISR(void); | |
static void NmiSR(void); | |
static void FaultISR(void); | |
static void IntDefaultHandler(void); | |
extern int main(void); | |
static unsigned long pulStack[64]; | |
//***************************************************************************** | |
// | |
// The vector table. Note that the proper constructs must be placed on this to | |
// ensure that it ends up at physical address 0x0000.0000. | |
// | |
//***************************************************************************** | |
__attribute__ ((section(".isr_vector"))) | |
void (* const g_pfnVectors[])(void) = | |
{ | |
(void (*)(void))((unsigned long)pulStack + sizeof(pulStack)), | |
// The initial stack pointer | |
ResetISR, // The reset handler | |
NmiSR, // The NMI handler | |
FaultISR, // The hard fault handler | |
IntDefaultHandler, // The MPU fault handler | |
IntDefaultHandler, // The bus fault handler | |
IntDefaultHandler, // The usage fault handler | |
0, // Reserved | |
0, // Reserved | |
0, // Reserved | |
0, // Reserved | |
IntDefaultHandler, // SVCall handler | |
IntDefaultHandler, // Debug monitor handler | |
0, // Reserved | |
IntDefaultHandler, // The PendSV handler | |
IntDefaultHandler // The SysTick handler | |
}; | |
//***************************************************************************** | |
// | |
// The following are constructs created by the linker, indicating where the | |
// the "data" and "bss" segments reside in memory. The initializers for the | |
// "data" segment resides immediately following the "text" segment. | |
// | |
//***************************************************************************** | |
extern unsigned long _etext; | |
extern unsigned long _data; | |
extern unsigned long _edata; | |
extern unsigned long _bss; | |
extern unsigned long _ebss; | |
//***************************************************************************** | |
// | |
// This is the code that gets called when the processor first starts execution | |
// following a reset event. Only the absolutely necessary set is performed, | |
// after which the application supplied entry() routine is called. | |
// | |
//***************************************************************************** | |
void ResetISR(void) | |
{ | |
unsigned long *pulSrc, *pulDest; | |
// | |
// Copy the data segment initializers from flash to SRAM. | |
// | |
pulSrc = &_etext; | |
pulDest = &_data; | |
while(pulDest < &_edata ) | |
{ | |
*pulDest++ = *pulSrc++; | |
} | |
// | |
// Zero fill the bss segment. | |
// | |
__asm(" ldr r0, =_bss\n" | |
" ldr r1, =_ebss\n" | |
" mov r2, #0\n" | |
" .thumb_func\n" | |
"zero_loop:\n" | |
" cmp r0, r1\n" | |
" it lt\n" | |
" strlt r2, [r0], #4\n" | |
" blt zero_loop"); | |
// | |
// Call the application's entry point. | |
// | |
main(); | |
} | |
//***************************************************************************** | |
// | |
// This is the code that gets called when the processor receives a NMI. This | |
// simply enters an infinite loop, preserving the system state for examination | |
// by a debugger. | |
// | |
//***************************************************************************** | |
static void NmiSR(void) | |
{ | |
// | |
// Enter an infinite loop. | |
// | |
while(1) { | |
; | |
} | |
} | |
//***************************************************************************** | |
// | |
// This is the code that gets called when the processor receives a fault | |
// interrupt. This simply enters an infinite loop, preserving the system state | |
// for examination by a debugger. | |
// | |
//***************************************************************************** | |
static void FaultISR(void) | |
{ | |
// | |
// Enter an infinite loop. | |
// | |
while(1) { | |
; | |
} | |
} | |
//***************************************************************************** | |
// | |
// This is the code that gets called when the processor receives an unexpected | |
// interrupt. This simply enters an infinite loop, preserving the system state | |
// for examination by a debugger. | |
// | |
//***************************************************************************** | |
static void IntDefaultHandler(void) | |
{ | |
// | |
// Go into an infinite loop. | |
// | |
while(1) { | |
; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# CMake Toolchain file for the gcc-arm-embedded toolchain. | |
# https://launchpad.net/gcc-arm-embedded | |
# | |
# Copyright (c) 2013 Swift Navigation Inc. | |
# Contact: Fergus Noble <[email protected]> | |
# | |
# This source is subject to the license found in the file 'LICENSE' which must | |
# be be distributed together with this source. All other rights reserved. | |
# | |
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, | |
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED | |
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. | |
include(CMakeForceCompiler) | |
# Targeting an embedded system, no OS. | |
set(CMAKE_SYSTEM_NAME Generic) | |
set(CMAKE_SYSTEM_PROCESSOR cortex-m3) | |
CMAKE_FORCE_C_COMPILER(arm-none-eabi-gcc GNU) | |
CMAKE_FORCE_CXX_COMPILER(arm-none-eabi-g++ GNU) | |
# Find the target environment prefix.. | |
# First see where gcc is keeping libc.a | |
execute_process( | |
COMMAND ${CMAKE_C_COMPILER} -print-file-name=libc.a | |
OUTPUT_VARIABLE CMAKE_INSTALL_PREFIX | |
OUTPUT_STRIP_TRAILING_WHITESPACE | |
) | |
# Strip the filename off | |
get_filename_component(CMAKE_INSTALL_PREFIX | |
"${CMAKE_INSTALL_PREFIX}" PATH | |
) | |
# Then find the canonical path to the directory one up from there | |
get_filename_component(CMAKE_INSTALL_PREFIX | |
"${CMAKE_INSTALL_PREFIX}/.." REALPATH | |
) | |
set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE FILEPATH | |
"Install path prefix, prepended onto install directories.") | |
message(STATUS "Cross-compiling with the gcc-arm-embedded toolchain") | |
message(STATUS "Toolchain prefix: ${CMAKE_INSTALL_PREFIX}") | |
set(CMAKE_FIND_ROOT_PATH ${CMAKE_INSTALL_PREFIX}) | |
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) | |
set(CMAKE_C_FLAGS | |
"${CMAKE_C_FLAGS}" | |
"-fno-common -ffunction-sections -fdata-sections" | |
) | |
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "cortex-m4") | |
set(CMAKE_C_FLAGS | |
"${CMAKE_C_FLAGS}" | |
"-mcpu=cortex-m4 -march=armv7e-m -mthumb" | |
"-mfloat-abi=hard -mfpu=fpv4-sp-d16" | |
) | |
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "cortex-m3") | |
set(CMAKE_C_FLAGS | |
"${CMAKE_C_FLAGS}" | |
"-mcpu=cortex-m3 -march=armv7-m -mthumb " | |
"-msoft-float" | |
) | |
# --specs=nosys.specs | |
else () | |
message(WARNING | |
"Processor not recognised in toolchain file, " | |
"compiler flags not configured." | |
) | |
endif () | |
# When we break up long strings in CMake we get semicolon | |
# separated lists, undo this here... | |
string(REGEX REPLACE ";" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") | |
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "") | |
set(BUILD_SHARED_LIBS OFF) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment