最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux內(nèi)核啟動流程詳解(基于 5.15.119 源碼)

 更新時間:2026年05月18日 08:30:56   作者:magic_now  
文章詳細介紹了基于Linux 5.15.119源碼的x86_64架構(gòu)內(nèi)核啟動流程,從GRUB加載bzImage到壓縮內(nèi)核解壓、初始化硬件、切換到保護模式、64位解壓入口,直至啟動第一個用戶進程/sbin/init的全過程,需要的朋友可以參考下

本文基于 Linux 5.15.119 實際源碼,從 GRUB 加載到第一個用戶進程 /sbin/init 啟動,完整梳理 x86_64 架構(gòu)的內(nèi)核啟動流程。

0. bzImage 的物理結(jié)構(gòu)

你執(zhí)行 make bzImage 編譯出來的文件,其實不是單一文件,而是兩部分拼接而成:

┌─────────────────┬─────────────────────────────┐
│   setup.bin     │    compressed/vmlinux       │
│  (實模式代碼)    │   (壓縮的真正的內(nèi)核)         │
│   ~30KB         │      幾MB ~ 幾十MB           │
└─────────────────┴─────────────────────────────┘
        ↑                              ↑
   從 bootsect 開始              從 startup_32 開始

Bootloader(GRUB)把它加載到內(nèi)存后,CPU 先執(zhí)行左邊的 setup.bin(還是古老的 16 位實模式),然后才進入右邊的壓縮內(nèi)核。

拼接工作在 arch/x86/boot/tools/build.c 中完成。

1. GRUB 加載 bzImage

GRUB 讀取內(nèi)核文件開頭的 內(nèi)核頭部(Kernel Header),獲取啟動協(xié)議信息。

源碼位置arch/x86/boot/header.S

這個文件開頭定義了一個兼容 MS-DOS 的頭部(MZ/PE 頭),讓 GRUB 能識別它:

#ifdef CONFIG_EFI_STUB
    .word   MZ_MAGIC            # "MZ" 魔數(shù)
#endif

頭部中包含了 GRUB 需要的關(guān)鍵字段:

字段含義
setup_sectssetup 部分占多少扇區(qū)
syssize內(nèi)核大小
version啟動協(xié)議版本
cmd_line_ptr命令行參數(shù)地址
code32_start32 位代碼入口點

GRUB 根據(jù)這些信息把 bzImage 加載到內(nèi)存,然后把控制權(quán)交給 header.S 中的入口。

2. 實模式(16 位)—— 收集硬件信息

CPU 當前狀態(tài):16 位實模式,只能直接訪問 1MB 內(nèi)存,沒有內(nèi)存保護。

入口函數(shù):main()

源碼位置arch/x86/boot/main.c

這是整個內(nèi)核啟動的第一個 C 函數(shù)

void main(void)
{
    /* 把 header 里的信息復(fù)制到 boot_params */
    copy_boot_params();

    /* 初始化早期控制臺 */
    console_init();

    /* 初始化堆內(nèi)存 */
    init_heap();

    /* 檢查 CPU 是否支持運行這個內(nèi)核 */
    if (validate_cpu()) {
        puts("Unable to boot...");
        die();
    }

    /* 告訴 BIOS 我們要進 64 位模式 */
    set_bios_mode();

    /* 用 BIOS 中斷探測內(nèi)存布局 */
    detect_memory();

    /* 設(shè)置鍵盤 */
    keyboard_init();

    /* 查詢各種 BIOS 信息 */
    query_ist();
#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
    query_apm_bios();
#endif
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
    query_edd();
#endif

    /* 設(shè)置顯示模式 */
    set_video();

    /* ? 進入保護模式 */
    go_to_protected_mode();
}

這些代碼看起來古老,但非常關(guān)鍵——它用 BIOS 中斷(int 0x10、int 0x15 等)收集硬件信息,全部存進全局變量 boot_params,后面內(nèi)核會一直用它。

3. 切換到保護模式(32 位)

go_to_protected_mode() 定義在 arch/x86/boot/pm.c

void go_to_protected_mode(void)
{
    /* 關(guān)閉中斷,執(zhí)行實模式最后的鉤子 */
    realmode_switch_hook();

    /* 開啟 A20 地址線(歷史遺留,為了訪問 1MB 以上內(nèi)存) */
    if (enable_a20()) {
        puts("A20 gate not responding, unable to boot...\n");
        die();
    }

    /* 重置協(xié)處理器 */
    reset_coprocessor();

    /* 屏蔽所有中斷 */
    mask_all_interrupts();

    /* 設(shè)置 IDT 和 GDT */
    setup_idt();
    setup_gdt();

    /* ? 真正跳轉(zhuǎn)到保護模式 */
    protected_mode_jump(boot_params.hdr.code32_start,
                        (u32)&boot_params + (ds() << 4));
}

真正的切換發(fā)生在匯編文件 pmjump.S 中:

SYM_FUNC_START(protected_mode_jump)
    movl    %edx, %esi          # %edx = boot_params 指針

    movl    %cr0, %edx
    orb     $X86_CR0_PE, %dl    # 設(shè)置 CR0 的 PE (Protection Enable) 位
    movl    %edx, %cr0          # 打開保護模式!

    # 長跳轉(zhuǎn)到 32 位代碼段
    .byte   0x66, 0xea          # ljmpl 指令
    .long   .Lin_pm32           # 目標偏移
    .word   __BOOT_CS           # 代碼段選擇子

.Lin_pm32:
    # 設(shè)置 32 位平坦模式的數(shù)據(jù)段
    movl    %ecx, %ds
    movl    %ecx, %es
    movl    %ecx, %fs
    movl    %ecx, %gs
    movl    %ecx, %ss

    jmpl    *%eax               # 跳轉(zhuǎn)到 32 位入口點

發(fā)生了什么:CPU 從 16 位實模式 → 32 位保護模式?,F(xiàn)在能訪問 4GB 內(nèi)存了,但還不是 64 位。

4. 32 位解壓入口

現(xiàn)在 CPU 開始執(zhí)行 arch/x86/boot/compressed/head_64.S 中的 startup_32。

注意:文件名雖然是 head_64.S,但前面一大段是 .code32(32 位代碼)。

    .code32
SYM_FUNC_START(startup_32)
    cld
    cli                         # 關(guān)中斷

    # 計算"實際加載地址"與"編譯時地址"的偏差
    # 因為 bootloader 可能把內(nèi)核加載到了意料之外的位置
    leal    (BP_scratch+4)(%esi), %esp
    call    1f
1:  popl    %ebp
    subl    $ rva(1b), %ebp

    # 加載新的 GDT
    leal    rva(gdt)(%ebp), %eax
    movl    %eax, 2(%eax)
    lgdt    (%eax)

    # 設(shè)置數(shù)據(jù)段寄存器
    movl    $__BOOT_DS, %eax
    movl    %eax, %ds
    movl    %eax, %es
    movl    %eax, %fs
    movl    %eax, %gs
    movl    %eax, %ss

然后它繼續(xù):

  1. 建立臨時的 4GB 頁表(為進入長模式做準備)
  2. 打開 PAE(Physical Address Extension,cr4 |= X86_CR4_PAE
  3. 設(shè)置 EFER.LME(Long Mode Enable)
  4. 啟用分頁(設(shè)置 cr0.PG = 1),CPU 自動進入兼容模式
  5. 長跳轉(zhuǎn)到 64 位代碼

5. 64 位模式下的解壓

繼續(xù)在同一份 head_64.S 中,現(xiàn)在 CPU 運行在 64 位模式了。

這段代碼的任務(wù)是:

  1. 找到壓縮的內(nèi)核數(shù)據(jù)(piggy.o 里包著 vmlinux.bin.gz.xz 等)
  2. 把它解壓到最終運行地址
  3. 跳轉(zhuǎn)到解壓后的內(nèi)核入口

解壓完成后,它跳轉(zhuǎn)到真正的內(nèi)核入口——startup_64(注意:這是另一個文件里的同名符號?。?。

相關(guān)文件

  • arch/x86/boot/compressed/head_64.S
  • arch/x86/boot/compressed/misc.c(解壓算法的 C 實現(xiàn))
  • arch/x86/boot/compressed/piggy.S(把壓縮后的內(nèi)核二進制打包成匯編對象)

6. 真正的內(nèi)核 64 位入口

現(xiàn)在進入 arch/x86/kernel/head_64.S 中的 startup_64

這是編譯后的 vmlinux 的第一條指令,也是內(nèi)核真正開始建立自己世界的地方。

    .code64
SYM_CODE_START_NOALIGN(startup_64)
    /* 設(shè)置棧(用 init_task 的棧) */
    leaq    (__end_init_task - FRAME_SIZE)(%rip), %rsp

    /* 調(diào)用 startup_64_setup_env 和 verify_cpu */
    leaq    _text(%rip), %rdi
    pushq   %rsi
    call    startup_64_setup_env
    popq    %rsi

    call    verify_cpu

    /* 修正頁表(內(nèi)核可能被加載到了與編譯地址不同的位置) */
    leaq    _text(%rip), %rdi
    pushq   %rsi
    call    __startup_64
    popq    %rsi

    /* 形成 CR3 值(頁表基址) */
    addq    $(early_top_pgt - __START_KERNEL_map), %rax

    /* 設(shè)置 CR4(PAE + PGE) */
    movl    $(X86_CR4_PAE | X86_CR4_PGE), %ecx
    movq    %rcx, %cr4

    /* 切換到新的頁表 */
    movq    %rax, %cr3

    /* 加載內(nèi)核的 GDT */
    lgdt    early_gdt_descr(%rip)

    /* 清空數(shù)據(jù)段寄存器 */
    xorl    %eax, %eax
    movl    %eax, %ds
    movl    %eax, %ss
    movl    %eax, %es
    movl    %eax, %fs
    movl    %eax, %gs

    /* 設(shè)置 IDT(早期中斷描述符表) */
    pushq   %rsi
    call    early_setup_idt
    popq    %rsi

    /* 設(shè)置 EFER(使能 SYSCALL 等) */
    movl    $MSR_EFER, %ecx
    rdmsr
    btsl    $_EFER_SCE, %eax       /* Enable System Call */
    ...
    wrmsr

    /* 設(shè)置 CR0 */
    movl    $CR0_STATE, %eax
    movq    %rax, %cr0

    /* 清空中斷標志 */
    pushq   $0
    popfq

    /* 準備跳轉(zhuǎn)到 C 代碼 */
    movq    %rsi, %rdi            # real_mode_data 作為參數(shù)

.Ljump_to_C_code:
    xorl    %ebp, %ebp            # 清空幀指針
    movq    initial_code(%rip), %rax    # rax = x86_64_start_kernel
    pushq   $__KERNEL_CS
    pushq   %rax
    lretq                         # 遠返回,進入 x86_64_start_kernel

關(guān)鍵點:

  • initial_code 是一個全局變量,值為 x86_64_start_kernel
  • initial_stack 指向 init_thread_union(這是 PID 0,也就是 swapper/idle 進程的棧)
  • lretq 完成一次遠返回,同時切換代碼段和跳轉(zhuǎn)到目標地址

7. x86 架構(gòu)的 C 語言入口

lretq 把你帶到了 arch/x86/kernel/head64.c

asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
{
    /* 編譯期檢查 */
    BUILD_BUG_ON(MODULES_VADDR < __START_KERNEL_map);
    ...

    /* 初始化 CR4 影子寄存器 */
    cr4_init_shadow();

    /* 清除臨時頁表(去掉 identity map) */
    reset_early_page_tables();

    /* 清零 BSS 段 */
    clear_bss();

    /* 復(fù)制 boot_params 到內(nèi)核空間 */
    copy_bootdata(__va(real_mode_data));

    /* 加載 CPU 微碼 */
    load_ucode_bsp();

    /* 設(shè)置正式頁表的高地址映射 */
    init_top_pgt[511] = early_top_pgt[511];

    x86_64_start_reservations(real_mode_data);
}

void __init x86_64_start_reservations(char *real_mode_data)
{
    if (!boot_params.hdr.version)
        copy_bootdata(__va(real_mode_data));

    x86_early_init_platform_quirks();

    /* 特殊平臺處理 */
    switch (boot_params.hdr.hardware_subarch) {
    case X86_SUBARCH_INTEL_MID:
        x86_intel_mid_early_setup();
        break;
    default:
        break;
    }

    start_kernel();                 /* ? 進入體系無關(guān)的通用初始化! */
}

從這里開始,代碼變得體系無關(guān)了——不管是 x86、ARM 還是 RISC-V,最終都會調(diào)用 start_kernel()。

8. 通用內(nèi)核初始化 —— start_kernel()

這是整個內(nèi)核最著名的函數(shù),位于 init/main.c

asmlinkage __visible void __init start_kernel(void)
{
    char *command_line;
    char *after_dashes;

    /* 設(shè)置 init_task(PID 0)的棧結(jié)束魔數(shù) */
    set_task_stack_end_magic(&init_task);

    smp_setup_processor_id();
    cgroup_init_early();

    /* 關(guān)中斷,初始化期間不允許打擾 */
    local_irq_disable();
    early_boot_irqs_disabled = true;

    boot_cpu_init();
    page_address_init();

    /* 打印 "Linux version 5.15.119 ..." */
    pr_notice("%s", linux_banner);

    early_security_init();

    /* ? 架構(gòu)相關(guān)初始化(內(nèi)存、CPU、ACPI 等) */
    setup_arch(&command_line);

    setup_boot_config();
    setup_command_line(command_line);
    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    smp_prepare_boot_cpu();
    boot_cpu_hotplug_init();

    /* 建立內(nèi)存管理區(qū) */
    build_all_zonelists(NULL);
    page_alloc_init();

    /* 打印命令行 */
    pr_notice("Kernel command line: %s\n", saved_command_line);

    /* 解析早期參數(shù)(如 mem=, console=) */
    parse_early_param();
    parse_args("Booting kernel", static_command_line, ...);

    /* ? 初始化內(nèi)存管理 */
    mm_init();

    ftrace_init();
    sched_init();                   /* ? 初始化調(diào)度器 */
    radix_tree_init();
    workqueue_init_early();
    rcu_init();
    trace_init();
    context_tracking_init();
    early_irq_init();
    init_IRQ();                     /* 初始化中斷 */
    tick_init();
    init_timers();
    timekeeping_init();
    time_init();                    /* 初始化時間子系統(tǒng) */
    random_init(command_line);
    boot_init_stack_canary();

    /* 開中斷 */
    local_irq_enable();
    early_boot_irqs_disabled = false;

    console_init();                 /* 正式初始化控制臺 */

    /* ? 初始化 VFS */
    vfs_caches_init();
    signals_init();
    pagecache_init();
    proc_root_init();               /* 創(chuàng)建 /proc */
    nsfs_init();
    cgroup_init();
    ...
    check_bugs();                   /* 檢查 CPU bug */

    /* ? 調(diào)用 rest_init() */
    arch_call_rest_init();
}

start_kernel() 初始化了內(nèi)核的幾乎所有核心子系統(tǒng)

  • 內(nèi)存管理(MM)
  • 進程調(diào)度
  • 中斷、定時器
  • 文件系統(tǒng)緩存
  • procfs、cgroups

但最后它自己不變成用戶進程,而是調(diào)用 rest_init()。

9. rest_init() —— 創(chuàng)建兩個"祖先進程"

源碼位置init/main.c

noinline void __ref rest_init(void)
{
    struct task_struct *tsk;
    int pid;

    rcu_scheduler_starting();

    /*
     * 創(chuàng)建 PID 1:init 進程(用戶態(tài)的祖先)
     */
    pid = kernel_thread(kernel_init, NULL, CLONE_FS);

    /* 把 init 固定在 boot CPU 上 */
    rcu_read_lock();
    tsk = find_task_by_pid_ns(pid, &init_pid_ns);
    tsk->flags |= PF_NO_SETAFFINITY;
    set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));
    rcu_read_unlock();

    /*
     * 創(chuàng)建 PID 2:kthreadd(內(nèi)核線程的祖先)
     */
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

    rcu_read_lock();
    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
    rcu_read_unlock();

    /*
     * 啟用調(diào)度器檢查
     */
    system_state = SYSTEM_SCHEDULING;

    complete(&kthreadd_done);

    /*
     * 當前線程(PID 0)變成 idle 進程,永遠執(zhí)行 schedule()
     */
    schedule_preempt_disabled();
    cpu_startup_entry(CPUHP_ONLINE);   /* 進入 idle 循環(huán) */
}

這是 Linux 進程樹的起點

PID進程作用
0swapper/idle當前線程變身而來,沒事干時執(zhí)行它
1kernel_init接下來啟動第一個用戶程序(/sbin/init
2kthreadd專門"收養(yǎng)"內(nèi)核線程,所有內(nèi)核線程的父進程

10. kernel_init() —— 啟動第一個用戶程序

源碼位置init/main.c

static int __ref kernel_init(void *unused)
{
    /* 等 kthreadd 準備好 */
    wait_for_completion(&kthreadd_done);

    /* 加載真正的根文件系統(tǒng) */
    kernel_init_freeable();

    /* 等所有異步 __init 代碼完成 */
    async_synchronize_full();

    /* 釋放 __init 段內(nèi)存(啟動完成后這些代碼不再需要) */
    free_initmem();
    mark_readonly();
    pti_finalize();

    /* 系統(tǒng)正式運行 */
    system_state = SYSTEM_RUNNING;
    numa_default_policy();
    rcu_end_inkernel_boot();

    /* 按優(yōu)先級嘗試啟動第一個用戶進程 */

    /* 1. initrd 中的 /init */
    if (ramdisk_execute_command) {
        ret = run_init_process(ramdisk_execute_command);
        if (!ret)
            return 0;
    }

    /* 2. 命令行 init=xxx 指定的程序 */
    if (execute_command) {
        ret = run_init_process(execute_command);
        if (!ret)
            return 0;
    }

    /* 3. 編譯時默認的 init */
    if (CONFIG_DEFAULT_INIT[0] != '\0') {
        ret = run_init_process(CONFIG_DEFAULT_INIT);
        if (!ret)
            return 0;
    }

    /* 4. 默認路徑 */
    if (!try_to_run_init_process("/sbin/init") ||
        !try_to_run_init_process("/etc/init") ||
        !try_to_run_init_process("/bin/init") ||
        !try_to_run_init_process("/bin/sh"))
        return 0;

    /* 全都失敗 */
    panic("No working init found.  Try passing init= option to kernel.");
}

一旦 run_init_process("/sbin/init") 成功,內(nèi)核就完成了它的啟動使命。

從這一刻起,系統(tǒng)控制權(quán)交給了用戶空間。

你看到的 systemd、sysvinit、或 bash,就是從這里開始的。

總結(jié):完整啟動路線圖

Mermaid 流程圖

ASCII 路線圖(備用)

GRUB 加載 bzImage
    │
    ▼
┌─────────────────────────────────────────────┐
│  arch/x86/boot/header.S                     │  內(nèi)核頭部,存放啟動協(xié)議信息
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  arch/x86/boot/main.c   main()              │  ?── 16位實模式
│      └── go_to_protected_mode()             │      收集硬件信息到 boot_params
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  arch/x86/boot/pmjump.S                     │  ?── 打開 CR0.PE
│      protected_mode_jump()                  │      進入 32 位保護模式
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  arch/x86/boot/compressed/head_64.S         │  ?── 32→64位切換
│      startup_32 → startup_64                │      建立頁表,解壓內(nèi)核
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  arch/x86/kernel/head_64.S                  │  ?── 真正的內(nèi)核 64 位入口
│      startup_64 → lretq                     │      設(shè)置頁表/GDT/IDT
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  arch/x86/kernel/head64.c                   │  ?── x86 架構(gòu) C 入口
│      x86_64_start_kernel()                  │      清零 BSS,加載微碼
│      └── start_kernel()                     │
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  init/main.c   start_kernel()               │  ?── 初始化所有子系統(tǒng)
│      └── arch_call_rest_init()              │      MM、調(diào)度、IRQ、VFS...
│          └── rest_init()                    │
│              ├── kernel_thread(kernel_init) │  PID 1
│              ├── kernel_thread(kthreadd)    │  PID 2
│              └── cpu_startup_entry()        │  PID 0 (idle)
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  init/main.c   kernel_init()                │  ?── 啟動 /sbin/init
│      └── run_init_process()                 │
└─────────────────────────────────────────────┘
    │
    ▼
  用戶空間(systemd / init / bash)

以上就是Linux內(nèi)核啟動流程詳解(基于 5.15.119 源碼)的詳細內(nèi)容,更多關(guān)于Linux內(nèi)核啟動流程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • linux命令實現(xiàn)音頻格式轉(zhuǎn)換和拼接的方法

    linux命令實現(xiàn)音頻格式轉(zhuǎn)換和拼接的方法

    今天小編就為大家分享一篇linux命令實現(xiàn)音頻格式轉(zhuǎn)換和拼接的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Linux(CentOS)上配置 SFTP服務(wù)器

    Linux(CentOS)上配置 SFTP服務(wù)器

    本篇文章主要介紹了Linux(CentOS)上配置 SFTP服務(wù)器。相比傳統(tǒng)的 ftp 服務(wù),SFTP 顯得更加方便、安全,有興趣的朋友可以了解一下。
    2017-03-03
  • linux下掛載VHD等虛擬磁盤文件的方法

    linux下掛載VHD等虛擬磁盤文件的方法

    本篇文章主要介紹了linux下掛載VHD等虛擬磁盤文件的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • apache性能測試工具ab使用詳解

    apache性能測試工具ab使用詳解

    這篇文章主要介紹了apache性能測試工具ab使用詳解,需要的朋友可以參考下
    2015-01-01
  • centos 7 安裝卸載apache(httpd)服務(wù)的詳細步驟

    centos 7 安裝卸載apache(httpd)服務(wù)的詳細步驟

    前面我們已經(jīng)安裝好了mysql,今天安裝httpd,然后試著訪問以下,由于博主已經(jīng)安裝過一次,所以先說卸載,再說安裝,需要的朋友可以參考下
    2020-07-07
  • Linux 修改 etc/hosts文件詳細介紹

    Linux 修改 etc/hosts文件詳細介紹

    這篇文章主要介紹了 Linux 修改 etc/hosts文件詳細介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • centos7切換啟動內(nèi)核與切換啟動模式的講解

    centos7切換啟動內(nèi)核與切換啟動模式的講解

    今天小編就為大家分享一篇關(guān)于centos7切換啟動內(nèi)核與切換啟動模式的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • Linux用戶切換與管理的完整指南

    Linux用戶切換與管理的完整指南

    這篇文章主要介紹了Linux系統(tǒng)中用戶切換與管理的全流程,涵蓋su/sudo權(quán)限操作、SSH遠程認證、會話管理工具、安全配置策略、狀態(tài)監(jiān)控命令及故障排查方法,重點強調(diào)了權(quán)限控制、安全加固與操作審計等核心實踐,需要的朋友可以參考下
    2025-07-07
  • 搭建阿里云ecs服務(wù)器之安裝圖形化界面的方法

    搭建阿里云ecs服務(wù)器之安裝圖形化界面的方法

    這篇文章主要介紹了搭建阿里云ecs服務(wù)器之安裝圖形化界面的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Xshell5連接虛擬機中的Linux的方法以及失敗原因解決

    Xshell5連接虛擬機中的Linux的方法以及失敗原因解決

    這篇文章主要介紹了Xshell5連接虛擬機中的Linux的方法以及失敗原因解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07

最新評論

双桥区| 普格县| 龙里县| 阿拉善右旗| 山西省| 诸城市| 尉氏县| 弋阳县| 平南县| 建水县| 贺兰县| 忻城县| 漯河市| 镇江市| 盐城市| 高平市| 剑阁县| 廉江市| 图们市| 桦川县| 萝北县| 九龙县| 洪江市| 淮北市| 温州市| 达尔| 濮阳市| 宁蒗| 胶南市| 紫阳县| 郓城县| 新野县| 太原市| 宁远县| 贡嘎县| 镇江市| 郁南县| 同心县| 固安县| 樟树市| 平凉市|