Sam Huang
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Linux Project1:實作回傳 Physical Address 的 System Call ================================================== ## 一、專案簡介(Project Overview) - **專案目標** - 在 Linux kernel 5.15.135 中新增一個系統呼叫:`void * my_get_physical_addresses(void *vaddr)` - 讓 user-space 程式可以查詢「某個虛擬位址目前是否對應到實體位址」,並觀察: - **Copy-on-Write (CoW)**:父子行程在 `fork()` 之後,對同一個 global 變數的實體位址變化。 - **Lazy allocation / Demand paging**:大型 global array 在尚未實際使用時,是否已經配置實體記憶體。 - **系統呼叫回傳值** - `0`:目前沒有實體位址被指派(page 尚未被配置或尚未建立 PTE)。 - 非 0:對應的實體位址(實際上是實體位址的 offset)。 - **小組成員** - 114552005 黃致霖 - 114552006 丁偉哲 - 114552036 許宗元 --- ## 二、實驗環境與前置準備 ### 2.1 環境與版本 - **作業系統**:Ubuntu Desktop 22.04(https://releases.ubuntu.com/jammy/) - **VM Machine 系統資源** : CPU 12 cores / Memory 8GB / Disk 60GB **(VM Workstation)** - **CPU 架構**:x86_64(對應 `syscall_64.tbl` 與五層 page table) - **Kernel 原始碼版本**:`linux-5.15.135` ### 2.2 安裝編譯工具 在 Ubuntu 上先安裝編譯 kernel 所需套件: ```bash sudo apt update sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev dwarves -y ``` ### 2.3 下載並解壓 Linux 5.15.135 Kernel Source Code ```bash # 當前路徑為使用者 home 目錄 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.135.tar.xz tar -xvf linux-5.15.135.tar.xz ``` ![下載解壓縮](https://hackmd.io/_uploads/HkxeKzvZbx.png) ![下載解壓縮2](https://hackmd.io/_uploads/SyeltfD-Wg.png) --- ## 三、新增系統呼叫 `my_get_physical_addresses` > 我們把所有和 system call 相關的程式放在 mycall/ 資料夾中。 > 主要檔案:`mycall/my_get_physical_addresses.c` ### 3.1 建立自訂目錄與檔案 進入 kernel Source code 目錄內並建立資料夾: ```bash cd ~/linux-5.15.135 mkdir mycall ``` 在 `mycall` 底下建立 `my_get_physical_addresses.c`: ```bash nano mycall/my_get_physical_addresses.c ``` 核心實作程式碼(摘要)如下: ``` #include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/mm.h> #include <linux/sched.h> #include <asm/page.h> #include <asm/pgtable.h> SYSCALL_DEFINE1(my_get_physical_addresses, void *, vaddr_ptr) { unsigned long vaddr = (unsigned long) vaddr_ptr; pgd_t *pgd; p4d_t *p4d; pud_t *pud; pmd_t *pmd; pte_t *pte; unsigned long paddr = 0; unsigned long page_addr = 0; unsigned long page_offset = 0; struct mm_struct *mm = current->mm; pgd = pgd_offset(mm, vaddr); if (pgd_none(*pgd) || pgd_bad(*pgd)) return 0; p4d = p4d_offset(pgd, vaddr); if (p4d_none(*p4d) || p4d_bad(*p4d)) return 0; pud = pud_offset(p4d, vaddr); if (pud_none(*pud) || pud_bad(*pud)) return 0; pmd = pmd_offset(pud, vaddr); if (pmd_none(*pmd) || pmd_bad(*pmd)) return 0; pte = pte_offset_map(pmd, vaddr); if (!pte) return 0; if (pte_none(*pte)) { pte_unmap(pte); return 0; } page_addr = (pte_val(*pte) & PTE_PFN_MASK); page_offset = vaddr & ~PAGE_MASK; paddr = page_addr | page_offset; pte_unmap(pte); return paddr; } ``` ### 3.2 實作邏輯說明(五層 page table 走訪) - **輸入**:一個 user space 的虛擬位址 `vaddr_ptr`。 - **步驟**: - 取得目前行程的 `mm_struct`:`current->mm`。 - 依序走訪五層 page table:`PGD → P4D → PUD → PMD → PTE`。 - 每一層若是 `none` 或 `bad`,代表該範圍尚未配置,直接回傳 `0`。 - 在 PTE 層取得 `pte_val(*pte)`,用 `PTE_PFN_MASK` 抽出 Page Frame Number(PFN),再加上虛擬位址在該頁中的 offset,組合成完整的 physical address。 - 完成後呼叫 `pte_unmap(pte)` 解除對 PTE 的暫時映射。 > 這個 system call 的核心工作,就是把 CPU 的「page-table walk」流程用 C 程式碼顯式實作出來,方便 user space 直接查詢實體位址。 ### 3.3 建立 `mycall/Makefile` 在 `mycall` 建立 Makefile: ```bash nano mycall/Makefile ``` 內容: ``` obj-y := my_get_physical_addresses.o ``` 代表在建構核心時,會把 `my_get_physical_addresses.o` 編進 vmlinux。 ### 3.4 修改頂層 `Makefile` 以加入新目錄 在 ~/Linux-5.15.135 目錄的 `Makefile` 中找到: ```text core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ ``` ![image](https://hackmd.io/_uploads/SJNJ2LY-bl.png) 修改為: ```text core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ mycall/ ``` ![image](https://hackmd.io/_uploads/B1N4nLFWZx.png) ### 3.5 註冊系統呼叫(syscall_64.tbl) 系統呼叫表路徑: `~/linux-5.15.135/arch/x86/entry/syscalls/syscall_64.tbl` 在適當位置(例如靠近其他自訂 syscall 的地方)新增一行: ```text 449 common my_get_physical_addresses sys_my_get_physical_addresses ``` > 實際內容請依目前檔案狀況為準,重點是: > - 號碼:`449`(對應 user space 的 `#define SYS_MY_GET_PHYS 449`) > - 名稱:`my_get_physical_addresses` > - 對應 kernel 端符號:`sys_my_get_physical_addresses` ![image](https://hackmd.io/_uploads/SkTn6UFWZl.png) ### 3.6 (可選)在 `~/include/linux/syscalls.h` 宣告 對於使用 `SYSCALL_DEFINE` 宏的版本,kernel 會自動產生對應宣告,一般來說不一定需要手動在 `syscalls.h` 加 prototype。 若要手動宣告,可在檔案結尾的 `#endif` 前加入: ```c asmlinkage long sys_my_get_physical_addresses(void *usr_ptr); ``` ![擷取2](https://hackmd.io/_uploads/SkwuAKwWWx.png) --- ## 四、Kernel 編譯與安裝流程 ### 4.1 載入並調整 Kernel 設定 ```bash cp /boot/config-$(uname -r) .config make menuconfig # 出現藍底 GUI 選單選取 Exit > Yes ``` ![image](https://hackmd.io/_uploads/BkFJWvtWZx.png) ![image](https://hackmd.io/_uploads/H1qq-vYWZg.png) ### 4.2 編譯 Kernel 在 kernel 根目錄執行: ```bash make -j$(nproc) ``` - `-j$(nproc)`:根據 CPU 核心數平行編譯,加快速度。 make 編譯過程與最後 Kernel ready 的畫面 ![編譯完成](https://hackmd.io/_uploads/HynJ-cvbbx.png) 可透過以下指令查看檔案是否產生,若無則編譯失敗。 ``` ls arch/x86/boot/bzImage ``` ### 4.3 Trouble Shooting 憑證相關錯誤的處理(若有) 如果在編譯過程遇到與憑證相關的錯誤(例如找不到 Debian 官方的簽章憑證) ![憑證錯誤問題](https://hackmd.io/_uploads/SJJibXDbZl.png) 可以採用以下流程: 1. 清理舊的編譯成果與設定 ```bash make mrproper ``` 2. 重新產生組態檔: ```bash make menuconfig ``` 3.使用 `scripts/config` 關閉憑證相關設定: ```bash scripts/config --disable SYSTEM_TRUSTED_KEYS scripts/config --disable SYSTEM_REVOCATION_KEYS scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEYS "" scripts/config --set-str CONFIG_SYSTEM_REVOCATION_KEYS "" ``` 4. 再次執行: ```bash make -j$(nproc) ``` ### 4.4 安裝 Kernel 並更新開機項目 ```bash sudo make modules_install sudo make install sudo update-grub ``` 接著重新開機: ```bash sudo reboot ``` 開機時按 `Shift` 或 `Esc`(或 F4,依 VM 設定)進入 GRUB 選單,選擇: - **Advanced options for Ubuntu** ![GRUB](https://hackmd.io/_uploads/r13PWqwbWl.png) - 再選擇剛安裝好的 `5.15.135` 核心版本。 ![GRUB2](https://hackmd.io/_uploads/HJDOW5v-Zl.png) 開機後用以下指令確認版本: ```bash uname -a ``` ![uname](https://hackmd.io/_uploads/HkOxGcwZZl.png) --- ## 五、User-space 測試程式設計 我們撰寫了兩個主要的測試程式,用來驗證 `my_get_physical_addresses` 的功能,並觀察: - **Question 1:Copy-on-Write 行為(test_cow)** - **Question 2:Lazy allocation / loader 行為(test_lazy)** ### 5.1 共用的 syscall wrapper 在兩個測試檔中,我們都使用相同的 wrapper 來呼叫 system call: ```startLine:endLine:Documents/workspace/Assigment1/tests/test_cow.c #define SYS_MY_GET_PHYS 449 unsigned long my_get_physical_addresses(void *vaddr) { return syscall(SYS_MY_GET_PHYS, vaddr); } ``` --- ## 六、Question 1:Copy-on-Write 測試(test_cow) ### 6.1 程式碼重點 測試檔路徑:`tests/test_cow.c` ```startLine:endLine:Documents/workspace/Assigment1/tests/test_cow.c #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> #define SYS_MY_GET_PHYS 449 unsigned long my_get_physical_addresses(void *vaddr) { return syscall(SYS_MY_GET_PHYS, vaddr); } int global_a = 123; int main() { unsigned long parent_use, child_use; printf("====== Before Fork ======\n"); parent_use = my_get_physical_addresses(&global_a); printf("Original Physical: %lx\n", parent_use); if (fork() == 0) { // Child process printf("=== Child Process Created ===\n"); child_use = my_get_physical_addresses(&global_a); printf("Child (Before Write) Physical: %lx\n", child_use); printf("=== Triggering COW (Writing to variable) ===\n"); global_a = 789; // 寫入變數,觸發 Copy-on-Write child_use = my_get_physical_addresses(&global_a); printf("Child (After Write) Physical: %lx\n", child_use); } else { wait(NULL); } return 0; } ``` ### 6.2 測試步驟與預期行為 1. **Fork 之前**: - 呼叫 `my_get_physical_addresses(&global_a)`,得到一個實體位址 `X`。 2. **Child 剛建立時(尚未寫入)**: - 在 child 中再查一次 `&global_a`,預期得到同一個實體位址 `X`,說明 parent/child 仍共用同一個 physical page。 3. **Child 寫入 `global_a = 789` 後**: - 再查 `&global_a`,預期得到另一個實體位址 `Y`,代表觸發 Copy-on-Write,child 取得新的實體頁。 ### 6.3 實際輸出示意與說明 (以下為示意格式,實際數值依執行結果為準) ```text ====== Before Fork ====== Original Physical: 2ca2c6010 === Child Process Created === Child (Before Write) Physical: 2ca2c6010 === Triggering COW (Writing to variable) === Child (After Write) Physical: 3661df010 ``` - `Original Physical` 與 `Child (Before Write)` 相同:說明 parent/child 共用同一個 physical page。 - `Child (After Write)` 不同:代表 child 寫入引發 page fault,kernel 為 child 建立新的實體 page(Copy-on-Write)。 ![test_cow 執行結果](https://hackmd.io/_uploads/Sy18rit-Zl.png) --- ## 七、Question 2:Lazy allocation 測試(test_lazy) ### 7.1 程式碼重點 測試檔路徑:`tests/test_lazy.c` ```startLine:endLine:Documents/workspace/Assigment1/tests/test_lazy.c #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #define SYS_MY_GET_PHYS 451 unsigned long my_get_physical_addresses(void *vaddr) { return syscall(SYS_MY_GET_PHYS, vaddr); } int a[2900000]; // 宣告超大陣列 int main() { unsigned long phy_add; printf("Checking a[0]...\n"); phy_add = my_get_physical_addresses(&a[0]); printf("Physical address of a[0]: %lx\n", phy_add); printf("Checking a[1999999]...\n"); phy_add = my_get_physical_addresses(&a[1999999]); printf("Physical address of a[1999999]: %lx\n", phy_add); printf("Writing to a[0]...\n"); a[0] = 1; phy_add = my_get_physical_addresses(&a[0]); printf("Physical address of a[0] (After Write): %lx\n", phy_add); return 0; } ``` ### 7.2 測試步驟與預期行為 1. 宣告一個很大的 global array:`int a[2900000];`,讓 kernel 需要為 .bss/.data 區預留大範圍虛擬位址。 2. 程式啟動後,什麼都還沒實際讀寫,只呼叫 system call 查詢: - `&a[0]` 的實體位址。 - `&a[1999999]` 的實體位址。 3. 預期觀察結果: - `a[0]`:可能已經有實體位址(或很快被 touch),回傳值多半為非 0。 - `a[1999999]`:在尚未真正讀寫時,很可能尚未分配實體頁,system call 會在 `pte_none(*pte)` 的地方回傳 `0`。 4. 之後寫入 `a[0] = 1;`,再查一次 `&a[0]`: - 預期 physical address 前後一致,說明這一頁本來就有 mapping 或在第一次查詢後就穩定存在。 ### 7.3 實際輸出示意與說明 (以下為示意格式,實際數值依執行結果為準) ```text Checking a[0]... Physical address of a[0]: 2ab228040 Checking a[1999999]... Physical address of a[1999999]: 0 Writing to a[0]... Physical address of a[0] (After Write): 2ab228040 ``` - `a[0]` 有實體位址:代表 array 前面的頁面已經配置或被存取。 - `a[1999999]` 回傳 0:代表對應的虛擬頁目前尚未有 PTE / 實體頁,符合 **lazy allocation / demand paging** 的行為。 - 對 `a[0]` 寫入後再查一次,位址不變:證明這一頁在寫入前後都是同一個 physical page。 ![test_lazy 執行結果](https://hackmd.io/_uploads/ryruBitZWl.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully