解壓內核鏡像

来源:https://www.cnblogs.com/jiau/archive/2020/05/09/12860249.html
-Advertisement-
Play Games

步驟 0 uboot 將 zImage 複製到記憶體之後,跳轉到 zImage 處開始執行,首先執行的代碼是 arch/arm/boot/compressed/head.S 文件,首先是一些涉及不同體繫結構調試相關的彙編巨集定義 ifdef DEBUG if defined(CONFIG_DEBUG_I ...


步驟 0

uboot 將 zImage 複製到記憶體之後,跳轉到 zImage 處開始執行,首先執行的代碼是
arch/arm/boot/compressed/head.S 文件,首先是一些涉及不同體繫結構調試相關的彙編巨集定義

#ifdef DEBUG
#if defined(CONFIG_DEBUG_ICEDCC)
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7)
        .macro  loadsp, rb, tmp
        .endm
        .macro  writeb, ch, rb
        mcr p14, 0, \ch, c0, c5, 0
        .endm
... 省略 ...
#endif
#endif
#endif

步驟 1

首先是保存 bootloader 傳遞過來的機器 ID 和 atags 起始地址

        @ 設置段名
        .section ".start"#alloc, #execinstr
        .align
        .arm                @ 設置指令為 arm 模式
start:
        .type   start,#function @ 聲明為函數標簽
        .rept   7
        mov r0, r0
        .endr
   ARM(        mov r0, r0      )
   ARM(        b   1f      )   @ 向下跳轉
 THUMB(        adr r12, BSYM(1f)   )
 THUMB(        bx  r12     )

        .word   0x016f2818  @ Magic numbers to help the loader
        .word   start       @ 程式其實地址,即 zImage 的地址
        .word   _edata      @ zImage 結束地址
 THUMB(        .thumb          )
1:      mov   r7, r1        @ 保存 bootloader 傳遞過來的機器 ID
        mov r8, r2          @ 保存 bootloader 傳遞過來的 atags 起始地址

步驟 2

關閉中斷、進入 SVC 模式

#ifndef __ARM_ARCH_2__
        mrs r2, cpsr        @ get current mode
        tst r2, #3          @ not user?
        bne not_angel
        mov r0, #0x17       @ 進入 SVC 模式
 ARM(        swi 0x123456    )   @ angel_SWI_ARM
 THUMB(        svc 0xab        )   @ angel_SWI_THUMB
not_angel:
        mrs r2, cpsr
        orr r2, r2, #0xc0   @ 關閉 FIQ 和 IRQ
        msr cpsr_c, r2
#else
        teqp    pc, #0x0c000003     @ turn off interrupts

步驟 3

為了加速解壓過程,打開緩存

#ifdef CONFIG_AUTO_ZRELADDR
        @ 如果配置了運行時自動計算重定位地址
        @ 則根據當前 pc 位置和 TEXT_OFFSET 計算出解壓位置
        @ TEXT_OFFSET 在 arch/arm/Makefile 中指定,表示的是相對於記憶體起始地址的偏移
        @ 定義為 textofs-y := 0x00008000   TEXT_OFFSET := $(textofs-y)
        mov r4, pc
        and r4, r4, #0xf8000000     @ 這裡假設 zImage 是被放在記憶體的前 128MB 內的
        add r4, r4, #TEXT_OFFSET    @ 得到 zImage 解壓的物理地址
#else
        @ 這裡是直接在 arch/arm/mach-s5p4418/Makefile.boot 中定義的
        @ 定義為 zreladdr-y    := 0x40008000
        ldr r4, =zreladdr @ r4 存放解壓後內核存放的起始地址
#endif
        @ 打開緩存和 MMU
        bl  cache_on

步驟 4

檢查解壓後的內核鏡像是否與當前鏡像發生覆蓋

restart:    adr r0, LC0
        ldmia   r0, {r1, r2, r3, r6, r10, r11, r12} @ 將 LC0 數據放入寄存器中
        ldr sp, [r0, #28] @ 更新棧指針位置

        sub r0, r0, r1      @ 計算當前程式位置和鏈接地址間的偏移量
        add r6, r6, r0      @ 得到 zImage 運行地址的結束位置
        add r10, r10, r0    @ 存放未壓縮內核大小的運行地址

        /*
         * 內核編譯系統會將未壓縮的內核大小追加到壓縮後的內核數據之後
         * 並以小端格式存儲
         */

        @ 取出未壓縮內核大小放入 r9
        ldrb    r9, [r10, #0]
        ldrb    lr, [r10, #1]
        orr r9, r9, lr, lsl #8
        ldrb    lr, [r10, #2]
        ldrb    r10, [r10, #3]
        orr r9, r9, lr, lsl #16
        orr r9, r9, r10, lsl #24

#ifndef CONFIG_ZBOOT_ROM
        /* 在棧指針之上分配記憶體空間放到 r10 中 (64k max) */
        add sp, sp, r0
        add r10, sp, #0x10000
#else
        mov r10, r6
#endif
        mov r5, #0          @ init dtb size to 0
        /*
         * 檢查解壓後的內核是否會覆蓋當前代碼
         *   r4  = 最終解壓後的內核起始地址
         *   r9  = 解壓後的內核鏡像大小
         *   r10 = 當前鏡像結束地址,其中包括所分配的記憶體區域
         * We basically want:
         *   r4 - 16k 頁表 >= r10 -> OK
         *   r4 + image length <= address of wont_overwrite -> OK
         */

        add r10, r10, #16384 @ 內核鏡像前的 16KB 頁表
        cmp r4, r10
        bhs wont_overwrite @ 解壓後的內核起始地址大於等於 r10
        add r10, r4, r9
        adr r9, wont_overwrite
        cmp r10, r9        @ 或者解壓後的內核結束地址在 wont_overwrite 地址之前
        bls wont_overwrite
        /*
         *   r6  = _edata
         *   r10 = end of the decompressed kernel
         */

        @ 當前代碼段向後移動到的目的地址,不足 256 位元組的補足 256 位元組,向上取整
        add r10, r10, #((reloc_code_end - restart + 256) & ~255)
        bic r10, r10, #255

        @ 當前代碼段起始地址,以 32 位元組為單位,向下取整
        adr r5, restart
        bic r5, r5, #31

        sub r9, r6, r5      @ 需要移動鏡像的大小
        add r9, r9, #31     @ 以 32 位元組為單位向上取整
        bic r9, r9, #31
        add r6, r9, r5      @ 迴圈結束地址
        add r9, r9, r10     @ 目的地址結束位置
        @ 迴圈移動當前鏡像
1:        ldmdb   r6!, {r0 - r3, r10 - r12, lr}
        cmp r6, r5
        stmdb   r9!, {r0 - r3, r10 - r12, lr}
        bhi 1b

        sub r6, r9, r6 @ 代碼重定位的偏移地址

#ifndef CONFIG_ZBOOT_ROM
        add sp, sp, r6 @ 對棧指針也進行重定位
#endif

        bl  cache_clean_flush
        @ 跳轉到重定位後的鏡像 restart 處重新執行,檢查是否存在覆蓋
        adr r0, BSYM(restart)
        add r0, r0, r6
        mov pc, r0

步驟 5

清理 bss 段、解壓內核、關閉緩存,最後啟動內核

/* 至此,當前鏡像和解壓後的內核不會發生覆蓋問題 */
wont_overwrite:
/*
 * If delta is zero, we are running at the address we were linked at.
 *   r0  = delta
 *   r2  = BSS start
 *   r3  = BSS end
 *   r4  = kernel execution address
 *   r5  = appended dtb size (0 if not present)
 *   r7  = architecture ID
 *   r8  = atags pointer
 *   r11 = GOT start
 *   r12 = GOT end
 *   sp  = stack pointer
 */

        orrs    r1, r0, r5
        beq not_relocated

        add r11, r11, r0
        add r12, r12, r0

not_relocated:    mov r0, #0
1:        str r0, [r2], #4        @ 清理 bss 段
        str r0, [r2], #4
        str r0, [r2], #4
        str r0, [r2], #4
        cmp r2, r3
        blo 1b

/*
 *   至此,C 語言運行環境已經初始化完成
 *   r4  = 解壓後的內核起始地址
 *   r7  = 機器 ID
 *   r8  = atags 指針
 */

        mov r0, r4
        mov r1, sp              @ 在棧指針之上分配記憶體空間
        add r2, sp, #0x10000    @ 64k max
        mov r3, r7
        bl  decompress_kernel   @ 解壓內核
        bl  cache_clean_flush
        bl  cache_off           @ 關閉緩存
        mov r0, #0          @ must be zero
        mov r1, r7          @ restore architecture number
        mov r2, r8          @ restore atags pointer
 ARM(        mov pc, r4  )     @ 啟動內核
 THUMB(        bx  r4  )       @ entry point is always ARM

        .align  2
        .type   LC0, #object
LC0:        .word   LC0         @ r1:LC0 的鏈接地址
        .word   __bss_start     @ r2:bss 段的起始地址
        .word   _end            @ r3:bss 段的結束地址
        .word   _edata          @ r6:zImage 的結束地址
        .word   input_data_end - 4  @ r10:存放未壓縮的內核大小的鏈接地址
        .word   _got_start      @ r11:全局偏移表起始位置
        .word   _got_end        @ ip:全局偏移表結束位置
        .word   .L_user_stack_end   @ sp:棧指針
        .size   LC0, . - LC0    @ 該 LC0 數據的大小

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • out的使用 ————————————————————————————————————————————————— class Program { static void Main(string[] args) { string tmp; //先聲明,但不初始化 User _user=new User ...
  • 由於微軟的一些迷之bug,像click事件一樣直接在事件中生成的方法無法觸發,包括MouseLeftButtonDown等,必須採取手動方法: 1.新建路由事件: private void bt_MouseDown(object sender, RoutedEventArgs e) { //bili ...
  • 通過閱讀 WPF 官方開源倉庫的代碼和文檔,可以瞭解到在進行獨立發佈的時候會在倉庫裡面帶上 vcruntime140 的原因 ...
  • 使用阿裡雲ECS或者其他常見的VPS服務部署應用的時候,需要手動配置環境,並且監測ECS的行為,做補丁之類的,搞得有點複雜。好在很多雲廠商(阿裡雲、Azure等)提供了Serverless服務,藉助於Serverless,開發人員可以更加專註於代碼的開發,減少運維的成本。 Azure的部署直接集成在 ...
  • tune2fs命令允許系統管理員在Linux ext2、ext3或ext4文件系統上調整、設置、查看文件系統參數。tune2fs -l 只會顯示 superblock 上的內容。有時候使用tune2fs命令遇到類似“Couldn't find valid filesystem superblock”... ...
  • 1,目標及展示 首先希望實現文字、圖片、控制項等在觸發後,呈現飄散並消失的效果。在QT常式《Qt Quick Particles Examples》是一個海星點擊滑鼠後呈現打散的效果,這個效果和最終需要的略有不同,所以我們在它的基礎上再加上我需要的一些元素,最終實現如下效果。 圖1(gif) 圖6 2 ...
  • 做為一個過來人,我談談我自己的看法,歡迎大家補充: 首先肯定的一點是:不要一上來就看內核代碼,基本上你會很快被挫敗感打敗。內核正在變得越來越龐大,學習曲線越來越陡峭,當你一無所知的時候冒然進入linux kernel,你會發現處處都是障礙,處處都是大坑,你根本走不下去。最好的方法是把對內核源代碼的熱 ...
  • Linux有非常多的版本,比如世面上常見的有 Ubuntu、RedHat、Fedora、Centos等等,這麼多的版本我們究竟該選哪一個呢?今天我帶大家對各個版本進行一下分析和比較,幫助大家來做出更好的選擇。 (一)Linux 是什麼? 首先瞭解一下Linux是什麼。它是一套類UNIX的操作系統,最 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...