(1)制作树莓派裸机操作系统

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_el1
    and     x1, x1, #3
    cbz     x1, 2f
    // 代码没有运行在主核心上,所以用死循环挂起代码
1:  wfe
    b       1b
2:  // 代码运行在主核心上,继续

    // 设置堆栈区的起点
    ldr     x1, =_start
    mov     sp, x1

    // 将BSS段清零
    ldr     x1, =__bss_start     // 起始地址
    ldr     w2, =__bss_size      // 段大小
3:  cbz     w2, 4f               // 如果为0,退出循环
    str     xzr, [x1], #8
    sub     w2, w2, #1
    cbnz    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_all
    and r0, r0, #0x1F
    mov r8, #0x1A
    cmp r0, r8
    beq overHyped
    b continue

overHyped: /* Get out of HYP mode */
    adr r1, continue
    msr ELR_hyp, r1
    mrs r1, cpsr_all
    and r1, r1, #0x1f    ;@ CPSR_MODE_MASK
    orr r1, r1, #0x13    ;@ CPSR_MODE_SUPERVISOR
    msr SPSR_hyp, r1
    eret

continue:
    /* Suspend the other cpu cores */
    mrc p15, 0, r0, c0, c0, 5
    ands r0, #3
    bne _halt

    /* set the cpu to SVC32 mode and disable interrupt */
    cps #Mode_SVC

    /* disable the data alignment check */
    mrc p15, 0, r1, c1, c0, 0
    bic 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, _main
    b _halt

_main:
    .word main

_halt:
    wfe
    b _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/bin

all: clean kernel8.img

boot.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.img

clean:
	/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 -nostartfiles

all: 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 自己的“彩虹闪屏”之后,您可能看到的只是一个空白的黑色屏幕。 然而,我们不应该感到如此惊讶:我们还没有要求它做任何事情,除了在无限循环中旋转。

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

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
3c root后,想刷回原来的华为包,步骤如下:(注意3点,1选择正确的recovery包,联通移动不通用,2UPDATE。app要放到sd卡上) 1:下载官方更新包,下载地址:http://consumer.huawei.com/cn/support/downloads/index.htm 选择智能手机,然后选择h30-u10(联通2g),h30-t10(移动2g),搜索并下载更新包(大概500M的文件,里边哟个pdf文档和一个dload文件夹) 联通2g:http://download-c.huawei.com/download/downloadCenter?downloadId=19327&version=30802&siteCode=cn 移动2g:http://download-c.huawei.com/download/downloadCenter?downloadId=19329&version=30811&siteCode=cn 移动1g:http://download-c.huawei.com/download/downloadCenter?downloadId=19263&version=30723&siteCode=cn 2.下载的包解压后,把dload文件夹复制到sdcard(最好是自己的内存卡要有800M以上的空间,我自己没有试验放到自带的sdcard是否可用)。具体看下载的包中pdf文档说明 (华为 H30-U10 智能手机版本升级指导书.pdf),一定要注意sd卡的格式要是FAT32,FAT格式貌似也可以。 3:刷入官方recovery包 01.手机链接USB到电脑,(打开手机助手或者豌豆荚,只要能连上就可以了) 02.打开文件下的:华为荣耀3C一键刷入recovery.img工具.bat,并运行 03.连接后,批处理提示:选择 recovery.img包,根据提示选择自己的包(移动版要用移动版本),我选择联通(我的是3c联通2g) 04.等待手机提示打开recovery模式,如果成功,这里就结束,然后选择关机 05.拔下usb数据线,按住音量上下键 +关机键,开机显示画面时,松开关机键进入recovery模式, 4.等3分钟左右。自动完成了!!哈哈成功!!(搞了1上午,终于o了) 如果提示:main ersion check not match :h30-t00 vs h30-u10,说明你选择的recovery.img版本不对,请重新选择移动,或者联通版
裸机程序和嵌入式操作系统各有其优缺点,具体如下: 裸机程序的优点: 1. 更加简洁:裸机程序不依赖操作系统,因此可以更加简洁,更容易理解和维护。 2. 更高的效率:裸机程序在资源使用上更加精细,可以更好地利用硬件资源,提高程序的运行效率。 3. 更加可靠:裸机程序在运行时不会受到操作系统的影响,因此可以更加可靠地运行。 裸机程序的缺点: 1. 缺乏通用性:裸机程序需要针对不同的硬件进行开发,因此在不同的硬件平台上需要重新进行开发和调试。 2. 缺乏实时性:裸机程序无法提供完整的实时性保证,因为它不能像操作系统那样对不同的任务进行调度和管理。 3. 缺乏灵活性:裸机程序缺乏操作系统的灵活性和可配置性,无法满足复杂的应用需求。 嵌入式操作系统的优点: 1. 更加通用:嵌入式操作系统可以在不同的硬件平台上运行,因此具有更广泛的适用范围。 2. 更加灵活:嵌入式操作系统可以提供更加灵活的配置和管理,能够满足复杂的应用需求。 3. 更加实时:嵌入式操作系统通常具有较好的实时性能,能够满足实时应用的需求。 嵌入式操作系统的缺点: 1. 更加复杂:嵌入式操作系统具有更加复杂的结构和逻辑,需要更高的开发和维护成本。 2. 更加占用资源:嵌入式操作系统需要占用一定的系统资源,可能会影响系统的效率。 3. 更加不可靠:嵌入式操作系统的复杂性可能会导致一些潜在的问题和安全隐患。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值