RISC-V semi-hosting原理以及实践

news2024/12/24 21:03:18

嵌入式裸机调试需要在有限资源的目标硬件上尽可能挖掘更多的信息,比如打印寄存器等等,但是即便看似很简单的串口打印,在有的情况下也是奢望,针对这种情况,能够有效利用主机资源协同调试的semi-host(半主机)技术应运而生。以下是关于semi-host的简单介绍。

  1. semi-host机制使用在目标处理器(arm,riscv等)上运行代的代码能够与正在运行调试器的主机进行通信,并使用其IO设施。
  2. 这些设施包括键盘,屏幕和磁盘IO.
  3. 嵌入式端使用C库中的函数(printf,scanf)能够使用主机的屏幕和键盘,而无需在目标系统上具备屏幕和键盘。
  4. semi-host最早由ARM在1995年定义,公开了ARM半主机规范,被很多调试器和C库支持,调试器比如jlink(rtti),trace32,以及ICE仿真器等,C库包括newlib,picolibc等。
  5. RISCV基于ARM版本也定义了自己的半主机规范。

semihost工作原理

semihosting=semi+hosting,表明了半主机操作一半在目标设备上执行,另一半在主机上执行,半主机通过一组特殊的软件指令序列来陷入主机,例如ARM的svc指令,RISCV的ebreak指令,这些指令会出发CPU进入异常执行流,在异常执行流中,执行调试代理程序处理异常,这些调试代理程序包括解析半主机命令并实现和主机通信的逻辑实现。

下图表示在不依赖串口的情况下,资源受限的目标平台将调试信息打印到主机的过程。

流程如下:

  • 目标设备上的应用程序调用标准库函数printf.
  • 在库的底层不会将调用重定向到串口,而是准备号要发送的数据后,使用特殊指令ebreak通知调试器。
  • 调试器收到通知后,检测到SEMI-HOST请求,然后执行对应的处理程序,将字符串显示出来。

下图是newlibc中 RISCV架构下触发SEMI-HOST请求的代码,在libgloss/riscv/semihost_syscall.h文件中。

由于CPU没有为semi-host保留异常号,为了将semihost触发的异常和其它异常区分开,在ebreak指令周围添加额外的指令来帮助调试器区分“半主机ebreak"和“常规ebreak".

其它约定包括,半主机调用号通过寄存器a0传递,调用参数的指针地质,通过a1寄存器传递,返回值放在a0中。

规范一共定义了24种类型的半主机调用:

picolibc中对方法的定义

支持半主机的C库
  1. Newlibc,如上截图。
  2. Picolibc,fork from newlibc.但是更轻量。
  3. Arm CMSIS。

如前面所谓分析,半主机主要是为了解决资源有限平台上的协同调试开发问题,glibc,musl libc等面向LINUX等大型应用场景的LIBC库不需要支持半主机,因为后者主要运行于RICH OS上,无需支持半主机机制。

QEMU半主机测试环境搭建

测试应用基于picolibc,编译方法如下:

$ sudo apt install gcc-riscv64-unknown-elf meson
$ git clone https://github.com/picolibc/picolibc.git
$ cd picolibc && mkdir build && cd build
$ ../scripts/do-riscv-configure
$ ninja
$ suso ninja install

编译生成了测试用例test/semihost/semihost-exit-extended-failure_rv64imafdc_lp64d, 之后安装

编译RISCV 64 QEMU:

参考博客Qemu在ARM和X86平台上的运行机制初探_papaofdoudou的博客-CSDN博客

这里使用8.0.0的QEMU,编译配置:

$ ./configure --target-list=arm-softmmu,aarch64-softmmu,i386-softmmu,x86_64-softmmu,riscv32-softmmu,riscv64-softmmu,aarch64-linux-user,arm-linux-user,riscv64-linux-user,x86_64-linux-user --audio-drv-list=alsa,sdl,pa --enable-system --enable-user --enable-linux-user --enable-sdl --enable-vnc --enable-virtfs --enable-kvm --enable-fdt --enable-debug --disable-strip --enable-debug-tcg --enable-debug-info --enable-debug --disable-strip --enable-vnc --prefix=/home/zlcao/semihost/install
$ make
$ make install

测试用例:

#include <stdio.h>

int main(void)
{
	printf("%s line %d, hello semihosting.\n", __func__, __LINE__);

	return 0;
}

编译

$ riscv64-unknown-elf-gcc --specs picolibc.specs --oslib=semihost -march=rv64imac -mabi=lp64 -mcmodel=medany -static main.c -o main

--oslib=semihost告诉编译器使用picolibc的semihost版实现,因为正常情况下它也有一个实现。使用picolibc.specs将程序连接到0x80000000运行,这是大部分RISCV及其内存的起始地址,也是QEMU “virt”及其的内存基址。由于使用的工具链是裸机工具链,这个地址是物理地址。

使用 qemu "virt" -serial stdio查看没有任何输出,因为我们用的是半主机的printf调用,没有用到串口终端,所以这里没有任何输出。

./../install/bin/qemu-system-riscv64 -M virt -bios main -display none -serial stdio

但是当我们加上-serial null -semihosting运行时,输出便出现了,-serial null的目的是禁止标准输出,这样如果有输出,一定是半主机机制的,方便对照,不加也行。

$ ./../install/bin/qemu-system-riscv64 -M virt -bios main -display none -serial null -semihosting

-bios目的是禁止opensbi启动。

手搓裸金属半主机用例

前面的用例使用了picolibc的半主机版printf实现,并且仅仅依赖于其实现,所以我们完全可以模仿printf手搓一份输出字符串调用,传入a0 4号半主机调用,调用名称SYS_WRITEO,该调用将目标机上一个以NULL结尾的字符串在主机侧的终端上输出。

实现代码:

测试用例源码:

static void smh_puts(char *str)
{
	asm volatile("addi  a1, %0, 0\n"
			"addi a0, zero, 4\n"
			".balign 16\n"
			".option push\n"
			".option norvc\n"
			"slli zero, zero, 0x1f\n"
			"ebreak\n"
			"srai zero, zero, 0x7\n"
			".option pop\n"
			: : "r"(str) : "a0", "a1", "memory");
}

int main(void)
{
	smh_puts("hello semihosting.\n");

	return 0;
}
C启动源码:
.text
.globl _start

_start:
	li sp, 0x80100000
	tail main

链接脚本semihosting.ld

OUTPUT_ARCH("riscv")
ENTRY(_start)

SECTIONS
{
	. = 0x80000000;
	.text : {
		crt0.o (.text)
		main.o (.text)
	}

	.rodata : {
		*(.rodata*)	
	}

	.data : {
		*(.data*)
	}
	
	.bss : {
		*(.bss*)
	}
}
makefile
all:
	riscv64-unknown-elf-gcc -nostdlib -march=rv64imac -mabi=lp64 -mcmodel=medany -static -c main.c -o main.o
	riscv64-unknown-elf-gcc -nostdlib -march=rv64imac -mabi=lp64 -mcmodel=medany -static -c crt0.S -o crt0.o
	riscv64-unknown-elf-ld -Tsemihosting.ld -static  crt0.o main.o -o main

sim:
	../install/bin/qemu-system-riscv64 -M virt -bios main -display none -serial null -semihosting

测试,可以看到,字符串通过SEMI HOST机制正常打印出来。 

qemu semihost实现

相对于运行用例,qemu站在上帝视角,相当于SEMIHOST架构中的主机方,其核心SEMI HOST实现逻辑是用函数do_common_semihosting实现的。

以SEMI HOST的文件操作命令为例,最终其调用的世纪上也是通过HOST机的OPEN函数实现的。

fopen的semihost实现

总结

半主机技术提供了一个便捷的开发环境,加快开发速度,优点包括:

  1. 方便调试和开发。
  2. 节省资源。
  3. 快速开发和原型验证
  4. 灵活,可移植性好
参考文章

ARM Semihosting - native but slow Debugging - Code Inside Out


结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/676135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

B. Fish Graph(dfs找环)

Problem - 1817B - Codeforces 给定一个具有n个节点和m条边的简单无向图。请注意&#xff0c;该图不一定是连通的。节点从1到n标记。 如果图包含具有特殊节点u的简单循环&#xff0c;则定义图为Fish Graph。除循环中的边之外&#xff0c;图应恰好有2条额外的边。两条边都应连接…

设计模式之外观模式笔记

设计模式之外观模式笔记 说明Facade(外观)目录外观模式示例类图电灯类电视机类空调类智能音箱外观类测试类 说明 记录下学习设计模式-外观模式的写法。JDK使用版本为1.8版本。 Facade(外观) 意图:为子系统中的一组接口提供一个一致的界面&#xff0c;Facade模式定义了一个高…

【2023,学点儿新Java-23】初步了解Java中的修饰符:static及其作用、native特性、final的理解

前情回顾&#xff1a; 【2023&#xff0c;学点儿新Java-22】Java中package的作用是什么 | Java中import的用法 | Java中的权限修饰符&#xff1a;private、protected、public【2023&#xff0c;学点儿新Java-21】Java中default的语法格式 | 父类私有的方法能被重写吗&#xff…

三分钟学习一个python小知识3-----------我的对python的列表和元组的理解

我的目录 1、python是什么2、列表的应用3. 元组的应用&#xff1a;4、深层次地进一步理解列表和元组4.1. 列表示例&#xff1a;4.2. 元组示例&#xff1a; 总结 1、python是什么 在Python中&#xff0c;列表和元组都是用于存储多个数据项的数据结构&#xff0c;但是它们有一些…

JavaWeb Tomcat

1.Web分类 静态web html这样的静态网页&#xff0c;只展示预先设定好的内容每个用户看到的内容是一样的不连接数据库&#xff0c;无法持久化数据&#xff08;比如注册&#xff09;动态web 动态展示内容每个用户看到的内容是不一样的&#xff0c;比如会有个性化推荐连接数据库&…

TienChin 项目改造完善项目结构分析

项目改造完善 更改 Banner Banner 生成网站&#xff1a;https://bootschool.net/ascii 更改启动类中的 Banner !> 如果不生效&#xff0c;需要重新编译一下项目工程(出现了启动之后还没改变就需要执行一下这个步骤)&#xff1a; 出现的原因是可能你没有删除 .idea 文件与 .i…

夜不收见证:夫妻从内江到成都,从真诚到真相

他们从四川内江的一条小巷&#xff0c;走进了成都的大街小巷。那里的房屋挨挨挤挤&#xff0c;像是在讲述他们曾经的梦想和勇气。他们是那些在内江的土地上种下了友情种子的少年&#xff0c;他们在成都的大地上&#xff0c;硕果累累。 他们从初中的课桌前走到了成人的世界里&am…

模拟电路系列文章-滤波器常识

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 滤波是一个动作&#xff0c;对不同频率输入信号&#xff0c;实施不同的增益和相移&#xff0c;以形成输出。滤波器&#xff0c;是执行这种动作的硬件设备或者软件程序。无论滤…

DJ4-7 SDN、OpenFlow

目录 一、SDN 1、SDN 的引入 2、SDN 体系结构的特征 3、SDN 控制器 4、SDN 通用转发 二、OpenFlow 一、SDN 1、SDN 的引入 软件定义网络 (Software Defined Network) SDN 源自美国斯坦福大学 Clean Slate 研究组提出的一种新型网络创新架构&#xff0c;可通过软件编程…

OCC-BEV:基于三维场景重建的多摄像机统一预训练

论文&#xff1a;https://arxiv.org/pdf/2305.18829.pdf 代码&#xff1a;https://github.com/chaytonmin/Occ-BEV 多摄像机3D感知技术&#xff08;能够收集车辆周围360的环境信息&#xff09;已经成为自动驾驶领域的一个突出研究领域&#xff0c;为 Lidarb-based 解决方案提供…

EMC学习笔记(九)特殊信号的EMC处理(一)

特殊信号的EMC处理&#xff08;一&#xff09; 1.电源接口EMC防护滤波电路1.1 24VDC电源口1.2 电源地的EMC电路1.3 Flyback EMC电路1.4 BUCK电路EMC电路1.5 推挽电路 2.时钟电路的EMC防护2.1 有源时钟2.2 无源时钟2.3 差分时钟 3.复位电路EMC防护4.对外接口信号的EMC防护4.1 差…

简历不要随意给猎头!他们会胡乱投递,影响你之后求职!

猎头是求职的重要途径之一&#xff0c;但猎头群体良莠不齐&#xff0c;并不是每个猎头都值得信任。 一位网友就对猎头持怀疑态度&#xff0c;问大家&#xff1a; 简历可以随意给猎头吗&#xff1f;给他们的时候需要注意什么&#xff1f;他们会不会群发&#xff0c;对自己之后求…

软考A计划-系统集成项目管理工程师-一般补充知识-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

F429驱动TFT裸屏时LTDC

F429驱动TFT裸屏时LTDC时序配置说明&#xff08;以V6的7寸驱动为例&#xff09; 说明&#xff1a; 1. 经常有兄弟问到这个问题&#xff0c;所有这里就写一个帖子。 2. 基础知识学习&#xff1a; TFT LCD的DE模式和HV模式的区别&#xff1a;http://bbs.armfly.com/read.php?tid…

Kafka搭建部署

解压文件 启动zookeeper 配置kafka环境变量 查看Kafka的版本内容 分发Kafka文件到slave1、slave2 修改server.properties文件 在Master、slave1和slave2节点上分别启动Kafka 在Master节点上执行如下命令来创建Topic 解压文件 tar -zxvf kafka_2.12-2.4.1.tgz -C /opt …

2022(一等奖)基于哨兵2影像的典型地表参量和红边指数的特征空间石漠化遥感监测模型

作品介绍 1 监测模型设计概述 &#xff08;1&#xff09;应用背景 石漠化是危害人们安全的自然灾害之一&#xff0c;也是土壤荒漠化其中的一种。我国西南地区是全球石漠化现象最严重的地区之一&#xff0c;长期的人为干预使得生态环境变得非常敏感&#xff0c;地表植被破坏严…

升级系统到Proxmox VE 8

Proxmox VE 8.0正式版发布 Proxmox VE 需要升级到7.4&#xff0c;验证一下。 rootpve99:~# pveversion pve-manager/7.4-13/46c37d9c (running kernel: 5.13.19-6-pve) rootpve99:~# pve7to8 CHECKING VERSION INFORMATION FOR PVE PACKAGES Checking for package updates.…

【实战与杂谈】本地搭建自己的游戏王卡片生成器

声明&#xff1a; 1.游戏王卡片制作器本身就是由【kooriookami】开发的&#xff0c;用于DIY卡片因此我只是原有功能再现并不会追加新功能 2.其次数据和卡图均来源于网络&#xff0c;因此我也只提供网络能获取该内容的途径&#xff0c;并不会预先准备好 最近一直没有时间看回复…

2023数字化产品经理如何建立自己的护城河线下演讲-上

来源&#xff1a;三爷出席《人人都是产品经理》2023数字化产品经理大会演讲实录 各位朋友们&#xff0c;大家下午好&#xff0c;非常高兴呢能受到人人都是产品经理官方的邀请&#xff0c;今天能有这样一个机会站在这里和大家做一个简单的分享。 ​ 编辑 添加图片注释&#xf…

C#/.Net的多播委托到底是啥?彻底剖析下

前言 委托在.Net里面被托管代码封装了之后&#xff0c;看起来似乎有些复杂。但是实际上委托即是函数指针&#xff0c;而多播委托&#xff0c;即是函数指针链。本篇来只涉及底层的逻辑&#xff0c;慎入。 概括 1.示例代码 public delegate void ABC(); //委托写在类的外面 publi…