--------------------------------------------------------------------------------
                         ROM CODE怎样从MMC启动
--------------------------------------------------------------------------------

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

ROM code将boot parameters的结构体指针通过R0寄存器传递给MLO,在start.s的reset部分,第一句指令就是:
bl save_boot_params.
5.07版本号中相关代码比較复杂。而7.00中就相对简单:
就是将R0的数据存储到r1所指的地址中,只存储了一个指针就返回了。


-------------------------------------------------------------------------

Start.s  Start

-------------------------------------------------------------------------
位于arch/arm/cpu/armv7/start.s

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

上电直接跳到reset异常处理例程


调用save_boot_params,保存boot參数。不详述。

continue...


cpy_clk_code是将DPLL的代码复制到SRAM中,暂不述。
cpu_init_crit仅仅在SPL阶段会被调用,用于setup important registers and memory timing.

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

接着调用lowlevel_init函数,位于arch/arm/cpu/armv7/omap-common/lowlevel_init.s文件。
从名字能够看出,该文件用于底层的初始化。


--------------------------------------------------------------------------------

lowlevel_init Start(lowlevel_init.s)

--------------------------------------------------------------------------------

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

这里首先建立一个暂时的栈,用于执行接下来c程序s_init。

当中LOW_LEVEL_SRAM_STACK定义在asm/arch/omap.h文件中面。


而0x4030B7FC位于MPU的L3 OCMC0区域。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

调用的函数s_init。位于board/ti/am335x/evm.c下。

在s_init中有几步非常关键


1、 preloader_console_init()用于初始化串口,调用serial_init(),该函数位于common/serial.c文件中面。


serial_init()函数首先检查当前有没有串口,显然没有,就仅仅能用默认串口default_serial_console结构。该结构定义在drivers/serial/serial.c中。


当中CONFIG_CONS_INDEX宏定义在include/configs/am335x_evm.h,定义为1表示使用UART0口。
这块是移植时候须要注意的地方。否则调试u-boot时候在默认的串口上不会信息打印。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

2、 enable_i2c0_pin_mux()
i2c_init()以及read_eeprom(),这三个函数主要适用于TI公司AM335x相关的板子。

     这一系列板子上面都有EEPROM而且存储了板子的信息。read_eeprom用于读取相关信息。
s_init
Continue...

定义变量is_ddr3用于选择初始化的对象,这也是移植时候须要注意的地方。
--------------------------------------------------------------------------------

lowlevel_init End(lowlevel_init.s)

--------------------------------------------------------------------------------


--------------------------------------------------------------------------------

call_board_init_f Start(start.s)

--------------------------------------------------------------------------------
Back to start.s
调用完cpu_init_crit后,start.s会继续。接着会调用board_init_f(),在调用之前会在内部SRAM中设立栈指针,
这样才干调用函数。由于函数调用须要入栈的操作。


1、栈指针值CONFIG_SYS_INIT_SP_ADDR
start.s又包括 config.h 文件(位于am335x/include/config.h,am335x是编译时候生成的,Makefile将与目标板相关的文件集中在此处)
config.h文件内容:


在configs/am335x_evm.h中定义了CONFIG_SYS_INIT_SP_ADDR:


即CONFIG_SYS_INIT_SP_ADDR = SRAM0_START + SRAM0_SIZE - GENERATED_GBL_DATA_SIZE
当中 SRAM0_START定义在hardware.h中,进入后可知 SRAM0_START = 0x402F0400,正是Memory Map中SRAM internel的首地址。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


SRAM0_SIZE定义在cpu.h中。进入后可知 SRAM0_SIZE = 0x1B400,这个SIZE一直将SRAM延伸到OCMC0里面,结束地址为0x4030B800。



GENERATED_GBL_DATA_SIZE定义在generic-asm-offset.h(asm-offset.h包括此头文件)中。值为128。
这个size的空间是用于存储global_data结构的数据,存储空间以16字节对齐(这个并未证明,由于代码里面没有在不论什么地方提到将全局变量指针指向此地)。


总结一下。到这一步,在MPU的内部OCMC0区设置栈底SP = 0x4030B800 - 128
= 0x4030B780,并在栈底上面存储分配128 Bytes空间用于存储全局数据。
2、MLO重定位
board_init_f函数位于arch/arm/cpu/armv7/omap-common/spl.c。该函数唯一做的事情就是向relocate_code
函数传入三个參数。然后程序流程又回到start.s文件。


在board_init_f()函数调用start.s中的relocate_code函数。这里实现重定位(实现机理能够百度之),
重定位后。后面的puts不会执行了。由于relocate_code不会返回。见下图。


--------------------------------------------------------------------------------

relocate_code Start(start.s) 

--------------------------------------------------------------------------------
relocate_code的代码例如以下:
/*

* void relocate_code (addr_sp, gd, addr_moni)

*

* This "function" does not return, instead it continues in RAM

* after relocating the monitor code.

*

*/

     .globl     relocate_code

relocate_code:

     mov     r4, r0     /* save addr_sp */

     mov     r5, r1     /* save addr of gd */

     mov     r6, r2     /* save addr of destination */



     /* Set up the stack                                  */

stack_setup:

     mov     sp, r4



     adr     r0, _start

     cmp     r0, r6

     moveq     r9, #0          /* no relocation. relocation offset(r9) = 0 */

     beq     clear_bss          /* skip relocation */

     mov     r1, r6               /* r1 <- scratch for copy_loop */

     ldr     r3, _image_copy_end_ofs

     add     r2, r0, r3          /* r2 <- source end address         */



copy_loop:

     ldmia     r0!, {r9-r10}          /* copy from source address [r0]    */

     stmia     r1!, {r9-r10}          /* copy to   target address [r1]    */

     cmp     r0, r2               /* until source end address [r2]    */

     blo     copy_loop



#ifndef CONFIG_SPL_BUILD

     /*

     * fix .rel.dyn relocations

     */

     ldr     r0, _TEXT_BASE          /* r0 <- Text base */

     sub     r9, r6, r0          /* r9 <- relocation offset */

     ldr     r10, _dynsym_start_ofs     /* r10 <- sym table ofs */

     add     r10, r10, r0          /* r10 <- sym table in FLASH */

     ldr     r2, _rel_dyn_start_ofs     /* r2 <- rel dyn start ofs */

     add     r2, r2, r0          /* r2 <- rel dyn start in FLASH */

     ldr     r3, _rel_dyn_end_ofs     /* r3 <- rel dyn end ofs */

     add     r3, r3, r0          /* r3 <- rel dyn end in FLASH */

fixloop:

     ldr     r0, [r2]          /* r0 <- location to fix up, IN FLASH! */

     add     r0, r0, r9          /* r0 <- location to fix up in RAM */

     ldr     r1, [r2, #4]

     and     r7, r1, #0xff

     cmp     r7, #23               /* relative fixup?

*/

     beq     fixrel

     cmp     r7, #2               /* absolute fixup?

*/

     beq     fixabs

     /* ignore unknown type of fixup */

     b     fixnext

fixabs:

     /* absolute fix: set location to (offset) symbol value */

     mov     r1, r1, LSR #4          /* r1 <- symbol index in .dynsym */

     add     r1, r10, r1          /* r1 <- address of symbol in table */

     ldr     r1, [r1, #4]          /* r1 <- symbol value */

     add     r1, r1, r9          /* r1 <- relocated sym addr */

     b     fixnext

fixrel:

     /* relative fix: increase location by offset */

     ldr     r1, [r0]

     add     r1, r1, r9

fixnext:

     str     r1, [r0]

     add     r2, r2, #8          /* each rel.dyn entry is 8 bytes */

     cmp     r2, r3

     blo     fixloop

     b     clear_bss

_rel_dyn_start_ofs:

     .word __rel_dyn_start - _start

_rel_dyn_end_ofs:

     .word __rel_dyn_end - _start

_dynsym_start_ofs:

     .word __dynsym_start - _start



#endif     /* #ifndef CONFIG_SPL_BUILD */



clear_bss:

#ifdef CONFIG_SPL_BUILD

     /* No relocation for SPL */

     ldr     r0, =__bss_start

     ldr     r1, =__bss_end__

#else

     ldr     r0, _bss_start_ofs

     ldr     r1, _bss_end_ofs

     mov     r4, r6               /* reloc addr */

     add     r0, r0, r4

     add     r1, r1, r4

#endif

     mov     r2, #0x00000000          /* clear                   */



clbss_l:str     r2, [r0]          /* clear loop...              */

     add     r0, r0, #4

     cmp     r0, r1

     bne     clbss_l



/*

* We are done. Do not return, instead branch to second part of board

* initialization, now running from RAM.

*/

jump_2_ram:

/*

* If I-cache is enabled invalidate it

*/

#ifndef CONFIG_SYS_ICACHE_OFF

     mcr     p15, 0, r0, c7, c5, 0     @ invalidate icache

     mcr     p15, 0, r0, c7, c10, 4     @ DSB

     mcr     p15, 0, r0, c7, c5, 4     @ ISB

#endif

     ldr     r0, _board_init_r_ofs

     adr     r1, _start

     add     lr, r0, r1

     add     lr, lr, r9

     /* setup parameters for board_init_r */

     mov     r0, r5          /* gd_t */

     mov     r1, r6          /* dest_addr */

     /* jump to it ... */

     mov     pc, lr



_board_init_r_ofs:

     .word board_init_r - _start


从代码的最后能够看出来,最后mov pc,lr,是跳到重定位后的board_init_r函数处。

代码还是那段代码,仅仅是在内存中的位置变化了。


再回到board_init_f中调用relocate_code函数。传入三个參数:
     relocate_code(CONFIG_SPL_STACK, &g_data, CONFIG_SPL_TEXT_BASE);
第一个參数是栈指针:CONFIG_SPL_STACK
第二个參数是全局数据结构指针:&g_data
第三个參数是重定位的目的地址:CONFIG_SPL_TEX_BASE
relocate_code的代码是用汇编书写的。这里要提到的是C參数怎样传递给汇编语言的。这里必需要提到ABI和EABI。
ABI是Application Binary Interface的缩写,跟API非常类似。但ABI是比API更贴近硬件的一层接口。它规定的
是二进制代码之间的调用规则。

我们知道API是与机器硬件平台无关的接口,如熟悉的printf函数,不同的库的实现可能是不同的。可是它们的接口名称
与參数类型都是一样的。

ABI比API的要求更严格。它要求在寄存器级别遵守相同的接口规范。如函数调用的參数传递规则,

寄存器、堆栈的使用方式等。编译器被要求遵守相同的ABI规范,这样不同编译器编译出来的库(相同硬件)才干被别的
编译器使用。
EABI是使用与嵌入式场合的应用二进制接口。这里就简单提一下:函数调用时,传递的參数假设都小于32bit则使用
R0-R3传递參数。參数个数超出4个则使用STACK传递。因此为了代码的效率。程序猿应该尽量保证将函数的參数个数限制
在4个下面。

对于CONFIG_SPL_STACK,是LOW_LEVEL_SRAM_STACK的宏定义。


另外am335x_evm.h还包括hardware.h


hardware.h包括omap.h

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

在omap.h中有LOW_LEVEL_SRAM_STACK的宏定义,这个宏定义和前文提到调用s_init函数前的建立栈底是一样的。


因为栈生长的方向是向下的,所以栈底必须设置为高地址处。这个地址已经快接近OCMC0的底部。


对于CONFIG_SPL_TEXT_BASE。正是MPU内部SRAM的起始地址。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

--------------------------------------------------------------------------------

relocate_code End(start.s)

--------------------------------------------------------------------------------
总结一下:从信息打印看,我们的板子的stack生长方向是递减的。
有一点非常疑惑的是:在调用board_init_f之前,SP设置为0x4030B780。进入board_init_f后调用
relocate_code,传入的SP地址參数为0x4030B7FC,SP往上面移动了。这是为什呢?由于重定位后是不会从
relocate_code函数返回的,所以board_init_f的入栈參数会被抹掉但无所谓,可是能不能将这两次的SP设置成一样的呢?
(PS: TI-SDK-AM335X-EVM-07.00中堆栈的设置没有让人confused的地方了)


--------------------------------------------------------------------------------

call_board_init_f End(start.s)

--------------------------------------------------------------------------------

board_init_f函数调用relocate_code。该函数实现代码的搬迁。

从以下的图中能够看到:


_start处于内存位置:0x402F0400
在relocate_code中,
relocate_code:

     mov     r4, r0     /* save addr_sp */

     mov     r5, r1     /* save addr of gd */

     mov     r6, r2     /* save addr of destination */
stack_setup:

     mov     sp, r4

     adr     r0, _start

     cmp     r0, r6

     moveq     r9, #0          /* no relocation. relocation offset(r9) = 0 */

     beq     clear_bss          /* skip relocation */

     mov     r1, r6               /* r1 <- scratch for copy_loop */

     ldr     r3, _image_copy_end_ofs

     add     r2, r0, r3          /* r2 <- source end address         */
将_start载入到r0中,与r6比較。而r6是由r2传递过来的目标地址CONFIG_SPL_TEXT_BASE=0x402F0400。
因此会运行beq clear_bss处,即copy_loop的代码不会运行。

在代码里面增加宏开关。又一次编译后依旧能运行。证实了这个想法:
MLO阶段不会将自己copy到SRAM中,copy动作应该是由ROM Code实现的。
另外一个证明就是,ti-sdk-07.00版本号的u-boot代码中明白了没有在MLO阶段调用relocate_code,只在u-boot阶段调用。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

-------------------------------------------------------------------------

Start.s  End

-------------------------------------------------------------------------

--------------------------------------------------------------------------------

board_init_r Start(start.s)

--------------------------------------------------------------------------------
relocate_code结束的时候。跳到board_init_r函数处。该函数位于arch/arm/cpu/armv7/omap-common/spl.c。

该函数主要初始化内存、各个外设:
     mem_malloc_init()
     timer_init()
     i2c_init()
     spl_board_init()
然后选择从那个外设载入image。我们调试的时候从SD卡载入u-boot的image,所以关注spl_mmc_load_image函数。
--------------------------------------------------------------------------------

spl_mmc_load_image Start(board_init_r) 

--------------------------------------------------------------------------------
首先取得boot_device的序号。这个序号是定义在boot_params结构体的第三个成员项


omap_boot_device函数定义在arch/arm/cpu/armv7/omap-common/boot-common.c中。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

结构体omap_boot_parameters定义在,这个定义与最開始
时候的Booting Parameters Structure是一致的。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

将boot_device和boot_params的地址都打印出来。例如以下图所看到的:

能够看到boot device是8,相应的是MMC/SD port 0设备。boot_params结构体的地址是0x40303990。位于L3 0CMC0存储区,非常显然这个地址是由连接器分配的。位于“Downloaded Image”区域。
而在spl_mmc_load_image中最关键的部分是,


将boot_mode打印出来,2相应MMCSD_MODE_FAT模式。


另外。因为代码的添加。这儿能够看到boot_params结构体的地址变成了0x403039B8。

而mmc_load_image_fat中最重要的代码就是解析header和读出image。

spl_parse_image_header将header的中信息解析出来放在结构体spl_image里面,file_fat_read函数将image读到spl_image.load_addr所指向的缓冲区。
--------------------------------------------------------------------------------
                     spl_mmc_load_image End(board_init_r) 

--------------------------------------------------------------------------------

spl_image是非常重要的一个结构体。将其打印出来看看有什么。


spl_image的地址已经到了0x8000,0000。这已经是Externel SDRAM的首地址了。那么谁安排spl_image的地址的?
搜索一番,发现spl_image处于.bss区域,即未初始化区域,map里面将其放在0x8000000地址。

回过头来查看arch/arm/cpu/armv7/omap-common/u-boot-spl.lds链接脚本文件,能够看到:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V4aWFuZ2xvbmdoYW9oYW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

也就是说.bss段被指向sdram存储区域。map文件则显示链接器将spl_image安排在第一个。不知道这样的安排是否是有意为之?(后来从7.00上面证明并不是刻意安排。而是ld的行为)从map看。似乎是谁离lds文件更近谁出如今map的最前面。这样的安排是有些道理的。一定程度上能解释为什么spl_image在map上处于第一个。

从spl_image.os的数值能够得出,下一步就是运行jump_to_image_no_args()函数。

该函数首先typedef一个新类型,该类型是入參和返回值均为void的函数指针类型,而且用这个类型定义一个变量image_entry,将spl_image.entry_point赋值给它,最后运行这个函数,从汇编的角度看,就是将spl_image.entry_point赋值给PC,下一步就是跳转到SDRAM的0x80100000运行。

--------------------------------------------------------------------------------

board_init_r End(start.s)

--------------------------------------------------------------------------------

MLO阶段结束。

ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)的更多相关文章

  1. ti processor sdk linux am335x evm Makefile hacking

    # # ti processor sdk linux am335x evm Makefile hacking # 说明: # 本文主要对TI的sdk中的Makefile脚本进行解读,是为了了解其工作机 ...

  2. ti processor sdk linux am335x evm /bin/create-sdcard.sh hacking

    #!/bin/bash # # ti processor sdk linux am335x evm /bin/create-sdcard.sh hacking # 说明: # 本文主要对TI的sdk中 ...

  3. ti processor sdk linux am335x evm /bin/setup-uboot-env.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/setup-uboot-env.sh hacking # 说明: # 本文主要对TI的sdk中 ...

  4. ti processor sdk linux am335x evm /bin/setup-targetfs-nfs.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/setup-targetfs-nfs.sh hacking # 说明: # 本文主要对TI的s ...

  5. ti processor sdk linux am335x evm /bin/setup-tftp.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/setup-tftp.sh hacking # 说明: # 本文主要对TI的sdk中的setu ...

  6. ti processor sdk linux am335x evm setup.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm setup.sh hacking # 说明: # 本文主要对TI的sdk中的setup.sh脚本进行解读 ...

  7. ti processor sdk linux am335x evm /bin/setup-host-check.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/setup-host-check.sh hacking # 说明: # 本文主要对TI的sdk ...

  8. ti processor sdk linux am335x evm /bin/unshallow-repositories.sh hacking

    #!/bin/bash # # ti processor sdk linux am335x evm /bin/unshallow-repositories.sh hacking # 说明: # 本文主 ...

  9. ti processor sdk linux am335x evm /bin/setup-package-install.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/setup-package-install.sh hacking # 说明: # 本文主要对T ...

随机推荐

  1. bat脚本启动exe并打开文件后退出 + 中文乱码

    写了个脚本用于复制模板到新的cpp文件. 将脚本路径加到环境变量里,只需在cmd窗口输入“new hdu 1419”,就会自动将模板拷贝到WORK_DIR下的hdu文件夹内一个名叫"1419 ...

  2. HDU 1241 Oil Deposits【DFS】

    解题思路:第一道DFS的题目--- 参看了紫书和网上的题解-- 在找到一块油田@的时候,往它的八个方向找,直到在能找到的范围内没有油田结束这次搜索 可以模拟一次DFS,比如说样例 在i=0,j=1时, ...

  3. Volatile variables

    Volatile variables apply another type of memory constraint to individual variables. The compiler oft ...

  4. 如何使用 Open Live Writer 插入原图

    博客园的指南里写了使用 Open Live Writer 插入原图.去掉阴影并设置为默认设置的步骤,但是我还是找了好久,最后通过别的文章加上摸索才知道了如何设置为原图.这里给出详细地图片: 首先,插入 ...

  5. PHP通过DOM操作XML

    PHP XML操作类DOMDocument属性及方法 注意大小写一定不能弄错. 属性: Attributes 存储节点的属性列表(只读) childNodes 存储节点的子节点列表(只读) dataT ...

  6. 关闭linux终端进程

    [root@linux-node1 ~]# w 22:16:45 up 24 days, 24 min, 2 users, load average: 0.28, 0.17, 0.15 USER TT ...

  7. crontab执行脚本和手动执行脚本输出结果不一致的问题处理

    背景:huskiesir最近用公司给分配的账户写了脚本去检测某应用状态并发送到企业邮箱,写完脚本之后去执行了一下,发现效果还不错,在邮箱显示效果如下: 10.11.116.6  检查结果OK,检查时间 ...

  8. * ? 【a-z】【0-9】通配符 学习

    通配符顾名思义就是通用的匹配信息的符号,比如星号(*)就是代表匹配零个或多个字符,问号(?)是代表匹配单个字符,中括号内加上数字[0-9]代表匹配单个阿拉伯数字的字符,而中括号内加上字母[abc]则是 ...

  9. LaTeX 矩阵

    本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50054363 LaTeX 写矩阵,需要 ...

  10. 洛谷 P2758 编辑距离

    P2758 编辑距离 题目描述 设A和B是两个字符串.我们要用最少的字符操作次数,将字符串A转换为字符串B.这里所说的字符操作共有三种: 1.删除一个字符: 2.插入一个字符: 3.将一个字符改为另一 ...