当前位置:首页>Linux>Linux_aarch64_head.S到main.c的环境建立

Linux_aarch64_head.S到main.c的环境建立

  • 2026-02-09 12:32:41
Linux_aarch64_head.S到main.c的环境建立

PS:要转载请注明出处,本人版权所有。PS: 这个只是基于《我自己》的理解,如果和你的原则及想法相冲突,请谅解,勿喷。

环境说明

  无

前言


  最开始,我仅仅是对linux比较感兴趣,觉得其很神奇的,能够做到很多事情。后面了解到其源码也是开源的,于是抱着学习的态度,简要的看了看相关的代码,在那个时候,我还看的比较粗略,仅仅是简单的会点编译,执行linux命令等等。这期间还有一个有印象的有趣的事儿就是那个pdf《Linux 那些事儿之USB》,大概就是讲述了作者因为要看pian儿,但是U盘识别不到,所以去细读USB相关linux 内核内容的资料。这精神,虽然我看不懂,但是我大为震撼!!!

  在我工作的近几年来,逐渐的和linux打上了交道,从最开始的hisi 3520a1系列的流媒体处理开始,为其搭建了文件系统,编译内核,同时为其适配EC20 4G模块,这期间,我基本都是照着别人的教程或者说文档,渐渐的熟悉了一些linux内核的一些事务。同时这期间,我做过一些简单的字符驱动玩耍模块,只能说玩玩可以的。

  在前几年中的某段时间,我接到一个任务,要在android进程之间大量传输数据2。这个时候我调研到了一个叫做android 匿名共享内存的东西,我发现了一个binder的驱动程序和linux unix socket的功能可以在android 和 linux 里面实现进程间的文件描述符的共享,注意这个方法是通用的,不像某些功能在linux里面能够使用,在android里面不能够使用。在这个时候,我天马行空实现了一个类似 binder的驱动demo3。这可以说是我第一个为了自己写的内核及的相关代码,而且具有实际应用意义。

  在这些工作过程中,我逐渐的觉得自己学习的《操作系统原理》与现实的差别,特别想把书中知识和实际系统结合起来,经过查询,如果想要大概了解linux 内核,最好从其远古的版本读起来,因为大概的脉络没有变,新内核只是更加的结构化,多了很多现代的功能。于是乎,有了《Linux Kernel 0.12 启动简介,调试记录(Ubuntu1804, Bochs, gdb)》一文4。经过了《Linux Kernel 0.12 启动简介,调试记录(Ubuntu1804, Bochs, gdb)》一文的学习之后,我基本了解了linux kernel 0.12版本内核的基本工作原理,例如其调度,内存管理等。其次是对于x86架构下,linux kernel 0.12的启动流程有了一个简要的认知。

  在最近这段时间,我的工作有部分和ai相关,有部分和android和linux的差异相关,需要我对linux内核有更深的印象和见解。于是在以前的基础上,这次,我要实际分析我们工作中所用的最新版本的内核,再一次的去验证一个内核从上电开始,到系统完整起来的过程。由于现代linux内核非常的巨大,所以我只关注我喜欢的部分。

  本文主要是分析aarch64架构的arch/arm64/kernel/head.S 到 init/main.c 中的start_kernel的过程。这可能也是我短时间内最后一次分析这种启动的过程,因为其实道理都是相同的,大部分都是cpu初始化,虚拟内存启用,由实地址切换为虚拟地址,创建init_task,设置sp,进入start_kernel。其实这里很多都是和特定的CPU有关系,内容是固定的。但是虚拟内存启用,初始task创建,初始sp指针初始化这些和《操作系统原理》有关联,可以印证我们所学。

  本文分为两大部分,一部分是head.S到main.c的调试环境建立, 二是从上电开始到进入start_kernel的代码注释分析和部分解释。

准备


  1. 1. AARCH64 异常等级要简单了解一下5
  2. 2. AARCH64 内存布局要简单了解一下6
  3. 3. 看长文警告,一定要有耐心,否则看不下去。

汇编部分的调试环境搭建


  本文的测试环境为qemu-system-aarch64 raspi3b 模拟板卡。linux内核为树莓派内核 rpi-5.15.y, 下载地址为:https://github.com/raspberrypi/linux.git

生成带调试符号的linux kernel 镜像

  在make menu的时候勾选: Kernel hacking > Compile-time checks and compiler options > Compile the kernel with debug info通过如下命令生成镜像:

cd rpi-linux-kernel-dircp arch/arm64/configs/bcm2711_defconfig .configmake ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfigmake ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs
生成rootfs.img镜像

  下载ubuntu-base-18.04.5-base-arm64.tar.gz的基础文件系统。

解压文件系统到指定目录tar -xzf ubuntu-base-18.04.5-base-arm64.tar.gz -C temp/*制作裸文件镜像dd if=/dev/zero of=linuxroot.img bs=1M count=2048sudo mkfs.ext4 linuxroot.imgmkdir  rootfssudo mount linuxroot.img rootfs/sudo cp -rfp temp/*  rootfs/sudo umount rootfs/e2fsck -p -f linuxroot.imgresize2fs  -M linuxroot.img
编译生成最新版qemu

  只有新版的qemu才支持raspi3b模拟板卡

下载qemu代码git clone https://github.com/qemu/qemu.gitcd qemumkdir buildcd build../configure --prefix=/home/sky/LinuxKernel/qemu_install --target-list=arm-softmmu,arm-linux-user,armeb-linux-user,aarch64-softmmu,aarch64-linux-user,aarch64_be-linux-user make
执行qemu加载镜像

  这里的linux目录是内核目录,qemu_install是qemu生成的最新可执行文件目录,当前目录有rootfs镜像linuxroot.img。

-S              freeze CPU at startup (use 'c' to start execution)-s              shorthand for -gdb tcp::1234 注意下面命令如果要直接运行,而不是等待gdb调试,请去掉最后的-s 和 -S。./qemu_install/bin/qemu-system-aarch64 \    -M raspi3b \    -kernel ./linux/arch/arm64/boot/Image \    -dtb ./linux/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb \    -drive id=hd-root,format=raw,file=./linuxroot.img \    -m 1024M \    -serial stdio \    -smp 4 \    -device usb-kbd \    -device usb-tablet \    -device usb-net,netdev=net0 \    -netdev user,id=net0,hostfwd=tcp::5555-:22 \    -append "rw earlycon=pl011,0x3f201000 console=ttyAMA0 loglevel=8 root=/dev/mmcblk0 rootwait" -S -s
gdb 连接调试

  注意请在qemu启动后面加上-s 和 -S。当连接成功时,这个时候cpu还未执行,输入ni执行到第一条指令。

没有gdb-multiarch自行安装这里的vmlinux就是编译生成的最终镜像gdb-multiarch  linux/vmlinux在gdb cli中执行target remote localhost:1234
汇编代码调试

  我这里把整个head.S里面重要的部分都dump下来了。跟着这个部分然后参考head.S去阅读,会有奇效。长文注释警告。

  首先是上电部分,当板卡上电后,会执行bootloader,bootloader会将内核和dtb放到特定的位置,然后按照Linux arm64 boot protocal去初始化对应的寄存器,最后进入head.S的第一条指令。

@ boot start ... ...//Linux arm64 boot protocal@ https://www.kernel.org/doc/Documentation/arm64/booting.txt@ 0x08000000 FDT/*- 主 CPU 通用寄存器设置  x0 = 系统 RAM 中设备树 blob (dtb) 的物理地址。  x1 = 0(留作将来使用)  x2 = 0(留作将来使用)  x3 = 0(留作将来使用)*///注意这里的0x18地址存放的是fdt的地址,地址为0x080000000x0000000000000000:    ldr    x0, 0x180x0000000000000004:    mov    x1, xzr0x0000000000000008:    mov    x2, xzr0x000000000000000c:    mov    x3, xzr//注意这里的0x20是存放的kernel地址,地址为0x002000000x0000000000000010:    ldr    x4, 0x200x0000000000000014:    br    x4@ 0x00200000 head.S start ... ...@ =======> now, go to 0x00200000

  注意,当我们进入head.S的最开始的地方的时候,有一个标准得到头如下。其中code1的部分将会跳转到真正执行的地方。

@ 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) */@ 0x200000  code0@ 0x200004  code1                            @ 0x200008  text_offset @ 0x20000c                           @ 0x200010  image_size                    @ 0x200014                    @ 0x200018  flags                       @ 0x20001c                          @ 0x200020  res2                    @ 0x200024                          @ 0x200028  res3                       @ 0x20002c                      @ 0x200030  res4                       @ 0x200034                    @ 0x200038  magic       @ 0x20003c  res5//注意,这里的code0,code1就是地址0x200000和0x200004的指令。整个0x200000到0x200040就是内核镜像的64字节头。0x0000000000200000:    ccmp    x18, #0x0#0xd, pl  // special NOP to identity as PE/COFF executable0x0000000000200004:    b    0x1190000 @ =======> now, go to 0x1190000(primary_entry)

  这是整个内核启动部分最重要的函数,所有的东西都在这里做完,然后跳转到start_kernel。下面我们会来重点分析这个部分的内容。详细请看注释。

//注意这里的几个bl指令,覆盖了进入kernel_start前的所有操作@ SYM_CODE_START(primary_entry)//跳转过去保存boot参数//保存x0(fdt),x1,x2,x3到符号boot_args的变量中,靠dcache_inval_poc中的ret返回到下一行指令0x0000000001190000:    bl    0x1190020 //preserve_boot_args//跳转过去执行不同异常等级的初始化,这里比较复杂,从开始的el2异常级别跳转到el1级别。0x0000000001190004:    bl    0xd5d000 //init_kernel_el//将内核镜像开始地址给x23,也就是0x2000000x0000000001190008:    adrp    x23, 0x200000// KASLR offset, defaults to 00x000000000119000c:    and    x23, x23, #0x1fffff//跳转过去根据w0的值,保存相关的cpu boot mode,注意当前我们的cpu已经处于el1等级,w0 存的是 el2 的标识符0x0000000001190010:    bl    0xd5d1f8//创建页表,这里面的创建只填充了相关的页表项,并没有开启mmu//idmap = 0x117e00, 0x117e0 = 0x117f03, 0x117f30 = 0x00c00701, //    注意,这时页表项表示2MB的区域。idmap区域包含了__cpu_setup和__primary_switch//这里执行完,有两个重要的数据结构:idmap_pg_dir 和 init_pg_dir//我们将物理地址__idmap_text_start映射到虚拟地址[__idmap_text_start, __idmap_text_end],注意观察,物理地址和虚拟地址基本是一致的。//还将物理地址_text映射到虚拟地址[KIMAGE_VADDR + KASLR, _end]0x0000000001190014:    bl    0x1190040//The following calls CPU setup code, see arch/arm64/mm/proc.S//注意,这里已经准备好了SCTLR在x0中,下面就是相关的初始化,然后准备打开mmu的参数0x0000000001190018:    bl    0xd5d6f4//最终的初始化,开启mmu,并跳转到kernel_start0x000000000119001c:    b    0xd5d3d8@ SYM_CODE_END(primary_entry)

  此部分对应保存启动参数,主要还是保存启动时,x0~x3。

@ SYM_CODE_START_LOCAL(preserve_boot_args)//x21保存dtb物理地址0x0000000001190020:    mov    x21, x0//将dtb,x1,x2,x3物理地址存放到变量arch/arm64/kernel/setup.c:u64 __cacheline_aligned boot_args[4];0x0000000001190024:    adrp    x0, 0x15450000x0000000001190028:    add    x0, x0, #0x0//存放dtb,x10x000000000119002c:    stp    x21, x1, [x0]//存放x2,x30x0000000001190030:    stp    x2, x3, [x0, #16]@ 刷新cache0x0000000001190034:    dmb    sy0x0000000001190038:    add    x1, x0, #0x200x000000000119003c:    b    0x2346a8@ SYM_CODE_END(preserve_boot_args)

  此部分很长,其实主要是汇编代码稍微复杂,其基本的作用就是创建页表,这里面的创建只填充了相关的页表项。分别创建了这里执行完,有两个重要的数据结构:idmap_pg_dir和init_pg_dir的数据结构。这里用的是两级映射,第一级是全局映射,第二级是每个项2MB的映射。这里的idmap_pg_dir映射的是__cpu_setup和__primary_switch部分的内容,这部分主要涉及到mmu开启的过程,需要将物理地址和虚拟地址对应起来。init_pg_dir主要是映射的是kernel虚拟地址和kernel镜像地址。

@ SYM_FUNC_START_LOCAL(__create_page_tables)//保存返回值到x280x0000000001190040:    mov    x28, x30//加载init_pg_dir 到x00x0000000001190044:    adrp    x0, 0x181d000//加载init_pg_end 到x10x0000000001190048:    adrp    x1, 0x1820000@ 刷新cache0x000000000119004c:    bl    0x2346a8//加载init_pg_dir 到x00x0000000001190050:    adrp    x0, 0x181d000//加载init_pg_end 到x10x0000000001190054:    adrp    x1, 0x1820000//求出init_pg的大小放入x1中count0x0000000001190058:    sub    x1, x1, x0//向x0中写入0,然后x1 -= 64,当x1等于0时候,所有pg清理完毕。0x000000000119005c:    stp    xzr, xzr, [x0], #160x0000000001190060:    stp    xzr, xzr, [x0], #160x0000000001190064:    stp    xzr, xzr, [x0], #160x0000000001190068:    stp    xzr, xzr, [x0], #160x000000000119006c:    subs    x1, x1, #0x400x0000000001190070:    b.ne    0x119005c  // b.any//根据配置加载不同的flag, SWAPPER_MM_MMUFLAGS0x0000000001190074:    mov    x7, #0x701                     // #1793// 获取idmap的页表基地址,idmap_pg_dir0x0000000001190078:    adrp    x0, 0x117e000@ 获取idmap的代码段虚地址,__idmap_text_start0x000000000119007c:    adrp    x3, 0xd5d000@ 将系统地址线位数给x5, VA_BITS_MIN0x0000000001190080:    mov    x5, #0x27                      // #39//获取变量地址到x6, vabits_actual0x0000000001190084:    adrp    x6, 0x17280000x0000000001190088:    add    x6, x6, #0x10//将39写入变量vabits_actual0x000000000119008c:    str    x5, [x6]0x0000000001190090:    dmb    sy0x0000000001190094:    dc    ivac, x6@ 判断虚拟地址空间是否够IDmap来映射0x0000000001190098:    adrp    x5, 0xd5d0000x000000000119009c:    clz    x5, x50x00000000011900a0:    cmp    x5, #0x19@ 这里要跳转,不需要扩展虚拟地址0x00000000011900a4:    b.ge    0x11900e0  // b.tcont@ 这部分是虚拟地址扩展的相关操作,这里不做详解0x00000000011900a8:    adrp    x6, 0x15550000x00000000011900ac:    add    x6, x6, #0xcc80x00000000011900b0:    str    x5, [x6]0x00000000011900b4:    dmb    sy0x00000000011900b8:    dc    ivac, x60x00000000011900bc:    mov    x4, #0x200                     // #5120x00000000011900c0:    add    x5, x0, #0x1, lsl #120x00000000011900c4:    mov    x6, x50x00000000011900c8:    orr    x6, x6, #0x30x00000000011900cc:    lsr    x5, x3, #390x00000000011900d0:    sub    x4, x4, #0x10x00000000011900d4:    and    x5, x5, x40x00000000011900d8:    str    x6, [x0, x5, lsl #3]0x00000000011900dc:    add    x0, x0, #0x1, lsl #12@ 从上面不需要扩展虚拟地址跳转而来,0x00000000011900a4@ 将512 个 pgd entry存入x40x00000000011900e0:    adrp    x4, 0x15550000x00000000011900e4:    ldr    x4, [x4, #3280]@ 将__idmap_text_end放入x60x00000000011900e8:    adrp    x6, 0xd5d0000x00000000011900ec:    add    x6, x6, #0x7e0@ 这里开始映射[__idmap_text_start, __idmap_text_end] 到 idmap_pg_dir中,@    且,这部分内容就是cpu_setup部分的内容,恰好对应开启mmu的代码。//tbl:    x0 = idmap_pg_dir = 0x117e000//rtbl:   x1 = 0 //vstart: x3 = __idmap_text_start = 0xd5d000//vend:   x6 = __idmap_text_end = 0xd5d7e0//flags:  x7 = SWAPPER_MM_MMUFLAGS//phys:   x3 = __idmap_text_start = 0xd5d000//pgds:   x4 = idmap_ptrs_per_pgd = 512//tmp regs: x10, x11, x12, x13, x14@ macro map_memory start ...@ __idmap_text_end - 1 是idmap映射结束的地方0x00000000011900f0:    sub    x6, x6, #0x1@ x1 = idmap的页表基地址(idmap_pg_dir) + 2^12 ,并指向了下一个page entry0x00000000011900f4:    add    x1, x0, #0x1, lsl #12@ 将x1 保存到 x140x00000000011900f8:    mov    x14, x1@ 将count赋值为00x00000000011900fc:    mov    x13, #0x0                       // #0// vstart:    x3 = __idmap_text_start = 0xd5d000// vend:    x6 = __idmap_text_end = 0xd5d7e0// shift:    30// ptrs:    x4 = idmap_ptrs_per_pgd = 512// istart:    x10// iend:    // count:    x13@ compute_indices  start ...//将vend右逻辑偏移shift(30)位0x0000000001190100:    lsr    x11, x6, #30//将ptrs(number of entries in page table)存放到istart, 每个表512项0x0000000001190104:    mov    x10, x4//pte 数量减一0x0000000001190108:    sub    x10, x10, #0x1//此时算出来vend的pgd index,根据虚拟地址右移30位,还剩9位,恰好表示512个项的id。// iend = (vend >> shift) & (ptrs - 1)0x000000000119010c:    and    x11, x11, x100x0000000001190110:    mov    x10, x40x0000000001190114:    mul    x10, x10, x13// iend += count * ptrs0x0000000001190118:    add    x11, x11, x10//将vstart右逻辑偏移shift位0x000000000119011c:    lsr    x10, x3, #300x0000000001190120:    mov    x13, x40x0000000001190124:    sub    x13, x13, #0x1// istart = (vstart >> shift) & (ptrs - 1), 此时算出来vstart的pgd index0x0000000001190128:    and    x10, x10, x13//计算出多少项page entry0x000000000119012c:    sub    x13, x11, x10@ compute_indices  end ...@ populate_entries start ... 0x0000000001190130:    mov    x12, x1//给当前entry设置内存属性0x0000000001190134:    orr    x12, x12, #0x3@ 向一级页表idmap_pg_dir(0x117e000)存入二级页表地址(0x117f000)0x0000000001190138:    str    x12, [x0, x10, lsl #3]0x000000000119013c:    add    x1, x1, #0x1, lsl #120x0000000001190140:    add    x10, x10, #0x10x0000000001190144:    cmp    x10, x110x0000000001190148:    b.ls    0x1190130  // b.plast@ populate_entries end ... //注意,这里相当于tbl=tbl+PAGE_SIZE,主要还是指向了二级页表//相当于现在一级页表为:idmap_pg_dir(0x117e000),里面存放的是0x0117f003//这里的x14是二级页表的地址,为0x0117f0000x000000000119014c:    mov    x0, x14//sv = rtbl = tbl+PAGE_SIZE+PAGE_SIZE,相当于指向了三级页表0x0000000001190150:    mov    x14, x1@ compute_indices  start ...//将vend右逻辑偏移shift位0x0000000001190154:    lsr    x11, x6, #21//将ptrs(number of entries in page table)存放到istart, 每个表512项0x0000000001190158:    mov    x10, #0x200                     // #512//pte 数量减一0x000000000119015c:    sub    x10, x10, #0x1//此时算出来vend的pgd index// iend = (vend >> shift) & (ptrs - 1)0x0000000001190160:    and    x11, x11, x100x0000000001190164:    mov    x10, #0x200                     // #5120x0000000001190168:    mul    x10, x10, x13// iend += count * ptrs0x000000000119016c:    add    x11, x11, x10//将vstart右逻辑偏移shift位0x0000000001190170:    lsr    x10, x3, #210x0000000001190174:    mov    x13, #0x200                     // #5120x0000000001190178:    sub    x13, x13, #0x1// istart = (vstart >> shift) & (ptrs - 1), 此时算出来vstart的pgd index0x000000000119017c:    and    x10, x10, x13//计算出多少项page entry0x0000000001190180:    sub    x13, x11, x10@ compute_indices  end ...@ x13 = 0xc00000, x3 = 0xd5d0000x0000000001190184:    and    x13, x3, #0xffffffffffe00000@ populate_entries start ... @ x12 = 0xc000000x0000000001190188:    mov    x12, x13//给当前entry设置内存属性0x000000000119018c:    orr    x12, x12, x7@ 向二级页表(0x117f000 + 6*8 = 0x117f030)存入地址0xc007010x0000000001190190:    str    x12, [x0, x10, lsl #3]0x0000000001190194:    add    x13, x13, #0x200, lsl #120x0000000001190198:    add    x10, x10, #0x10x000000000119019c:    cmp    x10, x110x00000000011901a0:    b.ls    0x1190188  // b.plast@ populate_entries end ... @ init_pg_dir  给x00x00000000011901a4:    adrp    x0, 0x181d000@ KIMAGE_VADDR 给x50x00000000011901a8:    mov    x5, #0xffffffc0ffffffff        // #-2705829396490x00000000011901ac:    movk    x5, #0x800, lsl #160x00000000011901b0:    movk    x5, #0x0// add KASLR displacement0x00000000011901b4:    add    x5, x5, x23@ 将页表项数目给x40x00000000011901b8:    mov    x4, #0x200                     // #512@ _end 给x60x00000000011901bc:    adrp    x6, 0x1820000@ _start 给x30x00000000011901c0:    adrp    x3, 0x200000@ 求出_end-_start0x00000000011901c4:    sub    x6, x6, x3@ 算出基于KIMAGE_VADDR和KASLR的偏移0x00000000011901c8:    add    x6, x6, x5//tbl:    x0 = init_pg_dir//rtbl:   x1 = 0//vstart: x5 = KIMAGE_VADDR + KASLR//vend:   x6 = _end//flags:  x7 = SWAPPER_MM_MMUFLAGS//phys:   x3 = _text//pgds:   x4 = PTRS_PER_PGD//tmp regs: x10, x11, x12, x13, x14@ macro map_memory start ...@ 开始填充页表init_pg_dir0x00000000011901cc:    sub    x6, x6, #0x10x00000000011901d0:    add    x1, x0, #0x1, lsl #120x00000000011901d4:    mov    x14, x10x00000000011901d8:    mov    x13, #0x0                       // #00x00000000011901dc:    lsr    x11, x6, #300x00000000011901e0:    mov    x10, x40x00000000011901e4:    sub    x10, x10, #0x10x00000000011901e8:    and    x11, x11, x100x00000000011901ec:    mov    x10, x40x00000000011901f0:    mul    x10, x10, x130x00000000011901f4:    add    x11, x11, x100x00000000011901f8:    lsr    x10, x5, #300x00000000011901fc:    mov    x13, x40x0000000001190200:    sub    x13, x13, #0x10x0000000001190204:    and    x10, x10, x130x0000000001190208:    sub    x13, x11, x100x000000000119020c:    mov    x12, x10x0000000001190210:    orr    x12, x12, #0x30x0000000001190214:    str    x12, [x0, x10, lsl #3]0x0000000001190218:    add    x1, x1, #0x1, lsl #120x000000000119021c:    add    x10, x10, #0x10x0000000001190220:    cmp    x10, x110x0000000001190224:    b.ls    0x119020c  // b.plast0x0000000001190228:    mov    x0, x140x000000000119022c:    mov    x14, x10x0000000001190230:    lsr    x11, x6, #210x0000000001190234:    mov    x10, #0x200                     // #5120x0000000001190238:    sub    x10, x10, #0x10x000000000119023c:    and    x11, x11, x100x0000000001190240:    mov    x10, #0x200                     // #5120x0000000001190244:    mul    x10, x10, x130x0000000001190248:    add    x11, x11, x100x000000000119024c:    lsr    x10, x5, #210x0000000001190250:    mov    x13, #0x200                     // #5120x0000000001190254:    sub    x13, x13, #0x10x0000000001190258:    and    x10, x10, x130x000000000119025c:    sub    x13, x11, x100x0000000001190260:    and    x13, x3, #0xffffffffffe000000x0000000001190264:    mov    x12, x130x0000000001190268:    orr    x12, x12, x70x000000000119026c:    str    x12, [x0, x10, lsl #3]0x0000000001190270:    add    x13, x13, #0x200, lsl #120x0000000001190274:    add    x10, x10, #0x10x0000000001190278:    cmp    x10, x110x000000000119027c:    b.ls    0x1190264  // b.plast@ macro map_memory end ...//内存屏障0x0000000001190280:    dmb    sy@ 刷新cache0x0000000001190284:    adrp    x0, 0x117e0000x0000000001190288:    adrp    x1, 0x11810000x000000000119028c:    bl    0x2346a8@ 刷新cache0x0000000001190290:    adrp    x0, 0x181d0000x0000000001190294:    adrp    x1, 0x18200000x0000000001190298:    bl    0x2346a8@ 返回到bl    __cpu_setup0x000000000119029c:    ret    x28@ SYM_FUNC_END(__create_page_tables)

  这部分是刷新i/d cache

@ dcache_inval_poc start ...0x00000000002346a8:    mrs    x3, ctr_el00x00000000002346ac:    nop0x00000000002346b0:    ubfx    x3, x3, #16#40x00000000002346b4:    mov    x2, #0x4                       // #40x00000000002346b8:    lsl    x2, x2, x30x00000000002346bc:    sub    x3, x2, #0x10x00000000002346c0:    tst    x1, x30x00000000002346c4:    bic    x1, x1, x30x00000000002346c8:    b.eq    0x2346d0  // b.none0x00000000002346cc:    dc    civac, x10x00000000002346d0:    tst    x0, x30x00000000002346d4:    bic    x0, x0, x30x00000000002346d8:    b.eq    0x2346e4  // b.none0x00000000002346dc:    dc    civac, x00x00000000002346e0:    b    0x2346e80x00000000002346e4:    dc    ivac, x00x00000000002346e8:    add    x0, x0, x20x00000000002346ec:    cmp    x0, x10x00000000002346f0:    b.cc    0x2346e4  // b.lo, b.ul, b.last0x00000000002346f4:    dsb    sy0x00000000002346f8:    ret@ dcache_inval_poc end ...

  这部分就是对应的是开始的在el2模式下初始化,并返回到el1,并保存启动参数。

@ SYM_FUNC_START(init_kernel_el)//读取当前的异常等级0x0000000000d5d000:    mrs    x0, currentel//判断是否为异常等级20x0000000000d5d004:    cmp    x0, #0x8//跳转到el2(qemu 模拟机器执行路径), init_el20x0000000000d5d008:    b.eq    0xd5d034  // b.none0x0000000000d5d00c:    mov    x0, #0x30500000                // #8105492480x0000000000d5d010:    movk    x0, #0x8000x0000000000d5d014:    msr    sctlr_el1, x00x0000000000d5d018:    isb0x0000000000d5d01c:    movz    x0, #0x0, lsl #160x0000000000d5d020:    movk    x0, #0x3c50x0000000000d5d024:    msr    spsr_el1, x00x0000000000d5d028:    msr    elr_el1, x300x0000000000d5d02c:    mov    w0, #0xe11                     // #36010x0000000000d5d030:    eret@ init_el2 start ... ...//配置hcr_el2寄存器,HCR(Hypervisor Configuration Register)0x0000000000d5d034:    mov    x0, #0x100000000000000         // #720575940379279360x0000000000d5d038:    movk    x0, #0x300, lsl #320x0000000000d5d03c:    movk    x0, #0x8000, lsl #160x0000000000d5d040:    movk    x0, #0x00x0000000000d5d044:    msr    hcr_el2, x0//ISB. 指令同步屏障0x0000000000d5d048:    isb//初始化el2下的各种状态/*.macro init_el2_state    __init_el2_sctlr    __init_el2_timers    __init_el2_debug    __init_el2_lor    __init_el2_stage2    __init_el2_gicv3    __init_el2_hstr    __init_el2_nvhe_idregs    __init_el2_nvhe_cptr    __init_el2_nvhe_sve    __init_el2_fgt    __init_el2_nvhe_prepare_eret.endm*///__init_el2_sctlr0x0000000000d5d04c:    mov    x0, #0x30c50000                // #8182169600x0000000000d5d050:    movk    x0, #0x8300x0000000000d5d054:    msr    sctlr_el2, x00x0000000000d5d058:    isb//__init_el2_timers0x0000000000d5d05c:    mov    x0, #0x3                       // #30x0000000000d5d060:    msr    cnthctl_el2, x00x0000000000d5d064:    msr    cntvoff_el2, xzr//__init_el2_debug0x0000000000d5d068:    mrs    x1, id_aa64dfr0_el10x0000000000d5d06c:    sbfx    x0, x1, #8#40x0000000000d5d070:    cmp    x0, #0x10x0000000000d5d074:    b.lt    0xd5d080  // b.tstop0x0000000000d5d078:    mrs    x0, pmcr_el00x0000000000d5d07c:    ubfx    x0, x0, #11#50x0000000000d5d080:    csel    x2, xzr, x0, lt  // lt = tstop0x0000000000d5d084:    ubfx    x0, x1, #32#40x0000000000d5d088:    cbz    x0, 0xd5d0a80x0000000000d5d08c:    mrs    x0, pmbidr_el10x0000000000d5d090:    and    x0, x0, #0x100x0000000000d5d094:    cbnz    x0, 0xd5d0a00x0000000000d5d098:    mov    x0, #0x50                      // #800x0000000000d5d09c:    msr    pmscr_el2, x00x0000000000d5d0a0:    mov    x0, #0x3000                    // #122880x0000000000d5d0a4:    orr    x2, x2, x00x0000000000d5d0a8:    ubfx    x0, x1, #44#40x0000000000d5d0ac:    cbz    x0, 0xd5d0c40x0000000000d5d0b0:    mrs    x0, s3_0_c9_c11_70x0000000000d5d0b4:    and    x0, x0, #0x100x0000000000d5d0b8:    cbnz    x0, 0xd5d0c40x0000000000d5d0bc:    mov    x0, #0x3000000                 // #503316480x0000000000d5d0c0:    orr    x2, x2, x00x0000000000d5d0c4:    msr    mdcr_el2, x2//__init_el2_lor0x0000000000d5d0c8:    mrs    x1, id_aa64mmfr1_el10x0000000000d5d0cc:    ubfx    x0, x1, #16#40x0000000000d5d0d0:    cbz    x0, 0xd5d0d80x0000000000d5d0d4:    msr    s3_0_c10_c4_3, xzr//__init_el2_stage20x0000000000d5d0d8:    msr    vttbr_el2, xzr//__init_el2_gicv30x0000000000d5d0dc:    mrs    x0, id_aa64pfr0_el10x0000000000d5d0e0:    ubfx    x0, x0, #24#40x0000000000d5d0e4:    cbz    x0, 0xd5d1080x0000000000d5d0e8:    mrs    x0, s3_4_c12_c9_50x0000000000d5d0ec:    orr    x0, x0, #0x10x0000000000d5d0f0:    orr    x0, x0, #0x80x0000000000d5d0f4:    msr    s3_4_c12_c9_5, x00x0000000000d5d0f8:    isb0x0000000000d5d0fc:    mrs    x0, s3_4_c12_c9_50x0000000000d5d100:    tbz    w0, #0, 0xd5d1080x0000000000d5d104:    msr    s3_4_c12_c11_0, xzr//__init_el2_hstr0x0000000000d5d108:    msr    hstr_el2, xzr//__init_el2_nvhe_idregs0x0000000000d5d10c:    mrs    x0, midr_el10x0000000000d5d110:    mrs    x1, mpidr_el10x0000000000d5d114:    msr    vpidr_el2, x00x0000000000d5d118:    msr    vmpidr_el2, x1//__init_el2_nvhe_cptr0x0000000000d5d11c:    mov    x0, #0x33ff                    // #133110x0000000000d5d120:    msr    cptr_el2, x0//__init_el2_nvhe_sve0x0000000000d5d124:    mrs    x1, id_aa64pfr0_el10x0000000000d5d128:    ubfx    x1, x1, #32#40x0000000000d5d12c:    cbz    x1, 0xd5d1440x0000000000d5d130:    and    x0, x0, #0xfffffffffffffeff0x0000000000d5d134:    msr    cptr_el2, x00x0000000000d5d138:    isb0x0000000000d5d13c:    mov    x1, #0x1ff                     // #5110x0000000000d5d140:    msr    zcr_el2, x1//__init_el2_fgt0x0000000000d5d144:    mrs    x1, id_aa64mmfr0_el10x0000000000d5d148:    ubfx    x1, x1, #56#40x0000000000d5d14c:    cbz    x1, 0xd5d18c0x0000000000d5d150:    mov    x0, xzr0x0000000000d5d154:    mrs    x1, id_aa64dfr0_el10x0000000000d5d158:    ubfx    x1, x1, #32#40x0000000000d5d15c:    cmp    x1, #0x30x0000000000d5d160:    b.lt    0xd5d168  // b.tstop0x0000000000d5d164:    orr    x0, x0, #0x40000000000000000x0000000000d5d168:    msr    s3_4_c3_c1_4, x00x0000000000d5d16c:    msr    s3_4_c3_c1_5, x00x0000000000d5d170:    msr    s3_4_c1_c1_4, xzr0x0000000000d5d174:    msr    s3_4_c1_c1_5, xzr0x0000000000d5d178:    msr    s3_4_c1_c1_6, xzr0x0000000000d5d17c:    mrs    x1, id_aa64pfr0_el10x0000000000d5d180:    ubfx    x1, x1, #44#40x0000000000d5d184:    cbz    x1, 0xd5d18c0x0000000000d5d188:    msr    s3_4_c3_c1_6, xzr// __init_el2_nvhe_prepare_eret0x0000000000d5d18c:    mov    x0, #0x3c5                     // #9650x0000000000d5d190:    msr    spsr_el2, x0//加载el2的中断向量表0x0000000000d5d194:    adrp    x0, 0xd4f0000x0000000000d5d198:    add    x0, x0, #0x00x0000000000d5d19c:    msr    vbar_el2, x00x0000000000d5d1a0:    isb/*    * Fruity CPUs seem to have HCR_EL2.E2H set to RES1,    * making it impossible to start in nVHE mode. Is that    * compliant with the architecture? Absolutely not!*/0x0000000000d5d1a4:    mrs    x0, hcr_el20x0000000000d5d1a8:    and    x0, x0, #0x400000000//跳转到1f(0xd5d1d0)位置继续执行0x0000000000d5d1ac:    cbz    x0, 0xd5d1d00x0000000000d5d1b0:    mov    x0, #0x30500000                // #8105492480x0000000000d5d1b4:    movk    x0, #0x8000x0000000000d5d1b8:    msr    sctlr_el12, x00x0000000000d5d1bc:    mov    x0, #0x3c9                     // #9690x0000000000d5d1c0:    msr    spsr_el1, x00x0000000000d5d1c4:    adr    x0, 0xd5d1e80x0000000000d5d1c8:    msr    elr_el1, x00x0000000000d5d1cc:    eret//将x0写入sctlr_el10x0000000000d5d1d0:    mov    x0, #0x30500000                // #8105492480x0000000000d5d1d4:    movk    x0, #0x8000x0000000000d5d1d8:    msr    sctlr_el1, x0//将当前的lr(x30)地址放到elr_el2中,后续eret到el1时,跳转到此地址执行0x0000000000d5d1dc:    msr    elr_el2, x30//将flag写入w0中0x0000000000d5d1e0:    mov    w0, #0xe12                     // #3602//注意这里的返回值,这里返回到elr_el2指向的地方,//也就是adrp    x23, __PHYS_OFFSET, 0x00000000011900080x0000000000d5d1e4:    eret0x0000000000d5d1e8:    mov    x0, #0x3                       // #30x0000000000d5d1ec:    hvc    #0x00x0000000000d5d1f0:    mov    x0, #0xe12                     // #36020x0000000000d5d1f4:    ret@ SYM_FUNC_END(init_kernel_el)@ SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)//加载__boot_cpu_mode符号地址,此地址存放0x0000000000d5d1f8:    adrp    x1, 0x17280000x0000000000d5d1fc:    add    x1, x1, #0x00x0000000000d5d200:    cmp    w0, #0xe120x0000000000d5d204:    b.ne    0xd5d20c  // b.any0x0000000000d5d208:    add    x1, x1, #0x40x0000000000d5d20c:    str    w0, [x1]0x0000000000d5d210:    dmb    sy0x0000000000d5d214:    dc    ivac, x1@ 返回到0x00000000011900140x0000000000d5d218:    ret@ SYM_FUNC_END(set_cpu_boot_mode_flag)

  这里包含3个步骤:

  1. 1. 这里其实包含了开启mmu,mmu开启时,tbbr0_el1是idmap_pg_dir,tbbr1_el1是init_pg_dir,还是使用的物理地址,所以这个时候的地址翻译由页表idmap_pg_dir来支持。
  2. 2. 当完成mmu开启后,就会将.rela.dyn段实现重定位,因为这部分的符号的实际地址为0,需要我们填写为实际的符号地址。
  3. 3. 当重定位完成后,会加载__primary_switched的虚拟地址,其地址在内核空间,当执行blr 跳转到__primary_switched的时候,这个时候的地址返回由页表init_pg_dir来支持。
@ SYM_FUNC_START(__enable_mmu)/*符合ARMv8的PE最大支持的物理地址宽度也是48个bit,当然,具体的实现可以自己定义(不能超过48个bit),具体的配置可以通过ID_AA64MMFR0_EL1 (AArch64 Memory Model Feature Register 0)这个RO寄存器获取*/0xd5d308        mrs    x2, id_aa64mmfr0_el1     @ 判断物理地址宽度是否满足最小和最大的要求。0xd5d30c        ubfx   x2, x2, #28#4                                        0xd5d310        cmp    x2, #0x0                                               0xd5d314        b.lt   0xd5d36c  // b.tstop                                   0xd5d318        cmp    x2, #0x7                                               0xd5d31c        b.gt   0xd5d36c     //update_early_cpu_boot_status0xd5d320        mov    x3, #0x0                        // #0                  0xd5d324        adrp   x2, 0x1728000                                          0xd5d328        add    x2, x2, #0x8                                           0xd5d32c        str    x3, [x2]                                               0xd5d330        dmb    sy                                                     0xd5d334        dc     ivac, x2   //加载idmap_pg_dir到ttbr0//注意,跳转过来时,x1是init_gdir0xd5d338        adrp   x2, 0x117e000                                          0xd5d33c        mov    x1, x1                                                 0xd5d340        mov    x2, x2           //加载两个映射表到tbbr0和1,在el1模式下面0xd5d344        msr    ttbr0_el1, x2                                          0xd5d348        msr    ttbr1_el1, x1                                          0xd5d34c        isb     //打开mmu0xd5d350        msr    sctlr_el1, x0                                          0xd5d354        isb                                                           0xd5d358        ic     iallu                                                  0xd5d35c        dsb    nsh                                                    0xd5d360        isb                                                           0xd5d364        ret  @ SYM_FUNC_END(__enable_mmu)//此部分作用为解决符号重定位问题//readelf -r vmlinux 读取重定位表//readelf -S vmlinux 读取所有section头//hexdump -s 0x24000 -n 16 vmlinux 读取重定位表中的第一项的目的地址内容,//       可以发现为8个0,需要我们来手动填写符号重定位地址@ SYM_FUNC_START_LOCAL(__relocate_kernel)0xd5d390        ldr    w9, 0xd5d438   // offset to reloc table                                                                                                                                    │0xd5d394        ldr    w10, 0xd5d43c  // size of reloc table  // default virtual offset                                                                                                                                  │0xd5d398        mov    x11, #0xffffffc0ffffffff        // #-270582939649                                                                                                  │0xd5d39c        movk   x11, #0x800, lsl #16                                                                                                                               │0xd5d3a0        movk   x11, #0x0     // actual virtual offset                                                                                                                                     │0xd5d3a4        add    x11, x11, x23   // x9保存了.rela.dyn区域的链接地址// x10保存了.rela.dyn区域的结束地址                                                                                                                                   │0xd5d3a8        add    x9, x9, x11                                                                                                                                        │0xd5d3ac        add    x10, x9, x10                                                                                                                                       │0xd5d3b0        cmp    x9, x10                                                                                                                                            │0xd5d3b4        b.cs   0xd5d3d4  // b.hs, b.nlast //获取一项offset和info+flag                                                                                                                        │0xd5d3b8        ldp    x12, x13, [x9], #24      //获取Addend值                                                                                                                          │0xd5d3bc        ldur   x14, [x9, #-8]                                                                                                                                     │0xd5d3c0        cmp    w13, #0x403                                                                                                                                        │0xd5d3c4        b.ne   0xd5d3b0  // b.any    //// relocate,这里主要是修正[offset + KASLR offset] = KASLR offset + append的值,也就是符号重定位了                                                                                                                             │0xd5d3c8        add    x14, x14, x23                                                                                                                                      │0xd5d3cc        str    x14, [x12, x23]                                                                                                                                    │0xd5d3d0        b      0xd5d3b0                                                                                                                                           │0xd5d3d4        ret    @ SYM_FUNC_END(__relocate_kernel)@ SYM_FUNC_START_LOCAL(__primary_switch)0xd5d3d8        mov    x19, x0         // preserve new SCTLR_EL1 value         0xd5d3dc        mrs    x20, sctlr_el1  // preserve old SCTLR_EL1 value         0xd5d3e0        adrp   x1, 0x181d000   // 将init_pg_dir 给x1  //跳转过去初始化mmu                                                            0xd5d3e4        bl     0xd5d308        //__enable_mmu        //将kernel image的.rela.dyn段实现重定位                  0xd5d3e8        bl     0xd5d390        //__relocate_kernel       //注意ldr指令加载的是__primary_switched的链接地址,//    注意这里的链接地址已经是虚拟地址了(例子值为:0xffffffc008f902a0)              0xd5d3ec        ldr    x8, 0xd5d448    //__primary_switched给x8                0xd5d3f0        adrp   x0, 0x200000    //__PHYS_OFFSET给x0   //注意这里的跳转指令,这个时候mmu已经生效了,由于目标地址为0xffffffc008f902a0,//      所以这个时候查询的页表为init_pg_dir                  0xd5d3f4        blr    x8  //跳转到__primary_switched                          0xd5d3f8        isb                                                           0xd5d3fc        msr    sctlr_el1, x20                                         0xd5d400        isb                                                           0xd5d404        bl     0x1190040                                              0xd5d408        tlbi   vmalle1                                                0xd5d40c        dsb    nsh                                                    0xd5d410        isb                                                           0xd5d414        msr    sctlr_el1, x19                                         0xd5d418        isb                                                           0xd5d41c        ic     iallu                                                  0xd5d420        dsb    nsh                                                    0xd5d424        isb                                                           0xd5d428        bl     0xd5d390                                               0xd5d42c        ldr    x8, 0xd5d448                                           0xd5d430        adrp   x0, 0x200000                                           0xd5d434        br     x8        @ SYM_FUNC_END(__primary_switch)

  这部分主要是在页表初始化好后,进行el1的一些cpu设置,并准备好mmu开启参数。

@     .pushsection ".idmap.text", "awx"@ SYM_FUNC_START(__cpu_setup)// Invalidate local TLB0x0000000000d5d6f4:    tlbi    vmalle10x0000000000d5d6f8:    dsb    nsh0x0000000000d5d6fc:    mov    x1, #0x300000                  // #3145728// Enable FP/ASIMD0x0000000000d5d700:    msr    cpacr_el1, x1// Reset mdscr_el1 and disable0x0000000000d5d704:    mov    x1, #0x1000                    // #4096// access to the DCC from EL00x0000000000d5d708:    msr    mdscr_el1, x1// Unmask debug exceptions now,0x0000000000d5d70c:    isb0x0000000000d5d710:    msr    daifclr, #0x80x0000000000d5d714:    mrs    x1, id_aa64dfr0_el10x0000000000d5d718:    sbfx    x1, x1, #8#40x0000000000d5d71c:    cmp    x1, #0x10x0000000000d5d720:    b.lt    0xd5d728  // b.tstop0x0000000000d5d724:    msr    pmuserenr_el0, xzr0x0000000000d5d728:    mrs    x1, id_aa64pfr0_el10x0000000000d5d72c:    ubfx    x1, x1, #44#40x0000000000d5d730:    cbz    x1, 0xd5d7380x0000000000d5d734:    msr    s3_3_c13_c2_3, xzr0x0000000000d5d738:    mov    x17, #0x400000000               // #171798691840x0000000000d5d73c:    movk    x17, #0x44, lsl #160x0000000000d5d740:    movk    x17, #0xffff0x0000000000d5d744:    mov    x16, #0x40000000000000          // #180143985094819840x0000000000d5d748:    movk    x16, #0x30, lsl #320x0000000000d5d74c:    movk    x16, #0xb559, lsl #160x0000000000d5d750:    movk    x16, #0x35190x0000000000d5d754:    mrs    x9, midr_el10x0000000000d5d758:    mov    x5, #0xffffffffffefffff        // #-10485770x0000000000d5d75c:    movk    x5, #0xffff0x0000000000d5d760:    and    x9, x9, x50x0000000000d5d764:    mov    x5, #0x460f0000                // #11753881600x0000000000d5d768:    movk    x5, #0x100x0000000000d5d76c:    cmp    x9, x50x0000000000d5d770:    b.ne    0xd5d788  // b.any0x0000000000d5d774:    mov    x5, #0x60000000000000          // #270215977642229760x0000000000d5d778:    movk    x5, #0x0, lsl #320x0000000000d5d77c:    movk    x5, #0x0, lsl #160x0000000000d5d780:    movk    x5, #0x00x0000000000d5d784:    bic    x16, x16, x50x0000000000d5d788:    adrp    x9, 0x15550000x0000000000d5d78c:    ldr    x9, [x9, #3272]0x0000000000d5d790:    bfxil    x16, x9, #0#60x0000000000d5d794:    mrs    x5, id_aa64mmfr0_el10x0000000000d5d798:    ubfx    x5, x5, #0#30x0000000000d5d79c:    mov    x6, #0x5                       // #50x0000000000d5d7a0:    cmp    x5, x60x0000000000d5d7a4:    csel    x5, x6, x5, hi  // hi = pmore0x0000000000d5d7a8:    bfi    x16, x5, #32#30x0000000000d5d7ac:    mrs    x9, id_aa64mmfr1_el10x0000000000d5d7b0:    and    x9, x9, #0xf0x0000000000d5d7b4:    cbz    x9, 0xd5d7bc0x0000000000d5d7b8:    orr    x16, x16, #0x80000000000x0000000000d5d7bc:    msr    mair_el1, x170x0000000000d5d7c0:    msr    tcr_el1, x16/*  * Prepare SCTLR, INIT_SCTLR_EL1_MMU_ON 给 x0  */0x0000000000d5d7c4:    mov    x0, #0x200000000000000         // #1441151880758558720x0000000000d5d7c8:    movk    x0, #0x20, lsl #320x0000000000d5d7cc:    movk    x0, #0x34f4, lsl #160x0000000000d5d7d0:    movk    x0, #0xd91d// return to head.S0x0000000000d5d7d4:    ret0x0000000000d5d7d8:    msr    tpidr_el2, x130x0000000000d5d7dc:    msr    disr_el1, xzr@ SYM_FUNC_END(__cpu_setup)

  当我们进入__primary_switched的时候,这个时候用的是内核地址。同时地址翻译是由init_pg_dir来完成。此过程初始化init_task,将

@ SYM_FUNC_START_LOCAL(__primary_switched)//将init_task给x40xffffffc008f902a0      adrp   x4, 0xffffffc00934f000 <inet6_offloads+1376>                        0xffffffc008f902a4      add    x4, x4, #0xb80   //init_cpu_task                                                   0xffffffc008f902a8      msr    sp_el0, x4                                                          0xffffffc008f902ac      ldr    x5, [x4, #24]                                                       0xffffffc008f902b0      add    sp, x5, #0x4, lsl #12                                               0xffffffc008f902b4      sub    sp, sp, #0x150                                                      0xffffffc008f902b8      stp    xzr, xzr, [sp, #304]                                                0xffffffc008f902bc      add    x29, sp, #0x130                                                     0xffffffc008f902c0      adrp   x5, 0xffffffc009349000 <event_hash+616>                             0xffffffc008f902c4      add    x5, x5, #0x7f8                                                      0xffffffc008f902c8      ldr    w6, [x4, #64]                                                       0xffffffc008f902cc      ldr    x5, [x5, x6, lsl #3]                                                0xffffffc008f902d0      msr    tpidr_el1, x5          //加载异常向量表地址                                                                             0xffffffc008f902d4      adrp   x8, 0xffffffc008010000 <bcm2835_handle_irq>                         0xffffffc008f902d8      add    x8, x8, #0x800                                                      0xffffffc008f902dc      msr    vbar_el1, x8                                                        0xffffffc008f902e0      isb //将x29,x30放入到sp0xffffffc008f902e4      stp    x29, x30, [sp, #-16]!                                               0xffffffc008f902e8      mov    x29, sp  // Save FDT pointer                                                                                                        0xffffffc008f902ec      adrp   x5, 0xffffffc009001000 <tmp_cmdline.73085+2040>                     0xffffffc008f902f0      str    x21, [x5, #920]                      // Save the offset between                                                                              0xffffffc008f902f4      adrp   x4, 0xffffffc008b70000 <kimage_vaddr>                                                                              0xffffffc008f902f8      ldr    x4, [x4]       // the kernel virtual and                                                                                                    0xffffffc008f902fc      sub    x4, x4, x0                                    // physical mappings                                                                     0xffffffc008f90300      adrp   x5, 0xffffffc008ebb000 <rt_sched_class+192>                                                                        0xffffffc008f90304      str    x4, [x5, #3392]       //Clear BSS                                                                                             0xffffffc008f90308      adrp   x0, 0xffffffc009529000 <__kvm_nvhe_cur>                                                                            0xffffffc008f9030c      add    x0, x0, #0x0                                                                                                       0xffffffc008f90310      mov    x1, xzr                                                                                                            0xffffffc008f90314      adrp   x2, 0xffffffc00961c000 <gssp_stats+24>                                                                             0xffffffc008f90318      add    x2, x2, #0xf8                                                                                                      0xffffffc008f9031c      sub    x2, x2, x0                                                                                                         0xffffffc008f90320      bl     0xffffffc008664200 <memset>                                                                                        0xffffffc008f90324      dsb    ishst    // pass FDT address in x0                                                                                                          0xffffffc008f90328      mov    x0, x21    // Try mapping the FDT early                                                                                                        0xffffffc008f9032c      bl     0xffffffc008f946c8 <early_fdt_map>    // Parse cpu feature overrides                                                                    0xffffffc008f90330      bl     0xffffffc008f96354 <init_feature_override>    //already running randomized?                                                                     0xffffffc008f90334      tst    x23, #0xffffffffffe00000                                                                                           0xffffffc008f90338      b.ne   0xffffffc008f90350 <__primary_switched+176>  // b.any// parse FDT for KASLR options                                                              0xffffffc008f9033c      bl     0xffffffc008f96b80 <kaslr_early_init>  // KASLR disabled? just proceed          这里直接跳转到 0xffffffc008f90350                                                              0xffffffc008f90340      cbz    x0, 0xffffffc008f90350 <__primary_switched+176>  // record KASLR offset                                                                  0xffffffc008f90344      orr    x23, x23, x0  // we must enable KASLR, return                                                                                                     0xffffffc008f90348      ldp    x29, x30, [sp], #16      // to __primary_switch()                                                                                         0xffffffc008f9034c      ret  // Prefer VHE if possible0xffffffc008f90350      bl     0xffffffc008021e6c <switch_to_vhe>                                                                                 0xffffffc008f90354      ldp    x29, x30, [sp], #16                  //跳转到kernel_start                                                                              0xffffffc008f90358      bl     0xffffffc008f90c40 <start_kernel>                                                                                  0xffffffc008f9035c      brk    #0x800                                                                                                             0xffffffc008f90360      msr    tpidr_el2, x5  @ SYM_FUNC_END(__primary_switched)

  注意,阅读本文这部分时,需要对照着head.S来看,这样才有一个基本的认识。

后记


  本文得到的基本流程为,上电,保存上电后的基础寄存器,在el2的模式下初始化cpu,保存启动标志,初始化两个页表(注意,这部分是精华,我这部分注释也最多),然后初始化el1模式下的cpu,并准备好开启mmu,最后在__primary_switch里面开启mmu,当mmu开启后,这个时候的地址还是物理地址,所以我们需要一个映射物理地址和虚拟地址相等的页表(idmap_pg_dir),重定位符号表,最后加载__primary_switched的虚拟地址(其虚拟地址在kernel logical memory map中),跳转到执行(此时查表init_pg_dir),然后初始化init_task,最后进入start_kernel。

  本文也没有尝试去完全注释每句代码,太繁杂了,对于我来说也没有意义,特别是一些特别的初始化,只有以后遇到了才去查询。Linux现代内核太大了,后面可能就要去看个人喜欢的模块,这样才有收获,不要尝试去阅读全部内容,那样太难了。

  每个人对于这部分的关注可能都是不一样的,如果本文没有写的地方,可以尝试搜索对应的关键字,可以得到更多的信息。

参考文献

[1]https://blog.csdn.net/u011728480/article/details/79498816[2]https://blog.csdn.net/u011728480/article/details/88420467[3]https://blog.csdn.net/u011728480/article/details/88553602[4]https://blog.csdn.net/u011728480/article/details/114491022[5]https://developer.arm.com/documentation/100933/0100[6]https://www.kernel.org/doc/html/latest/arm64/memory.html
打赏、订阅、收藏、丢香蕉、硬币,请关注公众号

PS: 请尊重原创,不喜勿喷。PS: 要转载请注明出处,本人版权所有。PS: 有问题请留言,看到后我会第一时间回复。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-09 17:10:01 HTTP/2.0 GET : https://f.mffb.com.cn/a/474481.html
  2. 运行时间 : 0.233014s [ 吞吐率:4.29req/s ] 内存消耗:5,083.58kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=3bd64a3fea7ac7432fdd9ba9c17186f6
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000956s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001367s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.010508s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.001328s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001378s ]
  6. SELECT * FROM `set` [ RunTime:0.001181s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001475s ]
  8. SELECT * FROM `article` WHERE `id` = 474481 LIMIT 1 [ RunTime:0.014236s ]
  9. UPDATE `article` SET `lasttime` = 1770628201 WHERE `id` = 474481 [ RunTime:0.008369s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.003597s ]
  11. SELECT * FROM `article` WHERE `id` < 474481 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.029535s ]
  12. SELECT * FROM `article` WHERE `id` > 474481 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.005739s ]
  13. SELECT * FROM `article` WHERE `id` < 474481 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.017309s ]
  14. SELECT * FROM `article` WHERE `id` < 474481 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.018261s ]
  15. SELECT * FROM `article` WHERE `id` < 474481 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.004944s ]
0.236419s