Google整Fuchsia代码整了好些年了,近期是有看到说Fuchsia可能会正式商用了,所以抽了空把Fuchsia代码下了下来,想从kernel起好好捋一捋代码,想从根本上理解其kernel部分的实现。
理解任何的系统,都是得从启动开始,先简单看了下Fuchsia平台上的启动部分。同样的,任何的系统启动都会分成芯片初始化–bootloader–kernel—应用程序,这样一个完整的过程。
而在X86平台上,因为BIOS的存在,所以芯片平台初始化的工作会由BIOS来完成,而且往往BIOS是闭源的,所以我们只能从bootloader开始。而fushia系统的bootloader逻辑也比较简单,由UEFI BIOS load起来,再通过UEFI接口找到启动分区,load kernel到内存,然后跳入kernel启动。
今天重点分析 kernel启动代码Start.S的代码逻辑:
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2009 Corey Tabaka
// Copyright (c) 2015 Intel Corporation
// Copyright (c) 2016 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <asm.h>
#include <arch/x86/asm.h>
#include <arch/x86/descriptor.h>
#include <arch/x86/mmu.h>
#include <arch/x86/registers.h>
#include <zircon/tls.h>
#define ADDR_OFFSET_MASK ((1 << ADDR_OFFSET)-1)
#define SHIFT_OFFSET(_s) ((_s) >> 3)
#define SHIFT_REMAIN(_s) ((_s) - (SHIFT_OFFSET(_s) << 3))
// Set a page table entry for the kernel module relocated 64-bit virtual
// address in 32-bit code. Clobbers the %ecx register.
.macro set_relocated_page_table_entry table, shift, value
// Extract 32-bit chunk of kernel_relocated_base containing the index bits
// for this page level shift.
mov PHYS(kernel_relocated_base + SHIFT_OFFSET(\shift)), %ecx
// Get the exact portion of the 32-bit value that is the index
shrl $SHIFT_REMAIN(\shift), %ecx
andl $ADDR_OFFSET_MASK, %ecx
// Get the address on the page table of index * 8 and set the value
shll $3, %ecx
addl $PHYS(\table), %ecx
movl \value, (%ecx)
.endm
// Clobbers %rax, %rdx.
.macro sample_ticks out
rdtsc
shl $32, %rdx
or %rdx, %rax
mov %rax, \out
.endm
// This section name is known specially to kernel.ld and gen-kaslr-fixups.sh.
// This code has relocations for absolute physical addresses, which do not get
// adjusted by the boot-time fixups (which this code calls at the end).
.section .text.boot, "ax", @progbits
.align 8
FUNCTION_LABEL(_start)
// As early as possible collect the time stamp.
sample_ticks %r15 //取当前时间
/* set up a temporary stack pointer */
mov $PHYS(_kstack_end), %rsp //设置栈指针,编译的时候,预留了栈段
// Save off the bootdata pointer in a register that won't get clobbered.
mov %rsi, %rbx
// The fixup code in image.S runs in 64-bit mode with paging enabled,
// so we can't run it too early. But it overlaps the bss, so we move
// it before zeroing the bss. We can't delay zeroing the bss because
// the page tables we're about to set up are themselves in bss.
// The first word after the kernel image (at __data_end in our view)
// gives the size of the following code. Copy it to _end.
mov PHYS(__data_end), %ecx
mov $PHYS(__data_end+4), %esi
mov $PHYS(_end), %edi
rep movsb // while (ecx-- > 0) *edi++ = *esi++;
// Now it's safe to zero the bss. //bss段内存清0
movl $PHYS(__bss_start), %edi
movl $PHYS(_end), %ecx
sub %edi, %ecx // Compute the length of the bss in bytes.
xor %eax, %eax
rep stosb // while (ecx-- > 0) *edi++ = al;
// _zbi_base is in bss, so now it's safe to set it.
mov %rbx, PHYS(_zbi_base)