aarch64 linux

2019-08-10 21:33:00 chengpao7316 阅读数 94

AArch64 Linux启动

AArch64异常模型由许多异常级别(EL0-EL3)组成,EL0和EL1具有安全和非安全两种模式对应。
EL2是hypervisor,仅存在于非安全模式。 EL3是最高优先级,仅在安全模式下存在。

出于本文档的目的,我们将使用术语“引导加载程序”来简单地定义在控制传递到Linux内核之前
在CPU上执行的所有软件。 这可能包括安全监视器和管理程序代码,或者它可能只是一些准备
最小引导环境的指令。

本质上,引导加载程序应该提供(至少)以下功能:
1.设置并初始化RAM
2.设置设备树
3.解压缩内核映像
4.调用内核映像

1.设置和初始化内存(必须)
引导加载程序将查找并初始化内核静态数据所要用到的所有RAM。 
它将所有数据以机器执行顺序放到内存里。(它可以使用内部算法自动定位和调整所有RAM,
或者它可以使用机器中RAM的知识,或者引导加载程序设计者认为合适的任何其他方法。)

2.设置设备树(必须)
设备树blob(dtb)必须放在8字节对齐地址上,且大小不得超过2MB。 
由于dtb将使用最大2MB的块进行可缓存映射,因此不得将其放置在必须与
任何特定属性映射的任何2M区域内。

注意:v4.2之前的版本还要求将DTB放在512 MB区域内,从内核Image下面的text_offset字节开始。

3.解压内核(可选)
AArch64内核当前不提供解压缩器,因此如果使用压缩的Image目标(例如Image.gz),
则需要由引导加载程序执行解压缩(gzip等)。 对于未实现此要求的引导加载程序,
可以使用未压缩的Image目标。

4.引导内核(必须)
一个压缩的内核镜像包含了一个64字节的头部信息:
  u32 code0;            /* Executable code */
  u32 code1;            /* Executable code */
  u64 text_offset;        /* Image load offset, little endian */
  u64 image_size;        /* Effective Image size, little endian */有效镜像大小
  u64 flags;            /* kernel flags, little endian */
  u64 res2    = 0;        /* reserved */
  u64 res3    = 0;        /* reserved */
  u64 res4    = 0;        /* reserved */
  u32 magic    = 0x644d5241;    /* Magic number, little endian, "ARM\x64" */
  u32 res5;                /* reserved (used for PE COFF offset) */
  
说明:
- 在V3.17版本之后,除非另有说明,否则都是小端模式

- code0和code1是负责分支到文本????

- 在通过EFI启动时,最初会跳过code0 / code1。res5是PE头的偏移量,
PE头具有EFI入口点(efi_stub_entry)。当stub完成其工作时,它会跳转到code0以恢复正常启动过程。

- 在v3.17之前,未指定text_offset的字节顺序。 在这些情况下,image_size为零,
并且text_offset在内核的字节顺序中为0x80000。 在image_size为非零的情况下,
image_size是little-endian,必须遵守。 在image_size为零的情况下,
可以假设text_offset为0x80000。

- The flags field (introduced in v3.17) is a little-endian 64-bit field
  composed as follows:
  Bit 0:    Kernel endianness.  1 if BE, 0 if LE.
  Bit 1-2:    Kernel Page size.
            0 - Unspecified.
            1 - 4K
            2 - 16K
            3 - 64K
  Bit 3:    Kernel physical placement
            0 - 2MB aligned base should be as close as possible
                to the base of DRAM, since memory below it is not
                accessible via the linear mapping
            1 - 2MB aligned base may be anywhere in physical
                memory
  Bits 4-63:    Reserved.

- 当image_size为零时,引导加载程序应该在内核映像结束后立即尝试保留尽可能多的
内存供内核使用。 所需的空间量将根据所选功能而有所不同,并且实际上是未绑定的。

镜像必须放在 2MB对齐的基地址偏移 text_offset地址中,并会在那里调用执行。   
2 MB对齐的基址和镜像的开头之间的区域对内核没有特殊意义,可以用于其他目的。 
至少从映像开头的image_size字节必须是空闲的,以供内核使用。
注意:v4.6之前的版本无法使用低于Image物理偏移量的内存,因此建议将Image放置在
尽可能靠近系统RAM启动位置的位置。

如果initrd / initramfs在引导时传递给内核,它必须完全驻留在最大32GB的1GB对齐
物理内存窗口中,完全覆盖内核Image。

向内核描述的任何内存(即使是在image开头之下)也没有被标记为从内核保留
(例如,在设备树中具有memreserve区域)将被认为是内核可用的。

在跳转到内核执行之前,必须满足以下条件:
1.关掉所有支持DMA的设备,以便内存不会被网络数据包或磁盘数据破坏。 
这将为您节省大量的调试时间。

2.主CPU的通用寄存器设置为:
  x0 = physical address of device tree blob (dtb) in system RAM.
  x1 = 0 (reserved for future use)
  x2 = 0 (reserved for future use)
  x3 = 0 (reserved for future use)

3. CPU模式
在PSTATE.DAIF中屏蔽所有中断(Debug, SError, IRQ and FIQ).
CPU必须位于EL2(推荐以便访问虚拟化扩展)或非安全EL1。

4. cache、mmu
mmu必须关闭
icache必须关闭
必须将与加载的内核映像相对应的地址范围清除到PoC。 
在存在启用高速缓存的系统高速缓存或其他连贯主控器的情况下,
这通常需要通过VA而不是set/way操作来维护高速缓存。
必须配置并且可以启用通过VA操作遵循架构缓存维护的系统缓存。
必须配置和禁用不遵循VA操作(不推荐)的架构缓存维护的系统缓存。

5.系统定时器
必须设置CNTFRQ定时器频率,并且CNTVOFF必须在所有CPU上编程为一致的值。 
如果在EL1进入内核,CNTHCTL_EL2必须设置为有效,EL1PCTEN(位0)。

6.Coherency
在进入内核时,内核引导的所有CPU必须是同一个一致性域的一部分。 
这可能需要IMPLEMENTATION DEFINED初始化,以便能够在每个CPU上接收维护操作。

7.系统寄存器
在进入内核映像的异常级别的所有可写架构系统寄存器必须由更高异常级别的软件初始化,
以防止在UNKNOWN状态下执行。

对于在v3模式下使用GICv3中断控制器的系统:
    - 如果存在EL3:
     ICC_SRE_EL3.Enable(第3位)必须初始化为0b1。
     必须将ICC_SRE_EL3.SRE(位0)初始化为0b1。
    - 如果在EL1进入内核:
     必须将ICC.SRE_EL2.Enable(第3位)初始化为0b1
     必须将ICC_SRE_EL2.SRE(位0)初始化为0b1。
    -  DT或ACPI表必须描述GICv3中断控制器。

对于在兼容性(v2)模式下使用GICv3中断控制器的系统:
    - 如果存在EL3:
     必须将ICC_SRE_EL3.SRE(位0)初始化为0b0。
    - 如果在EL1输入内核:
     必须将ICC_SRE_EL2.SRE(位0)初始化为0b0。
    -  DT或ACPI表必须描述GICv2中断控制器。

上述CPU模式,高速缓存,MMU,架构定时器,一致性和系统寄存器的要求适用于所有CPU。
所有CPU必须在相同的异常级别中进入内核。

期望引导加载程序以下列方式进入每个CPU的内核:

 - 主CPU必须直接跳转到内核映像的第一条指令。此CPU传递的设备树blob必须包含每个cpu节点
 的“enable-method”属性。支持的启用方法如下所述。

  预计引导加载程序将生成这些设备树属性,并在内核进入之前将它们插入到blob中。

 - 具有“spin-table”enable-method的CPU必须在其cpu节点中具有“cpu-release addr”属性。
 此属性标识自然对齐的64位零初始化内存位置。

  这些CPU应该在内核的保留区域内自旋(通过设备树中的/ memreserve / region与内核通信)
轮询它们的cpu-release-addr位置,该位置必须包含在保留区域中。可以插入wfe指令以减少
繁忙循环的开销,并且将由主CPU发出sev。当读取cpu-release-addr指向的位置返回非零值时,
CPU必须跳转到该值。该值将写为单个64位little-endian值,因此CPU必须在读取之前将读取值
转换为其本机字节序。

 - 具有“psci”启用方法的CPU应该保留在内核之外(即,在内存节点中向内核描述的内存区域之外,
 或者在内存中由/ memreserve / region描述的内存的保留区域之外)设备树)。内核将按照ARM文档
 编号ARM DEN 0022A(“ARM处理器上的电源状态协调接口系统软件”)中的描述发出CPU_ON调用,
 以将CPU带入内核。
 
 设备树需要包含psci节点,具体描述见Documentation/devicetree/bindings/arm/psci.txt.
 
-辅助寄存器设置:
  x0 = 0 (reserved for future use)
  x1 = 0 (reserved for future use)
  x2 = 0 (reserved for future use)
  x3 = 0 (reserved for future use)

转载于:https://my.oschina.net/u/3231839/blog/3086207

2017-08-17 15:39:53 x356982611 阅读数 17933

简介

在64位ubuntu14.04搭建交叉编译环境,去官网(www.linaro.org)下载解压,设置PATH路径即可

这里写图片描述
这里写图片描述
https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/aarch64-linux-gnu/
这里写图片描述

说明

gcc-linaro-6.3.1-2017.05-i686_aarch64-linux-gnu.tar.xz和gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz的区别 看下下面的图就知道了

这里写图片描述

引用

https://www.linaro.org/
http://www.veryarm.com/aarch64-linux-gnu-gcc
http://blog.csdn.net/x356982611
http://blog.csdn.net/yandaqijian/article/details/41748599

2018-11-11 15:54:31 SoaringLee_fighting 阅读数 4338

Date: 2018.11.11


学习参考: https://blog.csdn.net/listener51/article/details/82856001

1、指令编码长度
A32模式(ARM instruction sets),指令固定的编码长度为32bit
T32模式(Thumb instruction sets),指令可以编码成16bit长,也可编码成32bit长
A64模式(AArch64 instruction sets),指令固定的编码长度为32bit
2、当前指令的地址

在ARM32状态下,当前执行指令的地址通常是pc-8,而在Thumb状态下通常是pc-4。
参考地址:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0013d/index.html 程序计数器(pc)

拿ARMv7三级流水线做示例,如图,假设add指令fetch时,指令地址为pc1; add指令decode时,下一条指令sub又进入fetch阶段,此时pc2 = pc1 + 4; add指令execute时,sub指令后的cmp油进入fetch阶段,此时pc = pc2 + 4, 因此add指令执行时真正的pc地址pc1 = pc-8。
在这里插入图片描述
参考: https://blog.csdn.net/lee244868149/article/details/49488575/

在AARCH64状态下,当前执行指令的地址通常是pc。
英文原文:

Program counter
 The current Program Counter (PC) cannot be referred to by number as if part of the general register file and therefore cannot be used as the source or destination of arithmetic instructions, or as the base, index or transfer register of load and store instructions.
 The only instructions that read the PC are those whose function it is to compute a PC-relative address (ADR, ADRP, literal load, and direct branches), and the branch-and-link instructions that store a return address in the link register (BL and BLR). The only way to modify the program counter is using branch, exception generation and exception return instructions.
 Where the PC is read by an instruction to compute a PC-relative address, then its value is the address of that instruction. Unlike A32 and T32, there is no implied offset of 4 or 8 bytes.

参考: http://infocenter.arm.com/help/index.jsptopic=/com.arm.doc.den0024a/ch05s01s03.html 5.1.3. Registers

3、形参超过指定通用寄存器个数的访问方法

arm32下,前4个参数是通过r0~r3传递,第4个参数需要通过sp访问,第5个参数需要通过sp + 4 访问,第n个参数需要通过sp + 4*(n-4)访问。

arm64下,前8个参数是通过x0~x7传递,第8个参数需要通过sp访问,第9个参数需要通过sp + 8 访问,第n个参数需要通过sp + 8*(n-8)访问。

4、aarch64下< Vn >.< Ts >[< index2 >]的用法

示例:

 mov < Vd >.< Ts >[< index1 >], < Vn >.< Ts >[< index2 >]

其中Ts的值需要注意,只能是以下情况之一:

  • B :8bit
  • H:16bit
  • S :32bit
  • D: 64bit

注意:不要将Ts写成8B、2s等,因为是取矢量寄存器(Vn)中的元素。

5、aarch64下imm需注意的地方

示例:

cmp < Wn|WSP>, #< imm> {, < shift>}

其中imm是无符号立即数,取值范围[0, 4095]。

注意:在使用立即数的时候,需要看指令所支持的立即数范围。不同指令中立即数的取值范围可能不同。


THE END!

2019-08-28 23:09:32 FJDJFKDJFKDJFKD 阅读数 3871

交叉编译工具链

linaro 官网下载即可。https://www.linaro.org/downloads/
https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/
解压以后在环境变量 PATH 里加上工具链的路径。
export PATH=/path/to/bin/linaro-xxx/bin:$PATH
验证一下:aarch64-linux-gnu-gcc -v

内核编译

下载:

wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.10.tar.xz

在根目录下会产生 vmlinux*,arch/arm64/boot/下会产生 Image
vmlinux 编出来大概有190+M,Image 去除了很多调试信息,大概是15M。

cd ~/linux-4.10/

# cp ./arch/arm64/configs/defconfig  .config

mkdir build

# stay in the current dir, do not cd to ./build
# 如果需要调整配置选项,则使用 menuconfig 进行配置
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=./build defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=./build menuconfig
# 注意这里 menuconfig 需要选中以下两个选项,这里给 ramdisk 64M的空间,应当比后面生成的 rootfs 大。
	General setup  --->
	    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
	 
	Device Drivers  --->
	    [*] Block devices  --->
	        <*>   RAM block device support
	        (65536) Default RAM disk size (kbytes)
        
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=./build Image -j16

qemu 安装

请参考 qemu-4.x.x 安装

qemu-system-aarch64 运行

Linux 要如何启动?1

Linux kernel在自身初始化完成之后,需要能够找到并运行第一个用户程序(这个程序通常叫做“init”程序)。用户程序存在于文件系统之中,因此,内核必须找到并挂载一个文件系统才可以成功完成系统的引导过程。在grub中提供了一个选项“root=”用来指定第一个文件系统,但随着硬件的发展,很多情况下这个文件系统也许是存放在USB设备,SCSI设备等等多种多样的设备之上,如果需要正确引导,USB或者SCSI驱动模块首先需要运行起来,可是不巧的是,这些驱动程序也是存放在文件系统里,因此会形成一个悖论。

为解决此问题,Linux kernel 提出了一个RAM disk的解决方案,把一些启动所必须的用户程序和驱动模块放在RAM disk中,这个RAM disk看上去和普通的disk一样,有文件系统,有cache,内核启动时,首先把RAM disk挂载起来,等到init程序和一些必要模块运行起来之后,再切到真正的文件系统之中。

上面提到的RAM disk的方案实际上就是 initrd。 如果仔细考虑一下,initrd 虽然解决了问题但并不完美。 比如,disk 有cache 机制,对于 RAM disk 来说,这个cache机制就显得很多余且浪费空间;disk 需要文件系统,那文件系统(如ext2等)必须被编译进kernel而不能作为模块来使用。

Linux 2.6 kernel 提出了一种新的实现机制,即 initramfs。顾名思义,initramfs 只是一种 RAM filesystem 而不是 diskinitramfs 实际是一个 cpio 归档,启动所需的用户程序和驱动模块被归档成一个文件。因此,不需要 cache,也不需要文件系统。

QEMU has a command argument called “-kernel”. It is a very handy function!! Because of this feature, we don’t need to bother the complicated boot sequence and problems on locating Kernel Image. QEMU will uncompress the kernel image to a proper memory location and start to run the kernel code.

很显然指定 -kernel /path/to/kernel_image 即可。但是这样是无法正常启动 Linux 的。
qemu-system-aarch64 -kernel build/arch/arm64/boot/Image -append "console=ttyAMA0" -m 2048M -smp 4 -M virt -cpu cortex-a57 -nographic

qemu-system-aarch64 \
    -kernel build/arch/arm64/boot/Image \
    -append "console=ttyAMA0" \
    -m 2048M -smp 4  \
    -M virt -cpu cortex-a57 \
    -nographic

-m 指定内存大小
-M 指定虚拟机器「machine」的类型
-cpu 指定虚拟CPU的型号
-smp 指定对称多处理的核心数
-append 指定内核启动时使用的命令行参数「cmdline」

在这里插入图片描述
ctrl+a + c 进入 qemu-monitor,输入 q 退出,或者按 ctrl+a + x 退出 qemu。
在这里插入图片描述
出错如下:kernel panic ... unable to mount root fs ...。正确地启动需要一个根文件系统。

创建 root fs

Kernel modules are mostly drivers, both hardware drivers and software drivers. For example, the Ethernet! If the driver is a kernel module stored in root file system, Linux kernel will not be able to access the Internet before mounting the root file system. Another example is ext3, ext4 driver, Linux Kernel must contain these basic file system driver in order to execute init procedure because the init files are located in root file system. It’s somehow a very common problem which was very popular in early years. That’s why we have so-called initramfs or rootfs. They are minimal file system images containing all kernel modules(.ko files), init procedure scripts, and necessary binaries to boot a full system.

busybox2

wget https://busybox.net/downloads/busybox-1.30.1.tar.bz2
tar -xjf busybox-1.30.1.tar.bz2
cd busybox-1.30.1
make defconfig
make menuconfig
make -j16
make install

注意:

  1. 执行 make menuconfig 后需要修改配置,将 Build static binary (no shared libs) 选上。
  2. 对于要在非host平台运行的情况,其交叉编译工具链也要配好!
Build Options  --->
    [*] Build BusyBox as a static binary (no shared libs)

交叉编译选项别忘了
(/path/to/aarch64-linux-gnu-) Cross Compiler prefix

此法亲测可行。

BUSYBOX_VERSION=1.30.1

dd if=/dev/zero of=busybox-${BUSYBOX_VERSION}-rootfs_ext4.img bs=1M count=64 oflag=direct
mkfs.ext4 busybox-${BUSYBOX_VERSION}-rootfs_ext4.img
mkdir rootfs
sudo mount busybox-${BUSYBOX_VERSION}-rootfs_ext4.img rootfs/
sudo cp -raf busybox-${BUSYBOX_VERSION}/_install/* rootfs/

cd rootfs
sudo mkdir -p proc sys tmp root var mnt dev
sudo mknod dev/tty1 c 4 1
sudo mknod dev/tty2 c 4 2
sudo mknod dev/tty3 c 4 3
sudo mknod dev/tty4 c 4 4
sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3
sudo cp -r ../busybox-${BUSYBOX_VERSION}/examples/bootfloppy/etc/ .

cd ..
sudo umount rootfs

运行,起飞!

这里Image的路径被我移动过了,大家不要误会 =.=
注意这里启动设备是 -hda ,use ‘file’ as IDE hard disk 0/1 image。

qemu-system-aarch64 \
        -kernel ../linux-4.10/build/Image \
        -nographic \
        -append "root=/dev/vda console=ttyAMA0 rootfstype=ext4 init=/linuxrc rw" \
        -m 2048M \
        -smp 4  \
        -M virt \
        -cpu cortex-a57 \
        -hda busybox-1.30.1-rootfs_ext4.img

-M: Specify the machine type. Use “-M help” to list all the supported boards
-kernel: Specify the kernel image (bzimage)
-dtb: Specify the hardware description file (Device Tree Blob)
-nographic: Run QEMU without GUI. It’s much more convenient.
-append: Specify Linux kernel arguments. Here we set default console to ttyAMA0 which is one of QEMU’s console when Guest OS/Applications wants to print something on host’s terminal.
-drive: Specify a drive for the image. It can be SD card, flash, etc. It’s the lowest level of drive API. We use if(interface) SD card with write back cache policy to save image access time.
-sd: It is a higher level API to specify a drive. It’s equivalent to “-drive if=sd,file=”
-net nic,macaddr=$macaddr: Specify the mac address
-net tap,vlan=0,ifname=tap0: Use tap device for internet access
-snapshot: Don’t write back to the original disk image.

如下图所示,运行成功!可以用 ls 命令看下目录情况,由于未作任何系统配置,比如 /etc/passwd/etc/group/etc/shadow/etc/hostname 等文件,所以系统的操作和易用性还有待改进。
在这里插入图片描述

制作成 initramfs

直接用 cpio 打包压缩即可。

#cd rootfs
#find . -print0 | cpio --null -ov --format=newc  | gzip -9  > ../initramfs.cpio.gz


# or use this way

cd ../linux-4.10/build
# should cd to build, because the script use the related path,
# and gen_init_cpio is under build/usr/

sh ../scripts/gen_initramfs_list.sh \
        -o ../../run_linux/initramfs.cpio.gz ../../run_linux/rootfs2/

注意这里启动设备换成了 -initrd,use ‘file’ as initial ram disk。

qemu-system-aarch64 -kernel build/arch/arm64/boot/Image -initrd initramfs.cpio.gz -append "console=ttyAMA0 rdinit=/linuxrc" -M virt -cpu cortex-a57 -nographic -smp 4 -m 2048M


qemu-system-aarch64 \
	-kernel build/arch/arm64/boot/Image \
	-initrd initramfs.cpio.gz \
	-append "console=ttyAMA0 rdinit=/linuxrc" \
	-M virt \
	-cpu cortex-a57 \
	-nographic \
	-smp 4 \
	-m 2048M

注意:通常引导内核时向command line传递的参数都是 init=xxx ,而对于 initrd 则是传递 rdinit=xxx 。处理代码位于 init/main.c。rdinit=xxx 在内核中被 ramdisk_execute_command 变量接收,如果没有 rdinit 参数,ramdisk_execute_command默认为"/init"。sys_access() 检查ramdisk_execute_command指定的文件是否存在。

  1. 如果不存在的话,说明 ramdisk 中没有什么好执行的,使用 prepare_namespace() 准备根文件系统,因为要执行"init=xxx"指定的程序了。
  2. 如果 ramdisk_execute_command 指定的文件存在,则接下来全部由其接管。

如果使用 "init=/linuxrc" 参数,此时没有 rdinit 参数,则内核中默认去找 /init,没找到,则尝试挂载rootfs。rootfs挂载失败,则一直报错。

  • 解压和制作ramdisk:
    解压 gunzip -c …/initrd-cpio.gz | cpio -i
    制作 find . | cpio -o -H newc | gzip > …/ramdisk.cpio.gz

其他方法

记录一下网上看到一个方法,可以参考,实际上是把交叉编译选项放在命令行里带进去了。
如果是x86_64 的话,不需要 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install

制作根文件系统。

sudo mkdir rootfs
sudo cp _install/* -r rootfs/
sudo mkdir rootfs/lib
sudo cp -P /usr/arm-linux-gnueabi/lib/* rootfs/lib/

sudo mknod rootfs/dev/tty1 c 4 1
sudo mknod rootfs/dev/tty2 c 4 2
sudo mknod rootfs/dev/tty3 c 4 3
sudo mknod rootfs/dev/tty4 c 4 4

dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=32
mkfs.ext3 a9rootfs.ext3

sudo mkdir tmpfs
sudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loop
sudo cp -r rootfs/*  tmpfs/
sudo umount tmpfs

qemu-system-arm -M vexpress-a9 -m 512M -kernel /home/peter/work/src/linux/linux/arch/arm/boot/zImage -nographic -append "root=/dev/mmcblk0 console=ttyAMA0" -sd a9rootfs.ext3

Buildroot

推荐使用 Buildroot 的方法来创建 root fs,功能强大,便于定制。这里就不详述了。

x86_64

x86_64的同理,不过命令有些差别,这里也记录一下。根文件系统可以使用系统带的命令进行生成。

qemu-system-x86_64 -kernel ./bzImage -nographic -append "console=tty0" -initrd ramdisk.img -m 512

mkinitramfs -o ramdisk.img

qemu-system-x86_64 \
    -kernel ./bzImage \
    -nographic \
    -append "console=tty0" \
    -initrd ramdisk.img \
    -m 512

gdb 调试

在上述命令后加上 -s-S。前者是 -gdb tcp::1234 的缩写,后者表示 freeze CPU at startup (use 'c' to start execution)。运行后打开 gdb,加载内核调试文件,运行target remote :1234 attach 到 qemu 里的调试端口,使用 hbreak start_kernel 在 start_kernel 打个断点。然后 c 让内核继续运行。
在这里插入图片描述

Image zImage uImage3

1、首先来解释一下前面2个命令的区别。Image为普通的内核映像文件,而zImage为压缩过的内核映像文件(其中的z字母就是压缩的意思)。一般情况下,编译出来的Image大约为4M,而zImage不到2M。

2、然后来解释一下第3个命令uImage。它是uboot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。换句话说,如果直接从uImage的0x40位置开始执行,那么zImage和uImage没有任何区别。

为什么要用uboot 的mkimage工具处理内核映像zImage呢?

因为uboot在用bootm命令引导内核的时候,bootm需要读取一个64字节的文件头,来获取这个内核映象所针对的CPU体系结构、OS、加载到内存中的位置、在内存中入口点的位置以及映象名等等信息。这样bootm才能为OS设置好启动环境,并跳入内核映象的入口点。而mkimage就是添加这个文件头的专用工具。具体的实现请看uboot中bootm的源码和mkimage的源码。

下面介绍下mkimage这个工具的用法:

参数说明:

  • A:指定 CPU 的体系结构,有:alpha、arm 、x86、ia64、mips、mips64、 ppc 、s390、sh、sparc 、sparc64、m68k 等;
  • O:指定操作系统类型,有:openbsd、netbsd、freebsd、4_4bsd、linux、 svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos;
  • T:指定映象类型,有:standalone、kernel、ramdisk、multi、firmware、script、filesystem;
  • C:指定映象压缩方式,有:
    :none 不压缩(一般使用这个,因为 zImage 是已经被 bzip2 压缩过的自解压内核);
    :zip 用 gzip 的压缩方式;
    :bzip2 用 bzip2 的压缩方式;
  • a:指定映象在内存中的加载地址,映象下载到内存中时,要按照用 mkimage 制作映象时该参数所指定的地址值来下载;
  • e:指定映象运行入口点地址,这个地址就是-a 参数指定值加上 0x40(因为前面有个 mkimage 添加的 0x40 个字节的头);
  • n:指定映象名;
  • d:指定制作映象的源文件;

例如:下面命令的作用就是,将目录下的zImage文件制作成符合uboot引导要求的uImage.img文件,使得uboot能够正确的引导和启动linux内核。-e 的地址特别要小心,在 -a 指定的地址基础上加 0x40

mkimage -n ‘mykernel’ -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage uImage.img


  1. https://medicineyeh.wordpress.com/2016/03/29/buildup-your-arm-image-for-qemu/ ↩︎

  2. https://chasinglulu.github.io/2019/07/27/%E5%88%A9%E7%94%A8Qemu-4-0%E8%99%9A%E6%8B%9FARM64%E5%AE%9E%E9%AA%8C%E5%B9%B3%E5%8F%B0/ ↩︎

  3. https://blog.csdn.net/LEON1741/article/details/54809347 ↩︎

2016-12-23 15:59:55 rd_w_csdn 阅读数 36463

查看Android设备的CPU架构信息,可以使用命令来完成:

1、adb shell  
2、cat  /proc/cpuinfo
➜  ~ adb shell
shell@hennessy:/ $ cat  /proc/cpuinfo
Processor	: AArch64 Processor rev 2 (aarch64) //cpu架构
processor	: 0
BogoMIPS	: 26.00

//核心数
Features	: fp asimd aes pmull sha1 sha2 crc32
CPU implementer	: 0x41
CPU architecture: AArch64
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 2

Hardware	: MT6795 //品牌
shell@hennessy:/ $

AArch64是ARMv8 架构的一种执行状态。

为了更广泛地向企业领域推进,需要引入 64 位构架。同时也需要在 ARMv8 架构中引入新的 AArch64 执行状态。AArch64 不是一个单纯的 32 位 ARM 构架扩展,而是 ARMv8 内全新的构架,完全使用全新的 A64 指令集。这些都源自于多年对现代构架设计的深入研究。更重要的是, AArch64 作为一个分离出的执行状态,意味着一些未来的处理器可能不支持旧的 AArch32 执行状态。 虽然最初的 64 位 ARM 处理器将会完全向后兼容,但我们大胆且前瞻性地将 AArch64 作为在 ARMv8 处理器中唯一的执行状态。我们在这些系统中将不支持 32 位执行状态, 这将使许多有益的实现得到权衡,如默认情况下,使用一个较大的 64K 大小的页面,并会使得纯净的 64 位 ARM 服务器系统不受遗留代码的影响。立即进行这种划分是很重要的,因为有可能在未来几年内将出现仅支持 64 位的服务器系统。没有必要在新的 64 位架构中去实现一个完整的 32 位流水线,这将会提高未来 ARM 服务器系统的能效。这样回想起来, AArch64 作为在 Fedora ARM 项目中被支持的 ARM 构架是一个很自然的过程: armv5tel、armv7hl、aarch64。新的架构被命名为:aarch64,这同 ARM 自己选择的主线命名方式保持一致,同时也考虑到了 ARM 架构名与 ARM 商标分开的期望。

ARMv8-A 将 64 位架构支持引入 ARM 架构中,其中包括:

  • 64 位通用寄存器、SP(堆栈指针)和 PC(程序计数器)
  • 64 位数据处理和扩展的虚拟寻址

两种主要执行状态:

  • AArch64 - 64 位执行状态,包括该状态的异常模型、内存模型、程序员模型和指令集支持
  • AArch32 — 32 位执行状态,包括该状态的异常模型、内存模型、程序员模型和指令集支持

这些执行状态支持三个主要指令集

  • A32(或 ARM):32 位固定长度指令集,通过不同架构变体增强部分 32 位架构执行环境现在称为 AArch32。
  • T32 (Thumb) 是以 16 位固定长度指令集的形式引入的,随后在引入 Thumb-2 技术时增强为 16 位和 32 位混合长度指令集。部分 32 位架构执行环境现在称为 AArch32。
  • A64:提供与 ARM 和 Thumb 指令集类似功能的 32 位固定长度指令集。随 ARMv8-A 一起引入,它是一种 AArch64 指令集。
    ARM ISA 不断改进,以满足前沿应用程序开发人员日益增长的要求,同时保留了必要的向后兼容性,以保护软件开发投资。在 ARMv8-A 中,对 A32 和 T32 进行了一些增补,以保持与 A64 指令集一致。

传送门:
https://fedoraproject.org/wiki/Architectures/ARM/AArch64/zh-cn#.E4.BB.8B.E7.BB.8D

https://www.arm.com/zh/products/processors/instruction-set-architectures/armv8-architecture.php

引导AArch64 Linux

阅读数 1616