作者信息

作者: 彭东林

邮箱:pengdonglin137@163.com

QQ:405728433

平台简介

开发板:tiny4412ADK + S700 + 4GB Flash

要移植的内核版本:Linux-4.4.0 (支持device tree)

u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动)

busybox版本:busybox 1.25

交叉编译工具链: arm-none-linux-gnueabi-gcc

(gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29))

注意

继续上文。

到目前为止,板子已经可以起来了,接下来就可以针对板子的情况移植驱动程序了。这个放在以后再做,下面是我折腾过程中得到的一些知识,分享一下。

一、设备树反编译

在内核目录下当我们执行make dtbs后,就会在arch/arm/boot/dts下生成一些.dtb文件,那这个文件里是什么东西呢?我们可以用dtc命令反编译这些dtb文件,这里的可执行程序dtc在Linux内核源码中已经提供了,具体路径是:scripts/dtc/,可以使用下面的命令从Linux源码中编译出这个工具:

make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm scripts

这样就会在scripts/dtc下生成可执行程序dtc。

当然,如果没有Linux源码,也可以使用apt-get命令安装这个工具,命令如下:

sudo apt-get install device-tree-compiler

下面以exynos4412-tiny4412.dtb为例:

命令:

dtc -I dtb -O dts -o tiny4412.dts arch/arm/boot/dts/exynos4412-tiny4412.dtb

然后就会生成反编译后的文件 tiny4412.dts,部分内容如下:

/dts-v1/;

/ {
#address-cells = <;0x1>;
#size-cells = <;0x1>;
interrupt-parent = <;0x1>;
compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";
model = "FriendlyARM TINY4412 board based on Exynos4412"; chosen {
stdout-path = "/serial@13800000";
bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init=/linuxrc earlyprintk";
}; aliases {
spi0 = "/spi@13920000";
spi1 = "/spi@13930000";
spi2 = "/spi@13940000";
i2c0 = "/i2c@13860000";
i2c1 = "/i2c@13870000";
i2c2 = "/i2c@13880000";
i2c3 = "/i2c@13890000";
i2c4 = "/i2c@138A0000";
i2c5 = "/i2c@138B0000";
i2c6 = "/i2c@138C0000";
i2c7 = "/i2c@138D0000";
i2c8 = "/i2c@138E0000";
csis0 = "/camera/csis@11880000";
csis1 = "/camera/csis@11890000";
fimc0 = "/camera/fimc@11800000";
fimc1 = "/camera/fimc@11810000";
fimc2 = "/camera/fimc@11820000";
fimc3 = "/camera/fimc@11830000";
serial0 = "/serial@13800000";
serial1 = "/serial@13810000";
serial2 = "/serial@13820000";
serial3 = "/serial@13830000";
pinctrl0 = "/pinctrl@11400000";
pinctrl1 = "/pinctrl@11000000";
pinctrl2 = "/pinctrl@03860000";
pinctrl3 = "/pinctrl@106E0000";
fimc-lite0 = "/camera/fimc-lite@12390000";
fimc-lite1 = "/camera/fimc-lite@123A0000";
mshc0 = "/mmc@12550000";
}; memory {
device_type = "memory";
reg = <0x40000000 0x40000000>;
}; clock-controller@03810000 {
compatible = "samsung,exynos4210-audss-clock";
reg = <0x3810000 0xc>;
#clock-cells = <;0x1>;
linux,phandle = <;0x2>;
phandle = <;0x2>;
};
i2s@03830000 {
这个方法对于学习设备树很有帮助。

二、在u-boot打印信息

在u-boot中很多文件中是通过debug(… …)来打印信息,默认情况下这些log是打印不出来的。这个函数的定义是在include/common.h中:

#ifdef DEBUG
#define debug(fmt,args...)    printf (fmt ,##args)
#define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args);
#else
#define debug(fmt,args...)
#define debugX(level,fmt,args...)
#endif /* DEBUG */
所以可以在调用debug函数的C文件的最上面添加  #define DEBUG  即可。这个方法在Linux内核以及Android当中也很常用。

三、打开Linux内核启动早期的log

有时会遇到当在u-boot中执行完bootm后,打印出start kernel后串口就没有再输出任何信息了。此时就需要打开内核早期的log:

make menuconfig

Kernel hacking  --->

[*] Kernel low-level debugging functions (read help!)

Kernel low-level debugging port (Use Samsung S3C UART 0 for low-level debug)

[*] Early printk

对于earlyprintk,还需要在bootargs中添加参数earlyprintk才能生效,有了上面这几个配置,会有下面几个宏生效:

CONFIG_DEBUG_LL=y

CONFIG_DEBUG_S3C_UART0=y

CONFIG_DEBUG_LL_INCLUDE="debug/exynos.S"

CONFIG_DEBUG_UNCOMPRESS=y
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
CONFIG_EARLY_PRINTK=y

关于earlyprintk的解析在文件arch/arm/kernel/early_printk.c中:

   1: extern void printch(int);

   2: 

   3: static void early_write(const char *s, unsigned n)

   4: {

   5:     while (n-- >; 0) {

   6:         if (*s == '\n')

   7:             printch('\r');

   8:         printch(*s);

   9:         s++;

  10:     }

  11: }

  12:  

  13: static void early_console_write(struct console *con, const char *s, unsigned n)

  14: {

  15:     early_write(s, n);

  16: }

  17:  

  18: static struct console early_console_dev = {

  19:     .name =        "earlycon",

  20:     .write =    early_console_write,

  21:     .flags =    CON_PRINTBUFFER | CON_BOOT,

  22:     .index =    -1,

  23: };

  24: 

  25: static int __init setup_early_printk(char *buf)

  26: {

  27:     early_console = &;early_console_dev;

  28:     register_console(&;early_console_dev);

  29:     return 0;

  30: }

  31:  

  32: early_param("earlyprintk", setup_early_printk);

其中printch都是通过汇编语言实现的。

在arch/arm/Kconfig.debug中可以看到:

config DEBUG_LL
    bool "Kernel low-level debugging functions (read help!)"
    depends on DEBUG_KERNEL
    help
      Say Y here to include definitions of printascii, printch, printhex
      in the kernel.  This is helpful if you are debugging code that
      executes before the console is initialized
.

config DEBUG_S3C_UART0
    depends on PLAT_SAMSUNG
    select DEBUG_EXYNOS_UART if ARCH_EXYNOS
    select DEBUG_S3C24XX_UART if ARCH_S3C24XX
    select DEBUG_S5PV210_UART if ARCH_S5PV210
    bool "Use Samsung S3C UART 0 for low-level debug"
    help
      Say Y here if you want the debug print routines to direct
      their output to UART 0. The port must have been initialised
      by the boot-loader before use.

config DEBUG_LL_INCLUDE
    string
    ……
    default "debug/exynos.S" if DEBUG_EXYNOS_UART

config EARLY_PRINTK
    bool "Early printk"
    depends on DEBUG_LL
    help
      Say Y here if you want to have an early console using the
      kernel low-level debugging functions. Add earlyprintk to your
      kernel parameters to enable this console.

从上面的信息我们可以知道:

  • 在串口终端尚未注册时,内核定义了printascii、printch以及printhex用于调试;
  • early console使用的也是上面定义的函数,需要在传递给内核的参数中添加earlyprintk参数
  • Linux内核早期的print函数的输出串口要跟u-boot下使用的一致,即内核不再负责初始化了,让u-boot来做,所以二者一定要一致,否则那些print函数以及earlyprintk都没法输出信息;
  • 可以参考arch/arm/kernel/debug.S,printascii、printch以及printhex都是在这里定义的;
  • 在kernel进入C函数(start_kernel)后可以调用early_print来打印信息,它是在arch/arm/kernel/setup.c中定义的:
   1: void __init early_print(const char *str, ...)

   2: {

   3:     extern void printascii(const char *);

   4:     char buf[256];

   5:     va_list ap;

   6: 

   7:     va_start(ap, str);

   8:     vsnprintf(buf, sizeof(buf), str, ap);

   9:     va_end(ap);

  10:  

  11: #ifdef CONFIG_DEBUG_LL

  12:     printascii(buf);

  13: #endif

  14:     printk("%s", buf);

  15: }

可以看到,early_print也会调用printascii和printk,意思是用early_print打印的信息可能会重复出现在终端上(printk会缓冲一部分,当bootconsole注册后,会将printk缓冲区中的内容输出)。

上面所说的打印函数只能在内核自解压后的函数中才能使用,那么内核自解压过程中的信息是不是也可以打印呢?可以,内核自解压相关的文件在arch/arm/boot/compressed/下面,我们所熟知的:

Uncompressing Linux... done, booting the kernel.

就是这个目录下的代码打印出来的,具体代码如下:

arch/arm/boot/compressed/misc.c

   1: void

   2: decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,

   3:         unsigned long free_mem_ptr_end_p,

   4:         int arch_id)

   5: {

   6:     ......

   7:     putstr("Uncompressing Linux...");

   8:     ret = do_decompress(input_data, input_data_end - input_data,

   9:                 output_data, error);

  10:     ......

  11:     putstr(" done, booting the kernel.\n");

  12: }

其中,putstr的定义如下:

   1: static void putstr(const char *ptr)

   2: {

   3:     char c;

   4: 

   5:     while ((c = *ptr++) != '\0') {

   6:         if (c == '\n')

   7:             putc('\r');

   8:         putc(c);

   9:     }

  10:  

  11:     flush();

  12: }

putc是汇编实现的,arch/arm/boot/compressed/debug.S:

   1: #include CONFIG_DEBUG_LL_INCLUDE

   2:  

   3: ENTRY(putc)

   4:     addruart r1, r2, r3

   5:     waituart r3, r1

   6:     senduart r0, r1

   7:     busyuart r3, r1

   8:     mov     pc, lr

   9: ENDPROC(putc)

  10:  

  11:  

其中addruart的实现因soc的不同而不同,对于exynos4412,它的实现是(arch/arm/include/debug/exynos.S):

   1: .macro addruart, rp, rv, tmp

   2:     mrc    p15, 0, \tmp, c0, c0, 0

   3:     and    \tmp, \tmp, #0xf0

   4:     teq    \tmp, #0xf0        @@ A15

   5:     ldreq    \rp, =EXYNOS5_PA_UART

   6:     movne    \rp, #EXYNOS4_PA_UART    @@ EXYNOS4

   7:     ldr    \rv, =S3C_VA_UART

   8: CONFIG_DEBUG_S3C_UART != 0

   9:     add    \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)

  10:     add    \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)

  11: if

  12: .endm

这个函数的目的就是获得控制调试uart的寄存器的物理基地址(rp)和虚拟基地址(rv),这里也没有初始化uart的代码,所以必须跟u-boot使用的串口一致。

四、在内核自解压时dump内存

这是在调试设备树在内存中的镜像被自解压后的内核覆盖时发现的。下面是使用方法:

  • 首先需要按照上面的一节配置内核打开那几个宏
  • 修改arch/arm/boot/compressed/head.S,如下:
   1: diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S

   2: index 06e983f..7ecde2e 100644

   3: --- a/arch/arm/boot/compressed/head.S

   4: +++ b/arch/arm/boot/compressed/head.S

   5: @@ -22,6 +22,8 @@

   6:   * 100% relocatable.  Any attempt to do so will result in a crash.

   7:   * Please select one of the following when turning on debugging.

   8:   */

   9: +#define DEBUG

  10: +

  11:  #ifdef DEBUG

  12:  

  13:  #if defined(CONFIG_DEBUG_ICEDCC)

  14: @@ -65,7 +67,7 @@

  15:          .endm

  16:  #else

  17:          .macro    loadsp,    rb, tmp

  18: -        addruart \rb, \tmp

  19: +        addruart \rb, \tmp, \tmp

  20:          .endm

  21:  #endif

  22:  #endif

  23: @@ -536,6 +538,24 @@ not_relocated:    mov    r0, #0

  24:   *   r7  = architecture ID

  25:   *   r8  = atags pointer

  26:   */

  27: +        stmfd    sp!, {r0-r3, r10-r12, lr}

  28: +        kputc    #'\n'

  29: +        kputc    #'a'

  30: +        kputc    #'t'

  31: +        kputc    #'a'

  32: +        kputc    #'g'

  33: +        kputc    #'s'

  34: +        kputc    #':'

  35: +        kputc    #' '

  36: +        kputc    #'0'

  37: +        kputc    #'x'

  38: +        kphex    r8, 8        /* atags pointer */

  39: +        kputc    #'\n'

  40: +        mov    r0, r8

  41: +        bl    memdump        /* dump 256 bytes at start of kernel */

  42: +        kputc    #'\n'

  43: +        ldmfd    sp!, {r0-r3, r10-r12, lr}

  44: +

  45:          mov    r0, r4

  46:          mov    r1, sp            @ malloc space above stack

  47:          add    r2, sp, #0x10000    @ 64k max

  48: @@ -546,6 +566,26 @@ not_relocated:    mov    r0, #0

  49:          mov    r1, r7            @ restore architecture number

  50:          mov    r2, r8            @ restore atags pointer

  51:  

  52: +        stmfd    sp!, {r0-r3, r10-r12, lr}

  53: +        kputc    #'\n'

  54: +        kputc    #'\n'

  55: +        kputc    #'a'

  56: +        kputc    #'t'

  57: +        kputc    #'a'

  58: +        kputc    #'g'

  59: +        kputc    #'s'

  60: +        kputc    #':'

  61: +        kputc    #' '

  62: +        kputc    #'0'

  63: +        kputc    #'x'

  64: +        kphex    r8, 8        /* atags pointer */

  65: +        kputc    #'\n'

  66: +        mov    r0, r8

  67: +        bl    memdump        /* dump 256 bytes at start of kernel */

  68: +        kputc    #'\n'

  69: +        ldmfd    sp!, {r0-r3, r10-r12, lr}

  70: +

  71: +

  72:  #ifdef CONFIG_ARM_VIRT_EXT

  73:          mrs    r0, spsr        @ Get saved CPU boot mode

  74:          and    r0, r0, #MODE_MASK

可以使用kputc打印出一个字符,kphex用于打印一个指定位宽的十六进制数,将需要dump的内粗地址存放入r0,然后调用memdump即可,memdump会dump出256B的内容。u-boot在跳转到内核的时候传递三个参数,分别给了r0、r1、r2,在没有设备树之前,传给r0,r1和r2的分别是0,machid以及u-boot传给Linux内核参数的地址(如0x40000100),在有了设备树之后,传给r0的是0,传给r1的值无所谓,传给r2的是设备树镜像在内存中的地址。效果如下:

U-Boot 2010.12-00000-gb391276-dirty (Jan 17 2016 - 06:03:22) for TINY4412

 

 

CPU:    S5PC220 [Samsung SOC on SMP Platform Base on ARM CortexA9]

        APLL = 1400MHz, MPLL = 800MHz

 

Board:  TINY4412

DRAM:   1023 MiB

 

vdd_arm: 1.2

vdd_int: 1.0

vdd_mif: 1.1

 

BL1 version:  N/A (TrustZone Enabled BSP)

 

 

Checking Boot Mode ... SDMMC

REVISION: 1.1

MMC Device 0: 3803 MB

MMC Device 1: 3728 MB

MMC Device 2: N/A

*** Warning - using default environment

 

Net:    No ethernet found.

Hit any key to stop autoboot:  0 

TINY4412 # 

TINY4412 # dnw 0x40000000

OTG cable Connected!

Now, Waiting for DNW to transmit data

Download Done!! Download Address: 0x40000000, Download Filesize:0x43bde8

Checksum is being calculated.....

Checksum O.K.

TINY4412 # dnw  0x41000000

OTG cable Connected!

Now, Waiting for DNW to transmit data

Download Done!! Download Address: 0x41000000, Download Filesize:0x27752e

Checksum is being calculated...

Checksum O.K.

TINY4412 # dnw 0x42000000

OTG cable Connected!

Now, Waiting for DNW to transmit data

Download Done!! Download Address: 0x42000000, Download Filesize:0xa53a

Checksum is being calculated.

Checksum O.K.

TINY4412 # bootm 0x40000000 0x41000000 0x42000000

## Booting kernel from Legacy Image at 40000000 ...

   Image Name:   Linux-4.4.0-gbd49c0f-dirty

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    4439464 Bytes = 4335 KiB

   Load Address: 40008000

   Entry Point:  40008000

   Verifying Checksum ... OK

## Loading init Ramdisk from Legacy Image at 41000000 ...

   Image Name:   ramdisk

   Image Type:   ARM Linux RAMDisk Image (gzip compressed)

   Data Size:    2585838 Bytes = 2525 KiB

   Load Address: 00000000

   Entry Point:  00000000

   Verifying Checksum ... OK

## Flattened Device Tree blob at 42000000

   Booting using the fdt blob at 0x42000000

   Loading Kernel Image ... OK

OK

## Loading init Ramdisk from Legacy Image at 41000000 ...

   Image Name:   ramdisk

   Image Type:   ARM Linux RAMDisk Image (gzip compressed)

   Data Size:    2585838 Bytes = 2525 KiB

   Load Address: 00000000

   Entry Point:  00000000

   Verifying Checksum ... OK

   Loading Ramdisk to 43a84000, end 43cfb4ee ... OK

   Loading Device Tree to 413f2000, end 413ff539 ... OK

 

Starting kernel ...

 

 

atags: 0x413F2000

413F2000: EDFE0DD0 3AD50000 48000000 849E0000  28000000 11000000 10000000 00000000

413F2020: 22070000 3C9E0000 00000000 0040A843  00000000 EF742700 00000000 00000000

413F2040: 00000000 00000000 01000000 00000000  03000000 04000000 00000000 01000000

413F2060: 03000000 04000000 0F000000 01000000  03000000 04000000 1B000000 01000000

413F2080: 03000000 38000000 2C000000 65697266  796C646E 2C6D7261 796E6974 32313434

413F20A0: 6D617300 676E7573 7978652C 34736F6E  00323134 736D6173 2C676E75 6E797865

413F20C0: 0034736F 03000000 2F000000 37000000  65697246 796C646E 204D5241 594E4954

413F20E0: 32313434 616F6220 62206472 64657361  206E6F20 6E797845 3434736F 00003231

 

Uncompressing Linux... done, booting the kernel.

 

 

atags: 0x413F2000

413F2000: EDFE0DD0 3AD50000 48000000 849E0000  28000000 11000000 10000000 00000000

413F2020: 22070000 3C9E0000 00000000 0040A843  00000000 EF742700 00000000 00000000

413F2040: 00000000 00000000 01000000 00000000  03000000 04000000 00000000 01000000

413F2060: 03000000 04000000 0F000000 01000000  03000000 04000000 1B000000 01000000

413F2080: 03000000 38000000 2C000000 65697266  796C646E 2C6D7261 796E6974 32313434

413F20A0: 6D617300 676E7573 7978652C 34736F6E  00323134 736D6173 2C676E75 6E797865

413F20C0: 0034736F 03000000 2F000000 37000000  65697246 796C646E 204D5241 594E4954

413F20E0: 32313434 616F6220 62206472 64657361  206E6F20 6E797845 3434736F 00003231

 

[    0.000000] Booting Linux on physical CPU 0xa00

[    0.000000] Linux version 4.4.0-gbd49c0f-dirty (root@ubuntu) (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29) ) #25 SMP PREEMPT Tue Jan 19 05:50:47 PST 2016

[    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d

[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache

[    0.000000] Machine model: FriendlyARM TINY4412 board based on Exynos4412

[    0.000000] bootconsole [earlycon0] enabled

[    0.000000] cma: Reserved 64 MiB at 0x7bc00000

[    0.000000] Memory policy: Data cache writealloc

[    0.000000] Samsung CPU ID: 0xe4412011

[    0.000000] PERCPU: Embedded 12 pages/cpu @ef79b000 s18816 r8192 d22144 u49152

[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 260352

[    0.000000] Kernel command line: root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init=/linuxrc earlyprintk

[    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)

[    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)

[    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)

[    0.000000] Memory: 960824K/1047552K available (5867K kernel code, 293K rwdata, 2288K rodata, 440K init, 315K bss, 21192K reserved, 65536K cma-reserved, 195584K highmem)

[    0.000000] Virtual kernel memory layout:

[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)

[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)

[    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)

[    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)

[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)

[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)

[    0.000000]       .text : 0xc0008000 - 0xc07ff200   (8157 kB)

[    0.000000]       .init : 0xc0800000 - 0xc086e000   ( 440 kB)

[    0.000000]       .data : 0xc086e000 - 0xc08b7418   ( 294 kB)

[    0.000000]        .bss : 0xc08ba000 - 0xc0908d28   ( 316 kB)

可以看到 Uncompressing Linux... done, booting the kernel.前后就是dump出的设备树的内容(大小端 可能有些问题).

五、CONFIG_ARM_APPENDED_DTB

这个宏是Linux内核中的,它的作用是支持zImage+dtb的启动方式。为什么要有种方式呢?因为很多厂家都有自己的bootloader,但是这些bootloader并不都一定支持设备树,为了实现支持设备树启动,就引入了这种启动方式,即将编译出的zImage和编译出的设备树镜像文件拼成一个新的镜像,在内核的自解压代码中会识别到,不会出现自解压时导致设备树被覆盖,具体实现如下(arch/arm/boot/compressed/head.S)

mov    r5, #0            @ init dtb size to 0

#ifdef CONFIG_ARM_APPENDED_DTB

/*

*   r0  = delta

*   r2  = BSS start

*   r3  = BSS end

*   r4  = final kernel address (possibly with LSB set)

*   r5  = appended dtb size (still unknown)

*   r6  = _edata

*   r7  = architecture ID

*   r8  = atags/device tree pointer

*   r9  = size of decompressed image

*   r10 = end of this image, including  bss/stack/malloc space if non XIP

*   r11 = GOT start

*   r12 = GOT end

*   sp  = stack pointer

*

* if there are device trees (dtb) appended to zImage, advance r10 so that the

* dtb data will get relocated along with the kernel if necessary.

*/

 

ldr    lr, [r6, #0]

#ifndef __ARMEB__

ldr    r1, =0xedfe0dd0        @ sig is 0xd00dfeed big endian

#else

ldr    r1, =0xd00dfeed

#endif

cmp    lr, r1

bne    dtb_check_done        @ not found

 

#ifdef CONFIG_ARM_ATAG_DTB_COMPAT

/*

 * OK... Let's do some funky business here.

 * If we do have a DTB appended to zImage, and we do have

 * an ATAG list around, we want the later to be translated

 * and folded into the former here. No GOT fixup has occurred

 * yet, but none of the code we're about to call uses any

 * global variable.

*/

 

/* Get the initial DTB size */

ldr    r5, [r6, #4]

#ifndef __ARMEB__

/* convert to little endian */

eor    r1, r5, r5, ror #16

bic    r1, r1, #0x00ff0000

mov    r5, r5, ror #8

eor    r5, r5, r1, lsr #8

#endif

/* 50% DTB growth should be good enough */

add    r5, r5, r5, lsr #1

/* preserve 64-bit alignment */

add    r5, r5, #7

bic    r5, r5, #7

/* clamp to 32KB min and 1MB max */

cmp    r5, #(1 <;< 15)

movlo    r5, #(1 <;< 15)

cmp    r5, #(1 <;< 20)

movhi    r5, #(1 <;< 20)

/* temporarily relocate the stack past the DTB work space */

add    sp, sp, r5

 

stmfd    sp!, {r0-r3, ip, lr}

mov    r0, r8

mov    r1, r6

mov    r2, r5

bl    atags_to_fdt

 

/*

 * If returned value is 1, there is no ATAG at the location

 * pointed by r8.  Try the typical 0x100 offset from start

 * of RAM and hope for the best.

 */

cmp    r0, #1

sub    r0, r4, #TEXT_OFFSET

bic    r0, r0, #1

add    r0, r0, #0x100

mov    r1, r6

mov    r2, r5

bleq    atags_to_fdt

 

ldmfd    sp!, {r0-r3, ip, lr}

sub    sp, sp, r5

#endif

 

mov    r8, r6            @ use the appended device tree

 

/*

 * Make sure that the DTB doesn't end up in the final

 * kernel's .bss area. To do so, we adjust the decompressed

 * kernel size to compensate if that .bss size is larger

 * than the relocated code.

 */

ldr    r5, =_kernel_bss_size

adr    r1, wont_overwrite

sub    r1, r6, r1

subs    r1, r5, r1

addhi    r9, r9, r1

 

/* Get the current DTB size */

ldr    r5, [r6, #4]

#ifndef __ARMEB__

/* convert r5 (dtb size) to little endian */

eor    r1, r5, r5, ror #16

bic    r1, r1, #0x00ff0000

mov    r5, r5, ror #8

eor    r5, r5, r1, lsr #8

#endif

 

/* preserve 64-bit alignment */

add    r5, r5, #7

bic    r5, r5, #7

 

/* relocate some pointers past the appended dtb */

add    r6, r6, r5

add    r10, r10, r5

add    sp, sp, r5

dtb_check_done:

#endif

拼接方法:

cat zImage dts/exynos4412-tiny4412.dtb > dtbImage

也可以修改内核编译系统,在编译完成后自动实现拼接,可以参考下面的博文实现:

http://www.cnblogs.com/pengdonglin137/p/5134364.html

下面是使用dtbImage启动的方法:

1、修改设备树 arch/arm/boot/dts/exynos4412-tiny4412.dts

diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts

index 4840bbd..1e33ede 100644

--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts

+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts

@@ -21,6 +21,7 @@

 

        chosen {

                stdout-path = &;serial_0;

+               bootargs = "root=/dev/ram0 rw rootfstype=ext4 ramdisk=8192 initrd=0x41000000,8M console=ttySAC0,115200 init=/linuxrc mem=1024M"

        };


        memory {

@@ -78,7 +79,7 @@

        bus-width = <;4>;

        pinctrl-0 = <;&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;

        pinctrl-names = "default";

-       status = "okay";

+       status = "disabled";

 };

 

 &;serial_0 {

2、编译设备树 make dtbs,将生成的.dtb跟zImag拼接起来生成dtbImage

3、使用ramdisk启动,目前不能使用ramdisk.img,还不知道为什么。

4、启动开发板,进入u-boot命令行模式,执行如下命令:

在u-boot里执行下载dtbImage的命令: dnw 0x40008000

在开发机上执行: dnw dtbImage

在u-boot里执行下载ramdisk的命令:dnw 0x41000000

在开发机上执行: dnw ramdisk

启动内核: bootm 0x40008000   (u-boot不识别未压缩的ramdisk,ramdisk的地址在bootargs中指定为0x41000000,而且上面我们已经把ramdisk下载到0x41000000了)

下面是完整的log:

U-Boot 2010.12-00000-gb391276-dirty (Jan 17 2016 - 06:03:22) for TINY4412

 

 

CPU:    S5PC220 [Samsung SOC on SMP Platform Base on ARM CortexA9]

        APLL = 1400MHz, MPLL = 800MHz

 

Board:  TINY4412

DRAM:   1023 MiB

 

vdd_arm: 1.2

vdd_int: 1.0

vdd_mif: 1.1

 

BL1 version:  N/A (TrustZone Enabled BSP)

 

 

Checking Boot Mode ... SDMMC

REVISION: 1.1

MMC Device 0: 3803 MB

MMC Device 1: 3728 MB

MMC Device 2: N/A

*** Warning - using default environment

 

Net:    No ethernet found.

Hit any key to stop autoboot:  0 

TINY4412 # dnw 0x40008000

OTG cable Connected!

Now, Waiting for DNW to transmit data

Download Done!! Download Address: 0x40008000, Download Filesize:0x446302

Checksum is being calculated.....

Checksum O.K.

TINY4412 # dnw 0x41000000

OTG cable Connected!

Now, Waiting for DNW to transmit data

Download Done!! Download Address: 0x41000000, Download Filesize:0x800000

Checksum is being calculated.........

Checksum O.K.

TINY4412 # bootm 0x40008000

Boot with zImage

 

Starting kernel ...

 

 

atags: 0x40CF68E8

40CF68E8: EDFE0DD0 72A50000 38000000 749E0000  28000000 11000000 10000000 00000000

40CF6908: FE060000 3C9E0000 00000000 00000000  00000000 00000000 01000000 00000000

40CF6928: 03000000 04000000 00000000 01000000  03000000 04000000 0F000000 01000000

40CF6948: 03000000 04000000 1B000000 01000000  03000000 38000000 2C000000 65697266

40CF6968: 796C646E 2C6D7261 796E6974 32313434  6D617300 676E7573 7978652C 34736F6E

40CF6988: 00323134 736D6173 2C676E75 6E797865  0034736F 03000000 2F000000 37000000

40CF69A8: 65697246 796C646E 204D5241 594E4954  32313434 616F6220 62206472 64657361

40CF69C8: 206E6F20 6E797845 3434736F 00003231  01000000 736F6863 00006E65 03000000

 

Uncompressing Linux... done, booting the kernel.

 

 

atags: 0x40CF68E8

40CF68E8: EDFE0DD0 72A50000 38000000 749E0000  28000000 11000000 10000000 00000000

40CF6908: FE060000 3C9E0000 00000000 00000000  00000000 00000000 01000000 00000000

40CF6928: 03000000 04000000 00000000 01000000  03000000 04000000 0F000000 01000000

40CF6948: 03000000 04000000 1B000000 01000000  03000000 38000000 2C000000 65697266

40CF6968: 796C646E 2C6D7261 796E6974 32313434  6D617300 676E7573 7978652C 34736F6E

40CF6988: 00323134 736D6173 2C676E75 6E797865  0034736F 03000000 2F000000 37000000

40CF69A8: 65697246 796C646E 204D5241 594E4954  32313434 616F6220 62206472 64657361

40CF69C8: 206E6F20 6E797845 3434736F 00003231  01000000 736F6863 00006E65 03000000

 

[    0.000000] Booting Linux on physical CPU 0xa00

[    0.000000] Linux version 4.4.0-gbd49c0f-dirty (root@ubuntu) (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29) ) #25 SMP PREEMPT Tue Jan 19 05:50:47 PST 2016

[    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d

[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache

[    0.000000] Machine model: FriendlyARM TINY4412 board based on Exynos4412

[    0.000000] cma: Reserved 64 MiB at 0x7c000000

[    0.000000] Memory policy: Data cache writealloc

[    0.000000] Samsung CPU ID: 0xe4412011

[    0.000000] PERCPU: Embedded 12 pages/cpu @ef79b000 s18816 r8192 d22144 u49152

[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 260608

[    0.000000] Kernel command line: root=/dev/ram0 rw rootfstype=ext4 ramdisk=8192 initrd=0x41000000,8M console=ttySAC0,115200 init=/linuxrc mem=1024M

[    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)

[    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)

[    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)

[    0.000000] Memory: 956196K/1048576K available (5867K kernel code, 293K rwdata, 2288K rodata, 440K init, 315K bss, 26844K reserved, 65536K cma-reserved, 196608K highmem)

[    0.000000] Virtual kernel memory layout:

[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)

[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)

[    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)

[    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)

[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)

[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)

[    0.000000]       .text : 0xc0008000 - 0xc07ff200   (8157 kB)

[    0.000000]       .init : 0xc0800000 - 0xc086e000   ( 440 kB)

[    0.000000]       .data : 0xc086e000 - 0xc08b7418   ( 294 kB)

[    0.000000]        .bss : 0xc08ba000 - 0xc0908d28   ( 316 kB)

[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1

[    0.000000] Preemptible hierarchical RCU implementation.

[    0.000000]  Build-time adjustment of leaf fanout to 32.

[    0.000000]  RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.

[    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=32, nr_cpu_ids=4

[    0.000000] NR_IRQS:16 nr_irqs:16 16

[    0.000000] GIC physical location is 0x10490000

[    0.000000] L2C: platform modifies aux control register: 0x02070000 ->; 0x3e470001

[    0.000000] L2C: platform provided aux values permit register corruption.

[    0.000000] L2C: DT/platform modifies aux control register: 0x02070000 ->; 0x3e470001

[    0.000000] L2C-310 enabling early BRESP for Cortex-A9

[    0.000000] L2C-310: enabling full line of zeros but not enabled in Cortex-A9

[    0.000000] L2C-310 dynamic clock gating enabled, standby mode enabled

[    0.000000] L2C-310 cache controller enabled, 16 ways, 1024 kB

[    0.000000] L2C-310: CACHE_ID 0x4100c4c8, AUX_CTRL 0x4e470001

[    0.000000] Exynos4x12 clocks: sclk_apll = 466666667, sclk_mpll = 800000000

[    0.000000]  sclk_epll = 96000000, sclk_vpll = 108000000, arm_clk = 1400000000

[    0.000000] Switching to timer-based delay loop, resolution 41ns

[    0.000000] clocksource: mct-frc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns

[    0.000003] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns

[    0.000122] Console: colour dummy device 80x30

[    0.000135] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=120000)

[    0.000144] pid_max: default: 32768 minimum: 301

[    0.000209] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)

[    0.000217] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)

[    0.000586] CPU: Testing write buffer coherency: ok

[    0.000772] CPU0: thread -1, cpu 0, socket 10, mpidr 80000a00

[    0.000999] Setting up static identity map for 0x400082c0 - 0x40008318

[    0.045048] CPU1: thread -1, cpu 1, socket 10, mpidr 80000a01

[    0.060041] CPU2: thread -1, cpu 2, socket 10, mpidr 80000a02

[    0.075042] CPU3: thread -1, cpu 3, socket 10, mpidr 80000a03

[    0.075082] Brought up 4 CPUs

[    0.075096] SMP: Total of 4 processors activated (192.00 BogoMIPS).

[    0.075101] CPU: All CPU(s) started in SVC mode.

[    0.075611] devtmpfs: initialized

[    0.084566] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4

[    0.084839] lcd0-power-domain@10023C80 has as child subdomain: tv-power-domain@10023C20.

[    0.085225] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 9556302231375000 ns

[    0.087164] pinctrl core: initialized pinctrl subsystem

[    0.087929] NET: Registered protocol family 16

[    0.089226] DMA: preallocated 256 KiB pool for atomic coherent allocations

[    0.105005] cpuidle: using governor ladder

[    0.120000] cpuidle: using governor menu

[    0.120747] exynos-audss-clk 3810000.clock-controller: setup completed

[    0.157138] SCSI subsystem initialized

[    0.157506] usbcore: registered new interface driver usbfs

[    0.157580] usbcore: registered new interface driver hub

[    0.157660] usbcore: registered new device driver usb

[    0.158780] Advanced Linux Sound Architecture Driver Initialized.

[    0.159857] clocksource: Switched to clocksource mct-frc

[    0.169153] missing cooling_device property

[    0.169163] failed to build thermal zone cpu-thermal: -2

[    0.169260] NET: Registered protocol family 2

[    0.169627] TCP established hash table entries: 8192 (order: 3, 32768 bytes)

[    0.169686] TCP bind hash table entries: 8192 (order: 5, 163840 bytes)

[    0.169803] TCP: Hash tables configured (established 8192 bind 8192)

[    0.169921] UDP hash table entries: 512 (order: 2, 24576 bytes)

[    0.169950] UDP-Lite hash table entries: 512 (order: 2, 24576 bytes)

[    0.170092] NET: Registered protocol family 1

[    0.170297] RPC: Registered named UNIX socket transport module.

[    0.170305] RPC: Registered udp transport module.

[    0.170310] RPC: Registered tcp transport module.

[    0.170315] RPC: Registered tcp NFSv4.1 backchannel transport module.

[    0.170461] Trying to unpack rootfs image as initramfs...

[    0.170628] rootfs image is not initramfs (junk in compressed archive); looks like an initrd

[    0.193515] Freeing initrd memory: 8192K (c1000000 - c1800000)

[    0.194996] futex hash table entries: 1024 (order: 4, 65536 bytes)

[    0.204233] romfs: ROMFS MTD (C) 2007 Red Hat, Inc.

[    0.204924] bounce: pool size: 64 pages

[    0.204936] io scheduler noop registered

[    0.204945] io scheduler deadline registered

[    0.205116] io scheduler cfq registered (default)

[    0.209955] dma-pl330 12680000.pdma: Loaded driver for PL330 DMAC-141330

[    0.209967] dma-pl330 12680000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32

[    0.213022] dma-pl330 12690000.pdma: Loaded driver for PL330 DMAC-141330

[    0.213032] dma-pl330 12690000.pdma:         DBUFF-32x4bytes Num_Chans-8 Num_Peri-32 Num_Events-32

[    0.213909] dma-pl330 12850000.mdma: Loaded driver for PL330 DMAC-141330

[    0.213919] dma-pl330 12850000.mdma:         DBUFF-64x8bytes Num_Chans-8 Num_Peri-1 Num_Events-32

[    0.271176] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled

[    0.272413] 13800000.serial: ttySAC0 at MMIO 0x13800000 (irq = 44, base_baud = 0) is a S3C6400/10

[    0.908554] console [ttySAC0] enabled

[    0.912530] 13810000.serial: ttySAC1 at MMIO 0x13810000 (irq = 45, base_baud = 0) is a S3C6400/10

[    0.921327] 13820000.serial: ttySAC2 at MMIO 0x13820000 (irq = 46, base_baud = 0) is a S3C6400/10

[    0.930171] 13830000.serial: ttySAC3 at MMIO 0x13830000 (irq = 47, base_baud = 0) is a S3C6400/10

[    0.939720] [drm] Initialized drm 1.1.0 20060810

[    0.953371] brd: module loaded

[    0.958359] loop: module loaded

[    0.959171] usbcore: registered new interface driver r8152

[    0.959302] usbcore: registered new interface driver asix

[    0.960434] usbcore: registered new interface driver ax88179_178a

[    0.966498] usbcore: registered new interface driver cdc_ether

[    0.972325] usbcore: registered new interface driver dm9601

[    0.977884] usbcore: registered new interface driver smsc75xx

[    0.983611] usbcore: registered new interface driver smsc95xx

[    0.989325] usbcore: registered new interface driver net1080

[    0.994965] usbcore: registered new interface driver cdc_subset

[    1.000873] usbcore: registered new interface driver zaurus

[    1.006454] usbcore: registered new interface driver cdc_ncm

[    1.012397] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver

[    1.018528] ehci-exynos: EHCI EXYNOS driver

[    1.022808] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver

[    1.028850] ohci-exynos: OHCI EXYNOS driver

[    1.033363] usbcore: registered new interface driver usb-storage

[    1.039544] mousedev: PS/2 mouse device common for all mice

[    1.045326] s3c-rtc 10070000.rtc: failed to find rtc source clock

[    1.050645] s3c-rtc: probe of 10070000.rtc failed with error -2

[    1.056739] i2c /dev entries driver

[    1.062046] device-mapper: ioctl: 4.34.0-ioctl (2015-10-28) initialised: dm-devel@redhat.com

[    1.069226] sdhci: Secure Digital Host Controller Interface driver

[    1.074585] sdhci: Copyright(c) Pierre Ossman

[    1.079056] Synopsys Designware Multimedia Card Interface Driver

[    1.086865] usbcore: registered new interface driver usbhid

[    1.090471] usbhid: USB HID core driver

[    1.097222] NET: Registered protocol family 10

[    1.099233] sit: IPv6 over IPv4 tunneling driver

[    1.103848] NET: Registered protocol family 17

[    1.107765] NET: Registered protocol family 15

[    1.112340] Registering SWP/SWPB emulation handler

[    1.118177] hctosys: unable to open rtc device (rtc0)

[    1.134172] ALSA device list:

[    1.134208]   No soundcards found.

[    1.134917] RAMDISK: ext2 filesystem found at block 0

[    1.134972] RAMDISK: Loading 8192KiB [1 disk] into ram disk... done.

[    1.262918] EXT4-fs (ram0): mounted filesystem with red data mode. Opts: (null)

[    1.263014] VFS: Mounted root (ext4 filesystem) on device 1:0.

[    1.263132] devtmpfs: mounted

[    1.263411] Freeing unused kernel memory: 440K (c0800000 - c086e000)

 

Please press Enter to activate this console. 

[root@tiny4412 ]# 

[root@tiny4412 ]# 

基于tiny4412的Linux内核移植(支持device tree)(三)的更多相关文章

  1. 基于tiny4412的Linux内核移植(支持device tree)(二)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  2. 基于tiny4412的Linux内核移植(支持device tree)(一)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  3. 基于tiny4412的Linux内核移植 -- 设备树的展开

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  4. 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  5. 基于tiny4412的Linux内核移植 -- 设备树的展开【转】

    转自:https://www.cnblogs.com/pengdonglin137/p/5248114.html#_lab2_3_1 阅读目录(Content) 作者信息 平台简介 摘要 正文 一.根 ...

  6. 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  7. 基于tiny4412的Linux内核移植 -- PWM子系统学习(八)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  8. 基于tiny4412的Linux内核移植 -- SD卡驱动移植(五)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  9. 基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植(四)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

随机推荐

  1. const 引用的分析

    const 引用: 在初始化常量引用时,允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可.尤其,允许为一个常量引用绑定非常量的对象.字面值,甚至是一个表达式.我们来看 const ...

  2. C核心 那些个关键字

    概述 - C语言老了 目前而言(2017年5月12日) C语言中有 32 + 5 + 7 = 44 个关键字. 具体如下 O(∩_∩)O哈哈~ -> C89关键字 char short int ...

  3. rabbitmq和ons-rocketmq使用对比

    MQ,其实目的都是一样,就是应对系统的并发可以实现消峰和解耦的作用,类似于创建了一个线程异步操作,这一点可以了解一下一款优秀的并发框架(Disruptor),据说是每秒可以处理十万级数据, 目前据本人 ...

  4. [收集]关于MSSQL数据库的一些查询

    sqlserver快速查找所有存储过程中是否包含某字符 --将XXXX替换成你要查找的内容 select name from sysobjects o, syscomments s where o.i ...

  5. Memcached内存缓存技术

    Memcached是什么,有什么作用? Memcached是一个开源的.高性能的内存缓存软件,从名称上看Mem就是内存的意思,而Cache就是缓存的意思. Memcached通过在事先规划好的内存空间 ...

  6. tornado write render redirect IP

    write 用法( self.flush() ) render (跳转指定网页)用法 redirect(跳转指定路由)用法 self.request.remote_ip 显示用户 IP 地址 less ...

  7. 手机端GPS定位结合百度地图实现定位

    html页面: <!DOCTYPE html>  <html>  <head>      <meta http-equiv="Content-Typ ...

  8. 【hdoj_1085】Holding Bin-Laden Captive![母函数]

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1085 可以这样理解题意:给出1元,2元和5元的三种硬币若干,每种硬币数量给出,现在可以从所有的硬币中,选出 ...

  9. 微信小程序 - 分包加载

    小程序开发大家都知道,对主包的大小进行了限制,从最初的1M变成了现再的2M,一般情况下是够用了:但是偶尔可能会出现超出2M的可能,我们可以对小程序进行分包加载. 1.小程序分包加载 a. 某些情况下, ...

  10. Python基础系列----函数,面向对象,异常

    1.前言                                                                                               前 ...