[운영체제 구현 01] CentOS 9은 Bochs 2.7 가상머신을 설치 및 구성하고 간단한 부트로더를 작성하여 플로피디스크에 기록하여 부팅

系统环境:
OS:CentOS Stream release 9 (cmd: cat /etc/redhat-release)
Linux Kernel:Linux 5.14.0-142.el9.x86_64 (cmd: uname -a)

1. Bochs 가상 머신

Bochs오픈 소스 가상 머신 소프트웨어로 시스템 개발에 도움이 되는 관련 디버깅 기능을 제공합니다.운영 체제를 연구하거나 Linux커널 개발 내용.
다운로드 링크:
Bochs 공식 웹사이트: https://bochs.sourceforge.io/
Sourceforge 다운로드: https://sourceforge.net/projects/bochs/files/bochs/
Github 다운로드: https://github.com/stlintel/Bochs

2. Bochs 컴파일 및 설치

저자는 다운로드 sourceforge

2.2 소스 패키지 압축 해제

다운로드 후 소스 패키지의 압축을 풀어야 합니다.

[imaginemiracle@imos-ws Downloads]$ tar -zxvf bochs-2.7.tar.gz

2.3 종속성 설치 및 Bochs 구성

관련 종속성을 설치하십시오. 그렇지 않으면 먼저 구성 또는 컴파일에 종속성이 부족합니다.

[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install gcc-c++
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install gtk2-devel
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install readline-devel
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install xorg-x11-server-Xdmx.x86_64

2.3.1 Makefile 생성을 위한 configure 사용

압축해제 후 소스코드 디렉토리로 들어가 소스코드 설정 configure에 , 여기서 --prefix작성자는 지정된 위치에 설치 디렉토리를 설정하는데 사용합니다.

[imaginemiracle@imos-ws bochs-2.7]$ ./configure --prefix=/pgm/bochs --with-x11 --with-wx --enable-debugger --enable-all-optimizations --enable-readline --enable-long-phy-address --enable-ltdl-install --enable-idle-hack --enable-a20-pin --enable-x86-64 --enable-smp --enable-cpu-level=6 --enable-large-ramfile --enable-repeat-speedups --enable-fast-function-calls  --enable-handlers-chaining  --enable-trace-linking --enable-configurable-msrs --enable-show-ips --enable-cpp --enable-debugger-gui --enable-iodebug --enable-logging --enable-assert-checks --enable-fpu --enable-vmx=2 --enable-svm --enable-3dnow --enable-alignment-check  --enable-monitor-mwait --enable-avx  --enable-evex --enable-x86-debugger --enable-pci --enable-usb --enable-voodoo

2.3.2 컴파일하기

구성이 오류를 보고하지 않으면 직접 컴파일할 수 있습니다.

[imaginemiracle@imos-ws bochs-2.7]$ make

2.3.3. 참고: 'parser.o'에 필요한 대상 'parser.cc'를 만드는 규칙이 없습니다.

컴파일할 때 다음과 같은 오류가 발생할 수 있습니다.

make[1]: *** No rule to make target 'parser.cc', needed by 'parser.o'.  Stop.

2.3.4 no parser.cc 문제 해결

해당 .cpp파일을 .cc파일로 복사하기만 하면 됩니다.

[imaginemiracle@imos-ws bochs-2.7]$ cp bx_debug/parser.cpp bx_debug/parser.cc

[注]:不要疑问要怎么找到复制文件的目录所在。出错行紧后会提示从出错目录退出,这个目录便是缺少文件的目录,需要复制文件的目录也就在这里了。

2.3.5 계속 만들기, 계속 오류 보고: 치명적 오류: config.h: 해당 파일 또는 디렉터리 없음

make명령을 계속 실행 하지만 이러한 오류가 다시 발생합니다. 프롬프트를 찾을 수 없습니다.config.h

cd bx_debug && \
make  libdebug.a
make[1]: Entering directory '/home/imaginemiracle/Downloads/bochs-2.7/bx_debug'
g++ -g -O2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES      -c -o parser.o parser.cc
In file included from parser.y:8:
debug.h:25:10: fatal error: config.h: No such file or directory
   25 | #include "config.h"
      |          ^~~~~~~~~~
compilation terminated.
make[1]: *** [<builtin>: parser.o] Error 1
make[1]: Leaving directory '/home/imaginemiracle/Downloads/bochs-2.7/bx_debug'
make: *** [Makefile:327: bx_debug/libdebug.a] Error 2

2.3.6 config.h를 찾지 못하는 문제 해결

이 헤더 파일에 대해서는 소스 코드의 기본 디렉토리에서 볼 수 있습니다.

[imaginemiracle@imos-ws bochs-2.7]$ ls
aclocal.m4      bxversion.rc     configure     gui           ltdl.c         osdep.cpp       README
bios            bxversion.rc.in  configure.in  host          ltdlconf.h     osdep.h         README-wxWidgets
bochs.h         CHANGES          COPYING       install-sh    ltdlconf.h.in  param_names.h   TESTFORM.txt
build           config.cpp       cpu           instrument    ltmain.sh      PARAM_TREE.txt  TODO
bx_debug        config.guess     cpudb.h       iodev         main.cpp       patches         win32_enh_dbg.rc
bxdisasm.cpp    config.h         crc.cpp       libtool       Makefile       pc_system.cpp   win32res.rc
bxthread.cpp    config.h.in      doc           LICENSE       Makefile.in    pc_system.h     wxbochs.rc
bxthread.h      config.log       docs-html     logio.cpp     memory         plugin.cpp
bxversion.h     config.status    extplugin.h   logio.h       misc           plugin.h
bxversion.h.in  config.sub       gdbstub.cpp   ltdl-bochs.h  msrs.def       qemu-queue.h

오류 파일 열기

[imaginemiracle@imos-ws bochs-2.7]$ vim bx_debug/debug.h

25#include "config.h" 수정하십시오.#include "../config.h"
여기에 이미지 설명 삽입

2.3.7 계속 만들기, 계속 오류 보고: 치명적 오류: osdep.h: 해당 파일 또는 디렉터리 없음 및 치명적 오류: cpu/decoder/decoder.h: 해당 파일 또는 디렉터리 없음

앞의 것과 유사한 다른 두 가지 오류가 있으며 기본 디렉토리에서도 찾을 수 있으므로 을 osdep.h열고 bx_debug/debug.h#include “osdep.h”변경하고 #include "../osdep.h"수정하십시오 .36#include "cpu/decoder/decoder.h"
여기에 이미지 설명 삽입

2.3.8. 계속해서 만들면 오류가 보고됩니다: 'misc/bximage.o'에 필요한 대상 'misc/bximage.cc'를 만드는 규칙이 없으며 이러한 일련의 문제가 발생합니다.

이러한 유형의 문제는 첫 번째 오류와 유사하며 오류 디렉토리에 해당 .cpp파일이 . .cc파일로 복사하면 됩니다.

[imaginemiracle@imos-ws bochs-2.7]$ cp misc/bximage.cpp misc/bximage.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/hdimage.cpp iodev/hdimage/hdimage.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vmware3.cpp iodev/hdimage/vmware3.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vmware4.cpp iodev/hdimage/vmware4.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vpc.cpp iodev/hdimage/vpc.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vbox.cpp iodev/hdimage/vbox.cc

2.3.9 make install 이후 make 및 install 계속하기

현재 실행에 문제가 없을 make것이므로 make install설치 명령을 실행합니다.

[imaginemiracle@imos-ws bochs-2.7]$ make install

설치 디렉터리를 확인하세요.기본 설치 디렉터리를 사용하는 경우 직접 입력 boch하고 tab키를 사용하여 완료할 수 있습니다.

[imaginemiracle@imos-ws ~]$ ls /pgm/bochs/bin/
bochs  bximage

자, 여기에 생성된 실행 파일이 보이면 설치가 bochs된 .

3. 플로피 디스크 이미지 파일 만들기

방금 Bochs설치한 도구에는 bximage가상 머신 이미지를 만드는 데 사용되는 이라는 도구가 있습니다.

구체적인 사용 방법을 살펴보겠습니다:
(1) 직접 실행 bximage(작성자와 같이 지정된 디렉토리에 설치되어 있는 경우 먼저 ~/.bashrc파일 source ~/.bashrc예: export PATH=$PATH:/pgm/bochs/bin)

[imaginemiracle@imos-ws img]$ bximage
========================================================================
                                bximage
  Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
         $Id: bximage.cc 14091 2021-01-30 17:37:42Z sshwarts $
========================================================================

1. Create new floppy or hard disk image
2. Convert hard disk image to other format (mode)
3. Resize hard disk image
4. Commit 'undoable' redolog to base image
5. Disk image info

0. Quit

Please choose one [0] 1

(2) 여기에 입력하는 1것은 플로피 디스크 또는 하드 디스크를 생성하도록 선택하는 것을 의미하며 Enter 키를 누르면 다음 내용이 나타납니다.

Create image

Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd

(3) 여기에서 생성 유형이 플로피 디스크( fd) 또는 하드 디스크( hd)인지 선택하고 여기에 입력 fd하고 .

Choose the size of floppy disk image to create.
Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M.
 [1.44M]

(4) 다음으로 생성된 플로피 디스크의 크기를 선택하라는 메시지가 표시됩니다. 기본값은 입니다 1.44MB. 기본값을 사용하려면 여기에서 Enter 키를 누르십시오.

What should be the name of the image?
[a.img] imboot.img

Creating floppy image 'imboot.img' with 2880 sectors

The following line should appear in your bochsrc:
  floppya: image="imboot.img", status=inserted

(5) 다음 단계에서는 생성된 플로피 디스크의 이름을 묻습니다. 이 플로피 디스크는 나중에 운영 체제를 시작하는 프로그램 기본 a.img이름은 여기에 작성자가 입력한 이름 입니다.imboot.imgboot

자, 여기 플로피 디스크 이미지 파일이 생성되었습니다.

4. Bochs 운영 환경 구성

Bochs참고용 구성 파일은 의 설치 디렉토리 에 제공되며 /pgm/bochs/share/doc/bochs/bochsrc-sample.txt참조용으로 로컬에 사본을 복사하거나 작성자의 구성을 직접 복사하십시오.

# Configuration file generated by Bochs
#=======================================================================
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, iodebug=1

config_interface: textconfig
#display_library: wx
display_library: x

romimage: file=$BXSHARE/BIOS-bochs-latest, options=fastboot
romimage: file=/pgm/bochs/share/bochs/BIOS-bochs-latest
vgaromimage: file=/pgm/bochs/share/bochs/VGABIOS-lgpl-latest

# choose the boot disk
boot: floppy
floppy_bootsig_check: disabled=0
floppya: type=1_44, 1_44=/home/imaginemiracle/Miracle/Projects/imOS/img/imboot.img, status=inserted, write_protected=0

cpu: model=corei7_haswell_4770, count=1:1:1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
cpu: cpuid_limit_winnt=0

cpuid: x86_64=1, mmx=1, level=6, sep=1, simd=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1, apic=x2apic, sha=1, adx=1, xsaveopt=1, avx_f16c=1, avx_fma=1, bmi=bmi2, 1g_pages=1, pcid=1, fsgsbase=1, smep=1, smap=1, mwait=1, vmx=1
cpuid: family=6, model=0x1a, stepping=5, vendor_string="GenuineIntel", brand_string="Intel(R) Core(TM) i7-4770 CPU (Haswell)"

#memory: guest=512, host=256

pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5
#voodoo: enabled=1, model=voodoo1

keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: enabled=0, type=ps2, toggle=ctrl+mbutton

clock: sync=none, time0=local, rtc_sync=0
#cmosimage: file=cmos.img, rtc_init=time0

private_colormap: enabled=0

ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=none
ata0-slave: type=none
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none
ata1-slave: type=none
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9

boot: floppy
#boot: disk
floppy_bootsig_check: disabled=0

#log: /dev/null
log: bochsout.txt
logprefix: %t%e%d

panic: action=ask
error: action=report
info: action=report
debug: action=ignore, pci=report # report BX_DEBUG from module 'pci'

debugger_log: -
#com1: enabled=1, mode=term, dev=/dev/ttyp9

parport1: enabled=1, file="parport.out"

#sound: driver=default, waveout=/dev/dsp. wavein=, midiout=
speaker: enabled=1, mode=system
parport1: enabled=1, file=none
parport2: enabled=0

com1: enabled=1, mode=null
com2: enabled=0
com3: enabled=0
com4: enabled=0
#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=slirp.conf

magic_break: enabled=0
#debug_symbols: file="kernel.sym"
print_timestamps: enabled=1
port_e9_hack: enabled=0
private_colormap: enabled=0

megs: 2048

floppya의 구성 이 있으며 여기의 이미지 크기와 파일 경로는 전에 bximage도구에 의해 생성되었으며 imboot.img여기의 경로와 크기는 올바르게 작성되어야 합니다. 그렇지 않으면 시작되지 않습니다.

floppya: type=1_44, 1_44=/home/imaginemiracle/Miracle/Project/imOS/img/imboot.img, status=inserted, write_protected=0

5. 간단한 부트 프로그램 작성

새 파일을 만들고 열고 imboot.S다음을 BIOS기반 boot코드를 작성합니다.

org	0x7c00 ; BIOS 会加载引导程序到内存地址 0x7c00 处

BaseOfStack	equ	0x7c00 ; 定义一个标识符 BaseOfStack,代表值 0x7c00

Start:

mov ax, cs	; 将代码寄存器 cs 的段基地址设置到 ds、es、ss寄存器
mov	ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack

; 清屏

mov ax, 0600h
mov bx, 0700h
mov cx, 0h
mov dx, 0184fh
int 10h

; 设置光标位置

mov ax, 0200h
mov bx, 0000h
mov dx, 0000h
int 10h

; 在屏幕上打印字符串 "The imboot is working!"

mov ax, 1301h
mov bx, 000fh
mov dx, 0000h
mov cx, 22
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, IMBootMessage
int 10h

; 软盘驱动器复位

xor ah, ah
xor dl, dl
int 13h

jmp $

IMBootMessage:	dd	"The imboot is working!"

; 填充 0 到结尾前 2 个字节

times 510 - ($ - $$) db 0
dw 0xaa55	; BIOS会检测软盘的第 0 磁头第 1 扇区最后两个字节是否为 0x55aa(代码中写成 0xaa55 是由于x86 使用小端存储),以确定这个扇区是否是引导扇区

이 어셈블리 코드는 주로 BIOS인터럽트 서비스 루틴 int 10h과 화면 작업 int 13h완료 사용합니다.

주 기능 번호 를 int 10h저장하는 ah다른 기능을 사용하는 경우에도 int 13h마찬가지입니다 .

인터럽트 서비스 주요 기능 번호 AH 기능 설명 AL기능 BH기능 BL기능 CH기능 CL기능 DH기능 DL기능 ES:BP

INT 10h
02h 커서 위치 설정 페이지 번호 - - - - 커서의 열 번호 커서의 줄 번호 -
INT 10h 06h 지정된 범위만큼 창 스크롤 스크롤 열의 수; 화면을 지우는 것을
의미하며 현재 다른 속성은 유효하지 않습니다.0
스크롤 후 빈 위치의 속성 색상 속성 설정
:
* 비트 0~2: 글꼴 색상 (0: 검정색 1: 파란색 2: 녹색 3: 녹색 4: 빨간색 5: 보라색 6: 갈색 7: 흰색) * 비트 3:
글꼴 밝기(0: 기본 1: 강조 표시)
* 비트 4~6: 배경색(색상 값은 위와 동일)
* 비트 7: 글꼴 깜박임(0: 꺼짐 1: 사용)
- 스크롤 범위의 왼쪽 상단 모서리의 좌표 열 번호 스크롤 범위의 왼쪽 상단 모서리의 좌표 줄 번호 스크롤 범위 오른쪽 하단의 좌표 열 번호 스크롤 범위의 오른쪽 하단 모서리의 좌표 라인 번호 -
INT 10h 13h 한 줄의 문자열 표시 쓰기 모드:
00h: 문자열 속성을 BL제어 하고 길이 CX를 제어(단위: 바이트), 커서 위치는 변경되지 않음,
01h: 위와 동일하지만 표시가 종료되고 커서가 문자열의 끝으로 업데이트됨.
02h: 문자열은 마지막 바이트에 의해 제어됩니다. CX제어 단위를 변경합니다 Word. 커서 위치는 변경하지 않습니다.
03h: 동일 02h하지만 커서 위치를 문자열의 끝으로 업데이트합니다.
페이지 번호 문자 속성, 동일06h 문자열 길이 문자열 길이 커서가 위치한 줄 번호 커서가 위치한 열 번호 표시할 문자열의 메모리 주소
INT 13h 00h 디스크 드라이브 재설정 - - - - - - 00h: 첫 번째 플로피 드라이브( drive A:);
01h: 두 번째 플로피 드라이브( drive B:);

7fh: 128번째 플로피 드라이브;
80h: 첫 번째 하드 드라이브;

ffh: 128번째 하드 드라이브
-

6. Bochs에서 Boot 프로그램 실행

6.1 NASM 컴파일러 다운로드 및 설치

위의 코드를 작성했지만 아직 컴파일되지 않은 상태이며 컴파일러를 사용하여 NASM컴파일 먼저 설치해 보겠습니다.
다른 종속 항목을 먼저 설치합니다. Ubuntu시스템 sudo apt-get install build-essential직접 사용할 수 있습니다.

# Ubuntu 系统
imaginemiracle:~$ sudo apt-get install build-essential
imaginemiracle:~$ sudo apt-get install curl
# CentOS 系统
[imaginemiracle@imos-ws imboot]$ sudo yum install make automake gcc gcc-c++ kernel-devel
[imaginemiracle@imos-ws imboot]$ sudo yum install -y curl

nasm컴파일러를 다운로드하여 설치합니다 .

[imaginemiracle@imos-ws Downloads]$ curl -O -L https://www.nasm.us/pub/nasm/releasebuilds/2.15/nasm-2.15.tar.gz
[imaginemiracle@imos-ws Downloads]$ tar -zxvf nasm-2.15.tar.gz
[imaginemiracle@imos-ws Downloads]$ cd nasm-2.15/
[imaginemiracle@imos-ws nasm-2.15]$ ./autogen.sh
[imaginemiracle@imos-ws nasm-2.15]$ ./configure --prefix=/pgm/nasm
[imaginemiracle@imos-ws nasm-2.15]$ make install

nasm환경 변수 에 추가하고 vim ~/.bashrc다음 내용을 추가하십시오.

export PATH=$PATH:/pgm/bochs/bin:/pgm/nasm/bin

환경 변수 업데이트

source ~/.bashrc

6.2 프로그램을 컴파일하고 플로피 디스크에 굽기

방금 설치한 nasm도구 코드를 컴파일합니다 boot.

[imaginemiracle@imos-ws imboot]$ nasm imboot.S -o imboot.bin
[imaginemiracle@imos-ws imboot]$ ls
imboot.bin  imboot.S

컴파일은 바이너리 파일을 생성하고 이 파일을 이전에 만든 플로피 imboot.img디스크 .

[imaginemiracle@imos-ws img]$ dd if=../imboot/imboot.bin of=./imboot.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000104768 s, 4.9 MB/s

프로그래밍 또는 코드 작성이 올바른지 이미지 파일을 열어 imboot.img확인하십시오 .

[imaginemiracle@imos-ws img]$ vim imboot.img

파일이 바이너리 파일이기 때문에 파일을 열면 "잘못된 문자"가 표시되지만 %!xxd도구를 16바이너리로 변환하여 볼 수 있습니다.
여기에 이미지 설명 삽입
변환 후 다음 내용을 볼 수 있습니다.

여기에 이미지 설명 삽입

우리가 확인해야 할 것은 주로 플로피 디스크의 첫 번째 섹터의 마지막 두 바이트가 0x55aa부팅 섹터의 끝인지 여부를 나타내는 입니다. 섹터는 512크기 이고 여기에는 16행에 바이트가 있으므로 bytes 511row512 의 끝에 나타나야 합니다 . 32( 512 / 16 = 32)

여기에 이미지 설명 삽입

좋아, 우리의 코드와 프로그래밍이 괜찮은 것 같으니 다음 단계를 계속할 수 있다.

7. Bochs로 부팅 코드 시작

bochs명령을 사용 하고 구성 파일을 이전에 작성된 구성 파일로 지정합니다.

[imaginemiracle@imos-ws bochs-run]$ bochs -f bochsrc

실행 후 다음과 같은 결과가 출력됩니다.

========================================================================
                        Bochs x86 Emulator 2.7
              Built from SVN snapshot on August  1, 2021
                Timestamp: Sun Aug  1 10:07:00 CEST 2021
========================================================================
00000000000i[      ] BXSHARE not set. using compile time default '/pgm/bochs/share/bochs'
00000000000i[      ] reading configuration from bochsrc
00000000000i[      ] Ignoring magic break points
------------------------------
Bochs Configuration: Main Menu
------------------------------

This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate.  Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found.  When you are satisfied with the configuration, go
ahead and start the simulation.

You can also start bochs with the -q option to skip these menus.

1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit now

Please choose one: [6]

여기에서 기본 선택은 6우리가 제공한 이미지 파일 실행을 시작하는 것이므로 여기에서 Enter를 누르고 Enter를 누르십시오. 이 때 검은색 화면 인터페이스가 표시되어야 합니다. 이 때 프로그램을 실행 하려면
여기에 이미지 설명 삽입
명령줄에 계속 입력 c하거나 .continuebochsboot
여기에 이미지 설명 삽입

이때 코드에 있는 문자열이 출력 The imboot is working!된 , 이는 Boot프로그램이 실행되었음을 의미합니다.
여기에 이미지 설명 삽입

#이 글의 끝

이 시점에서 및 프로그램의 워크플로우와 가상 머신에서의 실제 시뮬레이션을 BIOS마스터했습니다 .boot

이 글이 도움이 되셨다면 좋아요를 눌러주세요^v^*
작성자를 존중해 주시고, 재인쇄 시 출처를 꼭 밝혀주세요! 협조해주셔서 감사합니다~
[작성자]: Imagine Miracle
[저작권]: 이 저작물은 "저작자 표시-비상업적 사용-동일조건변경허락 4.0 국제" 라이선스 계약에 따라 라이선스가 부여됩니다.
[이 기사 링크]: https://blog.csdn.net/qq_36393978/article/details/126260487

추천

출처blog.csdn.net/qq_36393978/article/details/126260487