1. 如何使用QEMU来模拟ARMv8开发平台
使用Qemu模拟Cortex-A9运行U-boot和linux 作者来源于网络
我的开发环境: Ubuntu-12.04 所有软件包为最新
1. 安装GNU工具链
sudo apt-get insatll gcc-arm-linux-gnueabi
sudo apt-get insatll g++-arm-linux-gnueabi
安装完成后会在 /usr/arm-linux-gnueabi/ 目录下生成库文件、头文件等。 我安装的GCC版本为:
arm-linux-gnueabi-gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
2. 安装Qemu模拟器
sudo apt-get install qemu qemu-system qemu-utils
这时应该已经可以运行qemu-system-arm命令了, 其版本为:
qemu-system-arm --version
QEMU emulator version 1.0.50 (Debian 1.0.50-2012.03-0ubuntu2), Copyright (c) 2003-2008 Fabrice Bellard
3. 编译和运行U-boot:
到 ftp://ftp.denx.de/pub/u-boot/ 下载最新版本的U-Boot源代码, 我用的目前最新版本 u-boot-2012.04.tar.bz2
解压后进入源代码目录,在Makefile里面增加两行:
2. android jni程序(c++)如何编译适用于arm-v8指令集的32位程序
可以看到Android上层的Application和ApplicationFramework都是使用java编写,
底层包括系统和使用众多的LIiraries都是C/C++编写的。
所以上层Java要调用底层的C/C++函数库必须通过Java的JNI来实现。
下面将学习Android是如何通过Jni来实现Java对C/C++函数的调用。以HelloWorld程序为例:
第一步:
使用Java编写HelloWorld 的Android应用程序:
package com.lucyfyr;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class HelloWorld extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.v("fresne", printJNI("I am HelloWorld Activity"));
}
static
{
//加载库文件
System.loadLibrary("HelloWorldJni");
}
//声明原生函数 参数为String类型 返回类型为String
private native String printJNI(String inputStr);
}
这一步我们可以使用eclipse来生成一个App;
因为eclipse会自动为我们编译此Java文件,后面要是用到。
第二步:
生成共享库的头文件:
进入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/
下:
可以看到里面后很多后缀为.class的文件,就是eclipse为我们自动编译好了的java文件,其中就有:
HelloWorld.class文件。
退回到classes一级目录:/HelloWorld/bin/classes/
执行如下命令:
javah com.lucyfyr.HelloWorld
生成文件:com_lucyfyr_HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lucyfyr_HelloWorld */
#ifndef _Included_com_lucyfyr_HelloWorld
#define _Included_com_lucyfyr_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lucyfyr_HelloWorld
* Method: printJNI
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
可以看到自动生成对应的函数:Java_com_lucyfyr_HelloWorld_printJNI
Java_ + 包名(com.lucyfyr) + 类名(HelloWorld) + 接口名(printJNI):必须要按此JNI规范来操作;
java虚拟机就可以在com.simon.HelloWorld类调用printJNI接口的时候自动找到这个C实现的Native函数调用。
当然函数名太长,可以在.c文件中通过函数名映射表来实现简化。
第三步:
实现JNI原生函数源文件:
新建com_lucyfyr_HelloWorld.c文件:
#include <jni.h>
#define LOG_TAG "HelloWorld"
#include <utils/Log.h>
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr)
{
LOGI("fresne Hello World From libhelloworld.so!");
// 从 instring 字符串取得指向字符串 UTF 编码的指针
const char *str =
(const char *)(*env)->GetStringUTFChars( env,inputStr, JNI_FALSE );
LOGI("fresne--->%s",(const char *)str);
// 通知虚拟机本地代码不再需要通过 str 访问 Java 字符串。
(*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str );
return (*env)->NewStringUTF(env, "Hello World! I am Native interface");
}
/* This function will be call when the library first be load.
* You can do some init in the libray. return which version jni it support.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
void *venv;
LOGI("fresne----->JNI_OnLoad!");
if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("fresne--->ERROR: GetEnv failed");
return -1;
}
return JNI_VERSION_1_4;
}
OnLoadJava_com_lucyfyr_HelloWorld_printJNI
函数里面做一些log输出 注意JNI中的log输出的不同。
JNI_OnLoad函数JNI规范定义的,当共享库第一次被加载的时候会被回调,
这个函数里面可以进行一些初始化工作,比如注册函数映射表,缓存一些变量等,
最后返回当前环境所支持的JNI环境。本例只是简单的返回当前JNI环境。
http://www.cnblogs.com/bastard/archive/2012/05/19/2508913.html
3. Linux 如何运行benchmark循环跑
Linux 如何运行benchmark循环跑如下
benchmark中包含了跑benchmark的源码benchncnn.cpp,感兴趣的可以先看一下里面的内容。在Linux的文件根目录下,新建一个build文件夹并进入,当然也可以不叫build,随便你自己起。mkdir build && cd build进入之后就可以进行编译了,编译之后在build文件夹下会生成一个叫benchmark的文件夹,之后的工作会在这里进行。编译用的是cmake,这里如果有问题的话可以注意一下cmake的版本,我用的版本是3.12.3。具体命令如下:cmake .
make -j8这里cmake编译实际上是要根据上一层文件夹的CMakeLists.txt的文本来的,这里的..其实就是表示的上一层文件夹。 Make -j后面的数字是开几个核,根据自己电脑的实际情况来。执行完成之后就可以看到build里有了benchmark的文件夹。
入这个文件夹,可以看到一个benchncnn的可执行文件已经编译好了,运行这个可执行文件就可以测试模型的速度。但是这个可执行文件默认的是找到当前文件夹下的param格式的文件。
所有自带的模型文件都在ncnn根目录下的benchmark的文件夹中,把里面所有的param文件都拷贝到现在的benchmark文件夹,然后执行如下命令./benchncnn 4 2 0 -1
第一个数字表示测试次数,第二个表示开的线程数(这一点ncnn做的不错),最后一个数字-1表示只测cpu。NCNN交叉编译到rk3288(armv7架构)和rk3399(armv8架构)的方法。
4. Linux内核中断之中断调用流程
本文基于 RockPI 4A 单板Linux4.4内核介绍中断调用流程。
ARMv8包括两种运行状态:AArch64和AArch32。
AArch64中不再使用AArch32中的7种特权模式,而是提出了Exception Levels的概念,包括:
1)EL0:用于用户态程序,权限最低
2)EL1:给内核使用,权限稍高
3)EL2:虚拟化相关,权限更高
4)EL3:安全相关,权限最高
Linux内核中一般只使用EL0和EL1。
AArch64异常向量表中的异常包括:
1)Synchronous exception(同步异常)
2)SError
3)IRQ
4)FIQ
注:SError、IRQ和FIQ属于异步异常。
在Linux内核中,在 arch/arm64/kernel/entry.S 文件中定义了异常向量表,内容如下:
选取 el1_irq() 函数介绍Linux内核中断的调用流程。
文件: arch/arm64/kernel/entry.S ,调用流程如下:
1、handle_irq()初始化
在 DTS 解析阶段完成 handle_irq() 函数的初始化,流程如下:
gic_irq_domain_map() 函数中完成了 handle_irq() 函数的赋值,具体执行如下:
2、handle_irq()实现
以共享外设中断 SPI 的中断处理函数 handle_fasteoi_irq() 为例,继续跟踪中断的执行过程。
handle_irq_event_percpu() 函数会调用已经注册的中断处理函数,同时唤醒 irq_thread 线程。
3、中断处理线程
在使用 request_threaded_irq() 函数申请中断时,会创建一个 irq_thread 线程,调用流程如下:
irq_thread 线程平时在睡眠状态,等待 handle_irq_event_percpu() 函数唤醒,进一步执行已注册的中断处理线程函数。
使用 DRM 框架中 HDMI 中断验证中断调用流程。
文件: driversgpudrmridgesynopsysdw-hdmi.c
在中断处理函数 dw_hdmi_hardirq() 和中断处理线程函数 dw_hdmi_irq 中增加 mp_stack() 调用( 注:仅限于调试验证 )。
插入 HDMI 线,系统启动后,显示中断调用流程的日志如下:
和