Linux学习 : 自己写bootloader
一、bootloader 目标:启动内核
基本功能:
①初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
②image比较大需要重定位到SDRAM
②将内核从NAND FLASH读到 SDRAM
③设置“要传给内核的参数”
④跳转执行内核
启动时间优化:
①提高CPU频率:
1,FCLK是CPU提供的时钟信号。
2,HCLK是为AHB总线提供的时钟信号, Advanced High-performance Bus,主要用于高速外设,比如内存控制器,中断控制器,LCD控制器, DMA 等。
3,PCLK是为APB总线提供的时钟信号,Advanced Peripherals Bus,主要用于低速外设,比如看门狗,UART控制器, IIS, I2C, SDI/MMC, GPIO,RTC and SPI等。
②启动ICACHE:
CPU将多条指令一次装入ICACHE,不用每次到SDRAM中去取指。
另外,DCACHE主要用来取数据,需要启用MMU.
1.start.S
- #define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
- #define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
- #define MEM_CTL_BASE 0x48000000
- .text
- .global _start
- _start:
- /* 1. 关看门狗 */
- ldr r0, =0x53000000
- mov r1, #
- str r1, [r0]
- /* 2. 设置时钟 */
- ldr r0, =0x4c000014
- // mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
- mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
- str r1, [r0]
- /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
- mrc p15, , r1, c1, c0, /* 读出控制寄存器 */
- orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
- mcr p15, , r1, c1, c0, /* 写入控制寄存器 */
- /* MPLLCON = S3C2440_MPLL_200MHZ */
- ldr r0, =0x4c000004
- ldr r1, =S3C2440_MPLL_400MHZ
- str r1, [r0]
- /* 启动ICACHE */
- mrc p15, , r0, c1, c0, @ read control reg 读协处理器
- orr r0, r0, #(<<)
- mcr p15, , r0, c1, c0, @ write it back 写入协处理器
- /* 3. 初始化SDRAM */
- ldr r0, =MEM_CTL_BASE
- adr r1, sdram_config /* sdram_config的当前地址 */
- add r3, r0, #(*)
- :
- ldr r2, [r1], #
- str r2, [r0], #
- cmp r0, r3
- bne 1b
- /* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
- ldr sp, =0x34000000
- bl nand_init
/* r0 r1 r2 表示给之后调用C函数传入的参数 */- mov r0, #
- ldr r1, =_start
- ldr r2, =__bss_start /*通过伪汇编获取bss段的结束地址*/
- sub r2, r2, r1
- bl copy_code_to_sdram
- bl clear_bss
- /* 5. 执行main */
- ldr lr, =halt
- ldr pc, =main
- halt:
- b halt
- sdram_config:
- .long 0x22011110 //BWSCON
- .long 0x00000700 //BANKCON0
- .long 0x00000700 //BANKCON1
- .long 0x00000700 //BANKCON2
- .long 0x00000700 //BANKCON3
- .long 0x00000700 //BANKCON4
- .long 0x00000700 //BANKCON5
- .long 0x00018005 //BANKCON6
- .long 0x00018005 //BANKCON7
- .long 0x008C04F4 // REFRESH
- .long 0x000000B1 //BANKSIZE
- .long 0x00000030 //MRSRB6
- .long 0x00000030 //MRSRB7
2.init.c
- /* NAND FLASH控制器 */
- #define NFCONF (*((volatile unsigned long *)0x4E000000))
- #define NFCONT (*((volatile unsigned long *)0x4E000004))
- #define NFCMMD (*((volatile unsigned char *)0x4E000008))
- #define NFADDR (*((puthexvolatile unsigned char *)0x4E00000C))
- #define NFDATA (*((volatile unsigned char *)0x4E000010))
- #define NFSTAT (*((volatile unsigned char *)0x4E000020))
- /* GPIO */
- #define GPHCON (*(volatile unsigned long *)0x56000070)
- #define GPHUP (*(volatile unsigned long *)0x56000078)
- /* UART registers*/
- #define ULCON0 (*(volatile unsigned long *)0x50000000)
- #define UCON0 (*(volatile unsigned long *)0x50000004)
- #define UFCON0 (*(volatile unsigned long *)0x50000008)
- #define UMCON0 (*(volatile unsigned long *)0x5000000c)
- #define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
- #define UTXH0 (*(volatile unsigned char *)0x50000020)
- #define URXH0 (*(volatile unsigned char *)0x50000024)
- #define UBRDIV0 (*(volatile unsigned long *)0x50000028)
- #define TXD0READY (1<<2)
- void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);
- int isBootFromNorFlash(void)
- {
- volatile int *p = (volatile int *);
- int val;
- val = *p;
- *p = 0x12345678;
- if (*p == 0x12345678)
- {
- /* 写成功, 是nand启动 */
- *p = val;
- return ;
- }
- else
- {
- /* NOR不能像内存一样写 */
- return ;
- }
- }
- void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
- {
- int i = ;
- /* 如果是NOR启动 */
- if (isBootFromNorFlash())
- {
- while (i < len)
- {
- dest[i] = src[i];
- i++;
- }
- }
- else
- {
- //nand_init();
- nand_read((unsigned int)src, dest, len);
- }
- }
- void clear_bss(void)
- {
- extern int __bss_start, __bss_end;
- int *p = &__bss_start;
- for (; p < &__bss_end; p++)
- *p = ;
- }
- void nand_init(void)
- {
- #define TACLS 0
- #define TWRPH0 1
- #define TWRPH1 0
- /* 设置时序 */
- NFCONF = (TACLS<<)|(TWRPH0<<)|(TWRPH1<<);
- /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
- NFCONT = (<<)|(<<)|(<<);
- }
- void nand_select(void)
- {
- NFCONT &= ~(<<);
- }
- void nand_deselect(void)
- {
- NFCONT |= (<<);
- }
- void nand_cmd(unsigned char cmd)
- {
- volatile int i;
- NFCMMD = cmd;
- for (i = ; i < ; i++);
- }
- void nand_addr(unsigned int addr)
- {
- unsigned int col = addr % ;
- unsigned int page = addr / ;
- volatile int i;
- NFADDR = col & 0xff;
- for (i = ; i < ; i++);
- NFADDR = (col >> ) & 0xff;
- for (i = ; i < ; i++);
- NFADDR = page & 0xff;
- for (i = ; i < ; i++);
- NFADDR = (page >> ) & 0xff;
- for (i = ; i < ; i++);
- NFADDR = (page >> ) & 0xff;
- for (i = ; i < ; i++);
- }
- void nand_wait_ready(void)
- {
- while (!(NFSTAT & ));
- }
- unsigned char nand_data(void)
- {
- return NFDATA;
- }
- void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
- {
- int col = addr % ;
- int i = ;
- /* 1. 选中 */
- nand_select();
- while (i < len)
- {
- /* 2. 发出读命令00h */
- nand_cmd(0x00);
- /* 3. 发出地址(分5步发出) */
- nand_addr(addr);
- /* 4. 发出读命令30h */
- nand_cmd(0x30);
- /* 5. 判断状态 */
- nand_wait_ready();
- /* 6. 读数据 */
- for (; (col < ) && (i < len); col++)
- {
- buf[i] = nand_data();
- i++;
- addr++;
- }
- col = ;
- }
- /* 7. 取消选中 */
- nand_deselect();
- }
- #define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz
- #define UART_CLK PCLK // UART0的时钟源设为PCLK
- #define UART_BAUD_RATE 115200 // 波特率
- #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
- /*
- * 初始化UART0
- * 115200,8N1,无流控
- */
- void uart0_init(void)
- {
- GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
- GPHUP = 0x0c; // GPH2,GPH3内部上拉
- ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)
- UCON0 = 0x05; // 查询方式,UART时钟源为PCLK
- UFCON0 = 0x00; // 不使用FIFO
- UMCON0 = 0x00; // 不使用流控
- UBRDIV0 = UART_BRD; // 波特率为115200
- }
- /*
- * 发送一个字符
- */
- void putc(unsigned char c)
- {
- /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
- while (!(UTRSTAT0 & TXD0READY));
- /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
- UTXH0 = c;
- }
- void puts(char *str)
- {
- int i = ;
- while (str[i])
- {
- putc(str[i]);
- i++;
- }
- }
- void puthex(unsigned int val)
- {
- /* 0x1234abcd */
- int i;
- int j;
- puts("0x");
- for (i = ; i < ; i++)
- {
- j = (val >> ((-i)*)) & 0xf;
- if ((j >= ) && (j <= ))
- putc('' + j);
- else
- putc('A' + j - 0xa);
- }
- }
3.boot.c
- #include "setup.h"
- extern void uart0_init(void);
- extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);
- extern void puts(char *str);
- extern void puthex(unsigned int val);
- static struct tag *params;
- void setup_start_tag(void)
- {
- params = (struct tag *)0x30000100;
- params->hdr.tag = ATAG_CORE; //0x54410001,表示参数的开始
- params->hdr.size = tag_size (tag_core); //5个
- params->u.core.flags = ;
- params->u.core.pagesize = ;
- params->u.core.rootdev = ;
- params = tag_next (params);
- }
- void setup_memory_tags(void)
- {
- params->hdr.tag = ATAG_MEM;
- params->hdr.size = tag_size (tag_mem32);
- params->u.mem.start = 0x30000000;
- params->u.mem.size = **; //64M
- params = tag_next (params); //如分多个内存存放tag,用tag_next查找
- }
- int strlen(char *str)
- {
- int i = ;
- while (str[i])
- {
- i++;
- }
- return i;
- }
- void strcpy(char *dest, char *src)
- {
- while ((*dest++ = *src++) != '\0');
- }
- void setup_commandline_tag(char *cmdline)
- {
- int len = strlen(cmdline) + ;
- params->hdr.tag = ATAG_CMDLINE;
- params->hdr.size = (sizeof (struct tag_header) + len + ) >> ; //向4取整
- strcpy (params->u.cmdline.cmdline, cmdline);
- params = tag_next (params);
- }
- void setup_end_tag(void)
- {
- params->hdr.tag = ATAG_NONE;
- params->hdr.size = ;
- }
- int main(void)
- {
- void (*theKernel)(int zero, int arch, unsigned int params);
- volatile unsigned int *p = (volatile unsigned int *)0x30008000;
- /* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */
- uart0_init();
- /* 1. 从NAND FLASH里把内核读入内存 */
- puts("Copy kernel from nand\n\r");
- nand_read(0x60000+, (unsigned char *)0x30008000, 0x200000);
- puthex(0x1234ABCD);
- puts("\n\r");
- puthex(*p);
- puts("\n\r");
- /* 2. 设置参数 ,与内核约定参数存放地址,Uboot写个内核的遗嘱^^*/
- puts("Set boot params\n\r");
- setup_start_tag();
- setup_memory_tags();
- setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
- setup_end_tag();
- /* 3. 跳转执行 */
- puts("Boot kernel\n\r");
- theKernel = (void (*)(int, int, unsigned int))0x30008000;
- theKernel(, , 0x30000100); //362:arm
- /*
- * mov r0, #0
- * ldr r1, =362
- * ldr r2, =0x30000100
- * mov pc, #0x30008000
- */
- puts("Error!\n\r");
- /* 如果一切正常, 不会执行到这里 */
- return -;
- }
4.boot.lds : 指定代码存放的位置
- SECTIONS {
- . = 0x33f80000; #与最高地址差512K
- .text : { *(.text) }
- . = ALIGN();
- .rodata : {*(.rodata*)}
- . = ALIGN();
- .data : { *(.data) }
- . = ALIGN();
- __bss_start = .; #bss段指向当前地址,保存未初始化或为0的全局变量
- .bss : { *(.bss) *(COMMON) }
- __bss_end = .; #bss段设定起始和结束地址,程序启动时统一初始化保存的变量
- }
5.setup.h
- /*
- * linux/include/asm/setup.h
- *
- * Copyright (C) 1997-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Structure passed to kernel to tell it about the
- * hardware it's running on. See linux/Documentation/arm/Setup
- * for more info.
- *
- * NOTE:
- * This file contains two ways to pass information from the boot
- * loader to the kernel. The old struct param_struct is deprecated,
- * but it will be kept in the kernel for 5 years from now
- * (2001). This will allow boot loaders to convert to the new struct
- * tag way.
- */
- #ifndef __ASMARM_SETUP_H
- #define __ASMARM_SETUP_H
- #define u8 unsigned char
- #define u16 unsigned short
- #define u32 unsigned long
- /*
- * Usage:
- * - do not go blindly adding fields, add them at the end
- * - when adding fields, don't rely on the address until
- * a patch from me has been released
- * - unused fields should be zero (for future expansion)
- * - this structure is relatively short-lived - only
- * guaranteed to contain useful data in setup_arch()
- */
- #define COMMAND_LINE_SIZE 1024
- /* This is the old deprecated way to pass parameters to the kernel */
- struct param_struct {
- union {
- struct {
- unsigned long page_size; /* 0 */
- unsigned long nr_pages; /* 4 */
- unsigned long ramdisk_size; /* 8 */
- unsigned long flags; /* 12 */
- #define FLAG_READONLY 1
- #define FLAG_RDLOAD 4
- #define FLAG_RDPROMPT 8
- unsigned long rootdev; /* 16 */
- unsigned long video_num_cols; /* 20 */
- unsigned long video_num_rows; /* 24 */
- unsigned long video_x; /* 28 */
- unsigned long video_y; /* 32 */
- unsigned long memc_control_reg; /* 36 */
- unsigned char sounddefault; /* 40 */
- unsigned char adfsdrives; /* 41 */
- unsigned char bytes_per_char_h; /* 42 */
- unsigned char bytes_per_char_v; /* 43 */
- unsigned long pages_in_bank[]; /* 44 */
- unsigned long pages_in_vram; /* 60 */
- unsigned long initrd_start; /* 64 */
- unsigned long initrd_size; /* 68 */
- unsigned long rd_start; /* 72 */
- unsigned long system_rev; /* 76 */
- unsigned long system_serial_low; /* 80 */
- unsigned long system_serial_high; /* 84 */
- unsigned long mem_fclk_21285; /* 88 */
- } s;
- char unused[];
- } u1;
- union {
- char paths[][];
- struct {
- unsigned long magic;
- char n[ - sizeof(unsigned long)];
- } s;
- } u2;
- char commandline[COMMAND_LINE_SIZE];
- };
- /*
- * The new way of passing information: a list of tagged entries
- */
- /* The list ends with an ATAG_NONE node. */
- #define ATAG_NONE 0x00000000
- struct tag_header {
- u32 size;
- u32 tag;
- };
- /* The list must start with an ATAG_CORE node */
- #define ATAG_CORE 0x54410001
- struct tag_core {
- u32 flags; /* bit 0 = read-only */
- u32 pagesize;
- u32 rootdev;
- };
- /* it is allowed to have multiple ATAG_MEM nodes */
- #define ATAG_MEM 0x54410002
- struct tag_mem32 {
- u32 size;
- u32 start; /* physical start address */
- };
- /* VGA text type displays */
- #define ATAG_VIDEOTEXT 0x54410003
- struct tag_videotext {
- u8 x;
- u8 y;
- u16 video_page;
- u8 video_mode;
- u8 video_cols;
- u16 video_ega_bx;
- u8 video_lines;
- u8 video_isvga;
- u16 video_points;
- };
- /* describes how the ramdisk will be used in kernel */
- #define ATAG_RAMDISK 0x54410004
- struct tag_ramdisk {
- u32 flags; /* bit 0 = load, bit 1 = prompt */
- u32 size; /* decompressed ramdisk size in _kilo_ bytes */
- u32 start; /* starting block of floppy-based RAM disk image */
- };
- /* describes where the compressed ramdisk image lives (virtual address) */
- /*
- * this one accidentally used virtual addresses - as such,
- * its depreciated.
- */
- #define ATAG_INITRD 0x54410005
- /* describes where the compressed ramdisk image lives (physical address) */
- #define ATAG_INITRD2 0x54420005
- struct tag_initrd {
- u32 start; /* physical start address */
- u32 size; /* size of compressed ramdisk image in bytes */
- };
- /* board serial number. "64 bits should be enough for everybody" */
- #define ATAG_SERIAL 0x54410006
- struct tag_serialnr {
- u32 low;
- u32 high;
- };
- /* board revision */
- #define ATAG_REVISION 0x54410007
- struct tag_revision {
- u32 rev;
- };
- /* initial values for vesafb-type framebuffers. see struct screen_info
- * in include/linux/tty.h
- */
- #define ATAG_VIDEOLFB 0x54410008
- struct tag_videolfb {
- u16 lfb_width;
- u16 lfb_height;
- u16 lfb_depth;
- u16 lfb_linelength;
- u32 lfb_base;
- u32 lfb_size;
- u8 red_size;
- u8 red_pos;
- u8 green_size;
- u8 green_pos;
- u8 blue_size;
- u8 blue_pos;
- u8 rsvd_size;
- u8 rsvd_pos;
- };
- /* command line: \0 terminated string */
- #define ATAG_CMDLINE 0x54410009
- struct tag_cmdline {
- char cmdline[]; /* this is the minimum size */
- };
- /* acorn RiscPC specific information */
- #define ATAG_ACORN 0x41000101
- struct tag_acorn {
- u32 memc_control_reg;
- u32 vram_pages;
- u8 sounddefault;
- u8 adfsdrives;
- };
- /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
- #define ATAG_MEMCLK 0x41000402
- struct tag_memclk {
- u32 fmemclk;
- };
- struct tag {
- struct tag_header hdr;
- union {
- struct tag_core core;
- struct tag_mem32 mem;
- struct tag_videotext videotext;
- struct tag_ramdisk ramdisk;
- struct tag_initrd initrd;
- struct tag_serialnr serialnr;
- struct tag_revision revision;
- struct tag_videolfb videolfb;
- struct tag_cmdline cmdline;
- /*
- * Acorn specific
- */
- struct tag_acorn acorn;
- /*
- * DC21285 specific
- */
- struct tag_memclk memclk;
- } u;
- };
- struct tagtable {
- u32 tag;
- int (*parse)(const struct tag *);
- };
- #define tag_member_present(tag,member) \
- ((unsigned long)(&((struct tag *)0L)->member + ) \
- <= (tag)->hdr.size * )
- #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
- #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
- #define for_each_tag(t,base) \
- for (t = base; t->hdr.size; t = tag_next(t))
- /*
- * Memory map description
- */
- #define NR_BANKS 8
- struct meminfo {
- int nr_banks;
- unsigned long end;
- struct {
- unsigned long start;
- unsigned long size;
- int node;
- } bank[NR_BANKS];
- };
- extern struct meminfo meminfo;
- #endif
6.Makefile
- CC = arm-linux-gcc
- LD = arm-linux-ld
- AR = arm-linux-ar
- OBJCOPY = arm-linux-objcopy
- OBJDUMP = arm-linux-objdump
- CFLAGS := -Wall -O2
- CPPFLAGS := -nostdinc - -fno-builtin
- objs := start.o init.o boot.o
- boot.bin: $(objs)
- ${LD} -Tboot.lds -o boot.elf $^
- ${OBJCOPY} -O binary -S boot.elf $@
- ${OBJDUMP} -D -m arm boot.elf > boot.dis
- %.o:%.c
- ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
- %.o:%.S
- ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
- clean:
- rm -f *.o *.bin *.elf *.dis
Linux学习 : 自己写bootloader的更多相关文章
- 【Linux学习】 写一个简单的Makefile编译源码获取当前系统时间
打算学习一下Linux,这两天先看了一下gcc的简单用法以及makefile的写法,今天是周末,天气闷热超市,早晨突然发现住处的冰箱可以用了,于是先出去吃了点东西,然后去超市买了一坨冰棍,老冰棍居多, ...
- Linux 学习笔记
Linux学习笔记 请切换web视图查看,表格比较大,方法:视图>>web板式视图 博客园不能粘贴图片吗 http://wenku.baidu.com/view/bda1c3067fd53 ...
- 【转】嵌入式Linux学习笔记
一 嵌入式系统定义: 应用于特定环境的硬件体系. 二 两样非常重要的能力: 1. 掌握各种新概念的能力 2. 调试的能力( 包括软件, 硬件 ) 三 需要的基础知识: 1. 操作系统理论基 ...
- 实验楼 linux 学习
实验楼 linux 学习 一.Linux 用户管理 1.查看用户 who am i // who mom likes whoami ====--------====== 输入的第一列表示打 ...
- linux学习笔记2-linux的常用命令
第一篇博客:linux学习笔记1-ubuntu的安装与基本设置 之中,已经介绍了如何安装linux操作系统,以及一些基本的设置修改. 本篇博客主要介绍linux中的一些常用的终端命令 ======== ...
- Linux学习历程(持续更新整理中)
1.文件目录操作命令 (1) ls 显示文件和目录列表 a ls -l 显示文件的详细信息 b ls -a 列出当前目录的所有文件,包含隐藏文件. c stat '目录/文件' 显示指定目录 ...
- [转] Linux学习之CentOS(十三)--CentOS6.4下Mysql数据库的安装与配置
from: http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html 如果要在Linux上做j2ee开发,首先得 ...
- Linux学习之CentOS--CentOS6.4下Mysql数据库的安装与配置【转】
如果要在Linux上做j2ee开发,首先得搭建好j2ee的开发环境,包括了jdk.tomcat.eclipse的安装(这个在之前的一篇随笔中已经有详细讲解了Linux学习之CentOS(七)--C ...
- Linux学习之CentOS(十三)--CentOS6.4下Mysql数据库的安装与配置
原文:http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html 如果要在Linux上做j2ee开发,首先得搭建好j ...
- linux学习书籍推荐linux学习书籍推荐
引用地址:http://www.cnblogs.com/notepi/archive/2013/06/15/3137103.html Linux 学习书目推荐 Linux基础 1.<Linux与 ...
随机推荐
- HTML 在安卓手机端软键盘弹出顶起页面布局的解决办法
$('body').height($('body')[0].clientHeight); 以上是背景即BODY被顶起的解决办法. 如果是footer被顶起,则可以用判断解决, $('input').f ...
- 元素定义了position:fixed;后怎么居中
div{ position:fixed; width:1200px; margin:0 auto; top:0; bottom:0; left:0; right:0; }
- Markdown学习和插件介绍
markdown能干啥 亲们github上的项目首页的 内容+样式,都是项目中README.md文件控制的.将md风格的代码,转化成html. 而且markdown语法非常简单,5-10分钟即可学会! ...
- linux网卡混杂模式
混杂模式就是接收所有经过网卡的数据包,包括不是发给本机的包,即不验证MAC地址.普通模式下网卡只接收发给本机的包(包括广播包)传递给上层程序,其它的包一律丢弃.一般来说,混杂模式不会影响网卡的正常工作 ...
- Android 四大组件之四(ContentProvider)
ContentProvider调用关系: ContentProvider(数据提供者)是应用程序之间共享数据的一种接口机制,是一种更为高级的数据共享方法. ContentProvider可以指定需要共 ...
- PBS 安装
How to install PBS Pro using the configure script. . Install the prerequisite packages for building ...
- R语言实战(一)介绍、数据集与图形初阶
本文对应<R语言实战>前3章,因为里面大部分内容已经比较熟悉,所以在这里只是起一个索引的作用. 第1章 R语言介绍 获取帮助函数 help(), ? 查看函数帮助 exampl ...
- App开发三种模式
APP开发三种模式 现在App开发的模式包含以下三种: Native App 原生开发AppWeb App 网页AppHybrid App 混合原生和Web技术开发的App 详细介绍: http:// ...
- 【转】Expire Google Drive Files 让Google Docs云盘共享连接在指定时间后自动失效
最近在清理Google Docs中之前共享过的文件链接,发现Google Docs多人协作共享过的链接会一直存在,在实际操作中较不灵活.正好订阅的RSS推送了Pseric写的这篇文章 - Expire ...
- Sphinx Search 学习 (一)
参考资料一:(中文)http://www.coreseek.cn/docs/coreseek_3.2-sphinx_0.9.9.html (官方)http://sphinxsearch.com/doc ...