1. 注意,注意,以下代码或有两个版本,版本一有错误,版本二为测试过的版本,目前只支持树莓派4B.

2. 原版出自 Github:

链接: link.

3. 以下操作大体与原文一样,但是添加了实际操作成功后的代码(版本二),以及增添了部分操作步骤,注意区分 !!

4. 制作完成后,将 SD卡 插入树莓派(4B),将观察到:

  • 电源灯(红灯): 亮
  • 状态灯(黄绿色灯):闪烁(启动中),不闪烁(启动成功)
  • 屏幕:刚启动时显示树莓派彩虹界面.之后为黑色(无显示).

5 . 树莓派启动状况

  • 3次闪烁:找不到start.elf

  • 4次闪烁:start.elf无法启动,因此它可能已损坏。或者,未正确插入卡,或卡插槽不工作。

  • 闪烁7次:kernel.img未找到

  • 闪烁8次:未识别SDRAM。在这种情况下,您的SDRAM可能已损坏,或者无法读取bootcode.bin或start.elf。

6.想点亮 LED ?如下

https://blog.csdn.net/qq_37459242/article/details/119223215

一.制作裸机操作系统

F1. 基于树莓派 4B

F2. 注意,注意,kernel.img 针对于 树莓派 1B/B+ 等较低版本,kerne7.img 针对于 树莓派 ??? ,kerne8.img 针对于 树莓派 4(或可向下兼容).

F3. 我们现在将 kernel7.img 复制到 SD 卡上。这个名称是有意义的,它向 RPi4发出信号,表示我们希望它以64位模式引导。也可以通过在 config.txt 中将 arm _ 64bit 设置为一个非零值来强制执行此操作。将操作系统引导到64位模式意味着我们可以利用 RPi4更大的可用内存容量。在将 .img 文件放入 SD 卡后,可以修改其中 config.txt 文件:
arm_64bit = 1

  1. 启动引导
    树莓派4B将要运行的第部分代码将需要用汇编语言编写。它进行一些检查与设置,然后将我们启动到我们的第一个C程序 – 操作系统内核。
  • ARM Cortex-A72具有四个核心。我们只希望代码在主核心上运行,因此我们检查处理器ID,然后让代码运行在主核心上,然后在小核上用死循环将其挂起。

  • 我们需要告诉我们的操作系统如何访问堆栈。我认为堆栈是当前执行的代码(例如Scratchpad Memory)使用的临时存储空间。我们需要为其留出内存并存储指向它的指针。

  • 我们还需要初始化BSS部分。这是内存中将存储未初始化变量的区域。在这里将所有内容初始化为零要比在我们的内核镜像中显式地初始化更有效。

  • 最后,我们可以跳到C语言中的main()。阅读并理解下面的代码,并将其另存为boot.S。作为参考,你可以阅读ARM Programmer’s Guide。

  • 版本一

section ".text.boot"  // 用于确保链接器将代码段放置于内核镜像的开头
.global _start  // 代码从这里开始执行_start:// 检查处理器ID,如果是0则为主核心,继续执行,否则挂起mrs     x1, mpidr_el1and     x1, x1, #3cbz     x1, 2f// 代码没有运行在主核心上,所以用死循环挂起代码
1:  wfeb       1b
2:  // 代码运行在主核心上,继续// 设置堆栈区的起点ldr     x1, =_startmov     sp, x1// 将BSS段清零ldr     x1, =__bss_start     // 起始地址ldr     w2, =__bss_size      // 段大小
3:  cbz     w2, 4f               // 如果为0,退出循环str     xzr, [x1], #8sub     w2, w2, #1cbnz    w2, 3b               // 如果不为0,继续循环// 跳转到main(),请确保main()不会return
4:  bl      main// 万一main函数return了,同样用死循环挂起主核心b       1b
  • 版本二
.equ Mode_USR,        0x10
.equ Mode_FIQ,        0x11
.equ Mode_IRQ,        0x12
.equ Mode_SVC,        0x13
.equ Mode_ABT,        0x17
.equ Mode_UND,        0x1B
.equ Mode_SYS,        0x1F.section ".text.boot"
/* entry */
.globl _start
_start:
/* Check for HYP mode */mrs r0, cpsr_alland r0, r0, #0x1Fmov r8, #0x1Acmp r0, r8beq overHypedb continueoverHyped: /* Get out of HYP mode */adr r1, continuemsr ELR_hyp, r1mrs r1, cpsr_alland r1, r1, #0x1f    ;@ CPSR_MODE_MASKorr r1, r1, #0x13    ;@ CPSR_MODE_SUPERVISORmsr SPSR_hyp, r1eretcontinue:/* Suspend the other cpu cores */mrc p15, 0, r0, c0, c0, 5ands r0, #3bne _halt/* set the cpu to SVC32 mode and disable interrupt */cps #Mode_SVC/* disable the data alignment check */mrc p15, 0, r1, c1, c0, 0bic r1, #(1<<1)mcr p15, 0, r1, c1, c0, 0/* set stack before our code */ldr sp, =_start/* clear .bss */mov     r0,#0                   /* get a zero                       */ldr     r1,=__bss_start         /* bss start                        */ldr     r2,=__bss_end           /* bss end                          */bss_loop:cmp     r1,r2                   /* check if data to clear           */strlo   r0,[r1],#4              /* clear 4 bytes                    */blo     bss_loop                /* loop until done                  *//* jump to C code, should not return */ldr     pc, _mainb _halt_main:.word main_halt:wfeb _halt
  1. 将以上代码链接到一起。我们使用了两种不同的语言编写了代码,我们需要以某种方式将它们组合在一起,以确保创建的镜像将按照我们期望的方式执行。我们为此使用链接脚本(linker script)。链接脚本还将定义与BSS相关的标签(也许你已经想知道它们在哪里定义了)。编写链接脚本是一件值得研究的事情。但是,对于我们的目标,你需要知道的只有将.text.boot放在第一行并使用KEEP(),我们能够保证text段(也就是代码段)出现在我们汇编代码的最开始。这也就意味着我们的第一条指令从0x80000开始,这正是树莓派4B在启动时将寻找内核的位置。我们的代码将从这里开始运行。现在你已经可以准备编译并启动你的OS。将以下内容另存为link.ld:
  • 版本一
SECTIONS
{. = 0x80000;     /* AArch64架构下,CPU会从这个地址加载内核 */.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }PROVIDE(_data = .);.data : { *(.data .data.* .gnu.linkonce.d*) }.bss (NOLOAD) : {. = ALIGN(16);__bss_start = .;*(.bss .bss.*)*(COMMON)__bss_end = .;}_end = .;/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;
  • 版本二
SECTIONS {/** First and formost we need the .init section, containing the code to * be run first. We allow room for the ATAGs and stack and conform to * the bootloader's expectation by putting this code at 0x8000.*/. = 0x8000;.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }/* * Next we put the data.*/.data : {*(.data)}.bss : {. = ALIGN(16);__bss_start = .; *(.bss*) *(COMMON*) __bss_end = .;}
}
__bss_size = (__bss_end - __bss_start) >> 3;
  1. 编写 makefile。将下面的代码另存为Makefile 。
  • 版本一

CFILES = $(wildcard *.c)
OFILES = $(CFILES:.c=.o)
GCCFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
GCCPATH = ../../gcc-arm-9.2-2019.12-x86_64-aarch64-none-elf/binall: clean kernel8.imgboot.o: boot.S$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c boot.S -o boot.o%.o: %.c$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c $< -o $@kernel8.img: boot.o $(OFILES)$(GCCPATH)/aarch64-none-elf-ld -nostdlib -nostartfiles boot.o $(OFILES) -T link.ld -o kernel8.elf$(GCCPATH)/aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.imgclean:/bin/rm kernel8.elf *.o *.img > /dev/null 2> /dev/null || true
  • CFILES :当前目录中已经存在的 .c 文件的列表(我们的输入) 》

  • OFILES :是相同的列表,但是用每个文件名中的 .c 被 .o 替换,这些是包含二进制代码的目标文件,它们将由编译器生成(我们的输出)。

  • gcCFLAGS :是一个参数列表,它告诉编译器我们正在为裸机构建程序,因此它不能依赖于我们常用的任何标准库。

  • GCCPATH :是我们的编译器的二进制文件的路径(你之前下载的ARM工具的解压缩的位置)

  • 然后是一个目标列表,在冒号之后列出了它们的依赖项。将执行每个目标下的缩进命令以构建该目标。 要构建 boot.o,我们依赖于源代码文件 boot.S 的存在。 然后,使用正确的标志运行我们的编译器,将 boot.S 作为我们的输入并生成 boot.o。

  • % 是 makefile 中的匹配通配符。要构建以 .o 结尾的文件,需要其名称类似的 .c 文件。 然后执行下面的命令列表。

  • 接下来,要构建 kernel8.img,我们首先必须构建 boot.o 以及OFILES 列表中的所有其他 .o 文件。如果有以上文件的话,我们使用命令与链接脚本 link.ld 将 boot.o 与其他目标文件连接起来,从而决定 kernel8.elf 镜像文件的布局。然而,ELF文件需要运行在一个操作系统下。因此,对于裸机环境,我们使用将ELF文件的必要部分提取到 kernel8.img 中。这是我们最终的树莓派4B的OS内核镜像。

  • 对于编译目标"clean"和"all",我们不必做多余的解释。

  • 版本二

CRO             ?= arm-none-eabi-
#CRO             ?= arm-linux-gnueabi-
TARGET          ?= bsp
CC              := $(CRO)gcc
LD              := $(CRO)ld
OBJCOPY         := $(CRO)objcopy
SRCS            = $(wildcard *.c)
OBJS            = $(SRCS:.c=.o)
CFLAGS          = -march=armv8-a -mtune=cortex-a72 -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfilesall: clean kernel7.img  start.o: start.S$(CC) $(CFLAGS) -c start.S -o start.o%.o: %.c$(CC) $(CFLAGS) -c $< -o $@kernel7.img: start.o $(OBJS)$(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel7.elf$(OBJCOPY) -O binary kernel7.elf kernel7.img
clean:rm kernel7.elf kernel7.img *.o >/dev/null 2>/dev/null || true
  1. 编译。现在我们已经有了我们的 Makefile,我们只需输入 make 来构建我们的内核映像。 由于“all”是我们的 Makefile 中列出的第一个目标,除非您另有说明,否则 make 将构建它。 在构建“all”时,它会首先清理所有旧构建,然后让我们重新构建 kernel7.img。
  • 创建完成的文件夹
-rw-r--r-- 1 Lenovo None  815 Jul 27 21:29 Makefile
-rw-r--r-- 1 Lenovo None  610 Sep 16  2020 link.ld
-rw-r--r-- 1 Lenovo None  454 Jul 27 21:28 main.c
-rw-r--r-- 1 Lenovo None 1648 Sep 16  2020 start.S
  1. 将我们的内核映像复制到 SD 卡。
  • 希望您已经拥有一张带有 Raspbian 映像的微型 SD 卡。 要引导我们的内核而不是 Raspbian,我们需要用我们自己的内核映像替换现有的内核映像,同时注意保持目录结构的其余部分完整无缺。

  • 在开发机器上,挂载 SD 卡并删除其中以 kernel 开头的所有文件。 更谨慎的方法可能是简单地将这些从 SD 卡移到本地硬盘驱动器上的备份文件夹中。 如果需要,您可以轻松地恢复这些。

  • 现在将我们的 kernel7.img 复制到 SD 卡上。 这个名字很有意义,它向 RPi4 发出信号,我们希望它以 64 位模式启动。 我们还可以通过在 config.txt 中将 arm_64bit 设置为非零值来强制执行此操作。 将我们的操作系统引导到 64 位模式意味着我们可以利用 RPi4 可用的更大内存容量。

  1. 制作完成的 SD卡 目录如下:
简略信息:COPYING.linux           bcm2710-rpi-3-b-plus.dtb  fixup4.dat    start.elf
LICENCE.broadcom        bcm2710-rpi-3-b.dtb       fixup4cd.dat  start4.elf
bcm2708-rpi-b-plus.dtb  bcm2710-rpi-cm3.dtb       fixup4db.dat  start4cd.elf
bcm2708-rpi-b-rev1.dtb  bcm2711-rpi-4-b.dtb       fixup4x.dat   start4db.elf
bcm2708-rpi-b.dtb       bcm2711-rpi-400.dtb       fixup_cd.dat  start4x.elf
bcm2708-rpi-cm.dtb      bcm2711-rpi-cm4.dtb       fixup_db.dat  start_cd.elf
bcm2708-rpi-zero-w.dtb  bootcode.bin              fixup_x.dat   start_db.elf
bcm2708-rpi-zero.dtb    cmdline.txt               issue.txt     start_x.elf
bcm2709-rpi-2-b.dtb     config.txt                kernel7.img
bcm2710-rpi-2-b.dtb     fixup.dat                 overlays详细信息:
-rw-r--r-- 1 Lenovo None   18693 Jan  5  2021 COPYING.linux
-rw-r--r-- 1 Lenovo None    1594 Jan  5  2021 LICENCE.broadcom
-rw-r--r-- 1 Lenovo None   25870 Mar  3 13:40 bcm2708-rpi-b-plus.dtb
-rw-r--r-- 1 Lenovo None   25218 Mar  3 13:40 bcm2708-rpi-b-rev1.dtb
-rw-r--r-- 1 Lenovo None   25607 Mar  3 13:40 bcm2708-rpi-b.dtb
-rw-r--r-- 1 Lenovo None   25529 Mar  3 13:40 bcm2708-rpi-cm.dtb
-rw-r--r-- 1 Lenovo None   26545 Mar  3 13:40 bcm2708-rpi-zero-w.dtb
-rw-r--r-- 1 Lenovo None   25352 Mar  3 13:40 bcm2708-rpi-zero.dtb
-rw-r--r-- 1 Lenovo None   26745 Mar  3 13:40 bcm2709-rpi-2-b.dtb
-rw-r--r-- 1 Lenovo None   26894 Mar  3 13:40 bcm2710-rpi-2-b.dtb
-rw-r--r-- 1 Lenovo None   29011 Mar  3 13:40 bcm2710-rpi-3-b-plus.dtb
-rw-r--r-- 1 Lenovo None   28392 Mar  3 13:40 bcm2710-rpi-3-b.dtb
-rw-r--r-- 1 Lenovo None   26890 Mar  3 13:40 bcm2710-rpi-cm3.dtb
-rw-r--r-- 1 Lenovo None   49090 Mar  3 13:40 bcm2711-rpi-4-b.dtb
-rw-r--r-- 1 Lenovo None   48810 Apr 30 14:01 bcm2711-rpi-400.dtb
-rw-r--r-- 1 Lenovo None   49202 Mar  3 13:40 bcm2711-rpi-cm4.dtb
-rw-r--r-- 1 Lenovo None   52456 Jan  5  2021 bootcode.bin
-rw-r--r-- 1 Lenovo None     169 May  7 15:00 cmdline.txt
-rw-r--r-- 1 Lenovo None    1832 Jul 17 00:23 config.txt
-rw-r--r-- 1 Lenovo None    7314 Apr 30 14:01 fixup.dat
-rw-r--r-- 1 Lenovo None    5446 Apr 30 14:01 fixup4.dat
-rw-r--r-- 1 Lenovo None    3191 Apr 30 14:01 fixup4cd.dat
-rw-r--r-- 1 Lenovo None    8454 Apr 30 14:01 fixup4db.dat
-rw-r--r-- 1 Lenovo None    8452 Apr 30 14:01 fixup4x.dat
-rw-r--r-- 1 Lenovo None    3191 Apr 30 14:01 fixup_cd.dat
-rw-r--r-- 1 Lenovo None   10298 Apr 30 14:01 fixup_db.dat
-rw-r--r-- 1 Lenovo None   10298 Apr 30 14:01 fixup_x.dat
-rw-r--r-- 1 Lenovo None     145 May  7 15:00 issue.txt
-rw-r--r-- 1 Lenovo None     552 Jul 17 00:37 kernel7.img
drwxr-xr-x 1 Lenovo None       0 Jul 27 22:25 overlays
-rw-r--r-- 1 Lenovo None 2952928 Apr 30 14:01 start.elf
-rw-r--r-- 1 Lenovo None 2228768 Apr 30 14:01 start4.elf
-rw-r--r-- 1 Lenovo None  793084 Apr 30 14:01 start4cd.elf
-rw-r--r-- 1 Lenovo None 3722504 Apr 30 14:01 start4db.elf
-rw-r--r-- 1 Lenovo None 2981160 Apr 30 14:01 start4x.elf
-rw-r--r-- 1 Lenovo None  793084 Apr 30 14:01 start_cd.elf
-rw-r--r-- 1 Lenovo None 4794472 Apr 30 14:01 start_db.elf
-rw-r--r-- 1 Lenovo None 3704712 Apr 30 14:01 start_x.elf
  • 从你的开发机器上安全地卸载 SD 卡,将它放回你的 RPi4 并启动它。

  • 您刚刚启动了自己的操作系统!

  • 尽管听起来令人兴奋,但在 RPi4 自己的“彩虹闪屏”之后,您可能看到的只是一个空白的黑色屏幕。 然而,我们不应该感到如此惊讶:我们还没有要求它做任何事情,除了在无限循环中旋转。

  • 不过,基础已经奠定,我们现在可以开始做令人兴奋的事情了。 恭喜你走到这一步!

(1)制作树莓派裸机操作系统相关推荐

  1. 07 树莓派裸机编程,并在Windows MSYS2 QEMU模拟器中运行

    作者 将狼才鲸 创建日期 2022-11-14 Gitee源码和工程地址:才鲸嵌入式 / 开源安防摄像机(嵌入式软件) CSDN文章地址:项目介绍:开源安防摄像机(嵌入式软件) 4)完整的环境安装步骤 ...

  2. 06 在MSYS2中编译树莓派裸机程序,并在QEMU中运行

    作者 将狼才鲸 创建日期 2022-11-14 Gitee源码和工程地址:才鲸嵌入式 / 开源安防摄像机(嵌入式软件) CSDN文章地址:项目介绍:开源安防摄像机(嵌入式软件) 4)完整的环境安装步骤 ...

  3. 树莓派 ubuntu gpio_如何给树莓派安装操作系统

    新的树莓派拿到手中,你迫不及待的要把玩.别急,这可不像你买的Macbook开机就能用,想要顺利启动树莓派,还要经历五个步骤. 准备一张micro SD卡 把操作系统写入SD卡 连接显示器等外围设备 通 ...

  4. buildroot制作树莓派CM3的系统

    之前我写过一篇文章讲如何通过buildroot制作树莓派CM3的系统镜像文件,整个的编译过程按照之前的文章进行可以顺利的得到一个镜像文件(sdcard.img).但是这个文件烧录到sd卡后可以在树莓派 ...

  5. linux制作手机系统,自己动手制作个性化Linux操作系统手机刷机包

    自己动手制作个性化Linux操作系统手机刷机包 本程序用于编辑 Linux 操作系统手机刷机包,运行环境为 Windows XP/2003/Vista.使用该程序可以对 Linux 操作系统手机刷机包 ...

  6. linux系统的手机刷机包,自己动手制作个性化Linux操作系统手机刷机包

    自己动手制作个性化Linux操作系统手机刷机包 本程序用于编辑 Linux 操作系统手机刷机包,运行环境为 Windows XP/2003/Vista.使用该程序可以对 Linux 操作系统手机刷机包 ...

  7. 在Mac上制作树莓派SD镜像

    先记录下,等有空翻译下,在Mac上制作树莓派的镜像还是比较麻烦的,好处是不需要第三方软件,用命令行就可以了.在windows上就比较简单. On Mac OS you have the choice ...

  8. 制作树莓派img镜像文件

    想做个树莓派的img镜像,然而对SD卡进行全盘复制很浪费空间,且不能恢复到比现有SD卡容量小的卡上,因此探索制作小img的方法,网上看了大神制作的脚本,比如https://github.com/con ...

  9. 【树莓派】制作树莓派最小镜像:img裁剪瘦身

    摘录部分要点内容如下(如果作者不允许转载,请联系即删除): 一.查看当前系统所占容量  用Win32DiskImager来制作镜像时是将sd卡正卡全部做成镜像,是因为无法读取到linux分区的原因,所 ...

最新文章

  1. 让我们来谈谈对Linux的认识,值得每一位运维人员深读
  2. mysql 用户无法读取日志文件_MySQL读取Binlog日志常见的3种错误
  3. 作者:夏梓峻(1986-),男,国家超级计算天津中心应用研发部副部长。
  4. 使用了未经检查或不安全的操作_违规操作就是对家庭的不负责!电气安全员提醒你的安全常识...
  5. Bootstrap 滚动监听
  6. 放弃月薪过万的城市工作,返乡创业做农业,面对未知风险,你敢尝试吗?
  7. NeHe OpenGL第四十四课:3D光晕
  8. 【ASP.NET MVC 学习笔记】- 18 Bundle(捆绑)
  9. pandas读取csv文件数据并对指定字段使用matplotlib画折线图
  10. Java 实现MD5
  11. python源码中的pass
  12. 业务太忙,真的是没时间搞自动化理由吗?
  13. 干涉光强公式怎么计算_光强的计算公式是什么啊?
  14. 2022年,渲染农场都怎么收费,比较便宜的渲染农场测评
  15. nginx防止CDN大量回源
  16. 数据库查询时报错com.mysql.jdbc.exceptions.jdbc4.MySQLDataException: ‘1.7725000000E10‘ in column ‘17‘ is outs
  17. 一个实用分数类Fraction的Java实现
  18. fir.im Weekly - Mobile developer 利器分享
  19. Zabbix使用SMTP发送邮件报警并且制定报警内容
  20. 9个不为人知的黑科技网站,每一个都强大到无敌!

热门文章

  1. 使用宏灵活的控制代码
  2. 【异步电机】矢量控制与标量控制
  3. 什么是ARM,STM32?
  4. 解数独 — Python
  5. [分析与设计]二手房房屋图片功能需求分析与设计
  6. 大华与巴斯勒相机实现单拍的不同
  7. Java实现windows,linux服务器word,excel转为PDF;aspose-words,Documents4j
  8. 28845-97-8,Ac-K-DAla-DAla-OH
  9. 自定义室内地图以及路径规划
  10. kubesphpe单机集群删除以及重建