QEMU for mini2440

Supported machines are:
integratorcp ARM Integrator/CP (ARM926EJ-S) (default)
versatilepb ARM Versatile/PB (ARM926EJ-S)
versatileab ARM Versatile/AB (ARM926EJ-S)
realview ARM RealView Emulation Baseboard (ARM926EJ-S)
akita Akita PDA (PXA270)
spitz Spitz PDA (PXA270)
borzoi Borzoi PDA (PXA270)
terrier Terrier PDA (PXA270)
sx1-v1 Siemens SX1 (OMAP310) V1
sx1 Siemens SX1 (OMAP310) V2
cheetah Palm Tungsten|E aka. Cheetah PDA (OMAP310)
n800 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810 Nokia N810 tablet aka. RX-44 (OMAP2420)
lm3s811evb Stellaris LM3S811EVB
lm3s6965evb Stellaris LM3S6965EVB
connex Gumstix Connex (PXA255)
verdex Gumstix Verdex (PXA270)
mainstone Mainstone II (PXA27x)
musicpal Marvell 88w8618 / MusicPal (ARM926EJ-S)
tosa Tosa PDA (PXA255)
mini2440 MINI2440 Chinese Samsung SoC dev board (S3C2440A)
syborg Syborg (Symbian Virtual Platform)

编译时遇到的问题

https://blog.csdn.net/MACMACip/article/details/105512052

 下载地址

http://mmmyddd.github.io/wiki/embed/busybox-linux-mini2440-qemu.html

 https://blog.csdn.net/ou_nana/article/details/106743201

https://www.cnblogs.com/jinmu190/archive/2011/03/21/1990698.html

https://www.cnblogs.com/pangblog/p/3367740.html

https://blog.csdn.net/multimicro/article/details/82953770

https://blog.csdn.net/maxwell_nc/article/details/44279553

https://blog.csdn.net/qq_36576792/article/details/86611633

https://blog.csdn.net/qq_36576792/article/details/86672033

https://blog.csdn.net/weixin_34290000/article/details/92633338

https://blog.csdn.net/MACMACip/article/details/105512052

http://pan.baidu.com/s/1pJlwr2r

https://xionghuilin.com/embedded-linux-s3c2440-qemu-and-graphic/

qemu-system-arm -M mini2440 -serial stdio -mtdblock nand.bin -usbdevicemouse 在nand.bin中可以不需要u-boot.bin,

在当前执行这条命令的文件夹下有u-boot.bin即可,一开始进入的u-boot是当前目录下的u-boot.bin

GDB

./local/bin/qemu-system-arm -M mini2440 -serial stdio -mtdblock nand.bin -usbdevice mouse -S -s

gdb-multiarch u-boot

target remote :1234

编译出现undefined reference to symbol 'timer_settime@@GLIBC_2.3.3'

修改Makefile.target,

搜索 LIBS+=-lz,    添加一行  LIBS+=-lrt

LIBS+=-lz
LIBS+=-lrt

 https://cloud.tencent.com/developer/article/1599556

 sudo apt-get install libsdl1.2-dev

git://repo.or.cz/qemu/mini2440.git

git://repo.or.cz/u-boot-openmoko/mini2440.git

gcc-3.4.6-glibc-2.3.6

http://labfile.oss.aliyuncs.com/courses/811/gcc-3.4.6-glibc-2.3.6.tar.bz2

 https://www.cnblogs.com/youguorong/p/6853699.html

 https://blog.csdn.net/rickleaf/article/details/6215756

修改启动部分为ram的最小地址直接启动

ricky@ricky-laptop:~/ecos/projects/mini2440-qemu/mini2440$ git diff
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start addr
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*10
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start addre
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address,
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*102
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start addres
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_S
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, 
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)>
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, 
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-b
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f8000
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0)
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-b
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) >
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000))
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot 
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) 
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot rel
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size *
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded override u-boot (size %x)/n", image_size);
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot alrea
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) {
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot relocati
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded override u-boot (size %x)/n", image_size);
-                   s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;  /* start address, u-boot 
-               }
-       }
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relo
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) {
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot relocating code
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded override u-boot (size %x)/n", image_size);
-                   s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;  /* start address, u-boot already
-               }
-       }
-       /*
-        * if a kernel was explicitly specified, we load it too
-        */
-       if (s->kernel) {
-               image_size = load_image(s->kernel, qemu_get_ram_ptr(0x02000000));
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated 
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) {
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot relocating code */
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded override u-boot (size %x)/n", image_size);
-                   s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;  /* start address, u-boot already reloc
-               }
-       }
-       /*
-        * if a kernel was explicitly specified, we load it too
-        */
-       if (s->kernel) {
-               image_size = load_image(s->kernel, qemu_get_ram_ptr(0x02000000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated *
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) {
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot relocating code */
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded override u-boot (size %x)/n", image_size);
-                   s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;  /* start address, u-boot already reloca
-               }
-       }
-       /*
-        * if a kernel was explicitly specified, we load it too
-        */
-       if (s->kernel) {
-               image_size = load_image(s->kernel, qemu_get_ram_ptr(0x02000000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
:
diff --git a/hw/mini2440.c b/hw/mini2440.c
index 5decf4b..7a70aae 100644
--- a/hw/mini2440.c
+++ b/hw/mini2440.c
@@ -258,46 +258,15 @@ static void mini2440_reset(void *opaque)
     struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
     uint32_t image_size;
 
-       /*
-        * Normally we would load 4 KB of nand to SRAM and jump there, but
-        * it is not working perfectly as expected, so we cheat and load
-        * it from nand directly relocated to 0x33f80000 and jump there
-        */
-       if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
-               mini2440_printf("loaded default u-boot from NAND/n");
-               s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated *
-       }
-#if 0 && defined(LATER)
-       if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) {
-           s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT;     /* start address, u-boot relocating code */
-           mini2440_printf("4KB SteppingStone loaded from NAND/n");
-       }
-#endif
-       /*
-        * if a u--boot is available as a file, we always use it
-        */
-       {
-           image_size = load_image("mini2440/u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-           if (image_size < 0)
-                   image_size = load_image("u-boot.bin", qemu_get_ram_ptr(0x03f80000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded override u-boot (size %x)/n", image_size);
-                   s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;  /* start address, u-boot already reloca
-               }
-       }
-       /*
-        * if a kernel was explicitly specified, we load it too
-        */
-       if (s->kernel) {
-               image_size = load_image(s->kernel, qemu_get_ram_ptr(0x02000000));
-               if (image_size > 0) {
-                       if (image_size & (512 -1))      /* round size to a NAND block size */
-                               image_size = (image_size + 512) & ~(512-1);
-                       mini2440_printf("loaded %s (size %x)/n", s->kernel, image_size);
-           }
-       }
+    if (s->kernel) {
+       image_size = load_image(s->kernel, qemu_get_ram_ptr(0));
+       if (image_size > 0) {
+           if (image_size & (512 -1))  
+               image_size = (image_size + 512) & ~(512-1);            
+           s->cpu->env->regs[15] = S3C_RAM_BASE ;
+           mini2440_printf("loaded kernel %s at %p/n", s->kernel, s->cpu->env->regs[15]);
+       }
+    }
 }
 
 /* Typical touchscreen calibration values */
@@ -353,6 +322,11 @@ static struct mini2440_board_s *mini2440_init_common(int ram_size,
     return s;
 }
 
 
 static void mini2440_init(ram_addr_t ram_size,
         const char *boot_device,
@@ -371,9 +345,18 @@ static void mini2440_init(ram_addr_t ram_size,
     mini = mini2440_init_common(ram_size,
                     kernel_filename, cpu_model, sd);
 
       mini->nand = nand_init(NAND_MFR_SAMSUNG, 0x76);
     mini->cpu->nand->reg(mini->cpu->nand, mini->nand);
 
     mini2440_reset(mini);
 }
原文地址:https://www.cnblogs.com/sinferwu/p/13225151.html