返回
Featured image of post (开坑)给树莓派写个os

(开坑)给树莓派写个os

想给树莓派4写个简单的os

概要

给树莓派写个os这个想法已经萌生很久了,最近课比较少,所以想初步试一试。
找到的资料主要是Github上的一个开源项目rpi4-osdev.初步的想法是参照这个教程先走一边,试试水。

前期准备

硬件材料

准备材料如下:

软件准备

由于我们的编码机并不是arm架构,所以我们要构建交叉编译环境,下载以下内容:

用什么编码?

汇编语言和C语言

现在我们可以开始写操作系统了!!!!!!!!!!

开机引导(bootstrapping)

开机引导程序

RPi4运行的第一个代码需要用汇编语言编写。它做一些检查,做一些设置,并将我们启动到我们的第一个C程序-内核(kernel).

  • 树莓派4B的CPU为Arm Cortex-A72,它有4个核心,我们只希望我们的代码在主核上运行,所以我们检查处理器ID(processor ID)并运行我们的代码(master)或挂起一个无限循环(slave)。
  • 我们需要告诉操作系统如何访问堆栈。堆栈是当前执行的代码所使用的临时存储空间,就像一块暂存区。我们需要为它留出内存,并存储一个指向它的指针。
  • 我们还需要初始化BSS部分。这是内存中的区域,其中将存储未初始化的变量。将所有内容初始化为零更有效,而不是在我们的内核镜像中占用空间。(雾,不知道什么意思,可能要看过ARMv8之后才能理解)(这个其实不是ARMv8中的,这个是可重定位目标文件中的.bss段)

    那些初始化为0的全局变量和静态变量也是被保存在bss中。 也就是说,bss包含:

    • 所有未被显示地初始化的全局变量和静态变量
    • 所有被显示地初始化为0的全局变量和静态变量
      如果想要深入理解,可以看CSAPP的7.4
  • 最后,我们可以跳转到C语言中的main()函数

初始化环境

// boot.S
.section ".text.boot"

.global _start 

_start:
    // 将程序切换至主处理器
    mrs x1, mpidr_el1
    and x1, x1, #3
    cbz x1, 2f          //如果x1是0,跳转到2

    // 挂起
1:  wfe
    b    1b

2:  // We're on the main core!

    // 设置栈段
    ldr     x1, =_start
    mov     sp, x1

    // BSS section置0
    ldr     x1, =__bss_start     // Start address
    ldr     w2, =__bss_size      // Size of the section
3:  cbz     w2, 4f               // Quit loop if zero
    str     xzr, [x1], #8
    sub     w2, w2, #1
    cbnz    w2, 3b               // Loop if non-zero

    // J跳转到main()函数
4:  bl      main
    // In case it does return, halt the master core too
    b       1b

核心代码

// kernel.c
int main(){
    while(1);
}

链接程序

// link.ld
SECTIONS
{
    . = 0x80000;     /* Kernel load address for AArch64 */
    .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;

关于核心引导位置,找到以下说法:booting.txt

Call the kernel image Requirement: MANDATORY

The decompressed kernel image contains a 64-byte header as follows:    
  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) */     

Prior to v3.17, the endianness of text_offset was not specified. In these cases image_size is zero and text_offset is 0x80000 in the endianness of the kernel. Where image_size is non-zero image_size is little-endian and must be respected. Where image_size is zero, text_offset can be assumed to be 0x80000.

To be continue….