Tiny4412模式跳转
ARM体系的CPU有以下7种工作模式:
1、用户模式(Usr):用于正常执行程序;
2、快速中断模式(FIQ):用于高速数据传输;
3、外部中断模式(IRQ):用于通常的中断处理;
4、管理模式(svc):操作系统使用的保护模式;
5、数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储以及存储保护;
6、系统模式(sys):运行具有特权的操作系统任务;
7、未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件;
如下图:

要进行模式跳转,就需要要有异常事件在触发它进行模式跳转,在ARM中,异常有如下几种:

(1)在异常向量表中,需要注意的是未定义指令(undefined),软中断(swi)是发生在译码阶段,其他五种都发生在执行阶段;ARM中的流水线分为:取值,译码,执行,仿存,回写这五步,当一条指令正在执行时,它的下一条指令正在译码,下下一条在取值,pc指向的是正在取值的那条指令,在模式跳转要回去的时候这点需要认真考虑;
(2)通过上图我们可以看出要是发生undefined,它就会自动跳到0x0000004这个地址去执行,那如果我们在这个地址放一段代码,到时候就可以知道有没有发生异常,是不是跳到0x0000004这个;思想就是这样,但是现在有遇到一个新的问题,因为在这个三星公司将0x00000000—0x00010000为iROM,这个地址是只能读,不能改,因此我们就要需开启mmu,把0x00000004映射到其他空闲的地址上去:
下面是代码:
int (*printf)(char *, ...) = 0xc3e114d8;
void enable_mmu();
void memcpy(unsigned long *dest, unsigned long *source, int len);
void init_table(unsigned long *addr);
unsigned long swi_init(); int main()
{
unsigned long source = swi_init();
printf("source is %x\n", source); memcpy(0x60000004, source, 0x1000);
enable_mmu(); __asm__ __volatile__ (
".word 0xffffffff\n"
); printf("welcom back\n");
} unsigned long swi_init()
{
unsigned long addr;
__asm__ __volatile__ (
"ldr %0, =start \n"
: "=r" (addr)
); return addr;
} void memcpy(unsigned long *dest, unsigned long *source, int len)
{
int i = ;
for(i = ; i < len; i++) {
dest[i] = source[i];
}
} void enable_mmu()
{
/*构建表*/
unsigned long addr = 0x50000000;
init_table(addr);
/*打开mmu*/
unsigned long mmu = ;
mmu = | ( << ) | ( << ) | ( << );
__asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
"MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
"MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
:
: "r" (addr), "r" (mmu)
:
); } __asm__ ( "start: \n"
"mov sp, #0x47000000\n"
"stmdb sp!, {r0-r12, lr}\n" "ldr r3, data\n"
"ldr r0, =str_und\n"
"blx r3\n" /*跳回去代码*/
"mov sp, #0x47000000\n"
"ldmdb sp, {r0-r12, pc}^\n"// "data:\n"
".word 0xc3e114d8\n" "str_und:\n"
".asciz \"this is undefined\\n\"\n"
".align 2\n"
); void init_table(unsigned long *addr)
{
unsigned long va = ;
unsigned long phys = ; //0x40000000-0x80000000 -> 0x40000000-0x80000000
for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
} //0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
}
//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x0; va < 0x10000000; va += 0x100000) {
phys = va + 0x60000000;
addr[va >> ] = phys | ;
} }
在开发板运行结果如下:

总结一下:当一个模式发生跳转是,需要三步:(1)将pc存到lr中,pc->lr;(2)将cpsr存到spsr,cpsr-spsr;(3)初始化sp;第一二步由系统硬件自动完成,第三部需要我们手动完成;
模式跳回去的时候逆过过来就ok,初始化sp,将lr还给pc,spsr还给cpsr,注意需要同时一起还,73行
上面代码还有一问题就是,要是几个异常一起发生怎么办,因为我们不能控制它每次执法生一个吧,cpu留给我们处理每个异常的只有4个字节,那么我们就需要进行二级跳转了,下面贴出二级跳转代码:
int (*printf)(char *, ...) = 0xc3e114d8;
void enable_mmu();
void init_table(unsigned long *addr);
void memcpy(unsigned char *dest, unsigned char *src, int len);
extern unsigned long vector_start; int main()
{
memcpy(0x70000000, vector_start, 0x1000);
enable_mmu(); __asm__ __volatile__(
".word 0x77777777\n"
"mov r3, #3\n"
"ldr r0, [r3]\n"
); printf("welcom back\n"); return ;
} void memcpy(unsigned char *dest, unsigned char *src, int len)
{
int i = ;
for(i = ; i < len; i++) {
dest[i] = src[i];
}
} void enable_mmu()
{
//step 1: creat ttb
unsigned long addr = 0x50000000;
init_table(addr);
//step 2: enable mmu
unsigned long mmu = ;
mmu = | ( << ) | ( << ) | ( << );
__asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"//set manage
"MCR p15, 0, %0, c2, c0, 0\n"//set ttb
"MCR p15, 0, %1, c1, c0, 0\n"//enable mmu
:
: "r" (addr), "r" (mmu)
:
); } __asm__( "vector: \n"
" b reset\n"
" b und\n"
" b swi\n"
" b pre_abt\n"
" b data_abt\n"
" .word 0x0\n"
" b irq\n"
" b fiq\n" "reset:\n" "und:\n"
/*模式跳转进来分三步:
*(1)将pc存到lr,pc->lr
*(2)将cpsr存到spsr
*(3)初始化sp
*前两部系统硬件帮我们完成,第三步需要我们手动配置*/
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, show\n"
" ldr r0, =str_und\n"
" blx r3\n" /*回去的时候逆回去就ok*,^表示同时还回去*/
" mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "swi:\n" " mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, show\n"
" ldr r0, =str_swi\n"
" blx r3\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n"
"pre_abt:\n" "data_abt:\n" " mov sp, #0x47000000\n"
" sub lr, lr, #4\n"//这句需要好好理解
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, show\n"
" ldr r0, =str_data\n"
" blx r3\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "irq:\n" "fiq:\n" "show:\n"
" .word 0xc3e114d8\n" "str_data:\n"
" .asciz \"this is data abort\\n\"\n"
" .align 2\n" "str_swi:\n"
" .asciz \"this is swi \\n\"\n"
" .align 2\n" "str_und:\n"
" .asciz \"this is undefined \\n\"\n"
" .align 2\n" ".global vector_start\n"
"vector_start: \n"
".word vector \n " ); void init_table(unsigned long *addr)
{
unsigned long va = ;
unsigned long phys = ; //0x40000000-0x80000000 -> 0x40000000-0x80000000
for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
} //0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
}
//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x0; va < 0x10000000; va += 0x100000) {
phys = va + 0x70000000;
addr[va >> ] = phys | ;
} }
下面是运行结果:

Tiny4412模式跳转的更多相关文章
- 移动端APP页面Webview模式跳转详解
首先,来看一下关于Android home键和back键区别 back键 Android的程序无需刻意的去退出,当你一按下手机的back键的时候,系统会默认调用程序栈中最上层Activity的Dest ...
- Android back键及backWebview模式跳转详解
首先,来看一下关于Android home键和back键区别 back键 Android的程序无需刻意的去退出,当你一按下手机的back键的时候,系统会默认调用程序栈中最上层Activity的Dest ...
- Eclipse 中 Debug 模式跳转到 exitCurrentThread 的问题解决
问题描述: Debug 模式启动项目,断点跳转到exitCurrentThread 解决方法: 修改Eclipse 配置 [window]->[Preferences]->[Java]-& ...
- 31、activity 四种工作模式
一个应用通常(不一定)对应一个任务栈,相当于有个集合,保存了这个app里所有的页面栈的规则是先进后出,"进"就相当于打开了一个页面,"出"就相当于返回时关闭一个 ...
- 通过slave_exec_mode=IDEMPOTENT跳过主从复制中的错误
通过slave_exec_mode=IDEMPOTENT跳过主从复制中的错误 set global slave_exec_mode=IDEMPOTENT slave_exec_mode 有两种模式 S ...
- 《Orange’s》保护模式
保护模式 完整代码 ; ========================================== ; pmtest1.asm ; 编译方法:nasm pmtest1.asm -o pmte ...
- vi编辑光标跳到文件开头和结尾以及清空文件命令
vi编辑光标跳到文件开头和结尾以及清空文件命令 按esc退出编辑模式 跳到文件开头: :1 跳到文件结尾: :$ 清空文件内容: 小写的 d 加上大写的 G
- linux连接工具隧道模式
使用linux连接工具,比如putty,xshell可以使用隧道模式跳转登录其他服务器 A->B B->C 比如正常情况下,A主机能访问B主机,B主机能访问C主机,那么就可以设置隧道模式让 ...
- 自制操作系统Antz(2)——进入保护模式 (上) jmp到保护模式
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.htm Linux内核源码分析地址:https://www.cnblogs.c ...
随机推荐
- Android绘图机制(三)——自定义View的实现方式以及半弧圆新控件
Android绘图机制(三)--自定义View的三种实现方式以及实战项目操作 在Android绘图机制(一)--自定义View的基础属性和方法 里说过,实现自定义View有三种方式,分别是 1.对现有 ...
- Gradle 1.12用户指南翻译——第四十四章. 分发插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- Windows2008修改密码策略简单介绍
Windows2008修改密码策略简单介绍 Windows的密码策略,确实是挺繁琐的,刚接触SharePoint2010,装的windows2008 R2,就遇到了改密码策略的问题. 打开本地安全策略 ...
- javascript中如何让类工厂和构造函数变成同一个函数
我们知道在js中可以用一个函数来定义对象的类,该函数称之为对象的构造函数,我们在需要create对象的时候直接调用这个构造函数即可: var Man = funciton(name){ this.na ...
- 关于gcc的一点小人性化提示
现在对于大多数平台的C编译器来说都会有很多种选择,而gcc和clang无疑是2个非常优秀的C编译器.当然他们也不只是C编译器.我最近用clang的比较多,原因有很多.不过一些小的细节很让我喜欢,比如O ...
- IT轮子系列(五)——MVC API 文件上传,总有一款是你需要的
前言 在对外提供的接口时,也常常需要提供上传文件的.在这篇文章中会描述三种上传方式. 1.第一款,通过Base64字符上传——PostFromBase64Str 首先,定义上传数据模型.对于模型的定义 ...
- 3sum(从数组中找出三个数的和为0)
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...
- vs工具
首页 精选版块 论坛帮助 论坛牛人 论坛地图 专家问答 CSDN > CSDN论坛 > .NET技术 > 非技术区 返回列表 管理菜单 结帖 发帖 回复 关注 [推荐] Visual ...
- Struts2,Spring,Hibernate优缺点
struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发. 优点: Struts跟Tomcat.Turbine等诸多Apache项目一样,是开源软件,这是它的 ...
- Xshell 5 配置上传下载命令
可以在官网https://www.netsarang.com/products/main.html 下载Xshell, 目前最新的版本已经到Xshell 6了 本人记录下安装的目录截图: 安装命令: ...