Add fl2440 linux-bsp folders
1 files modified
148 files added
| | |
| | | ## fl2440 |
| | | |
| | | FL2440开发板源码 |
| | | FL2440 ARM Linux Board BSP and application |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: beep.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code used to turn buzzer on/off on FL2440 board |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define GPBCON (*(unsigned long volatile *)0x56000010) |
| | | #define GPBDAT (*(unsigned long volatile *)0x56000014) |
| | | #define GPBUP (*(unsigned long volatile *)0x56000018) |
| | | |
| | | #define BEEP 0 /*Buzzer us GPB0 */ |
| | | #define LED0 5 |
| | | #define DELAY_TIME 40000000 |
| | | |
| | | static inline void delay (unsigned long loops) |
| | | { |
| | | __asm__ volatile ("1:\n" |
| | | "subs %0, %1, #1\n" |
| | | "bne 1b":"=r" (loops):"0" (loops)); |
| | | } |
| | | |
| | | int main(void) |
| | | { |
| | | GPBCON = (GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */ |
| | | GPBUP &= ~1; /* Enable pullup resister */ |
| | | |
| | | GPBDAT |= 0x560; |
| | | while(1) |
| | | { |
| | | GPBDAT &= ~(1<<BEEP); /* Set Beep GPIO as low level */ |
| | | delay(DELAY_TIME); |
| | | |
| | | GPBDAT |= 1<<BEEP; /* Set Beep GPIO as high level */ |
| | | delay(DELAY_TIME); |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: beep.lds |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: Cross tool link text, refer to u-boot.lds |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") |
| | | OUTPUT_ARCH(arm) |
| | | ENTRY(_start) |
| | | |
| | | SECTIONS{ |
| | | . = 0x33000000; |
| | | .text : { |
| | | *(.text) |
| | | *(.rodata) |
| | | } |
| | | |
| | | .data ALIGN(4): { |
| | | *(.data) |
| | | } |
| | | |
| | | .bss ALIGN(4): { |
| | | *(.bss) |
| | | } |
| | | } |
New file |
| | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM and C source code |
| | | # * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | |
| | | BINAME = beep |
| | | TEXTBASE = 0x33000000 |
| | | |
| | | CROSS = /opt/xtools/arm920t/bin/arm-linux- |
| | | CC = $(CROSS)gcc |
| | | LD = $(CROSS)ld |
| | | AR = $(CROSS)ar |
| | | OBJCOPY = $(CROSS)objcopy |
| | | OBJDUMP = $(CROSS)objdump |
| | | STRIP = $(CROSS)strip |
| | | READELF = $(CROSS)readelf |
| | | |
| | | CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin |
| | | AFLAGS = $(CFLAGS) -D__ASSEMBLY__ |
| | | |
| | | LDSCRIPT = ${BINAME}.lds |
| | | LDFLAGS = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE) |
| | | |
| | | SRC_C = $(wildcard *.c) |
| | | SRC_S = $(wildcard *.S) |
| | | OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) |
| | | OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) |
| | | |
| | | OBJ_ALL = $(OBJ_C) $(OBJ_S) |
| | | |
| | | .PHONY : all |
| | | all: ${OBJ_ALL} |
| | | ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} |
| | | ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin |
| | | rm -f *.elf *.o |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: |
| | | cp ${BINAME}.bin ~/winxp -f --reply=yes |
| | | |
| | | clean: |
| | | rm -f *.elf *.o |
| | | rm -f ${BINAME}.bin |
New file |
| | |
| | | /*********************************************************************** |
| | | * File: start.S |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This ASM used to disable watch dog and interrupt, then call C code to |
| | | * turn the buzzer on/off on FL2440 board. |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define pWTCON 0x53000000 /* Watch dog register address */ |
| | | #define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ |
| | | #define INTSUBMSK 0x4A00001C |
| | | |
| | | .text |
| | | .align 2 |
| | | .global _start |
| | | |
| | | _start: |
| | | |
| | | /* Disable watch dog */ |
| | | ldr r0, =pWTCON /*Save pwTCON address in r0*/ |
| | | mov r1, #0x0 /*Set r1=0x0*/ |
| | | str r1, [r0] /*Move the data in r1 to the address specify by r0*/ |
| | | |
| | | /* mask all IRQs by setting all bits in the INTMR - default */ |
| | | mov r1, #0xffffffff |
| | | ldr r0, =INTMSK |
| | | str r1, [r0] |
| | | |
| | | ldr r0, =INTSUBMSK |
| | | ldr r1, =0x7fff /*There are 15 bits used in INTSUBMSK on S3C2440*/ |
| | | str r1, [r0] |
| | | |
| | | bl main |
| | | |
| | | halt_loop: |
| | | b halt_loop |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: buzzer_led.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code used to turn buzzer on/off on FL2440 board |
| | | * ChangeLog: 1, Release initial version on "Tue Mar 22 21:58:24 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define GPBCON (*(unsigned long volatile *)0x56000010) |
| | | #define GPBDAT (*(unsigned long volatile *)0x56000014) |
| | | #define GPBUP (*(unsigned long volatile *)0x56000018) |
| | | |
| | | #define BEEP 0 /* Buzzer use GPB0 */ |
| | | #define LED0 5 /* LED0 use GPB5*/ |
| | | #define LED1 6 /* LED1 use GPB6*/ |
| | | #define LED2 8 /* LED2 use GPB8*/ |
| | | #define LED3 10 /* LED3 use GPB10*/ |
| | | #define DELAY_TIME 40000000 |
| | | |
| | | unsigned int led_gpio[4] = {5,6,8,10}; |
| | | |
| | | static inline void delay (unsigned long loops) |
| | | { |
| | | __asm__ volatile ("1:\n" |
| | | "subs %0, %1, #1\n" |
| | | "bne 1b":"=r" (loops):"0" (loops)); |
| | | } |
| | | |
| | | void init_led_buzzer(void) |
| | | { |
| | | GPBCON = (GPBCON|0x333C03)&0x111401; /* Set GPB0,GPB5,GPB8,GPB10 as GPIO input mode */ |
| | | GPBDAT |= 0x560; /* Set GPB0,GPB5,GPB6,GPB8,GPB10 as high level */ |
| | | } |
| | | |
| | | void turn_led_on(int led) |
| | | { |
| | | if(led > 3) |
| | | return; |
| | | |
| | | /* Set GPIO port as low level */ |
| | | GPBDAT = (GPBDAT & ( ~(1<<led_gpio[led])) ); |
| | | } |
| | | |
| | | /* Turn all LED off */ |
| | | void turn_all_led_off(void) |
| | | { |
| | | GPBDAT |= 0x560; /* Set GPIO port as high level */ |
| | | } |
| | | |
| | | void turn_beep_on(void) |
| | | { |
| | | GPBDAT |= 1<<BEEP; /* Set Beep GPIO as high level, turn beep on */ |
| | | } |
| | | |
| | | void turn_beep_off(void) |
| | | { |
| | | GPBDAT &= ~(1<<BEEP); /* Set Beep GPIO as low level, turn beep off */ |
| | | } |
| | | |
| | | void turn_buzzer(int times) |
| | | { |
| | | int i; |
| | | for(i=0; i<times; i++) |
| | | { |
| | | |
| | | turn_beep_on(); |
| | | delay(DELAY_TIME); |
| | | |
| | | turn_beep_off(); |
| | | delay(DELAY_TIME); |
| | | } |
| | | } |
| | | |
| | | void turn_led_buzzer_off(void) |
| | | { |
| | | turn_all_led_off(); |
| | | turn_beep_off(); |
| | | |
| | | return; |
| | | } |
| | | |
| | | /* Input value $key is passed by start.S |
| | | * |
| | | * Key2 pressed -> key=0, turn LED0 on, beep for 1 time |
| | | * Key3 pressed -> key=1, turn LED1 on, beep for 2 time |
| | | * Key4 pressed -> key=2, turn LED2 on, beep for 3 time |
| | | * Key5 pressed -> key=3, turn LED3 on, beep for 4 time |
| | | */ |
| | | |
| | | void turn_led_buzzer_on(int key) |
| | | { |
| | | turn_led_on(key); /* Set correspond LED on */ |
| | | turn_buzzer(key+1); /* Let buzzer beep for $key times */ |
| | | } |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: key.lds |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: Cross tool link text, refer to u-boot.lds |
| | | * ChangeLog: 1, Release initial version on "Tue Mar 22 21:58:24 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") |
| | | OUTPUT_ARCH(arm) |
| | | ENTRY(_start) |
| | | |
| | | SECTIONS{ |
| | | . = 0x33000000; |
| | | .text : { |
| | | *(.text) |
| | | *(.rodata) |
| | | } |
| | | |
| | | .data ALIGN(4): { |
| | | *(.data) |
| | | } |
| | | |
| | | .bss ALIGN(4): { |
| | | *(.bss) |
| | | } |
| | | } |
New file |
| | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM and C source code |
| | | # * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | |
| | | BINAME = key |
| | | TEXTBASE = 0x33000000 |
| | | |
| | | CROSS = /opt/xtools/arm920t/bin/arm-linux- |
| | | CC = $(CROSS)gcc |
| | | LD = $(CROSS)ld |
| | | AR = $(CROSS)ar |
| | | OBJCOPY = $(CROSS)objcopy |
| | | OBJDUMP = $(CROSS)objdump |
| | | STRIP = $(CROSS)strip |
| | | READELF = $(CROSS)readelf |
| | | |
| | | CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin |
| | | AFLAGS = $(CFLAGS) -D__ASSEMBLY__ |
| | | |
| | | LDSCRIPT = ${BINAME}.lds |
| | | LDFLAGS = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE) |
| | | |
| | | SRC_C = $(wildcard *.c) |
| | | SRC_S = $(wildcard *.S) |
| | | OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) |
| | | OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) |
| | | |
| | | OBJ_ALL = $(OBJ_C) $(OBJ_S) |
| | | |
| | | .PHONY : all |
| | | all: ${OBJ_ALL} |
| | | ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} |
| | | ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin |
| | | rm -f *.elf *.o |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: |
| | | cp ${BINAME}.bin ~/winxp -f --reply=yes |
| | | |
| | | clean: |
| | | rm -f *.elf *.o |
| | | rm -f ${BINAME}.bin |
New file |
| | |
| | | /*********************************************************************** |
| | | * File: start.S |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This ASM used to detect the four keys status, if it's pressed down |
| | | * then call the C function to turn the buzzer beep and LED on |
| | | * ChangeLog: 1, Release initial version on "Tue Mar 22 21:58:24 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define pWTCON 0x53000000 /* Watch dog register address */ |
| | | #define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ |
| | | #define INTSUBMSK 0x4A00001C |
| | | |
| | | #define GPFCON 0x56000050 |
| | | #define GPFDAT 0x56000054 |
| | | #define GPFUP 0x56000058 |
| | | |
| | | #define KEY2 0 /*KEY S2 use GPF0/EINT0 port*/ |
| | | #define KEY3 2 /*KEY S3 use GPF2/EINT2 port*/ |
| | | #define KEY4 3 /*KEY S4 use GPF3/EINT3 port*/ |
| | | #define KEY5 4 /*KEY S5 use GPF4/EINT4 port*/ |
| | | |
| | | .text |
| | | .align 2 |
| | | .global _start |
| | | |
| | | _start: |
| | | |
| | | /* Disable watch dog */ |
| | | ldr r0, =pWTCON /*Save pwTCON address in r0*/ |
| | | mov r1, #0x0 /*Set r1=0x0*/ |
| | | str r1, [r0] /*Move the data in r1 to the address specify by r0*/ |
| | | |
| | | /* mask all IRQs by setting all bits in the INTMR - default */ |
| | | mov r1, #0xffffffff |
| | | ldr r0, =INTMSK |
| | | str r1, [r0] |
| | | |
| | | ldr r0, =INTSUBMSK |
| | | ldr r1, =0x7fff /*There are 15 bits used in INTSUBMSK on S3C2440*/ |
| | | str r1, [r0] |
| | | |
| | | /*Set Beep GPIO port as GPIO input mode*/ |
| | | ldr r0, =GPFCON |
| | | ldr r1, [r0] |
| | | bic r1, r1, #0xf3 /* Set GPF0, GPF2, GPF3, as GPIO input mode(00)*/ |
| | | bic r1, r1, #0x0300 /* Set GPF4 as GPIO input mode(00)*/ |
| | | str r1, [r0] |
| | | |
| | | bl init_led_buzzer /*Call C function to init buzzer and LED GPIO port*/ |
| | | |
| | | loop_detect: |
| | | bl turn_led_buzzer_off |
| | | |
| | | ldr r1, =GPFDAT /*Read the four key GPIO data port*/ |
| | | ldr r2, [r1] |
| | | |
| | | /*Check Key2 pressed down or not*/ |
| | | mov r0, #0 /*Turn LED0 on*/ |
| | | tst r2, #0x1 |
| | | bleq led_beep_on |
| | | |
| | | /*Check Key3 pressed down or not*/ |
| | | mov r0, #1 /*Turn LED1 on*/ |
| | | tst r2, #0x4 |
| | | bleq led_beep_on |
| | | |
| | | /*Check Key4 pressed down or not*/ |
| | | mov r0, #2 /*Turn LED2 on*/ |
| | | tst r2, #0x8 |
| | | bleq led_beep_on |
| | | |
| | | /*Check Key5 pressed down or not*/ |
| | | mov r0, #3 /*Turn LED3 on*/ |
| | | tst r2, #0x10 |
| | | bleq led_beep_on |
| | | |
| | | /*No key pressed, detect again*/ |
| | | b loop_detect |
| | | |
| | | led_beep_on: |
| | | bl turn_led_buzzer_on /*Turn buzzer beep*/ |
| | | @mov pc, lr /*Why mov lr, pc can not work?*/ |
| | | b loop_detect |
| | | |
| | | |
| | | /*Won't come here*/ |
| | | halt_loop: |
| | | b halt_loop |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: led.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code used to turn LED0~LED4 on on FL2440 board |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define GPBCON (*(unsigned long volatile *)0x56000010) |
| | | #define GPBDAT (*(unsigned long volatile *)0x56000014) |
| | | #define GPBUP (*(unsigned long volatile *)0x56000018) |
| | | |
| | | #define LED0 5 /*LED0 use GPB5*/ |
| | | #define LED1 6 /*LED1 use GPB6*/ |
| | | #define LED2 8 /*LED2 use GPB8*/ |
| | | #define LED3 10 /*LED3 use GPB10*/ |
| | | |
| | | #define DELAY_TIME 1000000 |
| | | |
| | | static inline void delay (unsigned long loops) |
| | | { |
| | | __asm__ volatile ("1:\n" |
| | | "subs %0, %1, #1\n" |
| | | "bne 1b":"=r" (loops):"0" (loops)); |
| | | } |
| | | |
| | | void led_init(void) |
| | | { |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ |
| | | GPBCON = (GPBCON|0x333C00)&0x111400; |
| | | GPBUP = (GPBUP | 0x560); |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ |
| | | GPBDAT = (GPBDAT | 0x560); |
| | | } |
| | | |
| | | int main(void) |
| | | { |
| | | led_init(); |
| | | while(1) |
| | | { |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ |
| | | GPBDAT = (GPBDAT | 0x560); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED0 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED0)) ); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED1 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED1)) ); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED2 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED2)) ); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED3 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED3)) ); |
| | | delay(DELAY_TIME); |
| | | } |
| | | } |
| | | |
| | | void turn_led_on(int led) |
| | | { |
| | | GPBDAT = (GPBDAT & (~(1<<led)) ); |
| | | delay(DELAY_TIME); |
| | | } |
| | | |
| | | void turn_led_off(int led) |
| | | { |
| | | /* Turn LED0 on */ |
| | | GPBDAT = (GPBDAT | (1<<led) ); |
| | | delay(DELAY_TIME); |
| | | } |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: led.lds |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: Cross tool link text, refer to u-boot.lds |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") |
| | | OUTPUT_ARCH(arm) |
| | | ENTRY(_start) |
| | | |
| | | SECTIONS{ |
| | | . = 0x33000000; |
| | | .text : { |
| | | *(.text) |
| | | *(.rodata) |
| | | } |
| | | |
| | | .data ALIGN(4): { |
| | | *(.data) |
| | | } |
| | | |
| | | .bss ALIGN(4): { |
| | | *(.bss) |
| | | } |
| | | } |
New file |
| | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM and C source code |
| | | # * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | |
| | | BINAME = led |
| | | TEXTBASE = 0x33000000 |
| | | |
| | | CROSS = /opt/xtools/arm920t/bin/arm-linux- |
| | | CC = $(CROSS)gcc |
| | | LD = $(CROSS)ld |
| | | AR = $(CROSS)ar |
| | | OBJCOPY = $(CROSS)objcopy |
| | | OBJDUMP = $(CROSS)objdump |
| | | STRIP = $(CROSS)strip |
| | | READELF = $(CROSS)readelf |
| | | |
| | | CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin |
| | | AFLAGS = $(CFLAGS) -D__ASSEMBLY__ |
| | | |
| | | LDSCRIPT = ${BINAME}.lds |
| | | LDFLAGS = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE) |
| | | |
| | | SRC_C = $(wildcard *.c) |
| | | SRC_S = $(wildcard *.S) |
| | | OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) |
| | | OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) |
| | | |
| | | OBJ_ALL = $(OBJ_C) $(OBJ_S) |
| | | |
| | | .PHONY : all |
| | | all: ${OBJ_ALL} |
| | | ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} |
| | | ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin |
| | | rm -f *.elf *.o |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: |
| | | cp ${BINAME}.bin ~/winxp -f --reply=yes |
| | | |
| | | clean: |
| | | rm -f *.elf *.o |
| | | rm -f ${BINAME}.bin |
New file |
| | |
| | | /*********************************************************************** |
| | | * File: start.S |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This ASM used to disable watch dog and interrupt, then call C code to |
| | | * turn the four LEDs on/off on FL2440 board. |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define pWTCON 0x53000000 /* Watch dog register address */ |
| | | #define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ |
| | | #define INTSUBMSK 0x4A00001C |
| | | |
| | | #define LED0 5 /*LED0 use GPB5*/ |
| | | #define LED1 6 /*LED1 use GPB6*/ |
| | | #define LED2 8 /*LED2 use GPB8*/ |
| | | #define LED3 10 /*LED3 use GPB10*/ |
| | | |
| | | |
| | | .text |
| | | .align 2 |
| | | .global _start |
| | | |
| | | _start: |
| | | |
| | | /* Disable watch dog */ |
| | | ldr r0, =pWTCON /*Save pwTCON address in r0*/ |
| | | mov r1, #0x0 /*Set r1=0x0*/ |
| | | str r1, [r0] /*Move the data in r1 to the address specify by r0*/ |
| | | |
| | | |
| | | /* mask all IRQs by setting all bits in the INTMR - default */ |
| | | mov r1, #0xffffffff |
| | | ldr r0, =INTMSK |
| | | str r1, [r0] |
| | | |
| | | ldr r0, =INTSUBMSK |
| | | ldr r1, =0x7fff /*There are 15 bits used in INTSUBMSK on S3C2440*/ |
| | | str r1, [r0] |
| | | |
| | | bl led_init |
| | | |
| | | loop: |
| | | mov r0,#LED0 |
| | | bl turn_led_on |
| | | |
| | | mov r0,#LED1 |
| | | bl turn_led_on |
| | | |
| | | mov r0,#LED2 |
| | | bl turn_led_on |
| | | |
| | | mov r0,#LED3 |
| | | bl turn_led_on |
| | | |
| | | mov r0,#LED0 |
| | | bl turn_led_off |
| | | |
| | | mov r0,#LED1 |
| | | bl turn_led_off |
| | | |
| | | mov r0,#LED2 |
| | | bl turn_led_off |
| | | |
| | | mov r0,#LED3 |
| | | bl turn_led_off |
| | | |
| | | b loop |
| | | |
| | | @bl main |
| | | |
| | | halt_loop: |
| | | b halt_loop |
| | | |
New file |
| | |
| | | /*********************************************************************** |
| | | * File: led.S |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This ASM code used to turn LED0~LED4 on/off on FL2440 board |
| | | * ChangeLog: 1, Release initial version on "Sun Mar 20 18:41:04 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | |
| | | #define GPBCON 0x56000010 |
| | | #define GPBDAT 0x56000014 |
| | | #define GPBUP 0x56000018 |
| | | |
| | | #define OUTPUT 0x01 /*Set GPIO port as output mode*/ |
| | | #define INPUT 0x00 /*Set GPIO port as input mode*/ |
| | | |
| | | #define BEEP 0 /*On FL2440 board, LED0 use GPB0*/ |
| | | #define LED0 5 /*On FL2440 board, LED0 use GPB5*/ |
| | | #define LED1 6 /*On FL2440 board, LED0 use GPB6*/ |
| | | #define LED2 8 /*On FL2440 board, LED0 use GPB8*/ |
| | | #define LED3 10 /*On FL2440 board, LED0 use GPB10*/ |
| | | |
| | | #define DELAY 0X1000000 |
| | | |
| | | .text |
| | | .align 2 |
| | | .global _start |
| | | |
| | | _start: |
| | | /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/ |
| | | ldr r0, =GPBCON |
| | | ldr r1, [r0] |
| | | bic r1, r1, #0x3c00 /*Set GPBCON for GPIO5,GPIO6 as 0x00 */ |
| | | orr r1, r1, #0x1400 /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/ |
| | | bic r1, r1, #0x00330000 /*Set GPBCON for GPIO8,GPIO10 as 0x00*/ |
| | | orr r1, r1, #0x00110000 /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/ |
| | | str r1, [r0] |
| | | |
| | | /*Set internal pullup resister*/ |
| | | ldr r0, =GPBUP |
| | | ldr r1, [r0] |
| | | orr r1, r1, #0x0560 /*Set bit 5,6,8,10, disable pullup resister*/ |
| | | @bic r1, r1, #0x0560 /*Clear bit 5,6,8,10, enable pullup resister*/ |
| | | str r1, [r0] |
| | | |
| | | |
| | | loopled: |
| | | /*Turn off LED5, LED6, LED8, LED10*/ |
| | | ldr r2, =GPBDAT |
| | | ldr r3, [r2] |
| | | orr r3, r3, #0x0560 /*Set bit 5,6,8,10 as high level*/ |
| | | str r3, [r2] |
| | | ldr r0, =DELAY /*Sleep for a while*/ |
| | | bl delay |
| | | |
| | | /*Turn on LED0*/ |
| | | ldr r3, [r2] |
| | | bic r3, r3, #(1<<LED0) /*Clear bit 5, set GPB5 as low level*/ |
| | | str r3, [r2] |
| | | ldr r0, =DELAY /*Sleep for a while*/ |
| | | bl delay |
| | | |
| | | /*Turn on LED1*/ |
| | | ldr r3, [r2] |
| | | bic r3, r3, #(1<<LED1) /*Clear bit 6, set GPB6 as low level*/ |
| | | str r3, [r2] |
| | | ldr r0, =DELAY /*Sleep for a while*/ |
| | | bl delay |
| | | |
| | | /*Turn on LED2*/ |
| | | ldr r3, [r2] |
| | | bic r3, r3, #(1<<LED2) /*Clear bit 8, set GPB8 as low level*/ |
| | | str r3, [r2] |
| | | ldr r0, =DELAY /*Sleep for a while*/ |
| | | bl delay |
| | | |
| | | /*Turn on LED3*/ |
| | | ldr r3, [r2] |
| | | bic r3, r3, #(1<<LED3) /*Clear bit 10, set GPB10 as low level*/ |
| | | str r3, [r2] |
| | | ldr r0, =DELAY /*Sleep for a while*/ |
| | | bl delay |
| | | |
| | | |
| | | b loopled /*Loop running LED*/ |
| | | |
| | | delay: |
| | | sub r0, r0, #1 |
| | | cmp r0, #0x0 |
| | | bne delay |
| | | mov pc, lr |
| | | |
New file |
| | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM and C source code |
| | | # * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | |
| | | BINAME = led |
| | | TEXTBASE = 0x33000000 |
| | | #TEXTBASE =0 |
| | | |
| | | CROSS = /opt/xtools/arm920t/bin/arm-linux- |
| | | CC = $(CROSS)gcc |
| | | LD = $(CROSS)ld |
| | | AR = $(CROSS)ar |
| | | OBJCOPY = $(CROSS)objcopy |
| | | OBJDUMP = $(CROSS)objdump |
| | | STRIP = $(CROSS)strip |
| | | READELF = $(CROSS)readelf |
| | | |
| | | CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin |
| | | AFLAGS = $(CFLAGS) -D__ASSEMBLY__ |
| | | |
| | | LDFLAGS = -Ttext $(TEXTBASE) |
| | | |
| | | SRC_C = $(wildcard *.c) |
| | | SRC_S = $(wildcard *.S) |
| | | OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) |
| | | OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) |
| | | |
| | | OBJ_ALL = $(OBJ_C) $(OBJ_S) |
| | | |
| | | .PHONY : all |
| | | all: ${OBJ_ALL} |
| | | ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} |
| | | ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin |
| | | rm -f *.elf *.o |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: |
| | | cp ${BINAME}.bin ~/winxp -f --reply=yes |
| | | |
| | | clean: |
| | | rm -f *.elf *.o |
| | | rm -f ${BINAME}.bin |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: led.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code used to turn LED0~LED4 on on FL2440 board |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | #define GPBCON (*(unsigned long volatile *)0x56000010) |
| | | #define GPBDAT (*(unsigned long volatile *)0x56000014) |
| | | #define GPBUP (*(unsigned long volatile *)0x56000018) |
| | | |
| | | #define LED0 5 /*LED0 use GPB5*/ |
| | | #define LED1 6 /*LED1 use GPB6*/ |
| | | #define LED2 8 /*LED2 use GPB8*/ |
| | | #define LED3 10 /*LED3 use GPB10*/ |
| | | |
| | | #define DELAY_TIME 20000000 |
| | | |
| | | static inline void delay (unsigned long loops) |
| | | { |
| | | __asm__ volatile ("1:\n" |
| | | "subs %0, %1, #1\n" |
| | | "bne 1b":"=r" (loops):"0" (loops)); |
| | | } |
| | | |
| | | int main(void) |
| | | { |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ |
| | | GPBCON = (GPBCON|0x333C00)&0x111400; |
| | | GPBUP = (GPBUP | 0x560); |
| | | |
| | | while(1) |
| | | { |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ |
| | | GPBDAT = (GPBDAT | 0x560); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED0 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED0)) ); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED1 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED1)) ); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED2 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED2)) ); |
| | | delay(DELAY_TIME); |
| | | |
| | | /* Turn LED3 on */ |
| | | GPBDAT = (GPBDAT & (~(1<<LED3)) ); |
| | | delay(DELAY_TIME); |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | |
| | | /*********************************************************************** |
| | | * File: led.lds |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: Cross tool link text, refer to u-boot.lds |
| | | * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | * |
| | | ***********************************************************************/ |
| | | |
| | | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") |
| | | OUTPUT_ARCH(arm) |
| | | ENTRY(main) |
| | | |
| | | SECTIONS{ |
| | | . = 0x33000000; |
| | | .text : { |
| | | *(.text) |
| | | *(.rodata) |
| | | } |
| | | |
| | | .data ALIGN(4): { |
| | | *(.data) |
| | | } |
| | | |
| | | .bss ALIGN(4): { |
| | | *(.bss) |
| | | } |
| | | } |
New file |
| | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM and C source code |
| | | # * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | |
| | | BINAME = led |
| | | TEXTBASE = 0x33000000 |
| | | |
| | | CROSS = /opt/xtools/arm920t/bin/arm-linux- |
| | | CC = $(CROSS)gcc |
| | | LD = $(CROSS)ld |
| | | AR = $(CROSS)ar |
| | | OBJCOPY = $(CROSS)objcopy |
| | | OBJDUMP = $(CROSS)objdump |
| | | STRIP = $(CROSS)strip |
| | | READELF = $(CROSS)readelf |
| | | |
| | | CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin |
| | | AFLAGS = $(CFLAGS) -D__ASSEMBLY__ |
| | | |
| | | LDSCRIPT = ${BINAME}.lds |
| | | LDFLAGS = -T $(LDSCRIPT) -Ttext $(TEXTBASE) |
| | | |
| | | SRC_C = $(wildcard *.c) |
| | | SRC_S = $(wildcard *.S) |
| | | OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) |
| | | OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) |
| | | |
| | | OBJ_ALL = $(OBJ_C) $(OBJ_S) |
| | | |
| | | .PHONY : all |
| | | all: ${OBJ_ALL} |
| | | ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} |
| | | ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin |
| | | rm -f *.elf *.o |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: |
| | | cp ${BINAME}.bin ~/winxp -f --reply=yes |
| | | |
| | | clean: |
| | | rm -f *.elf *.o |
| | | rm -f ${BINAME}.bin |
New file |
| | |
| | | /* |
| | | * Multi-precision integer library |
| | | * |
| | | * Copyright (C) 2006 Christophe Devine |
| | | * |
| | | * This library is free software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU Lesser General Public |
| | | * License, version 2.1 as published by the Free Software Foundation. |
| | | * |
| | | * This library is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| | | * MA 02110-1301 USA |
| | | */ |
| | | /* |
| | | * This MPI implementation is based on: |
| | | * |
| | | * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf |
| | | * http://math.libtomcrypt.com/files/tommath.pdf |
| | | */ |
| | | |
| | | #ifndef _CRT_SECURE_NO_DEPRECATE |
| | | #define _CRT_SECURE_NO_DEPRECATE 1 |
| | | #endif |
| | | #include <common.h> |
| | | #include <bignum.h> |
| | | |
| | | /* |
| | | * Bits/chars to # of limbs conversion |
| | | */ |
| | | #define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) |
| | | #define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) |
| | | |
| | | /* |
| | | * Initialize one or more mpi |
| | | */ |
| | | void mpi_init( mpi *X, ... ) |
| | | { |
| | | va_list args; |
| | | |
| | | va_start( args, X ); |
| | | |
| | | while( X != NULL ) |
| | | { |
| | | memset( X, 0, sizeof( mpi ) ); |
| | | X = va_arg( args, mpi* ); |
| | | } |
| | | |
| | | va_end( args ); |
| | | } |
| | | |
| | | /* |
| | | * Unallocate one or more mpi |
| | | */ |
| | | void mpi_free( mpi *X, ... ) |
| | | { |
| | | va_list args; |
| | | |
| | | va_start( args, X ); |
| | | |
| | | while( X != NULL ) |
| | | { |
| | | if( X->p != NULL ) |
| | | { |
| | | memset( X->p, 0, X->n * ciL ); |
| | | free( X->p ); |
| | | } |
| | | |
| | | memset( X, 0, sizeof( mpi ) ); |
| | | |
| | | X = va_arg( args, mpi* ); |
| | | } |
| | | |
| | | va_end( args ); |
| | | } |
| | | |
| | | /* |
| | | * Enlarge X to the specified # of limbs |
| | | */ |
| | | int mpi_grow( mpi *X, int nblimbs ) |
| | | { |
| | | int n = X->n; |
| | | |
| | | if( n < nblimbs ) |
| | | { |
| | | if( X->s == 0 ) |
| | | X->s = 1; |
| | | |
| | | X->n = nblimbs; |
| | | X->p = (t_int *) realloc( X->p, X->n * ciL ); |
| | | |
| | | if( X->p == NULL ) |
| | | return( 1 ); |
| | | |
| | | memset( X->p + n, 0, ( X->n - n ) * ciL ); |
| | | } |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Copy the contents of Y into X |
| | | */ |
| | | int mpi_copy( mpi *X, mpi *Y ) |
| | | { |
| | | int ret, i; |
| | | |
| | | if( X == Y ) |
| | | return( 0 ); |
| | | |
| | | for( i = Y->n - 1; i > 0; i-- ) |
| | | if( Y->p[i] != 0 ) |
| | | break; |
| | | i++; |
| | | |
| | | X->s = Y->s; |
| | | |
| | | CHK( mpi_grow( X, i ) ); |
| | | |
| | | memset( X->p, 0, X->n * ciL ); |
| | | memcpy( X->p, Y->p, i * ciL ); |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Swap the contents of X and Y |
| | | */ |
| | | void mpi_swap( mpi *X, mpi *Y ) |
| | | { |
| | | mpi T; |
| | | |
| | | memcpy( &T, X , sizeof( mpi ) ); |
| | | memcpy( X , Y , sizeof( mpi ) ); |
| | | memcpy( Y , &T, sizeof( mpi ) ); |
| | | } |
| | | |
| | | /* |
| | | * Set value from integer |
| | | */ |
| | | int mpi_lset( mpi *X, int z ) |
| | | { |
| | | int ret; |
| | | |
| | | CHK( mpi_grow( X, 1 ) ); |
| | | memset( X->p, 0, X->n * ciL ); |
| | | X->p[0] = ( z < 0 ) ? -z : z; |
| | | X->s = ( z < 0 ) ? -1 : 1; |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Convert an ASCII character to digit value |
| | | */ |
| | | static int mpi_get_digit( t_int *d, int radix, char c ) |
| | | { |
| | | *d = 16; |
| | | |
| | | if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; |
| | | if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; |
| | | if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; |
| | | |
| | | if( *d >= (t_int) radix ) |
| | | return( ERR_MPI_INVALID_CHARACTER ); |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Set value from string |
| | | */ |
| | | int mpi_read( mpi *X, char *s, int radix ) |
| | | { |
| | | int ret, i, j, n; |
| | | t_int d; |
| | | mpi T; |
| | | |
| | | if( radix < 2 || radix > 16 ) |
| | | return( ERR_MPI_INVALID_PARAMETER ); |
| | | |
| | | mpi_init( &T, NULL ); |
| | | |
| | | if( radix == 16 ) |
| | | { |
| | | n = BITS_TO_LIMBS( strlen(s) << 2 ); |
| | | |
| | | CHK( mpi_grow( X, n ) ); |
| | | CHK( mpi_lset( X, 0 ) ); |
| | | |
| | | for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ ) |
| | | { |
| | | if( i == 0 && s[i] == '-' ) |
| | | { |
| | | X->s = -1; |
| | | break; |
| | | } |
| | | |
| | | CHK( mpi_get_digit( &d, radix, s[i] ) ); |
| | | X->p[j / (ciL * 2)] |= d << ( (j % (ciL * 2)) << 2 ); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_lset( X, 0 ) ); |
| | | |
| | | for( i = 0; i < (int) strlen( s ); i++ ) |
| | | { |
| | | if( i == 0 && s[i] == '-' ) |
| | | { |
| | | X->s = -1; |
| | | continue; |
| | | } |
| | | |
| | | CHK( mpi_get_digit( &d, radix, s[i] ) ); |
| | | CHK( mpi_mul_int( &T, X, radix ) ); |
| | | CHK( mpi_add_int( X, &T, d ) ); |
| | | } |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &T, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Helper to display the digits high-order first |
| | | */ |
| | | static int mpi_recurse_showf( mpi *X, int radix, FILE *fout ) |
| | | { |
| | | int ret; |
| | | t_int r; |
| | | |
| | | if( radix < 2 || radix > 16 ) |
| | | return( ERR_MPI_INVALID_PARAMETER ); |
| | | |
| | | CHK( mpi_mod_int( &r, X, radix ) ); |
| | | CHK( mpi_div_int( X, NULL, X, radix ) ); |
| | | |
| | | if( mpi_cmp_int( X, 0 ) != 0 ) |
| | | CHK( mpi_recurse_showf( X, radix, fout ) ); |
| | | |
| | | if( fout != NULL ) |
| | | fprintf( fout, "%c", ( r < 10 ) ? ( (char) r + 0x30 ) |
| | | : ( (char) r + 0x37 ) ); |
| | | else |
| | | printf( "%c", ( r < 10 ) ? ( (char) r + 0x30 ) |
| | | : ( (char) r + 0x37 ) ); |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Print the value of X into fout |
| | | */ |
| | | int mpi_showf( char *name, mpi *X, int radix, FILE *fout ) |
| | | { |
| | | int ret, i, j, k, l; |
| | | mpi T; |
| | | |
| | | if( radix < 2 || radix > 16 ) |
| | | return( ERR_MPI_INVALID_PARAMETER ); |
| | | |
| | | mpi_init( &T, NULL ); |
| | | |
| | | if( fout != NULL ) |
| | | fprintf( fout, "%s%c", name, ( X->s == -1 ) ? '-' : ' ' ); |
| | | else |
| | | printf( "%s%c", name, ( X->s == -1 ) ? '-' : ' ' ); |
| | | |
| | | if( radix == 16 ) |
| | | { |
| | | ret = 0; |
| | | |
| | | for( i = X->n - 1, l = 0; i >= 0; i-- ) |
| | | { |
| | | for( j = ciL - 1; j >= 0; j-- ) |
| | | { |
| | | k = ( X->p[i] >> (j << 3) ) & 0xFF; |
| | | |
| | | if( k == 0 && l == 0 && (i + j) != 0 ) |
| | | continue; |
| | | |
| | | if( fout != NULL ) |
| | | fprintf( fout, "%02X", k ); |
| | | else |
| | | printf( "%02X", k ); |
| | | |
| | | l = 1; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_copy( &T, X ) ); |
| | | CHK( mpi_recurse_showf( &T, radix, fout ) ); |
| | | } |
| | | |
| | | if( fout != NULL ) |
| | | fprintf( fout, "\n" ); |
| | | else |
| | | printf( "\n" ); |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &T, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Print the value of X on the console |
| | | */ |
| | | int mpi_show( char *name, mpi *X, int radix ) |
| | | { |
| | | return( mpi_showf( name, X, radix, NULL ) ); |
| | | } |
| | | |
| | | /* |
| | | * Import an unsigned value from binary data |
| | | */ |
| | | int mpi_import( mpi *X, unsigned char *buf, int buflen ) |
| | | { |
| | | int ret, i, j, n; |
| | | |
| | | for( n = 0; n < buflen; n++ ) |
| | | if( buf[n] != 0 ) |
| | | break; |
| | | |
| | | CHK( mpi_grow( X, CHARS_TO_LIMBS(buflen - n) ) ); |
| | | CHK( mpi_lset( X, 0 ) ); |
| | | |
| | | for( i = buflen - 1, j = 0; i >= n; i--, j++ ) |
| | | X->p[j / ciL] |= (t_int) buf[i] << ((j % ciL ) << 3); |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Export an unsigned value into binary data |
| | | */ |
| | | int mpi_export( mpi *X, unsigned char *buf, int *buflen ) |
| | | { |
| | | int i, j, n, ilen; |
| | | |
| | | n = ( mpi_size( X ) + 7 ) >> 3;
|
| | | ilen = n; |
| | | |
| | | if( *buflen < n ) |
| | | { |
| | | *buflen = n; |
| | | return( ERR_MPI_BUFFER_TOO_SMALL ); |
| | | }
|
| | | //*buflen = ilen;
|
| | | |
| | | |
| | | memset( buf, 0, *buflen ); |
| | | |
| | | for( i = *buflen - 1, j = 0; n > 0; i--, j++, n-- ) |
| | | buf[i] = (unsigned char) (X->p[j / ciL] >> ((j % ciL) << 3));
|
| | |
|
| | | |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Return the actual size in bits (without leading 0s) |
| | | */ |
| | | int mpi_size( mpi *X ) |
| | | { |
| | | int i, j; |
| | | |
| | | for( i = X->n - 1; i > 0; i-- ) |
| | | if( X->p[i] != 0 ) |
| | | break; |
| | | |
| | | for( j = biL - 1; j >= 0; j-- ) |
| | | if( ( ( X->p[i] >> j ) & 1 ) != 0 ) |
| | | break; |
| | | |
| | | return( ( i * biL ) + j + 1 ); |
| | | } |
| | | |
| | | /* |
| | | * Return the number of least significant bits |
| | | */ |
| | | int mpi_lsb( mpi *X ) |
| | | { |
| | | int i, j, count = 0; |
| | | |
| | | for( i = 0; i < X->n; i++ ) |
| | | for( j = 0; j < (int) biL; j++, count++ ) |
| | | if( ( ( X->p[i] >> j ) & 1 ) != 0 ) |
| | | return( count ); |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Left-shift: X <<= count |
| | | */ |
| | | int mpi_shift_l( mpi *X, int count ) |
| | | { |
| | | int ret, i, v0, t1; |
| | | t_int r0 = 0, r1; |
| | | |
| | | v0 = count / biL; |
| | | t1 = count & (biL - 1); |
| | | |
| | | i = mpi_size( X ) + count; |
| | | |
| | | if( X->n * (int) biL < i ) |
| | | CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); |
| | | |
| | | ret = 0; |
| | | |
| | | /* |
| | | * shift by count / limb_size |
| | | */ |
| | | if( v0 > 0 ) |
| | | { |
| | | for( i = X->n - 1; i >= v0; i-- ) |
| | | X->p[i] = X->p[i - v0]; |
| | | |
| | | for( ; i >= 0; i-- ) |
| | | X->p[i] = 0; |
| | | } |
| | | |
| | | /* |
| | | * shift by count % limb_size |
| | | */ |
| | | if( t1 > 0 ) |
| | | { |
| | | for( i = v0; i < X->n; i++ ) |
| | | { |
| | | r1 = X->p[i] >> (biL - t1); |
| | | X->p[i] <<= t1; |
| | | X->p[i] |= r0; |
| | | r0 = r1; |
| | | } |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Right-shift: X >>= count |
| | | */ |
| | | int mpi_shift_r( mpi *X, int count ) |
| | | { |
| | | int i, v0, v1; |
| | | t_int r0 = 0, r1; |
| | | |
| | | v0 = count / biL; |
| | | v1 = count & (biL - 1); |
| | | |
| | | /* |
| | | * shift by count / limb_size |
| | | */ |
| | | if( v0 > 0 ) |
| | | { |
| | | for( i = 0; i < X->n - v0; i++ ) |
| | | X->p[i] = X->p[i + v0]; |
| | | |
| | | for( ; i < X->n; i++ ) |
| | | X->p[i] = 0; |
| | | } |
| | | |
| | | /* |
| | | * shift by count % limb_size |
| | | */ |
| | | if( v1 > 0 ) |
| | | { |
| | | for( i = X->n - 1; i >= 0; i-- ) |
| | | { |
| | | r1 = X->p[i] << (biL - v1); |
| | | X->p[i] >>= v1; |
| | | X->p[i] |= r0; |
| | | r0 = r1; |
| | | } |
| | | } |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Compare unsigned values |
| | | */ |
| | | int mpi_cmp_abs( mpi *X, mpi *Y ) |
| | | { |
| | | int i, j; |
| | | |
| | | for( i = X->n - 1; i >= 0; i-- ) |
| | | if( X->p[i] != 0 ) |
| | | break; |
| | | |
| | | for( j = Y->n - 1; j >= 0; j-- ) |
| | | if( Y->p[j] != 0 ) |
| | | break; |
| | | |
| | | if( i < 0 && j < 0 ) |
| | | return( 0 ); |
| | | |
| | | if( i > j ) return( 1 ); |
| | | if( j > i ) return( -1 ); |
| | | |
| | | for( ; i >= 0; i-- ) |
| | | { |
| | | if( X->p[i] > Y->p[i] ) return( 1 ); |
| | | if( X->p[i] < Y->p[i] ) return( -1 ); |
| | | } |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Compare signed values |
| | | */ |
| | | int mpi_cmp_mpi( mpi *X, mpi *Y ) |
| | | { |
| | | int i, j; |
| | | |
| | | for( i = X->n - 1; i >= 0; i-- ) |
| | | if( X->p[i] != 0 ) |
| | | break; |
| | | |
| | | for( j = Y->n - 1; j >= 0; j-- ) |
| | | if( Y->p[j] != 0 ) |
| | | break; |
| | | |
| | | if( i < 0 && j < 0 ) |
| | | return( 0 ); |
| | | |
| | | if( i > j ) return( X->s ); |
| | | if( j > i ) return( -X->s ); |
| | | |
| | | if( X->s > 0 && Y->s < 0 ) return( 1 ); |
| | | if( Y->s > 0 && X->s < 0 ) return( -1 ); |
| | | |
| | | for( ; i >= 0; i-- ) |
| | | { |
| | | if( X->p[i] > Y->p[i] ) return( X->s ); |
| | | if( X->p[i] < Y->p[i] ) return( -X->s ); |
| | | } |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Compare signed values |
| | | */ |
| | | int mpi_cmp_int( mpi *X, int z ) |
| | | { |
| | | mpi Y; |
| | | t_int p[1]; |
| | | |
| | | *p = ( z < 0 ) ? -z : z; |
| | | Y.s = ( z < 0 ) ? -1 : 1; |
| | | Y.n = 1; |
| | | Y.p = p; |
| | | |
| | | return( mpi_cmp_mpi( X, &Y ) ); |
| | | } |
| | | |
| | | /* |
| | | * Unsigned addition: X = |A| + |B| (HAC 14.7) |
| | | */ |
| | | int mpi_add_abs( mpi *X, mpi *A, mpi *B ) |
| | | { |
| | | int ret, i, j; |
| | | t_int *o, *p, c; |
| | | |
| | | if( X == B ) |
| | | { |
| | | mpi *T = A; A = X; B = T; |
| | | } |
| | | |
| | | if( X != A ) |
| | | CHK( mpi_copy( X, A ) ); |
| | | |
| | | for( j = B->n - 1; j >= 0; j-- ) |
| | | if( B->p[j] != 0 ) |
| | | break; |
| | | |
| | | CHK( mpi_grow( X, j + 1 ) ); |
| | | |
| | | o = B->p; p = X->p; c = 0; |
| | | |
| | | for( i = 0; i <= j; i++, o++, p++ ) |
| | | { |
| | | *p += c; c = ( *p < c ); |
| | | *p += *o; c += ( *p < *o ); |
| | | } |
| | | |
| | | while( c != 0 ) |
| | | { |
| | | if( i >= X->n ) |
| | | { |
| | | CHK( mpi_grow( X, i + 1 ) ); |
| | | p = X->p + i; |
| | | } |
| | | |
| | | *p += c; c = ( *p < c ); i++; |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Helper for mpi substraction |
| | | */ |
| | | static void mpi_sub_hlp( int n, t_int *s, t_int *d ) |
| | | { |
| | | int i; |
| | | t_int c, z; |
| | | |
| | | for( i = c = 0; i < n; i++, s++, d++ ) |
| | | { |
| | | z = ( *d < c ); *d -= c; |
| | | c = ( *d < *s ) + z; *d -= *s; |
| | | } |
| | | |
| | | while( c != 0 ) |
| | | { |
| | | z = ( *d < c ); *d -= c; |
| | | c = z; i++; d++; |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * Unsigned substraction: X = |A| - |B| (HAC 14.9) |
| | | */ |
| | | int mpi_sub_abs( mpi *X, mpi *A, mpi *B ) |
| | | { |
| | | mpi TB; |
| | | int ret, n; |
| | | |
| | | if( mpi_cmp_abs( A, B ) < 0 ) |
| | | return( ERR_MPI_NEGATIVE_VALUE ); |
| | | |
| | | mpi_init( &TB, NULL ); |
| | | |
| | | if( X == B ) |
| | | { |
| | | CHK( mpi_copy( &TB, B ) ); |
| | | B = &TB; |
| | | } |
| | | |
| | | if( X != A ) |
| | | CHK( mpi_copy( X, A ) ); |
| | | |
| | | ret = 0; |
| | | |
| | | for( n = B->n - 1; n >= 0; n-- ) |
| | | if( B->p[n] != 0 ) |
| | | break; |
| | | |
| | | mpi_sub_hlp( n + 1, B->p, X->p ); |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &TB, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Signed addition: X = A + B |
| | | */ |
| | | int mpi_add_mpi( mpi *X, mpi *A, mpi *B ) |
| | | { |
| | | int ret, s = A->s; |
| | | |
| | | if( A->s * B->s < 0 ) |
| | | { |
| | | if( mpi_cmp_abs( A, B ) >= 0 ) |
| | | { |
| | | CHK( mpi_sub_abs( X, A, B ) ); |
| | | X->s = s; |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_sub_abs( X, B, A ) ); |
| | | X->s = -s; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_add_abs( X, A, B ) ); |
| | | X->s = s; |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Signed substraction: X = A - B |
| | | */ |
| | | int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ) |
| | | { |
| | | int ret, s = A->s; |
| | | |
| | | if( A->s * B->s > 0 ) |
| | | { |
| | | if( mpi_cmp_abs( A, B ) >= 0 ) |
| | | { |
| | | CHK( mpi_sub_abs( X, A, B ) ); |
| | | X->s = s; |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_sub_abs( X, B, A ) ); |
| | | X->s = -s; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_add_abs( X, A, B ) ); |
| | | X->s = s; |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Signed addition: X = A + b |
| | | */ |
| | | int mpi_add_int( mpi *X, mpi *A, int b ) |
| | | { |
| | | mpi _B; |
| | | t_int p[1]; |
| | | |
| | | p[0] = ( b < 0 ) ? -b : b; |
| | | _B.s = ( b < 0 ) ? -1 : 1; |
| | | _B.n = 1; |
| | | _B.p = p; |
| | | |
| | | return( mpi_add_mpi( X, A, &_B ) ); |
| | | } |
| | | |
| | | /* |
| | | * Signed substraction: X = A - b |
| | | */ |
| | | int mpi_sub_int( mpi *X, mpi *A, int b ) |
| | | { |
| | | mpi _B; |
| | | t_int p[1]; |
| | | |
| | | p[0] = ( b < 0 ) ? -b : b; |
| | | _B.s = ( b < 0 ) ? -1 : 1; |
| | | _B.n = 1; |
| | | _B.p = p; |
| | | |
| | | return( mpi_sub_mpi( X, A, &_B ) ); |
| | | } |
| | | |
| | | /* |
| | | * Helper for mpi multiplication |
| | | */ |
| | | static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b ) |
| | | { |
| | | t_int c = 0; |
| | | |
| | | #if defined(MULADDC_HUIT) |
| | | |
| | | for( ; i >= 8; i -= 8 ) |
| | | { |
| | | MULADDC_INIT |
| | | MULADDC_HUIT |
| | | MULADDC_STOP |
| | | } |
| | | |
| | | for( ; i > 0; i-- ) |
| | | { |
| | | MULADDC_INIT |
| | | MULADDC_CORE |
| | | MULADDC_STOP |
| | | } |
| | | |
| | | #else |
| | | if( i == 32 ) |
| | | { |
| | | MULADDC_INIT |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_STOP |
| | | } |
| | | else |
| | | { |
| | | if( i == 16 ) |
| | | { |
| | | MULADDC_INIT |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_STOP |
| | | } |
| | | else |
| | | { |
| | | for( ; i >= 8; i -= 8 ) |
| | | { |
| | | MULADDC_INIT |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_CORE MULADDC_CORE |
| | | MULADDC_STOP |
| | | } |
| | | |
| | | for( ; i > 0; i-- ) |
| | | { |
| | | MULADDC_INIT |
| | | MULADDC_CORE |
| | | MULADDC_STOP |
| | | } |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | do { |
| | | *d += c; c = ( *d < c ); d++; |
| | | } |
| | | while( c != 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Baseline multiplication: X = A * B (HAC 14.12) |
| | | */ |
| | | int mpi_mul_mpi( mpi *X, mpi *A, mpi *B ) |
| | | { |
| | | int ret, i, j; |
| | | mpi TA, TB; |
| | | |
| | | mpi_init( &TA, &TB, NULL ); |
| | | |
| | | if( X == A ) { CHK( mpi_copy( &TA, A ) ); A = &TA; } |
| | | if( X == B ) { CHK( mpi_copy( &TB, B ) ); B = &TB; } |
| | | |
| | | for( i = A->n - 1; i >= 0; i-- ) |
| | | if( A->p[i] != 0 ) |
| | | break; |
| | | |
| | | for( j = B->n - 1; j >= 0; j-- ) |
| | | if( B->p[j] != 0 ) |
| | | break; |
| | | |
| | | CHK( mpi_grow( X, i + j + 2 ) ); |
| | | CHK( mpi_lset( X, 0 ) ); |
| | | |
| | | for( i++; j >= 0; j-- ) |
| | | mpi_mul_hlp( i, A->p, X->p + j, B->p[j] ); |
| | | |
| | | X->s = A->s * B->s; |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &TB, &TA, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Baseline multiplication: X = A * b |
| | | */ |
| | | int mpi_mul_int( mpi *X, mpi *A, t_int b ) |
| | | { |
| | | mpi _B; |
| | | t_int p[1]; |
| | | |
| | | _B.s = 1; |
| | | _B.n = 1; |
| | | _B.p = p; |
| | | p[0] = b; |
| | | |
| | | return( mpi_mul_mpi( X, A, &_B ) ); |
| | | } |
| | | |
| | | /* |
| | | * Division by mpi: A = Q * B + R (HAC 14.20) |
| | | */ |
| | | int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B ) |
| | | { |
| | | int ret, i, n, t, k; |
| | | mpi X, Y, Z, T1, T2; |
| | | |
| | | if( mpi_cmp_int( B, 0 ) == 0 ) |
| | | return( ERR_MPI_DIVISION_BY_ZERO ); |
| | | |
| | | mpi_init( &X, &Y, &Z, &T1, &T2, NULL ); |
| | | |
| | | if( mpi_cmp_abs( A, B ) < 0 ) |
| | | { |
| | | if( Q != NULL ) CHK( mpi_lset( Q, 0 ) ); |
| | | if( R != NULL ) CHK( mpi_copy( R, A ) ); |
| | | return( 0 ); |
| | | } |
| | | |
| | | CHK( mpi_copy( &X, A ) ); |
| | | CHK( mpi_copy( &Y, B ) ); |
| | | X.s = Y.s = 1; |
| | | |
| | | CHK( mpi_grow( &Z, A->n + 2 ) ); |
| | | CHK( mpi_lset( &Z, 0 ) ); |
| | | CHK( mpi_grow( &T1, 2 ) ); |
| | | CHK( mpi_grow( &T2, 3 ) ); |
| | | |
| | | k = mpi_size( &Y ) % biL; |
| | | if( k < (int) biL - 1 ) |
| | | { |
| | | k = biL - 1 - k; |
| | | CHK( mpi_shift_l( &X, k ) ); |
| | | CHK( mpi_shift_l( &Y, k ) ); |
| | | } |
| | | else k = 0; |
| | | |
| | | n = X.n - 1; |
| | | t = Y.n - 1; |
| | | mpi_shift_l( &Y, biL * (n - t) ); |
| | | while( mpi_cmp_mpi( &X, &Y ) >= 0 ) |
| | | { |
| | | Z.p[n - t]++; |
| | | mpi_sub_mpi( &X, &X, &Y ); |
| | | } |
| | | mpi_shift_r( &Y, biL * (n - t) ); |
| | | |
| | | for( i = n; i > t ; i-- ) |
| | | { |
| | | if( X.p[i] >= Y.p[t] ) |
| | | Z.p[i - t - 1] = ~0; |
| | | else |
| | | { |
| | | #if defined(HAVE_LONGLONG) |
| | | t_dbl r; |
| | | |
| | | r = (t_dbl) X.p[i] << biL; |
| | | r |= (t_dbl) X.p[i - 1]; |
| | | r /= Y.p[t]; |
| | | if( r > ((t_dbl) 1 << biL) - 1) |
| | | r = ((t_dbl) 1 << biL) - 1; |
| | | |
| | | Z.p[i - t - 1] = (t_int) r; |
| | | #else |
| | | /* |
| | | * __udiv_qrnnd_c, from GMP/longlong.h |
| | | */ |
| | | t_int q0, q1, r0, r1; |
| | | t_int d0, d1, d, m; |
| | | |
| | | d = Y.p[t]; |
| | | d0 = ( d << biH ) >> biH; |
| | | d1 = ( d >> biH ); |
| | | |
| | | q1 = X.p[i] / d1; |
| | | r1 = X.p[i] - d1 * q1; |
| | | r1 <<= biH; |
| | | r1 |= ( X.p[i - 1] >> biH ); |
| | | |
| | | m = q1 * d0; |
| | | if( r1 < m ) |
| | | { |
| | | q1--, r1 += d; |
| | | while( r1 >= d && r1 < m ) |
| | | q1--, r1 += d; |
| | | } |
| | | r1 -= m; |
| | | |
| | | q0 = r1 / d1; |
| | | r0 = r1 - d1 * q0; |
| | | r0 <<= biH; |
| | | r0 |= ( X.p[i - 1] << biH ) >> biH; |
| | | |
| | | m = q0 * d0; |
| | | if( r0 < m ) |
| | | { |
| | | q0--, r0 += d; |
| | | while( r0 >= d && r0 < m ) |
| | | q0--, r0 += d; |
| | | } |
| | | r0 -= m; |
| | | |
| | | Z.p[i - t - 1] = ( q1 << biH ) | q0; |
| | | #endif |
| | | } |
| | | |
| | | Z.p[i - t - 1]++; |
| | | do |
| | | { |
| | | Z.p[i - t - 1]--; |
| | | |
| | | CHK( mpi_lset( &T1, 0 ) ); |
| | | T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; |
| | | T1.p[1] = Y.p[t]; |
| | | CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); |
| | | |
| | | CHK( mpi_lset( &T2, 0 ) ); |
| | | T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; |
| | | T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; |
| | | T2.p[2] = X.p[i]; |
| | | } |
| | | while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); |
| | | |
| | | CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); |
| | | CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); |
| | | CHK( mpi_sub_mpi( &X, &X, &T1 ) ); |
| | | |
| | | if( mpi_cmp_int( &X, 0 ) < 0 ) |
| | | { |
| | | CHK( mpi_copy( &T1, &Y ) ); |
| | | CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); |
| | | CHK( mpi_add_mpi( &X, &X, &T1 ) ); |
| | | Z.p[i - t - 1]--; |
| | | } |
| | | } |
| | | |
| | | if( Q != NULL ) |
| | | { |
| | | mpi_copy( Q, &Z ); |
| | | Q->s = A->s * B->s; |
| | | } |
| | | |
| | | if( R != NULL ) |
| | | { |
| | | mpi_shift_r( &X, k ); |
| | | mpi_copy( R, &X ); |
| | | |
| | | R->s = A->s; |
| | | if( mpi_cmp_int( R, 0 ) == 0 ) |
| | | R->s = 1; |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &X, &Y, &Z, &T1, &T2, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Division by int: A = Q * b + R |
| | | * |
| | | * Returns 0 if successful |
| | | * 1 if memory allocation failed |
| | | * ERR_MPI_DIVISION_BY_ZERO if b == 0 |
| | | */ |
| | | int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b ) |
| | | { |
| | | mpi _B; |
| | | t_int p[1]; |
| | | |
| | | p[0] = ( b < 0 ) ? -b : b; |
| | | _B.s = ( b < 0 ) ? -1 : 1; |
| | | _B.n = 1; |
| | | _B.p = p; |
| | | |
| | | return( mpi_div_mpi( Q, R, A, &_B ) ); |
| | | } |
| | | |
| | | /* |
| | | * Modulo: R = A mod B |
| | | */ |
| | | int mpi_mod_mpi( mpi *R, mpi *A, mpi *B ) |
| | | { |
| | | int ret; |
| | | |
| | | CHK( mpi_div_mpi( NULL, R, A, B ) ); |
| | | |
| | | while( mpi_cmp_int( R, 0 ) < 0 ) |
| | | CHK( mpi_add_mpi( R, R, B ) ); |
| | | |
| | | while( mpi_cmp_mpi( R, B ) >= 0 ) |
| | | CHK( mpi_sub_mpi( R, R, B ) ); |
| | | |
| | | cleanup: |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Modulo: r = A mod b |
| | | */ |
| | | int mpi_mod_int( t_int *r, mpi *A, int b ) |
| | | { |
| | | int i; |
| | | t_int x, y, z; |
| | | |
| | | if( b == 0 ) |
| | | return( ERR_MPI_DIVISION_BY_ZERO ); |
| | | |
| | | if( b < 0 ) |
| | | b = -b; |
| | | |
| | | /* |
| | | * handle trivial cases |
| | | */ |
| | | if( b == 1 ) { *r = 0; return( 0 ); } |
| | | if( b == 2 ) { *r = A->p[0] & 1; return( 0 ); } |
| | | |
| | | /* |
| | | * general case |
| | | */ |
| | | for( i = A->n - 1, y = 0; i >= 0; i-- ) |
| | | { |
| | | x = A->p[i]; |
| | | y = ( y << biH ) | ( x >> biH ); |
| | | z = y / b; |
| | | y -= z * b; |
| | | |
| | | x <<= biH; |
| | | y = ( y << biH ) | ( x >> biH ); |
| | | z = y / b; |
| | | y -= z * b; |
| | | } |
| | | |
| | | *r = y; |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Fast Montgomery initialization (thanks to Tom St Denis) |
| | | */ |
| | | static void mpi_montg_init( t_int *mm, mpi *N ) |
| | | { |
| | | t_int x, m0 = N->p[0]; |
| | | |
| | | x = m0; |
| | | x += ((m0 + 2) & 4) << 1; |
| | | x *= (2 - (m0 * x)); |
| | | |
| | | if( biL >= 16 ) x *= (2 - (m0 * x)); |
| | | if( biL >= 32 ) x *= (2 - (m0 * x)); |
| | | if( biL >= 64 ) x *= (2 - (m0 * x)); |
| | | |
| | | *mm = ~x + 1; |
| | | } |
| | | |
| | | /* |
| | | * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) |
| | | */ |
| | | static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T ) |
| | | { |
| | | int i, n, m; |
| | | t_int u0, u1, *d; |
| | | |
| | | memset( T->p, 0, ciL * T->n ); |
| | | |
| | | d = T->p; |
| | | n = N->n; |
| | | m = ( B->n < n ) ? B->n : n; |
| | | |
| | | for( i = 0; i < n; i++ ) |
| | | { |
| | | /* |
| | | * T = (T + u0*B + u1*N) / 2^biL |
| | | */ |
| | | u0 = A->p[i]; |
| | | u1 = ( d[0] + u0 * B->p[0] ) * mm; |
| | | |
| | | mpi_mul_hlp( m, B->p, d, u0 ); |
| | | mpi_mul_hlp( n, N->p, d, u1 ); |
| | | |
| | | *d++ = u0; d[n + 1] = 0; |
| | | } |
| | | |
| | | memcpy( A->p, d, ciL * (n + 1) ); |
| | | |
| | | if( mpi_cmp_abs( A, N ) >= 0 ) |
| | | mpi_sub_hlp( n, N->p, A->p ); |
| | | else |
| | | /* prevent timing attacks */ |
| | | mpi_sub_hlp( n, A->p, T->p ); |
| | | } |
| | | |
| | | /* |
| | | * Montgomery reduction: A = A * R^-1 mod N |
| | | */ |
| | | static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T ) |
| | | { |
| | | t_int z = 1; |
| | | mpi U; |
| | | |
| | | U.n = U.s = z; |
| | | U.p = &z; |
| | | |
| | | mpi_montmul( A, &U, N, mm, T ); |
| | | } |
| | | |
| | | /* |
| | | * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) |
| | | */ |
| | | int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR ) |
| | | { |
| | | int ret, i, j, wsize, wbits; |
| | | int bufsize, nblimbs, nbits; |
| | | t_int ei, mm, state; |
| | | mpi RR, T, W[64]; |
| | | |
| | | if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) |
| | | return( ERR_MPI_INVALID_PARAMETER ); |
| | | |
| | | /* |
| | | * Init temps and window size |
| | | */ |
| | | mpi_montg_init( &mm, N ); |
| | | mpi_init( &RR, &T, NULL ); |
| | | memset( W, 0, sizeof( W ) ); |
| | | |
| | | i = mpi_size( E ); |
| | | |
| | | wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : |
| | | ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; |
| | | |
| | | j = N->n + 1; |
| | | CHK( mpi_grow( X, j ) ); |
| | | CHK( mpi_grow( &W[1], j ) ); |
| | | CHK( mpi_grow( &T, j * 2 ) ); |
| | | |
| | | /* |
| | | * If 1st call, pre-compute R^2 mod N |
| | | */ |
| | | if( _RR == NULL || _RR->p == NULL ) |
| | | { |
| | | CHK( mpi_lset( &RR, 1 ) ); |
| | | CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); |
| | | CHK( mpi_mod_mpi( &RR, &RR, N ) ); |
| | | |
| | | if( _RR != NULL ) |
| | | memcpy( _RR, &RR, sizeof( mpi ) ); |
| | | } |
| | | else |
| | | memcpy( &RR, _RR, sizeof( mpi ) ); |
| | | |
| | | /* |
| | | * W[1] = A * R^2 * R^-1 mod N = A * R mod N |
| | | */ |
| | | if( mpi_cmp_mpi( A, N ) >= 0 ) |
| | | mpi_mod_mpi( &W[1], A, N ); |
| | | else mpi_copy( &W[1], A ); |
| | | |
| | | mpi_montmul( &W[1], &RR, N, mm, &T ); |
| | | |
| | | /* |
| | | * X = R^2 * R^-1 mod N = R mod N |
| | | */ |
| | | CHK( mpi_copy( X, &RR ) ); |
| | | mpi_montred( X, N, mm, &T ); |
| | | |
| | | if( wsize > 1 ) |
| | | { |
| | | /* |
| | | * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) |
| | | */ |
| | | j = 1 << (wsize - 1); |
| | | |
| | | CHK( mpi_grow( &W[j], N->n + 1 ) ); |
| | | CHK( mpi_copy( &W[j], &W[1] ) ); |
| | | |
| | | for( i = 0; i < wsize - 1; i++ ) |
| | | mpi_montmul( &W[j], &W[j], N, mm, &T ); |
| | | |
| | | /* |
| | | * W[i] = W[i - 1] * W[1] |
| | | */ |
| | | for( i = j + 1; i < (1 << wsize); i++ ) |
| | | { |
| | | CHK( mpi_grow( &W[i], N->n + 1 ) ); |
| | | CHK( mpi_copy( &W[i], &W[i - 1] ) ); |
| | | |
| | | mpi_montmul( &W[i], &W[1], N, mm, &T ); |
| | | } |
| | | } |
| | | |
| | | nblimbs = E->n; |
| | | bufsize = 0; |
| | | nbits = 0; |
| | | wbits = 0; |
| | | state = 0; |
| | | |
| | | while( 1 ) |
| | | { |
| | | if( bufsize == 0 ) |
| | | { |
| | | if( nblimbs-- == 0 ) |
| | | break; |
| | | |
| | | bufsize = sizeof( t_int ) << 3; |
| | | } |
| | | |
| | | bufsize--; |
| | | |
| | | ei = (E->p[nblimbs] >> bufsize) & 1; |
| | | |
| | | /* |
| | | * skip leading 0s |
| | | */ |
| | | if( ei == 0 && state == 0 ) |
| | | continue; |
| | | |
| | | if( ei == 0 && state == 1 ) |
| | | { |
| | | /* |
| | | * out of window, square X |
| | | */ |
| | | mpi_montmul( X, X, N, mm, &T ); |
| | | continue; |
| | | } |
| | | |
| | | /* |
| | | * add ei to current window |
| | | */ |
| | | state = 2; |
| | | |
| | | nbits++; |
| | | wbits |= (ei << (wsize - nbits)); |
| | | |
| | | if( nbits == wsize ) |
| | | { |
| | | /* |
| | | * X = X^wsize R^-1 mod N |
| | | */ |
| | | for( i = 0; i < wsize; i++ ) |
| | | mpi_montmul( X, X, N, mm, &T ); |
| | | |
| | | /* |
| | | * X = X * W[wbits] R^-1 mod N |
| | | */ |
| | | mpi_montmul( X, &W[wbits], N, mm, &T ); |
| | | |
| | | state--; |
| | | nbits = 0; |
| | | wbits = 0; |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * process the remaining bits |
| | | */ |
| | | for( i = 0; i < nbits; i++ ) |
| | | { |
| | | mpi_montmul( X, X, N, mm, &T ); |
| | | |
| | | wbits <<= 1; |
| | | |
| | | if( (wbits & (1 << wsize)) != 0 ) |
| | | mpi_montmul( X, &W[1], N, mm, &T ); |
| | | } |
| | | |
| | | /* |
| | | * X = A^E * R * R^-1 mod N = A^E mod N |
| | | */ |
| | | mpi_montred( X, N, mm, &T ); |
| | | |
| | | cleanup: |
| | | |
| | | for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ ) |
| | | mpi_free( &W[i], NULL ); |
| | | |
| | | if( _RR != NULL ) |
| | | mpi_free( &W[1], &T, NULL ); |
| | | else mpi_free( &W[1], &T, &RR, NULL ); |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Greatest common divisor: G = gcd(A, B) (HAC 14.54) |
| | | */ |
| | | int mpi_gcd( mpi *G, mpi *A, mpi *B ) |
| | | { |
| | | int ret, count; |
| | | mpi TG, TA, TB; |
| | | |
| | | mpi_init( &TG, &TA, &TB, NULL ); |
| | | |
| | | CHK( mpi_lset( &TG, 1 ) ); |
| | | CHK( mpi_copy( &TA, A ) ); |
| | | CHK( mpi_copy( &TB, B ) ); |
| | | |
| | | TA.s = TB.s = 1; |
| | | |
| | | count = ( mpi_lsb( &TA ) < mpi_lsb( &TB ) ) |
| | | ? mpi_lsb( &TA ) : mpi_lsb( &TB ); |
| | | |
| | | CHK( mpi_shift_l( &TG, count ) ); |
| | | CHK( mpi_shift_r( &TA, count ) ); |
| | | CHK( mpi_shift_r( &TB, count ) ); |
| | | |
| | | while( mpi_cmp_int( &TA, 0 ) != 0 ) |
| | | { |
| | | while( ( TA.p[0] & 1 ) == 0 ) CHK( mpi_shift_r( &TA, 1 ) ); |
| | | while( ( TB.p[0] & 1 ) == 0 ) CHK( mpi_shift_r( &TB, 1 ) ); |
| | | |
| | | if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) |
| | | { |
| | | CHK( mpi_sub_abs( &TA, &TA, &TB ) ); |
| | | CHK( mpi_shift_r( &TA, 1 ) ); |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_sub_abs( &TB, &TB, &TA ) ); |
| | | CHK( mpi_shift_r( &TB, 1 ) ); |
| | | } |
| | | } |
| | | |
| | | CHK( mpi_mul_mpi( G, &TG, &TB ) ); |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &TB, &TA, &TG, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) |
| | | */ |
| | | int mpi_inv_mod( mpi *X, mpi *A, mpi *N ) |
| | | { |
| | | int ret; |
| | | mpi G, TA, TU, U1, U2, TB, TV, V1, V2; |
| | | |
| | | if( mpi_cmp_int( N, 0 ) <= 0 ) |
| | | return( ERR_MPI_INVALID_PARAMETER ); |
| | | |
| | | mpi_init( &TA, &TU, &U1, &U2, &G, |
| | | &TB, &TV, &V1, &V2, NULL ); |
| | | |
| | | CHK( mpi_gcd( &G, A, N ) ); |
| | | |
| | | if( mpi_cmp_int( &G, 1 ) != 0 ) |
| | | { |
| | | ret = ERR_MPI_NOT_INVERTIBLE; |
| | | goto cleanup; |
| | | } |
| | | |
| | | CHK( mpi_mod_mpi( &TA, A, N ) ); |
| | | CHK( mpi_copy( &TU, &TA ) ); |
| | | CHK( mpi_copy( &TB, N ) ); |
| | | CHK( mpi_copy( &TV, N ) ); |
| | | |
| | | CHK( mpi_lset( &U1, 1 ) ); |
| | | CHK( mpi_lset( &U2, 0 ) ); |
| | | CHK( mpi_lset( &V1, 0 ) ); |
| | | CHK( mpi_lset( &V2, 1 ) ); |
| | | |
| | | do |
| | | { |
| | | while( ( TU.p[0] & 1 ) == 0 ) |
| | | { |
| | | CHK( mpi_shift_r( &TU, 1 ) ); |
| | | |
| | | if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) |
| | | { |
| | | CHK( mpi_add_mpi( &U1, &U1, &TB ) ); |
| | | CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); |
| | | } |
| | | |
| | | CHK( mpi_shift_r( &U1, 1 ) ); |
| | | CHK( mpi_shift_r( &U2, 1 ) ); |
| | | } |
| | | |
| | | while( ( TV.p[0] & 1 ) == 0 ) |
| | | { |
| | | CHK( mpi_shift_r( &TV, 1 ) ); |
| | | |
| | | if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) |
| | | { |
| | | CHK( mpi_add_mpi( &V1, &V1, &TB ) ); |
| | | CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); |
| | | } |
| | | |
| | | CHK( mpi_shift_r( &V1, 1 ) ); |
| | | CHK( mpi_shift_r( &V2, 1 ) ); |
| | | } |
| | | |
| | | if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) |
| | | { |
| | | CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); |
| | | CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); |
| | | CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); |
| | | CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); |
| | | CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); |
| | | } |
| | | } |
| | | while( mpi_cmp_int( &TU, 0 ) != 0 ); |
| | | |
| | | while( mpi_cmp_int( &V1, 0 ) < 0 ) |
| | | CHK( mpi_add_mpi( &V1, &V1, N ) ); |
| | | |
| | | while( mpi_cmp_mpi( &V1, N ) >= 0 ) |
| | | CHK( mpi_sub_mpi( &V1, &V1, N ) ); |
| | | |
| | | CHK( mpi_copy( X, &V1 ) ); |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &V2, &V1, &TV, &TB, &G, |
| | | &U2, &U1, &TU, &TA, NULL ); |
| | | |
| | | return( ret ); |
| | | } |
| | | |
| | | #if !defined(NO_GENPRIME) |
| | | static const int small_prime[] = |
| | | { |
| | | 3, 113, 271, 443, 619, 821, 1013, 1213, |
| | | 5, 127, 277, 449, 631, 823, 1019, 1217, |
| | | 7, 131, 281, 457, 641, 827, 1021, 1223, |
| | | 11, 137, 283, 461, 643, 829, 1031, 1229, |
| | | 13, 139, 293, 463, 647, 839, 1033, 1231, |
| | | 17, 149, 307, 467, 653, 853, 1039, 1237, |
| | | 19, 151, 311, 479, 659, 857, 1049, 1249, |
| | | 23, 157, 313, 487, 661, 859, 1051, 1259, |
| | | 29, 163, 317, 491, 673, 863, 1061, 1277, |
| | | 31, 167, 331, 499, 677, 877, 1063, 1279, |
| | | 37, 173, 337, 503, 683, 881, 1069, 1283, |
| | | 41, 179, 347, 509, 691, 883, 1087, 1289, |
| | | 43, 181, 349, 521, 701, 887, 1091, 1291, |
| | | 47, 191, 353, 523, 709, 907, 1093, 1297, |
| | | 53, 193, 359, 541, 719, 911, 1097, 1301, |
| | | 59, 197, 367, 547, 727, 919, 1103, 1303, |
| | | 61, 199, 373, 557, 733, 929, 1109, 1307, |
| | | 67, 211, 379, 563, 739, 937, 1117, 1319, |
| | | 71, 223, 383, 569, 743, 941, 1123, 1321, |
| | | 73, 227, 389, 571, 751, 947, 1129, 1327, |
| | | 79, 229, 397, 577, 757, 953, 1151, 1361, |
| | | 83, 233, 401, 587, 761, 967, 1153, 1367, |
| | | 89, 239, 409, 593, 769, 971, 1163, 1373, |
| | | 97, 241, 419, 599, 773, 977, 1171, 1381, |
| | | 101, 251, 421, 601, 787, 983, 1181, 1399, |
| | | 103, 257, 431, 607, 797, 991, 1187, 1409, |
| | | 107, 263, 433, 613, 809, 997, 1193, 1423, |
| | | 109, 269, 439, 617, 811, 1009, 1201, -110 |
| | | }; |
| | | |
| | | /* |
| | | * Miller-Rabin primality test (HAC 4.24) |
| | | */ |
| | | int mpi_is_prime( mpi *X ) |
| | | { |
| | | int ret, i, j, s, xs; |
| | | mpi W, R, T, A, RR; |
| | | |
| | | if( mpi_cmp_int( X, 0 ) == 0 ) |
| | | return( 0 ); |
| | | |
| | | mpi_init( &W, &R, &T, &A, &RR, NULL ); |
| | | xs = X->s; X->s = 1; |
| | | |
| | | /* |
| | | * test trivial factors first |
| | | */ |
| | | if( ( X->p[0] & 1 ) == 0 ) |
| | | return( ERR_MPI_IS_COMPOSITE ); |
| | | |
| | | for( i = 0; small_prime[i] > 0; i++ ) |
| | | { |
| | | t_int r; |
| | | |
| | | if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) |
| | | return( 0 ); |
| | | |
| | | CHK( mpi_mod_int( &r, X, small_prime[i] ) ); |
| | | |
| | | if( r == 0 ) |
| | | return( ERR_MPI_IS_COMPOSITE ); |
| | | } |
| | | |
| | | /* |
| | | * W = |X| - 1 |
| | | * R = W >> lsb( W ) |
| | | */ |
| | | CHK( mpi_sub_int( &W, X, 1 ) ); |
| | | CHK( mpi_copy( &R, &W ) ); |
| | | CHK( mpi_shift_r( &R, s = mpi_lsb( &W ) ) ); |
| | | |
| | | for( i = 0; i < 8; i++ ) |
| | | { |
| | | /* |
| | | * pick a random A, 1 < A < |X| - 1 |
| | | */ |
| | | CHK( mpi_grow( &A, X->n ) ); |
| | | |
| | | for( j = 0; j < A.n; j++ ) |
| | | A.p[j] = (t_int) rand() * rand(); |
| | | |
| | | CHK( mpi_shift_r( &A, mpi_size( &A ) - |
| | | mpi_size( &W ) + 1 ) ); |
| | | A.p[0] |= 3; |
| | | |
| | | /* |
| | | * A = A^R mod |X| |
| | | */ |
| | | CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); |
| | | |
| | | if( mpi_cmp_mpi( &A, &W ) == 0 || |
| | | mpi_cmp_int( &A, 1 ) == 0 ) |
| | | continue; |
| | | |
| | | j = 1; |
| | | while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) |
| | | { |
| | | /* |
| | | * A = A * A mod |X| |
| | | */ |
| | | CHK( mpi_mul_mpi( &T, &A, &A ) ); |
| | | CHK( mpi_mod_mpi( &A, &T, X ) ); |
| | | |
| | | if( mpi_cmp_int( &A, 1 ) == 0 ) |
| | | break; |
| | | |
| | | j++; |
| | | } |
| | | |
| | | /* |
| | | * not prime if A != |X| - 1 or A == 1 |
| | | */ |
| | | if( mpi_cmp_mpi( &A, &W ) != 0 || j < s ) |
| | | { |
| | | ret = ERR_MPI_IS_COMPOSITE; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | X->s = xs; |
| | | mpi_free( &A, &T, &R, &W, NULL ); |
| | | return( ret ); |
| | | } |
| | | |
| | | /* |
| | | * Prime number generation |
| | | */ |
| | | int mpi_gen_prime( mpi *X, int nbits, int dh_flag, |
| | | int (*rng_f)(void *), void *rng_d ) |
| | | { |
| | | int ret, k, n; |
| | | unsigned char *p; |
| | | mpi Y; |
| | | |
| | | if( nbits < 3 ) |
| | | return( ERR_MPI_INVALID_PARAMETER ); |
| | | |
| | | mpi_init( &Y, NULL ); |
| | | |
| | | n = BITS_TO_LIMBS( nbits ); |
| | | |
| | | CHK( mpi_grow( X, n ) ); |
| | | CHK( mpi_lset( X, 0 ) ); |
| | | |
| | | p = (unsigned char *) X->p; |
| | | for( k = 0; k < ciL * X->n; k++ ) |
| | | *p++ = rng_f( rng_d ); |
| | | |
| | | k = mpi_size( X ); |
| | | if( k < nbits ) CHK( mpi_shift_l( X, nbits - k ) ); |
| | | if( k > nbits ) CHK( mpi_shift_r( X, k - nbits ) ); |
| | | X->p[0] |= 3; |
| | | |
| | | if( dh_flag == 0 ) |
| | | { |
| | | while( ( ret = mpi_is_prime( X ) ) != 0 ) |
| | | { |
| | | if( ret != ERR_MPI_IS_COMPOSITE ) |
| | | goto cleanup; |
| | | |
| | | CHK( mpi_add_int( X, X, 2 ) ); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | CHK( mpi_sub_int( &Y, X, 1 ) ); |
| | | CHK( mpi_shift_r( &Y, 1 ) ); |
| | | |
| | | while( 1 ) |
| | | { |
| | | if( ( ret = mpi_is_prime( X ) ) == 0 ) |
| | | { |
| | | if( ( ret = mpi_is_prime( &Y ) ) == 0 ) |
| | | break; |
| | | |
| | | if( ret != ERR_MPI_IS_COMPOSITE ) |
| | | goto cleanup; |
| | | } |
| | | |
| | | if( ret != ERR_MPI_IS_COMPOSITE ) |
| | | goto cleanup; |
| | | |
| | | CHK( mpi_add_int( &Y, X, 1 ) ); |
| | | CHK( mpi_add_int( X, X, 2 ) ); |
| | | CHK( mpi_shift_r( &Y, 1 ) ); |
| | | } |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &Y, NULL ); |
| | | return( ret ); |
| | | } |
| | | #endif |
| | | |
| | | static const char _bignum_src[] = "_bignum_src"; |
| | | |
| | | #ifdef SELF_TEST |
| | | /* |
| | | * Checkup routine |
| | | */ |
| | | int mpi_self_test( void ) |
| | | { |
| | | int ret; |
| | | mpi A, E, N, X, Y, U, V; |
| | | |
| | | mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL ); |
| | | |
| | | CHK( mpi_read( &A, "EFE021C2645FD1DC586E69184AF4A31E" \ |
| | | "D5F53E93B5F123FA41680867BA110131" \ |
| | | "944FE7952E2517337780CB0DB80E61AA" \ |
| | | "E7C8DDC6C5C6AADEB34EB38A2F40D5E6", 16 ) ); |
| | | CHK( mpi_read( &E, "B2E7EFD37075B9F03FF989C7C5051C20" \ |
| | | "34D2A323810251127E7BF8625A4F49A5" \ |
| | | "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ |
| | | "5B5C25763222FEFCCFC38B832366C29E", 16 ) ); |
| | | CHK( mpi_read( &N, "0066A198186C18C10B2F5ED9B522752A" \ |
| | | "9830B69916E535C8F047518A889A43A5" \ |
| | | "94B6BED27A168D31D4A52F88925AA8F5", 16 ) ); |
| | | |
| | | CHK( mpi_mul_mpi( &X, &A, &N ) ); |
| | | CHK( mpi_read( &U, "602AB7ECA597A3D6B56FF9829A5E8B85" \ |
| | | "9E857EA95A03512E2BAE7391688D264A" \ |
| | | "A5663B0341DB9CCFD2C4C5F421FEC814" \ |
| | | "8001B72E848A38CAE1C65F78E56ABDEF" \ |
| | | "E12D3C039B8A02D6BE593F0BBBDA56F1" \ |
| | | "ECF677152EF804370C1A305CAF3B5BF1" \ |
| | | "30879B56C61DE584A0F53A2447A51E", 16 ) ); |
| | | |
| | | printf( " MPI test #1 (mul_mpi): " ); |
| | | if( mpi_cmp_mpi( &X, &U ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | printf( "passed\n" ); |
| | | |
| | | CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); |
| | | CHK( mpi_read( &U, "256567336059E52CAE22925474705F39A94", 16 ) ); |
| | | CHK( mpi_read( &V, "6613F26162223DF488E9CD48CC132C7A" \ |
| | | "0AC93C701B001B092E4E5B9F73BCD27B" \ |
| | | "9EE50D0657C77F374E903CDFA4C642", 16 ) ); |
| | | |
| | | printf( " MPI test #2 (div_mpi): " ); |
| | | if( mpi_cmp_mpi( &X, &U ) != 0 || |
| | | mpi_cmp_mpi( &Y, &V ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | printf( "passed\n" ); |
| | | |
| | | CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); |
| | | CHK( mpi_read( &U, "36E139AEA55215609D2816998ED020BB" \ |
| | | "BD96C37890F65171D948E9BC7CBAA4D9" \ |
| | | "325D24D6A3C12710F10A09FA08AB87", 16 ) ); |
| | | |
| | | printf( " MPI test #3 (exp_mod): " ); |
| | | if( mpi_cmp_mpi( &X, &U ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | printf( "passed\n" ); |
| | | |
| | | CHK( mpi_inv_mod( &X, &A, &N ) ); |
| | | CHK( mpi_read( &U, "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ |
| | | "C3DBA76456363A10869622EAC2DD84EC" \ |
| | | "C5B8A74DAC4D09E03B5E0BE779F2DF61", 16 ) ); |
| | | |
| | | printf( " MPI test #4 (inv_mod): " ); |
| | | if( mpi_cmp_mpi( &X, &U ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | printf( "passed\n" ); |
| | | |
| | | cleanup: |
| | | |
| | | if( ret != 0 ) |
| | | printf( "Unexpected error, return code = %d\n", ret ); |
| | | |
| | | mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL ); |
| | | |
| | | printf( "\n" ); |
| | | return( 0 ); |
| | | } |
| | | #else |
| | | int mpi_self_test( void ) |
| | | { |
| | | return( 0 ); |
| | | } |
| | | #endif |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: bootstrap.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code is the first stage bootloader(named bootstrap) |
| | | main code, test on FL2440 board. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #include <common.h> |
| | | #include <nand.h> |
| | | |
| | | int dbg_mode(struct boot_nand_t *nand); |
| | | unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[]); |
| | | |
| | | void print_buf(char *prompt, char *buf, int len) |
| | | { |
| | | int i; |
| | | printf("%s %d bytes\n", prompt, len); |
| | | printf("------------------------------------------------------------------------------------\n"); |
| | | for(i=0; i<len; i++) |
| | | { |
| | | printf("0x%02x ", buf[i]); |
| | | if(! (i+1)%32 ) |
| | | printf("\n"); |
| | | } |
| | | |
| | | printf("\n"); |
| | | printf("------------------------------------------------------------------------------------\n"); |
| | | } |
| | | |
| | | |
| | | int bootstrap_main(void) |
| | | { |
| | | struct boot_nand_t nand; |
| | | char buf[0x20000]; |
| | | ulong test_block = 0x0; /*0x1860000 is bad block*/ |
| | | // char *addr = (char *)TEXT_BASE; |
| | | char *addr = (char *)0x36000000; |
| | | |
| | | serial_init(); |
| | | init_led_beep(); |
| | | |
| | | printf("\bBootstrap Version 0.0.1\n"); |
| | | |
| | | turn_led_on(LED0); |
| | | |
| | | if (nand_init(&nand) < 0) |
| | | { |
| | | printf("Nandflash init failure.\n"); |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | #if 0 |
| | | nand_scrub(&nand); |
| | | |
| | | nand_erase(&nand, test_block, 0x20000, SKIP_BAD_BLOCK); |
| | | |
| | | memset(buf,0x00, sizeof(buf)); |
| | | nand_read_spare(&nand, test_block, 64, buf); |
| | | print_buf("Spare area read:", buf, 64); |
| | | |
| | | nand_read(&nand, test_block, nand.page_size, buf); |
| | | print_buf("Whole page Write:", buf, nand.page_size); |
| | | #endif |
| | | |
| | | #if 0 |
| | | /*Write spare area*/ |
| | | memset(buf,0x44,sizeof(buf)); |
| | | |
| | | nand_write(&nand, test_block, nand.page_size, buf); |
| | | nand_read(&nand, test_block, nand.page_size, buf); |
| | | print_buf("Whole page Write:", buf, nand.page_size); |
| | | |
| | | |
| | | nand_write_spare(&nand, 0x0000, 64, buf); |
| | | nand_read_spare(&nand, test_block, 64, buf); |
| | | print_buf("Spare area read:", buf, 64); |
| | | #endif |
| | | |
| | | dbg_mode(&nand); |
| | | |
| | | nand_read(&nand, LAUNCHER_NAND_ADDR, 1024, addr); |
| | | do_go_exec((void *)addr, 0, NULL); |
| | | |
| | | while (1) |
| | | ; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | __attribute__((weak)) |
| | | unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[]) |
| | | { |
| | | printf ("## Starting application at 0x%08lX ...\n", entry); |
| | | return entry (argc, argv); |
| | | } |
| | | |
| | | int dbg_mode(struct boot_nand_t *nand) |
| | | { |
| | | long size; |
| | | char *addr = (char *)TEXT_BASE; |
| | | ulong erase_size; |
| | | |
| | | dbg_print("Comes into bootstrap debug mode and Xmodem wait for receive new launcher:\n"); |
| | | |
| | | beep(1); |
| | | |
| | | size = xmodem_recv(addr); |
| | | dbg_print("\tBootstrap Receive Launcher file size: %ld bytes\n", size); |
| | | |
| | | erase_size = (size/nand->block_size + 1)*nand->block_size; |
| | | |
| | | nand_erase(nand, LAUNCHER_NAND_ADDR, erase_size, SKIP_BAD_BLOCK); |
| | | nand_write(nand, LAUNCHER_NAND_ADDR, size, addr); |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: bootstrap.lds |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This is the LD linker configure script for bootstrap |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") |
| | | OUTPUT_ARCH(arm) |
| | | ENTRY(_start) |
| | | |
| | | SECTIONS{ |
| | | . = ALIGN(4); |
| | | .text : |
| | | { |
| | | start.o (.text) |
| | | *(.text) |
| | | } |
| | | . = ALIGN(4); |
| | | .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } |
| | | . = ALIGN(4); |
| | | .rodata : { *(.rodata) } |
| | | . = ALIGN(4); |
| | | .data : { *(.data) } |
| | | . = ALIGN(4); |
| | | __bss_start = .; |
| | | .bss : { *(.bss) } |
| | | _end = .; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | * linux/lib/vsprintf.c |
| | | * |
| | | * Copyright (C) 1991, 1992 Linus Torvalds |
| | | */ |
| | | |
| | | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ |
| | | /* |
| | | * Wirzenius wrote this portably, Torvalds fucked it up :-) |
| | | */ |
| | | |
| | | #include <common.h> |
| | | |
| | | void * memset(void * s,int c,size_t count) |
| | | { |
| | | unsigned long *sl = (unsigned long *) s; |
| | | unsigned long cl = 0; |
| | | char *s8; |
| | | int i; |
| | | |
| | | /* do it one word at a time (32 bits or 64 bits) while possible */ |
| | | if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) { |
| | | for (i = 0; i < sizeof(*sl); i++) { |
| | | cl <<= 8; |
| | | cl |= c & 0xff; |
| | | } |
| | | while (count >= sizeof(*sl)) { |
| | | *sl++ = cl; |
| | | count -= sizeof(*sl); |
| | | } |
| | | } |
| | | /* fill 8 bits at a time */ |
| | | s8 = (char *)sl; |
| | | while (count--) |
| | | *s8++ = c; |
| | | |
| | | return s; |
| | | } |
| | | |
| | | #ifdef CONFIG_PRINTF_DBG |
| | | |
| | | size_t strnlen(const char *s, size_t count) |
| | | { |
| | | const char *sc; |
| | | |
| | | for (sc = s; count-- && *sc != '\0'; ++sc) |
| | | /* nothing */ ; |
| | | return sc - s; |
| | | } |
| | | |
| | | #define is_digit(c) ((c) >= '0' && (c) <= '9') |
| | | |
| | | static int skip_atoi(const char **s) |
| | | { |
| | | int i = 0; |
| | | |
| | | while (is_digit(**s)) |
| | | i = i * 10 + *((*s)++) - '0'; |
| | | return i; |
| | | } |
| | | |
| | | #define ZEROPAD 1 /* pad with zero */ |
| | | #define SIGN 2 /* unsigned/signed long */ |
| | | #define PLUS 4 /* show plus */ |
| | | #define SPACE 8 /* space if plus */ |
| | | #define LEFT 16 /* left justified */ |
| | | #define SPECIAL 32 /* 0x */ |
| | | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ |
| | | |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | #define do_div(n,base) ({ \ |
| | | unsigned int __res; \ |
| | | __res = ((unsigned long long) n) % base; \ |
| | | n = ((unsigned long long) n) / base; \ |
| | | __res; \ |
| | | }) |
| | | #else |
| | | #define do_div(n,base) ({ \ |
| | | int __res; \ |
| | | __res = ((unsigned long) n) % base; \ |
| | | n = ((unsigned long) n) / base; \ |
| | | __res; \ |
| | | }) |
| | | #endif |
| | | |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | static char *number(char *str, long long num, unsigned int base, int size, int precision, int type) |
| | | #else |
| | | static char *number(char *str, long num, unsigned int base, int size, int precision, int type) |
| | | #endif |
| | | { |
| | | char c, sign, tmp[66]; |
| | | const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; |
| | | int i; |
| | | |
| | | if (type & LARGE) |
| | | digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| | | if (type & LEFT) |
| | | type &= ~ZEROPAD; |
| | | if (base < 2 || base > 36) |
| | | return 0; |
| | | c = (type & ZEROPAD) ? '0' : ' '; |
| | | sign = 0; |
| | | if (type & SIGN) |
| | | { |
| | | if (num < 0) |
| | | { |
| | | sign = '-'; |
| | | num = -num; |
| | | size--; |
| | | } |
| | | else if (type & PLUS) |
| | | { |
| | | sign = '+'; |
| | | size--; |
| | | } |
| | | else if (type & SPACE) |
| | | { |
| | | sign = ' '; |
| | | size--; |
| | | } |
| | | } |
| | | if (type & SPECIAL) |
| | | { |
| | | if (base == 16) |
| | | size -= 2; |
| | | else if (base == 8) |
| | | size--; |
| | | } |
| | | i = 0; |
| | | if (num == 0) |
| | | tmp[i++] = '0'; |
| | | else |
| | | while (num != 0) |
| | | tmp[i++] = digits[do_div(num, base)]; |
| | | if (i > precision) |
| | | precision = i; |
| | | size -= precision; |
| | | if (!(type & (ZEROPAD + LEFT))) |
| | | while (size-- > 0) |
| | | *str++ = ' '; |
| | | if (sign) |
| | | *str++ = sign; |
| | | if (type & SPECIAL) |
| | | { |
| | | if (base == 8) |
| | | *str++ = '0'; |
| | | else if (base == 16) |
| | | { |
| | | *str++ = '0'; |
| | | *str++ = digits[33]; |
| | | } |
| | | } |
| | | if (!(type & LEFT)) |
| | | while (size-- > 0) |
| | | *str++ = c; |
| | | while (i < precision--) |
| | | *str++ = '0'; |
| | | while (i-- > 0) |
| | | *str++ = tmp[i]; |
| | | while (size-- > 0) |
| | | *str++ = ' '; |
| | | return str; |
| | | } |
| | | |
| | | /* Forward decl. needed for IP address printing stuff... */ |
| | | int sprintf(char *buf, const char *fmt, ...); |
| | | |
| | | int vsprintf(char *buf, const char *fmt, va_list args) |
| | | { |
| | | int len; |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | unsigned long long num; |
| | | #else |
| | | unsigned long num; |
| | | #endif |
| | | int i, base; |
| | | char *str; |
| | | const char *s; |
| | | |
| | | int flags; /* flags to number() */ |
| | | |
| | | int field_width; /* width of output field */ |
| | | int precision; /* min. # of digits for integers; max |
| | | * number of chars for from string */ |
| | | int qualifier; /* 'h', 'l', or 'q' for integer fields */ |
| | | |
| | | for (str = buf; *fmt; ++fmt) |
| | | { |
| | | if (*fmt != '%') |
| | | { |
| | | *str++ = *fmt; |
| | | continue; |
| | | } |
| | | |
| | | /* process flags */ |
| | | flags = 0; |
| | | repeat: |
| | | ++fmt; /* this also skips first '%' */ |
| | | switch (*fmt) |
| | | { |
| | | case '-': |
| | | flags |= LEFT; |
| | | goto repeat; |
| | | case '+': |
| | | flags |= PLUS; |
| | | goto repeat; |
| | | case ' ': |
| | | flags |= SPACE; |
| | | goto repeat; |
| | | case '#': |
| | | flags |= SPECIAL; |
| | | goto repeat; |
| | | case '0': |
| | | flags |= ZEROPAD; |
| | | goto repeat; |
| | | } |
| | | |
| | | /* get field width */ |
| | | field_width = -1; |
| | | if (is_digit(*fmt)) |
| | | field_width = skip_atoi(&fmt); |
| | | else if (*fmt == '*') |
| | | { |
| | | ++fmt; |
| | | /* it's the next argument */ |
| | | field_width = va_arg(args, int); |
| | | if (field_width < 0) |
| | | { |
| | | field_width = -field_width; |
| | | flags |= LEFT; |
| | | } |
| | | } |
| | | |
| | | /* get the precision */ |
| | | precision = -1; |
| | | if (*fmt == '.') |
| | | { |
| | | ++fmt; |
| | | if (is_digit(*fmt)) |
| | | precision = skip_atoi(&fmt); |
| | | else if (*fmt == '*') |
| | | { |
| | | ++fmt; |
| | | /* it's the next argument */ |
| | | precision = va_arg(args, int); |
| | | } |
| | | if (precision < 0) |
| | | precision = 0; |
| | | } |
| | | |
| | | /* get the conversion qualifier */ |
| | | qualifier = -1; |
| | | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
| | | *fmt == 'Z' || *fmt == 'z' || *fmt == 't' || *fmt == 'q') |
| | | { |
| | | qualifier = *fmt; |
| | | if (qualifier == 'l' && *(fmt + 1) == 'l') |
| | | { |
| | | qualifier = 'q'; |
| | | ++fmt; |
| | | } |
| | | ++fmt; |
| | | } |
| | | |
| | | /* default base */ |
| | | base = 10; |
| | | |
| | | switch (*fmt) |
| | | { |
| | | case 'c': |
| | | if (!(flags & LEFT)) |
| | | while (--field_width > 0) |
| | | *str++ = ' '; |
| | | *str++ = (unsigned char)va_arg(args, int); |
| | | while (--field_width > 0) |
| | | *str++ = ' '; |
| | | continue; |
| | | |
| | | case 's': |
| | | s = va_arg(args, char *); |
| | | if (!s) |
| | | s = "<NULL>"; |
| | | |
| | | len = strnlen(s, precision); |
| | | |
| | | if (!(flags & LEFT)) |
| | | while (len < field_width--) |
| | | *str++ = ' '; |
| | | for (i = 0; i < len; ++i) |
| | | *str++ = *s++; |
| | | while (len < field_width--) |
| | | *str++ = ' '; |
| | | continue; |
| | | |
| | | case 'p': |
| | | if (field_width == -1) |
| | | { |
| | | field_width = 2 * sizeof(void *); |
| | | flags |= ZEROPAD; |
| | | } |
| | | str = number(str, |
| | | (unsigned long)va_arg(args, void *), 16, field_width, precision, flags); |
| | | continue; |
| | | |
| | | case 'n': |
| | | if (qualifier == 'l') |
| | | { |
| | | long *ip = va_arg(args, long *); |
| | | *ip = (str - buf); |
| | | } |
| | | else |
| | | { |
| | | int *ip = va_arg(args, int *); |
| | | *ip = (str - buf); |
| | | } |
| | | continue; |
| | | |
| | | case '%': |
| | | *str++ = '%'; |
| | | continue; |
| | | |
| | | /* integer number formats - set up the flags and "break" */ |
| | | case 'o': |
| | | base = 8; |
| | | break; |
| | | |
| | | case 'X': |
| | | flags |= LARGE; |
| | | case 'x': |
| | | base = 16; |
| | | break; |
| | | |
| | | case 'd': |
| | | case 'i': |
| | | flags |= SIGN; |
| | | case 'u': |
| | | break; |
| | | |
| | | default: |
| | | *str++ = '%'; |
| | | if (*fmt) |
| | | *str++ = *fmt; |
| | | else |
| | | --fmt; |
| | | continue; |
| | | } |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | if (qualifier == 'q') /* "quad" for 64 bit variables */ |
| | | num = va_arg(args, unsigned long long); |
| | | else |
| | | #endif |
| | | if (qualifier == 'l') |
| | | { |
| | | num = va_arg(args, unsigned long); |
| | | } |
| | | else if (qualifier == 'Z' || qualifier == 'z') |
| | | { |
| | | num = va_arg(args, size_t); |
| | | } |
| | | else if (qualifier == 't') |
| | | { |
| | | num = va_arg(args, ptrdiff_t); |
| | | } |
| | | else if (qualifier == 'h') |
| | | { |
| | | num = (unsigned short)va_arg(args, int); |
| | | if (flags & SIGN) |
| | | num = (short)num; |
| | | } |
| | | else if (flags & SIGN) |
| | | num = va_arg(args, int); |
| | | else |
| | | num = va_arg(args, unsigned int); |
| | | str = number(str, num, base, field_width, precision, flags); |
| | | } |
| | | *str = '\0'; |
| | | return str - buf; |
| | | } |
| | | |
| | | void printf(const char *fmt, ...) |
| | | { |
| | | va_list args; |
| | | uint i; |
| | | char printbuffer[CFG_PBSIZE]; |
| | | |
| | | va_start(args, fmt); |
| | | |
| | | /* For this to work, printbuffer must be larger than |
| | | * anything we ever want to print. |
| | | */ |
| | | i = vsprintf(printbuffer, fmt, args); |
| | | va_end(args); |
| | | |
| | | serial_puts(printbuffer); |
| | | } |
| | | |
| | | int sprintf(char *buf, const char *fmt, ...) |
| | | { |
| | | va_list args; |
| | | int i; |
| | | |
| | | va_start(args, fmt); |
| | | i = vsprintf(buf, fmt, args); |
| | | va_end(args); |
| | | return i; |
| | | } |
| | | #else |
| | | void printf(const char *fmt, ...) |
| | | { |
| | | |
| | | } |
| | | #endif /*Define CONFIG_PRINTF_DBG */ |
New file |
| | |
| | | /* |
| | | * This file is derived from crc32.c from the zlib-1.1.3 distribution |
| | | * by Jean-loup Gailly and Mark Adler. |
| | | */ |
| | | |
| | | /* crc32.c -- compute the CRC-32 of a data stream |
| | | * Copyright (C) 1995-1998 Mark Adler |
| | | * For conditions of distribution and use, see copyright notice in zlib.h |
| | | */ |
| | | |
| | | #include <common.h> |
| | | |
| | | #define __cpu_to_le32(x) ((__u32)(x)) |
| | | #define cpu_to_le32 __cpu_to_le32 |
| | | # define le32_to_cpu(x) (x) |
| | | |
| | | #define local static |
| | | #define ZEXPORT /* empty */ |
| | | |
| | | #define tole(x) cpu_to_le32(x) |
| | | |
| | | #ifdef DYNAMIC_CRC_TABLE |
| | | |
| | | local int crc_table_empty = 1; |
| | | local uint32_t crc_table[256]; |
| | | local void make_crc_table OF((void)); |
| | | |
| | | /* |
| | | Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: |
| | | x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. |
| | | |
| | | Polynomials over GF(2) are represented in binary, one bit per coefficient, |
| | | with the lowest powers in the most significant bit. Then adding polynomials |
| | | is just exclusive-or, and multiplying a polynomial by x is a right shift by |
| | | one. If we call the above polynomial p, and represent a byte as the |
| | | polynomial q, also with the lowest power in the most significant bit (so the |
| | | byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, |
| | | where a mod b means the remainder after dividing a by b. |
| | | |
| | | This calculation is done using the shift-register method of multiplying and |
| | | taking the remainder. The register is initialized to zero, and for each |
| | | incoming bit, x^32 is added mod p to the register if the bit is a one (where |
| | | x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by |
| | | x (which is shifting right by one and adding x^32 mod p if the bit shifted |
| | | out is a one). We start with the highest power (least significant bit) of |
| | | q and repeat for all eight bits of q. |
| | | |
| | | The table is simply the CRC of all possible eight bit values. This is all |
| | | the information needed to generate CRC's on data a byte at a time for all |
| | | combinations of CRC register values and incoming bytes. |
| | | */ |
| | | local void make_crc_table() |
| | | { |
| | | uint32_t c; |
| | | int n, k; |
| | | uLong poly; /* polynomial exclusive-or pattern */ |
| | | /* terms of polynomial defining this crc (except x^32): */ |
| | | static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; |
| | | |
| | | /* make exclusive-or pattern from polynomial (0xedb88320L) */ |
| | | poly = 0L; |
| | | for (n = 0; n < sizeof(p)/sizeof(Byte); n++) |
| | | poly |= 1L << (31 - p[n]); |
| | | |
| | | for (n = 0; n < 256; n++) |
| | | { |
| | | c = (uLong)n; |
| | | for (k = 0; k < 8; k++) |
| | | c = c & 1 ? poly ^ (c >> 1) : c >> 1; |
| | | crc_table[n] = tole(c); |
| | | } |
| | | crc_table_empty = 0; |
| | | } |
| | | #else |
| | | /* ======================================================================== |
| | | * Table of CRC-32's of all single-byte values (made by make_crc_table) |
| | | */ |
| | | |
| | | local const uint32_t crc_table[256] = { |
| | | tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL), |
| | | tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L), |
| | | tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L), |
| | | tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L), |
| | | tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL), |
| | | tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L), |
| | | tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL), |
| | | tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L), |
| | | tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L), |
| | | tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL), |
| | | tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L), |
| | | tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L), |
| | | tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L), |
| | | tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL), |
| | | tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L), |
| | | tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL), |
| | | tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL), |
| | | tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L), |
| | | tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L), |
| | | tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L), |
| | | tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL), |
| | | tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L), |
| | | tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL), |
| | | tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L), |
| | | tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L), |
| | | tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL), |
| | | tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L), |
| | | tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L), |
| | | tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L), |
| | | tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL), |
| | | tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L), |
| | | tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL), |
| | | tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL), |
| | | tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L), |
| | | tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L), |
| | | tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L), |
| | | tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL), |
| | | tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L), |
| | | tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL), |
| | | tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L), |
| | | tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L), |
| | | tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL), |
| | | tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L), |
| | | tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L), |
| | | tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L), |
| | | tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL), |
| | | tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L), |
| | | tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL), |
| | | tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL), |
| | | tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L), |
| | | tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L), |
| | | tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L), |
| | | tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL), |
| | | tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L), |
| | | tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL), |
| | | tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L), |
| | | tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L), |
| | | tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL), |
| | | tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L), |
| | | tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L), |
| | | tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L), |
| | | tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL), |
| | | tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L), |
| | | tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL) |
| | | }; |
| | | #endif |
| | | |
| | | #if 0 |
| | | /* ========================================================================= |
| | | * This function can be used by asm versions of crc32() |
| | | */ |
| | | const uint32_t * ZEXPORT get_crc_table() |
| | | { |
| | | #ifdef DYNAMIC_CRC_TABLE |
| | | if (crc_table_empty) make_crc_table(); |
| | | #endif |
| | | return (const uint32_t *)crc_table; |
| | | } |
| | | #endif |
| | | |
| | | /* ========================================================================= */ |
| | | # if __BYTE_ORDER == __LITTLE_ENDIAN |
| | | # define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8) |
| | | # else |
| | | # define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8) |
| | | # endif |
| | | |
| | | /* ========================================================================= */ |
| | | |
| | | /* No ones complement version. JFFS2 (and other things ?) |
| | | * don't use ones compliment in their CRC calculations. |
| | | */ |
| | | uint32_t ZEXPORT crc32_no_comp(uint32_t crc, const uchar *buf, uint len) |
| | | { |
| | | const uint32_t *tab = crc_table; |
| | | const uint32_t *b =(const uint32_t *)buf; |
| | | size_t rem_len; |
| | | #ifdef DYNAMIC_CRC_TABLE |
| | | if (crc_table_empty) |
| | | make_crc_table(); |
| | | #endif |
| | | crc = cpu_to_le32(crc); |
| | | /* Align it */ |
| | | if (((long)b) & 3 && len) { |
| | | uint8_t *p = (uint8_t *)b; |
| | | do { |
| | | DO_CRC(*p++); |
| | | } while ((--len) && ((long)p)&3); |
| | | b = (uint32_t *)p; |
| | | } |
| | | |
| | | rem_len = len & 3; |
| | | len = len >> 2; |
| | | for (--b; len; --len) { |
| | | /* load data 32 bits wide, xor data 32 bits wide. */ |
| | | crc ^= *++b; /* use pre increment for speed */ |
| | | DO_CRC(0); |
| | | DO_CRC(0); |
| | | DO_CRC(0); |
| | | DO_CRC(0); |
| | | } |
| | | len = rem_len; |
| | | /* And the last few bytes */ |
| | | if (len) { |
| | | uint8_t *p = (uint8_t *)(b + 1) - 1; |
| | | do { |
| | | DO_CRC(*++p); /* use pre increment for speed */ |
| | | } while (--len); |
| | | } |
| | | |
| | | return le32_to_cpu(crc); |
| | | } |
| | | #undef DO_CRC |
| | | |
| | | uint32_t ZEXPORT crc32 (uint32_t crc, const uchar *p, uint len) |
| | | { |
| | | return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL; |
| | | } |
| | | |
New file |
| | |
| | | #ifndef _ARM_ERRNO_H |
| | | #define _ARM_ERRNO_H |
| | | |
| | | #define EPERM 1 /* Operation not permitted */ |
| | | #define ENOENT 2 /* No such file or directory */ |
| | | #define ESRCH 3 /* No such process */ |
| | | #define EINTR 4 /* Interrupted system call */ |
| | | #define EIO 5 /* I/O error */ |
| | | #define ENXIO 6 /* No such device or address */ |
| | | #define E2BIG 7 /* Arg list too long */ |
| | | #define ENOEXEC 8 /* Exec format error */ |
| | | #define EBADF 9 /* Bad file number */ |
| | | #define ECHILD 10 /* No child processes */ |
| | | #define EAGAIN 11 /* Try again */ |
| | | #define ENOMEM 12 /* Out of memory */ |
| | | #define EACCES 13 /* Permission denied */ |
| | | #define EFAULT 14 /* Bad address */ |
| | | #define ENOTBLK 15 /* Block device required */ |
| | | #define EBUSY 16 /* Device or resource busy */ |
| | | #define EEXIST 17 /* File exists */ |
| | | #define EXDEV 18 /* Cross-device link */ |
| | | #define ENODEV 19 /* No such device */ |
| | | #define ENOTDIR 20 /* Not a directory */ |
| | | #define EISDIR 21 /* Is a directory */ |
| | | #define EINVAL 22 /* Invalid argument */ |
| | | #define ENFILE 23 /* File table overflow */ |
| | | #define EMFILE 24 /* Too many open files */ |
| | | #define ENOTTY 25 /* Not a typewriter */ |
| | | #define ETXTBSY 26 /* Text file busy */ |
| | | #define EFBIG 27 /* File too large */ |
| | | #define ENOSPC 28 /* No space left on device */ |
| | | #define ESPIPE 29 /* Illegal seek */ |
| | | #define EROFS 30 /* Read-only file system */ |
| | | #define EMLINK 31 /* Too many links */ |
| | | #define EPIPE 32 /* Broken pipe */ |
| | | #define EDOM 33 /* Math argument out of domain of func */ |
| | | #define ERANGE 34 /* Math result not representable */ |
| | | #define EDEADLK 35 /* Resource deadlock would occur */ |
| | | #define ENAMETOOLONG 36 /* File name too long */ |
| | | #define ENOLCK 37 /* No record locks available */ |
| | | #define ENOSYS 38 /* Function not implemented */ |
| | | #define ENOTEMPTY 39 /* Directory not empty */ |
| | | #define ELOOP 40 /* Too many symbolic links encountered */ |
| | | #define EWOULDBLOCK EAGAIN /* Operation would block */ |
| | | #define ENOMSG 42 /* No message of desired type */ |
| | | #define EIDRM 43 /* Identifier removed */ |
| | | #define ECHRNG 44 /* Channel number out of range */ |
| | | #define EL2NSYNC 45 /* Level 2 not synchronized */ |
| | | #define EL3HLT 46 /* Level 3 halted */ |
| | | #define EL3RST 47 /* Level 3 reset */ |
| | | #define ELNRNG 48 /* Link number out of range */ |
| | | #define EUNATCH 49 /* Protocol driver not attached */ |
| | | #define ENOCSI 50 /* No CSI structure available */ |
| | | #define EL2HLT 51 /* Level 2 halted */ |
| | | #define EBADE 52 /* Invalid exchange */ |
| | | #define EBADR 53 /* Invalid request descriptor */ |
| | | #define EXFULL 54 /* Exchange full */ |
| | | #define ENOANO 55 /* No anode */ |
| | | #define EBADRQC 56 /* Invalid request code */ |
| | | #define EBADSLT 57 /* Invalid slot */ |
| | | #define EDEADLOCK 58 /* File locking deadlock error */ |
| | | #define EBFONT 59 /* Bad font file format */ |
| | | #define ENOSTR 60 /* Device not a stream */ |
| | | #define ENODATA 61 /* No data available */ |
| | | #define ETIME 62 /* Timer expired */ |
| | | #define ENOSR 63 /* Out of streams resources */ |
| | | #define ENONET 64 /* Machine is not on the network */ |
| | | #define ENOPKG 65 /* Package not installed */ |
| | | #define EREMOTE 66 /* Object is remote */ |
| | | #define ENOLINK 67 /* Link has been severed */ |
| | | #define EADV 68 /* Advertise error */ |
| | | #define ESRMNT 69 /* Srmount error */ |
| | | #define ECOMM 70 /* Communication error on send */ |
| | | #define EPROTO 71 /* Protocol error */ |
| | | #define EMULTIHOP 72 /* Multihop attempted */ |
| | | #define EDOTDOT 73 /* RFS specific error */ |
| | | #define EBADMSG 74 /* Not a data message */ |
| | | #define EOVERFLOW 75 /* Value too large for defined data type */ |
| | | #define ENOTUNIQ 76 /* Name not unique on network */ |
| | | #define EBADFD 77 /* File descriptor in bad state */ |
| | | #define EREMCHG 78 /* Remote address changed */ |
| | | #define ELIBACC 79 /* Can not access a needed shared library */ |
| | | #define ELIBBAD 80 /* Accessing a corrupted shared library */ |
| | | #define ELIBSCN 81 /* .lib section in a.out corrupted */ |
| | | #define ELIBMAX 82 /* Attempting to link in too many shared libraries */ |
| | | #define ELIBEXEC 83 /* Cannot exec a shared library directly */ |
| | | #define EILSEQ 84 /* Illegal byte sequence */ |
| | | #define ERESTART 85 /* Interrupted system call should be restarted */ |
| | | #define ESTRPIPE 86 /* Streams pipe error */ |
| | | #define EUSERS 87 /* Too many users */ |
| | | #define ENOTSOCK 88 /* Socket operation on non-socket */ |
| | | #define EDESTADDRREQ 89 /* Destination address required */ |
| | | #define EMSGSIZE 90 /* Message too long */ |
| | | #define EPROTOTYPE 91 /* Protocol wrong type for socket */ |
| | | #define ENOPROTOOPT 92 /* Protocol not available */ |
| | | #define EPROTONOSUPPORT 93 /* Protocol not supported */ |
| | | #define ESOCKTNOSUPPORT 94 /* Socket type not supported */ |
| | | #define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ |
| | | #define EPFNOSUPPORT 96 /* Protocol family not supported */ |
| | | #define EAFNOSUPPORT 97 /* Address family not supported by protocol */ |
| | | #define EADDRINUSE 98 /* Address already in use */ |
| | | #define EADDRNOTAVAIL 99 /* Cannot assign requested address */ |
| | | #define ENETDOWN 100 /* Network is down */ |
| | | #define ENETUNREACH 101 /* Network is unreachable */ |
| | | #define ENETRESET 102 /* Network dropped connection because of reset */ |
| | | #define ECONNABORTED 103 /* Software caused connection abort */ |
| | | #define ECONNRESET 104 /* Connection reset by peer */ |
| | | #define ENOBUFS 105 /* No buffer space available */ |
| | | #define EISCONN 106 /* Transport endpoint is already connected */ |
| | | #define ENOTCONN 107 /* Transport endpoint is not connected */ |
| | | #define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ |
| | | #define ETOOMANYREFS 109 /* Too many references: cannot splice */ |
| | | #define ETIMEDOUT 110 /* Connection timed out */ |
| | | #define ECONNREFUSED 111 /* Connection refused */ |
| | | #define EHOSTDOWN 112 /* Host is down */ |
| | | #define EHOSTUNREACH 113 /* No route to host */ |
| | | #define EALREADY 114 /* Operation already in progress */ |
| | | #define EINPROGRESS 115 /* Operation now in progress */ |
| | | #define ESTALE 116 /* Stale NFS file handle */ |
| | | #define EUCLEAN 117 /* Structure needs cleaning */ |
| | | #define ENOTNAM 118 /* Not a XENIX named type file */ |
| | | #define ENAVAIL 119 /* No XENIX semaphores available */ |
| | | #define EISNAM 120 /* Is a named type file */ |
| | | #define EREMOTEIO 121 /* Remote I/O error */ |
| | | #define EDQUOT 122 /* Quota exceeded */ |
| | | |
| | | #define ENOMEDIUM 123 /* No medium found */ |
| | | #define EMEDIUMTYPE 124 /* Wrong medium type */ |
| | | |
| | | /* Should never be seen by user programs */ |
| | | #define ERESTARTSYS 512 |
| | | #define ERESTARTNOINTR 513 |
| | | #define ERESTARTNOHAND 514 /* restart if no handler.. */ |
| | | #define ENOIOCTLCMD 515 /* No ioctl command */ |
| | | |
| | | #define _LAST_ERRNO 515 |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _ARCH_HARDWARE_H_ |
| | | #define _ARCH_HARDWARE_H_ |
| | | |
| | | #include <asm/sizes.h> |
| | | |
| | | #ifndef __ASSEMBLY__ |
| | | #define UData(Data) ((unsigned long) (Data)) |
| | | |
| | | #define __REG(x) (*(vu_long *)(x)) |
| | | #define __REGl(x) (*(vu_long *)(x)) |
| | | #define __REGi(x) (*(vu_int *)(x)) |
| | | #define __REGw(x) (*(vu_short *)(x)) |
| | | #define __REGb(x) (*(vu_char *)(x)) |
| | | #define __REG2(x,y) (*(vu_long *)((x) + (y))) |
| | | #else |
| | | #define UData(Data) (Data) |
| | | |
| | | #define __REG(x) (x) |
| | | #define __REGl(x) (x) |
| | | #define __REGi(x) (x) |
| | | #define __REGw(x) (x) |
| | | #define __REGb(x) (x) |
| | | #define __REG2(x,y) ((x) + (y)) |
| | | #endif |
| | | |
| | | #define Fld(Size, Shft) (((Size) << 16) + (Shft)) |
| | | |
| | | #define FSize(Field) ((Field) >> 16) |
| | | #define FShft(Field) ((Field) & 0x0000FFFF) |
| | | #define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) |
| | | #define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) |
| | | #define F1stBit(Field) (UData (1) << FShft (Field)) |
| | | |
| | | #define FClrBit(Data, Bit) (Data = (Data & ~(Bit))) |
| | | #define FClrFld(Data, Field) (Data = (Data & ~FMsk(Field))) |
| | | |
| | | #define FInsrt(Value, Field) \ |
| | | (UData (Value) << FShft (Field)) |
| | | |
| | | #define FExtr(Data, Field) \ |
| | | ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) |
| | | |
| | | #endif /* _ARCH_HARDWARE_H_ */ |
New file |
| | |
| | | /* |
| | | * linux/include/asm-arm/io.h |
| | | * |
| | | * Copyright (C) 1996-2000 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. |
| | | * |
| | | * Modifications: |
| | | * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both |
| | | * constant addresses and variable addresses. |
| | | * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture |
| | | * specific IO header files. |
| | | * 27-Mar-1999 PJB Second parameter of memcpy_toio is const.. |
| | | * 04-Apr-1999 PJB Added check_signature. |
| | | * 12-Dec-1999 RMK More cleanups |
| | | * 18-Jun-2000 RMK Removed virt_to_* and friends definitions |
| | | */ |
| | | #ifndef __ASM_ARM_IO_H |
| | | #define __ASM_ARM_IO_H |
| | | |
| | | #ifdef __KERNEL__ |
| | | |
| | | #include <linux/types.h> |
| | | |
| | | static inline void sync(void) |
| | | { |
| | | } |
| | | |
| | | /* |
| | | * Given a physical address and a length, return a virtual address |
| | | * that can be used to access the memory range with the caching |
| | | * properties specified by "flags". |
| | | */ |
| | | #define MAP_NOCACHE (0) |
| | | #define MAP_WRCOMBINE (0) |
| | | #define MAP_WRBACK (0) |
| | | #define MAP_WRTHROUGH (0) |
| | | |
| | | static inline void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) |
| | | { |
| | | return (void *)paddr; |
| | | } |
| | | |
| | | /* |
| | | * Take down a mapping set up by map_physmem(). |
| | | */ |
| | | static inline void unmap_physmem(void *vaddr, unsigned long flags) |
| | | { |
| | | |
| | | } |
| | | |
| | | /* |
| | | * Generic virtual read/write. Note that we don't support half-word |
| | | * read/writes. We define __arch_*[bl] here, and leave __arch_*w |
| | | * to the architecture specific code. |
| | | */ |
| | | #define __arch_getb(a) (*(volatile unsigned char *)(a)) |
| | | #define __arch_getw(a) (*(volatile unsigned short *)(a)) |
| | | #define __arch_getl(a) (*(volatile unsigned int *)(a)) |
| | | |
| | | #define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) |
| | | #define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) |
| | | #define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) |
| | | |
| | | extern void __raw_writesb(unsigned int addr, const void *data, int bytelen); |
| | | extern void __raw_writesw(unsigned int addr, const void *data, int wordlen); |
| | | extern void __raw_writesl(unsigned int addr, const void *data, int longlen); |
| | | |
| | | extern void __raw_readsb(unsigned int addr, void *data, int bytelen); |
| | | extern void __raw_readsw(unsigned int addr, void *data, int wordlen); |
| | | extern void __raw_readsl(unsigned int addr, void *data, int longlen); |
| | | |
| | | #define __raw_writeb(v,a) __arch_putb(v,a) |
| | | #define __raw_writew(v,a) __arch_putw(v,a) |
| | | #define __raw_writel(v,a) __arch_putl(v,a) |
| | | |
| | | #define __raw_readb(a) __arch_getb(a) |
| | | #define __raw_readw(a) __arch_getw(a) |
| | | #define __raw_readl(a) __arch_getl(a) |
| | | |
| | | #define writeb(v,a) __arch_putb(v,a) |
| | | #define writew(v,a) __arch_putw(v,a) |
| | | #define writel(v,a) __arch_putl(v,a) |
| | | |
| | | #define readb(a) __arch_getb(a) |
| | | #define readw(a) __arch_getw(a) |
| | | #define readl(a) __arch_getl(a) |
| | | |
| | | /* |
| | | * The compiler seems to be incapable of optimising constants |
| | | * properly. Spell it out to the compiler in some cases. |
| | | * These are only valid for small values of "off" (< 1<<12) |
| | | */ |
| | | #define __raw_base_writeb(val,base,off) __arch_base_putb(val,base,off) |
| | | #define __raw_base_writew(val,base,off) __arch_base_putw(val,base,off) |
| | | #define __raw_base_writel(val,base,off) __arch_base_putl(val,base,off) |
| | | |
| | | #define __raw_base_readb(base,off) __arch_base_getb(base,off) |
| | | #define __raw_base_readw(base,off) __arch_base_getw(base,off) |
| | | #define __raw_base_readl(base,off) __arch_base_getl(base,off) |
| | | |
| | | /* |
| | | * Now, pick up the machine-defined IO definitions |
| | | */ |
| | | #if 0 /* XXX###XXX */ |
| | | #include <asm/arch/io.h> |
| | | #endif /* XXX###XXX */ |
| | | |
| | | /* |
| | | * IO port access primitives |
| | | * ------------------------- |
| | | * |
| | | * The ARM doesn't have special IO access instructions; all IO is memory |
| | | * mapped. Note that these are defined to perform little endian accesses |
| | | * only. Their primary purpose is to access PCI and ISA peripherals. |
| | | * |
| | | * Note that for a big endian machine, this implies that the following |
| | | * big endian mode connectivity is in place, as described by numerous |
| | | * ARM documents: |
| | | * |
| | | * PCI: D0-D7 D8-D15 D16-D23 D24-D31 |
| | | * ARM: D24-D31 D16-D23 D8-D15 D0-D7 |
| | | * |
| | | * The machine specific io.h include defines __io to translate an "IO" |
| | | * address to a memory address. |
| | | * |
| | | * Note that we prevent GCC re-ordering or caching values in expressions |
| | | * by introducing sequence points into the in*() definitions. Note that |
| | | * __raw_* do not guarantee this behaviour. |
| | | * |
| | | * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space. |
| | | */ |
| | | #ifdef __io |
| | | #define outb(v,p) __raw_writeb(v,__io(p)) |
| | | #define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p)) |
| | | #define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p)) |
| | | |
| | | #define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) |
| | | #define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; }) |
| | | #define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; }) |
| | | |
| | | #define outsb(p,d,l) __raw_writesb(__io(p),d,l) |
| | | #define outsw(p,d,l) __raw_writesw(__io(p),d,l) |
| | | #define outsl(p,d,l) __raw_writesl(__io(p),d,l) |
| | | |
| | | #define insb(p,d,l) __raw_readsb(__io(p),d,l) |
| | | #define insw(p,d,l) __raw_readsw(__io(p),d,l) |
| | | #define insl(p,d,l) __raw_readsl(__io(p),d,l) |
| | | #endif |
| | | |
| | | #define outb_p(val,port) outb((val),(port)) |
| | | #define outw_p(val,port) outw((val),(port)) |
| | | #define outl_p(val,port) outl((val),(port)) |
| | | #define inb_p(port) inb((port)) |
| | | #define inw_p(port) inw((port)) |
| | | #define inl_p(port) inl((port)) |
| | | |
| | | #define outsb_p(port,from,len) outsb(port,from,len) |
| | | #define outsw_p(port,from,len) outsw(port,from,len) |
| | | #define outsl_p(port,from,len) outsl(port,from,len) |
| | | #define insb_p(port,to,len) insb(port,to,len) |
| | | #define insw_p(port,to,len) insw(port,to,len) |
| | | #define insl_p(port,to,len) insl(port,to,len) |
| | | |
| | | /* |
| | | * ioremap and friends. |
| | | * |
| | | * ioremap takes a PCI memory address, as specified in |
| | | * linux/Documentation/IO-mapping.txt. If you want a |
| | | * physical address, use __ioremap instead. |
| | | */ |
| | | extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags); |
| | | extern void __iounmap(void *addr); |
| | | |
| | | /* |
| | | * Generic ioremap support. |
| | | * |
| | | * Define: |
| | | * iomem_valid_addr(off,size) |
| | | * iomem_to_phys(off) |
| | | */ |
| | | #ifdef iomem_valid_addr |
| | | #define __arch_ioremap(off,sz,nocache) \ |
| | | ({ \ |
| | | unsigned long _off = (off), _size = (sz); \ |
| | | void *_ret = (void *)0; \ |
| | | if (iomem_valid_addr(_off, _size)) \ |
| | | _ret = __ioremap(iomem_to_phys(_off),_size,0); \ |
| | | _ret; \ |
| | | }) |
| | | |
| | | #define __arch_iounmap __iounmap |
| | | #endif |
| | | |
| | | #define ioremap(off,sz) __arch_ioremap((off),(sz),0) |
| | | #define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) |
| | | #define iounmap(_addr) __arch_iounmap(_addr) |
| | | |
| | | /* |
| | | * DMA-consistent mapping functions. These allocate/free a region of |
| | | * uncached, unwrite-buffered mapped memory space for use with DMA |
| | | * devices. This is the "generic" version. The PCI specific version |
| | | * is in pci.h |
| | | */ |
| | | extern void *consistent_alloc(int gfp, size_t size, dma_addr_t * handle); |
| | | extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); |
| | | extern void consistent_sync(void *vaddr, size_t size, int rw); |
| | | |
| | | /* |
| | | * String version of IO memory access ops: |
| | | */ |
| | | extern void _memcpy_fromio(void *, unsigned long, size_t); |
| | | extern void _memcpy_toio(unsigned long, const void *, size_t); |
| | | extern void _memset_io(unsigned long, int, size_t); |
| | | |
| | | extern void __readwrite_bug(const char *fn); |
| | | |
| | | /* |
| | | * If this architecture has PCI memory IO, then define the read/write |
| | | * macros. These should only be used with the cookie passed from |
| | | * ioremap. |
| | | */ |
| | | #ifdef __mem_pci |
| | | |
| | | #define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; }) |
| | | #define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) |
| | | #define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) |
| | | |
| | | #define writeb(v,c) __raw_writeb(v,__mem_pci(c)) |
| | | #define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) |
| | | #define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) |
| | | |
| | | #define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) |
| | | #define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) |
| | | #define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) |
| | | |
| | | #define eth_io_copy_and_sum(s,c,l,b) \ |
| | | eth_copy_and_sum((s),__mem_pci(c),(l),(b)) |
| | | |
| | | static inline int check_signature(unsigned long io_addr, const unsigned char *signature, int length) |
| | | { |
| | | int retval = 0; |
| | | do |
| | | { |
| | | if (readb(io_addr) != *signature) |
| | | goto out; |
| | | io_addr++; |
| | | signature++; |
| | | length--; |
| | | } |
| | | while (length); |
| | | retval = 1; |
| | | out: |
| | | return retval; |
| | | } |
| | | |
| | | #elif !defined(readb) |
| | | |
| | | #define readb(addr) (__readwrite_bug("readb"),0) |
| | | #define readw(addr) (__readwrite_bug("readw"),0) |
| | | #define readl(addr) (__readwrite_bug("readl"),0) |
| | | #define writeb(v,addr) __readwrite_bug("writeb") |
| | | #define writew(v,addr) __readwrite_bug("writew") |
| | | #define writel(v,addr) __readwrite_bug("writel") |
| | | |
| | | #define eth_io_copy_and_sum(a,b,c,d) __readwrite_bug("eth_io_copy_and_sum") |
| | | |
| | | #define check_signature(io,sig,len) (0) |
| | | |
| | | #endif /* __mem_pci */ |
| | | |
| | | /* |
| | | * If this architecture has ISA IO, then define the isa_read/isa_write |
| | | * macros. |
| | | */ |
| | | #ifdef __mem_isa |
| | | |
| | | #define isa_readb(addr) __raw_readb(__mem_isa(addr)) |
| | | #define isa_readw(addr) __raw_readw(__mem_isa(addr)) |
| | | #define isa_readl(addr) __raw_readl(__mem_isa(addr)) |
| | | #define isa_writeb(val,addr) __raw_writeb(val,__mem_isa(addr)) |
| | | #define isa_writew(val,addr) __raw_writew(val,__mem_isa(addr)) |
| | | #define isa_writel(val,addr) __raw_writel(val,__mem_isa(addr)) |
| | | #define isa_memset_io(a,b,c) _memset_io(__mem_isa(a),(b),(c)) |
| | | #define isa_memcpy_fromio(a,b,c) _memcpy_fromio((a),__mem_isa(b),(c)) |
| | | #define isa_memcpy_toio(a,b,c) _memcpy_toio(__mem_isa((a)),(b),(c)) |
| | | |
| | | #define isa_eth_io_copy_and_sum(a,b,c,d) \ |
| | | eth_copy_and_sum((a),__mem_isa(b),(c),(d)) |
| | | |
| | | static inline int |
| | | isa_check_signature(unsigned long io_addr, const unsigned char *signature, int length) |
| | | { |
| | | int retval = 0; |
| | | do |
| | | { |
| | | if (isa_readb(io_addr) != *signature) |
| | | goto out; |
| | | io_addr++; |
| | | signature++; |
| | | length--; |
| | | } |
| | | while (length); |
| | | retval = 1; |
| | | out: |
| | | return retval; |
| | | } |
| | | |
| | | #else /* __mem_isa */ |
| | | |
| | | #define isa_readb(addr) (__readwrite_bug("isa_readb"),0) |
| | | #define isa_readw(addr) (__readwrite_bug("isa_readw"),0) |
| | | #define isa_readl(addr) (__readwrite_bug("isa_readl"),0) |
| | | #define isa_writeb(val,addr) __readwrite_bug("isa_writeb") |
| | | #define isa_writew(val,addr) __readwrite_bug("isa_writew") |
| | | #define isa_writel(val,addr) __readwrite_bug("isa_writel") |
| | | #define isa_memset_io(a,b,c) __readwrite_bug("isa_memset_io") |
| | | #define isa_memcpy_fromio(a,b,c) __readwrite_bug("isa_memcpy_fromio") |
| | | #define isa_memcpy_toio(a,b,c) __readwrite_bug("isa_memcpy_toio") |
| | | |
| | | #define isa_eth_io_copy_and_sum(a,b,c,d) \ |
| | | __readwrite_bug("isa_eth_io_copy_and_sum") |
| | | |
| | | #define isa_check_signature(io,sig,len) (0) |
| | | |
| | | #endif /* __mem_isa */ |
| | | #endif /* __KERNEL__ */ |
| | | #endif /* __ASM_ARM_IO_H */ |
New file |
| | |
| | | /* |
| | | * linux/include/asm-arm/posix_types.h |
| | | * |
| | | * Copyright (C) 1996-1998 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. |
| | | * |
| | | * Changelog: |
| | | * 27-06-1996 RMK Created |
| | | */ |
| | | #ifndef __ARCH_ARM_POSIX_TYPES_H |
| | | #define __ARCH_ARM_POSIX_TYPES_H |
| | | |
| | | /* |
| | | * This file is generally used by user-level software, so you need to |
| | | * be a little careful about namespace pollution etc. Also, we cannot |
| | | * assume GCC is being used. |
| | | */ |
| | | |
| | | typedef unsigned short __kernel_dev_t; |
| | | typedef unsigned long __kernel_ino_t; |
| | | typedef unsigned short __kernel_mode_t; |
| | | typedef unsigned short __kernel_nlink_t; |
| | | typedef long __kernel_off_t; |
| | | typedef int __kernel_pid_t; |
| | | typedef unsigned short __kernel_ipc_pid_t; |
| | | typedef unsigned short __kernel_uid_t; |
| | | typedef unsigned short __kernel_gid_t; |
| | | typedef unsigned int __kernel_size_t; |
| | | typedef int __kernel_ssize_t; |
| | | typedef int __kernel_ptrdiff_t; |
| | | typedef long __kernel_time_t; |
| | | typedef long __kernel_suseconds_t; |
| | | typedef long __kernel_clock_t; |
| | | typedef int __kernel_daddr_t; |
| | | typedef char *__kernel_caddr_t; |
| | | typedef unsigned short __kernel_uid16_t; |
| | | typedef unsigned short __kernel_gid16_t; |
| | | typedef unsigned int __kernel_uid32_t; |
| | | typedef unsigned int __kernel_gid32_t; |
| | | |
| | | typedef unsigned short __kernel_old_uid_t; |
| | | typedef unsigned short __kernel_old_gid_t; |
| | | |
| | | #ifdef __GNUC__ |
| | | typedef long long __kernel_loff_t; |
| | | #endif |
| | | |
| | | typedef struct |
| | | { |
| | | #if defined(__KERNEL__) || defined(__USE_ALL) |
| | | int val[2]; |
| | | #else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ |
| | | int __val[2]; |
| | | #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ |
| | | } __kernel_fsid_t; |
| | | |
| | | #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) |
| | | |
| | | #undef __FD_SET |
| | | #define __FD_SET(fd, fdsetp) \ |
| | | (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31))) |
| | | |
| | | #undef __FD_CLR |
| | | #define __FD_CLR(fd, fdsetp) \ |
| | | (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31))) |
| | | |
| | | #undef __FD_ISSET |
| | | #define __FD_ISSET(fd, fdsetp) \ |
| | | ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0) |
| | | |
| | | #undef __FD_ZERO |
| | | #define __FD_ZERO(fdsetp) \ |
| | | (memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp))) |
| | | |
| | | #endif |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License as published by |
| | | * the Free Software Foundation; either version 2 of the License, or |
| | | * (at your option) any later version. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License |
| | | * along with this program; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | */ |
| | | /* DO NOT EDIT!! - this file automatically generated |
| | | * from .s file by awk -f s2h.awk |
| | | */ |
| | | /* Size defintions |
| | | * Copyright (C) ARM Limited 1998. All rights reserved. |
| | | */ |
| | | |
| | | #ifndef __sizes_h |
| | | #define __sizes_h 1 |
| | | |
| | | /* handy sizes */ |
| | | #define SZ_1K 0x00000400 |
| | | #define SZ_4K 0x00001000 |
| | | #define SZ_8K 0x00002000 |
| | | #define SZ_16K 0x00004000 |
| | | #define SZ_64K 0x00010000 |
| | | #define SZ_128K 0x00020000 |
| | | #define SZ_256K 0x00040000 |
| | | #define SZ_512K 0x00080000 |
| | | |
| | | #define SZ_1M 0x00100000 |
| | | #define SZ_2M 0x00200000 |
| | | #define SZ_4M 0x00400000 |
| | | #define SZ_8M 0x00800000 |
| | | #define SZ_16M 0x01000000 |
| | | #define SZ_32M 0x02000000 |
| | | #define SZ_64M 0x04000000 |
| | | #define SZ_128M 0x08000000 |
| | | #define SZ_256M 0x10000000 |
| | | #define SZ_512M 0x20000000 |
| | | |
| | | #define SZ_1G 0x40000000 |
| | | #define SZ_2G 0x80000000 |
| | | |
| | | #endif |
| | | |
| | | /* END */ |
New file |
| | |
| | | #ifndef __ASM_ARM_TYPES_H |
| | | #define __ASM_ARM_TYPES_H |
| | | |
| | | typedef unsigned short umode_t; |
| | | |
| | | /* |
| | | * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the |
| | | * header files exported to user space |
| | | */ |
| | | |
| | | typedef __signed__ char __s8; |
| | | typedef unsigned char __u8; |
| | | |
| | | typedef __signed__ short __s16; |
| | | typedef unsigned short __u16; |
| | | |
| | | typedef __signed__ int __s32; |
| | | typedef unsigned int __u32; |
| | | |
| | | #if defined(__GNUC__) |
| | | __extension__ typedef __signed__ long long __s64; |
| | | __extension__ typedef unsigned long long __u64; |
| | | #endif |
| | | |
| | | /* |
| | | * These aren't exported outside the kernel to avoid name space clashes |
| | | */ |
| | | #ifdef __KERNEL__ |
| | | |
| | | typedef signed char s8; |
| | | typedef unsigned char u8; |
| | | |
| | | typedef signed short s16; |
| | | typedef unsigned short u16; |
| | | |
| | | typedef signed int s32; |
| | | typedef unsigned int u32; |
| | | |
| | | typedef signed long long s64; |
| | | typedef unsigned long long u64; |
| | | |
| | | #define BITS_PER_LONG 32 |
| | | |
| | | /* Dma addresses are 32-bits wide. */ |
| | | |
| | | typedef u32 dma_addr_t; |
| | | |
| | | typedef unsigned long phys_addr_t; |
| | | typedef unsigned long phys_size_t; |
| | | |
| | | #endif /* __KERNEL__ */ |
| | | |
| | | #endif |
New file |
| | |
| | | /** |
| | | * \file bignum.h |
| | | */ |
| | | #ifndef _BIGNUM_H |
| | | #define _BIGNUM_H |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #define ERR_MPI_INVALID_CHARACTER 0x0002 |
| | | #define ERR_MPI_INVALID_PARAMETER 0x0004 |
| | | #define ERR_MPI_BUFFER_TOO_SMALL 0x0006 |
| | | #define ERR_MPI_NEGATIVE_VALUE 0x0008 |
| | | #define ERR_MPI_DIVISION_BY_ZERO 0x000A |
| | | #define ERR_MPI_NOT_INVERTIBLE 0x000C |
| | | #define ERR_MPI_IS_COMPOSITE 0x000E |
| | | |
| | | #define CHK(fc) if( ( ret = fc ) != 0 ) goto cleanup |
| | | |
| | | /* |
| | | * Define the base limb type |
| | | */ |
| | | #if defined(HAVE_INT16) /* 8086 */ |
| | | typedef unsigned int t_int; |
| | | typedef unsigned long t_dbl; |
| | | #else |
| | | typedef unsigned long t_int; |
| | | typedef unsigned long long t_dbl; |
| | | #endif |
| | | |
| | | #define ciL (int) sizeof(t_int) /* chars in limb */ |
| | | #define biL (ciL << 3) /* bits in limb */ |
| | | #define biH (ciL << 2) /* half limb size */ |
| | | |
| | | /** |
| | | * \brief MPI structure |
| | | */ |
| | | typedef struct |
| | | { |
| | | int s; /*!< integer sign */ |
| | | int n; /*!< total # of limbs */ |
| | | // t_int *p; /*!< pointer to limbs */ |
| | | unsigned long long *p; /*!< pointer to limbs */ |
| | | } |
| | | mpi; |
| | | |
| | | /** |
| | | * \brief Initialize one or more mpi |
| | | */ |
| | | void mpi_init( mpi *X, ... ); |
| | | |
| | | /** |
| | | * \brief Unallocate one or more mpi |
| | | */ |
| | | void mpi_free( mpi *X, ... ); |
| | | |
| | | /** |
| | | * \brief Enlarge X to the specified # of limbs |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_grow( mpi *X, int nblimbs ); |
| | | |
| | | /** |
| | | * \brief Copy the contents of Y into X |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_copy( mpi *X, mpi *Y ); |
| | | |
| | | /** |
| | | * \brief Swap the contents of X and Y |
| | | */ |
| | | void mpi_swap( mpi *X, mpi *Y ); |
| | | |
| | | /** |
| | | * \brief Set value from integer |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_lset( mpi *X, int z ); |
| | | |
| | | /** |
| | | * \brief Set value from string |
| | | * |
| | | * \param X destination mpi |
| | | * \param s string to read the value from |
| | | * \param radix numeric base of "s" |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_INVALID_PARAMETER if the radix is invalid |
| | | * ERR_MPI_INVALID_CHARACTER if a non-digit is found |
| | | */ |
| | | int mpi_read( mpi *X, char *s, int radix ); |
| | | |
| | | /** |
| | | * \brief Print the value of X into fout |
| | | * |
| | | * \param name string printed before the value |
| | | * \param X mpi to be printed |
| | | * \param radix chosen numeric base |
| | | * \param fout output file stream |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_INVALID_PARAMETER if the radix is invalid |
| | | */ |
| | | int mpi_showf( char *name, mpi *X, int radix, FILE *fout ); |
| | | |
| | | /** |
| | | * \brief Print the value of X on the console |
| | | * |
| | | * \param name string printed before the value |
| | | * \param X mpi to be printed |
| | | * \param radix chosen numeric base |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_INVALID_PARAMETER if the radix is invalid |
| | | */ |
| | | int mpi_show( char *name, mpi *X, int radix ); |
| | | |
| | | /** |
| | | * \brief Import an unsigned value from binary data |
| | | * |
| | | * \param X destination mpi |
| | | * \param buf input buffer |
| | | * \param buflen size of buffer |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_import( mpi *X, unsigned char *buf, int buflen ); |
| | | |
| | | /** |
| | | * \brief Export an unsigned value into binary data |
| | | * |
| | | * \param X source mpi |
| | | * \param buf output buffer |
| | | * \param buflen size of buffer |
| | | * |
| | | * \return 0 if successful, |
| | | * ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough |
| | | * |
| | | * \note Call this function with *buflen = 0 to obtain the |
| | | * required buffer size in *buflen. |
| | | */ |
| | | int mpi_export( mpi *X, unsigned char *buf, int *buflen ); |
| | | |
| | | /** |
| | | * \brief Return actual size in bits (without leading 0s) |
| | | */ |
| | | int mpi_size( mpi *X ); |
| | | |
| | | /** |
| | | * \brief Return number of least significant bits |
| | | */ |
| | | int mpi_lsb( mpi *X ); |
| | | |
| | | /** |
| | | * \brief Left-shift: X <<= count |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_shift_l( mpi *X, int count ); |
| | | |
| | | /** |
| | | * \brief Right-shift: X >>= count |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_shift_r( mpi *X, int count ); |
| | | |
| | | /** |
| | | * \brief Compare unsigned values |
| | | * |
| | | * \return 1 if |X| is greater than |Y|, |
| | | * -1 if |X| is lesser than |Y| or |
| | | * 0 if |X| is equal to |Y| |
| | | */ |
| | | int mpi_cmp_abs( mpi *X, mpi *Y ); |
| | | |
| | | /** |
| | | * \brief Compare signed values |
| | | * |
| | | * \return 1 if X is greater than Y, |
| | | * -1 if X is lesser than Y or |
| | | * 0 if X is equal to Y |
| | | */ |
| | | int mpi_cmp_mpi( mpi *X, mpi *Y ); |
| | | |
| | | /** |
| | | * \brief Compare signed values |
| | | * |
| | | * \return 1 if X is greater than z, |
| | | * -1 if X is lesser than z or |
| | | * 0 if X is equal to z |
| | | */ |
| | | int mpi_cmp_int( mpi *X, int z ); |
| | | |
| | | /** |
| | | * \brief Unsigned addition: X = |A| + |B| |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_add_abs( mpi *X, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Unsigned substraction: X = |A| - |B| |
| | | * |
| | | * \return 0 if successful, |
| | | * ERR_MPI_NEGATIVE_VALUE if B is greater than A |
| | | */ |
| | | int mpi_sub_abs( mpi *X, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Signed addition: X = A + B |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_add_mpi( mpi *X, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Signed substraction: X = A - B |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Signed addition: X = A + b |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_add_int( mpi *X, mpi *A, int b ); |
| | | |
| | | /** |
| | | * \brief Signed substraction: X = A - b |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_sub_int( mpi *X, mpi *A, int b ); |
| | | |
| | | /** |
| | | * \brief Baseline multiplication: X = A * B |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_mul_mpi( mpi *X, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Baseline multiplication: X = A * b |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_mul_int( mpi *X, mpi *A, t_int b ); |
| | | |
| | | /** |
| | | * \brief Division by mpi: A = Q * B + R |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_DIVISION_BY_ZERO if B == 0 |
| | | * |
| | | * \note Either Q or R can be NULL. |
| | | */ |
| | | int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Division by int: A = Q * b + R |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_DIVISION_BY_ZERO if b == 0 |
| | | * |
| | | * \note Either Q or R can be NULL. |
| | | */ |
| | | int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b ); |
| | | |
| | | /** |
| | | * \brief Modulo: R = A mod B |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_DIVISION_BY_ZERO if B == 0 |
| | | */ |
| | | int mpi_mod_mpi( mpi *R, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Modulo: r = A mod b |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_DIVISION_BY_ZERO if b == 0, |
| | | */ |
| | | int mpi_mod_int( t_int *r, mpi *A, int b ); |
| | | |
| | | /** |
| | | * \brief Sliding-window exponentiation: X = A^E mod N |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_INVALID_PARAMETER if N is negative or even |
| | | * |
| | | * \note _RR is used to avoid re-computing R*R mod N across |
| | | * multiple calls, which speeds up things a bit. It can |
| | | * be set to NULL if the extra performance is unneeded. |
| | | */ |
| | | int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR ); |
| | | |
| | | /** |
| | | * \brief Greatest common divisor: G = gcd(A, B) |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed |
| | | */ |
| | | int mpi_gcd( mpi *G, mpi *A, mpi *B ); |
| | | |
| | | /** |
| | | * \brief Modular inverse: X = A^-1 mod N |
| | | * |
| | | * \return 0 if successful, |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_INVALID_PARAMETER if N is negative or nil |
| | | * ERR_MPI_NOT_INVERTIBLE if A has no inverse mod N |
| | | */ |
| | | int mpi_inv_mod( mpi *X, mpi *A, mpi *N ); |
| | | |
| | | /** |
| | | * \brief Miller-Rabin primality test |
| | | * |
| | | * \return 0 if successful (probably prime), |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_IS_COMPOSITE if X is not prime |
| | | */ |
| | | int mpi_is_prime( mpi *X ); |
| | | |
| | | /** |
| | | * \brief Prime number generation |
| | | * |
| | | * \param X destination mpi |
| | | * \param nbits required size of X in bits |
| | | * \param dh_flag set this to 1 if (X-1)/2 must also be prime |
| | | * (needed for Diffie-Hellman) |
| | | * \param rng_f points to the RNG function |
| | | * \param rng_d points to the RNG data |
| | | * |
| | | * \return 0 if successful (probably prime), |
| | | * 1 if memory allocation failed, |
| | | * ERR_MPI_INVALID_PARAMETER if nbits is < 3 |
| | | */ |
| | | int mpi_gen_prime( mpi *X, int nbits, int dh_flag, |
| | | int (*rng_f)(void *), void *rng_d ); |
| | | |
| | | /** |
| | | * \brief Checkup routine |
| | | * |
| | | * \return 0 if successful, or 1 if the test failed |
| | | */ |
| | | int mpi_self_test( void ); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* bignum.h */ |
New file |
| | |
| | | /** |
| | | * \file bn_asm.h |
| | | * |
| | | * Multiply source vector [s] with b, add result |
| | | * to destination vector [d] and set carry c. |
| | | */ |
| | | #ifndef _BN_ASM_H |
| | | #define _BN_ASM_H |
| | | |
| | | #if defined(__GNUC__) |
| | | #if defined(__i386__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "movl %0, %%esi " :: "m" (s)); \ |
| | | asm( "movl %0, %%edi " :: "m" (d)); \ |
| | | asm( "movl %0, %%ecx " :: "m" (c)); \ |
| | | asm( "movl %0, %%ebx " :: "m" (b)); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "lodsl " ); \ |
| | | asm( "mull %ebx " ); \ |
| | | asm( "addl %ecx, %eax " ); \ |
| | | asm( "adcl $0, %edx " ); \ |
| | | asm( "addl (%edi), %eax " ); \ |
| | | asm( "adcl $0, %edx " ); \ |
| | | asm( "movl %edx, %ecx " ); \ |
| | | asm( "stosl " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "movl %%ecx, %0 " : "=m" (c)); \ |
| | | asm( "movl %%edi, %0 " : "=m" (d)); \ |
| | | asm( "movl %%esi, %0 " : "=m" (s) :: \ |
| | | "eax", "ecx", "edx", "ebx", "esi", "edi" ); |
| | | |
| | | #if defined(HAVE_SSE2) |
| | | |
| | | #define MULADDC_HUIT \ |
| | | asm( "movd %ecx, %mm1 " ); \ |
| | | asm( "movd %ebx, %mm0 " ); \ |
| | | asm( "movd (%edi), %mm3 " ); \ |
| | | asm( "paddq %mm3, %mm1 " ); \ |
| | | asm( "movd (%esi), %mm2 " ); \ |
| | | asm( "pmuludq %mm0, %mm2 " ); \ |
| | | asm( "movd 4(%esi), %mm4 " ); \ |
| | | asm( "pmuludq %mm0, %mm4 " ); \ |
| | | asm( "movd 8(%esi), %mm6 " ); \ |
| | | asm( "pmuludq %mm0, %mm6 " ); \ |
| | | asm( "movd 12(%esi), %mm7 " ); \ |
| | | asm( "pmuludq %mm0, %mm7 " ); \ |
| | | asm( "paddq %mm2, %mm1 " ); \ |
| | | asm( "movd 4(%edi), %mm3 " ); \ |
| | | asm( "paddq %mm4, %mm3 " ); \ |
| | | asm( "movd 8(%edi), %mm5 " ); \ |
| | | asm( "paddq %mm6, %mm5 " ); \ |
| | | asm( "movd 12(%edi), %mm4 " ); \ |
| | | asm( "paddq %mm4, %mm7 " ); \ |
| | | asm( "movd %mm1, (%edi) " ); \ |
| | | asm( "movd 16(%esi), %mm2 " ); \ |
| | | asm( "pmuludq %mm0, %mm2 " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "movd 20(%esi), %mm4 " ); \ |
| | | asm( "pmuludq %mm0, %mm4 " ); \ |
| | | asm( "paddq %mm3, %mm1 " ); \ |
| | | asm( "movd 24(%esi), %mm6 " ); \ |
| | | asm( "pmuludq %mm0, %mm6 " ); \ |
| | | asm( "movd %mm1, 4(%edi) " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "movd 28(%esi), %mm3 " ); \ |
| | | asm( "pmuludq %mm0, %mm3 " ); \ |
| | | asm( "paddq %mm5, %mm1 " ); \ |
| | | asm( "movd 16(%edi), %mm5 " ); \ |
| | | asm( "paddq %mm5, %mm2 " ); \ |
| | | asm( "movd %mm1, 8(%edi) " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "paddq %mm7, %mm1 " ); \ |
| | | asm( "movd 20(%edi), %mm5 " ); \ |
| | | asm( "paddq %mm5, %mm4 " ); \ |
| | | asm( "movd %mm1, 12(%edi) " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "paddq %mm2, %mm1 " ); \ |
| | | asm( "movd 24(%edi), %mm5 " ); \ |
| | | asm( "paddq %mm5, %mm6 " ); \ |
| | | asm( "movd %mm1, 16(%edi) " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "paddq %mm4, %mm1 " ); \ |
| | | asm( "movd 28(%edi), %mm5 " ); \ |
| | | asm( "paddq %mm5, %mm3 " ); \ |
| | | asm( "movd %mm1, 20(%edi) " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "paddq %mm6, %mm1 " ); \ |
| | | asm( "movd %mm1, 24(%edi) " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "paddq %mm3, %mm1 " ); \ |
| | | asm( "movd %mm1, 28(%edi) " ); \ |
| | | asm( "addl $32, %edi " ); \ |
| | | asm( "addl $32, %esi " ); \ |
| | | asm( "psrlq $32, %mm1 " ); \ |
| | | asm( "movd %mm1, %ecx " ); |
| | | |
| | | #endif /* SSE2 */ |
| | | #endif /* i386 */ |
| | | |
| | | #if defined(__amd64__) || defined (__x86_64__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "movq %0, %%rsi " :: "m" (s)); \ |
| | | asm( "movq %0, %%rdi " :: "m" (d)); \ |
| | | asm( "movq %0, %%rcx " :: "m" (c)); \ |
| | | asm( "movq %0, %%rbx " :: "m" (b)); \ |
| | | asm( "xorq %r8, %r8 " ); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "movq (%rsi),%rax " ); \ |
| | | asm( "mulq %rbx " ); \ |
| | | asm( "addq $8, %rsi " ); \ |
| | | asm( "addq %rcx, %rax " ); \ |
| | | asm( "movq %r8, %rcx " ); \ |
| | | asm( "adcq $0, %rdx " ); \ |
| | | asm( "nop " ); \ |
| | | asm( "addq %rax, (%rdi) " ); \ |
| | | asm( "adcq %rdx, %rcx " ); \ |
| | | asm( "addq $8, %rdi " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "movq %%rcx, %0 " : "=m" (c)); \ |
| | | asm( "movq %%rdi, %0 " : "=m" (d)); \ |
| | | asm( "movq %%rsi, %0 " : "=m" (s) :: \ |
| | | "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); |
| | | |
| | | #endif /* AMD64 */ |
| | | |
| | | #if defined(__mc68020__) || defined(__mcpu32__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "movl %0, %%a2 " :: "m" (s)); \ |
| | | asm( "movl %0, %%a3 " :: "m" (d)); \ |
| | | asm( "movl %0, %%d3 " :: "m" (c)); \ |
| | | asm( "movl %0, %%d2 " :: "m" (b)); \ |
| | | asm( "moveq #0, %d0 " ); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d4:%d1 " ); \ |
| | | asm( "addl %d3, %d1 " ); \ |
| | | asm( "addxl %d0, %d4 " ); \ |
| | | asm( "moveq #0, %d3 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "addxl %d4, %d3 " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "movl %%d3, %0 " : "=m" (c)); \ |
| | | asm( "movl %%a3, %0 " : "=m" (d)); \ |
| | | asm( "movl %%a2, %0 " : "=m" (s) :: \ |
| | | "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); |
| | | |
| | | #define MULADDC_HUIT \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d4:%d1 " ); \ |
| | | asm( "addxl %d3, %d1 " ); \ |
| | | asm( "addxl %d0, %d4 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d3:%d1 " ); \ |
| | | asm( "addxl %d4, %d1 " ); \ |
| | | asm( "addxl %d0, %d3 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d4:%d1 " ); \ |
| | | asm( "addxl %d3, %d1 " ); \ |
| | | asm( "addxl %d0, %d4 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d3:%d1 " ); \ |
| | | asm( "addxl %d4, %d1 " ); \ |
| | | asm( "addxl %d0, %d3 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d4:%d1 " ); \ |
| | | asm( "addxl %d3, %d1 " ); \ |
| | | asm( "addxl %d0, %d4 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d3:%d1 " ); \ |
| | | asm( "addxl %d4, %d1 " ); \ |
| | | asm( "addxl %d0, %d3 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d4:%d1 " ); \ |
| | | asm( "addxl %d3, %d1 " ); \ |
| | | asm( "addxl %d0, %d4 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "movel %a2@+, %d1 " ); \ |
| | | asm( "mulul %d2, %d3:%d1 " ); \ |
| | | asm( "addxl %d4, %d1 " ); \ |
| | | asm( "addxl %d0, %d3 " ); \ |
| | | asm( "addl %d1, %a3@+ " ); \ |
| | | asm( "addxl %d0, %d3 " ); |
| | | |
| | | #endif /* MC68020 */ |
| | | |
| | | #if defined(__powerpc__) || defined(__ppc__) |
| | | #if defined(__powerpc64__) || defined(__ppc64__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "ld %%r3, %0 " :: "m" (s)); \ |
| | | asm( "ld %%r4, %0 " :: "m" (d)); \ |
| | | asm( "ld %%r5, %0 " :: "m" (c)); \ |
| | | asm( "ld %%r6, %0 " :: "m" (b)); \ |
| | | asm( "addi %r3, %r3, -8 " ); \ |
| | | asm( "addi %r4, %r4, -8 " ); \ |
| | | asm( "addic %r5, %r5, 0 " ); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "ldu %r7, 8(%r3) " ); \ |
| | | asm( "mulld %r8, %r7, %r6 " ); \ |
| | | asm( "mulhdu %r9, %r7, %r6 " ); \ |
| | | asm( "adde %r8, %r8, %r5 " ); \ |
| | | asm( "ld %r7, 8(%r4) " ); \ |
| | | asm( "addze %r5, %r9 " ); \ |
| | | asm( "addc %r8, %r8, %r7 " ); \ |
| | | asm( "stdu %r8, 8(%r4) " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "addze %r5, %r5 " ); \ |
| | | asm( "addi %r4, %r4, 8 " ); \ |
| | | asm( "addi %r3, %r3, 8 " ); \ |
| | | asm( "std %%r5, %0 " : "=m" (c)); \ |
| | | asm( "std %%r4, %0 " : "=m" (d)); \ |
| | | asm( "std %%r3, %0 " : "=m" (s) :: \ |
| | | "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); |
| | | |
| | | #else |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "lwz %%r3, %0 " :: "m" (s)); \ |
| | | asm( "lwz %%r4, %0 " :: "m" (d)); \ |
| | | asm( "lwz %%r5, %0 " :: "m" (c)); \ |
| | | asm( "lwz %%r6, %0 " :: "m" (b)); \ |
| | | asm( "addi %r3, %r3, -4 " ); \ |
| | | asm( "addi %r4, %r4, -4 " ); \ |
| | | asm( "addic %r5, %r5, 0 " ); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "lwzu %r7, 4(%r3) " ); \ |
| | | asm( "mullw %r8, %r7, %r6 " ); \ |
| | | asm( "mulhwu %r9, %r7, %r6 " ); \ |
| | | asm( "adde %r8, %r8, %r5 " ); \ |
| | | asm( "lwz %r7, 4(%r4) " ); \ |
| | | asm( "addze %r5, %r9 " ); \ |
| | | asm( "addc %r8, %r8, %r7 " ); \ |
| | | asm( "stwu %r8, 4(%r4) " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "addze %r5, %r5 " ); \ |
| | | asm( "addi %r4, %r4, 4 " ); \ |
| | | asm( "addi %r3, %r3, 4 " ); \ |
| | | asm( "stw %%r5, %0 " : "=m" (c)); \ |
| | | asm( "stw %%r4, %0 " : "=m" (d)); \ |
| | | asm( "stw %%r3, %0 " : "=m" (s) :: \ |
| | | "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); |
| | | |
| | | #endif /* PowerPC 32-bit */ |
| | | #endif /* PowerPC 64-bit */ |
| | | |
| | | #if defined(__sparc__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "ld %0, %%o0 " :: "m" (s)); \ |
| | | asm( "ld %0, %%o1 " :: "m" (d)); \ |
| | | asm( "ld %0, %%o2 " :: "m" (c)); \ |
| | | asm( "ld %0, %%o3 " :: "m" (b)); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "ld [%o0], %o4 " ); \ |
| | | asm( "inc 4, %o0 " ); \ |
| | | asm( "ld [%o1], %o5 " ); \ |
| | | asm( "umul %o3, %o4, %o4 " ); \ |
| | | asm( "addcc %o4, %o2, %o4 " ); \ |
| | | asm( "rd %y, %g1 " ); \ |
| | | asm( "addx %g1, 0, %g1 " ); \ |
| | | asm( "addcc %o4, %o5, %o4 " ); \ |
| | | asm( "st %o4, [%o1] " ); \ |
| | | asm( "addx %g1, 0, %o2 " ); \ |
| | | asm( "inc 4, %o1 " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "st %%o2, %0 " : "=m" (c)); \ |
| | | asm( "st %%o1, %0 " : "=m" (d)); \ |
| | | asm( "st %%o0, %0 " : "=m" (s) :: \ |
| | | "g1", "o0", "o1", "o2", "o3", "o4", "o5" ); |
| | | |
| | | #endif /* SPARC8 */ |
| | | |
| | | #if defined(__tricore__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "ld.a %%a2, %0 " :: "m" (s)); \ |
| | | asm( "ld.a %%a3, %0 " :: "m" (d)); \ |
| | | asm( "ld.w %%d4, %0 " :: "m" (c)); \ |
| | | asm( "ld.w %%d1, %0 " :: "m" (b)); \ |
| | | asm( "xor %d5, %d5 " ); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "ld.w %d0, [%a2+] " ); \ |
| | | asm( "madd.u %e2, %e4, %d0, %d1 " ); \ |
| | | asm( "ld.w %d0, [%a3] " ); \ |
| | | asm( "addx %d2, %d2, %d0 " ); \ |
| | | asm( "addc %d3, %d3, 0 " ); \ |
| | | asm( "mov %d4, %d3 " ); \ |
| | | asm( "st.w [%a3+], %d2 " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "st.w %0, %%d4 " : "=m" (c)); \ |
| | | asm( "st.a %0, %%a3 " : "=m" (d)); \ |
| | | asm( "st.a %0, %%a2 " : "=m" (s) :: \ |
| | | "d0", "d1", "e2", "d4", "a2", "a3" ); |
| | | |
| | | #endif /* TriCore */ |
| | | |
| | | #if defined(__arm__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "ldr r0, %0 " :: "m" (s)); \ |
| | | asm( "ldr r1, %0 " :: "m" (d)); \ |
| | | asm( "ldr r2, %0 " :: "m" (c)); \ |
| | | asm( "ldr r3, %0 " :: "m" (b)); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "ldr r4, [r0], #4 " ); \ |
| | | asm( "mov r5, #0 " ); \ |
| | | asm( "ldr r6, [r1] " ); \ |
| | | asm( "umlal r2, r5, r3, r4 " ); \ |
| | | asm( "adds r7, r6, r2 " ); \ |
| | | asm( "adc r2, r5, #0 " ); \ |
| | | asm( "str r7, [r1], #4 " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "str r2, %0 " : "=m" (c)); \ |
| | | asm( "str r1, %0 " : "=m" (d)); \ |
| | | asm( "str r0, %0 " : "=m" (s) :: \ |
| | | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); |
| | | |
| | | #endif /* ARMv3 */ |
| | | |
| | | #if defined(__alpha__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "ldq $1, %0 " :: "m" (s)); \ |
| | | asm( "ldq $2, %0 " :: "m" (d)); \ |
| | | asm( "ldq $3, %0 " :: "m" (c)); \ |
| | | asm( "ldq $4, %0 " :: "m" (b)); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "ldq $6, 0($1) " ); \ |
| | | asm( "addq $1, 8, $1 " ); \ |
| | | asm( "mulq $6, $4, $7 " ); \ |
| | | asm( "umulh $6, $4, $6 " ); \ |
| | | asm( "addq $7, $3, $7 " ); \ |
| | | asm( "cmpult $7, $3, $3 " ); \ |
| | | asm( "ldq $5, 0($2) " ); \ |
| | | asm( "addq $7, $5, $7 " ); \ |
| | | asm( "cmpult $7, $5, $5 " ); \ |
| | | asm( "stq $7, 0($2) " ); \ |
| | | asm( "addq $2, 8, $2 " ); \ |
| | | asm( "addq $6, $3, $3 " ); \ |
| | | asm( "addq $5, $3, $3 " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "stq $3, %0 " : "=m" (c)); \ |
| | | asm( "stq $2, %0 " : "=m" (d)); \ |
| | | asm( "stq $1, %0 " : "=m" (s) :: \ |
| | | "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); |
| | | |
| | | #endif /* Alpha */ |
| | | |
| | | #if defined(__mips__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | asm( "lw $10, %0 " :: "m" (s)); \ |
| | | asm( "lw $11, %0 " :: "m" (d)); \ |
| | | asm( "lw $12, %0 " :: "m" (c)); \ |
| | | asm( "lw $13, %0 " :: "m" (b)); |
| | | |
| | | #define MULADDC_CORE \ |
| | | asm( "lw $14, 0($10) " ); \ |
| | | asm( "multu $13, $14 " ); \ |
| | | asm( "addi $10, $10, 4 " ); \ |
| | | asm( "mflo $14 " ); \ |
| | | asm( "mfhi $9 " ); \ |
| | | asm( "addu $14, $12, $14 " ); \ |
| | | asm( "lw $15, 0($11) " ); \ |
| | | asm( "sltu $12, $14, $12 " ); \ |
| | | asm( "addu $15, $14, $15 " ); \ |
| | | asm( "sltu $14, $15, $14 " ); \ |
| | | asm( "addu $12, $12, $9 " ); \ |
| | | asm( "sw $15, 0($11) " ); \ |
| | | asm( "addu $12, $12, $14 " ); \ |
| | | asm( "addi $11, $11, 4 " ); |
| | | |
| | | #define MULADDC_STOP \ |
| | | asm( "sw $12, %0 " : "=m" (c)); \ |
| | | asm( "sw $11, %0 " : "=m" (d)); \ |
| | | asm( "sw $10, %0 " : "=m" (s) :: \ |
| | | "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); |
| | | |
| | | #endif /* MIPS */ |
| | | #endif /* GNUC */ |
| | | |
| | | #if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) |
| | | |
| | | #define MULADDC_INIT \ |
| | | __asm mov esi, s \ |
| | | __asm mov edi, d \ |
| | | __asm mov ecx, c \ |
| | | __asm mov ebx, b |
| | | |
| | | #define MULADDC_CORE \ |
| | | __asm lodsd \ |
| | | __asm mul ebx \ |
| | | __asm add eax, ecx \ |
| | | __asm adc edx, 0 \ |
| | | __asm add eax, [edi] \ |
| | | __asm adc edx, 0 \ |
| | | __asm mov ecx, edx \ |
| | | __asm stosd |
| | | |
| | | #define MULADDC_STOP \ |
| | | __asm mov c, ecx \ |
| | | __asm mov d, edi \ |
| | | __asm mov s, esi \ |
| | | |
| | | #if defined HAVE_SSE2 |
| | | |
| | | #define EMIT __asm _emit |
| | | |
| | | #define MULADDC_HUIT \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x1F \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x16 \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x0F \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ |
| | | EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ |
| | | EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ |
| | | EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ |
| | | EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ |
| | | EMIT 0x0F EMIT 0x7E EMIT 0xC9 |
| | | |
| | | #endif /* SSE2 */ |
| | | #endif /* MSVC */ |
| | | |
| | | #if !defined(MULADDC_CORE) |
| | | #if defined(HAVE_LONGLONG) |
| | | |
| | | #define MULADDC_INIT \ |
| | | { \ |
| | | t_dbl r; \ |
| | | t_int r0, r1; |
| | | |
| | | #define MULADDC_CORE \ |
| | | r = *(s++) * (t_dbl) b; \ |
| | | r0 = r; \ |
| | | r1 = r >> biL; \ |
| | | r0 += c; r1 += (r0 < c); \ |
| | | r0 += *d; r1 += (r0 < *d); \ |
| | | c = r1; *(d++) = r0; |
| | | |
| | | #define MULADDC_STOP \ |
| | | } |
| | | |
| | | #else |
| | | #define MULADDC_INIT \ |
| | | { \ |
| | | t_int s0, s1, b0, b1; \ |
| | | t_int r0, r1, rx, ry; \ |
| | | b0 = ( b << biH ) >> biH; \ |
| | | b1 = ( b >> biH ); |
| | | |
| | | #define MULADDC_CORE \ |
| | | s0 = ( *s << biH ) >> biH; \ |
| | | s1 = ( *s >> biH ); s++; \ |
| | | rx = s0 * b1; r0 = s0 * b0; \ |
| | | ry = s1 * b0; r1 = s1 * b1; \ |
| | | r1 += ( rx >> biH ); \ |
| | | r1 += ( ry >> biH ); \ |
| | | rx <<= biH; ry <<= biH; \ |
| | | r0 += rx; r1 += (r0 < rx); \ |
| | | r0 += ry; r1 += (r0 < ry); \ |
| | | r0 += c; r1 += (r0 < c); \ |
| | | r0 += *d; r1 += (r0 < *d); \ |
| | | c = r1; *(d++) = r0; |
| | | |
| | | #define MULADDC_STOP \ |
| | | } |
| | | |
| | | #endif /* C (generic) */ |
| | | #endif /* C (longlong) */ |
| | | |
| | | #endif /* bn_asm.h */ |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: common.h |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: A busy head file |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #ifndef __COMMON_H |
| | | #define __COMMON_H |
| | | |
| | | #include <stdarg.h> |
| | | #include <config.h> |
| | | #include <asm/types.h> |
| | | #include <asm/io.h> |
| | | #include <linux/types.h> |
| | | |
| | | #define DEBUG |
| | | #ifdef DEBUG |
| | | #define dbg_print(format,args...) printf(format, ##args) |
| | | #else |
| | | #define dbg_print(format,args...) do{} while(0); |
| | | #endif |
| | | |
| | | typedef unsigned char uchar; |
| | | typedef volatile unsigned long vu_long; |
| | | typedef volatile unsigned short vu_short; |
| | | typedef volatile unsigned char vu_char; |
| | | typedef volatile unsigned int vu_int; |
| | | |
| | | /*Define in board.c*/ |
| | | inline void delay(unsigned long loops); |
| | | void init_led_beep(void); |
| | | void turn_led_on(int led); |
| | | void turn_led_off(int led); |
| | | void beep(int count); |
| | | |
| | | void serial_init(void); |
| | | void serial_send_byte(char c); |
| | | int serial_is_recv_enable(void); |
| | | int serial_recv_byte(void); |
| | | void serial_puts(const char *s); |
| | | long xmodem_recv(char *buf); |
| | | |
| | | /*Define in printf.c*/ |
| | | void * memset(void * s,int c,size_t count); |
| | | void printf(const char *fmt, ...); |
| | | int sprintf(char *buf, const char *fmt, ...); |
| | | |
| | | |
| | | #endif |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: start.S - Startup Code for ARM920 CPU-core |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: Configure file for bootstrap, just like u-boot-1.3.4/include/config/s3c2440.h |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #ifndef __CONFIG_H |
| | | #define __CONFIG_H |
| | | |
| | | #ifdef BOARD_SMDK2440 |
| | | #include <s3c2440.h> |
| | | #define CONFIG_S3C2440 |
| | | #endif |
| | | |
| | | #define MDIV_405 0x7f << 12 |
| | | #define PSDIV_405 0x21 |
| | | |
| | | #define CONFIG_LED_DEBUG 1 |
| | | |
| | | #define CONFIG_SYS_MALLOC_LEN (1024*1024) |
| | | #define CONFIG_SYS_GBL_DATA_SIZE 128 |
| | | #define CONFIG_STACKSIZE 0x40000 |
| | | |
| | | #define CFG_PBSIZE 384 /* Print Buffer Size */ |
| | | |
| | | #define CFG_MAX_NAND_DEVICE 1 |
| | | #define NAND_MAX_CHIPS 1 |
| | | #define CFG_NAND_BASE 0x4E000000 |
| | | |
| | | #define BOOTLOADER_ENV_ADDR 0x20000 /*Bootloader enviroment start address*/ |
| | | #define LAUNCHER_NAND_ADDR 0x40000 /*Laucher save in Nandflash address*/ |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_BITOPS_H |
| | | #define _LINUX_BITOPS_H |
| | | |
| | | /* |
| | | * ffs: find first bit set. This is defined the same way as |
| | | * the libc and compiler builtin ffs routines, therefore |
| | | * differs in spirit from the above ffz (man ffs). |
| | | */ |
| | | |
| | | static inline int generic_ffs(int x) |
| | | { |
| | | int r = 1; |
| | | |
| | | if (!x) |
| | | return 0; |
| | | if (!(x & 0xffff)) |
| | | { |
| | | x >>= 16; |
| | | r += 16; |
| | | } |
| | | if (!(x & 0xff)) |
| | | { |
| | | x >>= 8; |
| | | r += 8; |
| | | } |
| | | if (!(x & 0xf)) |
| | | { |
| | | x >>= 4; |
| | | r += 4; |
| | | } |
| | | if (!(x & 3)) |
| | | { |
| | | x >>= 2; |
| | | r += 2; |
| | | } |
| | | if (!(x & 1)) |
| | | { |
| | | x >>= 1; |
| | | r += 1; |
| | | } |
| | | return r; |
| | | } |
| | | |
| | | /* |
| | | * hweightN: returns the hamming weight (i.e. the number |
| | | * of bits set) of a N-bit word |
| | | */ |
| | | |
| | | static inline unsigned int generic_hweight32(unsigned int w) |
| | | { |
| | | unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); |
| | | res = (res & 0x33333333) + ((res >> 2) & 0x33333333); |
| | | res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); |
| | | res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); |
| | | return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); |
| | | } |
| | | |
| | | static inline unsigned int generic_hweight16(unsigned int w) |
| | | { |
| | | unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555); |
| | | res = (res & 0x3333) + ((res >> 2) & 0x3333); |
| | | res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); |
| | | return (res & 0x00FF) + ((res >> 8) & 0x00FF); |
| | | } |
| | | |
| | | static inline unsigned int generic_hweight8(unsigned int w) |
| | | { |
| | | unsigned int res = (w & 0x55) + ((w >> 1) & 0x55); |
| | | res = (res & 0x33) + ((res >> 2) & 0x33); |
| | | return (res & 0x0F) + ((res >> 4) & 0x0F); |
| | | } |
| | | |
| | | //#include <asm/bitops.h> |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_CONFIG_H |
| | | #define _LINUX_CONFIG_H |
| | | |
| | | /* #include <linux/autoconf.h> */ |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_CTYPE_H |
| | | #define _LINUX_CTYPE_H |
| | | |
| | | /* |
| | | * NOTE! This ctype does not handle EOF like the standard C |
| | | * library is required to. |
| | | */ |
| | | |
| | | #define _U 0x01 /* upper */ |
| | | #define _L 0x02 /* lower */ |
| | | #define _D 0x04 /* digit */ |
| | | #define _C 0x08 /* cntrl */ |
| | | #define _P 0x10 /* punct */ |
| | | #define _S 0x20 /* white space (space/lf/tab) */ |
| | | #define _X 0x40 /* hex digit */ |
| | | #define _SP 0x80 /* hard space (0x20) */ |
| | | |
| | | extern unsigned char _ctype[]; |
| | | |
| | | #define __ismask(x) (_ctype[(int)(unsigned char)(x)]) |
| | | |
| | | #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) |
| | | #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) |
| | | #define iscntrl(c) ((__ismask(c)&(_C)) != 0) |
| | | #define isdigit(c) ((__ismask(c)&(_D)) != 0) |
| | | #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) |
| | | #define islower(c) ((__ismask(c)&(_L)) != 0) |
| | | #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) |
| | | #define ispunct(c) ((__ismask(c)&(_P)) != 0) |
| | | #define isspace(c) ((__ismask(c)&(_S)) != 0) |
| | | #define isupper(c) ((__ismask(c)&(_U)) != 0) |
| | | #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) |
| | | |
| | | #define isascii(c) (((unsigned char)(c))<=0x7f) |
| | | #define toascii(c) (((unsigned char)(c))&0x7f) |
| | | |
| | | static inline unsigned char __tolower(unsigned char c) |
| | | { |
| | | if (isupper(c)) |
| | | c -= 'A' - 'a'; |
| | | return c; |
| | | } |
| | | |
| | | static inline unsigned char __toupper(unsigned char c) |
| | | { |
| | | if (islower(c)) |
| | | c -= 'a' - 'A'; |
| | | return c; |
| | | } |
| | | |
| | | #define tolower(c) __tolower(c) |
| | | #define toupper(c) __toupper(c) |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_POSIX_TYPES_H |
| | | #define _LINUX_POSIX_TYPES_H |
| | | |
| | | #include <linux/stddef.h> |
| | | |
| | | /* |
| | | * This allows for 1024 file descriptors: if NR_OPEN is ever grown |
| | | * beyond that you'll have to change this too. But 1024 fd's seem to be |
| | | * enough even for such "real" unices like OSF/1, so hopefully this is |
| | | * one limit that doesn't have to be changed [again]. |
| | | * |
| | | * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in |
| | | * <sys/time.h> (and thus <linux/time.h>) - but this is a more logical |
| | | * place for them. Solved by having dummy defines in <sys/time.h>. |
| | | */ |
| | | |
| | | /* |
| | | * Those macros may have been defined in <gnu/types.h>. But we always |
| | | * use the ones here. |
| | | */ |
| | | #undef __NFDBITS |
| | | #define __NFDBITS (8 * sizeof(unsigned long)) |
| | | |
| | | #undef __FD_SETSIZE |
| | | #define __FD_SETSIZE 1024 |
| | | |
| | | #undef __FDSET_LONGS |
| | | #define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) |
| | | |
| | | #undef __FDELT |
| | | #define __FDELT(d) ((d) / __NFDBITS) |
| | | |
| | | #undef __FDMASK |
| | | #define __FDMASK(d) (1UL << ((d) % __NFDBITS)) |
| | | |
| | | typedef struct |
| | | { |
| | | unsigned long fds_bits[__FDSET_LONGS]; |
| | | } __kernel_fd_set; |
| | | |
| | | /* Type of a signal handler. */ |
| | | typedef void (*__kernel_sighandler_t) (int); |
| | | |
| | | /* Type of a SYSV IPC key. */ |
| | | typedef int __kernel_key_t; |
| | | |
| | | #include <asm/posix_types.h> |
| | | |
| | | #endif /* _LINUX_POSIX_TYPES_H */ |
New file |
| | |
| | | #ifndef _LINUX_STDDEF_H |
| | | #define _LINUX_STDDEF_H |
| | | |
| | | #undef NULL |
| | | #if defined(__cplusplus) |
| | | #define NULL 0 |
| | | #else |
| | | #define NULL ((void *)0) |
| | | #endif |
| | | |
| | | #ifndef _SIZE_T |
| | | #include <linux/types.h> |
| | | #endif |
| | | |
| | | #undef offsetof |
| | | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_STRING_H_ |
| | | #define _LINUX_STRING_H_ |
| | | |
| | | #include <linux/types.h> /* for size_t */ |
| | | #include <linux/stddef.h> /* for NULL */ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" |
| | | { |
| | | #endif |
| | | |
| | | extern char *___strtok; |
| | | extern char *strpbrk(const char *, const char *); |
| | | extern char *strtok(char *, const char *); |
| | | extern char *strsep(char **, const char *); |
| | | extern __kernel_size_t strspn(const char *, const char *); |
| | | |
| | | /* |
| | | * Include machine specific inline routines |
| | | */ |
| | | #include <asm/string.h> |
| | | |
| | | #ifndef __HAVE_ARCH_STRCPY |
| | | extern char *strcpy(char *, const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNCPY |
| | | extern char *strncpy(char *, const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRCAT |
| | | extern char *strcat(char *, const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNCAT |
| | | extern char *strncat(char *, const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRCMP |
| | | extern int strcmp(const char *, const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNCMP |
| | | extern int strncmp(const char *, const char *, __kernel_size_t); |
| | | #endif |
| | | #if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ |
| | | extern int strnicmp(const char *, const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRCHR |
| | | extern char *strchr(const char *, int); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRRCHR |
| | | extern char *strrchr(const char *, int); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRSTR |
| | | extern char *strstr(const char *, const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRLEN |
| | | extern __kernel_size_t strlen(const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNLEN |
| | | extern __kernel_size_t strnlen(const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRDUP |
| | | extern char *strdup(const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRSWAB |
| | | extern char *strswab(const char *); |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMSET |
| | | extern void *memset(void *, int, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMCPY |
| | | extern void *memcpy(void *, const void *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMMOVE |
| | | extern void *memmove(void *, const void *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMSCAN |
| | | extern void *memscan(void *, int, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMCMP |
| | | extern int memcmp(const void *, const void *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMCHR |
| | | extern void *memchr(const void *, int, __kernel_size_t); |
| | | #endif |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _LINUX_STRING_H_ */ |
New file |
| | |
| | | #ifndef _LINUX_TIME_H |
| | | #define _LINUX_TIME_H |
| | | |
| | | #include <linux/types.h> |
| | | |
| | | #define _DEFUN(a,b,c) a(c) |
| | | #define _CONST const |
| | | #define _AND , |
| | | |
| | | #define _REENT_ONLY |
| | | |
| | | #define SECSPERMIN 60L |
| | | #define MINSPERHOUR 60L |
| | | #define HOURSPERDAY 24L |
| | | #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) |
| | | #define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) |
| | | #define DAYSPERWEEK 7 |
| | | #define MONSPERYEAR 12 |
| | | |
| | | #define YEAR_BASE 1900 |
| | | #define EPOCH_YEAR 1970 |
| | | #define EPOCH_WDAY 4 |
| | | |
| | | #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) |
| | | |
| | | /* Used by other time functions. */ |
| | | struct tm |
| | | { |
| | | int tm_sec; /* Seconds. [0-60] (1 leap second) */ |
| | | int tm_min; /* Minutes. [0-59] */ |
| | | int tm_hour; /* Hours. [0-23] */ |
| | | int tm_mday; /* Day. [1-31] */ |
| | | int tm_mon; /* Month. [0-11] */ |
| | | int tm_year; /* Year - 1900. */ |
| | | int tm_wday; /* Day of week. [0-6] */ |
| | | int tm_yday; /* Days in year.[0-365] */ |
| | | int tm_isdst; /* DST. [-1/0/1] */ |
| | | |
| | | # ifdef __USE_BSD |
| | | long int tm_gmtoff; /* Seconds east of UTC. */ |
| | | __const char *tm_zone; /* Timezone abbreviation. */ |
| | | # else |
| | | long int __tm_gmtoff; /* Seconds east of UTC. */ |
| | | __const char *__tm_zone; /* Timezone abbreviation. */ |
| | | # endif |
| | | }; |
| | | |
| | | static inline char *_DEFUN(asctime_r, (tim_p, result), _CONST struct tm *tim_p _AND char *result) |
| | | { |
| | | static _CONST char day_name[7][3] = { |
| | | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
| | | }; |
| | | static _CONST char mon_name[12][3] = { |
| | | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| | | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
| | | }; |
| | | |
| | | sprintf(result, "%.3s %.3s %.2d %.2d:%.2d:%.2d %d\n", |
| | | day_name[tim_p->tm_wday], |
| | | mon_name[tim_p->tm_mon], |
| | | tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec, 1900 + tim_p->tm_year); |
| | | return result; |
| | | } |
| | | |
| | | static inline struct tm *_DEFUN(localtime_r, (tim_p, res), |
| | | _CONST time_t * tim_p _AND struct tm *res) |
| | | { |
| | | static _CONST int mon_lengths[2][MONSPERYEAR] = { |
| | | {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, |
| | | {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} |
| | | }; |
| | | |
| | | static _CONST int year_lengths[2] = { |
| | | 365, |
| | | 366 |
| | | }; |
| | | |
| | | long days, rem; |
| | | int y; |
| | | int yleap; |
| | | _CONST int *ip; |
| | | |
| | | days = ((long)*tim_p) / SECSPERDAY; |
| | | rem = ((long)*tim_p) % SECSPERDAY; |
| | | while (rem < 0) |
| | | { |
| | | rem += SECSPERDAY; |
| | | --days; |
| | | } |
| | | while (rem >= SECSPERDAY) |
| | | { |
| | | rem -= SECSPERDAY; |
| | | ++days; |
| | | } |
| | | |
| | | /* compute hour, min, and sec */ |
| | | res->tm_hour = (int)(rem / SECSPERHOUR); |
| | | rem %= SECSPERHOUR; |
| | | res->tm_min = (int)(rem / SECSPERMIN); |
| | | res->tm_sec = (int)(rem % SECSPERMIN); |
| | | |
| | | /* compute day of week */ |
| | | if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) |
| | | res->tm_wday += DAYSPERWEEK; |
| | | |
| | | /* compute year & day of year */ |
| | | y = EPOCH_YEAR; |
| | | if (days >= 0) |
| | | { |
| | | for (;;) |
| | | { |
| | | yleap = isleap(y); |
| | | if (days < year_lengths[yleap]) |
| | | break; |
| | | y++; |
| | | days -= year_lengths[yleap]; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | do |
| | | { |
| | | --y; |
| | | yleap = isleap(y); |
| | | days += year_lengths[yleap]; |
| | | } |
| | | while (days < 0); |
| | | } |
| | | |
| | | res->tm_year = y - YEAR_BASE; |
| | | res->tm_yday = days; |
| | | ip = mon_lengths[yleap]; |
| | | for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) |
| | | days -= ip[res->tm_mon]; |
| | | res->tm_mday = days + 1; |
| | | |
| | | /* set daylight saving time flag */ |
| | | res->tm_isdst = -1; |
| | | |
| | | return (res); |
| | | } |
| | | |
| | | static inline char *_DEFUN(ctime_r, (tim_p, result), _CONST time_t * tim_p _AND char *result) |
| | | { |
| | | struct tm tm; |
| | | return asctime_r(localtime_r(tim_p, &tm), result); |
| | | } |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_TYPES_H |
| | | #define _LINUX_TYPES_H |
| | | |
| | | #ifdef __KERNEL__ |
| | | #include <linux/config.h> |
| | | #endif |
| | | |
| | | #include <linux/posix_types.h> |
| | | #include <asm/types.h> |
| | | |
| | | #ifndef __KERNEL_STRICT_NAMES |
| | | |
| | | typedef __kernel_fd_set fd_set; |
| | | typedef __kernel_dev_t dev_t; |
| | | typedef __kernel_ino_t ino_t; |
| | | typedef __kernel_mode_t mode_t; |
| | | typedef __kernel_nlink_t nlink_t; |
| | | typedef __kernel_off_t off_t; |
| | | typedef __kernel_pid_t pid_t; |
| | | typedef __kernel_daddr_t daddr_t; |
| | | typedef __kernel_key_t key_t; |
| | | typedef __kernel_suseconds_t suseconds_t; |
| | | |
| | | #ifdef __KERNEL__ |
| | | typedef __kernel_uid32_t uid_t; |
| | | typedef __kernel_gid32_t gid_t; |
| | | typedef __kernel_uid16_t uid16_t; |
| | | typedef __kernel_gid16_t gid16_t; |
| | | |
| | | #ifdef CONFIG_UID16 |
| | | /* This is defined by include/asm-{arch}/posix_types.h */ |
| | | typedef __kernel_old_uid_t old_uid_t; |
| | | typedef __kernel_old_gid_t old_gid_t; |
| | | #endif /* CONFIG_UID16 */ |
| | | |
| | | /* libc5 includes this file to define uid_t, thus uid_t can never change |
| | | * when it is included by non-kernel code |
| | | */ |
| | | #else |
| | | typedef __kernel_uid_t uid_t; |
| | | typedef __kernel_gid_t gid_t; |
| | | #endif /* __KERNEL__ */ |
| | | |
| | | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) |
| | | typedef __kernel_loff_t loff_t; |
| | | #endif |
| | | |
| | | /* |
| | | * The following typedefs are also protected by individual ifdefs for |
| | | * historical reasons: |
| | | */ |
| | | #ifndef _SIZE_T |
| | | #define _SIZE_T |
| | | typedef __kernel_size_t size_t; |
| | | #endif |
| | | |
| | | #ifndef _SSIZE_T |
| | | #define _SSIZE_T |
| | | typedef __kernel_ssize_t ssize_t; |
| | | #endif |
| | | |
| | | #ifndef _PTRDIFF_T |
| | | #define _PTRDIFF_T |
| | | typedef __kernel_ptrdiff_t ptrdiff_t; |
| | | #endif |
| | | |
| | | #ifndef _TIME_T |
| | | #define _TIME_T |
| | | typedef __kernel_time_t time_t; |
| | | #endif |
| | | |
| | | #ifndef _CLOCK_T |
| | | #define _CLOCK_T |
| | | typedef __kernel_clock_t clock_t; |
| | | #endif |
| | | |
| | | #ifndef _CADDR_T |
| | | #define _CADDR_T |
| | | typedef __kernel_caddr_t caddr_t; |
| | | #endif |
| | | |
| | | /* bsd */ |
| | | typedef unsigned char u_char; |
| | | typedef unsigned short u_short; |
| | | typedef unsigned int u_int; |
| | | typedef unsigned long u_long; |
| | | |
| | | /* sysv */ |
| | | typedef unsigned char unchar; |
| | | typedef unsigned short ushort; |
| | | typedef unsigned int uint; |
| | | typedef unsigned long ulong; |
| | | |
| | | #ifndef __BIT_TYPES_DEFINED__ |
| | | #define __BIT_TYPES_DEFINED__ |
| | | |
| | | typedef __u8 u_int8_t; |
| | | typedef __s8 int8_t; |
| | | typedef __u16 u_int16_t; |
| | | typedef __s16 int16_t; |
| | | typedef __u32 u_int32_t; |
| | | typedef __s32 int32_t; |
| | | |
| | | #endif /* !(__BIT_TYPES_DEFINED__) */ |
| | | |
| | | typedef __u8 uint8_t; |
| | | typedef __u16 uint16_t; |
| | | typedef __u32 uint32_t; |
| | | |
| | | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) |
| | | typedef __u64 uint64_t; |
| | | typedef __u64 u_int64_t; |
| | | typedef __s64 int64_t; |
| | | #endif |
| | | |
| | | #endif /* __KERNEL_STRICT_NAMES */ |
| | | |
| | | /* |
| | | * Below are truly Linux-specific types that should never collide with |
| | | * any application/library that wants linux/types.h. |
| | | */ |
| | | |
| | | struct ustat |
| | | { |
| | | __kernel_daddr_t f_tfree; |
| | | __kernel_ino_t f_tinode; |
| | | char f_fname[6]; |
| | | char f_fpack[6]; |
| | | }; |
| | | |
| | | #endif /* _LINUX_TYPES_H */ |
New file |
| | |
| | | /* |
| | | * linux/include/linux/mtd/nand.h |
| | | * |
| | | * Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org> |
| | | * Steven J. Hill <sjhill@realitydiluted.com> |
| | | * Thomas Gleixner <tglx@linutronix.de> |
| | | * |
| | | * 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. |
| | | * |
| | | * Info: |
| | | * Contains standard defines and IDs for NAND flash devices |
| | | * |
| | | * Changelog: |
| | | * See git changelog. |
| | | */ |
| | | #ifndef __LINUX_MTD_NAND_H |
| | | #define __LINUX_MTD_NAND_H |
| | | |
| | | #include <common.h> |
| | | #include <linux/bitops.h> |
| | | |
| | | #define NAND_K9F2G08 0xecda |
| | | |
| | | /* This constant declares the max. oobsize / page, which |
| | | * is supported now. If you add a chip with bigger oobsize/page |
| | | * adjust this accordingly. |
| | | */ |
| | | #define NAND_MAX_OOBSIZE 218 |
| | | #define NAND_MAX_PAGESIZE 4096 |
| | | |
| | | /* |
| | | * Constants for hardware specific CLE/ALE/NCE function |
| | | * |
| | | * These are bits which can be or'ed to set/clear multiple |
| | | * bits in one go. |
| | | */ |
| | | /* Select the chip by setting nCE to low */ |
| | | #define NAND_NCE 0x01 |
| | | /* Select the command latch by setting CLE to high */ |
| | | #define NAND_CLE 0x02 |
| | | /* Select the address latch by setting ALE to high */ |
| | | #define NAND_ALE 0x04 |
| | | |
| | | #define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) |
| | | #define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) |
| | | #define NAND_CTRL_CHANGE 0x80 |
| | | |
| | | /* |
| | | * Standard NAND flash commands |
| | | */ |
| | | #define NAND_CMD_READ0 0x00 /*Page read period 1*/ |
| | | #define NAND_CMD_READSTART 0x30 /*Page read period 2, for large page*/ |
| | | #define NAND_CMD_READID 0x90 /*Read production ID*/ |
| | | #define NAND_CMD_SEQIN 0x80 /*Page write period 1*/ |
| | | #define NAND_CMD_PAGEPROG 0x10 /*Page write period 2*/ |
| | | #define NAND_CMD_ERASE1 0x60 /*Block erase period 1*/ |
| | | #define NAND_CMD_ERASE2 0xd0 /*Block erase period 2*/ |
| | | #define NAND_CMD_STATUS 0x70 /*Read status command*/ |
| | | #define NAND_CMD_RESET 0xff /*Nandflash reset command*/ |
| | | #define NAND_CMD_READ1 1 |
| | | #define NAND_CMD_RNDOUT 0x05 /*Page random read period 1*/ |
| | | #define NAND_CMD_RNDOUTSTART 0xE0 /*Page random read period 2*/ |
| | | #define NAND_CMD_RNDIN 0x85 /*Page random write*/ |
| | | |
| | | #define NAND_CMD_READOOB 0x50 |
| | | #define NAND_CMD_STATUS_MULTI 0x71 |
| | | |
| | | /* Extended commands for large page devices */ |
| | | #define NAND_CMD_CACHEDPROG 0x15 |
| | | |
| | | /* Extended commands for AG-AND device */ |
| | | /* |
| | | * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but |
| | | * there is no way to distinguish that from NAND_CMD_READ0 |
| | | * until the remaining sequence of commands has been completed |
| | | * so add a high order bit and mask it off in the command. |
| | | */ |
| | | #define NAND_CMD_DEPLETE1 0x100 |
| | | #define NAND_CMD_DEPLETE2 0x38 |
| | | #define NAND_CMD_STATUS_MULTI 0x71 |
| | | #define NAND_CMD_STATUS_ERROR 0x72 |
| | | /* multi-bank error status (banks 0-3) */ |
| | | #define NAND_CMD_STATUS_ERROR0 0x73 |
| | | #define NAND_CMD_STATUS_ERROR1 0x74 |
| | | #define NAND_CMD_STATUS_ERROR2 0x75 |
| | | #define NAND_CMD_STATUS_ERROR3 0x76 |
| | | #define NAND_CMD_STATUS_RESET 0x7f |
| | | #define NAND_CMD_STATUS_CLEAR 0xff |
| | | |
| | | #define NAND_CMD_NONE -1 |
| | | |
| | | /* Status bits */ |
| | | #define NAND_STATUS_FAIL 0x01 |
| | | #define NAND_STATUS_FAIL_N1 0x02 |
| | | #define NAND_STATUS_TRUE_READY 0x20 |
| | | #define NAND_STATUS_READY 0x40 |
| | | #define NAND_STATUS_WP 0x80 |
| | | |
| | | /* |
| | | * Constants for ECC_MODES |
| | | */ |
| | | typedef enum |
| | | { |
| | | NAND_ECC_NONE, |
| | | NAND_ECC_SOFT, |
| | | NAND_ECC_HW, |
| | | NAND_ECC_HW_SYNDROME, |
| | | NAND_ECC_HW_OOB_FIRST, |
| | | } nand_ecc_modes_t; |
| | | |
| | | /* |
| | | * Constants for Hardware ECC |
| | | */ |
| | | /* Reset Hardware ECC for read */ |
| | | #define NAND_ECC_READ 0 |
| | | /* Reset Hardware ECC for write */ |
| | | #define NAND_ECC_WRITE 1 |
| | | /* Enable Hardware ECC before syndrom is read back from flash */ |
| | | #define NAND_ECC_READSYN 2 |
| | | |
| | | /* Bit mask for flags passed to do_nand_read_ecc */ |
| | | #define NAND_GET_DEVICE 0x80 |
| | | |
| | | /* Option constants for bizarre disfunctionality and real |
| | | * features |
| | | */ |
| | | /* Chip can not auto increment pages */ |
| | | #define NAND_NO_AUTOINCR 0x00000001 |
| | | /* Buswitdh is 16 bit */ |
| | | #define NAND_BUSWIDTH_16 0x00000002 |
| | | /* Device supports partial programming without padding */ |
| | | #define NAND_NO_PADDING 0x00000004 |
| | | /* Chip has cache program function */ |
| | | #define NAND_CACHEPRG 0x00000008 |
| | | /* Chip has copy back function */ |
| | | #define NAND_COPYBACK 0x00000010 |
| | | /* AND Chip which has 4 banks and a confusing page / block |
| | | * assignment. See Renesas datasheet for further information */ |
| | | #define NAND_IS_AND 0x00000020 |
| | | /* Chip has a array of 4 pages which can be read without |
| | | * additional ready /busy waits */ |
| | | #define NAND_4PAGE_ARRAY 0x00000040 |
| | | /* Chip requires that BBT is periodically rewritten to prevent |
| | | * bits from adjacent blocks from 'leaking' in altering data. |
| | | * This happens with the Renesas AG-AND chips, possibly others. */ |
| | | #define BBT_AUTO_REFRESH 0x00000080 |
| | | /* Chip does not require ready check on read. True |
| | | * for all large page devices, as they do not support |
| | | * autoincrement.*/ |
| | | #define NAND_NO_READRDY 0x00000100 |
| | | /* Chip does not allow subpage writes */ |
| | | #define NAND_NO_SUBPAGE_WRITE 0x00000200 |
| | | |
| | | /* Options valid for Samsung large page devices */ |
| | | #define NAND_SAMSUNG_LP_OPTIONS \ |
| | | (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK) |
| | | |
| | | /* Macros to identify the above */ |
| | | #define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR)) |
| | | #define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) |
| | | #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) |
| | | #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) |
| | | /* Large page NAND with SOFT_ECC should support subpage reads */ |
| | | #define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ |
| | | && (chip->page_shift > 9)) |
| | | |
| | | /* Mask to zero out the chip options, which come from the id table */ |
| | | #define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) |
| | | |
| | | /* Non chip related options */ |
| | | /* Use a flash based bad block table. This option is passed to the |
| | | * default bad block table function. */ |
| | | #define NAND_USE_FLASH_BBT 0x00010000 |
| | | /* This option skips the bbt scan during initialization. */ |
| | | #define NAND_SKIP_BBTSCAN 0x00020000 |
| | | /* This option is defined if the board driver allocates its own buffers |
| | | (e.g. because it needs them DMA-coherent */ |
| | | #define NAND_OWN_BUFFERS 0x00040000 |
| | | /* Options set by nand scan */ |
| | | /* bbt has already been read */ |
| | | #define NAND_BBT_SCANNED 0x40000000 |
| | | /* Nand scan has allocated controller struct */ |
| | | #define NAND_CONTROLLER_ALLOC 0x80000000 |
| | | |
| | | /* Cell info constants */ |
| | | #define NAND_CI_CHIPNR_MSK 0x03 |
| | | #define NAND_CI_CELLTYPE_MSK 0x0C |
| | | |
| | | /* |
| | | * NAND Flash Manufacturer ID Codes |
| | | */ |
| | | #define NAND_MFR_TOSHIBA 0x98 |
| | | #define NAND_MFR_SAMSUNG 0xec |
| | | #define NAND_MFR_FUJITSU 0x04 |
| | | #define NAND_MFR_NATIONAL 0x8f |
| | | #define NAND_MFR_RENESAS 0x07 |
| | | #define NAND_MFR_STMICRO 0x20 |
| | | #define NAND_MFR_HYNIX 0xad |
| | | #define NAND_MFR_MICRON 0x2c |
| | | #define NAND_MFR_AMD 0x01 |
| | | |
| | | /* |
| | | * Constants for oob configuration |
| | | */ |
| | | #define NAND_SMALL_BADBLOCK_POS 5 |
| | | #define NAND_LARGE_BADBLOCK_POS 0 |
| | | |
| | | |
| | | #if defined(CONFIG_S3C2410) |
| | | #define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) |
| | | #define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x4) |
| | | #define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0x8) |
| | | #define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0xc) |
| | | #define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x10) |
| | | #define NFSTAT_BUSY 1 |
| | | #define nand_select() (REG_NFCONF &= ~0x800) /*Clear bit 11*/ |
| | | #define nand_deselect() (REG_NFCONF |= 0x800) |
| | | #define nand_clear_RnB() do {} while (0) |
| | | #define nand_detect_RnB() do {} while (0) |
| | | #define nand_wait_RnB() do {} while (0) |
| | | |
| | | #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) |
| | | |
| | | #define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) |
| | | #define REG_NFCONT __REGi(ELFIN_NAND_BASE + 0x4) |
| | | #define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x8) |
| | | #define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0xc) |
| | | #define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0x10) |
| | | #define REG_NFDATA16 __REGw(ELFIN_NAND_BASE + 0x10) |
| | | #define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x20) |
| | | #define NFSTAT_BUSY 1 |
| | | #define nand_select() (REG_NFCONT &= ~(1 << 1)) |
| | | #define nand_deselect() (REG_NFCONT |= (1 << 1)) |
| | | #define nand_clear_RnB() (REG_NFSTAT |= (1 << 2)) |
| | | #define nand_detect_RnB() {while(!(REG_NFSTAT&(1<<2)));} /*Wait Read & Busy signal goto high(not busy)*/ |
| | | #define nand_wait_RnB() {while(!(REG_NFSTAT&(1<<0)));} /*Wait nand flash not busy, wait bit[0] goes to 1*/ |
| | | |
| | | #endif |
| | | |
| | | #define SKIP_BAD_BLOCK 1 |
| | | #define NOT_SKIP_BAD_BLOCK 0 |
| | | |
| | | struct boot_nand_t |
| | | { |
| | | int page_size; |
| | | int spare_size; |
| | | int block_size; |
| | | int block_num; |
| | | int bad_block_offset; |
| | | int id; |
| | | // unsigned long size; |
| | | }; |
| | | |
| | | int nand_init(struct boot_nand_t *nand); |
| | | int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); |
| | | int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); |
| | | int is_bad_block(struct boot_nand_t *nand, ulong addr); |
| | | int mark_bad_block(struct boot_nand_t *nand, ulong addr); |
| | | int nand_erase_block(struct boot_nand_t *nand, ulong block_num); |
| | | int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad); |
| | | void nand_scrub(struct boot_nand_t *nand); |
| | | int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); |
| | | int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); |
| | | int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); |
| | | int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); |
| | | |
| | | |
| | | |
| | | #endif /* __LINUX_MTD_NAND_H */ |
New file |
| | |
| | | /** |
| | | * \file rsa.h |
| | | */ |
| | | #ifndef _RSA_H |
| | | #define _RSA_H |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "bignum.h" |
| | | |
| | | #define ERR_RSA_BAD_INPUT_DATA 0x0300 |
| | | #define ERR_RSA_INVALID_PADDING 0x0310 |
| | | #define ERR_RSA_KEY_GEN_FAILED 0x0320 |
| | | #define ERR_RSA_KEY_CHK_FAILED 0x0330 |
| | | #define ERR_RSA_PUBLIC_FAILED 0x0340 |
| | | #define ERR_RSA_PRIVATE_FAILED 0x0350 |
| | | #define ERR_RSA_VERIFY_FAILED 0x0360 |
| | | |
| | | /* |
| | | * PKCS#1 stuff |
| | | */ |
| | | #define RSA_RAW 0 |
| | | #define RSA_MD2 2 |
| | | #define RSA_MD4 3 |
| | | #define RSA_MD5 4 |
| | | #define RSA_SHA1 5 |
| | | |
| | | #define RSA_SIGN 0x01 |
| | | #define RSA_CRYPT 0x02 |
| | | |
| | | /* |
| | | * DigestInfo ::= SEQUENCE { |
| | | * digestAlgorithm DigestAlgorithmIdentifier, |
| | | * digest Digest } |
| | | * |
| | | * DigestAlgorithmIdentifier ::= AlgorithmIdentifier |
| | | * |
| | | * Digest ::= OCTET STRING |
| | | */ |
| | | #define ASN1_HASH_MDX \ |
| | | "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48" \ |
| | | "\x86\xF7\x0D\x02\x00\x05\x00\x04\x10" |
| | | |
| | | #define ASN1_HASH_SHA1 \ |
| | | "\x30\x21\x30\x09\x06\x05\x2B\x0E\x03" \ |
| | | "\x02\x1A\x05\x00\x04\x14" |
| | | |
| | | typedef struct |
| | | { |
| | | int ver; /*!< should be 0 */ |
| | | int len; /*!< size(N) in chars */ |
| | | mpi N; /*!< public modulus */ |
| | | mpi E; /*!< public exponent */ |
| | | mpi D; /*!< private exponent */ |
| | | |
| | | mpi P; /*!< 1st prime factor */ |
| | | mpi Q; /*!< 2nd prime factor */ |
| | | mpi DP; /*!< D mod (P - 1) */ |
| | | mpi DQ; /*!< D mod (Q - 1) */ |
| | | mpi QP; /*!< inverse of Q % P */ |
| | | |
| | | mpi RN; /*!< cached R^2 mod N */ |
| | | mpi RP; /*!< cached R^2 mod P */ |
| | | mpi RQ; /*!< cached R^2 mod Q */ |
| | | } |
| | | rsa_context; |
| | | |
| | | /** |
| | | * \brief Generate an RSA keypair |
| | | * |
| | | * \param ctx RSA context to be initialized |
| | | * \param nbits size of the public key in bits |
| | | * \param exponent public exponent (e.g., 65537) |
| | | * \param rng_f points to the RNG function |
| | | * \param rng_d points to the RNG data |
| | | * |
| | | * \return 0 if successful, or an ERR_RSA_XXX error code |
| | | */ |
| | | int rsa_gen_key( rsa_context *ctx, int nbits, int exponent, |
| | | int (*rng_f)(void *), void *rng_d ); |
| | | |
| | | /** |
| | | * \brief Perform an RSA public key operation |
| | | * |
| | | * \return 0 if successful, or an ERR_RSA_XXX error code |
| | | * |
| | | * \note This function does not take care of message |
| | | * padding: both ilen and olen must be equal to |
| | | * the modulus size (ctx->len). Also, be sure |
| | | * to set input[0] = 0. |
| | | */ |
| | | int rsa_public( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ); |
| | | |
| | | /** |
| | | * \brief Perform an RSA private key operation |
| | | * |
| | | * \return 0 if successful, or an ERR_RSA_XXX error code |
| | | * |
| | | * \note This function does not take care of message |
| | | * padding: both ilen and olen must be equal to |
| | | * the modulus size (ctx->len). Also, be sure |
| | | * to set input[0] = 0. |
| | | */ |
| | | int rsa_private( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ); |
| | | |
| | | /** |
| | | * \brief Return 0 if the public key is valid, |
| | | * or ERR_RSA_KEY_CHECK_FAILED |
| | | */ |
| | | int rsa_check_pubkey( rsa_context *ctx ); |
| | | |
| | | /** |
| | | * \brief Return 0 if the private key is valid, |
| | | * or ERR_RSA_KEY_CHECK_FAILED |
| | | */ |
| | | int rsa_check_privkey( rsa_context *ctx ); |
| | | |
| | | /** |
| | | * \brief Add the PKCS#1 v1.5 padding and do a public RSA |
| | | * |
| | | * \param ctx RSA context |
| | | * \param input buffer holding the data to be encrypted |
| | | * \param ilen length of the plaintext; cannot be longer |
| | | * than the modulus, minus 3+8 for padding |
| | | * \param output buffer that will hold the ciphertext |
| | | * \param olen must be the same as the modulus size |
| | | * (for example, 128 if RSA-1024 is used) |
| | | * |
| | | * \return 0 if successful, or an ERR_RSA_XXX error code |
| | | */ |
| | | int rsa_pkcs1_encrypt( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ); |
| | | |
| | | /** |
| | | * \brief Do a private RSA, removes the PKCS#1 v1.5 padding |
| | | * |
| | | * \param ctx RSA context |
| | | * \param input buffer holding the encrypted data |
| | | * \param ilen must be the same as the modulus size |
| | | * \param output buffer that will hold the plaintext |
| | | * \param olen size of output buffer, will be updated |
| | | * to contain the length of the plaintext |
| | | * |
| | | * \return 0 if successful, or an ERR_RSA_XXX error code |
| | | */ |
| | | int rsa_pkcs1_decrypt( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ); |
| | | |
| | | /** |
| | | * \brief Perform a private RSA to sign a message digest |
| | | * |
| | | * \param ctx RSA context |
| | | * \param alg_id RSA_RAW, RSA_MD2/4/5 or RSA_SHA1 |
| | | * \param hash buffer holding the message digest |
| | | * \param hashlen message digest length |
| | | * \param sig buffer that will hold the ciphertext |
| | | * \param siglen must be the same as the modulus size |
| | | * (for example, 128 if RSA-1024 is used) |
| | | * |
| | | * \return 0 if the signing operation was successful, |
| | | * or an ERR_RSA_XXX error code |
| | | */ |
| | | int rsa_pkcs1_sign( rsa_context *ctx, int alg_id, |
| | | unsigned char *hash, int hashlen, |
| | | unsigned char *sig, int siglen ); |
| | | |
| | | /** |
| | | * \brief Perform a public RSA and check the message digest |
| | | * |
| | | * \param ctx points to an RSA public key |
| | | * \param alg_id RSA_RAW, RSA_MD2/4/5 or RSA_SHA1 |
| | | * \param hash buffer holding the message digest |
| | | * \param hashlen message digest length |
| | | * \param sig buffer holding the ciphertext |
| | | * \param siglen must be the same as the modulus size |
| | | * |
| | | * \return 0 if the verify operation was successful, |
| | | * or an ERR_RSA_XXX error code |
| | | */ |
| | | int rsa_pkcs1_verify( rsa_context *ctx, int alg_id, |
| | | unsigned char *hash, int hashlen, |
| | | unsigned char *sig, int siglen ); |
| | | |
| | | /** |
| | | * \brief Free the components of an RSA key |
| | | */ |
| | | void rsa_free( rsa_context *ctx ); |
| | | |
| | | /** |
| | | * \brief Checkup routine |
| | | * |
| | | * \return 0 if successful, or 1 if the test failed |
| | | */ |
| | | int rsa_self_test( void ); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * (C) Copyright 2003 |
| | | * David Müller ELSOFT AG Switzerland. d.mueller@elsoft.ch |
| | | * |
| | | * See file CREDITS for list of people who contributed to this |
| | | * project. |
| | | * |
| | | * This program is free software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU General Public License as |
| | | * published by the Free Software Foundation; either version 2 of |
| | | * the License, or (at your option) any later version. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License |
| | | * along with this program; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| | | * MA 02111-1307 USA |
| | | */ |
| | | |
| | | /************************************************ |
| | | * NAME : s3c2440.h |
| | | * |
| | | * Based on S3C2440A User's manual Rev 1.1 |
| | | ************************************************/ |
| | | |
| | | #ifndef __S3C2440_H__ |
| | | #define __S3C2440_H__ |
| | | |
| | | /*This is debug on FL2440 board*/ |
| | | #define BEEP 0 /*Buzzer use GPB0 */ |
| | | #define LED0 5 /*LED0 use GPB5 */ |
| | | #define LED1 6 /*LED1 use GPB6 */ |
| | | #define LED2 8 /*LED2 use GPB8 */ |
| | | #define LED3 10 /*LED3 use GPB10 */ |
| | | /*FL2440 LED & Beep define end*/ |
| | | |
| | | #define S3C24X0_UART_CHANNELS 3 |
| | | #define S3C24X0_SPI_CHANNELS 2 |
| | | |
| | | #include <asm/hardware.h> |
| | | |
| | | #ifndef __ASSEMBLY__ |
| | | typedef enum |
| | | { |
| | | S3C24X0_UART0, |
| | | S3C24X0_UART1, |
| | | } S3C24X0_UARTS_NR; |
| | | |
| | | #include <s3c24x0.h> |
| | | #endif |
| | | |
| | | #define ROM_BASE0 0x00000000 /* base address of rom bank 0 */ |
| | | #define ROM_BASE1 0x04000000 /* base address of rom bank 1 */ |
| | | #define DRAM_BASE0 0x30000000 /* base address of dram bank 0 */ |
| | | #define DRAM_BASE1 0x00000000 /* base address of dram bank 1 */ |
| | | |
| | | /* S3C2440 only supports 512 Byte HW ECC */ |
| | | #define S3C2410_ECCSIZE 512 |
| | | #define S3C2410_ECCBYTES 3 |
| | | |
| | | /* S3C2440 device base addresses */ |
| | | #define ELFIN_DMA_BASE 0x4b000000 |
| | | #define ELFIN_USB_DEVICE_BASE 0x44a00000 |
| | | #define ELFIN_I2C_BASE 0x54000000 |
| | | #define ELFIN_I2S_BASE 0x55000000 |
| | | #define ELFIN_ADC_BASE 0x58000000 |
| | | #define ELFIN_SPI_BASE 0x59000000 |
| | | #define ELFIN_SDI_BASE 0x5A000000 |
| | | |
| | | /* |
| | | * Memory controller |
| | | */ |
| | | |
| | | #define ELFIN_MEM_CON_BASE 0x48000000 |
| | | |
| | | #define BWSCON_OFFSET 0x00 |
| | | #define BANKCON0_OFFSET 0x04 |
| | | #define BANKCON1_OFFSET 0x08 |
| | | #define BANKCON2_OFFSET 0x0c |
| | | #define BANKCON3_OFFSET 0x10 |
| | | #define BANKCON4_OFFSET 0x14 |
| | | #define BANKCON5_OFFSET 0x18 |
| | | #define BANKCON6_OFFSET 0x1c |
| | | #define BANKCON7_OFFSET 0x20 |
| | | #define REFRESH_OFFSET 0x24 |
| | | #define BANKSIZE_OFFSET 0x28 |
| | | #define MRSRB6_OFFSET 0x2c |
| | | #define MRSRB7_OFFSET 0x30 |
| | | |
| | | #define BWSCON_REG __REG(0x48000000) |
| | | #define BANKCON0_REG __REG(0x48000004) |
| | | #define BANKCON1_REG __REG(0x48000008) |
| | | #define BANKCON2_REG __REG(0x4800000c) |
| | | #define BANKCON3_REG __REG(0x48000010) |
| | | #define BANKCON4_REG __REG(0x48000014) |
| | | #define BANKCON5_REG __REG(0x48000018) |
| | | #define BANKCON6_REG __REG(0x4800001c) |
| | | #define BANKCON7_REG __REG(0x48000020) |
| | | #define REFRESH_REG __REG(0x48000024) |
| | | #define BANKSIZE_REG __REG(0x48000028) |
| | | #define MRSRB6_REG __REG(0x4800002c) |
| | | #define MRSRB7_REG __REG(0x48000030) |
| | | |
| | | /* |
| | | * USB Host Controller |
| | | */ |
| | | #define ELFIN_USB_HOST_BASE 0x49000000 |
| | | |
| | | #define HcRevision_OFFSET 0x00 |
| | | #define HcControl_OFFSET 0x04 |
| | | #define HcCommonStatus_OFFSET 0x08 |
| | | #define HcIntStatus_OFFSET 0x0c |
| | | #define HcIntEnable_OFFSET 0x10 |
| | | #define HcIntDisable_OFFSET 0x14 |
| | | #define HcHCCA_OFFSET 0x18 |
| | | #define HcPerdCurED_OFFSET 0x1c |
| | | #define HcCtrlHeadED_OFFSET 0x20 |
| | | #define HcCtrlCurED_OFFSET 0x24 |
| | | #define HcBulkHeadED_OFFSET 0x28 |
| | | #define HcBulkCurED_OFFSET 0x2c |
| | | #define HcDoneHead_OFFSET 0x30 |
| | | #define HcRmInterval_OFFSET 0x34 |
| | | #define HcFmRemain_OFFSET 0x38 |
| | | #define HcFmNumber_OFFSET 0x3c |
| | | #define HcPerdStart_OFFSET 0x40 |
| | | #define HcLSThres_OFFSET 0x44 |
| | | #define HcRhDescA_OFFSET 0x48 |
| | | #define HcRhDescB_OFFSET 0x4c |
| | | #define HcRhStatus_OFFSET 0x50 |
| | | #define HcRhPortSts1_OFFSET 0x54 |
| | | #define HcRhPortSts2_OFFSET 0x58 |
| | | |
| | | #define HcRevision_REG __REG(0x49000000) |
| | | #define HcControl_REG __REG(0x49000004) |
| | | #define HcCommonStatus_REG __REG(0x49000008) |
| | | #define HcIntStatus_REG __REG(0x4900000c) |
| | | #define HcIntEnable_REG __REG(0x49000010) |
| | | #define HcIntDisable_REG __REG(0x49000014) |
| | | #define HcHCCA_REG __REG(0x49000018) |
| | | #define HcPerdCurED_REG __REG(0x4900001c) |
| | | #define HcCtrlHeadED_REG __REG(0x49000020) |
| | | #define HcCtrlCurED_REG __REG(0x49000024) |
| | | #define HcBulkHeadED_REG __REG(0x49000028) |
| | | #define HcBulkCurED_REG __REG(0x4900002c) |
| | | #define HcDoneHead_REG __REG(0x49000030) |
| | | #define HcRmInterval_REG __REG(0x49000034) |
| | | #define HcFmRemain_REG __REG(0x49000038) |
| | | #define HcFmNumber_REG __REG(0x4900003c) |
| | | #define HcPerdStart_REG __REG(0x49000040) |
| | | #define HcLSThres_REG __REG(0x49000044) |
| | | #define HcRhDescA_REG __REG(0x49000048) |
| | | #define HcRhDescB_REG __REG(0x4900004c) |
| | | #define HcRhStatus_REG __REG(0x49000050) |
| | | #define HcRhPortSts1_REG __REG(0x49000054) |
| | | #define HcRhPortSts2_REG __REG(0x49000058) |
| | | |
| | | /* |
| | | * Interrupt |
| | | */ |
| | | #define ELFIN_INTERRUPT_BASE 0x4a000000 |
| | | |
| | | #define SRCPND_OFFSET 0x00 |
| | | #define INTMOD_OFFSET 0x04 |
| | | #define INTMSK_OFFSET 0x08 |
| | | #define PRIORITY_OFFSET 0x0c |
| | | #define INTPND_OFFSET 0x10 |
| | | #define INTOFFSET_OFFSET 0x14 |
| | | #define SUBSRCPND_OFFSET 0x18 |
| | | #define INTSUBMSK_OFFSET 0x1c |
| | | |
| | | #define SRCPND_REG __REG(0x4a000000) |
| | | #define INTMOD_REG __REG(0x4a000004) |
| | | #define INTMSK_REG __REG(0x4a000008) |
| | | #define PRIORITY_REG __REG(0x4a00000c) |
| | | #define INTPND_REG __REG(0x4a000010) |
| | | #define INTOFFSET_REG __REG(0x4a000014) |
| | | #define SUBSRCPND_REG __REG(0x4a000018) |
| | | #define INTSUBMSK_REG __REG(0x4a00001C) |
| | | |
| | | /* |
| | | * Clock and power management |
| | | */ |
| | | |
| | | #define ELFIN_CLOCK_POWER_BASE 0x4c000000 |
| | | |
| | | #define LOCKTIME_OFFSET 0x00 |
| | | #define MPLLCON_OFFSET 0x04 |
| | | #define UPLLCON_OFFSET 0x08 |
| | | #define CLKCON_OFFSET 0x0c |
| | | #define CLKSLOW_OFFSET 0x10 |
| | | #define CLKDIVN_OFFSET 0x14 |
| | | #define CAMDIVN_OFFSET 0x18 |
| | | |
| | | #define LOCKTIME_REG __REG(0x4c000000) |
| | | #define MPLLCON_REG __REG(0x4c000004) |
| | | #define UPLLCON_REG __REG(0x4c000008) |
| | | #define CLKCON_REG __REG(0x4c00000c) |
| | | #define CLKSLOW_REG __REG(0x4c000010) |
| | | #define CLKDIVN_REG __REG(0x4c000014) |
| | | #define CAMDIVN_REG __REG(0x4c000018) |
| | | |
| | | /* |
| | | * LCD Controller |
| | | */ |
| | | #define ELFIN_LCD_BASE 0x4d000000 |
| | | |
| | | /* |
| | | * GPIO |
| | | */ |
| | | |
| | | #define ELFIN_GPIO_BASE 0x56000000 |
| | | |
| | | #define GPACON_OFFSET 0x00 |
| | | #define GPADAT_OFFSET 0x04 |
| | | #define GPAPU_OFFSET 0x08 |
| | | #define GPASLPCON_OFFSET 0x0C |
| | | #define GPABON_OFFSET 0x10 |
| | | #define GPBDAT_OFFSET 0x14 |
| | | #define GPBPU_OFFSET 0x18 |
| | | #define GPBSLPCON_OFFSET 0x1C |
| | | #define GPCCON_OFFSET 0x20 |
| | | #define GPCDAT_OFFSET 0x24 |
| | | #define GPCPU_OFFSET 0x28 |
| | | #define GPCSLPCON_OFFSET 0x2C |
| | | #define GPDCON_OFFSET 0x30 |
| | | #define GPDDAT_OFFSET 0x34 |
| | | #define GPDPU_OFFSET 0x38 |
| | | #define GPECON_OFFSET 0x40 |
| | | #define GPEDAT_OFFSET 0x44 |
| | | #define GPEPU_OFFSET 0x48 |
| | | #define GPESLPCON_OFFSET 0x4C |
| | | #define GPFCON_OFFSET 0x50 |
| | | #define GPFDAT_OFFSET 0x54 |
| | | #define GPFPU_OFFSET 0x58 |
| | | #define GPFSLPCON_OFFSET 0x5C |
| | | #define GPGCON_OFFSET 0x60 |
| | | #define GPGDAT_OFFSET 0x64 |
| | | #define GPGPU_OFFSET 0x68 |
| | | #define GPGSLPCON_OFFSET 0x6C |
| | | #define GPHCON_OFFSET 0x70 |
| | | #define GPHDAT_OFFSET 0x74 |
| | | #define GPHPU_OFFSET 0x78 |
| | | #define GPHSLPCON_OFFSET 0x7C |
| | | #define GPICON_OFFSET 0x80 |
| | | #define GPIDAT_OFFSET 0x84 |
| | | #define GPIPU_OFFSET 0x88 |
| | | #define GPISLPCON_OFFSET 0x8C |
| | | #define GPJCON_OFFSET 0x90 |
| | | #define GPJDAT_OFFSET 0x94 |
| | | #define GPJPU_OFFSET 0x98 |
| | | #define SPCON_OFFSET 0x9C |
| | | #define GPKCON_OFFSET 0xA0 |
| | | #define GPKDAT_OFFSET 0xA4 |
| | | #define GPKPU_OFFSET 0xA8 |
| | | #define GPKSLPCON_OFFSET 0xAC |
| | | #define EINTCON0_OFFSET 0xB0 |
| | | #define EINTCON1_OFFSET 0xB4 |
| | | #define EINTFLT0_OFFSET 0xB8 |
| | | #define EINTFLT1_OFFSET 0xBC |
| | | #define EINTMASK_OFFSET 0xC0 |
| | | #define EINTPEND_OFFSET 0xC4 |
| | | #define DSPGPSLP_OFFSET 0xC8 |
| | | #define MEM0CONSTOP_OFFSET 0xD0 |
| | | #define MEM1CONSTOP_OFFSET 0xD4 |
| | | #define MEM2CONSTOP_OFFSET 0xD8 |
| | | #define MEM0CONSLP_OFFSET 0xE0 |
| | | #define MEM1CONSLP_OFFSET 0xE4 |
| | | #define MEM2CONSLP_OFFSET 0xE8 |
| | | #define SPCONSLP_OFFSET 0xEC |
| | | #define SLPEN_OFFSET 0xF0 |
| | | #define MEM0DRVCON_OFFSET 0xF4 |
| | | #define MEM1DRVCON_OFFSET 0xF8 |
| | | #define MEM2DRVCON_OFFSET 0xFC |
| | | |
| | | #define GPACON_REG __REG(0x44800000) |
| | | #define GPADAT_REG __REG(0x44800004) |
| | | #define GPAPU_REG __REG(0x44800008) |
| | | #define GPASLPCON_REG __REG(0x4480000C) |
| | | #define GPABON_REG __REG(0x44800010) |
| | | #define GPBDAT_REG __REG(0x44800014) |
| | | #define GPBPU_REG __REG(0x44800018) |
| | | #define GPBSLPCON_REG __REG(0x4480001C) |
| | | #define GPCCON_REG __REG(0x44800020) |
| | | #define GPCDAT_REG __REG(0x44800024) |
| | | #define GPCPU_REG __REG(0x44800028) |
| | | #define GPCSLPCON_REG __REG(0x4480002C) |
| | | #define GPDCON_REG __REG(0x44800030) |
| | | #define GPDDAT_REG __REG(0x44800034) |
| | | #define GPDPU_REG __REG(0x44800038) |
| | | #define GPECON_REG __REG(0x44800040) |
| | | #define GPEDAT_REG __REG(0x44800044) |
| | | #define GPEPU_REG __REG(0x44800048) |
| | | #define GPESLPCON_REG __REG(0x4480004C) |
| | | #define GPFCON_REG __REG(0x44800050) |
| | | #define GPFDAT_REG __REG(0x44800054) |
| | | #define GPFPU_REG __REG(0x44800058) |
| | | #define GPFSLPCON_REG __REG(0x4480005C) |
| | | #define GPGCON_REG __REG(0x44800060) |
| | | #define GPGDAT_REG __REG(0x44800064) |
| | | #define GPGPU_REG __REG(0x44800068) |
| | | #define GPGSLPCON_REG __REG(0x4480006C) |
| | | #define GPHCON_REG __REG(0x44800070) |
| | | #define GPHDAT_REG __REG(0x44800074) |
| | | #define GPHPU_REG __REG(0x44800078) |
| | | #define GPHSLPCON_REG __REG(0x4480007C) |
| | | #define GPICON_REG __REG(0x44800080) |
| | | #define GPIDAT_REG __REG(0x44800084) |
| | | #define GPIPU_REG __REG(0x44800088) |
| | | #define GPISLPCON_REG __REG(0x4480008C) |
| | | #define GPJCON_REG __REG(0x44800090) |
| | | #define GPJDAT_REG __REG(0x44800094) |
| | | #define GPJPU_REG __REG(0x44800098) |
| | | #define SPCON_REG __REG(0x4480009C) |
| | | #define GPKCON_REG __REG(0x448000A0) |
| | | #define GPKDAT_REG __REG(0x448000A4) |
| | | #define GPKPU_REG __REG(0x448000A8) |
| | | #define GPKSLPCON_REG __REG(0x448000AC) |
| | | #define EINTCON0_REG __REG(0x448000B0) |
| | | #define EINTCON1_REG __REG(0x448000B4) |
| | | #define EINTFLT0_REG __REG(0x448000B8) |
| | | #define EINTFLT1_REG __REG(0x448000BC) |
| | | #define EINTMASK_REG __REG(0x448000C0) |
| | | #define EINTPEND_REG __REG(0x448000C4) |
| | | #define DSPGPSLP_REG __REG(0x448000C8) |
| | | #define MEM0CONSTOP_REG __REG(0x448000D0) |
| | | #define MEM1CONSTOP_REG __REG(0x448000D4) |
| | | #define MEM2CONSTOP_REG __REG(0x448000D8) |
| | | #define MEM0CONSLP_REG __REG(0x448000E0) |
| | | #define MEM1CONSLP_REG __REG(0x448000E4) |
| | | #define MEM2CONSLP_REG __REG(0x448000E8) |
| | | #define SPCONSLP_REG __REG(0x448000EC) |
| | | #define SLPEN_REG __REG(0x448000F0) |
| | | #define MEM0DRVCON_REG __REG(0x448000F4) |
| | | #define MEM1DRVCON_REG __REG(0x448000F8) |
| | | #define MEM2DRVCON_REG __REG(0x448000FC) |
| | | |
| | | /* |
| | | * Nand flash controller |
| | | */ |
| | | |
| | | #define ELFIN_NAND_BASE 0x4e000000 |
| | | |
| | | #define NFCONF_OFFSET 0x00 |
| | | #define NFCONT_OFFSET 0x04 |
| | | #define NFCMMD_OFFSET 0x08 |
| | | #define NFADDR_OFFSET 0x0c |
| | | #define NFDATA_OFFSET 0x10 |
| | | #define NFMECCD0_OFFSET 0x14 |
| | | #define NFMECCD1_OFFSET 0x18 |
| | | #define NFSECCD_OFFSET 0x1c |
| | | #define NFSTAT_OFFSET 0x20 |
| | | #define NFESTAT0_OFFSET 0x24 |
| | | #define NFESTAT1_OFFSET 0x28 |
| | | #define NFMECC0_OFFSET 0x2c |
| | | #define NFMECC1_OFFSET 0x30 |
| | | #define NFSECC_OFFSET 0x34 |
| | | #define NFSBLK_OFFSET 0x38 |
| | | #define NFEBLK_OFFSET 0x3c |
| | | |
| | | #define NFCONF (0x4e000000) |
| | | #define NFCONT (0x4e000004) |
| | | #define NFCMMD (0x4e000008) |
| | | #define NFADDR (0x4e00000C) |
| | | #define NFDATA (0x4e000010) |
| | | #define NFMECCDATA0 (0x4e000014) |
| | | #define NFMECCDATA1 (0x4e000018) |
| | | #define NFSECCDATA (0x4e00001c) |
| | | #define NFSTAT (0x4e000020) |
| | | #define NFESTAT0 (0x4e000024) |
| | | #define NFESTAT1 (0x4e000028) |
| | | #define NFMECC0 (0x4e00002C) |
| | | #define NFMECC1 (0x4e000030) |
| | | #define NFSECC (0x4e00003c) |
| | | |
| | | #define NFCONF_REG __REG(0x4e000000) |
| | | #define NFCONT_REG __REG(0x4e000004) |
| | | #define NFCMD_REG __REGb(0x4e000008) |
| | | #define NFADDR_REG __REGb(0x4e00000C) |
| | | #define NFDATA8_REG __REGb(0x4e000010) |
| | | #define NFDATA16_REG __REGw(0x4e000010) |
| | | #define NFDATA32_REG __REG(0x4e000010) |
| | | #define NFSTAT_REG __REG(0x4e000020) |
| | | |
| | | #define NFCONT_WP (1<<12) |
| | | #define NFCONT_SECCLOCK (1<<6) |
| | | #define NFCONT_MECCLOCK (1<<5) |
| | | #define NFCONT_INITECC (1<<4) |
| | | #define NFCONT_CS_ALT (1<<1) |
| | | #define NFCONT_CS (1<<1) |
| | | #define NFSTAT_RnB (1<<0) |
| | | |
| | | /* |
| | | * Watchdog timer |
| | | */ |
| | | |
| | | #define ELFIN_WATCHDOG_BASE 0x53000000 |
| | | |
| | | #define WTCON_OFFSET 0x00 |
| | | #define WTDAT_OFFSET 0x04 |
| | | #define WTCNT_OFFSET 0x08 |
| | | |
| | | #define WTCON_REG __REG(0x53000000) |
| | | #define WTDAT_REG __REG(0x53000004) |
| | | #define WTCNT_REG __REG(0x53000008) |
| | | |
| | | /* |
| | | * UART |
| | | */ |
| | | #define ELFIN_UART_BASE 0x50000000 |
| | | |
| | | #define ULCON0_OFFSET 0x00 |
| | | #define UCON0_OFFSET 0x04 |
| | | #define UFCON0_OFFSET 0x08 |
| | | #define UMCON0_OFFSET 0x0C |
| | | #define UTRSTAT0_OFFSET 0x10 |
| | | #define UERSTAT0_OFFSET 0x14 |
| | | #define UFSTAT0_OFFSET 0x18 |
| | | #define UMSTAT0_OFFSET 0x1C |
| | | #define UTXH0_OFFSET 0x20 |
| | | #define URXH0_OFFSET 0x24 |
| | | #define UBRDIV0_OFFSET 0x28 |
| | | |
| | | #define ULCON0_REG __REG(0x50000000) |
| | | #define UCON0_REG __REG(0x50000004) |
| | | #define UFCON0_REG __REG(0x50000008) |
| | | #define UMCON0_REG __REG(0x5000000C) |
| | | #define UTRSTAT0_REG __REG(0x50000010) |
| | | #define UERSTAT0_REG __REG(0x50000014) |
| | | #define UFSTAT0_REG __REG(0x50000018) |
| | | #define UMSTAT0_REG __REG(0x5000001C) |
| | | #define UTXH0_REG __REG(0x50000020) |
| | | #define URXH0_REG __REG(0x50000024) |
| | | #define UBRDIV0_REG __REG(0x50000028) |
| | | |
| | | #define ULCON1_REG __REG(0x50004000) |
| | | #define UCON1_REG __REG(0x50004004) |
| | | #define UFCON1_REG __REG(0x50004008) |
| | | #define UMCON1_REG __REG(0x5000400C) |
| | | #define UTRSTAT1_REG __REG(0x50004010) |
| | | #define UERSTAT1_REG __REG(0x50004014) |
| | | #define UFSTAT1_REG __REG(0x50004018) |
| | | #define UMSTAT1_REG __REG(0x5000401C) |
| | | #define UTXH1_REG __REG(0x50004020) |
| | | #define URXH1_REG __REG(0x50004024) |
| | | #define UBRDIV1_REG __REG(0x50004028) |
| | | |
| | | #define ULCON2_REG __REG(0x50008000) |
| | | #define UCON2_REG __REG(0x50008004) |
| | | #define UFCON2_REG __REG(0x50008008) |
| | | #define UMCON2_REG __REG(0x5000800C) |
| | | #define UTRSTAT2_REG __REG(0x50008010) |
| | | #define UERSTAT2_REG __REG(0x50008014) |
| | | #define UFSTAT2_REG __REG(0x50008018) |
| | | #define UMSTAT2_REG __REG(0x5000801C) |
| | | #define UTXH2_REG __REG(0x50008020) |
| | | #define URXH2_REG __REG(0x50008024) |
| | | #define UBRDIV2_REG __REG(0x50008028) |
| | | |
| | | #define UTRSTAT_TX_EMPTY (1 << 2) |
| | | #define UTRSTAT_RX_READY (1 << 0) |
| | | #define UART_ERR_MASK 0xF |
| | | |
| | | /* |
| | | * PWM timer |
| | | */ |
| | | #define ELFIN_TIMER_BASE 0x51000000 |
| | | |
| | | #define TCFG0_REG __REG(0x51000000) |
| | | #define TCFG1_REG __REG(0x51000004) |
| | | #define TCON_REG __REG(0x51000008) |
| | | #define TCNTB0_REG __REG(0x5100000C) |
| | | #define TCMPB0_REG __REG(0x51000010) |
| | | #define TCNTO0_REG __REG(0x51000014) |
| | | #define TCNTB1_REG __REG(0x51000018) |
| | | #define TCMPB1_REG __REG(0x5100001C) |
| | | #define TCNTO1_REG __REG(0x51000020) |
| | | #define TCNTB2_REG __REG(0x51000024) |
| | | #define TCMPB2_REG __REG(0x51000028) |
| | | #define TCNTO2_REG __REG(0x5100002C) |
| | | #define TCNTB3_REG __REG(0x51000030) |
| | | #define TCMPB3_REG __REG(0x51000034) |
| | | #define TCNTO3_REG __REG(0x51000038) |
| | | #define TCNTB4_REG __REG(0x5100003C) |
| | | #define TCNTO4_REG __REG(0x51000040) |
| | | |
| | | /* Fields */ |
| | | #define fTCFG0_DZONE Fld(8,16) /* the dead zone length (= timer 0) */ |
| | | #define fTCFG0_PRE1 Fld(8,8) /* prescaler value for time 2,3,4 */ |
| | | #define fTCFG0_PRE0 Fld(8,0) /* prescaler value for time 0,1 */ |
| | | #define fTCFG1_MUX4 Fld(4,16) |
| | | /* bits */ |
| | | #define TCFG0_DZONE(x) FInsrt((x), fTCFG0_DZONE) |
| | | #define TCFG0_PRE1(x) FInsrt((x), fTCFG0_PRE1) |
| | | #define TCFG0_PRE0(x) FInsrt((x), fTCFG0_PRE0) |
| | | #define TCON_4_AUTO (1 << 22) /* auto reload on/off for Timer 4 */ |
| | | #define TCON_4_UPDATE (1 << 21) /* manual Update TCNTB4 */ |
| | | #define TCON_4_ONOFF (1 << 20) /* 0: Stop, 1: start Timer 4 */ |
| | | #define COUNT_4_ON (TCON_4_ONOFF*1) |
| | | #define COUNT_4_OFF (TCON_4_ONOFF*0) |
| | | #define TCON_3_AUTO (1 << 19) /* auto reload on/off for Timer 3 */ |
| | | #define TIMER3_ATLOAD_ON (TCON_3_AUTO*1) |
| | | #define TIMER3_ATLAOD_OFF FClrBit(TCON, TCON_3_AUTO) |
| | | #define TCON_3_INVERT (1 << 18) /* 1: Inverter on for TOUT3 */ |
| | | #define TIMER3_IVT_ON (TCON_3_INVERT*1) |
| | | #define TIMER3_IVT_OFF (FClrBit(TCON, TCON_3_INVERT)) |
| | | #define TCON_3_MAN (1 << 17) /* manual Update TCNTB3,TCMPB3 */ |
| | | #define TIMER3_MANUP (TCON_3_MAN*1) |
| | | #define TIMER3_NOP (FClrBit(TCON, TCON_3_MAN)) |
| | | #define TCON_3_ONOFF (1 << 16) /* 0: Stop, 1: start Timer 3 */ |
| | | #define TIMER3_ON (TCON_3_ONOFF*1) |
| | | #define TIMER3_OFF (FClrBit(TCON, TCON_3_ONOFF)) |
| | | /* macros */ |
| | | #define GET_PRESCALE_TIMER4(x) FExtr((x), fTCFG0_PRE1) |
| | | #define GET_DIVIDER_TIMER4(x) FExtr((x), fTCFG1_MUX4) |
| | | |
| | | /* |
| | | * RTC Controller |
| | | */ |
| | | #define ELFIN_RTC_BASE 0x57000000 |
| | | #define RTCCON_REG __REG(0x57000040) |
| | | #define TICNT_REG __REG(0x57000044) |
| | | #define RTCALM_REG __REG(0x57000050) |
| | | #define ALMSEC_REG __REG(0x57000054) |
| | | #define ALMMIN_REG __REG(0x57000058) |
| | | #define ALMHOUR_REG __REG(0x5700005c) |
| | | #define ALMDATE_REG __REG(0x57000060) |
| | | #define ALMMON_REG __REG(0x57000064) |
| | | #define ALMYEAR_REG __REG(0x57000068) |
| | | #define BCDSEC_REG __REG(0x57000070) |
| | | #define BCDMIN_REG __REG(0x57000074) |
| | | #define BCDHOUR_REG __REG(0x57000078) |
| | | #define BCDDATE_REG __REG(0x5700007c) |
| | | #define BCDDAY_REG __REG(0x57000080) |
| | | #define BCDMON_REG __REG(0x57000084) |
| | | #define BCDYEAR_REG __REG(0x57000088) |
| | | |
| | | /* USB Device */ |
| | | #define ELFIN_USBD_BASE 0x52000000 |
| | | #define USB_DEVICE_PHYS_ADR ELFIN_USBD_BASE |
| | | |
| | | /* include common stuff */ |
| | | #ifndef __ASSEMBLY__ |
| | | static inline S3C24X0_MEMCTL *S3C24X0_GetBase_MEMCTL(void) |
| | | { |
| | | return (S3C24X0_MEMCTL *) (ELFIN_MEM_CON_BASE); |
| | | } |
| | | static inline S3C24X0_USB_HOST *S3C24X0_GetBase_USB_HOST(void) |
| | | { |
| | | return (S3C24X0_USB_HOST *) ELFIN_USB_HOST_BASE; |
| | | } |
| | | static inline S3C24X0_INTERRUPT *S3C24X0_GetBase_INTERRUPT(void) |
| | | { |
| | | return (S3C24X0_INTERRUPT *) ELFIN_INTERRUPT_BASE; |
| | | } |
| | | static inline S3C24X0_DMAS *S3C24X0_GetBase_DMAS(void) |
| | | { |
| | | return (S3C24X0_DMAS *) ELFIN_DMA_BASE; |
| | | } |
| | | static inline S3C24X0_CLOCK_POWER *S3C24X0_GetBase_CLOCK_POWER(void) |
| | | { |
| | | return (S3C24X0_CLOCK_POWER *) ELFIN_CLOCK_POWER_BASE; |
| | | } |
| | | static inline S3C24X0_LCD *S3C24X0_GetBase_LCD(void) |
| | | { |
| | | return (S3C24X0_LCD *) ELFIN_LCD_BASE; |
| | | } |
| | | static inline S3C2410_NAND *S3C2410_GetBase_NAND(void) |
| | | { |
| | | return (S3C2410_NAND *) ELFIN_NAND_BASE; |
| | | } |
| | | static inline S3C24X0_UART *S3C24X0_GetBase_UART(S3C24X0_UARTS_NR nr) |
| | | { |
| | | return (S3C24X0_UART *) (ELFIN_UART_BASE + (nr * 0x4000)); |
| | | } |
| | | static inline S3C24X0_TIMERS *S3C24X0_GetBase_TIMERS(void) |
| | | { |
| | | return (S3C24X0_TIMERS *) ELFIN_TIMER_BASE; |
| | | } |
| | | static inline S3C24X0_USB_DEVICE *S3C24X0_GetBase_USB_DEVICE(void) |
| | | { |
| | | return (S3C24X0_USB_DEVICE *) ELFIN_USB_DEVICE_BASE; |
| | | } |
| | | static inline S3C24X0_WATCHDOG *S3C24X0_GetBase_WATCHDOG(void) |
| | | { |
| | | return (S3C24X0_WATCHDOG *) ELFIN_WATCHDOG_BASE; |
| | | } |
| | | static inline S3C24X0_I2C *S3C24X0_GetBase_I2C(void) |
| | | { |
| | | return (S3C24X0_I2C *) ELFIN_I2C_BASE; |
| | | } |
| | | static inline S3C24X0_I2S *S3C24X0_GetBase_I2S(void) |
| | | { |
| | | return (S3C24X0_I2S *) ELFIN_I2S_BASE; |
| | | } |
| | | static inline S3C24X0_GPIO *S3C24X0_GetBase_GPIO(void) |
| | | { |
| | | return (S3C24X0_GPIO *) ELFIN_GPIO_BASE; |
| | | } |
| | | static inline S3C24X0_RTC *S3C24X0_GetBase_RTC(void) |
| | | { |
| | | return (S3C24X0_RTC *) ELFIN_RTC_BASE; |
| | | } |
| | | static inline S3C2410_ADC *S3C2410_GetBase_ADC(void) |
| | | { |
| | | return (S3C2410_ADC *) ELFIN_ADC_BASE; |
| | | } |
| | | static inline S3C24X0_SPI *S3C24X0_GetBase_SPI(void) |
| | | { |
| | | return (S3C24X0_SPI *) ELFIN_SPI_BASE; |
| | | } |
| | | static inline S3C2410_SDI *S3C2410_GetBase_SDI(void) |
| | | { |
| | | return (S3C2410_SDI *) ELFIN_SDI_BASE; |
| | | } |
| | | #else /* #ifndef __ASSEMBLY__ */ |
| | | |
| | | /* watchdog */ |
| | | #define WTCON_OFFSET 0x00 |
| | | |
| | | /* LCD controller */ |
| | | #define LCDBGCON_OFFSET 0x5c |
| | | |
| | | #endif /* #ifndef __ASSEMBLY__ */ |
| | | |
| | | /* PENDING BIT */ |
| | | #define BIT_EINT0 (0x1) |
| | | #define BIT_EINT1 (0x1<<1) |
| | | #define BIT_EINT2 (0x1<<2) |
| | | #define BIT_EINT3 (0x1<<3) |
| | | #define BIT_EINT4_7 (0x1<<4) |
| | | #define BIT_EINT8_23 (0x1<<5) |
| | | #define BIT_BAT_FLT (0x1<<7) |
| | | #define BIT_TICK (0x1<<8) |
| | | #define BIT_WDT (0x1<<9) |
| | | #define BIT_TIMER0 (0x1<<10) |
| | | #define BIT_TIMER1 (0x1<<11) |
| | | #define BIT_TIMER2 (0x1<<12) |
| | | #define BIT_TIMER3 (0x1<<13) |
| | | #define BIT_TIMER4 (0x1<<14) |
| | | #define BIT_UART2 (0x1<<15) |
| | | #define BIT_LCD (0x1<<16) |
| | | #define BIT_DMA0 (0x1<<17) |
| | | #define BIT_DMA1 (0x1<<18) |
| | | #define BIT_DMA2 (0x1<<19) |
| | | #define BIT_DMA3 (0x1<<20) |
| | | #define BIT_SDI (0x1<<21) |
| | | #define BIT_SPI0 (0x1<<22) |
| | | #define BIT_UART1 (0x1<<23) |
| | | #define BIT_USBH (0x1<<26) |
| | | #define BIT_IIC (0x1<<27) |
| | | #define BIT_UART0 (0x1<<28) |
| | | #define BIT_SPI1 (0x1<<29) |
| | | #define BIT_RTC (0x1<<30) |
| | | #define BIT_ADC (0x1<<31) |
| | | #define BIT_ALLMSK (0xFFFFFFFF) |
| | | |
| | | #define CLKCON_USBD (1<< 15) |
| | | #define BIT19 0x00080000 |
| | | #define BIT29 0x20000000 |
| | | #define BIT_USBD BIT29 |
| | | #define BIT_USBD_SUB BIT19 |
| | | |
| | | #define ClearPending(bit) {\ |
| | | rSRCPND = bit;\ |
| | | rINTPND = bit;\ |
| | | rINTPND;\ |
| | | } |
| | | /* Wait until rINTPND is changed for the case that the ISR is very short. */ |
| | | |
| | | #endif /*__S3C2440_H__*/ |
New file |
| | |
| | | /* |
| | | * (C) Copyright 2003 |
| | | * David Müller ELSOFT AG Switzerland. d.mueller@elsoft.ch |
| | | * |
| | | * See file CREDITS for list of people who contributed to this |
| | | * project. |
| | | * |
| | | * This program is free software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU General Public License as |
| | | * published by the Free Software Foundation; either version 2 of |
| | | * the License, or (at your option) any later version. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License |
| | | * along with this program; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| | | * MA 02111-1307 USA |
| | | */ |
| | | |
| | | /************************************************ |
| | | * NAME : s3c24x0.h |
| | | * Version : 31.3.2003 |
| | | * |
| | | * common stuff for SAMSUNG S3C24X0 SoC |
| | | ************************************************/ |
| | | |
| | | #ifndef __S3C24X0_H__ |
| | | #define __S3C24X0_H__ |
| | | |
| | | #include <asm/types.h> |
| | | |
| | | typedef volatile u8 S3C24X0_REG8; |
| | | typedef volatile u16 S3C24X0_REG16; |
| | | typedef volatile u32 S3C24X0_REG32; |
| | | |
| | | /* Memory controller (see manual chapter 5) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 BWSCON; |
| | | S3C24X0_REG32 BANKCON[8]; |
| | | S3C24X0_REG32 REFRESH; |
| | | S3C24X0_REG32 BANKSIZE; |
| | | S3C24X0_REG32 MRSRB6; |
| | | S3C24X0_REG32 MRSRB7; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_MEMCTL; |
| | | |
| | | /* USB HOST (see manual chapter 12) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 HcRevision; |
| | | S3C24X0_REG32 HcControl; |
| | | S3C24X0_REG32 HcCommonStatus; |
| | | S3C24X0_REG32 HcInterruptStatus; |
| | | S3C24X0_REG32 HcInterruptEnable; |
| | | S3C24X0_REG32 HcInterruptDisable; |
| | | S3C24X0_REG32 HcHCCA; |
| | | S3C24X0_REG32 HcPeriodCuttendED; |
| | | S3C24X0_REG32 HcControlHeadED; |
| | | S3C24X0_REG32 HcControlCurrentED; |
| | | S3C24X0_REG32 HcBulkHeadED; |
| | | S3C24X0_REG32 HcBuldCurrentED; |
| | | S3C24X0_REG32 HcDoneHead; |
| | | S3C24X0_REG32 HcRmInterval; |
| | | S3C24X0_REG32 HcFmRemaining; |
| | | S3C24X0_REG32 HcFmNumber; |
| | | S3C24X0_REG32 HcPeriodicStart; |
| | | S3C24X0_REG32 HcLSThreshold; |
| | | S3C24X0_REG32 HcRhDescriptorA; |
| | | S3C24X0_REG32 HcRhDescriptorB; |
| | | S3C24X0_REG32 HcRhStatus; |
| | | S3C24X0_REG32 HcRhPortStatus1; |
| | | S3C24X0_REG32 HcRhPortStatus2; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_USB_HOST; |
| | | |
| | | /* INTERRUPT (see manual chapter 14) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 SRCPND; |
| | | S3C24X0_REG32 INTMOD; |
| | | S3C24X0_REG32 INTMSK; |
| | | S3C24X0_REG32 PRIORITY; |
| | | S3C24X0_REG32 INTPND; |
| | | S3C24X0_REG32 INTOFFSET; |
| | | #ifdef CONFIG_S3C2410 |
| | | S3C24X0_REG32 SUBSRCPND; |
| | | S3C24X0_REG32 INTSUBMSK; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_INTERRUPT; |
| | | |
| | | /* DMAS (see manual chapter 8) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 DISRC; |
| | | #ifdef CONFIG_S3C2410 |
| | | S3C24X0_REG32 DISRCC; |
| | | #endif |
| | | S3C24X0_REG32 DIDST; |
| | | #ifdef CONFIG_S3C2410 |
| | | S3C24X0_REG32 DIDSTC; |
| | | #endif |
| | | S3C24X0_REG32 DCON; |
| | | S3C24X0_REG32 DSTAT; |
| | | S3C24X0_REG32 DCSRC; |
| | | S3C24X0_REG32 DCDST; |
| | | S3C24X0_REG32 DMASKTRIG; |
| | | #ifdef CONFIG_S3C2400 |
| | | S3C24X0_REG32 res[1]; |
| | | #endif |
| | | #ifdef CONFIG_S3C2410 |
| | | S3C24X0_REG32 res[7]; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_DMA; |
| | | |
| | | typedef struct |
| | | { |
| | | S3C24X0_DMA dma[4]; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_DMAS; |
| | | |
| | | /* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */ |
| | | /* (see S3C2410 manual chapter 7) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 LOCKTIME; |
| | | S3C24X0_REG32 MPLLCON; |
| | | S3C24X0_REG32 UPLLCON; |
| | | S3C24X0_REG32 CLKCON; |
| | | S3C24X0_REG32 CLKSLOW; |
| | | S3C24X0_REG32 CLKDIVN; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER; |
| | | |
| | | /* LCD CONTROLLER (see manual chapter 15) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 LCDCON1; |
| | | S3C24X0_REG32 LCDCON2; |
| | | S3C24X0_REG32 LCDCON3; |
| | | S3C24X0_REG32 LCDCON4; |
| | | S3C24X0_REG32 LCDCON5; |
| | | S3C24X0_REG32 LCDSADDR1; |
| | | S3C24X0_REG32 LCDSADDR2; |
| | | S3C24X0_REG32 LCDSADDR3; |
| | | S3C24X0_REG32 REDLUT; |
| | | S3C24X0_REG32 GREENLUT; |
| | | S3C24X0_REG32 BLUELUT; |
| | | S3C24X0_REG32 res[8]; |
| | | S3C24X0_REG32 DITHMODE; |
| | | S3C24X0_REG32 TPAL; |
| | | #ifdef CONFIG_S3C2410 |
| | | S3C24X0_REG32 LCDINTPND; |
| | | S3C24X0_REG32 LCDSRCPND; |
| | | S3C24X0_REG32 LCDINTMSK; |
| | | S3C24X0_REG32 LPCSEL; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_LCD; |
| | | |
| | | /* NAND FLASH (see S3C2410 manual chapter 6) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 NFCONF; |
| | | S3C24X0_REG32 NFCMD; |
| | | S3C24X0_REG32 NFADDR; |
| | | S3C24X0_REG32 NFDATA; |
| | | S3C24X0_REG32 NFSTAT; |
| | | S3C24X0_REG32 NFECC; |
| | | } /*__attribute__((__packed__))*/ S3C2410_NAND; |
| | | |
| | | /* UART (see manual chapter 11) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 ULCON; |
| | | S3C24X0_REG32 UCON; |
| | | S3C24X0_REG32 UFCON; |
| | | S3C24X0_REG32 UMCON; |
| | | S3C24X0_REG32 UTRSTAT; |
| | | S3C24X0_REG32 UERSTAT; |
| | | S3C24X0_REG32 UFSTAT; |
| | | S3C24X0_REG32 UMSTAT; |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 UTXH; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 URXH; |
| | | #else /* Little Endian */ |
| | | S3C24X0_REG8 UTXH; |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 URXH; |
| | | S3C24X0_REG8 res2[3]; |
| | | #endif |
| | | S3C24X0_REG32 UBRDIV; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_UART; |
| | | |
| | | /* PWM TIMER (see manual chapter 10) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 TCNTB; |
| | | S3C24X0_REG32 TCMPB; |
| | | S3C24X0_REG32 TCNTO; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_TIMER; |
| | | |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 TCFG0; |
| | | S3C24X0_REG32 TCFG1; |
| | | S3C24X0_REG32 TCON; |
| | | S3C24X0_TIMER ch[4]; |
| | | S3C24X0_REG32 TCNTB4; |
| | | S3C24X0_REG32 TCNTO4; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_TIMERS; |
| | | |
| | | /* USB DEVICE (see manual chapter 13) */ |
| | | typedef struct |
| | | { |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res[3]; |
| | | S3C24X0_REG8 EP_FIFO_REG; |
| | | #else /* little endian */ |
| | | S3C24X0_REG8 EP_FIFO_REG; |
| | | S3C24X0_REG8 res[3]; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_USB_DEV_FIFOS; |
| | | |
| | | typedef struct |
| | | { |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 EP_DMA_CON; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 EP_DMA_UNIT; |
| | | S3C24X0_REG8 res3[3]; |
| | | S3C24X0_REG8 EP_DMA_FIFO; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG8 EP_DMA_TTC_L; |
| | | S3C24X0_REG8 res5[3]; |
| | | S3C24X0_REG8 EP_DMA_TTC_M; |
| | | S3C24X0_REG8 res6[3]; |
| | | S3C24X0_REG8 EP_DMA_TTC_H; |
| | | #else /* little endian */ |
| | | S3C24X0_REG8 EP_DMA_CON; |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 EP_DMA_UNIT; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 EP_DMA_FIFO; |
| | | S3C24X0_REG8 res3[3]; |
| | | S3C24X0_REG8 EP_DMA_TTC_L; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG8 EP_DMA_TTC_M; |
| | | S3C24X0_REG8 res5[3]; |
| | | S3C24X0_REG8 EP_DMA_TTC_H; |
| | | S3C24X0_REG8 res6[3]; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_USB_DEV_DMAS; |
| | | |
| | | typedef struct |
| | | { |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 FUNC_ADDR_REG; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 PWR_REG; |
| | | S3C24X0_REG8 res3[3]; |
| | | S3C24X0_REG8 EP_INT_REG; |
| | | S3C24X0_REG8 res4[15]; |
| | | S3C24X0_REG8 USB_INT_REG; |
| | | S3C24X0_REG8 res5[3]; |
| | | S3C24X0_REG8 EP_INT_EN_REG; |
| | | S3C24X0_REG8 res6[15]; |
| | | S3C24X0_REG8 USB_INT_EN_REG; |
| | | S3C24X0_REG8 res7[3]; |
| | | S3C24X0_REG8 FRAME_NUM1_REG; |
| | | S3C24X0_REG8 res8[3]; |
| | | S3C24X0_REG8 FRAME_NUM2_REG; |
| | | S3C24X0_REG8 res9[3]; |
| | | S3C24X0_REG8 INDEX_REG; |
| | | S3C24X0_REG8 res10[7]; |
| | | S3C24X0_REG8 MAXP_REG; |
| | | S3C24X0_REG8 res11[3]; |
| | | S3C24X0_REG8 EP0_CSR_IN_CSR1_REG; |
| | | S3C24X0_REG8 res12[3]; |
| | | S3C24X0_REG8 IN_CSR2_REG; |
| | | S3C24X0_REG8 res13[7]; |
| | | S3C24X0_REG8 OUT_CSR1_REG; |
| | | S3C24X0_REG8 res14[3]; |
| | | S3C24X0_REG8 OUT_CSR2_REG; |
| | | S3C24X0_REG8 res15[3]; |
| | | S3C24X0_REG8 OUT_FIFO_CNT1_REG; |
| | | S3C24X0_REG8 res16[3]; |
| | | S3C24X0_REG8 OUT_FIFO_CNT2_REG; |
| | | #else /* little endian */ |
| | | S3C24X0_REG8 FUNC_ADDR_REG; |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 PWR_REG; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 EP_INT_REG; |
| | | S3C24X0_REG8 res3[15]; |
| | | S3C24X0_REG8 USB_INT_REG; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG8 EP_INT_EN_REG; |
| | | S3C24X0_REG8 res5[15]; |
| | | S3C24X0_REG8 USB_INT_EN_REG; |
| | | S3C24X0_REG8 res6[3]; |
| | | S3C24X0_REG8 FRAME_NUM1_REG; |
| | | S3C24X0_REG8 res7[3]; |
| | | S3C24X0_REG8 FRAME_NUM2_REG; |
| | | S3C24X0_REG8 res8[3]; |
| | | S3C24X0_REG8 INDEX_REG; |
| | | S3C24X0_REG8 res9[7]; |
| | | S3C24X0_REG8 MAXP_REG; |
| | | S3C24X0_REG8 res10[7]; |
| | | S3C24X0_REG8 EP0_CSR_IN_CSR1_REG; |
| | | S3C24X0_REG8 res11[3]; |
| | | S3C24X0_REG8 IN_CSR2_REG; |
| | | S3C24X0_REG8 res12[3]; |
| | | S3C24X0_REG8 OUT_CSR1_REG; |
| | | S3C24X0_REG8 res13[7]; |
| | | S3C24X0_REG8 OUT_CSR2_REG; |
| | | S3C24X0_REG8 res14[3]; |
| | | S3C24X0_REG8 OUT_FIFO_CNT1_REG; |
| | | S3C24X0_REG8 res15[3]; |
| | | S3C24X0_REG8 OUT_FIFO_CNT2_REG; |
| | | S3C24X0_REG8 res16[3]; |
| | | #endif /* __BIG_ENDIAN */ |
| | | S3C24X0_USB_DEV_FIFOS fifo[5]; |
| | | S3C24X0_USB_DEV_DMAS dma[5]; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_USB_DEVICE; |
| | | |
| | | /* WATCH DOG TIMER (see manual chapter 18) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 WTCON; |
| | | S3C24X0_REG32 WTDAT; |
| | | S3C24X0_REG32 WTCNT; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_WATCHDOG; |
| | | |
| | | /* IIC (see manual chapter 20) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 IICCON; |
| | | S3C24X0_REG32 IICSTAT; |
| | | S3C24X0_REG32 IICADD; |
| | | S3C24X0_REG32 IICDS; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_I2C; |
| | | |
| | | /* IIS (see manual chapter 21) */ |
| | | typedef struct |
| | | { |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG16 res1; |
| | | S3C24X0_REG16 IISCON; |
| | | S3C24X0_REG16 res2; |
| | | S3C24X0_REG16 IISMOD; |
| | | S3C24X0_REG16 res3; |
| | | S3C24X0_REG16 IISPSR; |
| | | S3C24X0_REG16 res4; |
| | | S3C24X0_REG16 IISFCON; |
| | | S3C24X0_REG16 res5; |
| | | S3C24X0_REG16 IISFIFO; |
| | | #else /* little endian */ |
| | | S3C24X0_REG16 IISCON; |
| | | S3C24X0_REG16 res1; |
| | | S3C24X0_REG16 IISMOD; |
| | | S3C24X0_REG16 res2; |
| | | S3C24X0_REG16 IISPSR; |
| | | S3C24X0_REG16 res3; |
| | | S3C24X0_REG16 IISFCON; |
| | | S3C24X0_REG16 res4; |
| | | S3C24X0_REG16 IISFIFO; |
| | | S3C24X0_REG16 res5; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_I2S; |
| | | |
| | | /* I/O PORT (see manual chapter 9) */ |
| | | typedef struct |
| | | { |
| | | #ifdef CONFIG_S3C2400 |
| | | S3C24X0_REG32 PACON; |
| | | S3C24X0_REG32 PADAT; |
| | | |
| | | S3C24X0_REG32 PBCON; |
| | | S3C24X0_REG32 PBDAT; |
| | | S3C24X0_REG32 PBUP; |
| | | |
| | | S3C24X0_REG32 PCCON; |
| | | S3C24X0_REG32 PCDAT; |
| | | S3C24X0_REG32 PCUP; |
| | | |
| | | S3C24X0_REG32 PDCON; |
| | | S3C24X0_REG32 PDDAT; |
| | | S3C24X0_REG32 PDUP; |
| | | |
| | | S3C24X0_REG32 PECON; |
| | | S3C24X0_REG32 PEDAT; |
| | | S3C24X0_REG32 PEUP; |
| | | |
| | | S3C24X0_REG32 PFCON; |
| | | S3C24X0_REG32 PFDAT; |
| | | S3C24X0_REG32 PFUP; |
| | | |
| | | S3C24X0_REG32 PGCON; |
| | | S3C24X0_REG32 PGDAT; |
| | | S3C24X0_REG32 PGUP; |
| | | |
| | | S3C24X0_REG32 OPENCR; |
| | | |
| | | S3C24X0_REG32 MISCCR; |
| | | S3C24X0_REG32 EXTINT; |
| | | #endif |
| | | #ifdef CONFIG_S3C2410 |
| | | S3C24X0_REG32 GPACON; |
| | | S3C24X0_REG32 GPADAT; |
| | | S3C24X0_REG32 res1[2]; |
| | | S3C24X0_REG32 GPBCON; |
| | | S3C24X0_REG32 GPBDAT; |
| | | S3C24X0_REG32 GPBUP; |
| | | S3C24X0_REG32 res2; |
| | | S3C24X0_REG32 GPCCON; |
| | | S3C24X0_REG32 GPCDAT; |
| | | S3C24X0_REG32 GPCUP; |
| | | S3C24X0_REG32 res3; |
| | | S3C24X0_REG32 GPDCON; |
| | | S3C24X0_REG32 GPDDAT; |
| | | S3C24X0_REG32 GPDUP; |
| | | S3C24X0_REG32 res4; |
| | | S3C24X0_REG32 GPECON; |
| | | S3C24X0_REG32 GPEDAT; |
| | | S3C24X0_REG32 GPEUP; |
| | | S3C24X0_REG32 res5; |
| | | S3C24X0_REG32 GPFCON; |
| | | S3C24X0_REG32 GPFDAT; |
| | | S3C24X0_REG32 GPFUP; |
| | | S3C24X0_REG32 res6; |
| | | S3C24X0_REG32 GPGCON; |
| | | S3C24X0_REG32 GPGDAT; |
| | | S3C24X0_REG32 GPGUP; |
| | | S3C24X0_REG32 res7; |
| | | S3C24X0_REG32 GPHCON; |
| | | S3C24X0_REG32 GPHDAT; |
| | | S3C24X0_REG32 GPHUP; |
| | | S3C24X0_REG32 res8; |
| | | |
| | | S3C24X0_REG32 MISCCR; |
| | | S3C24X0_REG32 DCLKCON; |
| | | S3C24X0_REG32 EXTINT0; |
| | | S3C24X0_REG32 EXTINT1; |
| | | S3C24X0_REG32 EXTINT2; |
| | | S3C24X0_REG32 EINTFLT0; |
| | | S3C24X0_REG32 EINTFLT1; |
| | | S3C24X0_REG32 EINTFLT2; |
| | | S3C24X0_REG32 EINTFLT3; |
| | | S3C24X0_REG32 EINTMASK; |
| | | S3C24X0_REG32 EINTPEND; |
| | | S3C24X0_REG32 GSTATUS0; |
| | | S3C24X0_REG32 GSTATUS1; |
| | | S3C24X0_REG32 GSTATUS2; |
| | | S3C24X0_REG32 GSTATUS3; |
| | | S3C24X0_REG32 GSTATUS4; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_GPIO; |
| | | |
| | | /* RTC (see manual chapter 17) */ |
| | | typedef struct |
| | | { |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res1[67]; |
| | | S3C24X0_REG8 RTCCON; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 TICNT; |
| | | S3C24X0_REG8 res3[11]; |
| | | S3C24X0_REG8 RTCALM; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG8 ALMSEC; |
| | | S3C24X0_REG8 res5[3]; |
| | | S3C24X0_REG8 ALMMIN; |
| | | S3C24X0_REG8 res6[3]; |
| | | S3C24X0_REG8 ALMHOUR; |
| | | S3C24X0_REG8 res7[3]; |
| | | S3C24X0_REG8 ALMDATE; |
| | | S3C24X0_REG8 res8[3]; |
| | | S3C24X0_REG8 ALMMON; |
| | | S3C24X0_REG8 res9[3]; |
| | | S3C24X0_REG8 ALMYEAR; |
| | | S3C24X0_REG8 res10[3]; |
| | | S3C24X0_REG8 RTCRST; |
| | | S3C24X0_REG8 res11[3]; |
| | | S3C24X0_REG8 BCDSEC; |
| | | S3C24X0_REG8 res12[3]; |
| | | S3C24X0_REG8 BCDMIN; |
| | | S3C24X0_REG8 res13[3]; |
| | | S3C24X0_REG8 BCDHOUR; |
| | | S3C24X0_REG8 res14[3]; |
| | | S3C24X0_REG8 BCDDATE; |
| | | S3C24X0_REG8 res15[3]; |
| | | S3C24X0_REG8 BCDDAY; |
| | | S3C24X0_REG8 res16[3]; |
| | | S3C24X0_REG8 BCDMON; |
| | | S3C24X0_REG8 res17[3]; |
| | | S3C24X0_REG8 BCDYEAR; |
| | | #else /* little endian */ |
| | | S3C24X0_REG8 res0[64]; |
| | | S3C24X0_REG8 RTCCON; |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 TICNT; |
| | | S3C24X0_REG8 res2[11]; |
| | | S3C24X0_REG8 RTCALM; |
| | | S3C24X0_REG8 res3[3]; |
| | | S3C24X0_REG8 ALMSEC; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG8 ALMMIN; |
| | | S3C24X0_REG8 res5[3]; |
| | | S3C24X0_REG8 ALMHOUR; |
| | | S3C24X0_REG8 res6[3]; |
| | | S3C24X0_REG8 ALMDATE; |
| | | S3C24X0_REG8 res7[3]; |
| | | S3C24X0_REG8 ALMMON; |
| | | S3C24X0_REG8 res8[3]; |
| | | S3C24X0_REG8 ALMYEAR; |
| | | S3C24X0_REG8 res9[3]; |
| | | S3C24X0_REG8 RTCRST; |
| | | S3C24X0_REG8 res10[3]; |
| | | S3C24X0_REG8 BCDSEC; |
| | | S3C24X0_REG8 res11[3]; |
| | | S3C24X0_REG8 BCDMIN; |
| | | S3C24X0_REG8 res12[3]; |
| | | S3C24X0_REG8 BCDHOUR; |
| | | S3C24X0_REG8 res13[3]; |
| | | S3C24X0_REG8 BCDDATE; |
| | | S3C24X0_REG8 res14[3]; |
| | | S3C24X0_REG8 BCDDAY; |
| | | S3C24X0_REG8 res15[3]; |
| | | S3C24X0_REG8 BCDMON; |
| | | S3C24X0_REG8 res16[3]; |
| | | S3C24X0_REG8 BCDYEAR; |
| | | S3C24X0_REG8 res17[3]; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C24X0_RTC; |
| | | |
| | | /* ADC (see manual chapter 16) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 ADCCON; |
| | | S3C24X0_REG32 ADCDAT; |
| | | } /*__attribute__((__packed__))*/ S3C2400_ADC; |
| | | |
| | | /* ADC (see manual chapter 16) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 ADCCON; |
| | | S3C24X0_REG32 ADCTSC; |
| | | S3C24X0_REG32 ADCDLY; |
| | | S3C24X0_REG32 ADCDAT0; |
| | | S3C24X0_REG32 ADCDAT1; |
| | | } /*__attribute__((__packed__))*/ S3C2410_ADC; |
| | | |
| | | /* SPI (see manual chapter 22) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 SPCON; |
| | | S3C24X0_REG32 SPSTA; |
| | | S3C24X0_REG32 SPPIN; |
| | | S3C24X0_REG32 SPPRE; |
| | | S3C24X0_REG32 SPTDAT; |
| | | S3C24X0_REG32 SPRDAT; |
| | | S3C24X0_REG32 res[2]; |
| | | } __attribute__ ((__packed__)) S3C24X0_SPI_CHANNEL; |
| | | |
| | | typedef struct |
| | | { |
| | | S3C24X0_SPI_CHANNEL ch[S3C24X0_SPI_CHANNELS]; |
| | | } /*__attribute__((__packed__))*/ S3C24X0_SPI; |
| | | |
| | | /* MMC INTERFACE (see S3C2400 manual chapter 19) */ |
| | | typedef struct |
| | | { |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 MMCON; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 MMCRR; |
| | | S3C24X0_REG8 res3[3]; |
| | | S3C24X0_REG8 MMFCON; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG8 MMSTA; |
| | | S3C24X0_REG16 res5; |
| | | S3C24X0_REG16 MMFSTA; |
| | | S3C24X0_REG8 res6[3]; |
| | | S3C24X0_REG8 MMPRE; |
| | | S3C24X0_REG16 res7; |
| | | S3C24X0_REG16 MMLEN; |
| | | S3C24X0_REG8 res8[3]; |
| | | S3C24X0_REG8 MMCR7; |
| | | S3C24X0_REG32 MMRSP[4]; |
| | | S3C24X0_REG8 res9[3]; |
| | | S3C24X0_REG8 MMCMD0; |
| | | S3C24X0_REG32 MMCMD1; |
| | | S3C24X0_REG16 res10; |
| | | S3C24X0_REG16 MMCR16; |
| | | S3C24X0_REG8 res11[3]; |
| | | S3C24X0_REG8 MMDAT; |
| | | #else |
| | | S3C24X0_REG8 MMCON; |
| | | S3C24X0_REG8 res1[3]; |
| | | S3C24X0_REG8 MMCRR; |
| | | S3C24X0_REG8 res2[3]; |
| | | S3C24X0_REG8 MMFCON; |
| | | S3C24X0_REG8 res3[3]; |
| | | S3C24X0_REG8 MMSTA; |
| | | S3C24X0_REG8 res4[3]; |
| | | S3C24X0_REG16 MMFSTA; |
| | | S3C24X0_REG16 res5; |
| | | S3C24X0_REG8 MMPRE; |
| | | S3C24X0_REG8 res6[3]; |
| | | S3C24X0_REG16 MMLEN; |
| | | S3C24X0_REG16 res7; |
| | | S3C24X0_REG8 MMCR7; |
| | | S3C24X0_REG8 res8[3]; |
| | | S3C24X0_REG32 MMRSP[4]; |
| | | S3C24X0_REG8 MMCMD0; |
| | | S3C24X0_REG8 res9[3]; |
| | | S3C24X0_REG32 MMCMD1; |
| | | S3C24X0_REG16 MMCR16; |
| | | S3C24X0_REG16 res10; |
| | | S3C24X0_REG8 MMDAT; |
| | | S3C24X0_REG8 res11[3]; |
| | | #endif |
| | | } /*__attribute__((__packed__))*/ S3C2400_MMC; |
| | | |
| | | /* SD INTERFACE (see S3C2410 manual chapter 19) */ |
| | | typedef struct |
| | | { |
| | | S3C24X0_REG32 SDICON; |
| | | S3C24X0_REG32 SDIPRE; |
| | | S3C24X0_REG32 SDICARG; |
| | | S3C24X0_REG32 SDICCON; |
| | | S3C24X0_REG32 SDICSTA; |
| | | S3C24X0_REG32 SDIRSP0; |
| | | S3C24X0_REG32 SDIRSP1; |
| | | S3C24X0_REG32 SDIRSP2; |
| | | S3C24X0_REG32 SDIRSP3; |
| | | S3C24X0_REG32 SDIDTIMER; |
| | | S3C24X0_REG32 SDIBSIZE; |
| | | S3C24X0_REG32 SDIDCON; |
| | | S3C24X0_REG32 SDIDCNT; |
| | | S3C24X0_REG32 SDIDSTA; |
| | | S3C24X0_REG32 SDIFSTA; |
| | | #ifdef __BIG_ENDIAN |
| | | S3C24X0_REG8 res[3]; |
| | | S3C24X0_REG8 SDIDAT; |
| | | #else |
| | | S3C24X0_REG8 SDIDAT; |
| | | S3C24X0_REG8 res[3]; |
| | | #endif |
| | | S3C24X0_REG32 SDIIMSK; |
| | | } /*__attribute__((__packed__))*/ S3C2410_SDI; |
| | | |
| | | #if 0 |
| | | /* Memory control */ |
| | | #define rBWSCON (*(volatile unsigned *)0x48000000) |
| | | #define rBANKCON0 (*(volatile unsigned *)0x48000004) |
| | | #define rBANKCON1 (*(volatile unsigned *)0x48000008) |
| | | #define rBANKCON2 (*(volatile unsigned *)0x4800000C) |
| | | #define rBANKCON3 (*(volatile unsigned *)0x48000010) |
| | | #define rBANKCON4 (*(volatile unsigned *)0x48000014) |
| | | #define rBANKCON5 (*(volatile unsigned *)0x48000018) |
| | | #define rBANKCON6 (*(volatile unsigned *)0x4800001C) |
| | | #define rBANKCON7 (*(volatile unsigned *)0x48000020) |
| | | #define rREFRESH (*(volatile unsigned *)0x48000024) |
| | | #define rBANKSIZE (*(volatile unsigned *)0x48000028) |
| | | #define rMRSRB6 (*(volatile unsigned *)0x4800002C) |
| | | #define rMRSRB7 (*(volatile unsigned *)0x48000030) |
| | | |
| | | /* USB HOST */ |
| | | #define rHcRevision (*(volatile unsigned *)0x49000000) |
| | | #define rHcControl (*(volatile unsigned *)0x49000004) |
| | | #define rHcCommonStatus (*(volatile unsigned *)0x49000008) |
| | | #define rHcInterruptStatus (*(volatile unsigned *)0x4900000C) |
| | | #define rHcInterruptEnable (*(volatile unsigned *)0x49000010) |
| | | #define rHcInterruptDisable (*(volatile unsigned *)0x49000014) |
| | | #define rHcHCCA (*(volatile unsigned *)0x49000018) |
| | | #define rHcPeriodCuttendED (*(volatile unsigned *)0x4900001C) |
| | | #define rHcControlHeadED (*(volatile unsigned *)0x49000020) |
| | | #define rHcControlCurrentED (*(volatile unsigned *)0x49000024) |
| | | #define rHcBulkHeadED (*(volatile unsigned *)0x49000028) |
| | | #define rHcBuldCurrentED (*(volatile unsigned *)0x4900002C) |
| | | #define rHcDoneHead (*(volatile unsigned *)0x49000030) |
| | | #define rHcRmInterval (*(volatile unsigned *)0x49000034) |
| | | #define rHcFmRemaining (*(volatile unsigned *)0x49000038) |
| | | #define rHcFmNumber (*(volatile unsigned *)0x4900003C) |
| | | #define rHcPeriodicStart (*(volatile unsigned *)0x49000040) |
| | | #define rHcLSThreshold (*(volatile unsigned *)0x49000044) |
| | | #define rHcRhDescriptorA (*(volatile unsigned *)0x49000048) |
| | | #define rHcRhDescriptorB (*(volatile unsigned *)0x4900004C) |
| | | #define rHcRhStatus (*(volatile unsigned *)0x49000050) |
| | | #define rHcRhPortStatus1 (*(volatile unsigned *)0x49000054) |
| | | #define rHcRhPortStatus2 (*(volatile unsigned *)0x49000058) |
| | | |
| | | /* INTERRUPT */ |
| | | #define rSRCPND (*(volatile unsigned *)0x4A000000) |
| | | #define rINTMOD (*(volatile unsigned *)0x4A000004) |
| | | #define rINTMSK (*(volatile unsigned *)0x4A000008) |
| | | #define rPRIORITY (*(volatile unsigned *)0x4A00000C) |
| | | #define rINTPND (*(volatile unsigned *)0x4A000010) |
| | | #define rINTOFFSET (*(volatile unsigned *)0x4A000014) |
| | | #define rSUBSRCPND (*(volatile unsigned *)0x4A000018) |
| | | #define rINTSUBMSK (*(volatile unsigned *)0x4A00001C) |
| | | |
| | | /* DMA */ |
| | | #define rDISRC0 (*(volatile unsigned *)0x4B000000) |
| | | #define rDISRCC0 (*(volatile unsigned *)0x4B000004) |
| | | #define rDIDST0 (*(volatile unsigned *)0x4B000008) |
| | | #define rDIDSTC0 (*(volatile unsigned *)0x4B00000C) |
| | | #define rDCON0 (*(volatile unsigned *)0x4B000010) |
| | | #define rDSTAT0 (*(volatile unsigned *)0x4B000014) |
| | | #define rDCSRC0 (*(volatile unsigned *)0x4B000018) |
| | | #define rDCDST0 (*(volatile unsigned *)0x4B00001C) |
| | | #define rDMASKTRIG0 (*(volatile unsigned *)0x4B000020) |
| | | #define rDISRC1 (*(volatile unsigned *)0x4B000040) |
| | | #define rDISRCC1 (*(volatile unsigned *)0x4B000044) |
| | | #define rDIDST1 (*(volatile unsigned *)0x4B000048) |
| | | #define rDIDSTC1 (*(volatile unsigned *)0x4B00004C) |
| | | #define rDCON1 (*(volatile unsigned *)0x4B000050) |
| | | #define rDSTAT1 (*(volatile unsigned *)0x4B000054) |
| | | #define rDCSRC1 (*(volatile unsigned *)0x4B000058) |
| | | #define rDCDST1 (*(volatile unsigned *)0x4B00005C) |
| | | #define rDMASKTRIG1 (*(volatile unsigned *)0x4B000060) |
| | | #define rDISRC2 (*(volatile unsigned *)0x4B000080) |
| | | #define rDISRCC2 (*(volatile unsigned *)0x4B000084) |
| | | #define rDIDST2 (*(volatile unsigned *)0x4B000088) |
| | | #define rDIDSTC2 (*(volatile unsigned *)0x4B00008C) |
| | | #define rDCON2 (*(volatile unsigned *)0x4B000090) |
| | | #define rDSTAT2 (*(volatile unsigned *)0x4B000094) |
| | | #define rDCSRC2 (*(volatile unsigned *)0x4B000098) |
| | | #define rDCDST2 (*(volatile unsigned *)0x4B00009C) |
| | | #define rDMASKTRIG2 (*(volatile unsigned *)0x4B0000A0) |
| | | #define rDISRC3 (*(volatile unsigned *)0x4B0000C0) |
| | | #define rDISRCC3 (*(volatile unsigned *)0x4B0000C4) |
| | | #define rDIDST3 (*(volatile unsigned *)0x4B0000C8) |
| | | #define rDIDSTC3 (*(volatile unsigned *)0x4B0000CC) |
| | | #define rDCON3 (*(volatile unsigned *)0x4B0000D0) |
| | | #define rDSTAT3 (*(volatile unsigned *)0x4B0000D4) |
| | | #define rDCSRC3 (*(volatile unsigned *)0x4B0000D8) |
| | | #define rDCDST3 (*(volatile unsigned *)0x4B0000DC) |
| | | #define rDMASKTRIG3 (*(volatile unsigned *)0x4B0000E0) |
| | | |
| | | /* CLOCK & POWER MANAGEMENT */ |
| | | #define rLOCKTIME (*(volatile unsigned *)0x4C000000) |
| | | #define rMPLLCON (*(volatile unsigned *)0x4C000004) |
| | | #define rUPLLCON (*(volatile unsigned *)0x4C000008) |
| | | #define rCLKCON (*(volatile unsigned *)0x4C00000C) |
| | | #define rCLKSLOW (*(volatile unsigned *)0x4C000010) |
| | | #define rCLKDIVN (*(volatile unsigned *)0x4C000014) |
| | | |
| | | /* LCD CONTROLLER */ |
| | | #define rLCDCON1 (*(volatile unsigned *)0x4D000000) |
| | | #define rLCDCON2 (*(volatile unsigned *)0x4D000004) |
| | | #define rLCDCON3 (*(volatile unsigned *)0x4D000008) |
| | | #define rLCDCON4 (*(volatile unsigned *)0x4D00000C) |
| | | #define rLCDCON5 (*(volatile unsigned *)0x4D000010) |
| | | #define rLCDSADDR1 (*(volatile unsigned *)0x4D000014) |
| | | #define rLCDSADDR2 (*(volatile unsigned *)0x4D000018) |
| | | #define rLCDSADDR3 (*(volatile unsigned *)0x4D00001C) |
| | | #define rREDLUT (*(volatile unsigned *)0x4D000020) |
| | | #define rGREENLUT (*(volatile unsigned *)0x4D000024) |
| | | #define rBLUELUT (*(volatile unsigned *)0x4D000028) |
| | | #define rDITHMODE (*(volatile unsigned *)0x4D00004C) |
| | | #define rTPAL (*(volatile unsigned *)0x4D000050) |
| | | #define rLCDINTPND (*(volatile unsigned *)0x4D000054) |
| | | #define rLCDSRCPND (*(volatile unsigned *)0x4D000058) |
| | | #define rLCDINTMSK (*(volatile unsigned *)0x4D00005C) |
| | | |
| | | /* NAND FLASH */ |
| | | #define rNFCONF (*(volatile unsigned *)0x4E000000) |
| | | #define rNFCMD (*(volatile unsigned *)0x4E000004) |
| | | #define rNFADDR (*(volatile unsigned *)0x4E000008) |
| | | #define rNFDATA (*(volatile unsigned *)0x4E00000C) |
| | | #define rNFSTAT (*(volatile unsigned *)0x4E000010) |
| | | #define rNFECC (*(volatile unsigned *)0x4E000014) |
| | | |
| | | /* UART */ |
| | | #define rULCON0 (*(volatile unsigned *)0x50000000) |
| | | #define rUCON0 (*(volatile unsigned *)0x50000004) |
| | | #define rUFCON0 (*(volatile unsigned *)0x50000008) |
| | | #define rUMCON0 (*(volatile unsigned *)0x5000000C) |
| | | #define rUTRSTAT0 (*(volatile unsigned *)0x50000010) |
| | | #define rUERSTAT0 (*(volatile unsigned *)0x50000014) |
| | | #define rUFSTAT0 (*(volatile unsigned *)0x50000018) |
| | | #define rUMSTAT0 (*(volatile unsigned *)0x5000001C) |
| | | #define rUBRDIV0 (*(volatile unsigned *)0x50000028) |
| | | |
| | | #define rULCON1 (*(volatile unsigned *)0x50004000) |
| | | #define rUCON1 (*(volatile unsigned *)0x50004004) |
| | | #define rUFCON1 (*(volatile unsigned *)0x50004008) |
| | | #define rUMCON1 (*(volatile unsigned *)0x5000400C) |
| | | #define rUTRSTAT1 (*(volatile unsigned *)0x50004010) |
| | | #define rUERSTAT1 (*(volatile unsigned *)0x50004014) |
| | | #define rUFSTAT1 (*(volatile unsigned *)0x50004018) |
| | | #define rUMSTAT1 (*(volatile unsigned *)0x5000401C) |
| | | #define rUBRDIV1 (*(volatile unsigned *)0x50004028) |
| | | |
| | | #define rULCON2 (*(volatile unsigned *)0x50008000) |
| | | #define rUCON2 (*(volatile unsigned *)0x50008004) |
| | | #define rUFCON2 (*(volatile unsigned *)0x50008008) |
| | | #define rUTRSTAT2 (*(volatile unsigned *)0x50008010) |
| | | #define rUERSTAT2 (*(volatile unsigned *)0x50008014) |
| | | #define rUFSTAT2 (*(volatile unsigned *)0x50008018) |
| | | #define rUBRDIV2 (*(volatile unsigned *)0x50008028) |
| | | |
| | | #ifdef __BIG_ENDIAN |
| | | #define rUTXH0 (*(volatile unsigned char *)0x50000023) |
| | | #define rURXH0 (*(volatile unsigned char *)0x50000027) |
| | | #define rUTXH1 (*(volatile unsigned char *)0x50004023) |
| | | #define rURXH1 (*(volatile unsigned char *)0x50004027) |
| | | #define rUTXH2 (*(volatile unsigned char *)0x50008023) |
| | | #define rURXH2 (*(volatile unsigned char *)0x50008027) |
| | | |
| | | #define WrUTXH0(ch) (*(volatile unsigned char *)0x50000023)=(unsigned char)(ch) |
| | | #define RdURXH0() (*(volatile unsigned char *)0x50000027) |
| | | #define WrUTXH1(ch) (*(volatile unsigned char *)0x50004023)=(unsigned char)(ch) |
| | | #define RdURXH1() (*(volatile unsigned char *)0x50004027) |
| | | #define WrUTXH2(ch) (*(volatile unsigned char *)0x50008023)=(unsigned char)(ch) |
| | | #define RdURXH2() (*(volatile unsigned char *)0x50008027) |
| | | |
| | | #define UTXH0 (0x50000020+3) /* byte_access address by DMA */ |
| | | #define URXH0 (0x50000024+3) |
| | | #define UTXH1 (0x50004020+3) |
| | | #define URXH1 (0x50004024+3) |
| | | #define UTXH2 (0x50008020+3) |
| | | #define URXH2 (0x50008024+3) |
| | | |
| | | #else /* Little Endian */ |
| | | #define rUTXH0 (*(volatile unsigned char *)0x50000020) |
| | | #define rURXH0 (*(volatile unsigned char *)0x50000024) |
| | | #define rUTXH1 (*(volatile unsigned char *)0x50004020) |
| | | #define rURXH1 (*(volatile unsigned char *)0x50004024) |
| | | #define rUTXH2 (*(volatile unsigned char *)0x50008020) |
| | | #define rURXH2 (*(volatile unsigned char *)0x50008024) |
| | | |
| | | #define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch) |
| | | #define RdURXH0() (*(volatile unsigned char *)0x50000024) |
| | | #define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch) |
| | | #define RdURXH1() (*(volatile unsigned char *)0x50004024) |
| | | #define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch) |
| | | #define RdURXH2() (*(volatile unsigned char *)0x50008024) |
| | | |
| | | #define UTXH0 (0x50000020) /* byte_access address by DMA */ |
| | | #define URXH0 (0x50000024) |
| | | #define UTXH1 (0x50004020) |
| | | #define URXH1 (0x50004024) |
| | | #define UTXH2 (0x50008020) |
| | | #define URXH2 (0x50008024) |
| | | #endif |
| | | |
| | | /* PWM TIMER */ |
| | | #define rTCFG0 (*(volatile unsigned *)0x51000000) |
| | | #define rTCFG1 (*(volatile unsigned *)0x51000004) |
| | | #define rTCON (*(volatile unsigned *)0x51000008) |
| | | #define rTCNTB0 (*(volatile unsigned *)0x5100000C) |
| | | #define rTCMPB0 (*(volatile unsigned *)0x51000010) |
| | | #define rTCNTO0 (*(volatile unsigned *)0x51000014) |
| | | #define rTCNTB1 (*(volatile unsigned *)0x51000018) |
| | | #define rTCMPB1 (*(volatile unsigned *)0x5100001C) |
| | | #define rTCNTO1 (*(volatile unsigned *)0x51000020) |
| | | #define rTCNTB2 (*(volatile unsigned *)0x51000024) |
| | | #define rTCMPB2 (*(volatile unsigned *)0x51000028) |
| | | #define rTCNTO2 (*(volatile unsigned *)0x5100002C) |
| | | #define rTCNTB3 (*(volatile unsigned *)0x51000030) |
| | | #define rTCMPB3 (*(volatile unsigned *)0x51000034) |
| | | #define rTCNTO3 (*(volatile unsigned *)0x51000038) |
| | | #define rTCNTB4 (*(volatile unsigned *)0x5100003C) |
| | | #define rTCNTO4 (*(volatile unsigned *)0x51000040) |
| | | |
| | | /* USB DEVICE */ |
| | | #ifdef __BIG_ENDIAN |
| | | #define rFUNC_ADDR_REG (*(volatile unsigned char *)0x52000143) |
| | | #define rPWR_REG (*(volatile unsigned char *)0x52000147) |
| | | #define rEP_INT_REG (*(volatile unsigned char *)0x5200014B) |
| | | #define rUSB_INT_REG (*(volatile unsigned char *)0x5200015B) |
| | | #define rEP_INT_EN_REG (*(volatile unsigned char *)0x5200015F) |
| | | #define rUSB_INT_EN_REG (*(volatile unsigned char *)0x5200016F) |
| | | #define rFRAME_NUM1_REG (*(volatile unsigned char *)0x52000173) |
| | | #define rFRAME_NUM2_REG (*(volatile unsigned char *)0x52000177) |
| | | #define rINDEX_REG (*(volatile unsigned char *)0x5200017B) |
| | | #define rMAXP_REG (*(volatile unsigned char *)0x52000183) |
| | | #define rEP0_CSR (*(volatile unsigned char *)0x52000187) |
| | | #define rIN_CSR1_REG (*(volatile unsigned char *)0x52000187) |
| | | #define rIN_CSR2_REG (*(volatile unsigned char *)0x5200018B) |
| | | #define rOUT_CSR1_REG (*(volatile unsigned char *)0x52000193) |
| | | #define rOUT_CSR2_REG (*(volatile unsigned char *)0x52000197) |
| | | #define rOUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x5200019B) |
| | | #define rOUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019F) |
| | | #define rEP0_FIFO (*(volatile unsigned char *)0x520001C3) |
| | | #define rEP1_FIFO (*(volatile unsigned char *)0x520001C7) |
| | | #define rEP2_FIFO (*(volatile unsigned char *)0x520001CB) |
| | | #define rEP3_FIFO (*(volatile unsigned char *)0x520001CF) |
| | | #define rEP4_FIFO (*(volatile unsigned char *)0x520001D3) |
| | | #define rEP1_DMA_CON (*(volatile unsigned char *)0x52000203) |
| | | #define rEP1_DMA_UNIT (*(volatile unsigned char *)0x52000207) |
| | | #define rEP1_DMA_FIFO (*(volatile unsigned char *)0x5200020B) |
| | | #define rEP1_DMA_TX_LO (*(volatile unsigned char *)0x5200020F) |
| | | #define rEP1_DMA_TX_MD (*(volatile unsigned char *)0x52000213) |
| | | #define rEP1_DMA_TX_HI (*(volatile unsigned char *)0x52000217) |
| | | #define rEP2_DMA_CON (*(volatile unsigned char *)0x5200021B) |
| | | #define rEP2_DMA_UNIT (*(volatile unsigned char *)0x5200021F) |
| | | #define rEP2_DMA_FIFO (*(volatile unsigned char *)0x52000223) |
| | | #define rEP2_DMA_TX_LO (*(volatile unsigned char *)0x52000227) |
| | | #define rEP2_DMA_TX_MD (*(volatile unsigned char *)0x5200022B) |
| | | #define rEP2_DMA_TX_HI (*(volatile unsigned char *)0x5200022F) |
| | | #define rEP3_DMA_CON (*(volatile unsigned char *)0x52000243) |
| | | #define rEP3_DMA_UNIT (*(volatile unsigned char *)0x52000247) |
| | | #define rEP3_DMA_FIFO (*(volatile unsigned char *)0x5200024B) |
| | | #define rEP3_DMA_TX_LO (*(volatile unsigned char *)0x5200024F) |
| | | #define rEP3_DMA_TX_MD (*(volatile unsigned char *)0x52000253) |
| | | #define rEP3_DMA_TX_HI (*(volatile unsigned char *)0x52000257) |
| | | #define rEP4_DMA_CON (*(volatile unsigned char *)0x5200025B) |
| | | #define rEP4_DMA_UNIT (*(volatile unsigned char *)0x5200025F) |
| | | #define rEP4_DMA_FIFO (*(volatile unsigned char *)0x52000263) |
| | | #define rEP4_DMA_TX_LO (*(volatile unsigned char *)0x52000267) |
| | | #define rEP4_DMA_TX_MD (*(volatile unsigned char *)0x5200026B) |
| | | #define rEP4_DMA_TX_HI (*(volatile unsigned char *)0x5200026F) |
| | | #else /* little endian */ |
| | | #define rFUNC_ADDR_REG (*(volatile unsigned char *)0x52000140) |
| | | #define rPWR_REG (*(volatile unsigned char *)0x52000144) |
| | | #define rEP_INT_REG (*(volatile unsigned char *)0x52000148) |
| | | #define rUSB_INT_REG (*(volatile unsigned char *)0x52000158) |
| | | #define rEP_INT_EN_REG (*(volatile unsigned char *)0x5200015C) |
| | | #define rUSB_INT_EN_REG (*(volatile unsigned char *)0x5200016C) |
| | | #define rFRAME_NUM1_REG (*(volatile unsigned char *)0x52000170) |
| | | #define rFRAME_NUM2_REG (*(volatile unsigned char *)0x52000174) |
| | | #define rINDEX_REG (*(volatile unsigned char *)0x52000178) |
| | | #define rMAXP_REG (*(volatile unsigned char *)0x52000180) |
| | | #define rEP0_CSR (*(volatile unsigned char *)0x52000184) |
| | | #define rIN_CSR1_REG (*(volatile unsigned char *)0x52000184) |
| | | #define rIN_CSR2_REG (*(volatile unsigned char *)0x52000188) |
| | | #define rOUT_CSR1_REG (*(volatile unsigned char *)0x52000190) |
| | | #define rOUT_CSR2_REG (*(volatile unsigned char *)0x52000194) |
| | | #define rOUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x52000198) |
| | | #define rOUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019C) |
| | | #define rEP0_FIFO (*(volatile unsigned char *)0x520001C0) |
| | | #define rEP1_FIFO (*(volatile unsigned char *)0x520001C4) |
| | | #define rEP2_FIFO (*(volatile unsigned char *)0x520001C8) |
| | | #define rEP3_FIFO (*(volatile unsigned char *)0x520001CC) |
| | | #define rEP4_FIFO (*(volatile unsigned char *)0x520001D0) |
| | | #define rEP1_DMA_CON (*(volatile unsigned char *)0x52000200) |
| | | #define rEP1_DMA_UNIT (*(volatile unsigned char *)0x52000204) |
| | | #define rEP1_DMA_FIFO (*(volatile unsigned char *)0x52000208) |
| | | #define rEP1_DMA_TX_LO (*(volatile unsigned char *)0x5200020C) |
| | | #define rEP1_DMA_TX_MD (*(volatile unsigned char *)0x52000210) |
| | | #define rEP1_DMA_TX_HI (*(volatile unsigned char *)0x52000214) |
| | | #define rEP2_DMA_CON (*(volatile unsigned char *)0x52000218) |
| | | #define rEP2_DMA_UNIT (*(volatile unsigned char *)0x5200021C) |
| | | #define rEP2_DMA_FIFO (*(volatile unsigned char *)0x52000220) |
| | | #define rEP2_DMA_TX_LO (*(volatile unsigned char *)0x52000224) |
| | | #define rEP2_DMA_TX_MD (*(volatile unsigned char *)0x52000228) |
| | | #define rEP2_DMA_TX_HI (*(volatile unsigned char *)0x5200022C) |
| | | #define rEP3_DMA_CON (*(volatile unsigned char *)0x52000240) |
| | | #define rEP3_DMA_UNIT (*(volatile unsigned char *)0x52000244) |
| | | #define rEP3_DMA_FIFO (*(volatile unsigned char *)0x52000248) |
| | | #define rEP3_DMA_TX_LO (*(volatile unsigned char *)0x5200024C) |
| | | #define rEP3_DMA_TX_MD (*(volatile unsigned char *)0x52000250) |
| | | #define rEP3_DMA_TX_HI (*(volatile unsigned char *)0x52000254) |
| | | #define rEP4_DMA_CON (*(volatile unsigned char *)0x52000258) |
| | | #define rEP4_DMA_UNIT (*(volatile unsigned char *)0x5200025C) |
| | | #define rEP4_DMA_FIFO (*(volatile unsigned char *)0x52000260) |
| | | #define rEP4_DMA_TX_LO (*(volatile unsigned char *)0x52000264) |
| | | #define rEP4_DMA_TX_MD (*(volatile unsigned char *)0x52000268) |
| | | #define rEP4_DMA_TX_HI (*(volatile unsigned char *)0x5200026C) |
| | | #endif /* __BIG_ENDIAN */ |
| | | |
| | | /* WATCH DOG TIMER */ |
| | | #define rWTCON (*(volatile unsigned *)0x53000000) |
| | | #define rWTDAT (*(volatile unsigned *)0x53000004) |
| | | #define rWTCNT (*(volatile unsigned *)0x53000008) |
| | | |
| | | /* IIC */ |
| | | #define rIICCON (*(volatile unsigned *)0x54000000) |
| | | #define rIICSTAT (*(volatile unsigned *)0x54000004) |
| | | #define rIICADD (*(volatile unsigned *)0x54000008) |
| | | #define rIICDS (*(volatile unsigned *)0x5400000C) |
| | | |
| | | /* IIS */ |
| | | #define rIISCON (*(volatile unsigned *)0x55000000) |
| | | #define rIISMOD (*(volatile unsigned *)0x55000004) |
| | | #define rIISPSR (*(volatile unsigned *)0x55000008) |
| | | #define rIISFCON (*(volatile unsigned *)0x5500000C) |
| | | |
| | | #ifdef __BIG_ENDIAN |
| | | #define IISFIF ((volatile unsigned short *)0x55000012) |
| | | #else /* little endian */ |
| | | #define IISFIF ((volatile unsigned short *)0x55000010) |
| | | #endif |
| | | |
| | | /* I/O PORT */ |
| | | #define rGPACON (*(volatile unsigned *)0x56000000) |
| | | #define rGPADAT (*(volatile unsigned *)0x56000004) |
| | | |
| | | #define rGPBCON (*(volatile unsigned *)0x56000010) |
| | | #define rGPBDAT (*(volatile unsigned *)0x56000014) |
| | | #define rGPBUP (*(volatile unsigned *)0x56000018) |
| | | |
| | | #define rGPCCON (*(volatile unsigned *)0x56000020) |
| | | #define rGPCDAT (*(volatile unsigned *)0x56000024) |
| | | #define rGPCUP (*(volatile unsigned *)0x56000028) |
| | | |
| | | #define rGPDCON (*(volatile unsigned *)0x56000030) |
| | | #define rGPDDAT (*(volatile unsigned *)0x56000034) |
| | | #define rGPDUP (*(volatile unsigned *)0x56000038) |
| | | |
| | | #define rGPECON (*(volatile unsigned *)0x56000040) |
| | | #define rGPEDAT (*(volatile unsigned *)0x56000044) |
| | | #define rGPEUP (*(volatile unsigned *)0x56000048) |
| | | |
| | | #define rGPFCON (*(volatile unsigned *)0x56000050) |
| | | #define rGPFDAT (*(volatile unsigned *)0x56000054) |
| | | #define rGPFUP (*(volatile unsigned *)0x56000058) |
| | | |
| | | #define rGPGCON (*(volatile unsigned *)0x56000060) |
| | | #define rGPGDAT (*(volatile unsigned *)0x56000064) |
| | | #define rGPGUP (*(volatile unsigned *)0x56000068) |
| | | |
| | | #define rGPHCON (*(volatile unsigned *)0x56000070) |
| | | #define rGPHDAT (*(volatile unsigned *)0x56000074) |
| | | #define rGPHUP (*(volatile unsigned *)0x56000078) |
| | | |
| | | #define rMISCCR (*(volatile unsigned *)0x56000080) |
| | | #define rDCLKCON (*(volatile unsigned *)0x56000084) |
| | | #define rEXTINT0 (*(volatile unsigned *)0x56000088) |
| | | #define rEXTINT1 (*(volatile unsigned *)0x5600008C) |
| | | #define rEXTINT2 (*(volatile unsigned *)0x56000090) |
| | | #define rEINTFLT0 (*(volatile unsigned *)0x56000094) |
| | | #define rEINTFLT1 (*(volatile unsigned *)0x56000098) |
| | | #define rEINTFLT2 (*(volatile unsigned *)0x5600009C) |
| | | #define rEINTFLT3 (*(volatile unsigned *)0x560000A0) |
| | | #define rEINTMASK (*(volatile unsigned *)0x560000A4) |
| | | #define rEINTPEND (*(volatile unsigned *)0x560000A8) |
| | | #define rGSTATUS0 (*(volatile unsigned *)0x560000AC) |
| | | #define rGSTATUS1 (*(volatile unsigned *)0x560000B0) |
| | | |
| | | /* RTC */ |
| | | #ifdef __BIG_ENDIAN |
| | | #define rRTCCON (*(volatile unsigned char *)0x57000043) |
| | | #define rTICNT (*(volatile unsigned char *)0x57000047) |
| | | #define rRTCALM (*(volatile unsigned char *)0x57000053) |
| | | #define rALMSEC (*(volatile unsigned char *)0x57000057) |
| | | #define rALMMIN (*(volatile unsigned char *)0x5700005B) |
| | | #define rALMHOUR (*(volatile unsigned char *)0x5700005F) |
| | | #define rALMDATE (*(volatile unsigned char *)0x57000063) |
| | | #define rALMMON (*(volatile unsigned char *)0x57000067) |
| | | #define rALMYEAR (*(volatile unsigned char *)0x5700006B) |
| | | #define rRTCRST (*(volatile unsigned char *)0x5700006F) |
| | | #define rBCDSEC (*(volatile unsigned char *)0x57000073) |
| | | #define rBCDMIN (*(volatile unsigned char *)0x57000077) |
| | | #define rBCDHOUR (*(volatile unsigned char *)0x5700007B) |
| | | #define rBCDDATE (*(volatile unsigned char *)0x5700007F) |
| | | #define rBCDDAY (*(volatile unsigned char *)0x57000083) |
| | | #define rBCDMON (*(volatile unsigned char *)0x57000087) |
| | | #define rBCDYEAR (*(volatile unsigned char *)0x5700008B) |
| | | #else /* little endian */ |
| | | #define rRTCCON (*(volatile unsigned char *)0x57000040) |
| | | #define rTICNT (*(volatile unsigned char *)0x57000044) |
| | | #define rRTCALM (*(volatile unsigned char *)0x57000050) |
| | | #define rALMSEC (*(volatile unsigned char *)0x57000054) |
| | | #define rALMMIN (*(volatile unsigned char *)0x57000058) |
| | | #define rALMHOUR (*(volatile unsigned char *)0x5700005C) |
| | | #define rALMDATE (*(volatile unsigned char *)0x57000060) |
| | | #define rALMMON (*(volatile unsigned char *)0x57000064) |
| | | #define rALMYEAR (*(volatile unsigned char *)0x57000068) |
| | | #define rRTCRST (*(volatile unsigned char *)0x5700006C) |
| | | #define rBCDSEC (*(volatile unsigned char *)0x57000070) |
| | | #define rBCDMIN (*(volatile unsigned char *)0x57000074) |
| | | #define rBCDHOUR (*(volatile unsigned char *)0x57000078) |
| | | #define rBCDDATE (*(volatile unsigned char *)0x5700007C) |
| | | #define rBCDDAY (*(volatile unsigned char *)0x57000080) |
| | | #define rBCDMON (*(volatile unsigned char *)0x57000084) |
| | | #define rBCDYEAR (*(volatile unsigned char *)0x57000088) |
| | | #endif |
| | | |
| | | /* ADC */ |
| | | #define rADCCON (*(volatile unsigned *)0x58000000) |
| | | #define rADCTSC (*(volatile unsigned *)0x58000004) |
| | | #define rADCDLY (*(volatile unsigned *)0x58000008) |
| | | #define rADCDAT0 (*(volatile unsigned *)0x5800000C) |
| | | #define rADCDAT1 (*(volatile unsigned *)0x58000010) |
| | | |
| | | /* SPI */ |
| | | #define rSPCON0 (*(volatile unsigned *)0x59000000) |
| | | #define rSPSTA0 (*(volatile unsigned *)0x59000004) |
| | | #define rSPPIN0 (*(volatile unsigned *)0x59000008) |
| | | #define rSPPRE0 (*(volatile unsigned *)0x5900000C) |
| | | #define rSPTDAT0 (*(volatile unsigned *)0x59000010) |
| | | #define rSPRDAT0 (*(volatile unsigned *)0x59000014) |
| | | #define rSPCON1 (*(volatile unsigned *)0x59000020) |
| | | #define rSPSTA1 (*(volatile unsigned *)0x59000024) |
| | | #define rSPPIN1 (*(volatile unsigned *)0x59000028) |
| | | #define rSPPRE1 (*(volatile unsigned *)0x5900002C) |
| | | #define rSPTDAT1 (*(volatile unsigned *)0x59000030) |
| | | #define rSPRDAT1 (*(volatile unsigned *)0x59000034) |
| | | |
| | | /* SD INTERFACE */ |
| | | #define rSDICON (*(volatile unsigned *)0x5A000000) |
| | | #define rSDIPRE (*(volatile unsigned *)0x5A000004) |
| | | #define rSDICmdArg (*(volatile unsigned *)0x5A000008) |
| | | #define rSDICmdCon (*(volatile unsigned *)0x5A00000C) |
| | | #define rSDICmdSta (*(volatile unsigned *)0x5A000010) |
| | | #define rSDIRSP0 (*(volatile unsigned *)0x5A000014) |
| | | #define rSDIRSP1 (*(volatile unsigned *)0x5A000018) |
| | | #define rSDIRSP2 (*(volatile unsigned *)0x5A00001C) |
| | | #define rSDIRSP3 (*(volatile unsigned *)0x5A000020) |
| | | #define rSDIDTimer (*(volatile unsigned *)0x5A000024) |
| | | #define rSDIBSize (*(volatile unsigned *)0x5A000028) |
| | | #define rSDIDatCon (*(volatile unsigned *)0x5A00002C) |
| | | #define rSDIDatCnt (*(volatile unsigned *)0x5A000030) |
| | | #define rSDIDatSta (*(volatile unsigned *)0x5A000034) |
| | | #define rSDIFSTA (*(volatile unsigned *)0x5A000038) |
| | | #ifdef __BIG_ENDIAN |
| | | #define rSDIDAT (*(volatile unsigned char *)0x5A00003F) |
| | | #else |
| | | #define rSDIDAT (*(volatile unsigned char *)0x5A00003C) |
| | | #endif |
| | | #define rSDIIntMsk (*(volatile unsigned *)0x5A000040) |
| | | |
| | | #endif |
| | | |
| | | #endif /*__S3C24X0_H__*/ |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: interrupt.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: The CPU interrupt vector table depends on function, called in start.S |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #include <common.h> |
| | | |
| | | void do_undefined_instruction(void) |
| | | { |
| | | |
| | | } |
| | | |
| | | void do_software_interrupt(void) |
| | | { |
| | | } |
| | | |
| | | void do_prefetch_abort(void) |
| | | { |
| | | } |
| | | |
| | | void do_data_abort(void) |
| | | { |
| | | } |
| | | |
| | | void do_not_used(void) |
| | | { |
| | | } |
| | | |
| | | void do_irq(void) |
| | | { |
| | | } |
| | | |
| | | void do_fiq(void) |
| | | { |
| | | } |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: k9f2g08.c: K9F2G08 read/write/erase functions for bootstrap |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code is the first stage bootloader(named bootstrap) |
| | | main code, test on FL2440 board. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | |
| | | /************************************************************* |
| | | * Read Status Register Definition of K9F2G08(Refer to k9f2g08u0m datasheet) |
| | | * |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O No. | Page Program | Block Erase | Cache Program | Read | Definition | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 0 | Pass/Fail | Pass/Fail | Pass/Fail(N) | Not use | Pass:0 Fail:1 | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 1 | Not use | Not use | Pass/Fail(N-1)| Not use | Pass:0 Fail:1 | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 2 | Not use | Not use | Not use | Not use | Don't care | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 3 | Not use | Not use | Not use | Not use | Don't care | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 4 | Not use | Not use | Not use | Not use | Don't care | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 5 | Ready/Busy | Ready/Busy |True Ready/Busy| Ready/Busy | Busy:0 Ready:1 | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 6 | Ready/Busy | Ready/Busy | Ready/Busy | Ready/Busy | Busy:0 Ready:1 | |
| | | * |-------------------------------------------------------------------------------------| |
| | | * | I/O 7 |Write protect |Write protect| Write protect |Write protect| Protect:0 Not:1| |
| | | * |-------------------------------------------------------------------------------------| |
| | | * |
| | | *************************************************************/ |
| | | |
| | | #include <nand.h> |
| | | |
| | | /** |
| | | * nand_read_id - Read the Nandflash ID |
| | | * @nand: The nand flash information |
| | | * return: The nandflash ID |
| | | */ |
| | | static unsigned short nand_read_id(void) |
| | | { |
| | | unsigned short id = 0; |
| | | |
| | | nand_select(); /* chip Enable */ |
| | | nand_clear_RnB(); /*Clear Ready & Busy signal*/ |
| | | |
| | | REG_NFCMD = NAND_CMD_READID; /*Read ID command*/ |
| | | REG_NFADDR = 0x00; /*Give address 0x00*/ |
| | | id = REG_NFDATA; /*First byte, Maker code: 0xEC->Samsung*/ |
| | | id = (id << 8) | REG_NFDATA; /*Second byte, Device ID:0xDA->K9F2G08*/ |
| | | |
| | | /*We can read the followed 3 bytes(0x10,0x95,0x44) here, but it's useless.*/ |
| | | |
| | | nand_deselect(); |
| | | |
| | | return id; |
| | | } |
| | | |
| | | #define TACLS 1 // 1-clk |
| | | #define TWRPH0 4 // 4-clk |
| | | #define TWRPH1 1 // 1-clk //TACLS+TWRPH0+TWRPH1>=50ns |
| | | |
| | | /** |
| | | * nand_init - Initial the Nandflash controller and nand flash information structure "nand" |
| | | * @nand: The nand flash information |
| | | * Return: 0->success <0 failed |
| | | */ |
| | | int nand_init(struct boot_nand_t *nand) |
| | | { |
| | | int i, ret = -1; |
| | | unsigned short nand_id; |
| | | |
| | | /*TACL=1, TWRPH0=4, TWRPH1=1, bit[0]=0 means the Nandflash bit witdth is 8bit(K9F2G08 is 8bit)*/ |
| | | REG_NFCONF= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0); |
| | | |
| | | /* |
| | | * Bit[13:12] No lock |
| | | * Bit[10:8] No nandflash interrupt |
| | | * Bit[6:4] Initialize ECC and lock data area & spare area ECC |
| | | * Bit[1] Enable nand flash chip select |
| | | * Bit[0] Enable nand flash controller |
| | | */ |
| | | REG_NFCONT= (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); |
| | | |
| | | |
| | | for (i=0; i<10; i++) ; /*Wait tWB(100ns)*/ |
| | | |
| | | nand_id = nand_read_id(); |
| | | |
| | | /*K9F2G08 page/read/write size is 2K bytes, spare size is 64 bytes |
| | | * and block/erase size is 128K*/ |
| | | if ( NAND_K9F2G08 == nand_id ) /* Samsung K9F2G08 */ |
| | | { |
| | | /*1 Device = 2048 Blocks, 1 Block=64Pages, 1 Pages=(2K Bytes data+ 64Bytes spare)*/ |
| | | nand->id = NAND_K9F2G08; |
| | | nand->spare_size = 64; /* 64 bytes */ |
| | | nand->page_size = 0x0800; /* 1<<11=2K */ |
| | | nand->block_size = 0x20000; /* 1<<17=128K*/ |
| | | nand->block_num = 2048; /* 1<<17=128K*/ |
| | | /*Bad block tag is the first byte in spare area*/ |
| | | nand->bad_block_offset = nand->page_size; |
| | | ret = 0; |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * nand_read_page - Read the data from a page main data area |
| | | * @nand: The nand flash information |
| | | * @page_num: The read page number |
| | | * @offset: The read data start offset address in the page |
| | | * @size: The request read data length |
| | | * @data: The read data output buffer |
| | | * Return: >=0 read bytes |
| | | */ |
| | | int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size) |
| | | { |
| | | uchar *ptr = (uchar *)data; |
| | | ulong i, bytes; |
| | | |
| | | /*Avoid the offset+size larger than a page size(include main data and spare data size) */ |
| | | bytes = ((nand->page_size+nand->spare_size-offset)>=size ? size : (nand->page_size+nand->spare_size)-offset); |
| | | |
| | | nand_select(); |
| | | nand_clear_RnB(); |
| | | |
| | | REG_NFCMD = NAND_CMD_READ0; |
| | | /* Write Address */ |
| | | REG_NFADDR = 0; |
| | | REG_NFADDR = 0; |
| | | REG_NFADDR = page_num & 0xff; |
| | | REG_NFADDR = (page_num >> 8) & 0xff; |
| | | REG_NFADDR = (page_num >> 16) & 0xff; |
| | | REG_NFCMD = NAND_CMD_READSTART; |
| | | |
| | | /* |
| | | * After give NAND_CMD_READSTART command, when the RnB get a rising edge signal, it |
| | | * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] |
| | | * in nandflash controller. After get this signal, then we can read the data or send |
| | | * followed command |
| | | */ |
| | | nand_detect_RnB(); |
| | | |
| | | /* If the offset address in the page is 0 and need read a whole page, |
| | | * then we read the whole page, or use the random page read */ |
| | | if(0==offset && nand->page_size==size) |
| | | goto START_READ; |
| | | |
| | | /*Page Random Read will come here*/ |
| | | REG_NFCMD = NAND_CMD_RNDOUT; |
| | | REG_NFADDR = offset & 0xff; |
| | | REG_NFADDR = (offset >> 8) & 0xff; |
| | | REG_NFCMD = NAND_CMD_RNDOUTSTART; |
| | | |
| | | START_READ: |
| | | for(i=0; i<bytes; i++) |
| | | { |
| | | *ptr = REG_NFDATA; |
| | | ptr++; |
| | | } |
| | | |
| | | nand_deselect(); |
| | | return bytes; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * nand_write_page - Write the data to a page main data area |
| | | * @nand: The nand flash information |
| | | * @page_num: The written page number |
| | | * @offset: The written data start offset address in the page |
| | | * @size: The written data length |
| | | * @data: The written data |
| | | * Return: >=0 write bytes |
| | | */ |
| | | int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size) |
| | | { |
| | | uchar *ptr8 = (uchar *)data; |
| | | uchar stat; |
| | | int ret; |
| | | ulong i, bytes; |
| | | |
| | | /*Avoid the offset+size larger than a page size(include main data and spare data size) */ |
| | | bytes = ((nand->page_size+nand->spare_size-offset)>size ? size : (nand->page_size+nand->spare_size)-offset); |
| | | |
| | | nand_select(); |
| | | nand_clear_RnB(); |
| | | |
| | | REG_NFCMD = NAND_CMD_SEQIN; |
| | | /* Write Address */ |
| | | REG_NFADDR = 0; |
| | | REG_NFADDR = 0; |
| | | REG_NFADDR = page_num & 0xff; |
| | | REG_NFADDR = (page_num >> 8) & 0xff; |
| | | REG_NFADDR = (page_num >> 16) & 0xff; |
| | | |
| | | /* If the offset address in the page is 0 and need write a whole page data, |
| | | * then we read the whole page, or use the random page program */ |
| | | if(0==offset && nand->page_size==size) |
| | | goto START_PROG; |
| | | |
| | | /*Random page program will come here*/ |
| | | REG_NFCMD = NAND_CMD_RNDIN; |
| | | REG_NFADDR = offset & 0xff; |
| | | REG_NFADDR = (offset >> 8) & 0xff; |
| | | |
| | | START_PROG: |
| | | for(i=0; i<bytes; i++) |
| | | { |
| | | REG_NFDATA = *ptr8; |
| | | ptr8++; |
| | | } |
| | | REG_NFCMD = NAND_CMD_PAGEPROG; |
| | | |
| | | /* |
| | | * After give NAND_CMD_PAGEPROG command, when the RnB get a rising edge signal, it |
| | | * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] |
| | | * in nandflash controller. After get this signal, then we can send followed command. |
| | | */ |
| | | nand_detect_RnB(); |
| | | |
| | | /* When program operation is completed, the Write Status register Bit[I/O] 0 maybe checked, |
| | | * bit[0]=0 means pass, or bit[0]=1 means Fail. Refer the top table definition */ |
| | | REG_NFCMD = NAND_CMD_STATUS; |
| | | stat = REG_NFDATA; |
| | | if(stat & 0x01) |
| | | { |
| | | dbg_print("Random Program page number @%lu failure\n", page_num); |
| | | ret = -1; /*Program failure*/ |
| | | } |
| | | else |
| | | { |
| | | ret = bytes; |
| | | } |
| | | |
| | | nand_deselect(); |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * is_bad_block - check the block which the "addr" in is valid or not |
| | | * @nand: Nandflash information |
| | | * @addr: The offset address in whole nandflash, no need block alignment |
| | | * Return: 1->bad block, 0->Valid block |
| | | */ |
| | | int is_bad_block(struct boot_nand_t *nand, ulong addr) |
| | | { |
| | | char data; |
| | | ulong page_num; |
| | | ulong block_start; |
| | | int page_shift = generic_ffs(nand->page_size)-1; |
| | | |
| | | /*Get start address of the block wherre the "addr" in*/ |
| | | block_start = addr & (~(nand->block_size-1)); |
| | | |
| | | /* Get the first page number in the block, the Bad Block Tag is set in |
| | | * the first bit in the first page spare area in the block */ |
| | | page_num = block_start >> page_shift; |
| | | |
| | | nand_read_page(nand, page_num, nand->bad_block_offset, &data, 1); |
| | | |
| | | if (data != 0xff) |
| | | { |
| | | printf("Bad Block @%08lx by address @%08lx\n",block_start, addr); |
| | | nand_deselect(); |
| | | return 1; |
| | | } |
| | | |
| | | nand_deselect(); |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * mark_bad_block - Mark the block as bad block |
| | | * @nand: Nandflash information |
| | | * @addr: The offset address in whole nandflash, no need block alignment |
| | | * Return: 0->mark bad block success, <0 mark bad block failed. |
| | | */ |
| | | int mark_bad_block(struct boot_nand_t *nand, ulong addr) |
| | | { |
| | | char data = 0xEE; |
| | | ulong page_num; |
| | | ulong block_num; |
| | | ulong block_start; |
| | | int ret; |
| | | |
| | | /*Get start address of the block wherre the "addr" in*/ |
| | | block_start = addr & (~(nand->block_size-1)); |
| | | |
| | | /* Get the first page number in the block, the Bad Block Tag is set in |
| | | * the first bit in the first page spare area in the block */ |
| | | page_num = block_start >> (generic_ffs(nand->page_size)-1); |
| | | |
| | | |
| | | ret = nand_write_page(nand, page_num, nand->bad_block_offset, &data, 1); |
| | | ret = ret<0 ? ret: 0; |
| | | |
| | | block_num = block_start >> (generic_ffs(nand->block_size)-1); |
| | | dbg_print("Mark bad block index [$%lu] address @0x%08lx %s.\n", |
| | | block_num, block_start, ret==0?"success":"failed"); |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * nand_erase_block - Erase a block specify by the block_num |
| | | * @nand: Nandflash information |
| | | * @block_num: The erase block index number |
| | | * Return: 0->success, <0 Failure |
| | | */ |
| | | |
| | | int nand_erase_block(struct boot_nand_t *nand, ulong block_num) |
| | | { |
| | | uchar stat; |
| | | int ret = 0; |
| | | ulong block_start; /*Block start address*/ |
| | | |
| | | nand_select(); |
| | | nand_clear_RnB(); |
| | | |
| | | REG_NFCMD = NAND_CMD_ERASE1; |
| | | REG_NFADDR = (block_num<<6) & 0xff; /*Row address A18~A19*/ |
| | | REG_NFADDR = (block_num>>2) & 0xff; /*Row address A20~A27*/ |
| | | REG_NFADDR = (block_num>>10) & 0x0f; /*Row address A28*/ |
| | | REG_NFCMD = NAND_CMD_ERASE2; |
| | | |
| | | /* |
| | | * After give NAND_CMD_ERASE2 command, when the RnB get a rising edge signal, it |
| | | * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] |
| | | * in nandflash controller. After get this signal, then we can send next command. |
| | | */ |
| | | nand_detect_RnB(); |
| | | |
| | | /* When erase operation is completed, the Write Status register Bit[I/O] 0 maybe checked, |
| | | * bit[0]=0 means pass, or bit[0]=1 means Fail. Refer the top table definition */ |
| | | REG_NFCMD = NAND_CMD_STATUS; |
| | | |
| | | stat = REG_NFDATA; |
| | | |
| | | block_start = block_num<<(generic_ffs(nand->block_size)-1); |
| | | if( stat&(1<<0) ) |
| | | { |
| | | printf("Erase block index [$%lu] address @0x%08lx failed.\n", block_num, block_start); |
| | | mark_bad_block(nand, block_start); |
| | | ret = -1; |
| | | goto OUT; |
| | | } |
| | | |
| | | dbg_print("Erase block index [$%lu] address @0x%08lx success.\n", block_num, block_start); |
| | | |
| | | OUT: |
| | | nand_deselect(); |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * nand_erase - Erase some blocks from start_addr |
| | | * @nand: Nandflash information |
| | | * @start_addr: The erase start address, it must be aligment |
| | | * @size: The erase block size, it must be n*block_size |
| | | * @skip_bad: Whether need auto skip the bad block or not, if skip, the erase size don't change |
| | | * Return: 0->success, >0 Bad block count |
| | | */ |
| | | int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad) |
| | | { |
| | | |
| | | int block_num, ret=0; |
| | | int failed = 0; |
| | | ulong addr; |
| | | int block_shift = generic_ffs(nand->block_size)-1; |
| | | |
| | | if ( (start_addr & (nand->block_size-1)) || (size & (nand->block_size-1)) ) |
| | | { |
| | | printf("nand erase address @0x%08lx or size $%lu not block aligment.\n", start_addr, size); |
| | | return -1; /* invalid alignment */ |
| | | } |
| | | |
| | | addr = start_addr; |
| | | while( addr<(start_addr+size) ) |
| | | { |
| | | block_num = addr>> block_shift; |
| | | ret = nand_erase_block(nand, block_num); |
| | | if(ret < 0) |
| | | { |
| | | if(skip_bad) |
| | | { |
| | | /*Erase next block*/ |
| | | addr += nand->block_size; |
| | | size += nand->block_size; |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | | failed ++; |
| | | } |
| | | } |
| | | else |
| | | addr += nand->block_size; |
| | | } |
| | | |
| | | /*If don't skip the bad block, then return the erase block failure times, or return OK.*/ |
| | | ret = (!skip_bad && failed) ? failed : 0; |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | /* |
| | | * nand_scrub - nand erase the whole Nandflash |
| | | * @nand: The nand flash information |
| | | */ |
| | | void nand_scrub(struct boot_nand_t *nand) |
| | | { |
| | | int i; |
| | | |
| | | for(i=0; i<nand->block_num; i++) |
| | | nand_erase_block(nand, i); |
| | | } |
| | | |
| | | /* nand_read_spare - Read some bytes from the spare first byte |
| | | * @nand: The nand flash information |
| | | * @page_addr: The page address in the whole Nand flash, no need page alignment |
| | | * @size: The spare area request read size, which start from the spare first byte |
| | | * @buf: The output data buffer |
| | | * Return: Read spare area data bytes |
| | | */ |
| | | int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf) |
| | | { |
| | | ulong page_num; |
| | | ulong bytes; |
| | | int page_shift = generic_ffs(nand->page_size)-1; |
| | | |
| | | size = size > nand->spare_size ? nand->spare_size : size; |
| | | |
| | | page_num = page_addr >> page_shift; /*The page number in the whole Nandflash*/ |
| | | |
| | | bytes = nand_read_page(nand, page_num, nand->bad_block_offset, buf, size); |
| | | |
| | | return bytes; |
| | | } |
| | | |
| | | /* nand_write_spare - Write some bytes to the spare first byte |
| | | * @nand: The nand flash information |
| | | * @page_addr: The page address in the whole Nand flash, no need page alignment |
| | | * @size: The write data size |
| | | * @buf: The write data |
| | | * Return: Write to spare area data bytes |
| | | */ |
| | | int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf) |
| | | { |
| | | ulong page_num; |
| | | ulong bytes; |
| | | int page_shift = generic_ffs(nand->page_size)-1; |
| | | |
| | | size = size > nand->spare_size ? nand->spare_size : size; |
| | | |
| | | page_num = page_addr >> page_shift; /*The page number in the whole Nandflash*/ |
| | | |
| | | bytes = nand_write_page(nand, page_num, nand->bad_block_offset, buf, size); |
| | | |
| | | return bytes; |
| | | } |
| | | |
| | | /** |
| | | * nand_read - Read some datas in the main data area in the page |
| | | * @nand: Nandflash information |
| | | * @start_addr: The read start address, it must be page alignment |
| | | * @size: The request read data size, no need alignment |
| | | * @buf: The read data output buffer |
| | | * Return: >=0 Read data bytes, <0 Read failure |
| | | */ |
| | | int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf) |
| | | { |
| | | ulong addr; |
| | | ulong page_num; |
| | | ulong page_offset; |
| | | ulong page_mask = nand->page_size-1; |
| | | ulong bytes = 0; |
| | | ulong left; |
| | | int page_shift = generic_ffs(nand->page_size)-1; |
| | | |
| | | left = size; |
| | | addr = start_addr; |
| | | |
| | | /* The address must be page alignment*/ |
| | | if( (addr & page_mask) ) |
| | | { |
| | | printf("nand read address @0x%08lx not alignment.\n", addr); |
| | | return -1; |
| | | } |
| | | |
| | | while(left > 0) |
| | | { |
| | | /*If the addr is block alignment, then we check this block is valid or not*/ |
| | | if ( ((addr&(nand->block_size-1))==0) && is_bad_block(nand, addr) ) |
| | | { |
| | | /*Skip Bad block and goto next block */ |
| | | dbg_print("Skip bad block @0x%08lx\n", addr); |
| | | addr += nand->block_size; |
| | | continue; |
| | | } |
| | | |
| | | page_num = addr >> page_shift; /*The page number in the whole Nandflash*/ |
| | | page_offset = addr & page_mask; /*The offset address in the page*/ |
| | | |
| | | if( left >= nand->page_size) |
| | | { |
| | | bytes = nand_read_page(nand, page_num, page_offset, buf, nand->page_size); |
| | | #if 1 |
| | | dbg_print("Read whole page: addr=%08lx page_num=%d page_offset=%08lx, bytes=%lu \n", |
| | | addr, page_num, page_offset, bytes); |
| | | #endif |
| | | } |
| | | else |
| | | { |
| | | bytes = nand_read_page(nand, page_num, page_offset, buf, size%nand->page_size); |
| | | #if 1 |
| | | printf("Read part page: addr=%08lx page_num=%d page_offset=%d, bytes=%lu \n", |
| | | addr, page_num, page_offset, size%nand->page_size); |
| | | #endif |
| | | } |
| | | |
| | | addr+=bytes; |
| | | buf += bytes; |
| | | left-=bytes; |
| | | } |
| | | |
| | | return bytes; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * nand_write - Write some datas to the main data area in the page |
| | | * @nand: Nandflash information |
| | | * @start_addr: The write start address, it must be page alignment |
| | | * @size: The write data size, no need alignment |
| | | * @buf: The write data |
| | | * Return: >=0 Write data bytes, <0 Write failure |
| | | */ |
| | | int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf) |
| | | { |
| | | ulong addr; |
| | | ulong page_num; |
| | | ulong page_offset; |
| | | ulong page_mask = nand->page_size-1; |
| | | ulong bytes = 0; |
| | | ulong left; |
| | | int page_shift = generic_ffs(nand->page_size)-1; |
| | | |
| | | left = size; |
| | | addr = start_addr; |
| | | |
| | | /* The address must be page alignment*/ |
| | | if( (addr & page_mask) ) |
| | | { |
| | | printf("nand read address @0x%08lx not alignment.\n", addr); |
| | | return -1; |
| | | } |
| | | |
| | | while(left > 0) |
| | | { |
| | | /*If the addr is block alignment, then we check this block is valid or not*/ |
| | | if ( ((addr&(nand->block_size-1))==0) && is_bad_block(nand, addr) ) |
| | | { |
| | | /*Skip Bad block and goto next block */ |
| | | dbg_print("Skip bad block @0x%08lx\n", addr); |
| | | addr += nand->block_size; |
| | | continue; |
| | | } |
| | | |
| | | page_num = addr >> page_shift; /*The page number in the whole Nandflash*/ |
| | | page_offset = addr & page_mask; /*The offset address in the page*/ |
| | | |
| | | if( left >= nand->page_size) |
| | | { |
| | | bytes = nand_write_page(nand, page_num, page_offset, buf, nand->page_size); |
| | | #if 1 |
| | | dbg_print("Write whole page: addr=%08lx page_num=%d page_offset=%08lx, bytes=%lu \n", |
| | | addr, page_num, page_offset, bytes); |
| | | #endif |
| | | } |
| | | else |
| | | { |
| | | bytes = nand_write_page(nand, page_num, page_offset, buf, size%nand->page_size); |
| | | #if 1 |
| | | dbg_print("Write part page: addr=%08lx page_num=%d page_offset=%d, bytes=%lu \n", |
| | | addr, page_num, page_offset, size%nand->page_size); |
| | | #endif |
| | | } |
| | | |
| | | addr+=bytes; |
| | | buf += bytes; |
| | | left-=bytes; |
| | | } |
| | | |
| | | return bytes; |
| | | } |
| | | |
| | | |
| | | #if 0 |
| | | |
| | | /** |
| | | * nand_wait - wait Nandflash goes to Ready to operate |
| | | */ |
| | | static inline void nand_wait(void) |
| | | { |
| | | int i; |
| | | |
| | | /*NFSTAG register bit[0] is RnB: 0->Nandflash Busy 1->Nandflash Ready to operate */ |
| | | while (!(REG_NFSTAT & NFSTAT_BUSY)) /*bit[0]*/ |
| | | { |
| | | dbg_print("Nandflash is busy.\n"); |
| | | for (i = 0; i < 10; i++) ; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * nand_reset - Reset the Nandflash |
| | | */ |
| | | static void nand_reset(void) |
| | | { |
| | | nand_select(); /* chip Enable */ |
| | | nand_clear_RnB(); /*Clear Ready & Busy signal*/ |
| | | |
| | | REG_NFCMD = NAND_CMD_RESET; /*Read ID command*/ |
| | | REG_NFADDR = 0x00; /*Give address 0x00*/ |
| | | |
| | | nand_detect_RnB(); |
| | | nand_deselect(); |
| | | } |
| | | #endif |
| | | |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: led_beep.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: LED & Beep operate funciton. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #include <common.h> |
| | | #define DELAY_TIME 1000000 |
| | | |
| | | /*LED & Beep */ |
| | | #define GPBCON (*(unsigned long volatile *)0x56000010) |
| | | #define GPBDAT (*(unsigned long volatile *)0x56000014) |
| | | #define GPBUP (*(unsigned long volatile *)0x56000018) |
| | | |
| | | inline void delay(unsigned long loops) |
| | | { |
| | | __asm__ volatile ("1:\n" "subs %0, %1, #1\n" "bne 1b":"=r" (loops):"0"(loops)); |
| | | } |
| | | |
| | | void init_led_beep(void) |
| | | { |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ |
| | | GPBCON = (GPBCON | 0x333C03) & 0x111401; |
| | | GPBUP = (GPBUP | 0x560); |
| | | /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ |
| | | GPBDAT = (GPBDAT | 0x560); |
| | | } |
| | | |
| | | void turn_led_on(int led) |
| | | { |
| | | GPBDAT = (GPBDAT & (~(1 << led))); |
| | | delay(DELAY_TIME); |
| | | } |
| | | |
| | | void turn_led_off(int led) |
| | | { |
| | | /* Turn LED0 on */ |
| | | GPBDAT = (GPBDAT | (1 << led)); |
| | | delay(DELAY_TIME); |
| | | } |
| | | |
| | | void beep(int count) |
| | | { |
| | | int i; |
| | | for (i = 0; i < count; i++) |
| | | { |
| | | GPBDAT |= 1 << BEEP; /* Set Beep GPIO as high level */ |
| | | delay(DELAY_TIME * 50); |
| | | |
| | | GPBDAT &= ~(1 << BEEP); /* Set Beep GPIO as low level */ |
| | | delay(DELAY_TIME * 50); |
| | | } |
| | | } |
New file |
| | |
| | | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM source code |
| | | # * ChangeLog: 1, Release initial version on "Sun Mar 20 18:41:04 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | # |
| | | |
| | | APP_NAME=bootstrap |
| | | #INST_PATH=/tftp |
| | | |
| | | # Enable "printf" function for help, don't enable it for production to save about 2K size |
| | | CONFIG_PRINTF_DBG=y |
| | | |
| | | # When wanna burn the image to nandflash and start from it, then commont follow option |
| | | RAM_DEBUG=y |
| | | |
| | | BOARD=SMDK2440 |
| | | #BOARD=SMDK2416 |
| | | |
| | | export BOARD |
| | | |
| | | SRC_TOP=$(CURDIR) |
| | | |
| | | CFLAGS+=-I${SRC_TOP}/include |
| | | CFLAGS+=-Os -D__KERNEL__ -DCONFIG_ARM -D__ARM__ -DBOARD_$(BOARD) |
| | | PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc |
| | | |
| | | ifeq ($(BOARD),SMDK2440) |
| | | PLATFORM_LIBS += -lc -L/opt/buildroot-2011.11/arm920t/usr/arm-unknown-linux-uclibcgnueabi/sysroot/usr/lib/ |
| | | ifeq ($(RAM_DEBUG),y) |
| | | TEXT_BASE=0x33000000 |
| | | else |
| | | TEXT_BASE=0x00000000 |
| | | endif |
| | | # Set the stack top base address here |
| | | CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=0x33000000 |
| | | CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- |
| | | CFLAGS+= -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float |
| | | CFLAGS+=-march=armv4t -Wall -Wstrict-prototypes -fno-stack-protector |
| | | endif |
| | | |
| | | ifeq ($(BOARD),SMDK2416) |
| | | TEXT_BASE=0x33000000 |
| | | CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) |
| | | CROSS_COMPILE=/opt/buildroot-2011.11/arm926t/usr/bin/arm-linux- |
| | | CFLAGS+= -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float -mfloat-abi=soft |
| | | CFLAGS+=-march=armv4t -Wstrict-prototypes -fno-stack-protector |
| | | endif |
| | | |
| | | AS = $(CROSS_COMPILE)as |
| | | LD = $(CROSS_COMPILE)ld |
| | | CC = $(CROSS_COMPILE)gcc |
| | | CPP = $(CC) -E |
| | | AR = $(CROSS_COMPILE)ar |
| | | NM = $(CROSS_COMPILE)nm |
| | | LDR = $(CROSS_COMPILE)ldr |
| | | STRIP = $(CROSS_COMPILE)strip |
| | | OBJCOPY = $(CROSS_COMPILE)objcopy |
| | | OBJDUMP = $(CROSS_COMPILE)objdump |
| | | RANLIB = $(CROSS_COMPILE)RANLIB |
| | | |
| | | gccincdir := $(shell $(CC) -print-file-name=include) |
| | | CFLAGS += -ffreestanding -nostdinc -isystem $(gccincdir) -pipe |
| | | |
| | | CFLAGS += -fno-builtin |
| | | LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE) |
| | | AFLAGS := $(CFLAGS) -D__ASSEMBLY__ |
| | | |
| | | export CROSS_COMPILE AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP CFLAGS |
| | | |
| | | SOBJS := start.o mem_init.o |
| | | OBJS := bootstrap.o led_beep.o interrupt.o serial.o common.o xmodem.o k9f2g08.o |
| | | |
| | | ifeq ($(CONFIG_PRINTF_DBG), y) |
| | | CFLAGS+=-DCONFIG_PRINTF_DBG |
| | | endif |
| | | |
| | | ALL: .depend $(SOBJS) $(OBJS) |
| | | cd $(SRC_TOP) |
| | | ${LD} $(LDFLAGS) $(SOBJS) \ |
| | | --start-group $(OBJS) \ |
| | | --end-group $(PLATFORM_LIBS) \ |
| | | -Map $(APP_NAME).map -o $(APP_NAME).elf |
| | | ${OBJCOPY} -O binary $(APP_NAME).elf $(APP_NAME).bin |
| | | @chmod 777 $(APP_NAME).bin |
| | | @rm -f *.elf *.o |
| | | |
| | | .depend: makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) |
| | | $(CC) -M $(AFLAGS) -D__ASSEMBLY__ $(SOBJS:.o=.S) > $@ |
| | | $(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@ |
| | | |
| | | sinclude .depend |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: $(APP_NAME).bin |
| | | cp $(APP_NAME).bin $(INST_PATH) -f |
| | | cp $(APP_NAME).bin /tftp -f |
| | | |
| | | clean: |
| | | @find $(OBJTREE) -type f \ |
| | | \( -name 'core' -o -name '*.bak' -o -name '*~' -o -name .depend \ |
| | | -o -name '*.o' -o -name '*.a' -o -name '*.elf' \) -print \ |
| | | | xargs rm -f |
| | | @rm -f $(APP_NAME).bin |
| | | @rm -f $(APP_NAME).map |
| | | |
| | | distclean clear: clean |
| | | @rm -f cscope.* tags |
| | | |
| | | |
New file |
| | |
| | | /* |
| | | * Memory Setup stuff - taken from blob memsetup.S |
| | | * |
| | | * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and |
| | | * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) |
| | | * |
| | | * Modified for the Samsung SMDK2410 by |
| | | * (C) Copyright 2002 |
| | | * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> |
| | | * |
| | | * Modified for the friendly-arm SBC-2410X by |
| | | * (C) Copyright 2005 |
| | | * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com> |
| | | * |
| | | * See file CREDITS for list of people who contributed to this |
| | | * project. |
| | | * |
| | | * This program is free software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU General Public License as |
| | | * published by the Free Software Foundation; either version 2 of |
| | | * the License, or (at your option) any later version. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License |
| | | * along with this program; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| | | * MA 02111-1307 USA |
| | | */ |
| | | |
| | | /* |
| | | * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S |
| | | * |
| | | * Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com> |
| | | */ |
| | | |
| | | #include <config.h> |
| | | |
| | | #define BWSCON 0x48000000 |
| | | |
| | | /* BWSCON */ |
| | | #define DW8 (0x0) |
| | | #define DW16 (0x1) |
| | | #define DW32 (0x2) |
| | | #define WAIT (0x1<<2) |
| | | #define UBLB (0x1<<3) |
| | | |
| | | #define B1_BWSCON (DW16) |
| | | #define B2_BWSCON (DW16) |
| | | #define B3_BWSCON (DW16 + WAIT + UBLB) |
| | | #define B4_BWSCON (DW16) |
| | | #define B5_BWSCON (DW16) |
| | | #define B6_BWSCON (DW32) |
| | | #define B7_BWSCON (DW32) |
| | | |
| | | #define B0_Tacs 0x0 |
| | | #define B0_Tcos 0x0 |
| | | #define B0_Tacc 0x7 |
| | | #define B0_Tcoh 0x0 |
| | | #define B0_Tah 0x0 |
| | | #define B0_Tacp 0x0 |
| | | #define B0_PMC 0x0 |
| | | |
| | | #define B1_Tacs 0x0 |
| | | #define B1_Tcos 0x0 |
| | | #define B1_Tacc 0x7 |
| | | #define B1_Tcoh 0x0 |
| | | #define B1_Tah 0x0 |
| | | #define B1_Tacp 0x0 |
| | | #define B1_PMC 0x0 |
| | | |
| | | #define B2_Tacs 0x0 |
| | | #define B2_Tcos 0x0 |
| | | #define B2_Tacc 0x7 |
| | | #define B2_Tcoh 0x0 |
| | | #define B2_Tah 0x0 |
| | | #define B2_Tacp 0x0 |
| | | #define B2_PMC 0x0 |
| | | |
| | | #define B3_Tacs 0xc |
| | | #define B3_Tcos 0x7 |
| | | #define B3_Tacc 0xf |
| | | #define B3_Tcoh 0x1 |
| | | #define B3_Tah 0x0 |
| | | #define B3_Tacp 0x0 |
| | | #define B3_PMC 0x0 |
| | | |
| | | #define B4_Tacs 0x0 |
| | | #define B4_Tcos 0x0 |
| | | #define B4_Tacc 0x7 |
| | | #define B4_Tcoh 0x0 |
| | | #define B4_Tah 0x0 |
| | | #define B4_Tacp 0x0 |
| | | #define B4_PMC 0x0 |
| | | |
| | | #define B5_Tacs 0xc |
| | | #define B5_Tcos 0x7 |
| | | #define B5_Tacc 0xf |
| | | #define B5_Tcoh 0x1 |
| | | #define B5_Tah 0x0 |
| | | #define B5_Tacp 0x0 |
| | | #define B5_PMC 0x0 |
| | | |
| | | #define B6_MT 0x3 /* SDRAM */ |
| | | #define B6_Trcd 0x1 |
| | | #define B6_SCAN 0x1 /* 9bit */ |
| | | |
| | | #define B7_MT 0x3 /* SDRAM */ |
| | | #define B7_Trcd 0x1 /* 3clk */ |
| | | #define B7_SCAN 0x1 /* 9bit */ |
| | | |
| | | /* REFRESH parameter */ |
| | | #define REFEN 0x1 /* Refresh enable */ |
| | | #define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ |
| | | #define Trc 0x3 /* 7clk */ |
| | | #define Tchr 0x2 /* 3clk */ |
| | | |
| | | #if defined(CONFIG_S3C2440) |
| | | #define Trp 0x2 /* 4clk */ |
| | | #define REFCNT 1012 |
| | | #else |
| | | #define Trp 0x0 /* 2clk */ |
| | | #define REFCNT 0x0459 |
| | | #endif |
| | | /**************************************/ |
| | | |
| | | _TEXT_BASE: |
| | | .word TEXT_BASE |
| | | |
| | | .globl mem_init |
| | | mem_init: |
| | | /* memory control configuration */ |
| | | /* make r0 relative the current location so that it */ |
| | | /* reads SMRDATA out of FLASH rather than memory ! */ |
| | | ldr r0, =SMRDATA |
| | | ldr r1, =mem_init |
| | | sub r0, r0, r1 |
| | | adr r3, mem_init /* r3 <- current position of code */ |
| | | add r0, r0, r3 |
| | | ldr r1, =BWSCON /* Bus Width Status Controller */ |
| | | add r2, r0, #13*4 |
| | | 0: |
| | | ldr r3, [r0], #4 |
| | | str r3, [r1], #4 |
| | | cmp r2, r0 |
| | | bne 0b |
| | | |
| | | /* everything is fine now */ |
| | | mov pc, lr |
| | | |
| | | .ltorg |
| | | /* the literal pools origin */ |
| | | |
| | | SMRDATA: |
| | | .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) |
| | | .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) |
| | | .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) |
| | | .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) |
| | | .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) |
| | | .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) |
| | | .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) |
| | | .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) |
| | | .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) |
| | | .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) |
| | | .word 0xb2 |
| | | .word 0x30 |
| | | .word 0x30 |
New file |
| | |
| | | /* |
| | | * linux/include/linux/mtd/nand.h |
| | | * |
| | | * Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org> |
| | | * Steven J. Hill <sjhill@realitydiluted.com> |
| | | * Thomas Gleixner <tglx@linutronix.de> |
| | | * |
| | | * 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. |
| | | * |
| | | * Info: |
| | | * Contains standard defines and IDs for NAND flash devices |
| | | * |
| | | * Changelog: |
| | | * See git changelog. |
| | | */ |
| | | #ifndef __LINUX_MTD_NAND_H |
| | | #define __LINUX_MTD_NAND_H |
| | | |
| | | #include <common.h> |
| | | #include <linux/bitops.h> |
| | | |
| | | #define NAND_K9F2G08 0xecda |
| | | |
| | | /* This constant declares the max. oobsize / page, which |
| | | * is supported now. If you add a chip with bigger oobsize/page |
| | | * adjust this accordingly. |
| | | */ |
| | | #define NAND_MAX_OOBSIZE 218 |
| | | #define NAND_MAX_PAGESIZE 4096 |
| | | |
| | | /* |
| | | * Constants for hardware specific CLE/ALE/NCE function |
| | | * |
| | | * These are bits which can be or'ed to set/clear multiple |
| | | * bits in one go. |
| | | */ |
| | | /* Select the chip by setting nCE to low */ |
| | | #define NAND_NCE 0x01 |
| | | /* Select the command latch by setting CLE to high */ |
| | | #define NAND_CLE 0x02 |
| | | /* Select the address latch by setting ALE to high */ |
| | | #define NAND_ALE 0x04 |
| | | |
| | | #define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) |
| | | #define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) |
| | | #define NAND_CTRL_CHANGE 0x80 |
| | | |
| | | /* |
| | | * Standard NAND flash commands |
| | | */ |
| | | #define NAND_CMD_READ0 0x00 /*Page read period 1*/ |
| | | #define NAND_CMD_READSTART 0x30 /*Page read period 2, for large page*/ |
| | | #define NAND_CMD_READID 0x90 /*Read production ID*/ |
| | | #define NAND_CMD_SEQIN 0x80 /*Page write period 1*/ |
| | | #define NAND_CMD_PAGEPROG 0x10 /*Page write period 2*/ |
| | | #define NAND_CMD_ERASE1 0x60 /*Block erase period 1*/ |
| | | #define NAND_CMD_ERASE2 0xd0 /*Block erase period 2*/ |
| | | #define NAND_CMD_STATUS 0x70 /*Read status command*/ |
| | | #define NAND_CMD_RESET 0xff /*Nandflash reset command*/ |
| | | #define NAND_CMD_READ1 1 |
| | | #define NAND_CMD_RNDOUT 0x05 /*Page random read period 1*/ |
| | | #define NAND_CMD_RNDOUTSTART 0xE0 /*Page random read period 2*/ |
| | | #define NAND_CMD_RNDIN 0x85 /*Page random write*/ |
| | | |
| | | #define NAND_CMD_READOOB 0x50 |
| | | #define NAND_CMD_STATUS_MULTI 0x71 |
| | | |
| | | /* Extended commands for large page devices */ |
| | | #define NAND_CMD_CACHEDPROG 0x15 |
| | | |
| | | /* Extended commands for AG-AND device */ |
| | | /* |
| | | * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but |
| | | * there is no way to distinguish that from NAND_CMD_READ0 |
| | | * until the remaining sequence of commands has been completed |
| | | * so add a high order bit and mask it off in the command. |
| | | */ |
| | | #define NAND_CMD_DEPLETE1 0x100 |
| | | #define NAND_CMD_DEPLETE2 0x38 |
| | | #define NAND_CMD_STATUS_MULTI 0x71 |
| | | #define NAND_CMD_STATUS_ERROR 0x72 |
| | | /* multi-bank error status (banks 0-3) */ |
| | | #define NAND_CMD_STATUS_ERROR0 0x73 |
| | | #define NAND_CMD_STATUS_ERROR1 0x74 |
| | | #define NAND_CMD_STATUS_ERROR2 0x75 |
| | | #define NAND_CMD_STATUS_ERROR3 0x76 |
| | | #define NAND_CMD_STATUS_RESET 0x7f |
| | | #define NAND_CMD_STATUS_CLEAR 0xff |
| | | |
| | | #define NAND_CMD_NONE -1 |
| | | |
| | | /* Status bits */ |
| | | #define NAND_STATUS_FAIL 0x01 |
| | | #define NAND_STATUS_FAIL_N1 0x02 |
| | | #define NAND_STATUS_TRUE_READY 0x20 |
| | | #define NAND_STATUS_READY 0x40 |
| | | #define NAND_STATUS_WP 0x80 |
| | | |
| | | /* |
| | | * Constants for ECC_MODES |
| | | */ |
| | | typedef enum |
| | | { |
| | | NAND_ECC_NONE, |
| | | NAND_ECC_SOFT, |
| | | NAND_ECC_HW, |
| | | NAND_ECC_HW_SYNDROME, |
| | | NAND_ECC_HW_OOB_FIRST, |
| | | } nand_ecc_modes_t; |
| | | |
| | | /* |
| | | * Constants for Hardware ECC |
| | | */ |
| | | /* Reset Hardware ECC for read */ |
| | | #define NAND_ECC_READ 0 |
| | | /* Reset Hardware ECC for write */ |
| | | #define NAND_ECC_WRITE 1 |
| | | /* Enable Hardware ECC before syndrom is read back from flash */ |
| | | #define NAND_ECC_READSYN 2 |
| | | |
| | | /* Bit mask for flags passed to do_nand_read_ecc */ |
| | | #define NAND_GET_DEVICE 0x80 |
| | | |
| | | /* Option constants for bizarre disfunctionality and real |
| | | * features |
| | | */ |
| | | /* Chip can not auto increment pages */ |
| | | #define NAND_NO_AUTOINCR 0x00000001 |
| | | /* Buswitdh is 16 bit */ |
| | | #define NAND_BUSWIDTH_16 0x00000002 |
| | | /* Device supports partial programming without padding */ |
| | | #define NAND_NO_PADDING 0x00000004 |
| | | /* Chip has cache program function */ |
| | | #define NAND_CACHEPRG 0x00000008 |
| | | /* Chip has copy back function */ |
| | | #define NAND_COPYBACK 0x00000010 |
| | | /* AND Chip which has 4 banks and a confusing page / block |
| | | * assignment. See Renesas datasheet for further information */ |
| | | #define NAND_IS_AND 0x00000020 |
| | | /* Chip has a array of 4 pages which can be read without |
| | | * additional ready /busy waits */ |
| | | #define NAND_4PAGE_ARRAY 0x00000040 |
| | | /* Chip requires that BBT is periodically rewritten to prevent |
| | | * bits from adjacent blocks from 'leaking' in altering data. |
| | | * This happens with the Renesas AG-AND chips, possibly others. */ |
| | | #define BBT_AUTO_REFRESH 0x00000080 |
| | | /* Chip does not require ready check on read. True |
| | | * for all large page devices, as they do not support |
| | | * autoincrement.*/ |
| | | #define NAND_NO_READRDY 0x00000100 |
| | | /* Chip does not allow subpage writes */ |
| | | #define NAND_NO_SUBPAGE_WRITE 0x00000200 |
| | | |
| | | /* Options valid for Samsung large page devices */ |
| | | #define NAND_SAMSUNG_LP_OPTIONS \ |
| | | (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK) |
| | | |
| | | /* Macros to identify the above */ |
| | | #define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR)) |
| | | #define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) |
| | | #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) |
| | | #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) |
| | | /* Large page NAND with SOFT_ECC should support subpage reads */ |
| | | #define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ |
| | | && (chip->page_shift > 9)) |
| | | |
| | | /* Mask to zero out the chip options, which come from the id table */ |
| | | #define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) |
| | | |
| | | /* Non chip related options */ |
| | | /* Use a flash based bad block table. This option is passed to the |
| | | * default bad block table function. */ |
| | | #define NAND_USE_FLASH_BBT 0x00010000 |
| | | /* This option skips the bbt scan during initialization. */ |
| | | #define NAND_SKIP_BBTSCAN 0x00020000 |
| | | /* This option is defined if the board driver allocates its own buffers |
| | | (e.g. because it needs them DMA-coherent */ |
| | | #define NAND_OWN_BUFFERS 0x00040000 |
| | | /* Options set by nand scan */ |
| | | /* bbt has already been read */ |
| | | #define NAND_BBT_SCANNED 0x40000000 |
| | | /* Nand scan has allocated controller struct */ |
| | | #define NAND_CONTROLLER_ALLOC 0x80000000 |
| | | |
| | | /* Cell info constants */ |
| | | #define NAND_CI_CHIPNR_MSK 0x03 |
| | | #define NAND_CI_CELLTYPE_MSK 0x0C |
| | | |
| | | /* |
| | | * NAND Flash Manufacturer ID Codes |
| | | */ |
| | | #define NAND_MFR_TOSHIBA 0x98 |
| | | #define NAND_MFR_SAMSUNG 0xec |
| | | #define NAND_MFR_FUJITSU 0x04 |
| | | #define NAND_MFR_NATIONAL 0x8f |
| | | #define NAND_MFR_RENESAS 0x07 |
| | | #define NAND_MFR_STMICRO 0x20 |
| | | #define NAND_MFR_HYNIX 0xad |
| | | #define NAND_MFR_MICRON 0x2c |
| | | #define NAND_MFR_AMD 0x01 |
| | | |
| | | /* |
| | | * Constants for oob configuration |
| | | */ |
| | | #define NAND_SMALL_BADBLOCK_POS 5 |
| | | #define NAND_LARGE_BADBLOCK_POS 0 |
| | | |
| | | |
| | | #if defined(CONFIG_S3C2410) |
| | | #define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) |
| | | #define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x4) |
| | | #define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0x8) |
| | | #define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0xc) |
| | | #define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x10) |
| | | #define NFSTAT_BUSY 1 |
| | | #define nand_select() (REG_NFCONF &= ~0x800) /*Clear bit 11*/ |
| | | #define nand_deselect() (REG_NFCONF |= 0x800) |
| | | #define nand_clear_RnB() do {} while (0) |
| | | #define nand_detect_RnB() do {} while (0) |
| | | #define nand_wait_RnB() do {} while (0) |
| | | |
| | | #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) |
| | | |
| | | #define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) |
| | | #define REG_NFCONT __REGi(ELFIN_NAND_BASE + 0x4) |
| | | #define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x8) |
| | | #define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0xc) |
| | | #define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0x10) |
| | | #define REG_NFDATA16 __REGw(ELFIN_NAND_BASE + 0x10) |
| | | #define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x20) |
| | | #define NFSTAT_BUSY 1 |
| | | #define nand_select() (REG_NFCONT &= ~(1 << 1)) |
| | | #define nand_deselect() (REG_NFCONT |= (1 << 1)) |
| | | #define nand_clear_RnB() (REG_NFSTAT |= (1 << 2)) |
| | | #define nand_detect_RnB() {while(!(REG_NFSTAT&(1<<2)));} /*Wait Read & Busy signal goto high(not busy)*/ |
| | | #define nand_wait_RnB() {while(!(REG_NFSTAT&(1<<0)));} /*Wait nand flash not busy, wait bit[0] goes to 1*/ |
| | | |
| | | #endif |
| | | |
| | | #define SKIP_BAD_BLOCK 1 |
| | | #define NOT_SKIP_BAD_BLOCK 0 |
| | | |
| | | struct boot_nand_t |
| | | { |
| | | int page_size; |
| | | int spare_size; |
| | | int block_size; |
| | | int block_num; |
| | | int bad_block_offset; |
| | | int id; |
| | | // unsigned long size; |
| | | }; |
| | | |
| | | int nand_init(struct boot_nand_t *nand); |
| | | int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); |
| | | int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); |
| | | int is_bad_block(struct boot_nand_t *nand, ulong addr); |
| | | int mark_bad_block(struct boot_nand_t *nand, ulong addr); |
| | | int nand_erase_block(struct boot_nand_t *nand, ulong block_num); |
| | | int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad); |
| | | void nand_scrub(struct boot_nand_t *nand); |
| | | int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); |
| | | int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); |
| | | int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); |
| | | int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); |
| | | |
| | | |
| | | |
| | | #endif /* __LINUX_MTD_NAND_H */ |
New file |
| | |
| | | /* |
| | | * The RSA PK cryptosystem |
| | | * |
| | | * Copyright (C) 2006 Christophe Devine |
| | | * |
| | | * This library is free software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU Lesser General Public |
| | | * License, version 2.1 as published by the Free Software Foundation. |
| | | * |
| | | * This library is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| | | * MA 02110-1301 USA |
| | | */ |
| | | /* |
| | | * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. |
| | | * |
| | | * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf |
| | | * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf |
| | | */ |
| | | |
| | | #ifndef _CRT_SECURE_NO_DEPRECATE |
| | | #define _CRT_SECURE_NO_DEPRECATE 1 |
| | | #endif |
| | | |
| | | #include <common.h> |
| | | #include <rsa.h> |
| | | |
| | | #if !defined(NO_GENPRIME) |
| | | /* |
| | | * Generate an RSA keypair |
| | | */ |
| | | int rsa_gen_key( rsa_context *ctx, int nbits, int exponent, |
| | | int (*rng_f)(void *), void *rng_d ) |
| | | { |
| | | int ret; |
| | | mpi P1, Q1, H, G; |
| | | |
| | | if( nbits < 128 || exponent < 3 || rng_f == NULL ) |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | |
| | | mpi_init( &P1, &Q1, &H, &G, NULL ); |
| | | |
| | | memset( ctx, 0, sizeof( rsa_context ) ); |
| | | |
| | | /* |
| | | * find primes P and Q with Q < P so that: |
| | | * GCD( E, (P-1)*(Q-1) ) == 1 |
| | | */ |
| | | CHK( mpi_lset( &ctx->E, exponent ) ); |
| | | |
| | | nbits >>= 1; |
| | | |
| | | do |
| | | { |
| | | CHK( mpi_gen_prime( &ctx->P, nbits, 0, rng_f, rng_d ) ); |
| | | CHK( mpi_gen_prime( &ctx->Q, nbits, 0, rng_f, rng_d ) ); |
| | | |
| | | if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) |
| | | mpi_swap( &ctx->P, &ctx->Q ); |
| | | |
| | | if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) |
| | | continue; |
| | | |
| | | CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); |
| | | CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); |
| | | CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); |
| | | CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); |
| | | CHK( mpi_gcd( &G, &ctx->E, &H ) ); |
| | | } |
| | | while( mpi_cmp_int( &G, 1 ) != 0 ); |
| | | |
| | | /* |
| | | * D = E^-1 mod ((P-1)*(Q-1)) |
| | | * DP = D mod (P - 1) |
| | | * DQ = D mod (Q - 1) |
| | | * QP = Q^-1 mod P |
| | | */ |
| | | CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); |
| | | CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); |
| | | CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); |
| | | CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); |
| | | |
| | | ctx->len = ( mpi_size( &ctx->N ) + 7 ) >> 3; |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &P1, &Q1, &H, &G, NULL ); |
| | | |
| | | if( ret != 0 ) |
| | | { |
| | | rsa_free( ctx ); |
| | | return( ERR_RSA_KEY_GEN_FAILED | ret ); |
| | | } |
| | | |
| | | return( 0 ); |
| | | } |
| | | #endif |
| | | |
| | | /* |
| | | * Perform an RSA public key operation |
| | | */ |
| | | int rsa_public( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ) |
| | | { |
| | | int ret; |
| | | mpi T; |
| | | |
| | | // if( ilen != ctx->len || olen != ctx->len ) |
| | | // return( ERR_RSA_BAD_INPUT_DATA );
|
| | | |
| | | |
| | | mpi_init( &T, NULL ); |
| | | |
| | | CHK( mpi_import( &T, input, ilen ) ); |
| | | |
| | | if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) |
| | | { |
| | | mpi_free( &T, NULL ); |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | } |
| | | |
| | | CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); |
| | | CHK( mpi_export( &T, output, olen ) ); |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &T, NULL ); |
| | | |
| | | if( ret != 0 ) |
| | | return( ERR_RSA_PUBLIC_FAILED | ret ); |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Perform an RSA private key operation |
| | | */ |
| | | int rsa_private( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ) |
| | | { |
| | | int ret; |
| | | mpi T, T1, T2; |
| | | |
| | | //if( ilen != ctx->len || olen != ctx->len ) |
| | | // return( ERR_RSA_BAD_INPUT_DATA ); |
| | | |
| | | mpi_init( &T, &T1, &T2, NULL ); |
| | | |
| | | CHK( mpi_import( &T, input, ilen ) ); |
| | | |
| | | if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) |
| | | { |
| | | mpi_free( &T, NULL ); |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | } |
| | | |
| | | #if 0 |
| | | CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); |
| | | #else |
| | | /* |
| | | * faster decryption using the CRT |
| | | * |
| | | * T1 = input ^ dP mod P |
| | | * T2 = input ^ dQ mod Q |
| | | */ |
| | | CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); |
| | | CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); |
| | | |
| | | /* |
| | | * T = (T1 - T2) * (Q^-1 mod P) mod P |
| | | */ |
| | | CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); |
| | | CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); |
| | | CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); |
| | | |
| | | /* |
| | | * output = T2 + T * Q |
| | | */ |
| | | CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); |
| | | CHK( mpi_add_mpi( &T, &T2, &T1 ) ); |
| | | #endif |
| | | |
| | | CHK( mpi_export( &T, output, olen ) ); |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &T, &T1, &T2, NULL ); |
| | | |
| | | if( ret != 0 ) |
| | | return( ERR_RSA_PRIVATE_FAILED | ret ); |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Check if the public key is valid |
| | | */ |
| | | int rsa_check_pubkey( rsa_context *ctx ) |
| | | { |
| | | if( ( ctx->N.p[0] & 1 ) == 0 || |
| | | ( ctx->E.p[0] & 1 ) == 0 ) |
| | | return( ERR_RSA_KEY_CHK_FAILED ); |
| | | |
| | | if( mpi_size( &ctx->N ) < 128 || |
| | | mpi_size( &ctx->N ) > 4096 ) |
| | | return( ERR_RSA_KEY_CHK_FAILED ); |
| | | |
| | | if( mpi_size( &ctx->E ) < 2 || |
| | | mpi_size( &ctx->E ) > 64 ) |
| | | return( ERR_RSA_KEY_CHK_FAILED ); |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Check if the private key is valid |
| | | */ |
| | | int rsa_check_privkey( rsa_context *ctx ) |
| | | { |
| | | int ret = 0; |
| | | mpi TN, P1, Q1, H, G; |
| | | |
| | | mpi_init( &TN, &P1, &Q1, &H, &G, NULL ); |
| | | |
| | | CHK( mpi_mul_mpi( &TN, &ctx->P, &ctx->Q ) ); |
| | | CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); |
| | | CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); |
| | | CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); |
| | | CHK( mpi_gcd( &G, &ctx->E, &H ) ); |
| | | |
| | | if( mpi_cmp_mpi( &TN, &ctx->N ) == 0 && |
| | | mpi_cmp_int( &G, 1 ) == 0 ) |
| | | { |
| | | mpi_free( &TN, &P1, &Q1, &H, &G, NULL ); |
| | | return( 0 ); |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | mpi_free( &TN, &P1, &Q1, &H, &G, NULL ); |
| | | return( ERR_RSA_KEY_CHK_FAILED | ret ); |
| | | } |
| | | |
| | | /* |
| | | * Add the PKCS#1 v1.5 padding and do a public RSA |
| | | */ |
| | | int rsa_pkcs1_encrypt( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ) |
| | | { |
| | | int nb_pad; |
| | | unsigned char *p = output; |
| | | |
| | | if( *olen != ctx->len || *olen < ilen + 11 ) |
| | | { |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | } |
| | | |
| | | nb_pad = *olen - 3 - ilen; |
| | | |
| | | *p++ = 0; |
| | | *p++ = RSA_CRYPT; |
| | | |
| | | while( nb_pad-- > 0 ) |
| | | { |
| | | do { *p = rand(); } while( *p == 0 ); |
| | | p++; |
| | | } |
| | | |
| | | *p++ = 0; |
| | | memcpy( p, input, ilen ); |
| | | |
| | | return( rsa_public( ctx, output, *olen, output, olen ) ); |
| | | } |
| | | |
| | | /* |
| | | * Do a private RSA, removes the PKCS#1 v1.5 padding |
| | | */ |
| | | int rsa_pkcs1_decrypt( rsa_context *ctx, |
| | | unsigned char *input, int ilen, |
| | | unsigned char *output, int *olen ) |
| | | { |
| | | int ret; |
| | | unsigned char *p, buf[512]; |
| | | |
| | | if( ilen != ctx->len || ilen < 16 || ilen > 512 ) |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | |
| | | if( ( ret = rsa_private( ctx, input, ilen, buf, &ilen ) ) != 0 ) |
| | | return( ret ); |
| | | |
| | | p = buf; |
| | | |
| | | if( *p++ != 0 || *p++ != RSA_CRYPT ) |
| | | return( ERR_RSA_INVALID_PADDING ); |
| | | |
| | | while( *p != 0 ) |
| | | { |
| | | if( p >= buf + ilen - 1 ) |
| | | return( ERR_RSA_INVALID_PADDING ); |
| | | p++; |
| | | } |
| | | p++; |
| | | |
| | | if( *olen < ilen - (int)(p - buf) ) |
| | | return( ERR_RSA_INVALID_PADDING ); |
| | | |
| | | *olen = ilen - (int)(p - buf); |
| | | memcpy( output, p, *olen ); |
| | | |
| | | return( 0 ); |
| | | } |
| | | |
| | | /* |
| | | * Perform a private RSA to sign a message digest |
| | | */ |
| | | int rsa_pkcs1_sign( rsa_context *ctx, int alg_id, |
| | | unsigned char *hash, int hashlen, |
| | | unsigned char *sig, int siglen ) |
| | | { |
| | | int nb_pad; |
| | | unsigned char *p = sig; |
| | | |
| | | if( siglen != ctx->len || siglen < 16 ) |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | |
| | | switch( alg_id ) |
| | | { |
| | | case RSA_RAW: |
| | | nb_pad = siglen - 3 - hashlen; |
| | | break; |
| | | |
| | | case RSA_MD2: |
| | | case RSA_MD4: |
| | | case RSA_MD5: |
| | | nb_pad = siglen - 3 - 34; |
| | | break; |
| | | |
| | | case RSA_SHA1: |
| | | nb_pad = siglen - 3 - 35; |
| | | break; |
| | | |
| | | default: |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | } |
| | | |
| | | if( nb_pad < 8 ) |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | |
| | | *p++ = 0; |
| | | *p++ = RSA_SIGN; |
| | | |
| | | memset( p, 0xFF, nb_pad ); |
| | | p += nb_pad; |
| | | *p++ = 0; |
| | | |
| | | switch( alg_id ) |
| | | { |
| | | case RSA_RAW: |
| | | memcpy( p, hash, hashlen ); |
| | | break; |
| | | |
| | | case RSA_MD2: |
| | | memcpy( p, ASN1_HASH_MDX, 18 ); |
| | | memcpy( p + 18, hash, 16 ); |
| | | p[13] = 2; break; |
| | | |
| | | case RSA_MD4: |
| | | memcpy( p, ASN1_HASH_MDX, 18 ); |
| | | memcpy( p + 18, hash, 16 ); |
| | | p[13] = 4; break; |
| | | |
| | | case RSA_MD5: |
| | | memcpy( p, ASN1_HASH_MDX, 18 ); |
| | | memcpy( p + 18, hash, 16 ); |
| | | p[13] = 5; break; |
| | | |
| | | case RSA_SHA1: |
| | | memcpy( p, ASN1_HASH_SHA1, 15 ); |
| | | memcpy( p + 15, hash, 20 ); |
| | | break; |
| | | |
| | | default: |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | } |
| | | |
| | | return( rsa_private( ctx, sig, siglen, sig, &siglen ) ); |
| | | } |
| | | |
| | | /* |
| | | * Perform a public RSA and check the message digest |
| | | */ |
| | | int rsa_pkcs1_verify( rsa_context *ctx, int alg_id, |
| | | unsigned char *hash, int hashlen, |
| | | unsigned char *sig, int siglen ) |
| | | { |
| | | int ret, len; |
| | | unsigned char *p, c, buf[512]; |
| | | |
| | | if( siglen != ctx->len || siglen < 16 || siglen > 512 ) |
| | | return( ERR_RSA_BAD_INPUT_DATA ); |
| | | |
| | | if( ( ret = rsa_public( ctx, sig, siglen, buf, &siglen ) ) != 0 ) |
| | | return( ret ); |
| | | |
| | | p = buf; |
| | | |
| | | if( *p++ != 0 || *p++ != RSA_SIGN ) |
| | | return( ERR_RSA_INVALID_PADDING ); |
| | | |
| | | while( *p != 0 ) |
| | | { |
| | | if( p >= buf + siglen - 1 || *p != 0xFF ) |
| | | return( ERR_RSA_INVALID_PADDING ); |
| | | p++; |
| | | } |
| | | p++; |
| | | |
| | | len = siglen - (int)( p - buf ); |
| | | |
| | | if( len == 34 ) |
| | | { |
| | | c = p[13]; |
| | | p[13] = 0; |
| | | |
| | | if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 ) |
| | | return( ERR_RSA_VERIFY_FAILED ); |
| | | |
| | | if( ( c == 2 && alg_id == RSA_MD2 ) || |
| | | ( c == 4 && alg_id == RSA_MD4 ) || |
| | | ( c == 5 && alg_id == RSA_MD5 ) ) |
| | | { |
| | | if( memcmp( p + 18, hash, 16 ) == 0 ) |
| | | return( 0 ); |
| | | else |
| | | return( ERR_RSA_VERIFY_FAILED ); |
| | | } |
| | | } |
| | | |
| | | if( len == 35 && alg_id == RSA_SHA1 ) |
| | | { |
| | | if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 && |
| | | memcmp( p + 15, hash, 20 ) == 0 ) |
| | | return( 0 ); |
| | | else |
| | | return( ERR_RSA_VERIFY_FAILED ); |
| | | } |
| | | |
| | | if( len == hashlen && alg_id == RSA_RAW ) |
| | | { |
| | | if( memcmp( p, hash, hashlen ) == 0 ) |
| | | return( 0 ); |
| | | else |
| | | return( ERR_RSA_VERIFY_FAILED ); |
| | | } |
| | | |
| | | return( ERR_RSA_INVALID_PADDING ); |
| | | } |
| | | |
| | | /* |
| | | * Free the components of an RSA key |
| | | */ |
| | | void rsa_free( rsa_context *ctx ) |
| | | { |
| | | mpi_free( &ctx->N, &ctx->E, &ctx->D, |
| | | &ctx->P, &ctx->Q, &ctx->DP, |
| | | &ctx->DQ, &ctx->QP, &ctx->RN, |
| | | &ctx->RP, &ctx->RQ, NULL ); |
| | | } |
| | | |
| | | //#include "md5.h" |
| | | |
| | | #define PTLEN 24 |
| | | #define CTLEN 128 |
| | | |
| | | /* |
| | | * Checkup routine |
| | | */ |
| | | int main ( void ) |
| | | { |
| | | int len; |
| | | rsa_context rsa; |
| | | unsigned char md5sum[16]; |
| | | unsigned char rsa_plaintext[PTLEN]; |
| | | unsigned char rsa_decrypted[PTLEN]; |
| | | unsigned char rsa_ciphertext[CTLEN]; |
| | | |
| | | memset( &rsa, 0, sizeof( rsa ) ); |
| | | |
| | | rsa.len = 128; |
| | | |
| | | mpi_read( &rsa.N , "9292758453063D803DD603D5E777D788" \ |
| | | "8ED1D5BF35786190FA2F23EBC0848AEA" \ |
| | | "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ |
| | | "7130B9CED7ACDF54CFC7555AC14EEBAB" \ |
| | | "93A89813FBF3C4F8066D2D800F7C38A8" \ |
| | | "1AE31942917403FF4946B0A83D3D3E05" \ |
| | | "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ |
| | | "5E94BB77B07507233A0BC7BAC8F90F79", 16 ); |
| | | |
| | | mpi_read( &rsa.E , "10001", 16 ); |
| | | mpi_read( &rsa.D , "24BF6185468786FDD303083D25E64EFC" \ |
| | | "66CA472BC44D253102F8B4A9D3BFA750" \ |
| | | "91386C0077937FE33FA3252D28855837" \ |
| | | "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ |
| | | "DF79C5CE07EE72C7F123142198164234" \ |
| | | "CABB724CF78B8173B9F880FC86322407" \ |
| | | "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ |
| | | "071513A1E85B5DFA031F21ECAE91A34D", 16 ); |
| | | |
| | | mpi_read( &rsa.P , "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ |
| | | "2C01CAD19EA484A87EA4377637E75500" \ |
| | | "FCB2005C5C7DD6EC4AC023CDA285D796" \ |
| | | "C3D9E75E1EFC42488BB4F1D13AC30A57", 16 ); |
| | | mpi_read( &rsa.Q , "C000DF51A7C77AE8D7C7370C1FF55B69" \ |
| | | "E211C2B9E5DB1ED0BF61D0D9899620F4" \ |
| | | "910E4168387E3C30AA1E00C339A79508" \ |
| | | "8452DD96A9A5EA5D9DCA68DA636032AF", 16 ); |
| | | |
| | | mpi_read( &rsa.DP, "C1ACF567564274FB07A0BBAD5D26E298" \ |
| | | "3C94D22288ACD763FD8E5600ED4A702D" \ |
| | | "F84198A5F06C2E72236AE490C93F07F8" \ |
| | | "3CC559CD27BC2D1CA488811730BB5725", 16 ); |
| | | mpi_read( &rsa.DQ, "4959CBF6F8FEF750AEE6977C155579C7" \ |
| | | "D8AAEA56749EA28623272E4F7D0592AF" \ |
| | | "7C1F1313CAC9471B5C523BFE592F517B" \ |
| | | "407A1BD76C164B93DA2D32A383E58357", 16 ); |
| | | mpi_read( &rsa.QP, "9AE7FBC99546432DF71896FC239EADAE" \ |
| | | "F38D18D2B2F0E2DD275AA977E2BF4411" \ |
| | | "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ |
| | | "A74206CEC169D74BF5A8C50D6F48EA08", 16 ); |
| | | |
| | | printf( " RSA key validation: " ); |
| | | |
| | | if( rsa_check_pubkey( &rsa ) != 0 || |
| | | rsa_check_privkey( &rsa ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | |
| | | printf( "passed\n PKCS#1 encryption : " ); |
| | | |
| | | memcpy( rsa_plaintext, |
| | | "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ |
| | | "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD", PTLEN ); |
| | | |
| | | len = CTLEN; |
| | | if( rsa_pkcs1_encrypt( &rsa, rsa_plaintext, PTLEN, |
| | | rsa_ciphertext, &len ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | |
| | | printf( "passed\n PKCS#1 decryption : " ); |
| | | |
| | | len = sizeof( rsa_decrypted ); |
| | | |
| | | if( rsa_pkcs1_decrypt( &rsa, rsa_ciphertext, CTLEN, |
| | | rsa_decrypted, &len ) != 0 || |
| | | memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | |
| | | printf( "passed\n" ); |
| | | |
| | | #if 0 |
| | | md5_csum( rsa_plaintext, PTLEN, md5sum ); |
| | | |
| | | if( rsa_pkcs1_sign( &rsa, RSA_MD5, md5sum, 16, |
| | | rsa_ciphertext, CTLEN ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | |
| | | printf( "passed\n PKCS#1 sig. verify: " ); |
| | | |
| | | if( rsa_pkcs1_verify( &rsa, RSA_MD5, md5sum, 16, |
| | | rsa_ciphertext, CTLEN ) != 0 ) |
| | | { |
| | | printf( "failed\n" ); |
| | | return( 1 ); |
| | | } |
| | | |
| | | printf( "passed\n\n" ); |
| | | #endif |
| | | |
| | | rsa_free( &rsa ); |
| | | return( 0 ); |
| | | } |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: serial.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: The UART on board drivers/functions. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #include <common.h> |
| | | #define GPHCON (*(unsigned long volatile *)0x56000070) |
| | | |
| | | void serial_init(void) |
| | | { |
| | | S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; |
| | | |
| | | /*Enable UART0,UART1,UART2 */ |
| | | GPHCON = 0x0000aaaa; |
| | | |
| | | /*Set Parity, Stopbit etc. */ |
| | | uart->ULCON &= 0XFFFFFF00; |
| | | uart->ULCON |= 0X03; |
| | | |
| | | /*Disable modem */ |
| | | uart->UMCON = 0x0; |
| | | |
| | | /*Set UART FIFO control register */ |
| | | uart->UFCON = 0x00; |
| | | uart->UCON = 0x805; /*Enable FIFO */ |
| | | |
| | | /* |
| | | * UBRDIV = (UART Clock)/(baudrate*16) -1 |
| | | * = (50 000 000)/(115200*16) -1 |
| | | * = 26 |
| | | * = 0x1A |
| | | */ |
| | | uart->UBRDIV = 0x1A; |
| | | } |
| | | |
| | | void serial_send_byte(char c) |
| | | { |
| | | S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; |
| | | /* wait for room in the tx FIFO */ |
| | | while (!(uart->UTRSTAT & 0x2)) ; |
| | | |
| | | uart->UTXH = c; |
| | | |
| | | if (c == '\n') /* If \n, also do \r */ |
| | | serial_send_byte('\r'); |
| | | } |
| | | |
| | | int serial_is_recv_enable(void) |
| | | { |
| | | S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; |
| | | return uart->UTRSTAT & 0x1; |
| | | } |
| | | |
| | | int serial_recv_byte(void) |
| | | { |
| | | S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; |
| | | |
| | | /* wait for character to arrive */ |
| | | while (!(uart->UTRSTAT & 0x1)) ; |
| | | |
| | | return uart->URXH & 0xff; |
| | | } |
| | | |
| | | void serial_puts(const char *s) |
| | | { |
| | | while (*s) |
| | | { |
| | | serial_send_byte(*s++); |
| | | } |
| | | } |
New file |
| | |
| | | |
| | | /******************************************************************************************** |
| | | * File: start.S - Startup Code for ARM920 CPU-core |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: When system power up, the CPU will comes here to excute the first code here. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | |
| | | /* |
| | | ************************************************************************* |
| | | * |
| | | * Jump vector table as in table 3.1 in [1] |
| | | * |
| | | ************************************************************************* |
| | | */ |
| | | |
| | | #include <config.h> |
| | | |
| | | .globl _start |
| | | _start: b start_code |
| | | ldr pc, _undefined_instruction |
| | | ldr pc, _software_interrupt |
| | | ldr pc, _prefetch_abort |
| | | ldr pc, _data_abort |
| | | ldr pc, _not_used |
| | | ldr pc, _irq |
| | | ldr pc, _fiq |
| | | |
| | | _undefined_instruction: .word undefined_instruction |
| | | _software_interrupt: .word software_interrupt |
| | | _prefetch_abort: .word prefetch_abort |
| | | _data_abort: .word data_abort |
| | | _not_used: .word not_used |
| | | _irq: .word irq |
| | | _fiq: .word fiq |
| | | |
| | | .balignl 16,0xdeadbeef |
| | | |
| | | |
| | | /* |
| | | ************************************************************************* |
| | | * |
| | | * Startup Code (called from the ARM reset exception vector) |
| | | * |
| | | * do important init only if we don't start from memory! |
| | | * relocate armboot to ram |
| | | * setup stack |
| | | * jump to second stage |
| | | * |
| | | ************************************************************************* |
| | | */ |
| | | |
| | | _TEXT_BASE: |
| | | .word TEXT_BASE |
| | | |
| | | .globl _armboot_start |
| | | _armboot_start: |
| | | .word _start |
| | | |
| | | /* |
| | | * These are defined in the board-specific linker script. |
| | | */ |
| | | .globl _bss_start |
| | | _bss_start: |
| | | .word __bss_start |
| | | |
| | | .globl _bss_end |
| | | _bss_end: |
| | | .word _end |
| | | |
| | | /* |
| | | * the actual start code |
| | | */ |
| | | |
| | | start_code: |
| | | /* |
| | | * set the cpu to SVC32 mode |
| | | */ |
| | | mrs r0, cpsr |
| | | bic r0, r0, #0x1f |
| | | orr r0, r0, #0xd3 |
| | | msr cpsr, r0 |
| | | |
| | | /* Disable watchdog */ |
| | | ldr r0, =ELFIN_WATCHDOG_BASE |
| | | mov r1, #0 |
| | | str r1, [r0] |
| | | |
| | | /* Disable Interrupt */ |
| | | ldr r0, =ELFIN_INTERRUPT_BASE |
| | | mov r1, #0xffffffff |
| | | str r1, [r0, #INTMSK_OFFSET] |
| | | ldr r1, =0x000007ff |
| | | str r1, [r0, #INTSUBMSK_OFFSET] |
| | | |
| | | /* flush v4 I/D caches */ |
| | | mov r0, #0 |
| | | mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ |
| | | mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ |
| | | |
| | | /* disable MMU stuff and caches */ |
| | | mrc p15, 0, r0, c1, c0, 0 |
| | | bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) |
| | | bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) |
| | | orr r0, r0, #0x00000002 @ set bit 2 (A) Align |
| | | orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache |
| | | mcr p15, 0, r0, c1, c0, 0 |
| | | |
| | | |
| | | /******************************************************************************************* |
| | | * Init system clock and power, FCLK:HCLK:PCLK = 1:4:8 |
| | | * Reference to S3C2440 datasheet: Chap 7 Clock&Power Management |
| | | * |
| | | * Initialize System Clock FCLK=400MHz HCLK=100MHz PCLK=50MHz |
| | | * FCLK is used by ARM920T |
| | | * HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, |
| | | * the interrupt controller, the LCD controller, the DMA and USB host block. |
| | | * PCLK is is used for APB bus,which is used by the peripherals such as WDT,IIS,I2C, |
| | | * PWM timer,MMC interface,ADC,UART,GPIO,RTC and SPI. |
| | | ******************************************************************************************/ |
| | | |
| | | /*Set LOCKTIME as default value 0x00ffffff*/ |
| | | ldr r0, =ELFIN_CLOCK_POWER_BASE |
| | | ldr r1, =0x00ffffff |
| | | str r1, [r0, #LOCKTIME_OFFSET] |
| | | |
| | | /******************************************************************************************* |
| | | * Reference to S3C2440 datasheet: Chap 7-8 ~ Page 242 |
| | | * |
| | | * Set the selection of Dividing Ratio between FCLK,HCLK and PCLK as FCLK:HCLK:PCLK = 1:4:8. |
| | | * This ratio is determined by HDIVN(here is 2) and PDIVN(here is 1) control register. |
| | | * Refer to the s3c2440 datasheet |
| | | *******************************************************************************************/ |
| | | ldr r0, =ELFIN_CLOCK_POWER_BASE |
| | | mov r1, #5 |
| | | str r1, [r0, #CLKDIVN_OFFSET] /*Set Clock Divider*/ |
| | | |
| | | mrc p15, 0, r1, c1, c0, 0 |
| | | orr r1, r1, #0xc0000000 |
| | | mcr p15, 0, r1, c1, c0, 0 |
| | | |
| | | /*************************************************************************************** |
| | | * Reference to S3C2440 datasheet: Chap 7-20 ~ Page 254 |
| | | * |
| | | * Set MPLLCON(0x4C000004) register as: |
| | | * [19:12]: MDIV(Main Divider control)=0x7F (value set in MDIV_405) |
| | | * [9:4]: PDIV(Pre-devider control)=0x02 (value set in PSDIV_405) |
| | | * [1:0]: SDIV(Post divider control)=0x01 (value set in PSDIV_405) |
| | | * |
| | | * MPLL(FCLK) = (2 * m * Fin)/(p * 2^s) |
| | | * m=(MDIV+8), p=(PDIV+2), s=SDIV |
| | | * |
| | | * So FCLK=((2*(127+8)*Fin)) / ((2+2)*2^1) |
| | | * = (2*135*12MHz)/8 |
| | | * = 405MHz |
| | | * For FCLK:HCLK:PCLK=1:4:8, so HCLK=100MHz, PCLK=50MHz |
| | | ***************************************************************************************/ |
| | | mov r1, #ELFIN_CLOCK_POWER_BASE |
| | | mov r2, #MDIV_405 |
| | | add r2, r2, #PSDIV_405 |
| | | str r2, [r1, #MPLLCON_OFFSET] |
| | | |
| | | /* Go to mem_init.S to Init memory controller register */ |
| | | bl mem_init |
| | | |
| | | /* Set up the stack */ |
| | | stack_setup: |
| | | ldr r0, =STACK_BASE /* upper 128 KiB: relocated uboot */ |
| | | sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ |
| | | sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */ |
| | | sub sp, r0, #12 /* leave 3 words for abort-stack */ |
| | | bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ |
| | | |
| | | clear_bss: |
| | | ldr r0, _bss_start /* find start of bss segment */ |
| | | ldr r1, _bss_end /* stop here */ |
| | | mov r2, #0x00000000 /* clear */ |
| | | |
| | | clbss_l:str r2, [r0] /* clear loop... */ |
| | | add r0, r0, #4 |
| | | cmp r0, r1 |
| | | ble clbss_l |
| | | |
| | | #if 0 /*Don't wanna init BEEP & LED here*/ |
| | | bl init_led_beep |
| | | |
| | | /* |
| | | * R0,R1,R2 are the 1st,2nd, 3rd argument passed to C function |
| | | * If need pass more than 3 arguments, then we need use stack. |
| | | */ |
| | | mov r0,#LED1 |
| | | bl turn_led_on |
| | | #endif |
| | | |
| | | bl bootstrap_main |
| | | |
| | | /* |
| | | ************************************************************************* |
| | | * |
| | | * Interrupt handling |
| | | * |
| | | ************************************************************************* |
| | | */ |
| | | |
| | | @ |
| | | @ IRQ stack frame. |
| | | @ |
| | | #define S_FRAME_SIZE 72 |
| | | |
| | | #define S_OLD_R0 68 |
| | | #define S_PSR 64 |
| | | #define S_PC 60 |
| | | #define S_LR 56 |
| | | #define S_SP 52 |
| | | |
| | | #define S_IP 48 |
| | | #define S_FP 44 |
| | | #define S_R10 40 |
| | | #define S_R9 36 |
| | | #define S_R8 32 |
| | | #define S_R7 28 |
| | | #define S_R6 24 |
| | | #define S_R5 20 |
| | | #define S_R4 16 |
| | | #define S_R3 12 |
| | | #define S_R2 8 |
| | | #define S_R1 4 |
| | | #define S_R0 0 |
| | | |
| | | #define MODE_SVC 0x13 |
| | | #define I_BIT 0x80 |
| | | |
| | | /* |
| | | * use bad_save_user_regs for abort/prefetch/undef/swi ... |
| | | * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling |
| | | */ |
| | | |
| | | .macro bad_save_user_regs |
| | | sub sp, sp, #S_FRAME_SIZE |
| | | stmia sp, {r0 - r12} @ Calling r0-r12 |
| | | ldr r2, _armboot_start |
| | | sub r2, r2, #(CONFIG_STACKSIZE) |
| | | sub r2, r2, #(CONFIG_SYS_MALLOC_LEN) |
| | | /* set base 2 words into abort stack */ |
| | | sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8) |
| | | ldmia r2, {r2 - r3} @ get pc, cpsr |
| | | add r0, sp, #S_FRAME_SIZE @ restore sp_SVC |
| | | |
| | | add r5, sp, #S_SP |
| | | mov r1, lr |
| | | stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr |
| | | mov r0, sp |
| | | .endm |
| | | |
| | | .macro irq_save_user_regs |
| | | sub sp, sp, #S_FRAME_SIZE |
| | | stmia sp, {r0 - r12} @ Calling r0-r12 |
| | | add r7, sp, #S_PC |
| | | stmdb r7, {sp, lr}^ @ Calling SP, LR |
| | | str lr, [r7, #0] @ Save calling PC |
| | | mrs r6, spsr |
| | | str r6, [r7, #4] @ Save CPSR |
| | | str r0, [r7, #8] @ Save OLD_R0 |
| | | mov r0, sp |
| | | .endm |
| | | |
| | | .macro irq_restore_user_regs |
| | | ldmia sp, {r0 - lr}^ @ Calling r0 - lr |
| | | mov r0, r0 |
| | | ldr lr, [sp, #S_PC] @ Get PC |
| | | add sp, sp, #S_FRAME_SIZE |
| | | /* return & move spsr_svc into cpsr */ |
| | | subs pc, lr, #4 |
| | | .endm |
| | | |
| | | .macro get_bad_stack |
| | | ldr r13, _armboot_start @ setup our mode stack |
| | | sub r13, r13, #(CONFIG_STACKSIZE) |
| | | sub r13, r13, #(CONFIG_SYS_MALLOC_LEN) |
| | | /* reserve a couple spots in abort stack */ |
| | | sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) |
| | | |
| | | str lr, [r13] @ save caller lr / spsr |
| | | mrs lr, spsr |
| | | str lr, [r13, #4] |
| | | |
| | | mov r13, #MODE_SVC @ prepare SVC-Mode |
| | | @ msr spsr_c, r13 |
| | | msr spsr, r13 |
| | | mov lr, pc |
| | | movs pc, lr |
| | | .endm |
| | | |
| | | .macro get_irq_stack @ setup IRQ stack |
| | | ldr sp, IRQ_STACK_START |
| | | .endm |
| | | |
| | | .macro get_fiq_stack @ setup FIQ stack |
| | | ldr sp, FIQ_STACK_START |
| | | .endm |
| | | |
| | | /* |
| | | * exception handlers |
| | | */ |
| | | .align 5 |
| | | undefined_instruction: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_undefined_instruction |
| | | |
| | | .align 5 |
| | | software_interrupt: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_software_interrupt |
| | | |
| | | .align 5 |
| | | prefetch_abort: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_prefetch_abort |
| | | |
| | | .align 5 |
| | | data_abort: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_data_abort |
| | | |
| | | .align 5 |
| | | not_used: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_not_used |
| | | |
| | | .align 5 |
| | | irq: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_irq |
| | | |
| | | .align 5 |
| | | fiq: |
| | | get_bad_stack |
| | | bad_save_user_regs |
| | | bl do_fiq |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: xmodem.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: Xmodem protocal used to download the second stage bootloader(launcher) |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #include <common.h> |
| | | |
| | | #define XMODEM_SOH 0x01 /*Start Of Header, standard Xmodem */ |
| | | #define XMODEM_STX 0x02 /*1K-Modem start Xmodem */ |
| | | #define XMODEM_EOT 0x04 /*End Of Transmission */ |
| | | #define XMODEM_ACK 0x06 |
| | | #define XMODEM_NAK 0x15 |
| | | #define XMODEM_CAN 0x18 /*Stop transmission */ |
| | | #define XMODEM_EOF 0x1a /*CTRL+Z EOF */ |
| | | |
| | | #define XMODEM_BLOCK_SIZE 128 |
| | | |
| | | static int xmodem_wait(void) |
| | | { |
| | | long cnt = 0; |
| | | |
| | | while (!serial_is_recv_enable()) |
| | | { |
| | | if (++cnt >= 2000000) |
| | | { |
| | | cnt = 0; |
| | | serial_send_byte(XMODEM_NAK); |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static int xmodem_read_block(unsigned char block_number, char *buf) |
| | | { |
| | | unsigned char c, block_num, check_sum; |
| | | int i; |
| | | |
| | | block_num = serial_recv_byte(); |
| | | if (block_num != block_number) |
| | | return -1; |
| | | |
| | | block_num ^= serial_recv_byte(); |
| | | if (block_num != 0xff) |
| | | return -1; |
| | | |
| | | check_sum = 0; |
| | | for (i = 0; i < XMODEM_BLOCK_SIZE; i++) |
| | | { |
| | | c = serial_recv_byte(); |
| | | *(buf++) = c; |
| | | check_sum += c; |
| | | } |
| | | |
| | | check_sum ^= serial_recv_byte(); |
| | | if (check_sum) |
| | | return -1; |
| | | |
| | | return i; |
| | | } |
| | | |
| | | long xmodem_recv(char *buf) |
| | | { |
| | | int r, receiving = 0; |
| | | long size = 0; |
| | | unsigned char c, block_number = 1; |
| | | |
| | | while (1) |
| | | { |
| | | if (!receiving) |
| | | xmodem_wait(); |
| | | |
| | | c = serial_recv_byte(); |
| | | |
| | | switch (c) |
| | | { |
| | | case XMODEM_EOT: |
| | | serial_send_byte(XMODEM_ACK); |
| | | |
| | | /*Remove the CMPEOF */ |
| | | long cnt = 0; |
| | | if ((buf[-1] == XMODEM_EOF) && (buf[-2] == XMODEM_EOF) && (buf[-3] == XMODEM_EOF)) |
| | | { |
| | | while (size && buf[-cnt - 1] == XMODEM_EOF) |
| | | cnt++; |
| | | } |
| | | |
| | | size -= cnt; |
| | | goto RECV_OK; |
| | | |
| | | case XMODEM_CAN: |
| | | return -1; |
| | | |
| | | case XMODEM_SOH: |
| | | receiving++; |
| | | r = xmodem_read_block(block_number, buf); |
| | | if (r < 0) |
| | | { |
| | | serial_send_byte(XMODEM_NAK); |
| | | } |
| | | else |
| | | { |
| | | block_number++; |
| | | size += r; |
| | | buf += r; |
| | | serial_send_byte(XMODEM_ACK); |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | if (receiving) |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | RECV_OK: |
| | | return size; |
| | | } |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: bootstrap.c |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This C code is the first stage bootloader(named bootstrap) |
| | | main code, test on FL2440 board. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <malloc.h> |
| | | #include "yaffsfs.h" |
| | | #include "s3c_board.h" |
| | | |
| | | #define MALLOC_SIZE 20 |
| | | |
| | | int mkdir(const char *mp, const char *name) |
| | | { |
| | | char full_name[100]; |
| | | sprintf(full_name, "%s/%s", mp, name); |
| | | printf("Create directory [%s]\n", full_name); |
| | | return yaffs_mkdir(full_name, S_IREAD| S_IWRITE); |
| | | } |
| | | |
| | | int mkfile(const char *mp, const char *name) |
| | | { |
| | | char full_name[100]; |
| | | char buf[100]; |
| | | int h; |
| | | |
| | | sprintf(full_name, "%s/%s", mp, name); |
| | | |
| | | h = yaffs_open(full_name, O_RDWR | O_CREAT | O_TRUNC, S_IREAD| S_IWRITE); |
| | | yaffs_write(h, name, strlen(name)); |
| | | yaffs_lseek(h, 0, SEEK_SET); |
| | | memset(buf, 0, sizeof(buf)); |
| | | yaffs_read(h, buf, sizeof(buf)); |
| | | printf("Create File [%s] content: [%s]\n", full_name, buf); |
| | | yaffs_close(h); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int rm(const char *mp, const char *name) |
| | | { |
| | | char full_name[100]; |
| | | |
| | | if(name) |
| | | sprintf(full_name, "%s/%s", mp, name); |
| | | else |
| | | strcpy(full_name, mp); |
| | | |
| | | printf("Remove %s\n", full_name); |
| | | return yaffs_rm(full_name, 1); |
| | | } |
| | | |
| | | int ls(const char *mp, const char *name) |
| | | { |
| | | int recursive = 1; |
| | | char full_name[100]; |
| | | |
| | | if(name) |
| | | sprintf(full_name, "%s/%s", mp, name); |
| | | else |
| | | strcpy(full_name, mp); |
| | | |
| | | printf("List folder '%s' %s recursive:\n", full_name, recursive?"with":"without"); |
| | | return yaffs_ls(full_name, recursive); |
| | | } |
| | | |
| | | |
| | | void dump_directory_tree_worker(const char *dname,int recursive) |
| | | { |
| | | yaffs_DIR *d; |
| | | struct yaffs_dirent *de; |
| | | struct yaffs_stat s; |
| | | char str[1000]; |
| | | |
| | | d = yaffs_opendir(dname); |
| | | |
| | | if(!d) |
| | | { |
| | | printf("opendir failed\n"); |
| | | } |
| | | else |
| | | { |
| | | while((de = yaffs_readdir(d)) != NULL) |
| | | { |
| | | sprintf(str,"%s/%s",dname,de->d_name); |
| | | |
| | | yaffs_lstat(str,&s); |
| | | |
| | | printf("%s inode %d obj %x length %lld mode %X ", |
| | | str,s.st_ino,de->d_dont_use, s.st_size,s.st_mode); |
| | | switch(s.st_mode & S_IFMT) |
| | | { |
| | | case S_IFREG: printf("data file"); break; |
| | | case S_IFDIR: printf("directory"); break; |
| | | case S_IFLNK: printf("symlink -->"); |
| | | if(yaffs_readlink(str,str,100) < 0) |
| | | printf("no alias"); |
| | | else |
| | | printf("\"%s\"",str); |
| | | break; |
| | | default: printf("unknown"); break; |
| | | } |
| | | printf("\n"); |
| | | |
| | | if((s.st_mode & S_IFMT) == S_IFDIR && recursive) |
| | | dump_directory_tree_worker(str,1); |
| | | } |
| | | |
| | | yaffs_closedir(d); |
| | | } |
| | | } |
| | | |
| | | |
| | | static void dump_directory_tree(const char *dname) |
| | | { |
| | | dump_directory_tree_worker(dname,1); |
| | | printf("\n"); |
| | | printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); |
| | | } |
| | | |
| | | void dumpDir(const char *dname) |
| | | { |
| | | dump_directory_tree_worker(dname,0); |
| | | printf("\n"); |
| | | printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); |
| | | } |
| | | |
| | | |
| | | void yaffs_test(const char *mountpt) |
| | | { |
| | | yaffs_start_up(); |
| | | |
| | | #if 0 |
| | | yaffs_mount(mountpt); |
| | | ls(mountpt, NULL); |
| | | |
| | | mkdir(mountpt, "foo"); |
| | | mkfile(mountpt, "foo/f1"); |
| | | |
| | | return ; |
| | | #endif |
| | | |
| | | yaffs_format(mountpt,0,0,0); |
| | | |
| | | yaffs_mount(mountpt); |
| | | printf("'%s' mounted\n", mountpt); |
| | | |
| | | mkdir(mountpt, "foo"); |
| | | mkfile(mountpt, "foo/f1"); |
| | | |
| | | mkfile(mountpt, "foo/f2"); |
| | | mkfile(mountpt, "foo/f3"); |
| | | mkfile(mountpt, "foo/f4"); |
| | | |
| | | mkdir(mountpt, "bar"); |
| | | mkfile(mountpt, "bar/f1"); |
| | | ls(mountpt, NULL); |
| | | |
| | | rm(mountpt, "foo/f4"); |
| | | rm(mountpt, "bar"); |
| | | ls(mountpt, NULL); |
| | | |
| | | printf("unmount and remount\n\n"); |
| | | |
| | | /* Unmount/remount yaffs_trace_mask */ |
| | | yaffs_unmount(mountpt); |
| | | yaffs_mount(mountpt); |
| | | ls(mountpt, NULL); |
| | | } |
| | | |
| | | int bootstrap_main(void) |
| | | { |
| | | char *ptr = NULL; |
| | | int rv = -1; |
| | | |
| | | console_serial_init(); |
| | | printf("\b\n"); |
| | | printf("\bBootstrap nandflash yaffs2 test Version 0.0.1\n"); |
| | | |
| | | /* armboot_start is defined in the board-specific linker script */ |
| | | mem_malloc_init (TEXT_BASE - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN); |
| | | |
| | | ptr = (char *)malloc(MALLOC_SIZE); |
| | | strncpy(ptr, "Hello World!\n", MALLOC_SIZE); |
| | | printf("Malloc address: %p, string: %s\n", ptr, ptr); |
| | | free(ptr); |
| | | |
| | | yaffs_test(YAFFSFS_MNT_POINT); |
| | | |
| | | hang: |
| | | while(1) |
| | | ; |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: bootstrap.lds |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: This is the LD linker configure script for bootstrap |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") |
| | | OUTPUT_ARCH(arm) |
| | | ENTRY(_start) |
| | | |
| | | SECTIONS{ |
| | | . = ALIGN(4); |
| | | .text : |
| | | { |
| | | start.o (.text) |
| | | *(.text) |
| | | } |
| | | . = ALIGN(4); |
| | | .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } |
| | | . = ALIGN(4); |
| | | .rodata : { *(.rodata) } |
| | | . = ALIGN(4); |
| | | .data : { *(.data) } |
| | | . = ALIGN(4); |
| | | __bss_start = .; |
| | | .bss : { *(.bss) } |
| | | _end = .; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | * Utility functions needed for (some) EABI conformant tool chains. |
| | | * |
| | | * (C) Copyright 2009 Wolfgang Denk <wd@denx.de> |
| | | * |
| | | * This program is Free Software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU General Public License as |
| | | * published by the Free Software Foundation; either version 2 of the |
| | | * License, or (at your option) any later version. |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | |
| | | #if 1 |
| | | int raise (int signum) |
| | | { |
| | | // printf("raise: Signal # %d caught\n", signum); |
| | | return 0; |
| | | } |
| | | |
| | | /* Dummy function to avoid linker complaints */ |
| | | void __aeabi_unwind_cpp_pr0(void) |
| | | { |
| | | }; |
| | | #else |
| | | void __aeabi_unwind_cpp_pr1(void) |
| | | { |
| | | }; |
| | | #endif |
New file |
| | |
| | | /*
|
| | | | ECC MAIN | BAD | RES | YAFFS_TAG |
|
| | | | 4 | 4 | 8 | 48 |
|
| | | */
|
| | |
|
| | | #include "k9f2g08_s3c.h"
|
| | |
|
| | | /* From yaffs_guts.h */
|
| | | #define YAFFS_OK 1
|
| | | #define YAFFS_FAIL 0
|
| | |
|
| | |
|
| | | int k9f2g08_init(void)
|
| | | {
|
| | | return YAFFS_OK;
|
| | | }
|
| | |
|
| | | int k9f2g08_deinit(void)
|
| | | {
|
| | | return YAFFS_OK;
|
| | | }
|
| | |
|
| | | static unsigned char wait_busy_status(void)
|
| | | {
|
| | | unsigned char rc;
|
| | |
|
| | | for (rc=0; rc <40; rc++);
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x70); // read status
|
| | | do {
|
| | | rc = bsp_nand_read_data8();
|
| | | } while ((rc & (1<<6)) == 0);
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | return rc;
|
| | | }
|
| | |
|
| | | int k9f2g08_mark_block_bad(unsigned int blk_num)
|
| | | {
|
| | | int row_addr = blk_num * 64;
|
| | | int col_addr = 2048;
|
| | |
|
| | | unsigned char status;
|
| | |
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x80); // write command
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(row_addr >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(row_addr >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(row_addr >> 16));
|
| | |
|
| | | bsp_nand_write_data32(0xFFFFFFFF);
|
| | | bsp_nand_write_data32(0x00000000);
|
| | | bsp_nand_write_data32(0xFFFFFFFF);
|
| | | bsp_nand_write_data32(0xFFFFFFFF);
|
| | | bsp_nand_write_cmd(0x10);
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | status = wait_busy_status();
|
| | |
|
| | | return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK;
|
| | | }
|
| | |
|
| | | int k9f2g08_write(unsigned int chunk, const unsigned char *dat, const unsigned char *spare, unsigned int spare_size)
|
| | | {
|
| | | int i;
|
| | | int col_addr;
|
| | | unsigned char status;
|
| | |
|
| | | if (dat) {
|
| | | col_addr = 0;
|
| | | } else {
|
| | | col_addr = 2048;
|
| | | }
|
| | |
|
| | |
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x80); // write command
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 16));
|
| | |
|
| | | bsp_nand_start_main_ecc();
|
| | | if (dat) {
|
| | | for (i=0; i<2048; i++)
|
| | | bsp_nand_write_data8(*dat++);
|
| | | }
|
| | |
|
| | | bsp_nand_stop_main_ecc();
|
| | |
|
| | | bsp_nand_write_data32(bsp_nand_read_spare_ecc0());
|
| | | bsp_nand_write_data32(0xFFFFFFFF);
|
| | | bsp_nand_write_data32(0xFFFFFFFF);
|
| | | bsp_nand_write_data32(0xFFFFFFFF);
|
| | |
|
| | | if (spare) {
|
| | | for (i=0; i<spare_size; i++)
|
| | | bsp_nand_write_data8(*spare++);
|
| | | }
|
| | |
|
| | | bsp_nand_write_cmd(0x10);
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | status = wait_busy_status();
|
| | |
|
| | | return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK;
|
| | | }
|
| | |
|
| | | int k9f2g08_read(unsigned int chunk, unsigned char *dat, unsigned char *spare, unsigned int spare_size, int *eccStatus)
|
| | | {
|
| | | int i;
|
| | | int col_addr;
|
| | | unsigned char *p = dat;
|
| | | unsigned int ecc = 0;
|
| | | int err_bit;
|
| | | int err_byte;
|
| | |
|
| | | if (dat) {
|
| | | col_addr = 0;
|
| | | } else {
|
| | | col_addr = 2048 + 16;
|
| | | }
|
| | |
|
| | |
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x00); // read command
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 16));
|
| | | bsp_nand_write_cmd(0x30); // read
|
| | | bsp_nand_wait_busy();
|
| | |
|
| | | if (dat) {
|
| | | bsp_nand_start_main_ecc();
|
| | | for (i=0; i<2048; i++)
|
| | | *p++ = bsp_nand_read_data8();
|
| | |
|
| | | bsp_nand_stop_main_ecc();
|
| | |
|
| | | ecc = bsp_nand_read_data32();
|
| | |
|
| | | bsp_nand_read_data32();
|
| | | bsp_nand_read_data32();
|
| | | bsp_nand_read_data32();
|
| | | }
|
| | | if (spare) {
|
| | | p = spare;
|
| | | for (i=0; i<spare_size; i++)
|
| | | *p++ = bsp_nand_read_data8();
|
| | | }
|
| | |
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | if (dat) {
|
| | | i = bsp_nand_main_check_ecc(ecc, &err_byte, &err_bit);
|
| | | if (i == 0) {
|
| | | *eccStatus = 0;
|
| | | return 0;
|
| | | }
|
| | |
|
| | | if (i < 0) {
|
| | | *eccStatus = -1;
|
| | | return 0;
|
| | | }
|
| | |
|
| | | *eccStatus = 1;
|
| | | dat[err_byte] ^= (1<<err_bit);
|
| | | }
|
| | |
|
| | | return YAFFS_OK;
|
| | | }
|
| | |
|
| | | int k9f2g08_erase_block(unsigned int blk_num)
|
| | | {
|
| | | unsigned char status;
|
| | | int chunk = blk_num * 64;
|
| | |
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x60); // erase command
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 16));
|
| | | bsp_nand_write_cmd(0xD0); // erase
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | status = wait_busy_status();
|
| | | return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK;
|
| | | }
|
| | |
|
| | | int k9f2g08_is_block_ok(unsigned int blk_num)
|
| | | {
|
| | | int chunk = blk_num * 64;
|
| | | int col_addr = 2048 + 4;
|
| | |
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x00); // read command
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 16));
|
| | | bsp_nand_write_cmd(0x30); // read
|
| | | bsp_nand_wait_busy();
|
| | |
|
| | | int tmp = bsp_nand_read_data32();
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | if (tmp == 0xFFFFFFFF) {
|
| | | return 1;
|
| | | }
|
| | | return 0;
|
| | | }
|
| | |
|
| | |
|
| | | int k9f2g08_read_id(unsigned int *id)
|
| | | {
|
| | | int rc = -1;
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x90); // read command
|
| | | bsp_nand_write_addr((unsigned char)0);
|
| | | do {
|
| | | if ((rc = bsp_nand_read_data8()) != 0xEC)
|
| | | break;
|
| | | *id = bsp_nand_read_data32();
|
| | | rc = 0;
|
| | | } while(0);
|
| | |
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | return rc;
|
| | | }
|
| | |
|
| | | int k9f2g08_read_ll(unsigned int chunk, unsigned char *dat, unsigned char *spare)
|
| | | {
|
| | | int i;
|
| | | int col_addr;
|
| | | unsigned char *p;
|
| | |
|
| | | if (dat) {
|
| | | col_addr = 0;
|
| | | } else {
|
| | | col_addr = 2048;
|
| | | }
|
| | |
|
| | |
|
| | | bsp_nand_set_cs(0);
|
| | | bsp_nand_write_cmd(0x00); // read command
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(col_addr >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 0));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 8));
|
| | | bsp_nand_write_addr((unsigned char)(chunk >> 16));
|
| | | bsp_nand_write_cmd(0x30); // read
|
| | |
|
| | | bsp_nand_wait_busy();
|
| | |
|
| | | if (dat) {
|
| | | p = dat;
|
| | | for (i=0; i<2048; i++)
|
| | | *p++ = bsp_nand_read_data8();
|
| | | }
|
| | | if (spare) {
|
| | | p = spare;
|
| | | for (i=0; i<64; i++)
|
| | | *p++ = bsp_nand_read_data8();
|
| | | }
|
| | |
|
| | | bsp_nand_set_cs(1);
|
| | |
|
| | | return 1;
|
| | | }
|
New file |
| | |
| | | #ifndef __K9F2G08_API_H__
|
| | | #define __K9F2G08_API_H__
|
| | |
|
| | | int k9f2g08_init(void);
|
| | | int k9f2g08_deinit(void);
|
| | | int k9f2g08_mark_block_bad(unsigned int blk_num);
|
| | | int k9f2g08_write(unsigned int chunk, const unsigned char *dat, const unsigned char *spare, unsigned int spare_size);
|
| | | int k9f2g08_read(unsigned int chunk, unsigned char *dat, unsigned char *spare, unsigned int spare_size, int *eccStatus);
|
| | | int k9f2g08_read_ll(unsigned int chunk, unsigned char *dat, unsigned char *spare);
|
| | | int k9f2g08_erase_block(unsigned int blk_num);
|
| | | int k9f2g08_is_block_ok(unsigned int blk_num);
|
| | | int k9f2g08_read_id(unsigned int *id);
|
| | |
|
| | | #endif // __K9F2G08_API_H__
|
New file |
| | |
| | | #ifndef __K9F2G08_S3C_H__
|
| | | #define __K9F2G08_S3C_H__
|
| | |
|
| | | #include "s3c2440.h"
|
| | |
|
| | | static inline void bsp_init_nand(void)
|
| | | {
|
| | | unsigned int reg;
|
| | |
|
| | | struct s3c2440_clock_power *clkpwr = s3c2440_get_base_clock_power();
|
| | | clkpwr->CLKCON |= (1<<4);
|
| | |
|
| | | struct s3c2440_gpio *gpio = s3c2440_get_base_gpio();
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | |
|
| | | reg = gpio->GPACON;
|
| | | reg |= (1<<22) | (1<<20) | (1<<19) | (1<<18) | (1<<17);
|
| | | gpio->GPACON = reg;
|
| | |
|
| | | nand->NFCONF = (1<<12) | (1<<8) | (1<<4) | (1<<3) |(1<<2) | (1<<5) | (0<<0);
|
| | | nand->NFCONT = 3;
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_set_cs(int level)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | if (level == 0) {
|
| | | nand->NFCONT &= ~(1<<1);
|
| | | // while (nand->NFSTAT & (1<<1));
|
| | | } else {
|
| | | nand->NFCONT |= 1<<1;
|
| | | // while ((nand->NFSTAT & (1<<1)) == 0);
|
| | | }
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_start_main_ecc(void)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | nand->NFCONT |= (1<<6) | (1<<5); // unlock all
|
| | | nand->NFCONT |= (1<<4); // init ecc
|
| | | nand->NFCONT &= ~(1<<6); // lock spare
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_stop_main_ecc(void)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | nand->NFCONT |= (1<<5); // lock main
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_start_spare_ecc(void)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | nand->NFCONT &= ~(1<<6); // unlock spare
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_stop_spare_ecc(void)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | nand->NFCONT |= (1<<6); // lock spare
|
| | | }
|
| | |
|
| | | static inline int bsp_nand_spare_check_ecc(unsigned short ecc, int *err_byte, int *err_bit)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | unsigned int ecc_wr = ((ecc & 0xFF00) << 8) | (ecc & 0x00FF);
|
| | |
|
| | | nand->NFSECCD = ecc_wr;
|
| | | int err = nand->NFESTAT0;
|
| | |
|
| | | if ((err & (3<<2)) == (0<<2)) // no err
|
| | | return 0;
|
| | |
|
| | |
|
| | | if ((err & (3<<2)) == (1<<2)) { // 1 bit err
|
| | | *err_byte = (err >> 21) & 0x0F;
|
| | | *err_bit = (err >> 18) & 0x07;
|
| | | return 1;
|
| | | }
|
| | |
|
| | | return -1;
|
| | |
|
| | | }
|
| | |
|
| | | static inline int bsp_nand_main_check_ecc(unsigned int ecc, int *err_byte, int *err_bit)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | |
|
| | | unsigned int ecc_wr = ((ecc & 0xFF00) << 8) | (ecc & 0x00FF);
|
| | | nand->NFMECCD0 = ecc_wr;
|
| | |
|
| | | ecc_wr = ((ecc & 0xFF000000) >> 8) | ((ecc & 0x00FF0000) >> 16);
|
| | | nand->NFMECCD1 = ecc_wr;
|
| | |
|
| | | int err = nand->NFESTAT0;
|
| | |
|
| | | if ((err & (3<<0)) == (0<<0)) // no err
|
| | | return 0;
|
| | |
|
| | |
|
| | | if ((err & (3<<0)) == (1<<0)) { // no err
|
| | | *err_byte = (err >> 7) & 0x7FF;
|
| | | *err_bit = (err >> 4) & 0x07;
|
| | | return 1;
|
| | | }
|
| | |
|
| | | return -1;
|
| | | }
|
| | |
|
| | |
|
| | | static inline void bsp_nand_write_cmd(unsigned char cmd)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | nand->NFCMD = cmd;
|
| | | }
|
| | |
|
| | |
|
| | | static inline void bsp_nand_write_addr(unsigned char addr)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | nand->NFADDR = addr;
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_write_data32(unsigned int dat)
|
| | | {
|
| | | *(volatile unsigned int *)(&(s3c2440_get_base_nand()->NFDATA)) = dat;
|
| | | }
|
| | |
|
| | |
|
| | | static inline void bsp_nand_write_data16(unsigned short dat)
|
| | | {
|
| | | *(volatile unsigned short *)(&(s3c2440_get_base_nand()->NFDATA)) = dat;
|
| | | }
|
| | |
|
| | | static inline void bsp_nand_write_data8(unsigned char dat)
|
| | | {
|
| | | *(volatile unsigned char *)(&(s3c2440_get_base_nand()->NFDATA)) = dat;
|
| | | }
|
| | |
|
| | |
|
| | | static inline unsigned int bsp_nand_read_data32(void)
|
| | | {
|
| | | return *(volatile unsigned int *)(&(s3c2440_get_base_nand()->NFDATA));
|
| | | }
|
| | |
|
| | |
|
| | | static inline unsigned short bsp_nand_read_data16(void)
|
| | | {
|
| | | return *(volatile unsigned short *)(&(s3c2440_get_base_nand()->NFDATA));
|
| | | }
|
| | |
|
| | | static inline unsigned char bsp_nand_read_data8(void)
|
| | | {
|
| | | return *(volatile unsigned char *)(&(s3c2440_get_base_nand()->NFDATA));
|
| | | }
|
| | |
|
| | | static inline unsigned short bsp_nand_read_spare_ecc0(void)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | return nand->NFSECC & 0xFFFF;
|
| | | }
|
| | |
|
| | | static inline unsigned int bsp_nand_read_main_ecc0(void)
|
| | | {
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | return nand->NFMECC0;
|
| | | }
|
| | |
|
| | |
|
| | | static inline void bsp_nand_wait_busy(void)
|
| | | {
|
| | | int i;
|
| | | for (i=10; i>0; i--);
|
| | | struct s3c2440_nand *nand = s3c2440_get_base_nand();
|
| | | while ((nand->NFSTAT & (1<<0)) == 0);
|
| | | }
|
| | |
|
| | | #endif //__K9F2G08_S3C_H__
|
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 CoherentPlus Sdn. Bhd. |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This is the common subdir Makefile which to compile all the C |
| | | # source code to object files and then generate the shared or |
| | | # static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, |
| | | # which depends on the variable $LINK_MODE. |
| | | # |
| | | # Version: 1.0.0(10/08/2011~) |
| | | # Author: Guo Wenxue <guowenxue@gmail.com> |
| | | # ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" |
| | | # |
| | | #********************************************************************************/ |
| | | |
| | | PWD=$(shell pwd) |
| | | LOCAL_COMPILE=YES |
| | | LINK_MODE=STATIC |
| | | |
| | | #If wanna compile in the subdir, not called by top makefile, uncomment it |
| | | ifneq (${TOP_COMPILE}, YES) |
| | | LOCAL_COMPILE=YES |
| | | endif |
| | | |
| | | LIBNAME=$(shell basename ${PWD}) |
| | | STALIB=lib${LIBNAME}.a |
| | | DYNLIB=lib${LIBNAME}.so |
| | | |
| | | VPATH= . |
| | | C_SRCS = $(wildcard ${VPATH}/*.c) |
| | | AS_SRCS = $(wildcard ${VPATH}/*.S) |
| | | OBJS = $(patsubst %.c,%.o,$(C_SRCS)) |
| | | OBJS += $(patsubst %.S,%.o,$(AS_SRCS)) |
| | | |
| | | #====================================================== |
| | | # ---> Doesn't call by top makefile, compile by local |
| | | #====================================================== |
| | | ifeq (${LOCAL_COMPILE}, YES) |
| | | ARCH?=arm920t |
| | | #ARCH?=i386 |
| | | CFLAGS+=-fPIC |
| | | TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") |
| | | ifneq (,$(filter i386,$(TMP))) |
| | | CROSS_COMPILE= |
| | | else |
| | | CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- |
| | | endif |
| | | |
| | | PRJDIR?=$(shell pwd) |
| | | CFLAGS+=-I${PRJDIR} |
| | | CC = ${CROSS_COMPILE}gcc |
| | | AR = ${CROSS_COMPILE}ar |
| | | |
| | | endif #End local compile |
| | | |
| | | ifeq ("${LINK_MODE}", "STATIC") |
| | | LIBS = ${STALIB} |
| | | else |
| | | LIBS=${DYNLIB} |
| | | endif |
| | | |
| | | all: entry ${LIBS} install |
| | | |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | #$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o |
| | | ${STALIB}: $(OBJS) |
| | | $(AR) -rcu $@ $(OBJS) |
| | | |
| | | ${DYNLIB}: $(OBJS) |
| | | $(CC) -fPIC -shared -o $@ $(OBJS) |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | |
| | | %.o : %.c |
| | | $(CC) -c $< $(CFLAGS) |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @if [ ! -z "${LIBS_PATH}" ] ; then \ |
| | | mkdir -p ${LIBS_PATH} ; \ |
| | | cp ${LIBS} ${LIBS_PATH}; \ |
| | | fi; |
| | | |
| | | |
| | | clean: |
| | | @rm -f *.o |
| | | @rm -rf *.gdb *.a *.so |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
New file |
| | |
| | | #ifndef __S3C2440_H__ |
| | | #define __S3C2440_H__ |
| | | |
| | | #define S3C2440_UART_CHANNELS 3 |
| | | #define S3C2440_SPI_CHANNELS 2 |
| | | |
| | | /* Memory controller (see manual chapter 5) */ |
| | | struct s3c2440_memctl { |
| | | volatile unsigned int BWSCON; |
| | | volatile unsigned int BANKCON[8]; |
| | | volatile unsigned int REFRESH; |
| | | volatile unsigned int BANKSIZE; |
| | | volatile unsigned int MRSRB6; |
| | | volatile unsigned int MRSRB7; |
| | | }; |
| | | |
| | | |
| | | /* USB HOST (see manual chapter 12) */ |
| | | struct s3c2440_usb_host { |
| | | volatile unsigned int HcRevision; |
| | | volatile unsigned int HcControl; |
| | | volatile unsigned int HcCommonStatus; |
| | | volatile unsigned int HcInterruptStatus; |
| | | volatile unsigned int HcInterruptEnable; |
| | | volatile unsigned int HcInterruptDisable; |
| | | volatile unsigned int HcHCCA; |
| | | volatile unsigned int HcPeriodCuttendED; |
| | | volatile unsigned int HcControlHeadED; |
| | | volatile unsigned int HcControlCurrentED; |
| | | volatile unsigned int HcBulkHeadED; |
| | | volatile unsigned int HcBuldCurrentED; |
| | | volatile unsigned int HcDoneHead; |
| | | volatile unsigned int HcRmInterval; |
| | | volatile unsigned int HcFmRemaining; |
| | | volatile unsigned int HcFmNumber; |
| | | volatile unsigned int HcPeriodicStart; |
| | | volatile unsigned int HcLSThreshold; |
| | | volatile unsigned int HcRhDescriptorA; |
| | | volatile unsigned int HcRhDescriptorB; |
| | | volatile unsigned int HcRhStatus; |
| | | volatile unsigned int HcRhPortStatus1; |
| | | volatile unsigned int HcRhPortStatus2; |
| | | }; |
| | | |
| | | |
| | | /* INTERRUPT (see manual chapter 14) */ |
| | | struct s3c2440_interrupt { |
| | | volatile unsigned int SRCPND; |
| | | volatile unsigned int INTMOD; |
| | | volatile unsigned int INTMSK; |
| | | volatile unsigned int PRIORITY; |
| | | volatile unsigned int INTPND; |
| | | volatile unsigned int INTOFFSET; |
| | | volatile unsigned int SUBSRCPND; |
| | | volatile unsigned int INTSUBMSK; |
| | | }; |
| | | |
| | | |
| | | /* DMAS (see manual chapter 8) */ |
| | | struct s3c2440_dma { |
| | | volatile unsigned int DISRC; |
| | | volatile unsigned int DISRCC; |
| | | volatile unsigned int DIDST; |
| | | volatile unsigned int DIDSTC; |
| | | volatile unsigned int DCON; |
| | | volatile unsigned int DSTAT; |
| | | volatile unsigned int DCSRC; |
| | | volatile unsigned int DCDST; |
| | | volatile unsigned int DMASKTRIG; |
| | | volatile unsigned int res[7]; |
| | | }; |
| | | |
| | | struct s3c2440_dmas { |
| | | struct s3c2440_dma dma[4]; |
| | | }; |
| | | |
| | | |
| | | struct s3c2440_clock_power { |
| | | volatile unsigned int LOCKTIME; |
| | | volatile unsigned int MPLLCON; |
| | | volatile unsigned int UPLLCON; |
| | | volatile unsigned int CLKCON; |
| | | volatile unsigned int CLKSLOW; |
| | | volatile unsigned int CLKDIVN; |
| | | volatile unsigned int CAMDIVN; |
| | | }; |
| | | |
| | | |
| | | /* LCD CONTROLLER (see manual chapter 15) */ |
| | | struct s3c2440_lcd { |
| | | volatile unsigned int LCDCON1; |
| | | volatile unsigned int LCDCON2; |
| | | volatile unsigned int LCDCON3; |
| | | volatile unsigned int LCDCON4; |
| | | volatile unsigned int LCDCON5; |
| | | volatile unsigned int LCDSADDR1; |
| | | volatile unsigned int LCDSADDR2; |
| | | volatile unsigned int LCDSADDR3; |
| | | volatile unsigned int REDLUT; |
| | | volatile unsigned int GREENLUT; |
| | | volatile unsigned int BLUELUT; |
| | | volatile unsigned int res[8]; |
| | | volatile unsigned int DITHMODE; |
| | | volatile unsigned int TPAL; |
| | | volatile unsigned int LCDINTPND; |
| | | volatile unsigned int LCDSRCPND; |
| | | volatile unsigned int LCDINTMSK; |
| | | volatile unsigned int TCONSEL; |
| | | }; |
| | | |
| | | |
| | | /* NAND FLASH (see S3C2440 manual chapter 6) */ |
| | | struct s3c2440_nand { |
| | | volatile unsigned int NFCONF; |
| | | volatile unsigned int NFCONT; |
| | | volatile unsigned int NFCMD; |
| | | volatile unsigned int NFADDR; |
| | | volatile unsigned int NFDATA; |
| | | volatile unsigned int NFMECCD0; |
| | | volatile unsigned int NFMECCD1; |
| | | volatile unsigned int NFSECCD; |
| | | volatile unsigned int NFSTAT; |
| | | volatile unsigned int NFESTAT0; |
| | | volatile unsigned int NFESTAT1; |
| | | volatile unsigned int NFMECC0; |
| | | volatile unsigned int NFMECC1; |
| | | volatile unsigned int NFSECC; |
| | | volatile unsigned int NFSBLK; |
| | | volatile unsigned int NFEBLK; |
| | | }; |
| | | |
| | | |
| | | /* UART (see manual chapter 11) */ |
| | | struct s3c2440_uart { |
| | | volatile unsigned int ULCON; |
| | | volatile unsigned int UCON; |
| | | volatile unsigned int UFCON; |
| | | volatile unsigned int UMCON; |
| | | volatile unsigned int UTRSTAT; |
| | | volatile unsigned int UERSTAT; |
| | | volatile unsigned int UFSTAT; |
| | | volatile unsigned int UMSTAT; |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char UTXH; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char URXH; |
| | | #else /* Little Endian */ |
| | | volatile unsigned char UTXH; |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char URXH; |
| | | volatile unsigned char res2[3]; |
| | | #endif |
| | | volatile unsigned int UBRDIV; |
| | | }; |
| | | |
| | | |
| | | /* PWM TIMER (see manual chapter 10) */ |
| | | struct s3c2440_timer { |
| | | volatile unsigned int TCNTB; |
| | | volatile unsigned int TCMPB; |
| | | volatile unsigned int TCNTO; |
| | | }; |
| | | |
| | | struct s3c2440_timers { |
| | | volatile unsigned int TCFG0; |
| | | volatile unsigned int TCFG1; |
| | | volatile unsigned int TCON; |
| | | struct s3c2440_timer ch[4]; |
| | | volatile unsigned int TCNTB4; |
| | | volatile unsigned int TCNTO4; |
| | | }; |
| | | |
| | | |
| | | /* USB DEVICE (see manual chapter 13) */ |
| | | struct s3c2440_usb_dev_fifos { |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned char res[3]; |
| | | volatile unsigned char EP_FIFO_REG; |
| | | #else /* little endian */ |
| | | volatile unsigned char EP_FIFO_REG; |
| | | volatile unsigned char res[3]; |
| | | #endif |
| | | }; |
| | | |
| | | struct s3c2440_usb_dev_dmas { |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char EP_DMA_CON; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char EP_DMA_UNIT; |
| | | volatile unsigned char res3[3]; |
| | | volatile unsigned char EP_DMA_FIFO; |
| | | volatile unsigned char res4[3]; |
| | | volatile unsigned char EP_DMA_TTC_L; |
| | | volatile unsigned char res5[3]; |
| | | volatile unsigned char EP_DMA_TTC_M; |
| | | volatile unsigned char res6[3]; |
| | | volatile unsigned char EP_DMA_TTC_H; |
| | | #else /* little endian */ |
| | | volatile unsigned char EP_DMA_CON; |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char EP_DMA_UNIT; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char EP_DMA_FIFO; |
| | | volatile unsigned char res3[3]; |
| | | volatile unsigned char EP_DMA_TTC_L; |
| | | volatile unsigned char res4[3]; |
| | | volatile unsigned char EP_DMA_TTC_M; |
| | | volatile unsigned char res5[3]; |
| | | volatile unsigned char EP_DMA_TTC_H; |
| | | volatile unsigned char res6[3]; |
| | | #endif |
| | | }; |
| | | |
| | | struct s3c2440_usb_device { |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char FUNC_ADDR_REG; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char PWR_REG; |
| | | volatile unsigned char res3[3]; |
| | | volatile unsigned char EP_INT_REG; |
| | | volatile unsigned char res4[15]; |
| | | volatile unsigned char USB_INT_REG; |
| | | volatile unsigned char res5[3]; |
| | | volatile unsigned char EP_INT_EN_REG; |
| | | volatile unsigned char res6[15]; |
| | | volatile unsigned char USB_INT_EN_REG; |
| | | volatile unsigned char res7[3]; |
| | | volatile unsigned char FRAME_NUM1_REG; |
| | | volatile unsigned char res8[3]; |
| | | volatile unsigned char FRAME_NUM2_REG; |
| | | volatile unsigned char res9[3]; |
| | | volatile unsigned char INDEX_REG; |
| | | volatile unsigned char res10[7]; |
| | | volatile unsigned char MAXP_REG; |
| | | volatile unsigned char res11[3]; |
| | | volatile unsigned char EP0_CSR_IN_CSR1_REG; |
| | | volatile unsigned char res12[3]; |
| | | volatile unsigned char IN_CSR2_REG; |
| | | volatile unsigned char res13[7]; |
| | | volatile unsigned char OUT_CSR1_REG; |
| | | volatile unsigned char res14[3]; |
| | | volatile unsigned char OUT_CSR2_REG; |
| | | volatile unsigned char res15[3]; |
| | | volatile unsigned char OUT_FIFO_CNT1_REG; |
| | | volatile unsigned char res16[3]; |
| | | volatile unsigned char OUT_FIFO_CNT2_REG; |
| | | #else /* little endian */ |
| | | volatile unsigned char FUNC_ADDR_REG; |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char PWR_REG; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char EP_INT_REG; |
| | | volatile unsigned char res3[15]; |
| | | volatile unsigned char USB_INT_REG; |
| | | volatile unsigned char res4[3]; |
| | | volatile unsigned char EP_INT_EN_REG; |
| | | volatile unsigned char res5[15]; |
| | | volatile unsigned char USB_INT_EN_REG; |
| | | volatile unsigned char res6[3]; |
| | | volatile unsigned char FRAME_NUM1_REG; |
| | | volatile unsigned char res7[3]; |
| | | volatile unsigned char FRAME_NUM2_REG; |
| | | volatile unsigned char res8[3]; |
| | | volatile unsigned char INDEX_REG; |
| | | volatile unsigned char res9[7]; |
| | | volatile unsigned char MAXP_REG; |
| | | volatile unsigned char res10[7]; |
| | | volatile unsigned char EP0_CSR_IN_CSR1_REG; |
| | | volatile unsigned char res11[3]; |
| | | volatile unsigned char IN_CSR2_REG; |
| | | volatile unsigned char res12[3]; |
| | | volatile unsigned char OUT_CSR1_REG; |
| | | volatile unsigned char res13[7]; |
| | | volatile unsigned char OUT_CSR2_REG; |
| | | volatile unsigned char res14[3]; |
| | | volatile unsigned char OUT_FIFO_CNT1_REG; |
| | | volatile unsigned char res15[3]; |
| | | volatile unsigned char OUT_FIFO_CNT2_REG; |
| | | volatile unsigned char res16[3]; |
| | | #endif /* __BIG_ENDIAN */ |
| | | struct s3c2440_usb_dev_fifos fifo[5]; |
| | | struct s3c2440_usb_dev_dmas dma[5]; |
| | | }; |
| | | |
| | | |
| | | /* WATCH DOG TIMER (see manual chapter 18) */ |
| | | struct s3c2440_watchdog { |
| | | volatile unsigned int WTCON; |
| | | volatile unsigned int WTDAT; |
| | | volatile unsigned int WTCNT; |
| | | }; |
| | | |
| | | |
| | | /* IIC (see manual chapter 20) */ |
| | | struct s3c2440_i2c { |
| | | volatile unsigned int IICCON; |
| | | volatile unsigned int IICSTAT; |
| | | volatile unsigned int IICADD; |
| | | volatile unsigned int IICDS; |
| | | }; |
| | | |
| | | |
| | | /* IIS (see manual chapter 21) */ |
| | | struct s3c2440_i2s { |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned short res1; |
| | | volatile unsigned short IISCON; |
| | | volatile unsigned short res2; |
| | | volatile unsigned short IISMOD; |
| | | volatile unsigned short res3; |
| | | volatile unsigned short IISPSR; |
| | | volatile unsigned short res4; |
| | | volatile unsigned short IISFCON; |
| | | volatile unsigned short res5; |
| | | volatile unsigned short IISFIFO; |
| | | #else /* little endian */ |
| | | volatile unsigned short IISCON; |
| | | volatile unsigned short res1; |
| | | volatile unsigned short IISMOD; |
| | | volatile unsigned short res2; |
| | | volatile unsigned short IISPSR; |
| | | volatile unsigned short res3; |
| | | volatile unsigned short IISFCON; |
| | | volatile unsigned short res4; |
| | | volatile unsigned short IISFIFO; |
| | | volatile unsigned short res5; |
| | | #endif |
| | | }; |
| | | |
| | | |
| | | /* I/O PORT (see manual chapter 9) */ |
| | | struct s3c2440_gpio { |
| | | volatile unsigned int GPACON; |
| | | volatile unsigned int GPADAT; |
| | | volatile unsigned int res1[2]; |
| | | volatile unsigned int GPBCON; |
| | | volatile unsigned int GPBDAT; |
| | | volatile unsigned int GPBUP; |
| | | volatile unsigned int res2; |
| | | volatile unsigned int GPCCON; |
| | | volatile unsigned int GPCDAT; |
| | | volatile unsigned int GPCUP; |
| | | volatile unsigned int res3; |
| | | volatile unsigned int GPDCON; |
| | | volatile unsigned int GPDDAT; |
| | | volatile unsigned int GPDUP; |
| | | volatile unsigned int res4; |
| | | volatile unsigned int GPECON; |
| | | volatile unsigned int GPEDAT; |
| | | volatile unsigned int GPEUP; |
| | | volatile unsigned int res5; |
| | | volatile unsigned int GPFCON; |
| | | volatile unsigned int GPFDAT; |
| | | volatile unsigned int GPFUP; |
| | | volatile unsigned int res6; |
| | | volatile unsigned int GPGCON; |
| | | volatile unsigned int GPGDAT; |
| | | volatile unsigned int GPGUP; |
| | | volatile unsigned int res7; |
| | | volatile unsigned int GPHCON; |
| | | volatile unsigned int GPHDAT; |
| | | volatile unsigned int GPHUP; |
| | | volatile unsigned int res8; |
| | | |
| | | volatile unsigned int MISCCR; |
| | | volatile unsigned int DCLKCON; |
| | | volatile unsigned int EXTINT0; |
| | | volatile unsigned int EXTINT1; |
| | | volatile unsigned int EXTINT2; |
| | | volatile unsigned int EINTFLT0; |
| | | volatile unsigned int EINTFLT1; |
| | | volatile unsigned int EINTFLT2; |
| | | volatile unsigned int EINTFLT3; |
| | | volatile unsigned int EINTMASK; |
| | | volatile unsigned int EINTPEND; |
| | | volatile unsigned int GSTATUS0; |
| | | volatile unsigned int GSTATUS1; |
| | | volatile unsigned int GSTATUS2; |
| | | volatile unsigned int GSTATUS3; |
| | | volatile unsigned int GSTATUS4; |
| | | }; |
| | | |
| | | |
| | | /* RTC (see manual chapter 17) */ |
| | | struct s3c2440_rtc { |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned char res1[67]; |
| | | volatile unsigned char RTCCON; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char TICNT; |
| | | volatile unsigned char res3[11]; |
| | | volatile unsigned char RTCALM; |
| | | volatile unsigned char res4[3]; |
| | | volatile unsigned char ALMSEC; |
| | | volatile unsigned char res5[3]; |
| | | volatile unsigned char ALMMIN; |
| | | volatile unsigned char res6[3]; |
| | | volatile unsigned char ALMHOUR; |
| | | volatile unsigned char res7[3]; |
| | | volatile unsigned char ALMDATE; |
| | | volatile unsigned char res8[3]; |
| | | volatile unsigned char ALMMON; |
| | | volatile unsigned char res9[3]; |
| | | volatile unsigned char ALMYEAR; |
| | | volatile unsigned char res10[3]; |
| | | volatile unsigned char RTCRST; |
| | | volatile unsigned char res11[3]; |
| | | volatile unsigned char BCDSEC; |
| | | volatile unsigned char res12[3]; |
| | | volatile unsigned char BCDMIN; |
| | | volatile unsigned char res13[3]; |
| | | volatile unsigned char BCDHOUR; |
| | | volatile unsigned char res14[3]; |
| | | volatile unsigned char BCDDATE; |
| | | volatile unsigned char res15[3]; |
| | | volatile unsigned char BCDDAY; |
| | | volatile unsigned char res16[3]; |
| | | volatile unsigned char BCDMON; |
| | | volatile unsigned char res17[3]; |
| | | volatile unsigned char BCDYEAR; |
| | | #else /* little endian */ |
| | | volatile unsigned char res0[64]; |
| | | volatile unsigned char RTCCON; |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char TICNT; |
| | | volatile unsigned char res2[11]; |
| | | volatile unsigned char RTCALM; |
| | | volatile unsigned char res3[3]; |
| | | volatile unsigned char ALMSEC; |
| | | volatile unsigned char res4[3]; |
| | | volatile unsigned char ALMMIN; |
| | | volatile unsigned char res5[3]; |
| | | volatile unsigned char ALMHOUR; |
| | | volatile unsigned char res6[3]; |
| | | volatile unsigned char ALMDATE; |
| | | volatile unsigned char res7[3]; |
| | | volatile unsigned char ALMMON; |
| | | volatile unsigned char res8[3]; |
| | | volatile unsigned char ALMYEAR; |
| | | volatile unsigned char res9[3]; |
| | | volatile unsigned char RTCRST; |
| | | volatile unsigned char res10[3]; |
| | | volatile unsigned char BCDSEC; |
| | | volatile unsigned char res11[3]; |
| | | volatile unsigned char BCDMIN; |
| | | volatile unsigned char res12[3]; |
| | | volatile unsigned char BCDHOUR; |
| | | volatile unsigned char res13[3]; |
| | | volatile unsigned char BCDDATE; |
| | | volatile unsigned char res14[3]; |
| | | volatile unsigned char BCDDAY; |
| | | volatile unsigned char res15[3]; |
| | | volatile unsigned char BCDMON; |
| | | volatile unsigned char res16[3]; |
| | | volatile unsigned char BCDYEAR; |
| | | volatile unsigned char res17[3]; |
| | | #endif |
| | | }; |
| | | |
| | | |
| | | /* ADC (see manual chapter 16) */ |
| | | struct s3c2440_adc { |
| | | volatile unsigned int ADCCON; |
| | | volatile unsigned int ADCTSC; |
| | | volatile unsigned int ADCDLY; |
| | | volatile unsigned int ADCDAT0; |
| | | volatile unsigned int ADCDAT1; |
| | | volatile unsigned int ADCUPDN; |
| | | }; |
| | | |
| | | |
| | | /* SPI (see manual chapter 22) */ |
| | | struct s3c2440_spi_channel { |
| | | volatile unsigned char SPCON; |
| | | volatile unsigned char res1[3]; |
| | | volatile unsigned char SPSTA; |
| | | volatile unsigned char res2[3]; |
| | | volatile unsigned char SPPIN; |
| | | volatile unsigned char res3[3]; |
| | | volatile unsigned char SPPRE; |
| | | volatile unsigned char res4[3]; |
| | | volatile unsigned char SPTDAT; |
| | | volatile unsigned char res5[3]; |
| | | volatile unsigned char SPRDAT; |
| | | volatile unsigned char res6[3]; |
| | | volatile unsigned char res7[16]; |
| | | }; |
| | | |
| | | struct s3c2440_spi { |
| | | struct s3c2440_spi_channel ch[S3C2440_SPI_CHANNELS]; |
| | | }; |
| | | |
| | | |
| | | struct s3c2440_sdi { |
| | | volatile unsigned int SDICON; |
| | | volatile unsigned int SDIPRE; |
| | | volatile unsigned int SDICARG; |
| | | volatile unsigned int SDICCON; |
| | | volatile unsigned int SDICSTA; |
| | | volatile unsigned int SDIRSP0; |
| | | volatile unsigned int SDIRSP1; |
| | | volatile unsigned int SDIRSP2; |
| | | volatile unsigned int SDIRSP3; |
| | | volatile unsigned int SDIDTIMER; |
| | | volatile unsigned int SDIBSIZE; |
| | | volatile unsigned int SDIDCON; |
| | | volatile unsigned int SDIDCNT; |
| | | volatile unsigned int SDIDSTA; |
| | | volatile unsigned int SDIFSTA; |
| | | #ifdef __BIG_ENDIAN |
| | | volatile unsigned char res[3]; |
| | | volatile unsigned char SDIDAT; |
| | | #else |
| | | volatile unsigned char SDIDAT; |
| | | volatile unsigned char res[3]; |
| | | #endif |
| | | volatile unsigned int SDIIMSK; |
| | | }; |
| | | |
| | | |
| | | |
| | | /* S3C2440 only supports 512 Byte HW ECC */ |
| | | #define S3C2440_ECCSIZE 512 |
| | | #define S3C2440_ECCBYTES 3 |
| | | |
| | | enum s3c2440_uarts_nr { |
| | | S3C2440_UART0 = 0, |
| | | S3C2440_UART1 = 1, |
| | | S3C2440_UART2 = 2 |
| | | }; |
| | | |
| | | /* S3C2440 device base addresses */ |
| | | #define S3C2440_MEMCTL_BASE 0x48000000 |
| | | #define S3C2440_USB_HOST_BASE 0x49000000 |
| | | #define S3C2440_INTERRUPT_BASE 0x4A000000 |
| | | #define S3C2440_DMA_BASE 0x4B000000 |
| | | #define S3C2440_CLOCK_POWER_BASE 0x4C000000 |
| | | #define S3C2440_LCD_BASE 0x4D000000 |
| | | #define S3C2440_NAND_BASE 0x4E000000 |
| | | #define S3C2440_UART_BASE 0x50000000 |
| | | #define S3C2440_TIMER_BASE 0x51000000 |
| | | #define S3C2440_USB_DEVICE_BASE 0x52000140 |
| | | #define S3C2440_WATCHDOG_BASE 0x53000000 |
| | | #define S3C2440_I2C_BASE 0x54000000 |
| | | #define S3C2440_I2S_BASE 0x55000000 |
| | | #define S3C2440_GPIO_BASE 0x56000000 |
| | | #define S3C2440_RTC_BASE 0x57000000 |
| | | #define S3C2440_ADC_BASE 0x58000000 |
| | | #define S3C2440_SPI_BASE 0x59000000 |
| | | #define S3C2440_SDI_BASE 0x5A000000 |
| | | |
| | | |
| | | static inline struct s3c2440_memctl *s3c2440_get_base_memctl(void) |
| | | { |
| | | return (struct s3c2440_memctl *)S3C2440_MEMCTL_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_usb_host *s3c2440_get_base_usb_host(void) |
| | | { |
| | | return (struct s3c2440_usb_host *)S3C2440_USB_HOST_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_interrupt *s3c2440_get_base_interrupt(void) |
| | | { |
| | | return (struct s3c2440_interrupt *)S3C2440_INTERRUPT_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_dmas *s3c2440_get_base_dmas(void) |
| | | { |
| | | return (struct s3c2440_dmas *)S3C2440_DMA_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_clock_power *s3c2440_get_base_clock_power(void) |
| | | { |
| | | return (struct s3c2440_clock_power *)S3C2440_CLOCK_POWER_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_lcd *s3c2440_get_base_lcd(void) |
| | | { |
| | | return (struct s3c2440_lcd *)S3C2440_LCD_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_nand *s3c2440_get_base_nand(void) |
| | | { |
| | | return (struct s3c2440_nand *)S3C2440_NAND_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_uart *s3c2440_get_base_uart(enum s3c2440_uarts_nr n) |
| | | { |
| | | return (struct s3c2440_uart *)(S3C2440_UART_BASE + (n * 0x4000)); |
| | | } |
| | | |
| | | static inline struct s3c2440_timers *s3c2440_get_base_timers(void) |
| | | { |
| | | return (struct s3c2440_timers *)S3C2440_TIMER_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_usb_device *s3c2440_get_base_usb_device(void) |
| | | { |
| | | return (struct s3c2440_usb_device *)S3C2440_USB_DEVICE_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_watchdog *s3c2440_get_base_watchdog(void) |
| | | { |
| | | return (struct s3c2440_watchdog *)S3C2440_WATCHDOG_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_i2c *s3c2440_get_base_i2c(void) |
| | | { |
| | | return (struct s3c2440_i2c *)S3C2440_I2C_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_i2s *s3c2440_get_base_i2s(void) |
| | | { |
| | | return (struct s3c2440_i2s *)S3C2440_I2S_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_gpio *s3c2440_get_base_gpio(void) |
| | | { |
| | | return (struct s3c2440_gpio *)S3C2440_GPIO_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_rtc *s3c2440_get_base_rtc(void) |
| | | { |
| | | return (struct s3c2440_rtc *)S3C2440_RTC_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_adc *s3c2440_get_base_adc(void) |
| | | { |
| | | return (struct s3c2440_adc *)S3C2440_ADC_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_spi *s3c2440_get_base_spi(void) |
| | | { |
| | | return (struct s3c2440_spi *)S3C2440_SPI_BASE; |
| | | } |
| | | |
| | | static inline struct s3c2440_sdi *s3c2440_get_base_sdi(void) |
| | | { |
| | | return (struct s3c2440_sdi *)S3C2440_SDI_BASE; |
| | | } |
| | | |
| | | #endif /*__S3C2440_H__*/ |
New file |
| | |
| | | #include "s3c_board.h"
|
| | | #include "s3c2440.h"
|
| | |
|
| | | unsigned int s3c2440_get_fclk(void)
|
| | | { |
| | | struct s3c2440_clock_power *clk_power = s3c2440_get_base_clock_power();
|
| | | unsigned int r, m, p, s;
|
| | |
|
| | | r = clk_power->MPLLCON;
|
| | |
|
| | | m = ((r & 0xFF000) >> 12) + 8;
|
| | | p = ((r & 0x003F0) >> 4) + 2;
|
| | | s = r & 0x3;
|
| | |
|
| | | return (SYS_CLK_FREQ * m * 2) / (p << s);
|
| | | }
|
| | | |
| | | unsigned int s3c2440_get_hclk(void)
|
| | | {
|
| | | struct s3c2440_clock_power * const clk_power = s3c2440_get_base_clock_power();
|
| | | unsigned int fclk = s3c2440_get_fclk();
|
| | |
|
| | | if (clk_power->CLKDIVN & 0x6)
|
| | | {
|
| | | if ((clk_power->CLKDIVN & 0x6)==2)
|
| | | return fclk/2;
|
| | | if ((clk_power->CLKDIVN & 0x6)==6)
|
| | | return (clk_power->CAMDIVN & 0x100) ? fclk/6 : fclk/3;
|
| | | if ((clk_power->CLKDIVN & 0x6)==4)
|
| | | return (clk_power->CAMDIVN & 0x200) ? fclk/8 : fclk/4;
|
| | | return fclk;
|
| | | }
|
| | |
|
| | | return fclk;
|
| | | }
|
| | | |
| | | unsigned int s3c2440_get_pclk(void)
|
| | | {
|
| | | struct s3c2440_clock_power * const clk_power = s3c2440_get_base_clock_power();
|
| | | unsigned int hclk = s3c2440_get_hclk();
|
| | |
|
| | | return (clk_power->CLKDIVN & 0x1) ? hclk/2 : hclk;
|
| | | }
|
| | | |
| | | unsigned int s3c2440_get_uclk(void)
|
| | | {
|
| | | struct s3c2440_clock_power *clk_power = s3c2440_get_base_clock_power();
|
| | | unsigned int r, m, p, s;
|
| | |
|
| | | r = clk_power->UPLLCON;
|
| | |
|
| | | m = ((r & 0xFF000) >> 12) + 8;
|
| | | p = ((r & 0x003F0) >> 4) + 2;
|
| | | s = r & 0x3;
|
| | |
|
| | | return (SYS_CLK_FREQ * m) / (p << s);
|
| | | }
|
| | |
|
| | | void s3c2440_set_baudrate(unsigned int baudrate, int index)
|
| | | {
|
| | | struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
|
| | | unsigned int reg = 0;
|
| | | int i; |
| | | reg = s3c2440_get_pclk() / (16 * baudrate) - 1;
|
| | |
|
| | | uart->UBRDIV = reg;
|
| | | for (i = 0; i < 100; i++);
|
| | | } |
| | | |
| | | int s3c2440_serial_init(unsigned int baudrate, int index)
|
| | | {
|
| | | struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
|
| | |
|
| | | /* FIFO enable, Tx/Rx FIFO clear */
|
| | | uart->UFCON = 0x07;
|
| | | uart->UMCON = 0x0;
|
| | |
|
| | | /* Normal,No parity,1 stop,8 bit */
|
| | | uart->ULCON = 0x3;
|
| | | /*
|
| | | * tx=level,rx=edge,disable timeout int.,enable rx error int.,
|
| | | * normal,interrupt or polling
|
| | | */
|
| | | uart->UCON = (1<<8) | (1<<2) | (1<<0);
|
| | |
|
| | | // uart->UMCON = 0x1; /* RTS up */
|
| | | |
| | | s3c2440_set_baudrate(baudrate, index);
|
| | |
|
| | | return (0);
|
| | | }
|
| | |
|
| | | int s3c2440_serail_set_afc(int enable, int index)
|
| | | {
|
| | | if (index != S3C2440_UART0 || index != S3C2440_UART1)
|
| | | return -1;
|
| | |
|
| | | struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
|
| | | if (enable) {
|
| | | uart->UMCON = (1<<4);
|
| | | } else {
|
| | | uart->UMCON = 0;
|
| | | uart->UMCON = 0;
|
| | | uart->UMCON = 0;
|
| | | uart->UMCON = 1;
|
| | | }
|
| | |
|
| | | return 0;
|
| | | }
|
| | |
|
| | | /*
|
| | | * Read a single byte from the serial port. Returns 1 on success, 0
|
| | | * otherwise. When the function is succesfull, the character read is
|
| | | * written into its argument c.
|
| | | */
|
| | | int s3c2440_serial_getc (int index)
|
| | | {
|
| | | struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
|
| | |
|
| | | /* wait for character to arrive */
|
| | | //while (!(uart->UTRSTAT & 0x1));
|
| | | while(!(uart->UFSTAT & 0x1F));
|
| | |
|
| | | return uart->URXH & 0xff;
|
| | | } |
| | |
|
| | | #if 0
|
| | | static int hwflow = 0; /* turned off by default */
|
| | | int hwflow_onoff(int on)
|
| | | {
|
| | | switch(on) {
|
| | | case 0:
|
| | | default:
|
| | | break; /* return current */
|
| | | case 1:
|
| | | hwflow = 1; /* turn on */
|
| | | break;
|
| | | case -1:
|
| | | hwflow = 0; /* turn off */
|
| | | break;
|
| | | }
|
| | | return hwflow;
|
| | | }
|
| | | #endif
|
| | |
|
| | | #if 0 |
| | | static int be_quiet = 0;
|
| | | void disable_putc(void)
|
| | | {
|
| | | be_quiet = 1;
|
| | | }
|
| | |
|
| | | void enable_putc(void)
|
| | | {
|
| | | be_quiet = 0;
|
| | | }
|
| | | #endif
|
| | |
|
| | |
|
| | | /*
|
| | | * Output a single byte to the serial port.
|
| | | */
|
| | | void s3c2440_serial_putc (char c, int index)
|
| | | {
|
| | | struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
|
| | |
|
| | | /* wait for room in the tx FIFO */
|
| | | //while ((!(uart->UTRSTAT & 0x2)));
|
| | | while (uart->UFSTAT & (1<<14));
|
| | | uart->UTXH = c;
|
| | | }
|
| | |
|
| | |
|
| | | void s3c2440_serial_puts(const char *s, int index)
|
| | | {
|
| | | while (*s) |
| | | {
|
| | | if (*s == '\n') /* If \n, also do \r */
|
| | | s3c2440_serial_putc('\r', index);
|
| | | s3c2440_serial_putc (*s++, index);
|
| | | }
|
| | | }
|
| | |
|
| | |
|
| | | void s3c2440_interrupt_enable(unsigned int mask)
|
| | | {
|
| | | mask = ~mask;
|
| | | struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
|
| | | interrupt->INTMSK &= mask;
|
| | | }
|
| | |
|
| | | void s3c2440_interrupt_disable(unsigned int mask)
|
| | | {
|
| | | struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
|
| | | interrupt->INTMSK |= mask;
|
| | | }
|
| | |
|
| | | void s3c2440_sub_interrupt_enable(unsigned int mask)
|
| | | {
|
| | | mask = ~mask;
|
| | | struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
|
| | | interrupt->INTSUBMSK &= mask;
|
| | | }
|
| | |
|
| | | void s3c2440_sub_interrupt_disable(unsigned int mask)
|
| | | {
|
| | | struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
|
| | | interrupt->INTSUBMSK |= mask;
|
| | | }
|
| | |
|
| | |
|
| | |
|
| | | |
New file |
| | |
| | | #ifndef __S3C_BOARD_H__
|
| | | #define __S3C_BOARD_H__
|
| | |
|
| | | #include "s3c2440.h"
|
| | |
|
| | | #define SYS_CLK_FREQ 12000000 |
| | | #define CONSOLE_SERIAL S3C2440_UART0
|
| | | #define CONSOLE_BAUDRATE 115200
|
| | |
|
| | | unsigned int s3c2440_get_fclk(void);
|
| | | unsigned int s3c2440_get_hclk(void);
|
| | | unsigned int s3c2440_get_pclk(void);
|
| | | unsigned int s3c2440_get_uclk(void);
|
| | |
|
| | | void s3c2440_set_baudrate(unsigned int baudrate, int index);
|
| | | int s3c2440_serial_init(unsigned int baudrate, int index);
|
| | | int s3c2440_serail_set_afc(int enable, int index);
|
| | | int s3c2440_serial_getc (int index);
|
| | | void s3c2440_serial_putc (char ch, int index);
|
| | | int s3c2440_serial_tstc(int index);
|
| | | void s3c2440_serial_puts(const char *s, int index);
|
| | |
|
| | | #define console_serial_init() s3c2440_serial_init(CONSOLE_BAUDRATE, CONSOLE_SERIAL)
|
| | | #define console_serial_getc() s3c2440_serial_getc(CONSOLE_SERIAL)
|
| | | #define console_serial_tstc() s3c2440_serial_tstc(CONSOLE_SERIAL)
|
| | | #define console_serial_putc(c) s3c2440_serial_putc(c, CONSOLE_SERIAL)
|
| | | #define console_serial_puts(s) s3c2440_serial_puts(s, CONSOLE_SERIAL)
|
| | |
|
| | | void s3c2440_interrupt_enable(unsigned int mask);
|
| | | void s3c2440_interrupt_disable(unsigned int mask);
|
| | | void s3c2440_sub_interrupt_enable(unsigned int mask);
|
| | | void s3c2440_sub_interrupt_disable(unsigned int mask);
|
| | |
|
| | | #endif
|
New file |
| | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <malloc.h> |
| | | |
| | | #define DEBUG 1 |
| | | |
| | | #if 0 /* Moved to malloc.h */ |
| | | /* ---------- To make a malloc.h, start cutting here ------------ */ |
| | | |
| | | /* |
| | | A version of malloc/free/realloc written by Doug Lea and released to the |
| | | public domain. Send questions/comments/complaints/performance data |
| | | to dl@cs.oswego.edu |
| | | |
| | | * VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee) |
| | | |
| | | Note: There may be an updated version of this malloc obtainable at |
| | | ftp://g.oswego.edu/pub/misc/malloc.c |
| | | Check before installing! |
| | | |
| | | * Why use this malloc? |
| | | |
| | | This is not the fastest, most space-conserving, most portable, or |
| | | most tunable malloc ever written. However it is among the fastest |
| | | while also being among the most space-conserving, portable and tunable. |
| | | Consistent balance across these factors results in a good general-purpose |
| | | allocator. For a high-level description, see |
| | | http://g.oswego.edu/dl/html/malloc.html |
| | | |
| | | * Synopsis of public routines |
| | | |
| | | (Much fuller descriptions are contained in the program documentation below.) |
| | | |
| | | malloc(size_t n); |
| | | Return a pointer to a newly allocated chunk of at least n bytes, or null |
| | | if no space is available. |
| | | free(Void_t* p); |
| | | Release the chunk of memory pointed to by p, or no effect if p is null. |
| | | realloc(Void_t* p, size_t n); |
| | | Return a pointer to a chunk of size n that contains the same data |
| | | as does chunk p up to the minimum of (n, p's size) bytes, or null |
| | | if no space is available. The returned pointer may or may not be |
| | | the same as p. If p is null, equivalent to malloc. Unless the |
| | | #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a |
| | | size argument of zero (re)allocates a minimum-sized chunk. |
| | | memalign(size_t alignment, size_t n); |
| | | Return a pointer to a newly allocated chunk of n bytes, aligned |
| | | in accord with the alignment argument, which must be a power of |
| | | two. |
| | | valloc(size_t n); |
| | | Equivalent to memalign(pagesize, n), where pagesize is the page |
| | | size of the system (or as near to this as can be figured out from |
| | | all the includes/defines below.) |
| | | pvalloc(size_t n); |
| | | Equivalent to valloc(minimum-page-that-holds(n)), that is, |
| | | round up n to nearest pagesize. |
| | | calloc(size_t unit, size_t quantity); |
| | | Returns a pointer to quantity * unit bytes, with all locations |
| | | set to zero. |
| | | cfree(Void_t* p); |
| | | Equivalent to free(p). |
| | | malloc_trim(size_t pad); |
| | | Release all but pad bytes of freed top-most memory back |
| | | to the system. Return 1 if successful, else 0. |
| | | malloc_usable_size(Void_t* p); |
| | | Report the number usable allocated bytes associated with allocated |
| | | chunk p. This may or may not report more bytes than were requested, |
| | | due to alignment and minimum size constraints. |
| | | malloc_stats(); |
| | | Prints brief summary statistics. |
| | | mallinfo() |
| | | Returns (by copy) a struct containing various summary statistics. |
| | | mallopt(int parameter_number, int parameter_value) |
| | | Changes one of the tunable parameters described below. Returns |
| | | 1 if successful in changing the parameter, else 0. |
| | | |
| | | * Vital statistics: |
| | | |
| | | Alignment: 8-byte |
| | | 8 byte alignment is currently hardwired into the design. This |
| | | seems to suffice for all current machines and C compilers. |
| | | |
| | | Assumed pointer representation: 4 or 8 bytes |
| | | Code for 8-byte pointers is untested by me but has worked |
| | | reliably by Wolfram Gloger, who contributed most of the |
| | | changes supporting this. |
| | | |
| | | Assumed size_t representation: 4 or 8 bytes |
| | | Note that size_t is allowed to be 4 bytes even if pointers are 8. |
| | | |
| | | Minimum overhead per allocated chunk: 4 or 8 bytes |
| | | Each malloced chunk has a hidden overhead of 4 bytes holding size |
| | | and status information. |
| | | |
| | | Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) |
| | | 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) |
| | | |
| | | When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte |
| | | ptrs but 4 byte size) or 24 (for 8/8) additional bytes are |
| | | needed; 4 (8) for a trailing size field |
| | | and 8 (16) bytes for free list pointers. Thus, the minimum |
| | | allocatable size is 16/24/32 bytes. |
| | | |
| | | Even a request for zero bytes (i.e., malloc(0)) returns a |
| | | pointer to something of the minimum allocatable size. |
| | | |
| | | Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes |
| | | 8-byte size_t: 2^63 - 16 bytes |
| | | |
| | | It is assumed that (possibly signed) size_t bit values suffice to |
| | | represent chunk sizes. `Possibly signed' is due to the fact |
| | | that `size_t' may be defined on a system as either a signed or |
| | | an unsigned type. To be conservative, values that would appear |
| | | as negative numbers are avoided. |
| | | Requests for sizes with a negative sign bit when the request |
| | | size is treaded as a long will return null. |
| | | |
| | | Maximum overhead wastage per allocated chunk: normally 15 bytes |
| | | |
| | | Alignnment demands, plus the minimum allocatable size restriction |
| | | make the normal worst-case wastage 15 bytes (i.e., up to 15 |
| | | more bytes will be allocated than were requested in malloc), with |
| | | two exceptions: |
| | | 1. Because requests for zero bytes allocate non-zero space, |
| | | the worst case wastage for a request of zero bytes is 24 bytes. |
| | | 2. For requests >= mmap_threshold that are serviced via |
| | | mmap(), the worst case wastage is 8 bytes plus the remainder |
| | | from a system page (the minimal mmap unit); typically 4096 bytes. |
| | | |
| | | * Limitations |
| | | |
| | | Here are some features that are NOT currently supported |
| | | |
| | | * No user-definable hooks for callbacks and the like. |
| | | * No automated mechanism for fully checking that all accesses |
| | | to malloced memory stay within their bounds. |
| | | * No support for compaction. |
| | | |
| | | * Synopsis of compile-time options: |
| | | |
| | | People have reported using previous versions of this malloc on all |
| | | versions of Unix, sometimes by tweaking some of the defines |
| | | below. It has been tested most extensively on Solaris and |
| | | Linux. It is also reported to work on WIN32 platforms. |
| | | People have also reported adapting this malloc for use in |
| | | stand-alone embedded systems. |
| | | |
| | | The implementation is in straight, hand-tuned ANSI C. Among other |
| | | consequences, it uses a lot of macros. Because of this, to be at |
| | | all usable, this code should be compiled using an optimizing compiler |
| | | (for example gcc -O2) that can simplify expressions and control |
| | | paths. |
| | | |
| | | __STD_C (default: derived from C compiler defines) |
| | | Nonzero if using ANSI-standard C compiler, a C++ compiler, or |
| | | a C compiler sufficiently close to ANSI to get away with it. |
| | | DEBUG (default: NOT defined) |
| | | Define to enable debugging. Adds fairly extensive assertion-based |
| | | checking to help track down memory errors, but noticeably slows down |
| | | execution. |
| | | REALLOC_ZERO_BYTES_FREES (default: NOT defined) |
| | | Define this if you think that realloc(p, 0) should be equivalent |
| | | to free(p). Otherwise, since malloc returns a unique pointer for |
| | | malloc(0), so does realloc(p, 0). |
| | | HAVE_MEMCPY (default: defined) |
| | | Define if you are not otherwise using ANSI STD C, but still |
| | | have memcpy and memset in your C library and want to use them. |
| | | Otherwise, simple internal versions are supplied. |
| | | USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) |
| | | Define as 1 if you want the C library versions of memset and |
| | | memcpy called in realloc and calloc (otherwise macro versions are used). |
| | | At least on some platforms, the simple macro versions usually |
| | | outperform libc versions. |
| | | HAVE_MMAP (default: defined as 1) |
| | | Define to non-zero to optionally make malloc() use mmap() to |
| | | allocate very large blocks. |
| | | HAVE_MREMAP (default: defined as 0 unless Linux libc set) |
| | | Define to non-zero to optionally make realloc() use mremap() to |
| | | reallocate very large blocks. |
| | | malloc_getpagesize (default: derived from system #includes) |
| | | Either a constant or routine call returning the system page size. |
| | | HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) |
| | | Optionally define if you are on a system with a /usr/include/malloc.h |
| | | that declares struct mallinfo. It is not at all necessary to |
| | | define this even if you do, but will ensure consistency. |
| | | INTERNAL_SIZE_T (default: size_t) |
| | | Define to a 32-bit type (probably `unsigned int') if you are on a |
| | | 64-bit machine, yet do not want or need to allow malloc requests of |
| | | greater than 2^31 to be handled. This saves space, especially for |
| | | very small chunks. |
| | | INTERNAL_LINUX_C_LIB (default: NOT defined) |
| | | Defined only when compiled as part of Linux libc. |
| | | Also note that there is some odd internal name-mangling via defines |
| | | (for example, internally, `malloc' is named `mALLOc') needed |
| | | when compiling in this case. These look funny but don't otherwise |
| | | affect anything. |
| | | WIN32 (default: undefined) |
| | | Define this on MS win (95, nt) platforms to compile in sbrk emulation. |
| | | LACKS_UNISTD_H (default: undefined if not WIN32) |
| | | Define this if your system does not have a <unistd.h>. |
| | | LACKS_SYS_PARAM_H (default: undefined if not WIN32) |
| | | Define this if your system does not have a <sys/param.h>. |
| | | MORECORE (default: sbrk) |
| | | The name of the routine to call to obtain more memory from the system. |
| | | MORECORE_FAILURE (default: -1) |
| | | The value returned upon failure of MORECORE. |
| | | MORECORE_CLEARS (default 1) |
| | | true (1) if the routine mapped to MORECORE zeroes out memory (which |
| | | holds for sbrk). |
| | | DEFAULT_TRIM_THRESHOLD |
| | | DEFAULT_TOP_PAD |
| | | DEFAULT_MMAP_THRESHOLD |
| | | DEFAULT_MMAP_MAX |
| | | Default values of tunable parameters (described in detail below) |
| | | controlling interaction with host system routines (sbrk, mmap, etc). |
| | | These values may also be changed dynamically via mallopt(). The |
| | | preset defaults are those that give best performance for typical |
| | | programs/systems. |
| | | USE_DL_PREFIX (default: undefined) |
| | | Prefix all public routines with the string 'dl'. Useful to |
| | | quickly avoid procedure declaration conflicts and linker symbol |
| | | conflicts with existing memory allocation routines. |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | |
| | | /* Preliminaries */ |
| | | |
| | | #ifndef __STD_C |
| | | #ifdef __STDC__ |
| | | #define __STD_C 1 |
| | | #else |
| | | #if __cplusplus |
| | | #define __STD_C 1 |
| | | #else |
| | | #define __STD_C 0 |
| | | #endif /*__cplusplus*/ |
| | | #endif /*__STDC__*/ |
| | | #endif /*__STD_C*/ |
| | | |
| | | #ifndef Void_t |
| | | #if (__STD_C || defined(WIN32)) |
| | | #define Void_t void |
| | | #else |
| | | #define Void_t char |
| | | #endif |
| | | #endif /*Void_t*/ |
| | | |
| | | #if __STD_C |
| | | #include <stddef.h> /* for size_t */ |
| | | #else |
| | | #include <sys/types.h> |
| | | #endif |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdio.h> /* needed for malloc_stats */ |
| | | |
| | | |
| | | /* |
| | | Compile-time options |
| | | */ |
| | | |
| | | |
| | | /* |
| | | Debugging: |
| | | |
| | | Because freed chunks may be overwritten with link fields, this |
| | | malloc will often die when freed memory is overwritten by user |
| | | programs. This can be very effective (albeit in an annoying way) |
| | | in helping track down dangling pointers. |
| | | |
| | | If you compile with -DDEBUG, a number of assertion checks are |
| | | enabled that will catch more memory errors. You probably won't be |
| | | able to make much sense of the actual assertion errors, but they |
| | | should help you locate incorrectly overwritten memory. The |
| | | checking is fairly extensive, and will slow down execution |
| | | noticeably. Calling malloc_stats or mallinfo with DEBUG set will |
| | | attempt to check every non-mmapped allocated and free chunk in the |
| | | course of computing the summmaries. (By nature, mmapped regions |
| | | cannot be checked very much automatically.) |
| | | |
| | | Setting DEBUG may also be helpful if you are trying to modify |
| | | this code. The assertions in the check routines spell out in more |
| | | detail the assumptions and invariants underlying the algorithms. |
| | | |
| | | */ |
| | | |
| | | /* |
| | | INTERNAL_SIZE_T is the word-size used for internal bookkeeping |
| | | of chunk sizes. On a 64-bit machine, you can reduce malloc |
| | | overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' |
| | | at the expense of not being able to handle requests greater than |
| | | 2^31. This limitation is hardly ever a concern; you are encouraged |
| | | to set this. However, the default version is the same as size_t. |
| | | */ |
| | | |
| | | #ifndef INTERNAL_SIZE_T |
| | | #define INTERNAL_SIZE_T size_t |
| | | #endif |
| | | |
| | | /* |
| | | REALLOC_ZERO_BYTES_FREES should be set if a call to |
| | | realloc with zero bytes should be the same as a call to free. |
| | | Some people think it should. Otherwise, since this malloc |
| | | returns a unique pointer for malloc(0), so does realloc(p, 0). |
| | | */ |
| | | |
| | | |
| | | /* #define REALLOC_ZERO_BYTES_FREES */ |
| | | |
| | | |
| | | /* |
| | | WIN32 causes an emulation of sbrk to be compiled in |
| | | mmap-based options are not currently supported in WIN32. |
| | | */ |
| | | |
| | | /* #define WIN32 */ |
| | | #ifdef WIN32 |
| | | #define MORECORE wsbrk |
| | | #define HAVE_MMAP 0 |
| | | |
| | | #define LACKS_UNISTD_H |
| | | #define LACKS_SYS_PARAM_H |
| | | |
| | | /* |
| | | Include 'windows.h' to get the necessary declarations for the |
| | | Microsoft Visual C++ data structures and routines used in the 'sbrk' |
| | | emulation. |
| | | |
| | | Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft |
| | | Visual C++ header files are included. |
| | | */ |
| | | #define WIN32_LEAN_AND_MEAN |
| | | #include <windows.h> |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | HAVE_MEMCPY should be defined if you are not otherwise using |
| | | ANSI STD C, but still have memcpy and memset in your C library |
| | | and want to use them in calloc and realloc. Otherwise simple |
| | | macro versions are defined here. |
| | | |
| | | USE_MEMCPY should be defined as 1 if you actually want to |
| | | have memset and memcpy called. People report that the macro |
| | | versions are often enough faster than libc versions on many |
| | | systems that it is better to use them. |
| | | |
| | | */ |
| | | |
| | | #define HAVE_MEMCPY |
| | | |
| | | #ifndef USE_MEMCPY |
| | | #ifdef HAVE_MEMCPY |
| | | #define USE_MEMCPY 1 |
| | | #else |
| | | #define USE_MEMCPY 0 |
| | | #endif |
| | | #endif |
| | | |
| | | #if (__STD_C || defined(HAVE_MEMCPY)) |
| | | |
| | | #if __STD_C |
| | | void* memset(void*, int, size_t); |
| | | void* memcpy(void*, const void*, size_t); |
| | | #else |
| | | #ifdef WIN32 |
| | | /* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */ |
| | | /* 'windows.h' */ |
| | | #else |
| | | Void_t* memset(); |
| | | Void_t* memcpy(); |
| | | #endif |
| | | #endif |
| | | #endif |
| | | |
| | | #if USE_MEMCPY |
| | | |
| | | /* The following macros are only invoked with (2n+1)-multiples of |
| | | INTERNAL_SIZE_T units, with a positive integer n. This is exploited |
| | | for fast inline execution when n is small. */ |
| | | |
| | | #define MALLOC_ZERO(charp, nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T mzsz = (nbytes); \ |
| | | if(mzsz <= 9*sizeof(mzsz)) { \ |
| | | INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ |
| | | if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ |
| | | *mz++ = 0; \ |
| | | if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ |
| | | *mz++ = 0; \ |
| | | if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ |
| | | *mz++ = 0; }}} \ |
| | | *mz++ = 0; \ |
| | | *mz++ = 0; \ |
| | | *mz = 0; \ |
| | | } else memset((charp), 0, mzsz); \ |
| | | } while(0) |
| | | |
| | | #define MALLOC_COPY(dest,src,nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T mcsz = (nbytes); \ |
| | | if(mcsz <= 9*sizeof(mcsz)) { \ |
| | | INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ |
| | | INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ |
| | | if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; }}} \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | *mcdst = *mcsrc ; \ |
| | | } else memcpy(dest, src, mcsz); \ |
| | | } while(0) |
| | | |
| | | #else /* !USE_MEMCPY */ |
| | | |
| | | /* Use Duff's device for good zeroing/copying performance. */ |
| | | |
| | | #define MALLOC_ZERO(charp, nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ |
| | | long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ |
| | | if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ |
| | | switch (mctmp) { \ |
| | | case 0: for(;;) { *mzp++ = 0; \ |
| | | case 7: *mzp++ = 0; \ |
| | | case 6: *mzp++ = 0; \ |
| | | case 5: *mzp++ = 0; \ |
| | | case 4: *mzp++ = 0; \ |
| | | case 3: *mzp++ = 0; \ |
| | | case 2: *mzp++ = 0; \ |
| | | case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ |
| | | } \ |
| | | } while(0) |
| | | |
| | | #define MALLOC_COPY(dest,src,nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ |
| | | INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ |
| | | long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ |
| | | if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ |
| | | switch (mctmp) { \ |
| | | case 0: for(;;) { *mcdst++ = *mcsrc++; \ |
| | | case 7: *mcdst++ = *mcsrc++; \ |
| | | case 6: *mcdst++ = *mcsrc++; \ |
| | | case 5: *mcdst++ = *mcsrc++; \ |
| | | case 4: *mcdst++ = *mcsrc++; \ |
| | | case 3: *mcdst++ = *mcsrc++; \ |
| | | case 2: *mcdst++ = *mcsrc++; \ |
| | | case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ |
| | | } \ |
| | | } while(0) |
| | | |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | Define HAVE_MMAP to optionally make malloc() use mmap() to |
| | | allocate very large blocks. These will be returned to the |
| | | operating system immediately after a free(). |
| | | */ |
| | | |
| | | #ifndef HAVE_MMAP |
| | | #define HAVE_MMAP 1 |
| | | #endif |
| | | |
| | | /* |
| | | Define HAVE_MREMAP to make realloc() use mremap() to re-allocate |
| | | large blocks. This is currently only possible on Linux with |
| | | kernel versions newer than 1.3.77. |
| | | */ |
| | | |
| | | #ifndef HAVE_MREMAP |
| | | #ifdef INTERNAL_LINUX_C_LIB |
| | | #define HAVE_MREMAP 1 |
| | | #else |
| | | #define HAVE_MREMAP 0 |
| | | #endif |
| | | #endif |
| | | |
| | | #if HAVE_MMAP |
| | | |
| | | #include <unistd.h> |
| | | #include <fcntl.h> |
| | | #include <sys/mman.h> |
| | | |
| | | #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
| | | #define MAP_ANONYMOUS MAP_ANON |
| | | #endif |
| | | |
| | | #endif /* HAVE_MMAP */ |
| | | |
| | | /* |
| | | Access to system page size. To the extent possible, this malloc |
| | | manages memory from the system in page-size units. |
| | | |
| | | The following mechanics for getpagesize were adapted from |
| | | bsd/gnu getpagesize.h |
| | | */ |
| | | |
| | | #ifndef LACKS_UNISTD_H |
| | | # include <unistd.h> |
| | | #endif |
| | | |
| | | #ifndef malloc_getpagesize |
| | | # ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ |
| | | # ifndef _SC_PAGE_SIZE |
| | | # define _SC_PAGE_SIZE _SC_PAGESIZE |
| | | # endif |
| | | # endif |
| | | # ifdef _SC_PAGE_SIZE |
| | | # define malloc_getpagesize sysconf(_SC_PAGE_SIZE) |
| | | # else |
| | | # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) |
| | | extern size_t getpagesize(); |
| | | # define malloc_getpagesize getpagesize() |
| | | # else |
| | | # ifdef WIN32 |
| | | # define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */ |
| | | # else |
| | | # ifndef LACKS_SYS_PARAM_H |
| | | # include <sys/param.h> |
| | | # endif |
| | | # ifdef EXEC_PAGESIZE |
| | | # define malloc_getpagesize EXEC_PAGESIZE |
| | | # else |
| | | # ifdef NBPG |
| | | # ifndef CLSIZE |
| | | # define malloc_getpagesize NBPG |
| | | # else |
| | | # define malloc_getpagesize (NBPG * CLSIZE) |
| | | # endif |
| | | # else |
| | | # ifdef NBPC |
| | | # define malloc_getpagesize NBPC |
| | | # else |
| | | # ifdef PAGESIZE |
| | | # define malloc_getpagesize PAGESIZE |
| | | # else |
| | | # define malloc_getpagesize (4096) /* just guess */ |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | |
| | | This version of malloc supports the standard SVID/XPG mallinfo |
| | | routine that returns a struct containing the same kind of |
| | | information you can get from malloc_stats. It should work on |
| | | any SVID/XPG compliant system that has a /usr/include/malloc.h |
| | | defining struct mallinfo. (If you'd like to install such a thing |
| | | yourself, cut out the preliminary declarations as described above |
| | | and below and save them in a malloc.h file. But there's no |
| | | compelling reason to bother to do this.) |
| | | |
| | | The main declaration needed is the mallinfo struct that is returned |
| | | (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a |
| | | bunch of fields, most of which are not even meaningful in this |
| | | version of malloc. Some of these fields are are instead filled by |
| | | mallinfo() with other numbers that might possibly be of interest. |
| | | |
| | | HAVE_USR_INCLUDE_MALLOC_H should be set if you have a |
| | | /usr/include/malloc.h file that includes a declaration of struct |
| | | mallinfo. If so, it is included; else an SVID2/XPG2 compliant |
| | | version is declared below. These must be precisely the same for |
| | | mallinfo() to work. |
| | | |
| | | */ |
| | | |
| | | /* #define HAVE_USR_INCLUDE_MALLOC_H */ |
| | | |
| | | #if HAVE_USR_INCLUDE_MALLOC_H |
| | | #include "/usr/include/malloc.h" |
| | | #else |
| | | |
| | | /* SVID2/XPG mallinfo structure */ |
| | | |
| | | struct mallinfo { |
| | | int arena; /* total space allocated from system */ |
| | | int ordblks; /* number of non-inuse chunks */ |
| | | int smblks; /* unused -- always zero */ |
| | | int hblks; /* number of mmapped regions */ |
| | | int hblkhd; /* total space in mmapped regions */ |
| | | int usmblks; /* unused -- always zero */ |
| | | int fsmblks; /* unused -- always zero */ |
| | | int uordblks; /* total allocated space */ |
| | | int fordblks; /* total non-inuse space */ |
| | | int keepcost; /* top-most, releasable (via malloc_trim) space */ |
| | | }; |
| | | |
| | | /* SVID2/XPG mallopt options */ |
| | | |
| | | #define M_MXFAST 1 /* UNUSED in this malloc */ |
| | | #define M_NLBLKS 2 /* UNUSED in this malloc */ |
| | | #define M_GRAIN 3 /* UNUSED in this malloc */ |
| | | #define M_KEEP 4 /* UNUSED in this malloc */ |
| | | |
| | | #endif |
| | | |
| | | /* mallopt options that actually do something */ |
| | | |
| | | #define M_TRIM_THRESHOLD -1 |
| | | #define M_TOP_PAD -2 |
| | | #define M_MMAP_THRESHOLD -3 |
| | | #define M_MMAP_MAX -4 |
| | | |
| | | |
| | | #ifndef DEFAULT_TRIM_THRESHOLD |
| | | #define DEFAULT_TRIM_THRESHOLD (128 * 1024) |
| | | #endif |
| | | |
| | | /* |
| | | M_TRIM_THRESHOLD is the maximum amount of unused top-most memory |
| | | to keep before releasing via malloc_trim in free(). |
| | | |
| | | Automatic trimming is mainly useful in long-lived programs. |
| | | Because trimming via sbrk can be slow on some systems, and can |
| | | sometimes be wasteful (in cases where programs immediately |
| | | afterward allocate more large chunks) the value should be high |
| | | enough so that your overall system performance would improve by |
| | | releasing. |
| | | |
| | | The trim threshold and the mmap control parameters (see below) |
| | | can be traded off with one another. Trimming and mmapping are |
| | | two different ways of releasing unused memory back to the |
| | | system. Between these two, it is often possible to keep |
| | | system-level demands of a long-lived program down to a bare |
| | | minimum. For example, in one test suite of sessions measuring |
| | | the XF86 X server on Linux, using a trim threshold of 128K and a |
| | | mmap threshold of 192K led to near-minimal long term resource |
| | | consumption. |
| | | |
| | | If you are using this malloc in a long-lived program, it should |
| | | pay to experiment with these values. As a rough guide, you |
| | | might set to a value close to the average size of a process |
| | | (program) running on your system. Releasing this much memory |
| | | would allow such a process to run in memory. Generally, it's |
| | | worth it to tune for trimming rather tham memory mapping when a |
| | | program undergoes phases where several large chunks are |
| | | allocated and released in ways that can reuse each other's |
| | | storage, perhaps mixed with phases where there are no such |
| | | chunks at all. And in well-behaved long-lived programs, |
| | | controlling release of large blocks via trimming versus mapping |
| | | is usually faster. |
| | | |
| | | However, in most programs, these parameters serve mainly as |
| | | protection against the system-level effects of carrying around |
| | | massive amounts of unneeded memory. Since frequent calls to |
| | | sbrk, mmap, and munmap otherwise degrade performance, the default |
| | | parameters are set to relatively high values that serve only as |
| | | safeguards. |
| | | |
| | | The default trim value is high enough to cause trimming only in |
| | | fairly extreme (by current memory consumption standards) cases. |
| | | It must be greater than page size to have any useful effect. To |
| | | disable trimming completely, you can set to (unsigned long)(-1); |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef DEFAULT_TOP_PAD |
| | | #define DEFAULT_TOP_PAD (0) |
| | | #endif |
| | | |
| | | /* |
| | | M_TOP_PAD is the amount of extra `padding' space to allocate or |
| | | retain whenever sbrk is called. It is used in two ways internally: |
| | | |
| | | * When sbrk is called to extend the top of the arena to satisfy |
| | | a new malloc request, this much padding is added to the sbrk |
| | | request. |
| | | |
| | | * When malloc_trim is called automatically from free(), |
| | | it is used as the `pad' argument. |
| | | |
| | | In both cases, the actual amount of padding is rounded |
| | | so that the end of the arena is always a system page boundary. |
| | | |
| | | The main reason for using padding is to avoid calling sbrk so |
| | | often. Having even a small pad greatly reduces the likelihood |
| | | that nearly every malloc request during program start-up (or |
| | | after trimming) will invoke sbrk, which needlessly wastes |
| | | time. |
| | | |
| | | Automatic rounding-up to page-size units is normally sufficient |
| | | to avoid measurable overhead, so the default is 0. However, in |
| | | systems where sbrk is relatively slow, it can pay to increase |
| | | this value, at the expense of carrying around more memory than |
| | | the program needs. |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef DEFAULT_MMAP_THRESHOLD |
| | | #define DEFAULT_MMAP_THRESHOLD (128 * 1024) |
| | | #endif |
| | | |
| | | /* |
| | | |
| | | M_MMAP_THRESHOLD is the request size threshold for using mmap() |
| | | to service a request. Requests of at least this size that cannot |
| | | be allocated using already-existing space will be serviced via mmap. |
| | | (If enough normal freed space already exists it is used instead.) |
| | | |
| | | Using mmap segregates relatively large chunks of memory so that |
| | | they can be individually obtained and released from the host |
| | | system. A request serviced through mmap is never reused by any |
| | | other request (at least not directly; the system may just so |
| | | happen to remap successive requests to the same locations). |
| | | |
| | | Segregating space in this way has the benefit that mmapped space |
| | | can ALWAYS be individually released back to the system, which |
| | | helps keep the system level memory demands of a long-lived |
| | | program low. Mapped memory can never become `locked' between |
| | | other chunks, as can happen with normally allocated chunks, which |
| | | menas that even trimming via malloc_trim would not release them. |
| | | |
| | | However, it has the disadvantages that: |
| | | |
| | | 1. The space cannot be reclaimed, consolidated, and then |
| | | used to service later requests, as happens with normal chunks. |
| | | 2. It can lead to more wastage because of mmap page alignment |
| | | requirements |
| | | 3. It causes malloc performance to be more dependent on host |
| | | system memory management support routines which may vary in |
| | | implementation quality and may impose arbitrary |
| | | limitations. Generally, servicing a request via normal |
| | | malloc steps is faster than going through a system's mmap. |
| | | |
| | | All together, these considerations should lead you to use mmap |
| | | only for relatively large requests. |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef DEFAULT_MMAP_MAX |
| | | #if HAVE_MMAP |
| | | #define DEFAULT_MMAP_MAX (64) |
| | | #else |
| | | #define DEFAULT_MMAP_MAX (0) |
| | | #endif |
| | | #endif |
| | | |
| | | /* |
| | | M_MMAP_MAX is the maximum number of requests to simultaneously |
| | | service using mmap. This parameter exists because: |
| | | |
| | | 1. Some systems have a limited number of internal tables for |
| | | use by mmap. |
| | | 2. In most systems, overreliance on mmap can degrade overall |
| | | performance. |
| | | 3. If a program allocates many large regions, it is probably |
| | | better off using normal sbrk-based allocation routines that |
| | | can reclaim and reallocate normal heap memory. Using a |
| | | small value allows transition into this mode after the |
| | | first few allocations. |
| | | |
| | | Setting to 0 disables all use of mmap. If HAVE_MMAP is not set, |
| | | the default value is 0, and attempts to set it to non-zero values |
| | | in mallopt will fail. |
| | | */ |
| | | |
| | | |
| | | /* |
| | | USE_DL_PREFIX will prefix all public routines with the string 'dl'. |
| | | Useful to quickly avoid procedure declaration conflicts and linker |
| | | symbol conflicts with existing memory allocation routines. |
| | | |
| | | */ |
| | | |
| | | /* #define USE_DL_PREFIX */ |
| | | |
| | | |
| | | /* |
| | | |
| | | Special defines for linux libc |
| | | |
| | | Except when compiled using these special defines for Linux libc |
| | | using weak aliases, this malloc is NOT designed to work in |
| | | multithreaded applications. No semaphores or other concurrency |
| | | control are provided to ensure that multiple malloc or free calls |
| | | don't run at the same time, which could be disasterous. A single |
| | | semaphore could be used across malloc, realloc, and free (which is |
| | | essentially the effect of the linux weak alias approach). It would |
| | | be hard to obtain finer granularity. |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifdef INTERNAL_LINUX_C_LIB |
| | | |
| | | #if __STD_C |
| | | |
| | | Void_t * __default_morecore_init (ptrdiff_t); |
| | | Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; |
| | | |
| | | #else |
| | | |
| | | Void_t * __default_morecore_init (); |
| | | Void_t *(*__morecore)() = __default_morecore_init; |
| | | |
| | | #endif |
| | | |
| | | #define MORECORE (*__morecore) |
| | | #define MORECORE_FAILURE 0 |
| | | #define MORECORE_CLEARS 1 |
| | | |
| | | #else /* INTERNAL_LINUX_C_LIB */ |
| | | |
| | | #if __STD_C |
| | | extern Void_t* sbrk(ptrdiff_t); |
| | | #else |
| | | extern Void_t* sbrk(); |
| | | #endif |
| | | |
| | | #ifndef MORECORE |
| | | #define MORECORE sbrk |
| | | #endif |
| | | |
| | | #ifndef MORECORE_FAILURE |
| | | #define MORECORE_FAILURE -1 |
| | | #endif |
| | | |
| | | #ifndef MORECORE_CLEARS |
| | | #define MORECORE_CLEARS 1 |
| | | #endif |
| | | |
| | | #endif /* INTERNAL_LINUX_C_LIB */ |
| | | |
| | | #if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) |
| | | |
| | | #define cALLOc __libc_calloc |
| | | #define fREe __libc_free |
| | | #define mALLOc __libc_malloc |
| | | #define mEMALIGn __libc_memalign |
| | | #define rEALLOc __libc_realloc |
| | | #define vALLOc __libc_valloc |
| | | #define pvALLOc __libc_pvalloc |
| | | #define mALLINFo __libc_mallinfo |
| | | #define mALLOPt __libc_mallopt |
| | | |
| | | #pragma weak calloc = __libc_calloc |
| | | #pragma weak free = __libc_free |
| | | #pragma weak cfree = __libc_free |
| | | #pragma weak malloc = __libc_malloc |
| | | #pragma weak memalign = __libc_memalign |
| | | #pragma weak realloc = __libc_realloc |
| | | #pragma weak valloc = __libc_valloc |
| | | #pragma weak pvalloc = __libc_pvalloc |
| | | #pragma weak mallinfo = __libc_mallinfo |
| | | #pragma weak mallopt = __libc_mallopt |
| | | |
| | | #else |
| | | |
| | | #ifdef USE_DL_PREFIX |
| | | #define cALLOc dlcalloc |
| | | #define fREe dlfree |
| | | #define mALLOc dlmalloc |
| | | #define mEMALIGn dlmemalign |
| | | #define rEALLOc dlrealloc |
| | | #define vALLOc dlvalloc |
| | | #define pvALLOc dlpvalloc |
| | | #define mALLINFo dlmallinfo |
| | | #define mALLOPt dlmallopt |
| | | #else /* USE_DL_PREFIX */ |
| | | #define cALLOc calloc |
| | | #define fREe free |
| | | #define mALLOc malloc |
| | | #define mEMALIGn memalign |
| | | #define rEALLOc realloc |
| | | #define vALLOc valloc |
| | | #define pvALLOc pvalloc |
| | | #define mALLINFo mallinfo |
| | | #define mALLOPt mallopt |
| | | #endif /* USE_DL_PREFIX */ |
| | | |
| | | #endif |
| | | |
| | | /* Public routines */ |
| | | |
| | | #if __STD_C |
| | | |
| | | Void_t* mALLOc(size_t); |
| | | void fREe(Void_t*); |
| | | Void_t* rEALLOc(Void_t*, size_t); |
| | | Void_t* mEMALIGn(size_t, size_t); |
| | | Void_t* vALLOc(size_t); |
| | | Void_t* pvALLOc(size_t); |
| | | Void_t* cALLOc(size_t, size_t); |
| | | void cfree(Void_t*); |
| | | int malloc_trim(size_t); |
| | | size_t malloc_usable_size(Void_t*); |
| | | void malloc_stats(); |
| | | int mALLOPt(int, int); |
| | | struct mallinfo mALLINFo(void); |
| | | #else |
| | | Void_t* mALLOc(); |
| | | void fREe(); |
| | | Void_t* rEALLOc(); |
| | | Void_t* mEMALIGn(); |
| | | Void_t* vALLOc(); |
| | | Void_t* pvALLOc(); |
| | | Void_t* cALLOc(); |
| | | void cfree(); |
| | | int malloc_trim(); |
| | | size_t malloc_usable_size(); |
| | | void malloc_stats(); |
| | | int mALLOPt(); |
| | | struct mallinfo mALLINFo(); |
| | | #endif |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | }; /* end of extern "C" */ |
| | | #endif |
| | | |
| | | /* ---------- To make a malloc.h, end cutting here ------------ */ |
| | | #endif /* 0 */ /* Moved to malloc.h */ |
| | | |
| | | #include <malloc.h> |
| | | #ifdef DEBUG |
| | | #if __STD_C |
| | | static void malloc_update_mallinfo (void); |
| | | void malloc_stats (void); |
| | | #else |
| | | static void malloc_update_mallinfo (); |
| | | void malloc_stats(); |
| | | #endif |
| | | #endif /* DEBUG */ |
| | | |
| | | /* |
| | | Emulation of sbrk for WIN32 |
| | | All code within the ifdef WIN32 is untested by me. |
| | | |
| | | Thanks to Martin Fong and others for supplying this. |
| | | */ |
| | | |
| | | |
| | | #ifdef WIN32 |
| | | |
| | | #define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \ |
| | | ~(malloc_getpagesize-1)) |
| | | #define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1)) |
| | | |
| | | /* resrve 64MB to insure large contiguous space */ |
| | | #define RESERVED_SIZE (1024*1024*64) |
| | | #define NEXT_SIZE (2048*1024) |
| | | #define TOP_MEMORY ((unsigned long)2*1024*1024*1024) |
| | | |
| | | struct GmListElement; |
| | | typedef struct GmListElement GmListElement; |
| | | |
| | | struct GmListElement |
| | | { |
| | | GmListElement* next; |
| | | void* base; |
| | | }; |
| | | |
| | | static GmListElement* head = 0; |
| | | static unsigned int gNextAddress = 0; |
| | | static unsigned int gAddressBase = 0; |
| | | static unsigned int gAllocatedSize = 0; |
| | | |
| | | static |
| | | GmListElement* makeGmListElement (void* bas) |
| | | { |
| | | GmListElement* this; |
| | | this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement)); |
| | | assert (this); |
| | | if (this) |
| | | { |
| | | this->base = bas; |
| | | this->next = head; |
| | | head = this; |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | void gcleanup () |
| | | { |
| | | BOOL rval; |
| | | assert ( (head == NULL) || (head->base == (void*)gAddressBase)); |
| | | if (gAddressBase && (gNextAddress - gAddressBase)) |
| | | { |
| | | rval = VirtualFree ((void*)gAddressBase, |
| | | gNextAddress - gAddressBase, |
| | | MEM_DECOMMIT); |
| | | assert (rval); |
| | | } |
| | | while (head) |
| | | { |
| | | GmListElement* next = head->next; |
| | | rval = VirtualFree (head->base, 0, MEM_RELEASE); |
| | | assert (rval); |
| | | LocalFree (head); |
| | | head = next; |
| | | } |
| | | } |
| | | |
| | | static |
| | | void* findRegion (void* start_address, unsigned long size) |
| | | { |
| | | MEMORY_BASIC_INFORMATION info; |
| | | if (size >= TOP_MEMORY) return NULL; |
| | | |
| | | while ((unsigned long)start_address + size < TOP_MEMORY) |
| | | { |
| | | VirtualQuery (start_address, &info, sizeof (info)); |
| | | if ((info.State == MEM_FREE) && (info.RegionSize >= size)) |
| | | return start_address; |
| | | else |
| | | { |
| | | /* Requested region is not available so see if the */ |
| | | /* next region is available. Set 'start_address' */ |
| | | /* to the next region and call 'VirtualQuery()' */ |
| | | /* again. */ |
| | | |
| | | start_address = (char*)info.BaseAddress + info.RegionSize; |
| | | |
| | | /* Make sure we start looking for the next region */ |
| | | /* on the *next* 64K boundary. Otherwise, even if */ |
| | | /* the new region is free according to */ |
| | | /* 'VirtualQuery()', the subsequent call to */ |
| | | /* 'VirtualAlloc()' (which follows the call to */ |
| | | /* this routine in 'wsbrk()') will round *down* */ |
| | | /* the requested address to a 64K boundary which */ |
| | | /* we already know is an address in the */ |
| | | /* unavailable region. Thus, the subsequent call */ |
| | | /* to 'VirtualAlloc()' will fail and bring us back */ |
| | | /* here, causing us to go into an infinite loop. */ |
| | | |
| | | start_address = |
| | | (void *) AlignPage64K((unsigned long) start_address); |
| | | } |
| | | } |
| | | return NULL; |
| | | |
| | | } |
| | | |
| | | |
| | | void* wsbrk (long size) |
| | | { |
| | | void* tmp; |
| | | if (size > 0) |
| | | { |
| | | if (gAddressBase == 0) |
| | | { |
| | | gAllocatedSize = max (RESERVED_SIZE, AlignPage (size)); |
| | | gNextAddress = gAddressBase = |
| | | (unsigned int)VirtualAlloc (NULL, gAllocatedSize, |
| | | MEM_RESERVE, PAGE_NOACCESS); |
| | | } else if (AlignPage (gNextAddress + size) > (gAddressBase + |
| | | gAllocatedSize)) |
| | | { |
| | | long new_size = max (NEXT_SIZE, AlignPage (size)); |
| | | void* new_address = (void*)(gAddressBase+gAllocatedSize); |
| | | do |
| | | { |
| | | new_address = findRegion (new_address, new_size); |
| | | |
| | | if (new_address == 0) |
| | | return (void*)-1; |
| | | |
| | | gAddressBase = gNextAddress = |
| | | (unsigned int)VirtualAlloc (new_address, new_size, |
| | | MEM_RESERVE, PAGE_NOACCESS); |
| | | /* repeat in case of race condition */ |
| | | /* The region that we found has been snagged */ |
| | | /* by another thread */ |
| | | } |
| | | while (gAddressBase == 0); |
| | | |
| | | assert (new_address == (void*)gAddressBase); |
| | | |
| | | gAllocatedSize = new_size; |
| | | |
| | | if (!makeGmListElement ((void*)gAddressBase)) |
| | | return (void*)-1; |
| | | } |
| | | if ((size + gNextAddress) > AlignPage (gNextAddress)) |
| | | { |
| | | void* res; |
| | | res = VirtualAlloc ((void*)AlignPage (gNextAddress), |
| | | (size + gNextAddress - |
| | | AlignPage (gNextAddress)), |
| | | MEM_COMMIT, PAGE_READWRITE); |
| | | if (res == 0) |
| | | return (void*)-1; |
| | | } |
| | | tmp = (void*)gNextAddress; |
| | | gNextAddress = (unsigned int)tmp + size; |
| | | return tmp; |
| | | } |
| | | else if (size < 0) |
| | | { |
| | | unsigned int alignedGoal = AlignPage (gNextAddress + size); |
| | | /* Trim by releasing the virtual memory */ |
| | | if (alignedGoal >= gAddressBase) |
| | | { |
| | | VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal, |
| | | MEM_DECOMMIT); |
| | | gNextAddress = gNextAddress + size; |
| | | return (void*)gNextAddress; |
| | | } |
| | | else |
| | | { |
| | | VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase, |
| | | MEM_DECOMMIT); |
| | | gNextAddress = gAddressBase; |
| | | return (void*)-1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | return (void*)gNextAddress; |
| | | } |
| | | } |
| | | |
| | | #endif |
| | | |
| | | |
| | | |
| | | /* |
| | | Type declarations |
| | | */ |
| | | |
| | | |
| | | struct malloc_chunk |
| | | { |
| | | INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ |
| | | INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ |
| | | struct malloc_chunk* fd; /* double links -- used only if free. */ |
| | | struct malloc_chunk* bk; |
| | | } __attribute__((__may_alias__)) ; |
| | | |
| | | typedef struct malloc_chunk* mchunkptr; |
| | | |
| | | /* |
| | | |
| | | malloc_chunk details: |
| | | |
| | | (The following includes lightly edited explanations by Colin Plumb.) |
| | | |
| | | Chunks of memory are maintained using a `boundary tag' method as |
| | | described in e.g., Knuth or Standish. (See the paper by Paul |
| | | Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a |
| | | survey of such techniques.) Sizes of free chunks are stored both |
| | | in the front of each chunk and at the end. This makes |
| | | consolidating fragmented chunks into bigger chunks very fast. The |
| | | size fields also hold bits representing whether chunks are free or |
| | | in use. |
| | | |
| | | An allocated chunk looks like this: |
| | | |
| | | |
| | | chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Size of previous chunk, if allocated | | |
| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Size of chunk, in bytes |P| |
| | | mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | User data starts here... . |
| | | . . |
| | | . (malloc_usable_space() bytes) . |
| | | . | |
| | | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Size of chunk | |
| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | |
| | | |
| | | Where "chunk" is the front of the chunk for the purpose of most of |
| | | the malloc code, but "mem" is the pointer that is returned to the |
| | | user. "Nextchunk" is the beginning of the next contiguous chunk. |
| | | |
| | | Chunks always begin on even word boundries, so the mem portion |
| | | (which is returned to the user) is also on an even word boundary, and |
| | | thus double-word aligned. |
| | | |
| | | Free chunks are stored in circular doubly-linked lists, and look like this: |
| | | |
| | | chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Size of previous chunk | |
| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | `head:' | Size of chunk, in bytes |P| |
| | | mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Forward pointer to next chunk in list | |
| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Back pointer to previous chunk in list | |
| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | | Unused space (may be 0 bytes long) . |
| | | . . |
| | | . | |
| | | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | `foot:' | Size of chunk, in bytes | |
| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | | |
| | | The P (PREV_INUSE) bit, stored in the unused low-order bit of the |
| | | chunk size (which is always a multiple of two words), is an in-use |
| | | bit for the *previous* chunk. If that bit is *clear*, then the |
| | | word before the current chunk size contains the previous chunk |
| | | size, and can be used to find the front of the previous chunk. |
| | | (The very first chunk allocated always has this bit set, |
| | | preventing access to non-existent (or non-owned) memory.) |
| | | |
| | | Note that the `foot' of the current chunk is actually represented |
| | | as the prev_size of the NEXT chunk. (This makes it easier to |
| | | deal with alignments etc). |
| | | |
| | | The two exceptions to all this are |
| | | |
| | | 1. The special chunk `top', which doesn't bother using the |
| | | trailing size field since there is no |
| | | next contiguous chunk that would have to index off it. (After |
| | | initialization, `top' is forced to always exist. If it would |
| | | become less than MINSIZE bytes long, it is replenished via |
| | | malloc_extend_top.) |
| | | |
| | | 2. Chunks allocated via mmap, which have the second-lowest-order |
| | | bit (IS_MMAPPED) set in their size fields. Because they are |
| | | never merged or traversed from any other chunk, they have no |
| | | foot size or inuse information. |
| | | |
| | | Available chunks are kept in any of several places (all declared below): |
| | | |
| | | * `av': An array of chunks serving as bin headers for consolidated |
| | | chunks. Each bin is doubly linked. The bins are approximately |
| | | proportionally (log) spaced. There are a lot of these bins |
| | | (128). This may look excessive, but works very well in |
| | | practice. All procedures maintain the invariant that no |
| | | consolidated chunk physically borders another one. Chunks in |
| | | bins are kept in size order, with ties going to the |
| | | approximately least recently used chunk. |
| | | |
| | | The chunks in each bin are maintained in decreasing sorted order by |
| | | size. This is irrelevant for the small bins, which all contain |
| | | the same-sized chunks, but facilitates best-fit allocation for |
| | | larger chunks. (These lists are just sequential. Keeping them in |
| | | order almost never requires enough traversal to warrant using |
| | | fancier ordered data structures.) Chunks of the same size are |
| | | linked with the most recently freed at the front, and allocations |
| | | are taken from the back. This results in LRU or FIFO allocation |
| | | order, which tends to give each chunk an equal opportunity to be |
| | | consolidated with adjacent freed chunks, resulting in larger free |
| | | chunks and less fragmentation. |
| | | |
| | | * `top': The top-most available chunk (i.e., the one bordering the |
| | | end of available memory) is treated specially. It is never |
| | | included in any bin, is used only if no other chunk is |
| | | available, and is released back to the system if it is very |
| | | large (see M_TRIM_THRESHOLD). |
| | | |
| | | * `last_remainder': A bin holding only the remainder of the |
| | | most recently split (non-top) chunk. This bin is checked |
| | | before other non-fitting chunks, so as to provide better |
| | | locality for runs of sequentially allocated chunks. |
| | | |
| | | * Implicitly, through the host system's memory mapping tables. |
| | | If supported, requests greater than a threshold are usually |
| | | serviced via calls to mmap, and then later released via munmap. |
| | | |
| | | */ |
| | | |
| | | /* sizes, alignments */ |
| | | |
| | | #define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) |
| | | #define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ) |
| | | #define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) |
| | | #define MINSIZE (sizeof(struct malloc_chunk)) |
| | | |
| | | /* conversion from malloc headers to user pointers, and back */ |
| | | |
| | | #define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) |
| | | #define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) |
| | | |
| | | /* pad request bytes into a usable size */ |
| | | |
| | | #define request2size(req) \ |
| | | (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \ |
| | | (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \ |
| | | (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK))) |
| | | |
| | | /* Check if m has acceptable alignment */ |
| | | |
| | | #define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | Physical chunk operations |
| | | */ |
| | | |
| | | |
| | | /* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ |
| | | |
| | | #define PREV_INUSE 0x1 |
| | | |
| | | /* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ |
| | | |
| | | #define IS_MMAPPED 0x2 |
| | | |
| | | /* Bits to mask off when extracting size */ |
| | | |
| | | #define SIZE_BITS (PREV_INUSE|IS_MMAPPED) |
| | | |
| | | |
| | | /* Ptr to next physical malloc_chunk. */ |
| | | |
| | | #define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) |
| | | |
| | | /* Ptr to previous physical malloc_chunk */ |
| | | |
| | | #define prev_chunk(p)\ |
| | | ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) |
| | | |
| | | |
| | | /* Treat space at ptr + offset as a chunk */ |
| | | |
| | | #define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | Dealing with use bits |
| | | */ |
| | | |
| | | /* extract p's inuse bit */ |
| | | |
| | | #define inuse(p)\ |
| | | ((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) |
| | | |
| | | /* extract inuse bit of previous chunk */ |
| | | |
| | | #define prev_inuse(p) ((p)->size & PREV_INUSE) |
| | | |
| | | /* check for mmap()'ed chunk */ |
| | | |
| | | #define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) |
| | | |
| | | /* set/clear chunk as in use without otherwise disturbing */ |
| | | |
| | | #define set_inuse(p)\ |
| | | ((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE |
| | | |
| | | #define clear_inuse(p)\ |
| | | ((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) |
| | | |
| | | /* check/set/clear inuse bits in known places */ |
| | | |
| | | #define inuse_bit_at_offset(p, s)\ |
| | | (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) |
| | | |
| | | #define set_inuse_bit_at_offset(p, s)\ |
| | | (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) |
| | | |
| | | #define clear_inuse_bit_at_offset(p, s)\ |
| | | (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | Dealing with size fields |
| | | */ |
| | | |
| | | /* Get size, ignoring use bits */ |
| | | |
| | | #define chunksize(p) ((p)->size & ~(SIZE_BITS)) |
| | | |
| | | /* Set size at head, without disturbing its use bit */ |
| | | |
| | | #define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) |
| | | |
| | | /* Set size/use ignoring previous bits in header */ |
| | | |
| | | #define set_head(p, s) ((p)->size = (s)) |
| | | |
| | | /* Set size at footer (only when chunk is not in use) */ |
| | | |
| | | #define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | Bins |
| | | |
| | | The bins, `av_' are an array of pairs of pointers serving as the |
| | | heads of (initially empty) doubly-linked lists of chunks, laid out |
| | | in a way so that each pair can be treated as if it were in a |
| | | malloc_chunk. (This way, the fd/bk offsets for linking bin heads |
| | | and chunks are the same). |
| | | |
| | | Bins for sizes < 512 bytes contain chunks of all the same size, spaced |
| | | 8 bytes apart. Larger bins are approximately logarithmically |
| | | spaced. (See the table below.) The `av_' array is never mentioned |
| | | directly in the code, but instead via bin access macros. |
| | | |
| | | Bin layout: |
| | | |
| | | 64 bins of size 8 |
| | | 32 bins of size 64 |
| | | 16 bins of size 512 |
| | | 8 bins of size 4096 |
| | | 4 bins of size 32768 |
| | | 2 bins of size 262144 |
| | | 1 bin of size what's left |
| | | |
| | | There is actually a little bit of slop in the numbers in bin_index |
| | | for the sake of speed. This makes no difference elsewhere. |
| | | |
| | | The special chunks `top' and `last_remainder' get their own bins, |
| | | (this is implemented via yet more trickery with the av_ array), |
| | | although `top' is never properly linked to its bin since it is |
| | | always handled specially. |
| | | |
| | | */ |
| | | |
| | | #define NAV 128 /* number of bins */ |
| | | |
| | | typedef struct malloc_chunk* mbinptr; |
| | | |
| | | /* access macros */ |
| | | |
| | | #define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ)) |
| | | #define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr))) |
| | | #define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr))) |
| | | |
| | | /* |
| | | The first 2 bins are never indexed. The corresponding av_ cells are instead |
| | | used for bookkeeping. This is not to save space, but to simplify |
| | | indexing, maintain locality, and avoid some initialization tests. |
| | | */ |
| | | |
| | | #define top (av_[2]) /* The topmost chunk */ |
| | | #define last_remainder (bin_at(1)) /* remainder from last split */ |
| | | |
| | | |
| | | /* |
| | | Because top initially points to its own bin with initial |
| | | zero size, thus forcing extension on the first malloc request, |
| | | we avoid having any special code in malloc to check whether |
| | | it even exists yet. But we still need to in malloc_extend_top. |
| | | */ |
| | | |
| | | #define initial_top ((mchunkptr)(bin_at(0))) |
| | | |
| | | /* Helper macro to initialize bins */ |
| | | |
| | | #define IAV(i) bin_at(i), bin_at(i) |
| | | |
| | | static mbinptr av_[NAV * 2 + 2] = { |
| | | NULL, NULL, |
| | | IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), |
| | | IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), |
| | | IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23), |
| | | IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31), |
| | | IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39), |
| | | IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47), |
| | | IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55), |
| | | IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63), |
| | | IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71), |
| | | IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79), |
| | | IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87), |
| | | IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95), |
| | | IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103), |
| | | IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), |
| | | IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), |
| | | IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) |
| | | }; |
| | | |
| | | ulong mem_malloc_start = 0; |
| | | ulong mem_malloc_end = 0; |
| | | ulong mem_malloc_brk = 0; |
| | | |
| | | void *sbrk(ptrdiff_t increment) |
| | | { |
| | | ulong old = mem_malloc_brk; |
| | | ulong new = old + increment; |
| | | |
| | | /* |
| | | * if we are giving memory back make sure we clear it out since |
| | | * we set MORECORE_CLEARS to 1 |
| | | */ |
| | | if (increment < 0) |
| | | memset((void *)new, 0, -increment); |
| | | |
| | | if ((new < mem_malloc_start) || (new > mem_malloc_end)) |
| | | return (void *)MORECORE_FAILURE; |
| | | |
| | | mem_malloc_brk = new; |
| | | |
| | | return (void *)old; |
| | | } |
| | | |
| | | void mem_malloc_init(ulong start, ulong size) |
| | | { |
| | | mem_malloc_start = start; |
| | | mem_malloc_end = start + size; |
| | | mem_malloc_brk = start; |
| | | |
| | | memset((void *)mem_malloc_start, 0, size); |
| | | printf("malloc memory space: 0x%lx~0x%lx\n", start, start+size); |
| | | } |
| | | |
| | | /* field-extraction macros */ |
| | | |
| | | #define first(b) ((b)->fd) |
| | | #define last(b) ((b)->bk) |
| | | |
| | | /* |
| | | Indexing into bins |
| | | */ |
| | | |
| | | #define bin_index(sz) \ |
| | | (((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \ |
| | | ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \ |
| | | ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \ |
| | | ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \ |
| | | ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \ |
| | | ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \ |
| | | 126) |
| | | /* |
| | | bins for chunks < 512 are all spaced 8 bytes apart, and hold |
| | | identically sized chunks. This is exploited in malloc. |
| | | */ |
| | | |
| | | #define MAX_SMALLBIN 63 |
| | | #define MAX_SMALLBIN_SIZE 512 |
| | | #define SMALLBIN_WIDTH 8 |
| | | |
| | | #define smallbin_index(sz) (((unsigned long)(sz)) >> 3) |
| | | |
| | | /* |
| | | Requests are `small' if both the corresponding and the next bin are small |
| | | */ |
| | | |
| | | #define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH) |
| | | |
| | | |
| | | |
| | | /* |
| | | To help compensate for the large number of bins, a one-level index |
| | | structure is used for bin-by-bin searching. `binblocks' is a |
| | | one-word bitvector recording whether groups of BINBLOCKWIDTH bins |
| | | have any (possibly) non-empty bins, so they can be skipped over |
| | | all at once during during traversals. The bits are NOT always |
| | | cleared as soon as all bins in a block are empty, but instead only |
| | | when all are noticed to be empty during traversal in malloc. |
| | | */ |
| | | |
| | | #define BINBLOCKWIDTH 4 /* bins per block */ |
| | | |
| | | #define binblocks_r ((INTERNAL_SIZE_T)av_[1]) /* bitvector of nonempty blocks */ |
| | | #define binblocks_w (av_[1]) |
| | | |
| | | /* bin<->block macros */ |
| | | |
| | | #define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH)) |
| | | #define mark_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r | idx2binblock(ii))) |
| | | #define clear_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r & ~(idx2binblock(ii)))) |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /* Other static bookkeeping data */ |
| | | |
| | | /* variables holding tunable values */ |
| | | |
| | | static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD; |
| | | static unsigned long top_pad = DEFAULT_TOP_PAD; |
| | | static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX; |
| | | static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD; |
| | | |
| | | /* The first value returned from sbrk */ |
| | | static char* sbrk_base = (char*)(-1); |
| | | |
| | | /* The maximum memory obtained from system via sbrk */ |
| | | static unsigned long max_sbrked_mem = 0; |
| | | |
| | | /* The maximum via either sbrk or mmap */ |
| | | static unsigned long max_total_mem = 0; |
| | | |
| | | /* internal working copy of mallinfo */ |
| | | static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
| | | |
| | | /* The total memory obtained from system via sbrk */ |
| | | #define sbrked_mem (current_mallinfo.arena) |
| | | |
| | | /* Tracking mmaps */ |
| | | |
| | | #ifdef DEBUG |
| | | static unsigned int n_mmaps = 0; |
| | | #endif /* DEBUG */ |
| | | static unsigned long mmapped_mem = 0; |
| | | #if HAVE_MMAP |
| | | static unsigned int max_n_mmaps = 0; |
| | | static unsigned long max_mmapped_mem = 0; |
| | | #endif |
| | | |
| | | |
| | | |
| | | /* |
| | | Debugging support |
| | | */ |
| | | |
| | | #ifdef DEBUG |
| | | |
| | | |
| | | /* |
| | | These routines make a number of assertions about the states |
| | | of data structures that should be true at all times. If any |
| | | are not true, it's very likely that a user program has somehow |
| | | trashed memory. (It's also possible that there is a coding error |
| | | in malloc. In which case, please report it!) |
| | | */ |
| | | |
| | | #if __STD_C |
| | | static void do_check_chunk(mchunkptr p) |
| | | #else |
| | | static void do_check_chunk(p) mchunkptr p; |
| | | #endif |
| | | { |
| | | INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; |
| | | |
| | | /* No checkable chunk is mmapped */ |
| | | assert(!chunk_is_mmapped(p)); |
| | | |
| | | /* Check for legal address ... */ |
| | | assert((char*)p >= sbrk_base); |
| | | if (p != top) |
| | | assert((char*)p + sz <= (char*)top); |
| | | else |
| | | assert((char*)p + sz <= sbrk_base + sbrked_mem); |
| | | |
| | | } |
| | | |
| | | |
| | | #if __STD_C |
| | | static void do_check_free_chunk(mchunkptr p) |
| | | #else |
| | | static void do_check_free_chunk(p) mchunkptr p; |
| | | #endif |
| | | { |
| | | INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; |
| | | mchunkptr next = chunk_at_offset(p, sz); |
| | | |
| | | do_check_chunk(p); |
| | | |
| | | /* Check whether it claims to be free ... */ |
| | | assert(!inuse(p)); |
| | | |
| | | /* Unless a special marker, must have OK fields */ |
| | | if ((long)sz >= (long)MINSIZE) |
| | | { |
| | | assert((sz & MALLOC_ALIGN_MASK) == 0); |
| | | assert(aligned_OK(chunk2mem(p))); |
| | | /* ... matching footer field */ |
| | | assert(next->prev_size == sz); |
| | | /* ... and is fully consolidated */ |
| | | assert(prev_inuse(p)); |
| | | assert (next == top || inuse(next)); |
| | | |
| | | /* ... and has minimally sane links */ |
| | | assert(p->fd->bk == p); |
| | | assert(p->bk->fd == p); |
| | | } |
| | | else /* markers are always of size SIZE_SZ */ |
| | | assert(sz == SIZE_SZ); |
| | | } |
| | | |
| | | #if __STD_C |
| | | static void do_check_inuse_chunk(mchunkptr p) |
| | | #else |
| | | static void do_check_inuse_chunk(p) mchunkptr p; |
| | | #endif |
| | | { |
| | | mchunkptr next = next_chunk(p); |
| | | do_check_chunk(p); |
| | | |
| | | /* Check whether it claims to be in use ... */ |
| | | assert(inuse(p)); |
| | | |
| | | /* ... and is surrounded by OK chunks. |
| | | Since more things can be checked with free chunks than inuse ones, |
| | | if an inuse chunk borders them and debug is on, it's worth doing them. |
| | | */ |
| | | if (!prev_inuse(p)) |
| | | { |
| | | mchunkptr prv = prev_chunk(p); |
| | | assert(next_chunk(prv) == p); |
| | | do_check_free_chunk(prv); |
| | | } |
| | | if (next == top) |
| | | { |
| | | assert(prev_inuse(next)); |
| | | assert(chunksize(next) >= MINSIZE); |
| | | } |
| | | else if (!inuse(next)) |
| | | do_check_free_chunk(next); |
| | | |
| | | } |
| | | |
| | | #if __STD_C |
| | | static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) |
| | | #else |
| | | static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; |
| | | #endif |
| | | { |
| | | INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; |
| | | long room = sz - s; |
| | | |
| | | do_check_inuse_chunk(p); |
| | | |
| | | /* Legal size ... */ |
| | | assert((long)sz >= (long)MINSIZE); |
| | | assert((sz & MALLOC_ALIGN_MASK) == 0); |
| | | assert(room >= 0); |
| | | assert(room < (long)MINSIZE); |
| | | |
| | | /* ... and alignment */ |
| | | assert(aligned_OK(chunk2mem(p))); |
| | | |
| | | |
| | | /* ... and was allocated at front of an available chunk */ |
| | | assert(prev_inuse(p)); |
| | | |
| | | } |
| | | |
| | | |
| | | #define check_free_chunk(P) do_check_free_chunk(P) |
| | | #define check_inuse_chunk(P) do_check_inuse_chunk(P) |
| | | #define check_chunk(P) do_check_chunk(P) |
| | | #define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) |
| | | #else |
| | | #define check_free_chunk(P) |
| | | #define check_inuse_chunk(P) |
| | | #define check_chunk(P) |
| | | #define check_malloced_chunk(P,N) |
| | | #endif |
| | | |
| | | |
| | | |
| | | /* |
| | | Macro-based internal utilities |
| | | */ |
| | | |
| | | |
| | | /* |
| | | Linking chunks in bin lists. |
| | | Call these only with variables, not arbitrary expressions, as arguments. |
| | | */ |
| | | |
| | | /* |
| | | Place chunk p of size s in its bin, in size order, |
| | | putting it ahead of others of same size. |
| | | */ |
| | | |
| | | |
| | | #define frontlink(P, S, IDX, BK, FD) \ |
| | | { \ |
| | | if (S < MAX_SMALLBIN_SIZE) \ |
| | | { \ |
| | | IDX = smallbin_index(S); \ |
| | | mark_binblock(IDX); \ |
| | | BK = bin_at(IDX); \ |
| | | FD = BK->fd; \ |
| | | P->bk = BK; \ |
| | | P->fd = FD; \ |
| | | FD->bk = BK->fd = P; \ |
| | | } \ |
| | | else \ |
| | | { \ |
| | | IDX = bin_index(S); \ |
| | | BK = bin_at(IDX); \ |
| | | FD = BK->fd; \ |
| | | if (FD == BK) mark_binblock(IDX); \ |
| | | else \ |
| | | { \ |
| | | while (FD != BK && S < chunksize(FD)) FD = FD->fd; \ |
| | | BK = FD->bk; \ |
| | | } \ |
| | | P->bk = BK; \ |
| | | P->fd = FD; \ |
| | | FD->bk = BK->fd = P; \ |
| | | } \ |
| | | } |
| | | |
| | | |
| | | /* take a chunk off a list */ |
| | | |
| | | #define unlink(P, BK, FD) \ |
| | | { \ |
| | | BK = P->bk; \ |
| | | FD = P->fd; \ |
| | | FD->bk = BK; \ |
| | | BK->fd = FD; \ |
| | | } \ |
| | | |
| | | /* Place p as the last remainder */ |
| | | |
| | | #define link_last_remainder(P) \ |
| | | { \ |
| | | last_remainder->fd = last_remainder->bk = P; \ |
| | | P->fd = P->bk = last_remainder; \ |
| | | } |
| | | |
| | | /* Clear the last_remainder bin */ |
| | | |
| | | #define clear_last_remainder \ |
| | | (last_remainder->fd = last_remainder->bk = last_remainder) |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /* Routines dealing with mmap(). */ |
| | | |
| | | #if HAVE_MMAP |
| | | |
| | | #if __STD_C |
| | | static mchunkptr mmap_chunk(size_t size) |
| | | #else |
| | | static mchunkptr mmap_chunk(size) size_t size; |
| | | #endif |
| | | { |
| | | size_t page_mask = malloc_getpagesize - 1; |
| | | mchunkptr p; |
| | | |
| | | #ifndef MAP_ANONYMOUS |
| | | static int fd = -1; |
| | | #endif |
| | | |
| | | if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */ |
| | | |
| | | /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because |
| | | * there is no following chunk whose prev_size field could be used. |
| | | */ |
| | | size = (size + SIZE_SZ + page_mask) & ~page_mask; |
| | | |
| | | #ifdef MAP_ANONYMOUS |
| | | p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, |
| | | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
| | | #else /* !MAP_ANONYMOUS */ |
| | | if (fd < 0) |
| | | { |
| | | fd = open("/dev/zero", O_RDWR); |
| | | if(fd < 0) return 0; |
| | | } |
| | | p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); |
| | | #endif |
| | | |
| | | if(p == (mchunkptr)-1) return 0; |
| | | |
| | | n_mmaps++; |
| | | if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps; |
| | | |
| | | /* We demand that eight bytes into a page must be 8-byte aligned. */ |
| | | assert(aligned_OK(chunk2mem(p))); |
| | | |
| | | /* The offset to the start of the mmapped region is stored |
| | | * in the prev_size field of the chunk; normally it is zero, |
| | | * but that can be changed in memalign(). |
| | | */ |
| | | p->prev_size = 0; |
| | | set_head(p, size|IS_MMAPPED); |
| | | |
| | | mmapped_mem += size; |
| | | if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) |
| | | max_mmapped_mem = mmapped_mem; |
| | | if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) |
| | | max_total_mem = mmapped_mem + sbrked_mem; |
| | | return p; |
| | | } |
| | | |
| | | #if __STD_C |
| | | static void munmap_chunk(mchunkptr p) |
| | | #else |
| | | static void munmap_chunk(p) mchunkptr p; |
| | | #endif |
| | | { |
| | | INTERNAL_SIZE_T size = chunksize(p); |
| | | int ret; |
| | | |
| | | assert (chunk_is_mmapped(p)); |
| | | assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); |
| | | assert((n_mmaps > 0)); |
| | | assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0); |
| | | |
| | | n_mmaps--; |
| | | mmapped_mem -= (size + p->prev_size); |
| | | |
| | | ret = munmap((char *)p - p->prev_size, size + p->prev_size); |
| | | |
| | | /* munmap returns non-zero on failure */ |
| | | assert(ret == 0); |
| | | } |
| | | |
| | | #if HAVE_MREMAP |
| | | |
| | | #if __STD_C |
| | | static mchunkptr mremap_chunk(mchunkptr p, size_t new_size) |
| | | #else |
| | | static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size; |
| | | #endif |
| | | { |
| | | size_t page_mask = malloc_getpagesize - 1; |
| | | INTERNAL_SIZE_T offset = p->prev_size; |
| | | INTERNAL_SIZE_T size = chunksize(p); |
| | | char *cp; |
| | | |
| | | assert (chunk_is_mmapped(p)); |
| | | assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); |
| | | assert((n_mmaps > 0)); |
| | | assert(((size + offset) & (malloc_getpagesize-1)) == 0); |
| | | |
| | | /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */ |
| | | new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask; |
| | | |
| | | cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1); |
| | | |
| | | if (cp == (char *)-1) return 0; |
| | | |
| | | p = (mchunkptr)(cp + offset); |
| | | |
| | | assert(aligned_OK(chunk2mem(p))); |
| | | |
| | | assert((p->prev_size == offset)); |
| | | set_head(p, (new_size - offset)|IS_MMAPPED); |
| | | |
| | | mmapped_mem -= size + offset; |
| | | mmapped_mem += new_size; |
| | | if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) |
| | | max_mmapped_mem = mmapped_mem; |
| | | if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) |
| | | max_total_mem = mmapped_mem + sbrked_mem; |
| | | return p; |
| | | } |
| | | |
| | | #endif /* HAVE_MREMAP */ |
| | | |
| | | #endif /* HAVE_MMAP */ |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | Extend the top-most chunk by obtaining memory from system. |
| | | Main interface to sbrk (but see also malloc_trim). |
| | | */ |
| | | |
| | | #if __STD_C |
| | | static void malloc_extend_top(INTERNAL_SIZE_T nb) |
| | | #else |
| | | static void malloc_extend_top(nb) INTERNAL_SIZE_T nb; |
| | | #endif |
| | | { |
| | | char* brk; /* return value from sbrk */ |
| | | INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */ |
| | | INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */ |
| | | char* new_brk; /* return of 2nd sbrk call */ |
| | | INTERNAL_SIZE_T top_size; /* new size of top chunk */ |
| | | |
| | | mchunkptr old_top = top; /* Record state of old top */ |
| | | INTERNAL_SIZE_T old_top_size = chunksize(old_top); |
| | | char* old_end = (char*)(chunk_at_offset(old_top, old_top_size)); |
| | | |
| | | /* Pad request with top_pad plus minimal overhead */ |
| | | |
| | | INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE; |
| | | unsigned long pagesz = malloc_getpagesize; |
| | | |
| | | /* If not the first time through, round to preserve page boundary */ |
| | | /* Otherwise, we need to correct to a page size below anyway. */ |
| | | /* (We also correct below if an intervening foreign sbrk call.) */ |
| | | |
| | | if (sbrk_base != (char*)(-1)) |
| | | sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1); |
| | | |
| | | brk = (char*)(MORECORE (sbrk_size)); |
| | | |
| | | /* Fail if sbrk failed or if a foreign sbrk call killed our space */ |
| | | if (brk == (char*)(MORECORE_FAILURE) || |
| | | (brk < old_end && old_top != initial_top)) |
| | | return; |
| | | |
| | | sbrked_mem += sbrk_size; |
| | | |
| | | if (brk == old_end) /* can just add bytes to current top */ |
| | | { |
| | | top_size = sbrk_size + old_top_size; |
| | | set_head(top, top_size | PREV_INUSE); |
| | | } |
| | | else |
| | | { |
| | | if (sbrk_base == (char*)(-1)) /* First time through. Record base */ |
| | | sbrk_base = brk; |
| | | else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */ |
| | | sbrked_mem += brk - (char*)old_end; |
| | | |
| | | /* Guarantee alignment of first new chunk made from this space */ |
| | | front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK; |
| | | if (front_misalign > 0) |
| | | { |
| | | correction = (MALLOC_ALIGNMENT) - front_misalign; |
| | | brk += correction; |
| | | } |
| | | else |
| | | correction = 0; |
| | | |
| | | /* Guarantee the next brk will be at a page boundary */ |
| | | |
| | | correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) & |
| | | ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size)); |
| | | |
| | | /* Allocate correction */ |
| | | new_brk = (char*)(MORECORE (correction)); |
| | | if (new_brk == (char*)(MORECORE_FAILURE)) return; |
| | | |
| | | sbrked_mem += correction; |
| | | |
| | | top = (mchunkptr)brk; |
| | | top_size = new_brk - brk + correction; |
| | | set_head(top, top_size | PREV_INUSE); |
| | | |
| | | if (old_top != initial_top) |
| | | { |
| | | |
| | | /* There must have been an intervening foreign sbrk call. */ |
| | | /* A double fencepost is necessary to prevent consolidation */ |
| | | |
| | | /* If not enough space to do this, then user did something very wrong */ |
| | | if (old_top_size < MINSIZE) |
| | | { |
| | | set_head(top, PREV_INUSE); /* will force null return from malloc */ |
| | | return; |
| | | } |
| | | |
| | | /* Also keep size a multiple of MALLOC_ALIGNMENT */ |
| | | old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; |
| | | set_head_size(old_top, old_top_size); |
| | | chunk_at_offset(old_top, old_top_size )->size = |
| | | SIZE_SZ|PREV_INUSE; |
| | | chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size = |
| | | SIZE_SZ|PREV_INUSE; |
| | | /* If possible, release the rest. */ |
| | | if (old_top_size >= MINSIZE) |
| | | fREe(chunk2mem(old_top)); |
| | | } |
| | | } |
| | | |
| | | if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem) |
| | | max_sbrked_mem = sbrked_mem; |
| | | if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) |
| | | max_total_mem = mmapped_mem + sbrked_mem; |
| | | |
| | | /* We always land on a page boundary */ |
| | | assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /* Main public routines */ |
| | | |
| | | |
| | | /* |
| | | Malloc Algorthim: |
| | | |
| | | The requested size is first converted into a usable form, `nb'. |
| | | This currently means to add 4 bytes overhead plus possibly more to |
| | | obtain 8-byte alignment and/or to obtain a size of at least |
| | | MINSIZE (currently 16 bytes), the smallest allocatable size. |
| | | (All fits are considered `exact' if they are within MINSIZE bytes.) |
| | | |
| | | From there, the first successful of the following steps is taken: |
| | | |
| | | 1. The bin corresponding to the request size is scanned, and if |
| | | a chunk of exactly the right size is found, it is taken. |
| | | |
| | | 2. The most recently remaindered chunk is used if it is big |
| | | enough. This is a form of (roving) first fit, used only in |
| | | the absence of exact fits. Runs of consecutive requests use |
| | | the remainder of the chunk used for the previous such request |
| | | whenever possible. This limited use of a first-fit style |
| | | allocation strategy tends to give contiguous chunks |
| | | coextensive lifetimes, which improves locality and can reduce |
| | | fragmentation in the long run. |
| | | |
| | | 3. Other bins are scanned in increasing size order, using a |
| | | chunk big enough to fulfill the request, and splitting off |
| | | any remainder. This search is strictly by best-fit; i.e., |
| | | the smallest (with ties going to approximately the least |
| | | recently used) chunk that fits is selected. |
| | | |
| | | 4. If large enough, the chunk bordering the end of memory |
| | | (`top') is split off. (This use of `top' is in accord with |
| | | the best-fit search rule. In effect, `top' is treated as |
| | | larger (and thus less well fitting) than any other available |
| | | chunk since it can be extended to be as large as necessary |
| | | (up to system limitations). |
| | | |
| | | 5. If the request size meets the mmap threshold and the |
| | | system supports mmap, and there are few enough currently |
| | | allocated mmapped regions, and a call to mmap succeeds, |
| | | the request is allocated via direct memory mapping. |
| | | |
| | | 6. Otherwise, the top of memory is extended by |
| | | obtaining more space from the system (normally using sbrk, |
| | | but definable to anything else via the MORECORE macro). |
| | | Memory is gathered from the system (in system page-sized |
| | | units) in a way that allows chunks obtained across different |
| | | sbrk calls to be consolidated, but does not require |
| | | contiguous memory. Thus, it should be safe to intersperse |
| | | mallocs with other sbrk calls. |
| | | |
| | | |
| | | All allocations are made from the the `lowest' part of any found |
| | | chunk. (The implementation invariant is that prev_inuse is |
| | | always true of any allocated chunk; i.e., that each allocated |
| | | chunk borders either a previously allocated and still in-use chunk, |
| | | or the base of its memory arena.) |
| | | |
| | | */ |
| | | |
| | | #if __STD_C |
| | | Void_t* mALLOc(size_t bytes) |
| | | #else |
| | | Void_t* mALLOc(bytes) size_t bytes; |
| | | #endif |
| | | { |
| | | mchunkptr victim; /* inspected/selected chunk */ |
| | | INTERNAL_SIZE_T victim_size; /* its size */ |
| | | int idx; /* index for bin traversal */ |
| | | mbinptr bin; /* associated bin */ |
| | | mchunkptr remainder; /* remainder from a split */ |
| | | long remainder_size; /* its size */ |
| | | int remainder_index; /* its bin index */ |
| | | unsigned long block; /* block traverser bit */ |
| | | int startidx; /* first bin of a traversed block */ |
| | | mchunkptr fwd; /* misc temp for linking */ |
| | | mchunkptr bck; /* misc temp for linking */ |
| | | mbinptr q; /* misc temp */ |
| | | |
| | | INTERNAL_SIZE_T nb; |
| | | |
| | | /* check if mem_malloc_init() was run */ |
| | | if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) { |
| | | /* not initialized yet */ |
| | | return NULL; |
| | | } |
| | | |
| | | if ((long)bytes < 0) return NULL; |
| | | |
| | | nb = request2size(bytes); /* padded request size; */ |
| | | |
| | | /* Check for exact match in a bin */ |
| | | |
| | | if (is_small_request(nb)) /* Faster version for small requests */ |
| | | { |
| | | idx = smallbin_index(nb); |
| | | |
| | | /* No traversal or size check necessary for small bins. */ |
| | | |
| | | q = bin_at(idx); |
| | | victim = last(q); |
| | | |
| | | /* Also scan the next one, since it would have a remainder < MINSIZE */ |
| | | if (victim == q) |
| | | { |
| | | q = next_bin(q); |
| | | victim = last(q); |
| | | } |
| | | if (victim != q) |
| | | { |
| | | victim_size = chunksize(victim); |
| | | unlink(victim, bck, fwd); |
| | | set_inuse_bit_at_offset(victim, victim_size); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | } |
| | | |
| | | idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */ |
| | | |
| | | } |
| | | else |
| | | { |
| | | idx = bin_index(nb); |
| | | bin = bin_at(idx); |
| | | |
| | | for (victim = last(bin); victim != bin; victim = victim->bk) |
| | | { |
| | | victim_size = chunksize(victim); |
| | | remainder_size = victim_size - nb; |
| | | |
| | | if (remainder_size >= (long)MINSIZE) /* too big */ |
| | | { |
| | | --idx; /* adjust to rescan below after checking last remainder */ |
| | | break; |
| | | } |
| | | |
| | | else if (remainder_size >= 0) /* exact fit */ |
| | | { |
| | | unlink(victim, bck, fwd); |
| | | set_inuse_bit_at_offset(victim, victim_size); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | } |
| | | } |
| | | |
| | | ++idx; |
| | | |
| | | } |
| | | |
| | | /* Try to use the last split-off remainder */ |
| | | |
| | | if ( (victim = last_remainder->fd) != last_remainder) |
| | | { |
| | | victim_size = chunksize(victim); |
| | | remainder_size = victim_size - nb; |
| | | |
| | | if (remainder_size >= (long)MINSIZE) /* re-split */ |
| | | { |
| | | remainder = chunk_at_offset(victim, nb); |
| | | set_head(victim, nb | PREV_INUSE); |
| | | link_last_remainder(remainder); |
| | | set_head(remainder, remainder_size | PREV_INUSE); |
| | | set_foot(remainder, remainder_size); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | } |
| | | |
| | | clear_last_remainder; |
| | | |
| | | if (remainder_size >= 0) /* exhaust */ |
| | | { |
| | | set_inuse_bit_at_offset(victim, victim_size); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | } |
| | | |
| | | /* Else place in bin */ |
| | | |
| | | frontlink(victim, victim_size, remainder_index, bck, fwd); |
| | | } |
| | | |
| | | /* |
| | | If there are any possibly nonempty big-enough blocks, |
| | | search for best fitting chunk by scanning bins in blockwidth units. |
| | | */ |
| | | |
| | | if ( (block = idx2binblock(idx)) <= binblocks_r) |
| | | { |
| | | |
| | | /* Get to the first marked block */ |
| | | |
| | | if ( (block & binblocks_r) == 0) |
| | | { |
| | | /* force to an even block boundary */ |
| | | idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH; |
| | | block <<= 1; |
| | | while ((block & binblocks_r) == 0) |
| | | { |
| | | idx += BINBLOCKWIDTH; |
| | | block <<= 1; |
| | | } |
| | | } |
| | | |
| | | /* For each possibly nonempty block ... */ |
| | | for (;;) |
| | | { |
| | | startidx = idx; /* (track incomplete blocks) */ |
| | | q = bin = bin_at(idx); |
| | | |
| | | /* For each bin in this block ... */ |
| | | do |
| | | { |
| | | /* Find and use first big enough chunk ... */ |
| | | |
| | | for (victim = last(bin); victim != bin; victim = victim->bk) |
| | | { |
| | | victim_size = chunksize(victim); |
| | | remainder_size = victim_size - nb; |
| | | |
| | | if (remainder_size >= (long)MINSIZE) /* split */ |
| | | { |
| | | remainder = chunk_at_offset(victim, nb); |
| | | set_head(victim, nb | PREV_INUSE); |
| | | unlink(victim, bck, fwd); |
| | | link_last_remainder(remainder); |
| | | set_head(remainder, remainder_size | PREV_INUSE); |
| | | set_foot(remainder, remainder_size); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | } |
| | | |
| | | else if (remainder_size >= 0) /* take */ |
| | | { |
| | | set_inuse_bit_at_offset(victim, victim_size); |
| | | unlink(victim, bck, fwd); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | } |
| | | |
| | | } |
| | | |
| | | bin = next_bin(bin); |
| | | |
| | | } while ((++idx & (BINBLOCKWIDTH - 1)) != 0); |
| | | |
| | | /* Clear out the block bit. */ |
| | | |
| | | do /* Possibly backtrack to try to clear a partial block */ |
| | | { |
| | | if ((startidx & (BINBLOCKWIDTH - 1)) == 0) |
| | | { |
| | | av_[1] = (mbinptr)(binblocks_r & ~block); |
| | | break; |
| | | } |
| | | --startidx; |
| | | q = prev_bin(q); |
| | | } while (first(q) == q); |
| | | |
| | | /* Get to the next possibly nonempty block */ |
| | | |
| | | if ( (block <<= 1) <= binblocks_r && (block != 0) ) |
| | | { |
| | | while ((block & binblocks_r) == 0) |
| | | { |
| | | idx += BINBLOCKWIDTH; |
| | | block <<= 1; |
| | | } |
| | | } |
| | | else |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | /* Try to use top chunk */ |
| | | |
| | | /* Require that there be a remainder, ensuring top always exists */ |
| | | if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) |
| | | { |
| | | |
| | | #if HAVE_MMAP |
| | | /* If big and would otherwise need to extend, try to use mmap instead */ |
| | | if ((unsigned long)nb >= (unsigned long)mmap_threshold && |
| | | (victim = mmap_chunk(nb)) != 0) |
| | | return chunk2mem(victim); |
| | | #endif |
| | | |
| | | /* Try to extend */ |
| | | malloc_extend_top(nb); |
| | | if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) |
| | | return NULL; /* propagate failure */ |
| | | } |
| | | |
| | | victim = top; |
| | | set_head(victim, nb | PREV_INUSE); |
| | | top = chunk_at_offset(victim, nb); |
| | | set_head(top, remainder_size | PREV_INUSE); |
| | | check_malloced_chunk(victim, nb); |
| | | return chunk2mem(victim); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | |
| | | free() algorithm : |
| | | |
| | | cases: |
| | | |
| | | 1. free(0) has no effect. |
| | | |
| | | 2. If the chunk was allocated via mmap, it is release via munmap(). |
| | | |
| | | 3. If a returned chunk borders the current high end of memory, |
| | | it is consolidated into the top, and if the total unused |
| | | topmost memory exceeds the trim threshold, malloc_trim is |
| | | called. |
| | | |
| | | 4. Other chunks are consolidated as they arrive, and |
| | | placed in corresponding bins. (This includes the case of |
| | | consolidating with the current `last_remainder'). |
| | | |
| | | */ |
| | | |
| | | |
| | | #if __STD_C |
| | | void fREe(Void_t* mem) |
| | | #else |
| | | void fREe(mem) Void_t* mem; |
| | | #endif |
| | | { |
| | | mchunkptr p; /* chunk corresponding to mem */ |
| | | INTERNAL_SIZE_T hd; /* its head field */ |
| | | INTERNAL_SIZE_T sz; /* its size */ |
| | | int idx; /* its bin index */ |
| | | mchunkptr next; /* next contiguous chunk */ |
| | | INTERNAL_SIZE_T nextsz; /* its size */ |
| | | INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */ |
| | | mchunkptr bck; /* misc temp for linking */ |
| | | mchunkptr fwd; /* misc temp for linking */ |
| | | int islr; /* track whether merging with last_remainder */ |
| | | |
| | | if (mem == NULL) /* free(0) has no effect */ |
| | | return; |
| | | |
| | | p = mem2chunk(mem); |
| | | hd = p->size; |
| | | |
| | | #if HAVE_MMAP |
| | | if (hd & IS_MMAPPED) /* release mmapped memory. */ |
| | | { |
| | | munmap_chunk(p); |
| | | return; |
| | | } |
| | | #endif |
| | | |
| | | check_inuse_chunk(p); |
| | | |
| | | sz = hd & ~PREV_INUSE; |
| | | next = chunk_at_offset(p, sz); |
| | | nextsz = chunksize(next); |
| | | |
| | | if (next == top) /* merge with top */ |
| | | { |
| | | sz += nextsz; |
| | | |
| | | if (!(hd & PREV_INUSE)) /* consolidate backward */ |
| | | { |
| | | prevsz = p->prev_size; |
| | | p = chunk_at_offset(p, -((long) prevsz)); |
| | | sz += prevsz; |
| | | unlink(p, bck, fwd); |
| | | } |
| | | |
| | | set_head(p, sz | PREV_INUSE); |
| | | top = p; |
| | | if ((unsigned long)(sz) >= (unsigned long)trim_threshold) |
| | | malloc_trim(top_pad); |
| | | return; |
| | | } |
| | | |
| | | set_head(next, nextsz); /* clear inuse bit */ |
| | | |
| | | islr = 0; |
| | | |
| | | if (!(hd & PREV_INUSE)) /* consolidate backward */ |
| | | { |
| | | prevsz = p->prev_size; |
| | | p = chunk_at_offset(p, -((long) prevsz)); |
| | | sz += prevsz; |
| | | |
| | | if (p->fd == last_remainder) /* keep as last_remainder */ |
| | | islr = 1; |
| | | else |
| | | unlink(p, bck, fwd); |
| | | } |
| | | |
| | | if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */ |
| | | { |
| | | sz += nextsz; |
| | | |
| | | if (!islr && next->fd == last_remainder) /* re-insert last_remainder */ |
| | | { |
| | | islr = 1; |
| | | link_last_remainder(p); |
| | | } |
| | | else |
| | | unlink(next, bck, fwd); |
| | | } |
| | | |
| | | |
| | | set_head(p, sz | PREV_INUSE); |
| | | set_foot(p, sz); |
| | | if (!islr) |
| | | frontlink(p, sz, idx, bck, fwd); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | |
| | | Realloc algorithm: |
| | | |
| | | Chunks that were obtained via mmap cannot be extended or shrunk |
| | | unless HAVE_MREMAP is defined, in which case mremap is used. |
| | | Otherwise, if their reallocation is for additional space, they are |
| | | copied. If for less, they are just left alone. |
| | | |
| | | Otherwise, if the reallocation is for additional space, and the |
| | | chunk can be extended, it is, else a malloc-copy-free sequence is |
| | | taken. There are several different ways that a chunk could be |
| | | extended. All are tried: |
| | | |
| | | * Extending forward into following adjacent free chunk. |
| | | * Shifting backwards, joining preceding adjacent space |
| | | * Both shifting backwards and extending forward. |
| | | * Extending into newly sbrked space |
| | | |
| | | Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a |
| | | size argument of zero (re)allocates a minimum-sized chunk. |
| | | |
| | | If the reallocation is for less space, and the new request is for |
| | | a `small' (<512 bytes) size, then the newly unused space is lopped |
| | | off and freed. |
| | | |
| | | The old unix realloc convention of allowing the last-free'd chunk |
| | | to be used as an argument to realloc is no longer supported. |
| | | I don't know of any programs still relying on this feature, |
| | | and allowing it would also allow too many other incorrect |
| | | usages of realloc to be sensible. |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | #if __STD_C |
| | | Void_t* rEALLOc(Void_t* oldmem, size_t bytes) |
| | | #else |
| | | Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; |
| | | #endif |
| | | { |
| | | INTERNAL_SIZE_T nb; /* padded request size */ |
| | | |
| | | mchunkptr oldp; /* chunk corresponding to oldmem */ |
| | | INTERNAL_SIZE_T oldsize; /* its size */ |
| | | |
| | | mchunkptr newp; /* chunk to return */ |
| | | INTERNAL_SIZE_T newsize; /* its size */ |
| | | Void_t* newmem; /* corresponding user mem */ |
| | | |
| | | mchunkptr next; /* next contiguous chunk after oldp */ |
| | | INTERNAL_SIZE_T nextsize; /* its size */ |
| | | |
| | | mchunkptr prev; /* previous contiguous chunk before oldp */ |
| | | INTERNAL_SIZE_T prevsize; /* its size */ |
| | | |
| | | mchunkptr remainder; /* holds split off extra space from newp */ |
| | | INTERNAL_SIZE_T remainder_size; /* its size */ |
| | | |
| | | mchunkptr bck; /* misc temp for linking */ |
| | | mchunkptr fwd; /* misc temp for linking */ |
| | | |
| | | #ifdef REALLOC_ZERO_BYTES_FREES |
| | | if (bytes == 0) { fREe(oldmem); return 0; } |
| | | #endif |
| | | |
| | | if ((long)bytes < 0) return NULL; |
| | | |
| | | /* realloc of null is supposed to be same as malloc */ |
| | | if (oldmem == NULL) return mALLOc(bytes); |
| | | |
| | | newp = oldp = mem2chunk(oldmem); |
| | | newsize = oldsize = chunksize(oldp); |
| | | |
| | | |
| | | nb = request2size(bytes); |
| | | |
| | | #if HAVE_MMAP |
| | | if (chunk_is_mmapped(oldp)) |
| | | { |
| | | #if HAVE_MREMAP |
| | | newp = mremap_chunk(oldp, nb); |
| | | if(newp) return chunk2mem(newp); |
| | | #endif |
| | | /* Note the extra SIZE_SZ overhead. */ |
| | | if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */ |
| | | /* Must alloc, copy, free. */ |
| | | newmem = mALLOc(bytes); |
| | | if (newmem == 0) return 0; /* propagate failure */ |
| | | MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); |
| | | munmap_chunk(oldp); |
| | | return newmem; |
| | | } |
| | | #endif |
| | | |
| | | check_inuse_chunk(oldp); |
| | | |
| | | if ((long)(oldsize) < (long)(nb)) |
| | | { |
| | | |
| | | /* Try expanding forward */ |
| | | |
| | | next = chunk_at_offset(oldp, oldsize); |
| | | if (next == top || !inuse(next)) |
| | | { |
| | | nextsize = chunksize(next); |
| | | |
| | | /* Forward into top only if a remainder */ |
| | | if (next == top) |
| | | { |
| | | if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE)) |
| | | { |
| | | newsize += nextsize; |
| | | top = chunk_at_offset(oldp, nb); |
| | | set_head(top, (newsize - nb) | PREV_INUSE); |
| | | set_head_size(oldp, nb); |
| | | return chunk2mem(oldp); |
| | | } |
| | | } |
| | | |
| | | /* Forward into next chunk */ |
| | | else if (((long)(nextsize + newsize) >= (long)(nb))) |
| | | { |
| | | unlink(next, bck, fwd); |
| | | newsize += nextsize; |
| | | goto split; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | next = NULL; |
| | | nextsize = 0; |
| | | } |
| | | |
| | | /* Try shifting backwards. */ |
| | | |
| | | if (!prev_inuse(oldp)) |
| | | { |
| | | prev = prev_chunk(oldp); |
| | | prevsize = chunksize(prev); |
| | | |
| | | /* try forward + backward first to save a later consolidation */ |
| | | |
| | | if (next != NULL) |
| | | { |
| | | /* into top */ |
| | | if (next == top) |
| | | { |
| | | if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE)) |
| | | { |
| | | unlink(prev, bck, fwd); |
| | | newp = prev; |
| | | newsize += prevsize + nextsize; |
| | | newmem = chunk2mem(newp); |
| | | MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
| | | top = chunk_at_offset(newp, nb); |
| | | set_head(top, (newsize - nb) | PREV_INUSE); |
| | | set_head_size(newp, nb); |
| | | return newmem; |
| | | } |
| | | } |
| | | |
| | | /* into next chunk */ |
| | | else if (((long)(nextsize + prevsize + newsize) >= (long)(nb))) |
| | | { |
| | | unlink(next, bck, fwd); |
| | | unlink(prev, bck, fwd); |
| | | newp = prev; |
| | | newsize += nextsize + prevsize; |
| | | newmem = chunk2mem(newp); |
| | | MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
| | | goto split; |
| | | } |
| | | } |
| | | |
| | | /* backward only */ |
| | | if (prev != NULL && (long)(prevsize + newsize) >= (long)nb) |
| | | { |
| | | unlink(prev, bck, fwd); |
| | | newp = prev; |
| | | newsize += prevsize; |
| | | newmem = chunk2mem(newp); |
| | | MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
| | | goto split; |
| | | } |
| | | } |
| | | |
| | | /* Must allocate */ |
| | | |
| | | newmem = mALLOc (bytes); |
| | | |
| | | if (newmem == NULL) /* propagate failure */ |
| | | return NULL; |
| | | |
| | | /* Avoid copy if newp is next chunk after oldp. */ |
| | | /* (This can only happen when new chunk is sbrk'ed.) */ |
| | | |
| | | if ( (newp = mem2chunk(newmem)) == next_chunk(oldp)) |
| | | { |
| | | newsize += chunksize(newp); |
| | | newp = oldp; |
| | | goto split; |
| | | } |
| | | |
| | | /* Otherwise copy, free, and exit */ |
| | | MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
| | | fREe(oldmem); |
| | | return newmem; |
| | | } |
| | | |
| | | |
| | | split: /* split off extra room in old or expanded chunk */ |
| | | |
| | | if (newsize - nb >= MINSIZE) /* split off remainder */ |
| | | { |
| | | remainder = chunk_at_offset(newp, nb); |
| | | remainder_size = newsize - nb; |
| | | set_head_size(newp, nb); |
| | | set_head(remainder, remainder_size | PREV_INUSE); |
| | | set_inuse_bit_at_offset(remainder, remainder_size); |
| | | fREe(chunk2mem(remainder)); /* let free() deal with it */ |
| | | } |
| | | else |
| | | { |
| | | set_head_size(newp, newsize); |
| | | set_inuse_bit_at_offset(newp, newsize); |
| | | } |
| | | |
| | | check_inuse_chunk(newp); |
| | | return chunk2mem(newp); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | |
| | | memalign algorithm: |
| | | |
| | | memalign requests more than enough space from malloc, finds a spot |
| | | within that chunk that meets the alignment request, and then |
| | | possibly frees the leading and trailing space. |
| | | |
| | | The alignment argument must be a power of two. This property is not |
| | | checked by memalign, so misuse may result in random runtime errors. |
| | | |
| | | 8-byte alignment is guaranteed by normal malloc calls, so don't |
| | | bother calling memalign with an argument of 8 or less. |
| | | |
| | | Overreliance on memalign is a sure way to fragment space. |
| | | |
| | | */ |
| | | |
| | | |
| | | #if __STD_C |
| | | Void_t* mEMALIGn(size_t alignment, size_t bytes) |
| | | #else |
| | | Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; |
| | | #endif |
| | | { |
| | | INTERNAL_SIZE_T nb; /* padded request size */ |
| | | char* m; /* memory returned by malloc call */ |
| | | mchunkptr p; /* corresponding chunk */ |
| | | char* brk; /* alignment point within p */ |
| | | mchunkptr newp; /* chunk to return */ |
| | | INTERNAL_SIZE_T newsize; /* its size */ |
| | | INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */ |
| | | mchunkptr remainder; /* spare room at end to split off */ |
| | | long remainder_size; /* its size */ |
| | | |
| | | if ((long)bytes < 0) return NULL; |
| | | |
| | | /* If need less alignment than we give anyway, just relay to malloc */ |
| | | |
| | | if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); |
| | | |
| | | /* Otherwise, ensure that it is at least a minimum chunk size */ |
| | | |
| | | if (alignment < MINSIZE) alignment = MINSIZE; |
| | | |
| | | /* Call malloc with worst case padding to hit alignment. */ |
| | | |
| | | nb = request2size(bytes); |
| | | m = (char*)(mALLOc(nb + alignment + MINSIZE)); |
| | | |
| | | if (m == NULL) return NULL; /* propagate failure */ |
| | | |
| | | p = mem2chunk(m); |
| | | |
| | | if ((((unsigned long)(m)) % alignment) == 0) /* aligned */ |
| | | { |
| | | #if HAVE_MMAP |
| | | if(chunk_is_mmapped(p)) |
| | | return chunk2mem(p); /* nothing more to do */ |
| | | #endif |
| | | } |
| | | else /* misaligned */ |
| | | { |
| | | /* |
| | | Find an aligned spot inside chunk. |
| | | Since we need to give back leading space in a chunk of at |
| | | least MINSIZE, if the first calculation places us at |
| | | a spot with less than MINSIZE leader, we can move to the |
| | | next aligned spot -- we've allocated enough total room so that |
| | | this is always possible. |
| | | */ |
| | | |
| | | brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment)); |
| | | if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment; |
| | | |
| | | newp = (mchunkptr)brk; |
| | | leadsize = brk - (char*)(p); |
| | | newsize = chunksize(p) - leadsize; |
| | | |
| | | #if HAVE_MMAP |
| | | if(chunk_is_mmapped(p)) |
| | | { |
| | | newp->prev_size = p->prev_size + leadsize; |
| | | set_head(newp, newsize|IS_MMAPPED); |
| | | return chunk2mem(newp); |
| | | } |
| | | #endif |
| | | |
| | | /* give back leader, use the rest */ |
| | | |
| | | set_head(newp, newsize | PREV_INUSE); |
| | | set_inuse_bit_at_offset(newp, newsize); |
| | | set_head_size(p, leadsize); |
| | | fREe(chunk2mem(p)); |
| | | p = newp; |
| | | |
| | | assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0); |
| | | } |
| | | |
| | | /* Also give back spare room at the end */ |
| | | |
| | | remainder_size = chunksize(p) - nb; |
| | | |
| | | if (remainder_size >= (long)MINSIZE) |
| | | { |
| | | remainder = chunk_at_offset(p, nb); |
| | | set_head(remainder, remainder_size | PREV_INUSE); |
| | | set_head_size(p, nb); |
| | | fREe(chunk2mem(remainder)); |
| | | } |
| | | |
| | | check_inuse_chunk(p); |
| | | return chunk2mem(p); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | valloc just invokes memalign with alignment argument equal |
| | | to the page size of the system (or as near to this as can |
| | | be figured out from all the includes/defines above.) |
| | | */ |
| | | |
| | | #if __STD_C |
| | | Void_t* vALLOc(size_t bytes) |
| | | #else |
| | | Void_t* vALLOc(bytes) size_t bytes; |
| | | #endif |
| | | { |
| | | return mEMALIGn (malloc_getpagesize, bytes); |
| | | } |
| | | |
| | | /* |
| | | pvalloc just invokes valloc for the nearest pagesize |
| | | that will accommodate request |
| | | */ |
| | | |
| | | |
| | | #if __STD_C |
| | | Void_t* pvALLOc(size_t bytes) |
| | | #else |
| | | Void_t* pvALLOc(bytes) size_t bytes; |
| | | #endif |
| | | { |
| | | size_t pagesize = malloc_getpagesize; |
| | | return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1)); |
| | | } |
| | | |
| | | /* |
| | | |
| | | calloc calls malloc, then zeroes out the allocated chunk. |
| | | |
| | | */ |
| | | |
| | | #if __STD_C |
| | | Void_t* cALLOc(size_t n, size_t elem_size) |
| | | #else |
| | | Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; |
| | | #endif |
| | | { |
| | | mchunkptr p; |
| | | INTERNAL_SIZE_T csz; |
| | | |
| | | INTERNAL_SIZE_T sz = n * elem_size; |
| | | |
| | | |
| | | /* check if expand_top called, in which case don't need to clear */ |
| | | #if MORECORE_CLEARS |
| | | mchunkptr oldtop = top; |
| | | INTERNAL_SIZE_T oldtopsize = chunksize(top); |
| | | #endif |
| | | Void_t* mem = mALLOc (sz); |
| | | |
| | | if ((long)n < 0) return NULL; |
| | | |
| | | if (mem == NULL) |
| | | return NULL; |
| | | else |
| | | { |
| | | p = mem2chunk(mem); |
| | | |
| | | /* Two optional cases in which clearing not necessary */ |
| | | |
| | | |
| | | #if HAVE_MMAP |
| | | if (chunk_is_mmapped(p)) return mem; |
| | | #endif |
| | | |
| | | csz = chunksize(p); |
| | | |
| | | #if MORECORE_CLEARS |
| | | if (p == oldtop && csz > oldtopsize) |
| | | { |
| | | /* clear only the bytes from non-freshly-sbrked memory */ |
| | | csz = oldtopsize; |
| | | } |
| | | #endif |
| | | |
| | | MALLOC_ZERO(mem, csz - SIZE_SZ); |
| | | return mem; |
| | | } |
| | | } |
| | | |
| | | /* |
| | | |
| | | cfree just calls free. It is needed/defined on some systems |
| | | that pair it with calloc, presumably for odd historical reasons. |
| | | |
| | | */ |
| | | |
| | | #if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__) |
| | | #if __STD_C |
| | | void cfree(Void_t *mem) |
| | | #else |
| | | void cfree(mem) Void_t *mem; |
| | | #endif |
| | | { |
| | | fREe(mem); |
| | | } |
| | | #endif |
| | | |
| | | |
| | | |
| | | /* |
| | | |
| | | Malloc_trim gives memory back to the system (via negative |
| | | arguments to sbrk) if there is unused memory at the `high' end of |
| | | the malloc pool. You can call this after freeing large blocks of |
| | | memory to potentially reduce the system-level memory requirements |
| | | of a program. However, it cannot guarantee to reduce memory. Under |
| | | some allocation patterns, some large free blocks of memory will be |
| | | locked between two used chunks, so they cannot be given back to |
| | | the system. |
| | | |
| | | The `pad' argument to malloc_trim represents the amount of free |
| | | trailing space to leave untrimmed. If this argument is zero, |
| | | only the minimum amount of memory to maintain internal data |
| | | structures will be left (one page or less). Non-zero arguments |
| | | can be supplied to maintain enough trailing space to service |
| | | future expected allocations without having to re-obtain memory |
| | | from the system. |
| | | |
| | | Malloc_trim returns 1 if it actually released any memory, else 0. |
| | | |
| | | */ |
| | | |
| | | #if __STD_C |
| | | int malloc_trim(size_t pad) |
| | | #else |
| | | int malloc_trim(pad) size_t pad; |
| | | #endif |
| | | { |
| | | long top_size; /* Amount of top-most memory */ |
| | | long extra; /* Amount to release */ |
| | | char* current_brk; /* address returned by pre-check sbrk call */ |
| | | char* new_brk; /* address returned by negative sbrk call */ |
| | | |
| | | unsigned long pagesz = malloc_getpagesize; |
| | | |
| | | top_size = chunksize(top); |
| | | extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; |
| | | |
| | | if (extra < (long)pagesz) /* Not enough memory to release */ |
| | | return 0; |
| | | |
| | | else |
| | | { |
| | | /* Test to make sure no one else called sbrk */ |
| | | current_brk = (char*)(MORECORE (0)); |
| | | if (current_brk != (char*)(top) + top_size) |
| | | return 0; /* Apparently we don't own memory; must fail */ |
| | | |
| | | else |
| | | { |
| | | new_brk = (char*)(MORECORE (-extra)); |
| | | |
| | | if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */ |
| | | { |
| | | /* Try to figure out what we have */ |
| | | current_brk = (char*)(MORECORE (0)); |
| | | top_size = current_brk - (char*)top; |
| | | if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */ |
| | | { |
| | | sbrked_mem = current_brk - sbrk_base; |
| | | set_head(top, top_size | PREV_INUSE); |
| | | } |
| | | check_chunk(top); |
| | | return 0; |
| | | } |
| | | |
| | | else |
| | | { |
| | | /* Success. Adjust top accordingly. */ |
| | | set_head(top, (top_size - extra) | PREV_INUSE); |
| | | sbrked_mem -= extra; |
| | | check_chunk(top); |
| | | return 1; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /* |
| | | malloc_usable_size: |
| | | |
| | | This routine tells you how many bytes you can actually use in an |
| | | allocated chunk, which may be more than you requested (although |
| | | often not). You can use this many bytes without worrying about |
| | | overwriting other allocated objects. Not a particularly great |
| | | programming practice, but still sometimes useful. |
| | | |
| | | */ |
| | | |
| | | #if __STD_C |
| | | size_t malloc_usable_size(Void_t* mem) |
| | | #else |
| | | size_t malloc_usable_size(mem) Void_t* mem; |
| | | #endif |
| | | { |
| | | mchunkptr p; |
| | | if (mem == NULL) |
| | | return 0; |
| | | else |
| | | { |
| | | p = mem2chunk(mem); |
| | | if(!chunk_is_mmapped(p)) |
| | | { |
| | | if (!inuse(p)) return 0; |
| | | check_inuse_chunk(p); |
| | | return chunksize(p) - SIZE_SZ; |
| | | } |
| | | return chunksize(p) - 2*SIZE_SZ; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /* Utility to update current_mallinfo for malloc_stats and mallinfo() */ |
| | | |
| | | #ifdef DEBUG |
| | | static void malloc_update_mallinfo() |
| | | { |
| | | int i; |
| | | mbinptr b; |
| | | mchunkptr p; |
| | | #ifdef DEBUG |
| | | mchunkptr q; |
| | | #endif |
| | | |
| | | INTERNAL_SIZE_T avail = chunksize(top); |
| | | int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0; |
| | | |
| | | for (i = 1; i < NAV; ++i) |
| | | { |
| | | b = bin_at(i); |
| | | for (p = last(b); p != b; p = p->bk) |
| | | { |
| | | #ifdef DEBUG |
| | | check_free_chunk(p); |
| | | for (q = next_chunk(p); |
| | | q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; |
| | | q = next_chunk(q)) |
| | | check_inuse_chunk(q); |
| | | #endif |
| | | avail += chunksize(p); |
| | | navail++; |
| | | } |
| | | } |
| | | |
| | | current_mallinfo.ordblks = navail; |
| | | current_mallinfo.uordblks = sbrked_mem - avail; |
| | | current_mallinfo.fordblks = avail; |
| | | current_mallinfo.hblks = n_mmaps; |
| | | current_mallinfo.hblkhd = mmapped_mem; |
| | | current_mallinfo.keepcost = chunksize(top); |
| | | |
| | | } |
| | | #endif /* DEBUG */ |
| | | |
| | | |
| | | |
| | | /* |
| | | |
| | | malloc_stats: |
| | | |
| | | Prints on the amount of space obtain from the system (both |
| | | via sbrk and mmap), the maximum amount (which may be more than |
| | | current if malloc_trim and/or munmap got called), the maximum |
| | | number of simultaneous mmap regions used, and the current number |
| | | of bytes allocated via malloc (or realloc, etc) but not yet |
| | | freed. (Note that this is the number of bytes allocated, not the |
| | | number requested. It will be larger than the number requested |
| | | because of alignment and bookkeeping overhead.) |
| | | |
| | | */ |
| | | |
| | | #ifdef DEBUG |
| | | void malloc_stats() |
| | | { |
| | | malloc_update_mallinfo(); |
| | | printf("max system bytes = %10u\n", |
| | | (unsigned int)(max_total_mem)); |
| | | printf("system bytes = %10u\n", |
| | | (unsigned int)(sbrked_mem + mmapped_mem)); |
| | | printf("in use bytes = %10u\n", |
| | | (unsigned int)(current_mallinfo.uordblks + mmapped_mem)); |
| | | #if HAVE_MMAP |
| | | printf("max mmap regions = %10u\n", |
| | | (unsigned int)max_n_mmaps); |
| | | #endif |
| | | } |
| | | #endif /* DEBUG */ |
| | | |
| | | /* |
| | | mallinfo returns a copy of updated current mallinfo. |
| | | */ |
| | | |
| | | #ifdef DEBUG |
| | | struct mallinfo mALLINFo() |
| | | { |
| | | malloc_update_mallinfo(); |
| | | return current_mallinfo; |
| | | } |
| | | #endif /* DEBUG */ |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | mallopt: |
| | | |
| | | mallopt is the general SVID/XPG interface to tunable parameters. |
| | | The format is to provide a (parameter-number, parameter-value) pair. |
| | | mallopt then sets the corresponding parameter to the argument |
| | | value if it can (i.e., so long as the value is meaningful), |
| | | and returns 1 if successful else 0. |
| | | |
| | | See descriptions of tunable parameters above. |
| | | |
| | | */ |
| | | |
| | | #if __STD_C |
| | | int mALLOPt(int param_number, int value) |
| | | #else |
| | | int mALLOPt(param_number, value) int param_number; int value; |
| | | #endif |
| | | { |
| | | switch(param_number) |
| | | { |
| | | case M_TRIM_THRESHOLD: |
| | | trim_threshold = value; return 1; |
| | | case M_TOP_PAD: |
| | | top_pad = value; return 1; |
| | | case M_MMAP_THRESHOLD: |
| | | mmap_threshold = value; return 1; |
| | | case M_MMAP_MAX: |
| | | #if HAVE_MMAP |
| | | n_mmaps_max = value; return 1; |
| | | #else |
| | | if (value != 0) return 0; else n_mmaps_max = value; return 1; |
| | | #endif |
| | | |
| | | default: |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | /* |
| | | |
| | | History: |
| | | |
| | | V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) |
| | | * return null for negative arguments |
| | | * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com> |
| | | * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' |
| | | (e.g. WIN32 platforms) |
| | | * Cleanup up header file inclusion for WIN32 platforms |
| | | * Cleanup code to avoid Microsoft Visual C++ compiler complaints |
| | | * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing |
| | | memory allocation routines |
| | | * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) |
| | | * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to |
| | | usage of 'assert' in non-WIN32 code |
| | | * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to |
| | | avoid infinite loop |
| | | * Always call 'fREe()' rather than 'free()' |
| | | |
| | | V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) |
| | | * Fixed ordering problem with boundary-stamping |
| | | |
| | | V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) |
| | | * Added pvalloc, as recommended by H.J. Liu |
| | | * Added 64bit pointer support mainly from Wolfram Gloger |
| | | * Added anonymously donated WIN32 sbrk emulation |
| | | * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen |
| | | * malloc_extend_top: fix mask error that caused wastage after |
| | | foreign sbrks |
| | | * Add linux mremap support code from HJ Liu |
| | | |
| | | V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) |
| | | * Integrated most documentation with the code. |
| | | * Add support for mmap, with help from |
| | | Wolfram Gloger (Gloger@lrz.uni-muenchen.de). |
| | | * Use last_remainder in more cases. |
| | | * Pack bins using idea from colin@nyx10.cs.du.edu |
| | | * Use ordered bins instead of best-fit threshhold |
| | | * Eliminate block-local decls to simplify tracing and debugging. |
| | | * Support another case of realloc via move into top |
| | | * Fix error occuring when initial sbrk_base not word-aligned. |
| | | * Rely on page size for units instead of SBRK_UNIT to |
| | | avoid surprises about sbrk alignment conventions. |
| | | * Add mallinfo, mallopt. Thanks to Raymond Nijssen |
| | | (raymond@es.ele.tue.nl) for the suggestion. |
| | | * Add `pad' argument to malloc_trim and top_pad mallopt parameter. |
| | | * More precautions for cases where other routines call sbrk, |
| | | courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). |
| | | * Added macros etc., allowing use in linux libc from |
| | | H.J. Lu (hjl@gnu.ai.mit.edu) |
| | | * Inverted this history list |
| | | |
| | | V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) |
| | | * Re-tuned and fixed to behave more nicely with V2.6.0 changes. |
| | | * Removed all preallocation code since under current scheme |
| | | the work required to undo bad preallocations exceeds |
| | | the work saved in good cases for most test programs. |
| | | * No longer use return list or unconsolidated bins since |
| | | no scheme using them consistently outperforms those that don't |
| | | given above changes. |
| | | * Use best fit for very large chunks to prevent some worst-cases. |
| | | * Added some support for debugging |
| | | |
| | | V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) |
| | | * Removed footers when chunks are in use. Thanks to |
| | | Paul Wilson (wilson@cs.texas.edu) for the suggestion. |
| | | |
| | | V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) |
| | | * Added malloc_trim, with help from Wolfram Gloger |
| | | (wmglo@Dent.MED.Uni-Muenchen.DE). |
| | | |
| | | V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) |
| | | |
| | | V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) |
| | | * realloc: try to expand in both directions |
| | | * malloc: swap order of clean-bin strategy; |
| | | * realloc: only conditionally expand backwards |
| | | * Try not to scavenge used bins |
| | | * Use bin counts as a guide to preallocation |
| | | * Occasionally bin return list chunks in first scan |
| | | * Add a few optimizations from colin@nyx10.cs.du.edu |
| | | |
| | | V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) |
| | | * faster bin computation & slightly different binning |
| | | * merged all consolidations to one part of malloc proper |
| | | (eliminating old malloc_find_space & malloc_clean_bin) |
| | | * Scan 2 returns chunks (not just 1) |
| | | * Propagate failure in realloc if malloc returns 0 |
| | | * Add stuff to allow compilation on non-ANSI compilers |
| | | from kpv@research.att.com |
| | | |
| | | V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) |
| | | * removed potential for odd address access in prev_chunk |
| | | * removed dependency on getpagesize.h |
| | | * misc cosmetics and a bit more internal documentation |
| | | * anticosmetics: mangled names in macros to evade debugger strangeness |
| | | * tested on sparc, hp-700, dec-mips, rs6000 |
| | | with gcc & native cc (hp, dec only) allowing |
| | | Detlefs & Zorn comparison study (in SIGPLAN Notices.) |
| | | |
| | | Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) |
| | | * Based loosely on libg++-1.2X malloc. (It retains some of the overall |
| | | structure of old version, but most details differ.) |
| | | |
| | | */ |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 CoherentPlus Sdn. Bhd. |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This is the common subdir Makefile which to compile all the C |
| | | # source code to object files and then generate the shared or |
| | | # static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, |
| | | # which depends on the variable $LINK_MODE. |
| | | # |
| | | # Version: 1.0.0(10/08/2011~) |
| | | # Author: Guo Wenxue <guowenxue@gmail.com> |
| | | # ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" |
| | | # |
| | | #********************************************************************************/ |
| | | |
| | | PWD=$(shell pwd) |
| | | LOCAL_COMPILE=YES |
| | | LINK_MODE=STATIC |
| | | |
| | | #If wanna compile in the subdir, not called by top makefile, uncomment it |
| | | ifneq (${TOP_COMPILE}, YES) |
| | | LOCAL_COMPILE=YES |
| | | endif |
| | | |
| | | LIBNAME=$(shell basename ${PWD}) |
| | | STALIB=lib${LIBNAME}.a |
| | | DYNLIB=lib${LIBNAME}.so |
| | | |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | #====================================================== |
| | | # ---> Doesn't call by top makefile, compile by local |
| | | #====================================================== |
| | | ifeq (${LOCAL_COMPILE}, YES) |
| | | ARCH?=arm920t |
| | | #ARCH?=i386 |
| | | CFLAGS+=-fPIC |
| | | TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") |
| | | ifneq (,$(filter i386,$(TMP))) |
| | | CROSS_COMPILE= |
| | | else |
| | | CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- |
| | | endif |
| | | |
| | | PRJDIR?=$(shell pwd) |
| | | CFLAGS+=-I${PRJDIR} |
| | | CC = ${CROSS_COMPILE}gcc |
| | | AR = ${CROSS_COMPILE}ar |
| | | |
| | | endif #End local compile |
| | | |
| | | ifeq ("${LINK_MODE}", "STATIC") |
| | | LIBS = ${STALIB} |
| | | else |
| | | LIBS=${DYNLIB} |
| | | endif |
| | | |
| | | all: entry ${LIBS} install |
| | | |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | #$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o |
| | | ${STALIB}: $(OBJS) |
| | | $(AR) -rcu $@ $(OBJS) |
| | | |
| | | ${DYNLIB}: $(OBJS) |
| | | $(CC) -fPIC -shared -o $@ $(OBJS) |
| | | |
| | | %.o : %.c |
| | | $(CC) -c $< $(CFLAGS) |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @if [ ! -z "${LIBS_PATH}" ] ; then \ |
| | | mkdir -p ${LIBS_PATH} ; \ |
| | | cp ${LIBS} ${LIBS_PATH}; \ |
| | | fi; |
| | | |
| | | |
| | | clean: |
| | | @rm -f *.o |
| | | @rm -rf *.gdb *.a *.so |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
New file |
| | |
| | | /* |
| | | A version of malloc/free/realloc written by Doug Lea and released to the |
| | | public domain. Send questions/comments/complaints/performance data |
| | | to dl@cs.oswego.edu |
| | | |
| | | * VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee) |
| | | |
| | | Note: There may be an updated version of this malloc obtainable at |
| | | ftp://g.oswego.edu/pub/misc/malloc.c |
| | | Check before installing! |
| | | |
| | | * Why use this malloc? |
| | | |
| | | This is not the fastest, most space-conserving, most portable, or |
| | | most tunable malloc ever written. However it is among the fastest |
| | | while also being among the most space-conserving, portable and tunable. |
| | | Consistent balance across these factors results in a good general-purpose |
| | | allocator. For a high-level description, see |
| | | http://g.oswego.edu/dl/html/malloc.html |
| | | |
| | | * Synopsis of public routines |
| | | |
| | | (Much fuller descriptions are contained in the program documentation below.) |
| | | |
| | | malloc(size_t n); |
| | | Return a pointer to a newly allocated chunk of at least n bytes, or null |
| | | if no space is available. |
| | | free(Void_t* p); |
| | | Release the chunk of memory pointed to by p, or no effect if p is null. |
| | | realloc(Void_t* p, size_t n); |
| | | Return a pointer to a chunk of size n that contains the same data |
| | | as does chunk p up to the minimum of (n, p's size) bytes, or null |
| | | if no space is available. The returned pointer may or may not be |
| | | the same as p. If p is null, equivalent to malloc. Unless the |
| | | #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a |
| | | size argument of zero (re)allocates a minimum-sized chunk. |
| | | memalign(size_t alignment, size_t n); |
| | | Return a pointer to a newly allocated chunk of n bytes, aligned |
| | | in accord with the alignment argument, which must be a power of |
| | | two. |
| | | valloc(size_t n); |
| | | Equivalent to memalign(pagesize, n), where pagesize is the page |
| | | size of the system (or as near to this as can be figured out from |
| | | all the includes/defines below.) |
| | | pvalloc(size_t n); |
| | | Equivalent to valloc(minimum-page-that-holds(n)), that is, |
| | | round up n to nearest pagesize. |
| | | calloc(size_t unit, size_t quantity); |
| | | Returns a pointer to quantity * unit bytes, with all locations |
| | | set to zero. |
| | | cfree(Void_t* p); |
| | | Equivalent to free(p). |
| | | malloc_trim(size_t pad); |
| | | Release all but pad bytes of freed top-most memory back |
| | | to the system. Return 1 if successful, else 0. |
| | | malloc_usable_size(Void_t* p); |
| | | Report the number usable allocated bytes associated with allocated |
| | | chunk p. This may or may not report more bytes than were requested, |
| | | due to alignment and minimum size constraints. |
| | | malloc_stats(); |
| | | Prints brief summary statistics on stderr. |
| | | mallinfo() |
| | | Returns (by copy) a struct containing various summary statistics. |
| | | mallopt(int parameter_number, int parameter_value) |
| | | Changes one of the tunable parameters described below. Returns |
| | | 1 if successful in changing the parameter, else 0. |
| | | |
| | | * Vital statistics: |
| | | |
| | | Alignment: 8-byte |
| | | 8 byte alignment is currently hardwired into the design. This |
| | | seems to suffice for all current machines and C compilers. |
| | | |
| | | Assumed pointer representation: 4 or 8 bytes |
| | | Code for 8-byte pointers is untested by me but has worked |
| | | reliably by Wolfram Gloger, who contributed most of the |
| | | changes supporting this. |
| | | |
| | | Assumed size_t representation: 4 or 8 bytes |
| | | Note that size_t is allowed to be 4 bytes even if pointers are 8. |
| | | |
| | | Minimum overhead per allocated chunk: 4 or 8 bytes |
| | | Each malloced chunk has a hidden overhead of 4 bytes holding size |
| | | and status information. |
| | | |
| | | Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) |
| | | 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) |
| | | |
| | | When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte |
| | | ptrs but 4 byte size) or 24 (for 8/8) additional bytes are |
| | | needed; 4 (8) for a trailing size field |
| | | and 8 (16) bytes for free list pointers. Thus, the minimum |
| | | allocatable size is 16/24/32 bytes. |
| | | |
| | | Even a request for zero bytes (i.e., malloc(0)) returns a |
| | | pointer to something of the minimum allocatable size. |
| | | |
| | | Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes |
| | | 8-byte size_t: 2^63 - 16 bytes |
| | | |
| | | It is assumed that (possibly signed) size_t bit values suffice to |
| | | represent chunk sizes. `Possibly signed' is due to the fact |
| | | that `size_t' may be defined on a system as either a signed or |
| | | an unsigned type. To be conservative, values that would appear |
| | | as negative numbers are avoided. |
| | | Requests for sizes with a negative sign bit when the request |
| | | size is treaded as a long will return null. |
| | | |
| | | Maximum overhead wastage per allocated chunk: normally 15 bytes |
| | | |
| | | Alignnment demands, plus the minimum allocatable size restriction |
| | | make the normal worst-case wastage 15 bytes (i.e., up to 15 |
| | | more bytes will be allocated than were requested in malloc), with |
| | | two exceptions: |
| | | 1. Because requests for zero bytes allocate non-zero space, |
| | | the worst case wastage for a request of zero bytes is 24 bytes. |
| | | 2. For requests >= mmap_threshold that are serviced via |
| | | mmap(), the worst case wastage is 8 bytes plus the remainder |
| | | from a system page (the minimal mmap unit); typically 4096 bytes. |
| | | |
| | | * Limitations |
| | | |
| | | Here are some features that are NOT currently supported |
| | | |
| | | * No user-definable hooks for callbacks and the like. |
| | | * No automated mechanism for fully checking that all accesses |
| | | to malloced memory stay within their bounds. |
| | | * No support for compaction. |
| | | |
| | | * Synopsis of compile-time options: |
| | | |
| | | People have reported using previous versions of this malloc on all |
| | | versions of Unix, sometimes by tweaking some of the defines |
| | | below. It has been tested most extensively on Solaris and |
| | | Linux. It is also reported to work on WIN32 platforms. |
| | | People have also reported adapting this malloc for use in |
| | | stand-alone embedded systems. |
| | | |
| | | The implementation is in straight, hand-tuned ANSI C. Among other |
| | | consequences, it uses a lot of macros. Because of this, to be at |
| | | all usable, this code should be compiled using an optimizing compiler |
| | | (for example gcc -O2) that can simplify expressions and control |
| | | paths. |
| | | |
| | | __STD_C (default: derived from C compiler defines) |
| | | Nonzero if using ANSI-standard C compiler, a C++ compiler, or |
| | | a C compiler sufficiently close to ANSI to get away with it. |
| | | DEBUG (default: NOT defined) |
| | | Define to enable debugging. Adds fairly extensive assertion-based |
| | | checking to help track down memory errors, but noticeably slows down |
| | | execution. |
| | | REALLOC_ZERO_BYTES_FREES (default: NOT defined) |
| | | Define this if you think that realloc(p, 0) should be equivalent |
| | | to free(p). Otherwise, since malloc returns a unique pointer for |
| | | malloc(0), so does realloc(p, 0). |
| | | HAVE_MEMCPY (default: defined) |
| | | Define if you are not otherwise using ANSI STD C, but still |
| | | have memcpy and memset in your C library and want to use them. |
| | | Otherwise, simple internal versions are supplied. |
| | | USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) |
| | | Define as 1 if you want the C library versions of memset and |
| | | memcpy called in realloc and calloc (otherwise macro versions are used). |
| | | At least on some platforms, the simple macro versions usually |
| | | outperform libc versions. |
| | | HAVE_MMAP (default: defined as 1) |
| | | Define to non-zero to optionally make malloc() use mmap() to |
| | | allocate very large blocks. |
| | | HAVE_MREMAP (default: defined as 0 unless Linux libc set) |
| | | Define to non-zero to optionally make realloc() use mremap() to |
| | | reallocate very large blocks. |
| | | malloc_getpagesize (default: derived from system #includes) |
| | | Either a constant or routine call returning the system page size. |
| | | HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) |
| | | Optionally define if you are on a system with a /usr/include/malloc.h |
| | | that declares struct mallinfo. It is not at all necessary to |
| | | define this even if you do, but will ensure consistency. |
| | | INTERNAL_SIZE_T (default: size_t) |
| | | Define to a 32-bit type (probably `unsigned int') if you are on a |
| | | 64-bit machine, yet do not want or need to allow malloc requests of |
| | | greater than 2^31 to be handled. This saves space, especially for |
| | | very small chunks. |
| | | INTERNAL_LINUX_C_LIB (default: NOT defined) |
| | | Defined only when compiled as part of Linux libc. |
| | | Also note that there is some odd internal name-mangling via defines |
| | | (for example, internally, `malloc' is named `mALLOc') needed |
| | | when compiling in this case. These look funny but don't otherwise |
| | | affect anything. |
| | | WIN32 (default: undefined) |
| | | Define this on MS win (95, nt) platforms to compile in sbrk emulation. |
| | | LACKS_UNISTD_H (default: undefined if not WIN32) |
| | | Define this if your system does not have a <unistd.h>. |
| | | LACKS_SYS_PARAM_H (default: undefined if not WIN32) |
| | | Define this if your system does not have a <sys/param.h>. |
| | | MORECORE (default: sbrk) |
| | | The name of the routine to call to obtain more memory from the system. |
| | | MORECORE_FAILURE (default: -1) |
| | | The value returned upon failure of MORECORE. |
| | | MORECORE_CLEARS (default 1) |
| | | true (1) if the routine mapped to MORECORE zeroes out memory (which |
| | | holds for sbrk). |
| | | DEFAULT_TRIM_THRESHOLD |
| | | DEFAULT_TOP_PAD |
| | | DEFAULT_MMAP_THRESHOLD |
| | | DEFAULT_MMAP_MAX |
| | | Default values of tunable parameters (described in detail below) |
| | | controlling interaction with host system routines (sbrk, mmap, etc). |
| | | These values may also be changed dynamically via mallopt(). The |
| | | preset defaults are those that give best performance for typical |
| | | programs/systems. |
| | | USE_DL_PREFIX (default: undefined) |
| | | Prefix all public routines with the string 'dl'. Useful to |
| | | quickly avoid procedure declaration conflicts and linker symbol |
| | | conflicts with existing memory allocation routines. |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef __MALLOC_H__ |
| | | #define __MALLOC_H__ |
| | | |
| | | /* Preliminaries */ |
| | | |
| | | #ifndef __STD_C |
| | | #ifdef __STDC__ |
| | | #define __STD_C 1 |
| | | #else |
| | | #if __cplusplus |
| | | #define __STD_C 1 |
| | | #else |
| | | #define __STD_C 0 |
| | | #endif /*__cplusplus*/ |
| | | #endif /*__STDC__*/ |
| | | #endif /*__STD_C*/ |
| | | |
| | | #ifndef Void_t |
| | | #if (__STD_C || defined(WIN32)) |
| | | #define Void_t void |
| | | #else |
| | | #define Void_t char |
| | | #endif |
| | | #endif /*Void_t*/ |
| | | |
| | | #if __STD_C |
| | | #include <types.h> /* for size_t */ |
| | | #else |
| | | #include <sys/types.h> |
| | | #endif /* __STD_C */ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #define assert(x) ((void)0) |
| | | |
| | | #if 0 /* not for U-Boot */ |
| | | #include <stdio.h> /* needed for malloc_stats */ |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | Compile-time options |
| | | */ |
| | | |
| | | |
| | | /* |
| | | Debugging: |
| | | |
| | | Because freed chunks may be overwritten with link fields, this |
| | | malloc will often die when freed memory is overwritten by user |
| | | programs. This can be very effective (albeit in an annoying way) |
| | | in helping track down dangling pointers. |
| | | |
| | | If you compile with -DDEBUG, a number of assertion checks are |
| | | enabled that will catch more memory errors. You probably won't be |
| | | able to make much sense of the actual assertion errors, but they |
| | | should help you locate incorrectly overwritten memory. The |
| | | checking is fairly extensive, and will slow down execution |
| | | noticeably. Calling malloc_stats or mallinfo with DEBUG set will |
| | | attempt to check every non-mmapped allocated and free chunk in the |
| | | course of computing the summmaries. (By nature, mmapped regions |
| | | cannot be checked very much automatically.) |
| | | |
| | | Setting DEBUG may also be helpful if you are trying to modify |
| | | this code. The assertions in the check routines spell out in more |
| | | detail the assumptions and invariants underlying the algorithms. |
| | | |
| | | */ |
| | | |
| | | /* |
| | | INTERNAL_SIZE_T is the word-size used for internal bookkeeping |
| | | of chunk sizes. On a 64-bit machine, you can reduce malloc |
| | | overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' |
| | | at the expense of not being able to handle requests greater than |
| | | 2^31. This limitation is hardly ever a concern; you are encouraged |
| | | to set this. However, the default version is the same as size_t. |
| | | */ |
| | | |
| | | #ifndef INTERNAL_SIZE_T |
| | | #define INTERNAL_SIZE_T size_t |
| | | #endif |
| | | |
| | | /* |
| | | REALLOC_ZERO_BYTES_FREES should be set if a call to |
| | | realloc with zero bytes should be the same as a call to free. |
| | | Some people think it should. Otherwise, since this malloc |
| | | returns a unique pointer for malloc(0), so does realloc(p, 0). |
| | | */ |
| | | |
| | | |
| | | /* #define REALLOC_ZERO_BYTES_FREES */ |
| | | |
| | | |
| | | /* |
| | | WIN32 causes an emulation of sbrk to be compiled in |
| | | mmap-based options are not currently supported in WIN32. |
| | | */ |
| | | |
| | | /* #define WIN32 */ |
| | | #ifdef WIN32 |
| | | #define MORECORE wsbrk |
| | | #define HAVE_MMAP 0 |
| | | |
| | | #define LACKS_UNISTD_H |
| | | #define LACKS_SYS_PARAM_H |
| | | |
| | | /* |
| | | Include 'windows.h' to get the necessary declarations for the |
| | | Microsoft Visual C++ data structures and routines used in the 'sbrk' |
| | | emulation. |
| | | |
| | | Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft |
| | | Visual C++ header files are included. |
| | | */ |
| | | #define WIN32_LEAN_AND_MEAN |
| | | #include <windows.h> |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | HAVE_MEMCPY should be defined if you are not otherwise using |
| | | ANSI STD C, but still have memcpy and memset in your C library |
| | | and want to use them in calloc and realloc. Otherwise simple |
| | | macro versions are defined here. |
| | | |
| | | USE_MEMCPY should be defined as 1 if you actually want to |
| | | have memset and memcpy called. People report that the macro |
| | | versions are often enough faster than libc versions on many |
| | | systems that it is better to use them. |
| | | |
| | | */ |
| | | |
| | | #define HAVE_MEMCPY |
| | | |
| | | #ifndef USE_MEMCPY |
| | | #ifdef HAVE_MEMCPY |
| | | #define USE_MEMCPY 1 |
| | | #else |
| | | #define USE_MEMCPY 0 |
| | | #endif |
| | | #endif |
| | | |
| | | #if (__STD_C || defined(HAVE_MEMCPY)) |
| | | |
| | | #if __STD_C |
| | | void* memset(void*, int, size_t); |
| | | void* memcpy(void*, const void*, size_t); |
| | | #else |
| | | #ifdef WIN32 |
| | | /* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */ |
| | | /* 'windows.h' */ |
| | | #else |
| | | Void_t* memset(); |
| | | Void_t* memcpy(); |
| | | #endif |
| | | #endif |
| | | #endif |
| | | |
| | | #if USE_MEMCPY |
| | | |
| | | /* The following macros are only invoked with (2n+1)-multiples of |
| | | INTERNAL_SIZE_T units, with a positive integer n. This is exploited |
| | | for fast inline execution when n is small. */ |
| | | |
| | | #define MALLOC_ZERO(charp, nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T mzsz = (nbytes); \ |
| | | if(mzsz <= 9*sizeof(mzsz)) { \ |
| | | INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ |
| | | if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ |
| | | *mz++ = 0; \ |
| | | if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ |
| | | *mz++ = 0; \ |
| | | if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ |
| | | *mz++ = 0; }}} \ |
| | | *mz++ = 0; \ |
| | | *mz++ = 0; \ |
| | | *mz = 0; \ |
| | | } else memset((charp), 0, mzsz); \ |
| | | } while(0) |
| | | |
| | | #define MALLOC_COPY(dest,src,nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T mcsz = (nbytes); \ |
| | | if(mcsz <= 9*sizeof(mcsz)) { \ |
| | | INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ |
| | | INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ |
| | | if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; }}} \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | *mcdst++ = *mcsrc++; \ |
| | | *mcdst = *mcsrc ; \ |
| | | } else memcpy(dest, src, mcsz); \ |
| | | } while(0) |
| | | |
| | | #else /* !USE_MEMCPY */ |
| | | |
| | | /* Use Duff's device for good zeroing/copying performance. */ |
| | | |
| | | #define MALLOC_ZERO(charp, nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ |
| | | long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ |
| | | if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ |
| | | switch (mctmp) { \ |
| | | case 0: for(;;) { *mzp++ = 0; \ |
| | | case 7: *mzp++ = 0; \ |
| | | case 6: *mzp++ = 0; \ |
| | | case 5: *mzp++ = 0; \ |
| | | case 4: *mzp++ = 0; \ |
| | | case 3: *mzp++ = 0; \ |
| | | case 2: *mzp++ = 0; \ |
| | | case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ |
| | | } \ |
| | | } while(0) |
| | | |
| | | #define MALLOC_COPY(dest,src,nbytes) \ |
| | | do { \ |
| | | INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ |
| | | INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ |
| | | long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ |
| | | if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ |
| | | switch (mctmp) { \ |
| | | case 0: for(;;) { *mcdst++ = *mcsrc++; \ |
| | | case 7: *mcdst++ = *mcsrc++; \ |
| | | case 6: *mcdst++ = *mcsrc++; \ |
| | | case 5: *mcdst++ = *mcsrc++; \ |
| | | case 4: *mcdst++ = *mcsrc++; \ |
| | | case 3: *mcdst++ = *mcsrc++; \ |
| | | case 2: *mcdst++ = *mcsrc++; \ |
| | | case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ |
| | | } \ |
| | | } while(0) |
| | | |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | Define HAVE_MMAP to optionally make malloc() use mmap() to |
| | | allocate very large blocks. These will be returned to the |
| | | operating system immediately after a free(). |
| | | */ |
| | | |
| | | /*** |
| | | #ifndef HAVE_MMAP |
| | | #define HAVE_MMAP 1 |
| | | #endif |
| | | ***/ |
| | | #undef HAVE_MMAP /* Not available for U-Boot */ |
| | | |
| | | /* |
| | | Define HAVE_MREMAP to make realloc() use mremap() to re-allocate |
| | | large blocks. This is currently only possible on Linux with |
| | | kernel versions newer than 1.3.77. |
| | | */ |
| | | |
| | | /*** |
| | | #ifndef HAVE_MREMAP |
| | | #ifdef INTERNAL_LINUX_C_LIB |
| | | #define HAVE_MREMAP 1 |
| | | #else |
| | | #define HAVE_MREMAP 0 |
| | | #endif |
| | | #endif |
| | | ***/ |
| | | #undef HAVE_MREMAP /* Not available for U-Boot */ |
| | | |
| | | #ifdef HAVE_MMAP |
| | | |
| | | #include <unistd.h> |
| | | #include <fcntl.h> |
| | | #include <sys/mman.h> |
| | | |
| | | #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
| | | #define MAP_ANONYMOUS MAP_ANON |
| | | #endif |
| | | |
| | | #endif /* HAVE_MMAP */ |
| | | |
| | | /* |
| | | Access to system page size. To the extent possible, this malloc |
| | | manages memory from the system in page-size units. |
| | | |
| | | The following mechanics for getpagesize were adapted from |
| | | bsd/gnu getpagesize.h |
| | | */ |
| | | |
| | | #define LACKS_UNISTD_H /* Shortcut for U-Boot */ |
| | | #define malloc_getpagesize 4096 |
| | | |
| | | #ifndef LACKS_UNISTD_H |
| | | # include <unistd.h> |
| | | #endif |
| | | |
| | | #ifndef malloc_getpagesize |
| | | # ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ |
| | | # ifndef _SC_PAGE_SIZE |
| | | # define _SC_PAGE_SIZE _SC_PAGESIZE |
| | | # endif |
| | | # endif |
| | | # ifdef _SC_PAGE_SIZE |
| | | # define malloc_getpagesize sysconf(_SC_PAGE_SIZE) |
| | | # else |
| | | # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) |
| | | extern size_t getpagesize(); |
| | | # define malloc_getpagesize getpagesize() |
| | | # else |
| | | # ifdef WIN32 |
| | | # define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */ |
| | | # else |
| | | # ifndef LACKS_SYS_PARAM_H |
| | | # include <sys/param.h> |
| | | # endif |
| | | # ifdef EXEC_PAGESIZE |
| | | # define malloc_getpagesize EXEC_PAGESIZE |
| | | # else |
| | | # ifdef NBPG |
| | | # ifndef CLSIZE |
| | | # define malloc_getpagesize NBPG |
| | | # else |
| | | # define malloc_getpagesize (NBPG * CLSIZE) |
| | | # endif |
| | | # else |
| | | # ifdef NBPC |
| | | # define malloc_getpagesize NBPC |
| | | # else |
| | | # ifdef PAGESIZE |
| | | # define malloc_getpagesize PAGESIZE |
| | | # else |
| | | # define malloc_getpagesize (4096) /* just guess */ |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | # endif |
| | | #endif |
| | | |
| | | |
| | | /* |
| | | |
| | | This version of malloc supports the standard SVID/XPG mallinfo |
| | | routine that returns a struct containing the same kind of |
| | | information you can get from malloc_stats. It should work on |
| | | any SVID/XPG compliant system that has a /usr/include/malloc.h |
| | | defining struct mallinfo. (If you'd like to install such a thing |
| | | yourself, cut out the preliminary declarations as described above |
| | | and below and save them in a malloc.h file. But there's no |
| | | compelling reason to bother to do this.) |
| | | |
| | | The main declaration needed is the mallinfo struct that is returned |
| | | (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a |
| | | bunch of fields, most of which are not even meaningful in this |
| | | version of malloc. Some of these fields are are instead filled by |
| | | mallinfo() with other numbers that might possibly be of interest. |
| | | |
| | | HAVE_USR_INCLUDE_MALLOC_H should be set if you have a |
| | | /usr/include/malloc.h file that includes a declaration of struct |
| | | mallinfo. If so, it is included; else an SVID2/XPG2 compliant |
| | | version is declared below. These must be precisely the same for |
| | | mallinfo() to work. |
| | | |
| | | */ |
| | | |
| | | /* #define HAVE_USR_INCLUDE_MALLOC_H */ |
| | | |
| | | #ifdef HAVE_USR_INCLUDE_MALLOC_H |
| | | #include "/usr/include/malloc.h" |
| | | #else |
| | | |
| | | /* SVID2/XPG mallinfo structure */ |
| | | |
| | | struct mallinfo { |
| | | int arena; /* total space allocated from system */ |
| | | int ordblks; /* number of non-inuse chunks */ |
| | | int smblks; /* unused -- always zero */ |
| | | int hblks; /* number of mmapped regions */ |
| | | int hblkhd; /* total space in mmapped regions */ |
| | | int usmblks; /* unused -- always zero */ |
| | | int fsmblks; /* unused -- always zero */ |
| | | int uordblks; /* total allocated space */ |
| | | int fordblks; /* total non-inuse space */ |
| | | int keepcost; /* top-most, releasable (via malloc_trim) space */ |
| | | }; |
| | | |
| | | /* SVID2/XPG mallopt options */ |
| | | |
| | | #define M_MXFAST 1 /* UNUSED in this malloc */ |
| | | #define M_NLBLKS 2 /* UNUSED in this malloc */ |
| | | #define M_GRAIN 3 /* UNUSED in this malloc */ |
| | | #define M_KEEP 4 /* UNUSED in this malloc */ |
| | | |
| | | #endif |
| | | |
| | | /* mallopt options that actually do something */ |
| | | |
| | | #define M_TRIM_THRESHOLD -1 |
| | | #define M_TOP_PAD -2 |
| | | #define M_MMAP_THRESHOLD -3 |
| | | #define M_MMAP_MAX -4 |
| | | |
| | | |
| | | #ifndef DEFAULT_TRIM_THRESHOLD |
| | | #define DEFAULT_TRIM_THRESHOLD (128 * 1024) |
| | | #endif |
| | | |
| | | /* |
| | | M_TRIM_THRESHOLD is the maximum amount of unused top-most memory |
| | | to keep before releasing via malloc_trim in free(). |
| | | |
| | | Automatic trimming is mainly useful in long-lived programs. |
| | | Because trimming via sbrk can be slow on some systems, and can |
| | | sometimes be wasteful (in cases where programs immediately |
| | | afterward allocate more large chunks) the value should be high |
| | | enough so that your overall system performance would improve by |
| | | releasing. |
| | | |
| | | The trim threshold and the mmap control parameters (see below) |
| | | can be traded off with one another. Trimming and mmapping are |
| | | two different ways of releasing unused memory back to the |
| | | system. Between these two, it is often possible to keep |
| | | system-level demands of a long-lived program down to a bare |
| | | minimum. For example, in one test suite of sessions measuring |
| | | the XF86 X server on Linux, using a trim threshold of 128K and a |
| | | mmap threshold of 192K led to near-minimal long term resource |
| | | consumption. |
| | | |
| | | If you are using this malloc in a long-lived program, it should |
| | | pay to experiment with these values. As a rough guide, you |
| | | might set to a value close to the average size of a process |
| | | (program) running on your system. Releasing this much memory |
| | | would allow such a process to run in memory. Generally, it's |
| | | worth it to tune for trimming rather tham memory mapping when a |
| | | program undergoes phases where several large chunks are |
| | | allocated and released in ways that can reuse each other's |
| | | storage, perhaps mixed with phases where there are no such |
| | | chunks at all. And in well-behaved long-lived programs, |
| | | controlling release of large blocks via trimming versus mapping |
| | | is usually faster. |
| | | |
| | | However, in most programs, these parameters serve mainly as |
| | | protection against the system-level effects of carrying around |
| | | massive amounts of unneeded memory. Since frequent calls to |
| | | sbrk, mmap, and munmap otherwise degrade performance, the default |
| | | parameters are set to relatively high values that serve only as |
| | | safeguards. |
| | | |
| | | The default trim value is high enough to cause trimming only in |
| | | fairly extreme (by current memory consumption standards) cases. |
| | | It must be greater than page size to have any useful effect. To |
| | | disable trimming completely, you can set to (unsigned long)(-1); |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef DEFAULT_TOP_PAD |
| | | #define DEFAULT_TOP_PAD (0) |
| | | #endif |
| | | |
| | | /* |
| | | M_TOP_PAD is the amount of extra `padding' space to allocate or |
| | | retain whenever sbrk is called. It is used in two ways internally: |
| | | |
| | | * When sbrk is called to extend the top of the arena to satisfy |
| | | a new malloc request, this much padding is added to the sbrk |
| | | request. |
| | | |
| | | * When malloc_trim is called automatically from free(), |
| | | it is used as the `pad' argument. |
| | | |
| | | In both cases, the actual amount of padding is rounded |
| | | so that the end of the arena is always a system page boundary. |
| | | |
| | | The main reason for using padding is to avoid calling sbrk so |
| | | often. Having even a small pad greatly reduces the likelihood |
| | | that nearly every malloc request during program start-up (or |
| | | after trimming) will invoke sbrk, which needlessly wastes |
| | | time. |
| | | |
| | | Automatic rounding-up to page-size units is normally sufficient |
| | | to avoid measurable overhead, so the default is 0. However, in |
| | | systems where sbrk is relatively slow, it can pay to increase |
| | | this value, at the expense of carrying around more memory than |
| | | the program needs. |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef DEFAULT_MMAP_THRESHOLD |
| | | #define DEFAULT_MMAP_THRESHOLD (128 * 1024) |
| | | #endif |
| | | |
| | | /* |
| | | |
| | | M_MMAP_THRESHOLD is the request size threshold for using mmap() |
| | | to service a request. Requests of at least this size that cannot |
| | | be allocated using already-existing space will be serviced via mmap. |
| | | (If enough normal freed space already exists it is used instead.) |
| | | |
| | | Using mmap segregates relatively large chunks of memory so that |
| | | they can be individually obtained and released from the host |
| | | system. A request serviced through mmap is never reused by any |
| | | other request (at least not directly; the system may just so |
| | | happen to remap successive requests to the same locations). |
| | | |
| | | Segregating space in this way has the benefit that mmapped space |
| | | can ALWAYS be individually released back to the system, which |
| | | helps keep the system level memory demands of a long-lived |
| | | program low. Mapped memory can never become `locked' between |
| | | other chunks, as can happen with normally allocated chunks, which |
| | | menas that even trimming via malloc_trim would not release them. |
| | | |
| | | However, it has the disadvantages that: |
| | | |
| | | 1. The space cannot be reclaimed, consolidated, and then |
| | | used to service later requests, as happens with normal chunks. |
| | | 2. It can lead to more wastage because of mmap page alignment |
| | | requirements |
| | | 3. It causes malloc performance to be more dependent on host |
| | | system memory management support routines which may vary in |
| | | implementation quality and may impose arbitrary |
| | | limitations. Generally, servicing a request via normal |
| | | malloc steps is faster than going through a system's mmap. |
| | | |
| | | All together, these considerations should lead you to use mmap |
| | | only for relatively large requests. |
| | | |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifndef DEFAULT_MMAP_MAX |
| | | #ifdef HAVE_MMAP |
| | | #define DEFAULT_MMAP_MAX (64) |
| | | #else |
| | | #define DEFAULT_MMAP_MAX (0) |
| | | #endif |
| | | #endif |
| | | |
| | | /* |
| | | M_MMAP_MAX is the maximum number of requests to simultaneously |
| | | service using mmap. This parameter exists because: |
| | | |
| | | 1. Some systems have a limited number of internal tables for |
| | | use by mmap. |
| | | 2. In most systems, overreliance on mmap can degrade overall |
| | | performance. |
| | | 3. If a program allocates many large regions, it is probably |
| | | better off using normal sbrk-based allocation routines that |
| | | can reclaim and reallocate normal heap memory. Using a |
| | | small value allows transition into this mode after the |
| | | first few allocations. |
| | | |
| | | Setting to 0 disables all use of mmap. If HAVE_MMAP is not set, |
| | | the default value is 0, and attempts to set it to non-zero values |
| | | in mallopt will fail. |
| | | */ |
| | | |
| | | |
| | | /* |
| | | USE_DL_PREFIX will prefix all public routines with the string 'dl'. |
| | | Useful to quickly avoid procedure declaration conflicts and linker |
| | | symbol conflicts with existing memory allocation routines. |
| | | |
| | | */ |
| | | |
| | | /* #define USE_DL_PREFIX */ |
| | | |
| | | |
| | | /* |
| | | |
| | | Special defines for linux libc |
| | | |
| | | Except when compiled using these special defines for Linux libc |
| | | using weak aliases, this malloc is NOT designed to work in |
| | | multithreaded applications. No semaphores or other concurrency |
| | | control are provided to ensure that multiple malloc or free calls |
| | | don't run at the same time, which could be disasterous. A single |
| | | semaphore could be used across malloc, realloc, and free (which is |
| | | essentially the effect of the linux weak alias approach). It would |
| | | be hard to obtain finer granularity. |
| | | |
| | | */ |
| | | |
| | | |
| | | #ifdef INTERNAL_LINUX_C_LIB |
| | | |
| | | #if __STD_C |
| | | |
| | | Void_t * __default_morecore_init (ptrdiff_t); |
| | | Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; |
| | | |
| | | #else |
| | | |
| | | Void_t * __default_morecore_init (); |
| | | Void_t *(*__morecore)() = __default_morecore_init; |
| | | |
| | | #endif |
| | | |
| | | #define MORECORE (*__morecore) |
| | | #define MORECORE_FAILURE 0 |
| | | #define MORECORE_CLEARS 1 |
| | | |
| | | #else /* INTERNAL_LINUX_C_LIB */ |
| | | |
| | | #if __STD_C |
| | | extern Void_t* sbrk(ptrdiff_t); |
| | | #else |
| | | extern Void_t* sbrk(); |
| | | #endif |
| | | |
| | | #ifndef MORECORE |
| | | #define MORECORE sbrk |
| | | #endif |
| | | |
| | | #ifndef MORECORE_FAILURE |
| | | #define MORECORE_FAILURE -1 |
| | | #endif |
| | | |
| | | #ifndef MORECORE_CLEARS |
| | | #define MORECORE_CLEARS 1 |
| | | #endif |
| | | |
| | | #endif /* INTERNAL_LINUX_C_LIB */ |
| | | |
| | | #if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) |
| | | |
| | | #define cALLOc __libc_calloc |
| | | #define fREe __libc_free |
| | | #define mALLOc __libc_malloc |
| | | #define mEMALIGn __libc_memalign |
| | | #define rEALLOc __libc_realloc |
| | | #define vALLOc __libc_valloc |
| | | #define pvALLOc __libc_pvalloc |
| | | #define mALLINFo __libc_mallinfo |
| | | #define mALLOPt __libc_mallopt |
| | | |
| | | #pragma weak calloc = __libc_calloc |
| | | #pragma weak free = __libc_free |
| | | #pragma weak cfree = __libc_free |
| | | #pragma weak malloc = __libc_malloc |
| | | #pragma weak memalign = __libc_memalign |
| | | #pragma weak realloc = __libc_realloc |
| | | #pragma weak valloc = __libc_valloc |
| | | #pragma weak pvalloc = __libc_pvalloc |
| | | #pragma weak mallinfo = __libc_mallinfo |
| | | #pragma weak mallopt = __libc_mallopt |
| | | |
| | | #else |
| | | |
| | | #ifdef USE_DL_PREFIX |
| | | #define cALLOc dlcalloc |
| | | #define fREe dlfree |
| | | #define mALLOc dlmalloc |
| | | #define mEMALIGn dlmemalign |
| | | #define rEALLOc dlrealloc |
| | | #define vALLOc dlvalloc |
| | | #define pvALLOc dlpvalloc |
| | | #define mALLINFo dlmallinfo |
| | | #define mALLOPt dlmallopt |
| | | #else /* USE_DL_PREFIX */ |
| | | #define cALLOc calloc |
| | | #define fREe free |
| | | #define mALLOc malloc |
| | | #define mEMALIGn memalign |
| | | #define rEALLOc realloc |
| | | #define vALLOc valloc |
| | | #define pvALLOc pvalloc |
| | | #define mALLINFo mallinfo |
| | | #define mALLOPt mallopt |
| | | #endif /* USE_DL_PREFIX */ |
| | | |
| | | #endif |
| | | |
| | | /* Public routines */ |
| | | |
| | | #if __STD_C |
| | | |
| | | Void_t* mALLOc(size_t); |
| | | void fREe(Void_t*); |
| | | Void_t* rEALLOc(Void_t*, size_t); |
| | | Void_t* mEMALIGn(size_t, size_t); |
| | | Void_t* vALLOc(size_t); |
| | | Void_t* pvALLOc(size_t); |
| | | Void_t* cALLOc(size_t, size_t); |
| | | void cfree(Void_t*); |
| | | int malloc_trim(size_t); |
| | | size_t malloc_usable_size(Void_t*); |
| | | void malloc_stats(void); |
| | | int mALLOPt(int, int); |
| | | struct mallinfo mALLINFo(void); |
| | | #else |
| | | Void_t* mALLOc(); |
| | | void fREe(); |
| | | Void_t* rEALLOc(); |
| | | Void_t* mEMALIGn(); |
| | | Void_t* vALLOc(); |
| | | Void_t* pvALLOc(); |
| | | Void_t* cALLOc(); |
| | | void cfree(); |
| | | int malloc_trim(); |
| | | size_t malloc_usable_size(); |
| | | void malloc_stats(); |
| | | int mALLOPt(); |
| | | struct mallinfo mALLINFo(); |
| | | #endif |
| | | |
| | | /* |
| | | * Begin and End of memory area for malloc(), and current "brk" |
| | | */ |
| | | extern ulong mem_malloc_start; |
| | | extern ulong mem_malloc_end; |
| | | extern ulong mem_malloc_brk; |
| | | |
| | | void mem_malloc_init(ulong start, ulong size); |
| | | |
| | | #ifdef __cplusplus |
| | | }; /* end of extern "C" */ |
| | | #endif |
| | | |
| | | #endif /* __MALLOC_H__ */ |
New file |
| | |
| | | /* |
| | | * linux/lib/vsprintf.c |
| | | * |
| | | * Copyright (C) 1991, 1992 Linus Torvalds |
| | | */ |
| | | |
| | | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ |
| | | /* |
| | | * Wirzenius wrote this portably, Torvalds fucked it up :-) |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include "s3c_board.h" |
| | | |
| | | #define CFG_PBSIZE 1024 /* Print Buffer Size */ |
| | | |
| | | #define is_digit(c) ((c) >= '0' && (c) <= '9') |
| | | |
| | | static int skip_atoi(const char **s) |
| | | { |
| | | int i = 0; |
| | | |
| | | while (is_digit(**s)) |
| | | i = i * 10 + *((*s)++) - '0'; |
| | | return i; |
| | | } |
| | | |
| | | #define ZEROPAD 1 /* pad with zero */ |
| | | #define SIGN 2 /* unsigned/signed long */ |
| | | #define PLUS 4 /* show plus */ |
| | | #define SPACE 8 /* space if plus */ |
| | | #define LEFT 16 /* left justified */ |
| | | #define SPECIAL 32 /* 0x */ |
| | | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ |
| | | |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | #define do_div(n,base) ({ \ |
| | | unsigned int __res; \ |
| | | __res = ((unsigned long long) n) % base; \ |
| | | n = ((unsigned long long) n) / base; \ |
| | | __res; \ |
| | | }) |
| | | #else |
| | | #define do_div(n,base) ({ \ |
| | | int __res; \ |
| | | __res = ((unsigned long) n) % base; \ |
| | | n = ((unsigned long) n) / base; \ |
| | | __res; \ |
| | | }) |
| | | #endif |
| | | |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | static char *number(char *str, long long num, unsigned int base, int size, int precision, int type) |
| | | #else |
| | | static char *number(char *str, long num, unsigned int base, int size, int precision, int type) |
| | | #endif |
| | | { |
| | | char c, sign, tmp[66]; |
| | | const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; |
| | | int i; |
| | | |
| | | if (type & LARGE) |
| | | digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| | | if (type & LEFT) |
| | | type &= ~ZEROPAD; |
| | | if (base < 2 || base > 36) |
| | | return 0; |
| | | c = (type & ZEROPAD) ? '0' : ' '; |
| | | sign = 0; |
| | | if (type & SIGN) |
| | | { |
| | | if (num < 0) |
| | | { |
| | | sign = '-'; |
| | | num = -num; |
| | | size--; |
| | | } |
| | | else if (type & PLUS) |
| | | { |
| | | sign = '+'; |
| | | size--; |
| | | } |
| | | else if (type & SPACE) |
| | | { |
| | | sign = ' '; |
| | | size--; |
| | | } |
| | | } |
| | | if (type & SPECIAL) |
| | | { |
| | | if (base == 16) |
| | | size -= 2; |
| | | else if (base == 8) |
| | | size--; |
| | | } |
| | | i = 0; |
| | | if (num == 0) |
| | | tmp[i++] = '0'; |
| | | else |
| | | while (num != 0) |
| | | tmp[i++] = digits[do_div(num, base)]; |
| | | if (i > precision) |
| | | precision = i; |
| | | size -= precision; |
| | | if (!(type & (ZEROPAD + LEFT))) |
| | | while (size-- > 0) |
| | | *str++ = ' '; |
| | | if (sign) |
| | | *str++ = sign; |
| | | if (type & SPECIAL) |
| | | { |
| | | if (base == 8) |
| | | *str++ = '0'; |
| | | else if (base == 16) |
| | | { |
| | | *str++ = '0'; |
| | | *str++ = digits[33]; |
| | | } |
| | | } |
| | | if (!(type & LEFT)) |
| | | while (size-- > 0) |
| | | *str++ = c; |
| | | while (i < precision--) |
| | | *str++ = '0'; |
| | | while (i-- > 0) |
| | | *str++ = tmp[i]; |
| | | while (size-- > 0) |
| | | *str++ = ' '; |
| | | return str; |
| | | } |
| | | |
| | | /* Forward decl. needed for IP address printing stuff... */ |
| | | int sprintf(char *buf, const char *fmt, ...); |
| | | |
| | | int vsprintf(char *buf, const char *fmt, va_list args) |
| | | { |
| | | int len; |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | unsigned long long num; |
| | | #else |
| | | unsigned long num; |
| | | #endif |
| | | int i, base; |
| | | char *str; |
| | | const char *s; |
| | | |
| | | int flags; /* flags to number() */ |
| | | |
| | | int field_width; /* width of output field */ |
| | | int precision; /* min. # of digits for integers; max |
| | | * number of chars for from string */ |
| | | int qualifier; /* 'h', 'l', or 'q' for integer fields */ |
| | | |
| | | for (str = buf; *fmt; ++fmt) |
| | | { |
| | | if (*fmt != '%') |
| | | { |
| | | *str++ = *fmt; |
| | | continue; |
| | | } |
| | | |
| | | /* process flags */ |
| | | flags = 0; |
| | | repeat: |
| | | ++fmt; /* this also skips first '%' */ |
| | | switch (*fmt) |
| | | { |
| | | case '-': |
| | | flags |= LEFT; |
| | | goto repeat; |
| | | case '+': |
| | | flags |= PLUS; |
| | | goto repeat; |
| | | case ' ': |
| | | flags |= SPACE; |
| | | goto repeat; |
| | | case '#': |
| | | flags |= SPECIAL; |
| | | goto repeat; |
| | | case '0': |
| | | flags |= ZEROPAD; |
| | | goto repeat; |
| | | } |
| | | |
| | | /* get field width */ |
| | | field_width = -1; |
| | | if (is_digit(*fmt)) |
| | | field_width = skip_atoi(&fmt); |
| | | else if (*fmt == '*') |
| | | { |
| | | ++fmt; |
| | | /* it's the next argument */ |
| | | field_width = va_arg(args, int); |
| | | if (field_width < 0) |
| | | { |
| | | field_width = -field_width; |
| | | flags |= LEFT; |
| | | } |
| | | } |
| | | |
| | | /* get the precision */ |
| | | precision = -1; |
| | | if (*fmt == '.') |
| | | { |
| | | ++fmt; |
| | | if (is_digit(*fmt)) |
| | | precision = skip_atoi(&fmt); |
| | | else if (*fmt == '*') |
| | | { |
| | | ++fmt; |
| | | /* it's the next argument */ |
| | | precision = va_arg(args, int); |
| | | } |
| | | if (precision < 0) |
| | | precision = 0; |
| | | } |
| | | |
| | | /* get the conversion qualifier */ |
| | | qualifier = -1; |
| | | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
| | | *fmt == 'Z' || *fmt == 'z' || *fmt == 't' || *fmt == 'q') |
| | | { |
| | | qualifier = *fmt; |
| | | if (qualifier == 'l' && *(fmt + 1) == 'l') |
| | | { |
| | | qualifier = 'q'; |
| | | ++fmt; |
| | | } |
| | | ++fmt; |
| | | } |
| | | |
| | | /* default base */ |
| | | base = 10; |
| | | |
| | | switch (*fmt) |
| | | { |
| | | case 'c': |
| | | if (!(flags & LEFT)) |
| | | while (--field_width > 0) |
| | | *str++ = ' '; |
| | | *str++ = (unsigned char)va_arg(args, int); |
| | | while (--field_width > 0) |
| | | *str++ = ' '; |
| | | continue; |
| | | |
| | | case 's': |
| | | s = va_arg(args, char *); |
| | | if (!s) |
| | | s = "<NULL>"; |
| | | |
| | | len = strnlen(s, precision); |
| | | |
| | | if (!(flags & LEFT)) |
| | | while (len < field_width--) |
| | | *str++ = ' '; |
| | | for (i = 0; i < len; ++i) |
| | | *str++ = *s++; |
| | | while (len < field_width--) |
| | | *str++ = ' '; |
| | | continue; |
| | | |
| | | case 'p': |
| | | if (field_width == -1) |
| | | { |
| | | field_width = 2 * sizeof(void *); |
| | | flags |= ZEROPAD; |
| | | } |
| | | str = number(str, |
| | | (unsigned long)va_arg(args, void *), 16, field_width, precision, flags); |
| | | continue; |
| | | |
| | | case 'n': |
| | | if (qualifier == 'l') |
| | | { |
| | | long *ip = va_arg(args, long *); |
| | | *ip = (str - buf); |
| | | } |
| | | else |
| | | { |
| | | int *ip = va_arg(args, int *); |
| | | *ip = (str - buf); |
| | | } |
| | | continue; |
| | | |
| | | case '%': |
| | | *str++ = '%'; |
| | | continue; |
| | | |
| | | /* integer number formats - set up the flags and "break" */ |
| | | case 'o': |
| | | base = 8; |
| | | break; |
| | | |
| | | case 'X': |
| | | flags |= LARGE; |
| | | case 'x': |
| | | base = 16; |
| | | break; |
| | | |
| | | case 'd': |
| | | case 'i': |
| | | flags |= SIGN; |
| | | case 'u': |
| | | break; |
| | | |
| | | default: |
| | | *str++ = '%'; |
| | | if (*fmt) |
| | | *str++ = *fmt; |
| | | else |
| | | --fmt; |
| | | continue; |
| | | } |
| | | #ifdef CFG_64BIT_VSPRINTF |
| | | if (qualifier == 'q') /* "quad" for 64 bit variables */ |
| | | num = va_arg(args, unsigned long long); |
| | | else |
| | | #endif |
| | | if (qualifier == 'l') |
| | | { |
| | | num = va_arg(args, unsigned long); |
| | | } |
| | | else if (qualifier == 'Z' || qualifier == 'z') |
| | | { |
| | | num = va_arg(args, size_t); |
| | | } |
| | | else if (qualifier == 't') |
| | | { |
| | | num = va_arg(args, ptrdiff_t); |
| | | } |
| | | else if (qualifier == 'h') |
| | | { |
| | | num = (unsigned short)va_arg(args, int); |
| | | if (flags & SIGN) |
| | | num = (short)num; |
| | | } |
| | | else if (flags & SIGN) |
| | | num = va_arg(args, int); |
| | | else |
| | | num = va_arg(args, unsigned int); |
| | | str = number(str, num, base, field_width, precision, flags); |
| | | } |
| | | *str = '\0'; |
| | | return str - buf; |
| | | } |
| | | |
| | | void printf(const char *fmt, ...) |
| | | { |
| | | va_list args; |
| | | uint i; |
| | | char printbuffer[CFG_PBSIZE]; |
| | | |
| | | va_start(args, fmt); |
| | | |
| | | /* For this to work, printbuffer must be larger than |
| | | * anything we ever want to print. |
| | | */ |
| | | i = vsprintf(printbuffer, fmt, args); |
| | | va_end(args); |
| | | |
| | | console_serial_puts(printbuffer); |
| | | } |
| | | |
| | | int sprintf(char *buf, const char *fmt, ...) |
| | | { |
| | | va_list args; |
| | | int i; |
| | | |
| | | va_start(args, fmt); |
| | | i = vsprintf(buf, fmt, args); |
| | | va_end(args); |
| | | return i; |
| | | } |
New file |
| | |
| | | /******************************************************************************************** |
| | | * File: common.h |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: A busy head file |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | #ifndef __COMMON_H |
| | | #define __COMMON_H |
| | | |
| | | #include <stdarg.h> |
| | | #include <types.h> |
| | | |
| | | #ifdef DEBUG |
| | | #define dbg_print(format,args...) printf(format, ##args) |
| | | #else |
| | | #define dbg_print(format,args...) do{} while(0); |
| | | #endif |
| | | |
| | | void serial_init(void); |
| | | void serial_send_byte(char c); |
| | | int serial_is_recv_enable(void); |
| | | int serial_recv_byte(void); |
| | | void serial_puts(const char *s); |
| | | |
| | | /*Define in printf.c*/ |
| | | void printf(const char *fmt, ...); |
| | | int sprintf(char *buf, const char *fmt, ...); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * linux/lib/string.c |
| | | * |
| | | * Copyright (C) 1991, 1992 Linus Torvalds |
| | | */ |
| | | |
| | | /* |
| | | * stupid library routines.. The optimized versions should generally be found |
| | | * as inline code in <asm-xx/string.h> |
| | | * |
| | | * These are buggy as well.. |
| | | * |
| | | * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de> |
| | | * - Added strsep() which will replace strtok() soon (because strsep() is |
| | | * reentrant and should be faster). Use only strsep() in new code, please. |
| | | */ |
| | | |
| | | #include <types.h> |
| | | #include <malloc.h> |
| | | |
| | | |
| | | #if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ |
| | | /** |
| | | * strnicmp - Case insensitive, length-limited string comparison |
| | | * @s1: One string |
| | | * @s2: The other string |
| | | * @len: the maximum number of characters to compare |
| | | */ |
| | | int strnicmp(const char *s1, const char *s2, size_t len) |
| | | { |
| | | /* Yes, Virginia, it had better be unsigned */ |
| | | unsigned char c1, c2; |
| | | |
| | | c1 = 0; c2 = 0; |
| | | if (len) { |
| | | do { |
| | | c1 = *s1; c2 = *s2; |
| | | s1++; s2++; |
| | | if (!c1) |
| | | break; |
| | | if (!c2) |
| | | break; |
| | | if (c1 == c2) |
| | | continue; |
| | | c1 = tolower(c1); |
| | | c2 = tolower(c2); |
| | | if (c1 != c2) |
| | | break; |
| | | } while (--len); |
| | | } |
| | | return (int)c1 - (int)c2; |
| | | } |
| | | #endif |
| | | |
| | | char * ___strtok; |
| | | |
| | | #ifndef __HAVE_ARCH_STRCPY |
| | | /** |
| | | * strcpy - Copy a %NUL terminated string |
| | | * @dest: Where to copy the string to |
| | | * @src: Where to copy the string from |
| | | */ |
| | | char * strcpy(char * dest,const char *src) |
| | | { |
| | | char *tmp = dest; |
| | | |
| | | while ((*dest++ = *src++) != '\0') |
| | | /* nothing */; |
| | | return tmp; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRNCPY |
| | | /** |
| | | * strncpy - Copy a length-limited, %NUL-terminated string |
| | | * @dest: Where to copy the string to |
| | | * @src: Where to copy the string from |
| | | * @count: The maximum number of bytes to copy |
| | | * |
| | | * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. |
| | | * However, the result is not %NUL-terminated if the source exceeds |
| | | * @count bytes. |
| | | */ |
| | | char * strncpy(char * dest,const char *src,size_t count) |
| | | { |
| | | char *tmp = dest; |
| | | |
| | | while (count-- && (*dest++ = *src++) != '\0') |
| | | /* nothing */; |
| | | |
| | | return tmp; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRCAT |
| | | /** |
| | | * strcat - Append one %NUL-terminated string to another |
| | | * @dest: The string to be appended to |
| | | * @src: The string to append to it |
| | | */ |
| | | char * strcat(char * dest, const char * src) |
| | | { |
| | | char *tmp = dest; |
| | | |
| | | while (*dest) |
| | | dest++; |
| | | while ((*dest++ = *src++) != '\0') |
| | | ; |
| | | |
| | | return tmp; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRNCAT |
| | | /** |
| | | * strncat - Append a length-limited, %NUL-terminated string to another |
| | | * @dest: The string to be appended to |
| | | * @src: The string to append to it |
| | | * @count: The maximum numbers of bytes to copy |
| | | * |
| | | * Note that in contrast to strncpy, strncat ensures the result is |
| | | * terminated. |
| | | */ |
| | | char * strncat(char *dest, const char *src, size_t count) |
| | | { |
| | | char *tmp = dest; |
| | | |
| | | if (count) { |
| | | while (*dest) |
| | | dest++; |
| | | while ((*dest++ = *src++)) { |
| | | if (--count == 0) { |
| | | *dest = '\0'; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return tmp; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRCMP |
| | | /** |
| | | * strcmp - Compare two strings |
| | | * @cs: One string |
| | | * @ct: Another string |
| | | */ |
| | | int strcmp(const char * cs,const char * ct) |
| | | { |
| | | register signed char __res; |
| | | |
| | | while (1) { |
| | | if ((__res = *cs - *ct++) != 0 || !*cs++) |
| | | break; |
| | | } |
| | | |
| | | return __res; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRNCMP |
| | | /** |
| | | * strncmp - Compare two length-limited strings |
| | | * @cs: One string |
| | | * @ct: Another string |
| | | * @count: The maximum number of bytes to compare |
| | | */ |
| | | int strncmp(const char * cs,const char * ct,size_t count) |
| | | { |
| | | register signed char __res = 0; |
| | | |
| | | while (count) { |
| | | if ((__res = *cs - *ct++) != 0 || !*cs++) |
| | | break; |
| | | count--; |
| | | } |
| | | |
| | | return __res; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRCHR |
| | | /** |
| | | * strchr - Find the first occurrence of a character in a string |
| | | * @s: The string to be searched |
| | | * @c: The character to search for |
| | | */ |
| | | char * strchr(const char * s, int c) |
| | | { |
| | | for(; *s != (char) c; ++s) |
| | | if (*s == '\0') |
| | | return NULL; |
| | | return (char *) s; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRLEN |
| | | /** |
| | | * strlen - Find the length of a string |
| | | * @s: The string to be sized |
| | | */ |
| | | size_t strlen(const char * s) |
| | | { |
| | | const char *sc; |
| | | |
| | | for (sc = s; *sc != '\0'; ++sc) |
| | | /* nothing */; |
| | | return sc - s; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRRCHR |
| | | /** |
| | | * strrchr - Find the last occurrence of a character in a string |
| | | * @s: The string to be searched |
| | | * @c: The character to search for |
| | | */ |
| | | char * strrchr(const char * s, int c) |
| | | { |
| | | const char *p = s + strlen(s); |
| | | do { |
| | | if (*p == (char)c) |
| | | return (char *)p; |
| | | } while (--p >= s); |
| | | return NULL; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRNLEN |
| | | /** |
| | | * strnlen - Find the length of a length-limited string |
| | | * @s: The string to be sized |
| | | * @count: The maximum number of bytes to search |
| | | */ |
| | | size_t strnlen(const char * s, size_t count) |
| | | { |
| | | const char *sc; |
| | | |
| | | for (sc = s; count-- && *sc != '\0'; ++sc) |
| | | /* nothing */; |
| | | return sc - s; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRDUP |
| | | char * strdup(const char *s) |
| | | { |
| | | char *new; |
| | | |
| | | if ((s == NULL) || ((new = malloc (strlen(s) + 1)) == NULL) ) |
| | | { |
| | | return NULL; |
| | | } |
| | | |
| | | strcpy (new, s); |
| | | return new; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRSPN |
| | | /** |
| | | * strspn - Calculate the length of the initial substring of @s which only |
| | | * contain letters in @accept |
| | | * @s: The string to be searched |
| | | * @accept: The string to search for |
| | | */ |
| | | size_t strspn(const char *s, const char *accept) |
| | | { |
| | | const char *p; |
| | | const char *a; |
| | | size_t count = 0; |
| | | |
| | | for (p = s; *p != '\0'; ++p) { |
| | | for (a = accept; *a != '\0'; ++a) { |
| | | if (*p == *a) |
| | | break; |
| | | } |
| | | if (*a == '\0') |
| | | return count; |
| | | ++count; |
| | | } |
| | | |
| | | return count; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRPBRK |
| | | /** |
| | | * strpbrk - Find the first occurrence of a set of characters |
| | | * @cs: The string to be searched |
| | | * @ct: The characters to search for |
| | | */ |
| | | char * strpbrk(const char * cs,const char * ct) |
| | | { |
| | | const char *sc1,*sc2; |
| | | |
| | | for( sc1 = cs; *sc1 != '\0'; ++sc1) { |
| | | for( sc2 = ct; *sc2 != '\0'; ++sc2) { |
| | | if (*sc1 == *sc2) |
| | | return (char *) sc1; |
| | | } |
| | | } |
| | | return NULL; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRTOK |
| | | /** |
| | | * strtok - Split a string into tokens |
| | | * @s: The string to be searched |
| | | * @ct: The characters to search for |
| | | * |
| | | * WARNING: strtok is deprecated, use strsep instead. |
| | | */ |
| | | char * strtok(char * s,const char * ct) |
| | | { |
| | | char *sbegin, *send; |
| | | |
| | | sbegin = s ? s : ___strtok; |
| | | if (!sbegin) { |
| | | return NULL; |
| | | } |
| | | sbegin += strspn(sbegin,ct); |
| | | if (*sbegin == '\0') { |
| | | ___strtok = NULL; |
| | | return( NULL ); |
| | | } |
| | | send = strpbrk( sbegin, ct); |
| | | if (send && *send != '\0') |
| | | *send++ = '\0'; |
| | | ___strtok = send; |
| | | return (sbegin); |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRSEP |
| | | /** |
| | | * strsep - Split a string into tokens |
| | | * @s: The string to be searched |
| | | * @ct: The characters to search for |
| | | * |
| | | * strsep() updates @s to point after the token, ready for the next call. |
| | | * |
| | | * It returns empty tokens, too, behaving exactly like the libc function |
| | | * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. |
| | | * Same semantics, slimmer shape. ;) |
| | | */ |
| | | char * strsep(char **s, const char *ct) |
| | | { |
| | | char *sbegin = *s, *end; |
| | | |
| | | if (sbegin == NULL) |
| | | return NULL; |
| | | |
| | | end = strpbrk(sbegin, ct); |
| | | if (end) |
| | | *end++ = '\0'; |
| | | *s = end; |
| | | |
| | | return sbegin; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRSWAB |
| | | /** |
| | | * strswab - swap adjacent even and odd bytes in %NUL-terminated string |
| | | * s: address of the string |
| | | * |
| | | * returns the address of the swapped string or NULL on error. If |
| | | * string length is odd, last byte is untouched. |
| | | */ |
| | | char *strswab(const char *s) |
| | | { |
| | | char *p, *q; |
| | | |
| | | if ((NULL == s) || ('\0' == *s)) { |
| | | return (NULL); |
| | | } |
| | | |
| | | for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) { |
| | | char tmp; |
| | | |
| | | tmp = *p; |
| | | *p = *q; |
| | | *q = tmp; |
| | | } |
| | | |
| | | return (char *) s; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMSET |
| | | /** |
| | | * memset - Fill a region of memory with the given value |
| | | * @s: Pointer to the start of the area. |
| | | * @c: The byte to fill the area with |
| | | * @count: The size of the area. |
| | | * |
| | | * Do not use memset() to access IO space, use memset_io() instead. |
| | | */ |
| | | void * memset(void * s,int c,size_t count) |
| | | { |
| | | unsigned long *sl = (unsigned long *) s; |
| | | unsigned long cl = 0; |
| | | char *s8; |
| | | int i; |
| | | |
| | | /* do it one word at a time (32 bits or 64 bits) while possible */ |
| | | if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) { |
| | | for (i = 0; i < sizeof(*sl); i++) { |
| | | cl <<= 8; |
| | | cl |= c & 0xff; |
| | | } |
| | | while (count >= sizeof(*sl)) { |
| | | *sl++ = cl; |
| | | count -= sizeof(*sl); |
| | | } |
| | | } |
| | | /* fill 8 bits at a time */ |
| | | s8 = (char *)sl; |
| | | while (count--) |
| | | *s8++ = c; |
| | | |
| | | return s; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_BCOPY |
| | | /** |
| | | * bcopy - Copy one area of memory to another |
| | | * @src: Where to copy from |
| | | * @dest: Where to copy to |
| | | * @count: The size of the area. |
| | | * |
| | | * Note that this is the same as memcpy(), with the arguments reversed. |
| | | * memcpy() is the standard, bcopy() is a legacy BSD function. |
| | | * |
| | | * You should not use this function to access IO space, use memcpy_toio() |
| | | * or memcpy_fromio() instead. |
| | | */ |
| | | char * bcopy(const char * src, char * dest, int count) |
| | | { |
| | | char *tmp = dest; |
| | | |
| | | while (count--) |
| | | *tmp++ = *src++; |
| | | |
| | | return dest; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMCPY |
| | | /** |
| | | * memcpy - Copy one area of memory to another |
| | | * @dest: Where to copy to |
| | | * @src: Where to copy from |
| | | * @count: The size of the area. |
| | | * |
| | | * You should not use this function to access IO space, use memcpy_toio() |
| | | * or memcpy_fromio() instead. |
| | | */ |
| | | void * memcpy(void *dest, const void *src, size_t count) |
| | | { |
| | | unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src; |
| | | char *d8, *s8; |
| | | |
| | | /* while all data is aligned (common case), copy a word at a time */ |
| | | if ( (((ulong)dest | (ulong)src) & (sizeof(*dl) - 1)) == 0) { |
| | | while (count >= sizeof(*dl)) { |
| | | *dl++ = *sl++; |
| | | count -= sizeof(*dl); |
| | | } |
| | | } |
| | | /* copy the reset one byte at a time */ |
| | | d8 = (char *)dl; |
| | | s8 = (char *)sl; |
| | | while (count--) |
| | | *d8++ = *s8++; |
| | | |
| | | return dest; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMMOVE |
| | | /** |
| | | * memmove - Copy one area of memory to another |
| | | * @dest: Where to copy to |
| | | * @src: Where to copy from |
| | | * @count: The size of the area. |
| | | * |
| | | * Unlike memcpy(), memmove() copes with overlapping areas. |
| | | */ |
| | | void * memmove(void * dest,const void *src,size_t count) |
| | | { |
| | | char *tmp, *s; |
| | | |
| | | if (dest <= src) { |
| | | tmp = (char *) dest; |
| | | s = (char *) src; |
| | | while (count--) |
| | | *tmp++ = *s++; |
| | | } |
| | | else { |
| | | tmp = (char *) dest + count; |
| | | s = (char *) src + count; |
| | | while (count--) |
| | | *--tmp = *--s; |
| | | } |
| | | |
| | | return dest; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMCMP |
| | | /** |
| | | * memcmp - Compare two areas of memory |
| | | * @cs: One area of memory |
| | | * @ct: Another area of memory |
| | | * @count: The size of the area. |
| | | */ |
| | | int memcmp(const void * cs,const void * ct,size_t count) |
| | | { |
| | | const unsigned char *su1, *su2; |
| | | int res = 0; |
| | | |
| | | for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) |
| | | if ((res = *su1 - *su2) != 0) |
| | | break; |
| | | return res; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMSCAN |
| | | /** |
| | | * memscan - Find a character in an area of memory. |
| | | * @addr: The memory area |
| | | * @c: The byte to search for |
| | | * @size: The size of the area. |
| | | * |
| | | * returns the address of the first occurrence of @c, or 1 byte past |
| | | * the area if @c is not found |
| | | */ |
| | | void * memscan(void * addr, int c, size_t size) |
| | | { |
| | | unsigned char * p = (unsigned char *) addr; |
| | | |
| | | while (size) { |
| | | if (*p == c) |
| | | return (void *) p; |
| | | p++; |
| | | size--; |
| | | } |
| | | return (void *) p; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_STRSTR |
| | | /** |
| | | * strstr - Find the first substring in a %NUL terminated string |
| | | * @s1: The string to be searched |
| | | * @s2: The string to search for |
| | | */ |
| | | char * strstr(const char * s1,const char * s2) |
| | | { |
| | | int l1, l2; |
| | | |
| | | l2 = strlen(s2); |
| | | if (!l2) |
| | | return (char *) s1; |
| | | l1 = strlen(s1); |
| | | while (l1 >= l2) { |
| | | l1--; |
| | | if (!memcmp(s1,s2,l2)) |
| | | return (char *) s1; |
| | | s1++; |
| | | } |
| | | return NULL; |
| | | } |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMCHR |
| | | /** |
| | | * memchr - Find a character in an area of memory. |
| | | * @s: The memory area |
| | | * @c: The byte to search for |
| | | * @n: The size of the area. |
| | | * |
| | | * returns the address of the first occurrence of @c, or %NULL |
| | | * if @c is not found |
| | | */ |
| | | void *memchr(const void *s, int c, size_t n) |
| | | { |
| | | const unsigned char *p = s; |
| | | while (n-- != 0) { |
| | | if ((unsigned char)c == *p++) { |
| | | return (void *)(p-1); |
| | | } |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | #endif |
New file |
| | |
| | | #ifndef _LINUX_STRING_H_ |
| | | #define _LINUX_STRING_H_ |
| | | |
| | | #include <types.h> /* for size_t */ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | extern char * ___strtok; |
| | | extern char * strpbrk(const char *,const char *); |
| | | extern char * strtok(char *,const char *); |
| | | extern char * strsep(char **,const char *); |
| | | extern __kernel_size_t strspn(const char *,const char *); |
| | | |
| | | |
| | | /* |
| | | * Include machine specific inline routines |
| | | */ |
| | | #ifndef __HAVE_ARCH_STRCPY |
| | | extern char * strcpy(char *,const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNCPY |
| | | extern char * strncpy(char *,const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRCAT |
| | | extern char * strcat(char *, const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNCAT |
| | | extern char * strncat(char *, const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRCMP |
| | | extern int strcmp(const char *,const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNCMP |
| | | extern int strncmp(const char *,const char *,__kernel_size_t); |
| | | #endif |
| | | #if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ |
| | | extern int strnicmp(const char *, const char *, __kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRCHR |
| | | extern char * strchr(const char *,int); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRRCHR |
| | | extern char * strrchr(const char *,int); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRSTR |
| | | extern char * strstr(const char *,const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRLEN |
| | | extern __kernel_size_t strlen(const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRNLEN |
| | | extern __kernel_size_t strnlen(const char *,__kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRDUP |
| | | extern char * strdup(const char *); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_STRSWAB |
| | | extern char * strswab(const char *); |
| | | #endif |
| | | |
| | | #ifndef __HAVE_ARCH_MEMSET |
| | | extern void * memset(void *,int,__kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMCPY |
| | | extern void * memcpy(void *,const void *,__kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMMOVE |
| | | extern void * memmove(void *,const void *,__kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMSCAN |
| | | extern void * memscan(void *,int,__kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMCMP |
| | | extern int memcmp(const void *,const void *,__kernel_size_t); |
| | | #endif |
| | | #ifndef __HAVE_ARCH_MEMCHR |
| | | extern void * memchr(const void *,int,__kernel_size_t); |
| | | #endif |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _LINUX_STRING_H_ */ |
New file |
| | |
| | | #ifndef _LINUX_TYPES_H |
| | | #define _LINUX_TYPES_H |
| | | |
| | | |
| | | #undef NULL |
| | | #if defined(__cplusplus) |
| | | #define NULL 0 |
| | | #else |
| | | #define NULL ((void *)0) |
| | | #endif |
| | | |
| | | /* bsd */ |
| | | typedef unsigned char u_char; |
| | | typedef unsigned short u_short; |
| | | typedef unsigned int u_int; |
| | | typedef unsigned long u_long; |
| | | |
| | | /* sysv */ |
| | | typedef unsigned char unchar; |
| | | typedef unsigned short ushort; |
| | | typedef unsigned int uint; |
| | | typedef unsigned long ulong; |
| | | |
| | | /* |
| | | * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the |
| | | * header files exported to user space |
| | | */ |
| | | typedef __signed__ char __s8; |
| | | typedef unsigned char __u8; |
| | | typedef __signed__ short __s16; |
| | | typedef unsigned short __u16; |
| | | typedef __signed__ int __s32; |
| | | typedef unsigned int __u32; |
| | | #if defined(__GNUC__) |
| | | __extension__ typedef __signed__ long long __s64; |
| | | __extension__ typedef unsigned long long __u64; |
| | | #endif |
| | | |
| | | typedef signed char s8; |
| | | typedef unsigned char u8; |
| | | typedef signed short s16; |
| | | typedef unsigned short u16; |
| | | typedef signed int s32; |
| | | typedef unsigned int u32; |
| | | typedef signed long long s64; |
| | | typedef unsigned long long u64; |
| | | |
| | | typedef unsigned int __kernel_size_t; |
| | | typedef int __kernel_ssize_t; |
| | | typedef int __kernel_ptrdiff_t; |
| | | typedef long __kernel_off_t; |
| | | typedef long long __kernel_loff_t; |
| | | typedef unsigned short __kernel_dev_t; |
| | | typedef unsigned short __kernel_mode_t; |
| | | |
| | | |
| | | typedef __kernel_dev_t dev_t; |
| | | typedef __kernel_mode_t mode_t; |
| | | typedef __kernel_off_t off_t; |
| | | typedef __kernel_loff_t loff_t; |
| | | |
| | | #ifndef _PTRDIFF_T |
| | | #define _PTRDIFF_T |
| | | typedef __kernel_ptrdiff_t ptrdiff_t; |
| | | #endif |
| | | |
| | | #ifndef _SIZE_T |
| | | #define _SIZE_T |
| | | typedef __kernel_size_t size_t; |
| | | #endif |
| | | |
| | | #ifndef _SSIZE_T |
| | | #define _SSIZE_T |
| | | typedef __kernel_ssize_t ssize_t; |
| | | #endif |
| | | |
| | | #ifndef __BIT_TYPES_DEFINED__ |
| | | #define __BIT_TYPES_DEFINED__ |
| | | |
| | | typedef __u8 u_int8_t; |
| | | typedef __s8 int8_t; |
| | | typedef __u16 u_int16_t; |
| | | typedef __s16 int16_t; |
| | | typedef __u32 u_int32_t; |
| | | typedef __s32 int32_t; |
| | | |
| | | #endif /* !(__BIT_TYPES_DEFINED__) */ |
| | | |
| | | typedef __u8 uint8_t; |
| | | typedef __u16 uint16_t; |
| | | typedef __u32 uint32_t; |
| | | |
| | | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) |
| | | typedef __u64 uint64_t; |
| | | typedef __u64 u_int64_t; |
| | | typedef __s64 int64_t; |
| | | #endif |
| | | |
| | | #endif /* _LINUX_TYPES_H */ |
New file |
| | |
| | | |
| | | # *********************************************************************** |
| | | # * File: makefile |
| | | # * Version: 1.0.0 |
| | | # * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | # * Description: Makefile used to cross compile the ASM source code |
| | | # * ChangeLog: 1, Release initial version on "Sun Mar 20 18:41:04 CST 2011" |
| | | # * |
| | | # *********************************************************************** |
| | | # |
| | | |
| | | APP_NAME=bootstrap |
| | | INST_PATH=/tftp |
| | | SRC_TOP=$(CURDIR) |
| | | |
| | | OBJS_MAIN := bootstrap.o start.o |
| | | OBJS_BSP += ${SRC_TOP}/bsp/*.o |
| | | OBJS_COMMON += ${SRC_TOP}/common/*.o |
| | | OBJS_YAFFS2 += ${SRC_TOP}/yaffs2/*.o |
| | | |
| | | CFLAGS+=-I${SRC_TOP}/common |
| | | CFLAGS+=-I${SRC_TOP}/bsp |
| | | CFLAGS+=-I${SRC_TOP}/yaffs2 |
| | | |
| | | # Set the stack top base address here |
| | | TEXT_BASE=0x31000000 |
| | | STACK_BASE=0x31010000 |
| | | MALLOC_SIZE=0x100000 |
| | | CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=${STACK_BASE} -DCONFIG_SYS_MALLOC_LEN=${MALLOC_SIZE} |
| | | |
| | | CFLAGS+=-DDEBUG |
| | | |
| | | gccincdir := $(shell $(CC) -print-file-name=include) |
| | | CFLAGS += -ffreestanding -nostdinc -isystem $(gccincdir) -pipe |
| | | CFLAGS+= -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float |
| | | CFLAGS+=-march=armv4t -Wall -Wno-unused -Wstrict-prototypes -fno-stack-protector |
| | | CFLAGS += -fno-builtin |
| | | LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE) |
| | | AFLAGS := $(CFLAGS) -D__ASSEMBLY__ |
| | | export CFLAGS |
| | | export AFLAGS |
| | | |
| | | #CFLAGS+=-Os -D__KERNEL__ -DCONFIG_ARM -D__ARM__ |
| | | PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc |
| | | #PLATFORM_LIBS += -L/opt/buildroot-2011.11/arm920t/usr/arm-unknown-linux-uclibcgnueabi/sysroot/usr/lib/ -lc |
| | | |
| | | CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- |
| | | AS = $(CROSS_COMPILE)as |
| | | LD = $(CROSS_COMPILE)ld |
| | | CC = $(CROSS_COMPILE)gcc |
| | | CPP = $(CC) -E |
| | | AR = $(CROSS_COMPILE)ar |
| | | NM = $(CROSS_COMPILE)nm |
| | | LDR = $(CROSS_COMPILE)ldr |
| | | STRIP = $(CROSS_COMPILE)strip |
| | | OBJCOPY = $(CROSS_COMPILE)objcopy |
| | | OBJDUMP = $(CROSS_COMPILE)objdump |
| | | RANLIB = $(CROSS_COMPILE)RANLIB |
| | | |
| | | export CROSS_COMPILE AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP CFLAGS |
| | | |
| | | ALL: clean bsp_lib common_lib yaffs2_lib ${OBJS_MAIN} |
| | | echo ${OBJS_BSP} |
| | | cd $(SRC_TOP) |
| | | ${LD} $(LDFLAGS) \ |
| | | --start-group ${OBJS_BSP} ${OBJS_COMMON} ${OBJS_YAFFS2} $(OBJS_MAIN) \ |
| | | --end-group $(PLATFORM_LIBS) \ |
| | | -Map $(APP_NAME).map -o $(APP_NAME).elf |
| | | ${OBJCOPY} -O binary $(APP_NAME).elf $(APP_NAME).bin |
| | | @chmod 777 $(APP_NAME).bin |
| | | @rm -f *.elf *.o |
| | | @make install |
| | | |
| | | bsp_lib: |
| | | @make -C bsp |
| | | |
| | | common_lib: |
| | | @make -C common |
| | | |
| | | yaffs2_lib: |
| | | @make -C yaffs2 |
| | | |
| | | %.o: %.S |
| | | $(CC) $(AFLAGS) -c -o $@ $< |
| | | |
| | | %.o: %.c |
| | | $(CC) $(CFLAGS) -c -o $@ $< |
| | | |
| | | install: $(APP_NAME).bin |
| | | cp $(APP_NAME).bin $(INST_PATH) -f |
| | | |
| | | clean: |
| | | @find $(OBJTREE) -type f \ |
| | | \( -name 'core' -o -name '*.bak' -o -name '*~' -o -name .depend \ |
| | | -o -name '*.o' -o -name '*.a' -o -name '*.elf' \) -print \ |
| | | | xargs rm -f |
| | | @rm -f $(APP_NAME).bin |
| | | @rm -f $(APP_NAME).map |
| | | @make clean -C yaffs2 |
| | | |
| | | distclean clear: clean |
| | | @rm -f cscope.* tags |
| | | |
| | | |
New file |
| | |
| | | |
| | | /******************************************************************************************** |
| | | * File: start.S - Startup Code for ARM920 CPU-core |
| | | * Version: 1.0.0 |
| | | * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> |
| | | * Description: When system power up, the CPU will comes here to excute the first code here. |
| | | * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | |
| | | /* |
| | | ************************************************************************* |
| | | * |
| | | * Jump vector table as in table 3.1 in [1] |
| | | * |
| | | ************************************************************************* |
| | | */ |
| | | |
| | | .globl _start |
| | | _start: b start_code |
| | | |
| | | _TEXT_BASE: |
| | | .word TEXT_BASE |
| | | |
| | | .globl _armboot_start |
| | | _armboot_start: |
| | | .word _start |
| | | |
| | | /* |
| | | * These are defined in the board-specific linker script. |
| | | */ |
| | | .globl _bss_start |
| | | _bss_start: |
| | | .word __bss_start |
| | | |
| | | .globl _bss_end |
| | | _bss_end: |
| | | .word _end |
| | | |
| | | start_code: |
| | | /* Set up the stack */ |
| | | stack_setup: |
| | | ldr r0, =TEXT_BASE /* upper 128 KiB: relocated uboot */ |
| | | sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ |
| | | sub sp, r0, #12 /* leave 3 words for abort-stack */ |
| | | bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ |
| | | |
| | | clear_bss: |
| | | ldr r0, _bss_start /* find start of bss segment */ |
| | | ldr r1, _bss_end /* stop here */ |
| | | mov r2, #0x00000000 /* clear */ |
| | | |
| | | clbss_l:str r2, [r0] /* clear loop... */ |
| | | add r0, r0, #4 |
| | | cmp r0, r1 |
| | | ble clbss_l |
| | | |
| | | bl bootstrap_main |
| | | |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 CoherentPlus Sdn. Bhd. |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This is the common subdir Makefile which to compile all the C |
| | | # source code to object files and then generate the shared or |
| | | # static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, |
| | | # which depends on the variable $LINK_MODE. |
| | | # |
| | | # Version: 1.0.0(10/08/2011~) |
| | | # Author: Guo Wenxue <guowenxue@gmail.com> |
| | | # ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" |
| | | # |
| | | #********************************************************************************/ |
| | | |
| | | PWD=$(shell pwd) |
| | | LOCAL_COMPILE=YES |
| | | LINK_MODE=STATIC |
| | | |
| | | #If wanna compile in the subdir, not called by top makefile, uncomment it |
| | | ifneq (${TOP_COMPILE}, YES) |
| | | LOCAL_COMPILE=YES |
| | | endif |
| | | |
| | | LIBNAME=$(shell basename ${PWD}) |
| | | STALIB=lib${LIBNAME}.a |
| | | DYNLIB=lib${LIBNAME}.so |
| | | |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | #====================================================== |
| | | # ---> Doesn't call by top makefile, compile by local |
| | | #====================================================== |
| | | ifeq (${LOCAL_COMPILE}, YES) |
| | | ARCH?=arm920t |
| | | #ARCH?=i386 |
| | | CFLAGS+=-fPIC |
| | | TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") |
| | | ifneq (,$(filter i386,$(TMP))) |
| | | CROSS_COMPILE= |
| | | else |
| | | CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- |
| | | endif |
| | | |
| | | PRJDIR?=$(shell pwd) |
| | | CFLAGS+=-I${PRJDIR} |
| | | CC = ${CROSS_COMPILE}gcc |
| | | AR = ${CROSS_COMPILE}ar |
| | | |
| | | endif #End local compile |
| | | |
| | | ifeq ("${LINK_MODE}", "STATIC") |
| | | LIBS = ${STALIB} |
| | | else |
| | | LIBS=${DYNLIB} |
| | | endif |
| | | |
| | | all: entry ${LIBS} install |
| | | |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | #$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o |
| | | ${STALIB}: $(OBJS) |
| | | $(AR) -rcu $@ $(OBJS) |
| | | |
| | | ${DYNLIB}: $(OBJS) |
| | | $(CC) -fPIC -shared -o $@ $(OBJS) |
| | | |
| | | %.o : %.c |
| | | $(CC) -c $< $(CFLAGS) |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @if [ ! -z "${LIBS_PATH}" ] ; then \ |
| | | mkdir -p ${LIBS_PATH} ; \ |
| | | cp ${LIBS} ${LIBS_PATH}; \ |
| | | fi; |
| | | |
| | | |
| | | clean: |
| | | @rm -f *.o |
| | | @rm -rf *.gdb *.a *.so |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * 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. |
| | | */ |
| | | |
| | | #include "yaffs_allocator.h" |
| | | #include "yaffs_guts.h" |
| | | #include "yaffs_trace.h" |
| | | #include "yportenv.h" |
| | | |
| | | /* |
| | | * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks |
| | | * of approx 100 objects that are themn allocated singly. |
| | | * This is basically a simplified slab allocator. |
| | | * |
| | | * We don't use the Linux slab allocator because slab does not allow |
| | | * us to dump all the objects in one hit when we do a umount and tear |
| | | * down all the tnodes and objects. slab requires that we first free |
| | | * the individual objects. |
| | | * |
| | | * Once yaffs has been mainlined I shall try to motivate for a change |
| | | * to slab to provide the extra features we need here. |
| | | */ |
| | | |
| | | struct yaffs_tnode_list { |
| | | struct yaffs_tnode_list *next; |
| | | struct yaffs_tnode *tnodes; |
| | | }; |
| | | |
| | | struct yaffs_obj_list { |
| | | struct yaffs_obj_list *next; |
| | | struct yaffs_obj *objects; |
| | | }; |
| | | |
| | | struct yaffs_allocator { |
| | | int n_tnodes_created; |
| | | struct yaffs_tnode *free_tnodes; |
| | | int n_free_tnodes; |
| | | struct yaffs_tnode_list *alloc_tnode_list; |
| | | |
| | | int n_obj_created; |
| | | struct list_head free_objs; |
| | | int n_free_objects; |
| | | |
| | | struct yaffs_obj_list *allocated_obj_list; |
| | | }; |
| | | |
| | | static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_allocator *allocator = |
| | | (struct yaffs_allocator *)dev->allocator; |
| | | struct yaffs_tnode_list *tmp; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | while (allocator->alloc_tnode_list) { |
| | | tmp = allocator->alloc_tnode_list->next; |
| | | |
| | | kfree(allocator->alloc_tnode_list->tnodes); |
| | | kfree(allocator->alloc_tnode_list); |
| | | allocator->alloc_tnode_list = tmp; |
| | | } |
| | | |
| | | allocator->free_tnodes = NULL; |
| | | allocator->n_free_tnodes = 0; |
| | | allocator->n_tnodes_created = 0; |
| | | } |
| | | |
| | | static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | allocator->alloc_tnode_list = NULL; |
| | | allocator->free_tnodes = NULL; |
| | | allocator->n_free_tnodes = 0; |
| | | allocator->n_tnodes_created = 0; |
| | | } |
| | | |
| | | static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) |
| | | { |
| | | struct yaffs_allocator *allocator = |
| | | (struct yaffs_allocator *)dev->allocator; |
| | | int i; |
| | | struct yaffs_tnode *new_tnodes; |
| | | u8 *mem; |
| | | struct yaffs_tnode *curr; |
| | | struct yaffs_tnode *next; |
| | | struct yaffs_tnode_list *tnl; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return YAFFS_FAIL; |
| | | } |
| | | |
| | | if (n_tnodes < 1) |
| | | return YAFFS_OK; |
| | | |
| | | /* make these things */ |
| | | new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); |
| | | mem = (u8 *) new_tnodes; |
| | | |
| | | if (!new_tnodes) { |
| | | yaffs_trace(YAFFS_TRACE_ERROR, |
| | | "yaffs: Could not allocate Tnodes"); |
| | | return YAFFS_FAIL; |
| | | } |
| | | |
| | | /* New hookup for wide tnodes */ |
| | | for (i = 0; i < n_tnodes - 1; i++) { |
| | | curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; |
| | | next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; |
| | | curr->internal[0] = next; |
| | | } |
| | | |
| | | curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; |
| | | curr->internal[0] = allocator->free_tnodes; |
| | | allocator->free_tnodes = (struct yaffs_tnode *)mem; |
| | | |
| | | allocator->n_free_tnodes += n_tnodes; |
| | | allocator->n_tnodes_created += n_tnodes; |
| | | |
| | | /* Now add this bunch of tnodes to a list for freeing up. |
| | | * NB If we can't add this to the management list it isn't fatal |
| | | * but it just means we can't free this bunch of tnodes later. |
| | | */ |
| | | tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); |
| | | if (!tnl) { |
| | | yaffs_trace(YAFFS_TRACE_ERROR, |
| | | "Could not add tnodes to management list"); |
| | | return YAFFS_FAIL; |
| | | } else { |
| | | tnl->tnodes = new_tnodes; |
| | | tnl->next = allocator->alloc_tnode_list; |
| | | allocator->alloc_tnode_list = tnl; |
| | | } |
| | | |
| | | yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added"); |
| | | |
| | | return YAFFS_OK; |
| | | } |
| | | |
| | | struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_allocator *allocator = |
| | | (struct yaffs_allocator *)dev->allocator; |
| | | struct yaffs_tnode *tn = NULL; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return NULL; |
| | | } |
| | | |
| | | /* If there are none left make more */ |
| | | if (!allocator->free_tnodes) |
| | | yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); |
| | | |
| | | if (allocator->free_tnodes) { |
| | | tn = allocator->free_tnodes; |
| | | allocator->free_tnodes = allocator->free_tnodes->internal[0]; |
| | | allocator->n_free_tnodes--; |
| | | } |
| | | |
| | | return tn; |
| | | } |
| | | |
| | | /* FreeTnode frees up a tnode and puts it back on the free list */ |
| | | void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) |
| | | { |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | if (tn) { |
| | | tn->internal[0] = allocator->free_tnodes; |
| | | allocator->free_tnodes = tn; |
| | | allocator->n_free_tnodes++; |
| | | } |
| | | dev->checkpoint_blocks_required = 0; /* force recalculation */ |
| | | } |
| | | |
| | | /*--------------- yaffs_obj alloaction ------------------------ |
| | | * |
| | | * Free yaffs_objs are stored in a list using obj->siblings. |
| | | * The blocks of allocated objects are stored in a linked list. |
| | | */ |
| | | |
| | | static void yaffs_init_raw_objs(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | allocator->allocated_obj_list = NULL; |
| | | INIT_LIST_HEAD(&allocator->free_objs); |
| | | allocator->n_free_objects = 0; |
| | | } |
| | | |
| | | static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | struct yaffs_obj_list *tmp; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | while (allocator->allocated_obj_list) { |
| | | tmp = allocator->allocated_obj_list->next; |
| | | kfree(allocator->allocated_obj_list->objects); |
| | | kfree(allocator->allocated_obj_list); |
| | | allocator->allocated_obj_list = tmp; |
| | | } |
| | | |
| | | INIT_LIST_HEAD(&allocator->free_objs); |
| | | allocator->n_free_objects = 0; |
| | | allocator->n_obj_created = 0; |
| | | } |
| | | |
| | | static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) |
| | | { |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | int i; |
| | | struct yaffs_obj *new_objs; |
| | | struct yaffs_obj_list *list; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return YAFFS_FAIL; |
| | | } |
| | | |
| | | if (n_obj < 1) |
| | | return YAFFS_OK; |
| | | |
| | | /* make these things */ |
| | | new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); |
| | | list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); |
| | | |
| | | if (!new_objs || !list) { |
| | | kfree(new_objs); |
| | | new_objs = NULL; |
| | | kfree(list); |
| | | list = NULL; |
| | | yaffs_trace(YAFFS_TRACE_ALLOCATE, |
| | | "Could not allocate more objects"); |
| | | return YAFFS_FAIL; |
| | | } |
| | | |
| | | /* Hook them into the free list */ |
| | | for (i = 0; i < n_obj; i++) |
| | | list_add(&new_objs[i].siblings, &allocator->free_objs); |
| | | |
| | | allocator->n_free_objects += n_obj; |
| | | allocator->n_obj_created += n_obj; |
| | | |
| | | /* Now add this bunch of Objects to a list for freeing up. */ |
| | | |
| | | list->objects = new_objs; |
| | | list->next = allocator->allocated_obj_list; |
| | | allocator->allocated_obj_list = list; |
| | | |
| | | return YAFFS_OK; |
| | | } |
| | | |
| | | struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_obj *obj = NULL; |
| | | struct list_head *lh; |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return obj; |
| | | } |
| | | |
| | | /* If there are none left make more */ |
| | | if (list_empty(&allocator->free_objs)) |
| | | yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); |
| | | |
| | | if (!list_empty(&allocator->free_objs)) { |
| | | lh = allocator->free_objs.next; |
| | | obj = list_entry(lh, struct yaffs_obj, siblings); |
| | | list_del_init(lh); |
| | | allocator->n_free_objects--; |
| | | } |
| | | |
| | | return obj; |
| | | } |
| | | |
| | | void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) |
| | | { |
| | | |
| | | struct yaffs_allocator *allocator = dev->allocator; |
| | | |
| | | if (!allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | /* Link into the free list. */ |
| | | list_add(&obj->siblings, &allocator->free_objs); |
| | | allocator->n_free_objects++; |
| | | } |
| | | |
| | | void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) |
| | | { |
| | | |
| | | if (!dev->allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | yaffs_deinit_raw_tnodes(dev); |
| | | yaffs_deinit_raw_objs(dev); |
| | | kfree(dev->allocator); |
| | | dev->allocator = NULL; |
| | | } |
| | | |
| | | void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_allocator *allocator; |
| | | |
| | | if (dev->allocator) { |
| | | BUG(); |
| | | return; |
| | | } |
| | | |
| | | allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); |
| | | if (allocator) { |
| | | dev->allocator = allocator; |
| | | yaffs_init_raw_tnodes(dev); |
| | | yaffs_init_raw_objs(dev); |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_ALLOCATOR_H__ |
| | | #define __YAFFS_ALLOCATOR_H__ |
| | | |
| | | #include "yaffs_guts.h" |
| | | |
| | | void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); |
| | | void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); |
| | | |
| | | struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); |
| | | void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); |
| | | |
| | | struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); |
| | | void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * 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. |
| | | */ |
| | | |
| | | #include "yaffs_guts.h" |
| | | #include "yaffs_attribs.h" |
| | | |
| | | void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) |
| | | { |
| | | obj->yst_uid = oh->yst_uid; |
| | | obj->yst_gid = oh->yst_gid; |
| | | obj->yst_atime = oh->yst_atime; |
| | | obj->yst_mtime = oh->yst_mtime; |
| | | obj->yst_ctime = oh->yst_ctime; |
| | | obj->yst_rdev = oh->yst_rdev; |
| | | } |
| | | |
| | | void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) |
| | | { |
| | | oh->yst_uid = obj->yst_uid; |
| | | oh->yst_gid = obj->yst_gid; |
| | | oh->yst_atime = obj->yst_atime; |
| | | oh->yst_mtime = obj->yst_mtime; |
| | | oh->yst_ctime = obj->yst_ctime; |
| | | oh->yst_rdev = obj->yst_rdev; |
| | | |
| | | } |
| | | |
| | | void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) |
| | | { |
| | | obj->yst_mtime = Y_CURRENT_TIME; |
| | | if (do_a) |
| | | obj->yst_atime = obj->yst_mtime; |
| | | if (do_c) |
| | | obj->yst_ctime = obj->yst_mtime; |
| | | } |
| | | |
| | | void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) |
| | | { |
| | | yaffs_load_current_time(obj, 1, 1); |
| | | obj->yst_rdev = rdev; |
| | | obj->yst_uid = uid; |
| | | obj->yst_gid = gid; |
| | | } |
| | | |
| | | static loff_t yaffs_get_file_size(struct yaffs_obj *obj) |
| | | { |
| | | YCHAR *alias = NULL; |
| | | obj = yaffs_get_equivalent_obj(obj); |
| | | |
| | | switch (obj->variant_type) { |
| | | case YAFFS_OBJECT_TYPE_FILE: |
| | | return obj->variant.file_variant.file_size; |
| | | case YAFFS_OBJECT_TYPE_SYMLINK: |
| | | alias = obj->variant.symlink_variant.alias; |
| | | if (!alias) |
| | | return 0; |
| | | return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); |
| | | default: |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) |
| | | { |
| | | unsigned int valid = attr->ia_valid; |
| | | |
| | | if (valid & ATTR_MODE) |
| | | obj->yst_mode = attr->ia_mode; |
| | | if (valid & ATTR_UID) |
| | | obj->yst_uid = attr->ia_uid; |
| | | if (valid & ATTR_GID) |
| | | obj->yst_gid = attr->ia_gid; |
| | | |
| | | if (valid & ATTR_ATIME) |
| | | obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); |
| | | if (valid & ATTR_CTIME) |
| | | obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); |
| | | if (valid & ATTR_MTIME) |
| | | obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); |
| | | |
| | | if (valid & ATTR_SIZE) |
| | | yaffs_resize_file(obj, attr->ia_size); |
| | | |
| | | yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); |
| | | |
| | | return YAFFS_OK; |
| | | |
| | | } |
| | | |
| | | int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) |
| | | { |
| | | unsigned int valid = 0; |
| | | |
| | | attr->ia_mode = obj->yst_mode; |
| | | valid |= ATTR_MODE; |
| | | attr->ia_uid = obj->yst_uid; |
| | | valid |= ATTR_UID; |
| | | attr->ia_gid = obj->yst_gid; |
| | | valid |= ATTR_GID; |
| | | |
| | | Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; |
| | | valid |= ATTR_ATIME; |
| | | Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; |
| | | valid |= ATTR_CTIME; |
| | | Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; |
| | | valid |= ATTR_MTIME; |
| | | |
| | | attr->ia_size = yaffs_get_file_size(obj); |
| | | valid |= ATTR_SIZE; |
| | | |
| | | attr->ia_valid = valid; |
| | | |
| | | return YAFFS_OK; |
| | | } |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_ATTRIBS_H__ |
| | | #define __YAFFS_ATTRIBS_H__ |
| | | |
| | | #include "yaffs_guts.h" |
| | | |
| | | void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); |
| | | void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); |
| | | void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); |
| | | void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); |
| | | int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); |
| | | int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * 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. |
| | | */ |
| | | |
| | | #include "yaffs_bitmap.h" |
| | | #include "yaffs_trace.h" |
| | | /* |
| | | * Chunk bitmap manipulations |
| | | */ |
| | | |
| | | static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) |
| | | { |
| | | if (blk < dev->internal_start_block || blk > dev->internal_end_block) { |
| | | yaffs_trace(YAFFS_TRACE_ERROR, |
| | | "BlockBits block %d is not valid", |
| | | blk); |
| | | BUG(); |
| | | } |
| | | return dev->chunk_bits + |
| | | (dev->chunk_bit_stride * (blk - dev->internal_start_block)); |
| | | } |
| | | |
| | | void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) |
| | | { |
| | | if (blk < dev->internal_start_block || blk > dev->internal_end_block || |
| | | chunk < 0 || chunk >= dev->param.chunks_per_block) { |
| | | yaffs_trace(YAFFS_TRACE_ERROR, |
| | | "Chunk Id (%d:%d) invalid", |
| | | blk, chunk); |
| | | BUG(); |
| | | } |
| | | } |
| | | |
| | | void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) |
| | | { |
| | | u8 *blk_bits = yaffs_block_bits(dev, blk); |
| | | |
| | | memset(blk_bits, 0, dev->chunk_bit_stride); |
| | | } |
| | | |
| | | void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) |
| | | { |
| | | u8 *blk_bits = yaffs_block_bits(dev, blk); |
| | | |
| | | yaffs_verify_chunk_bit_id(dev, blk, chunk); |
| | | blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); |
| | | } |
| | | |
| | | void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) |
| | | { |
| | | u8 *blk_bits = yaffs_block_bits(dev, blk); |
| | | |
| | | yaffs_verify_chunk_bit_id(dev, blk, chunk); |
| | | blk_bits[chunk / 8] |= (1 << (chunk & 7)); |
| | | } |
| | | |
| | | int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) |
| | | { |
| | | u8 *blk_bits = yaffs_block_bits(dev, blk); |
| | | |
| | | yaffs_verify_chunk_bit_id(dev, blk, chunk); |
| | | return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; |
| | | } |
| | | |
| | | int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) |
| | | { |
| | | u8 *blk_bits = yaffs_block_bits(dev, blk); |
| | | int i; |
| | | |
| | | for (i = 0; i < dev->chunk_bit_stride; i++) { |
| | | if (*blk_bits) |
| | | return 1; |
| | | blk_bits++; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) |
| | | { |
| | | u8 *blk_bits = yaffs_block_bits(dev, blk); |
| | | int i; |
| | | int n = 0; |
| | | |
| | | for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) |
| | | n += hweight8(*blk_bits); |
| | | |
| | | return n; |
| | | } |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | /* |
| | | * Chunk bitmap manipulations |
| | | */ |
| | | |
| | | #ifndef __YAFFS_BITMAP_H__ |
| | | #define __YAFFS_BITMAP_H__ |
| | | |
| | | #include "yaffs_guts.h" |
| | | |
| | | void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); |
| | | void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); |
| | | void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); |
| | | void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); |
| | | int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); |
| | | int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); |
| | | int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * 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. |
| | | */ |
| | | |
| | | #include "yaffs_checkptrw.h" |
| | | #include "yaffs_getblockinfo.h" |
| | | |
| | | struct yaffs_checkpt_chunk_hdr { |
| | | int version; |
| | | int seq; |
| | | u32 sum; |
| | | u32 xor; |
| | | } ; |
| | | |
| | | |
| | | static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) |
| | | { |
| | | return chunk - dev->chunk_offset; |
| | | } |
| | | |
| | | static int apply_block_offset(struct yaffs_dev *dev, int block) |
| | | { |
| | | return block - dev->block_offset; |
| | | } |
| | | |
| | | static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_checkpt_chunk_hdr hdr; |
| | | |
| | | hdr.version = YAFFS_CHECKPOINT_VERSION; |
| | | hdr.seq = dev->checkpt_page_seq; |
| | | hdr.sum = dev->checkpt_sum; |
| | | hdr.xor = dev->checkpt_xor; |
| | | |
| | | dev->checkpt_byte_offs = sizeof(hdr); |
| | | |
| | | memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); |
| | | } |
| | | |
| | | static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) |
| | | { |
| | | struct yaffs_checkpt_chunk_hdr hdr; |
| | | |
| | | memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); |
| | | |
| | | dev->checkpt_byte_offs = sizeof(hdr); |
| | | |
| | | return hdr.version == YAFFS_CHECKPOINT_VERSION && |
| | | hdr.seq == dev->checkpt_page_seq && |
| | | hdr.sum == dev->checkpt_sum && |
| | | hdr.xor == dev->checkpt_xor; |
| | | } |
| | | |
| | | static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) |
| | | { |
| | | int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "checkpt blocks_avail = %d", blocks_avail); |
| | | |
| | | return (blocks_avail <= 0) ? 0 : 1; |
| | | } |
| | | |
| | | static int yaffs_checkpt_erase(struct yaffs_dev *dev) |
| | | { |
| | | int i; |
| | | |
| | | if (!dev->param.erase_fn) |
| | | return 0; |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "checking blocks %d to %d", |
| | | dev->internal_start_block, dev->internal_end_block); |
| | | |
| | | for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { |
| | | struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); |
| | | int offset_i = apply_block_offset(dev, i); |
| | | int result; |
| | | |
| | | if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "erasing checkpt block %d", i); |
| | | |
| | | dev->n_erasures++; |
| | | |
| | | result = dev->param.erase_fn(dev, offset_i); |
| | | if(result) { |
| | | bi->block_state = YAFFS_BLOCK_STATE_EMPTY; |
| | | dev->n_erased_blocks++; |
| | | dev->n_free_chunks += |
| | | dev->param.chunks_per_block; |
| | | } else { |
| | | dev->param.bad_block_fn(dev, offset_i); |
| | | bi->block_state = YAFFS_BLOCK_STATE_DEAD; |
| | | } |
| | | } |
| | | } |
| | | |
| | | dev->blocks_in_checkpt = 0; |
| | | |
| | | return 1; |
| | | } |
| | | |
| | | static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) |
| | | { |
| | | int i; |
| | | int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "allocating checkpt block: erased %d reserved %d avail %d next %d ", |
| | | dev->n_erased_blocks, dev->param.n_reserved_blocks, |
| | | blocks_avail, dev->checkpt_next_block); |
| | | |
| | | if (dev->checkpt_next_block >= 0 && |
| | | dev->checkpt_next_block <= dev->internal_end_block && |
| | | blocks_avail > 0) { |
| | | |
| | | for (i = dev->checkpt_next_block; i <= dev->internal_end_block; |
| | | i++) { |
| | | struct yaffs_block_info *bi; |
| | | |
| | | bi = yaffs_get_block_info(dev, i); |
| | | if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { |
| | | dev->checkpt_next_block = i + 1; |
| | | dev->checkpt_cur_block = i; |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "allocating checkpt block %d", i); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); |
| | | |
| | | dev->checkpt_next_block = -1; |
| | | dev->checkpt_cur_block = -1; |
| | | } |
| | | |
| | | static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) |
| | | { |
| | | int i; |
| | | struct yaffs_ext_tags tags; |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "find next checkpt block: start: blocks %d next %d", |
| | | dev->blocks_in_checkpt, dev->checkpt_next_block); |
| | | |
| | | if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) |
| | | for (i = dev->checkpt_next_block; i <= dev->internal_end_block; |
| | | i++) { |
| | | int chunk = i * dev->param.chunks_per_block; |
| | | enum yaffs_block_state state; |
| | | u32 seq; |
| | | |
| | | dev->param.read_chunk_tags_fn(dev, |
| | | apply_chunk_offset(dev, chunk), |
| | | NULL, &tags); |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", |
| | | i, (int) state, |
| | | tags.obj_id, tags.seq_number, |
| | | tags.ecc_result); |
| | | |
| | | if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) |
| | | continue; |
| | | |
| | | dev->param.query_block_fn(dev, |
| | | apply_block_offset(dev, i), |
| | | &state, &seq); |
| | | if (state == YAFFS_BLOCK_STATE_DEAD) |
| | | continue; |
| | | |
| | | /* Right kind of block */ |
| | | dev->checkpt_next_block = tags.obj_id; |
| | | dev->checkpt_cur_block = i; |
| | | dev->checkpt_block_list[dev->blocks_in_checkpt] = i; |
| | | dev->blocks_in_checkpt++; |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "found checkpt block %d", i); |
| | | return; |
| | | } |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); |
| | | |
| | | dev->checkpt_next_block = -1; |
| | | dev->checkpt_cur_block = -1; |
| | | } |
| | | |
| | | int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) |
| | | { |
| | | int i; |
| | | |
| | | dev->checkpt_open_write = writing; |
| | | |
| | | /* Got the functions we need? */ |
| | | if (!dev->param.write_chunk_tags_fn || |
| | | !dev->param.read_chunk_tags_fn || |
| | | !dev->param.erase_fn || !dev->param.bad_block_fn) |
| | | return 0; |
| | | |
| | | if (writing && !yaffs2_checkpt_space_ok(dev)) |
| | | return 0; |
| | | |
| | | if (!dev->checkpt_buffer) |
| | | dev->checkpt_buffer = |
| | | kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); |
| | | if (!dev->checkpt_buffer) |
| | | return 0; |
| | | |
| | | dev->checkpt_page_seq = 0; |
| | | dev->checkpt_byte_count = 0; |
| | | dev->checkpt_sum = 0; |
| | | dev->checkpt_xor = 0; |
| | | dev->checkpt_cur_block = -1; |
| | | dev->checkpt_cur_chunk = -1; |
| | | dev->checkpt_next_block = dev->internal_start_block; |
| | | |
| | | if (writing) { |
| | | memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); |
| | | yaffs2_checkpt_init_chunk_hdr(dev); |
| | | return yaffs_checkpt_erase(dev); |
| | | } |
| | | |
| | | /* Opening for a read */ |
| | | /* Set to a value that will kick off a read */ |
| | | dev->checkpt_byte_offs = dev->data_bytes_per_chunk; |
| | | /* A checkpoint block list of 1 checkpoint block per 16 block is |
| | | * (hopefully) going to be way more than we need */ |
| | | dev->blocks_in_checkpt = 0; |
| | | dev->checkpt_max_blocks = |
| | | (dev->internal_end_block - dev->internal_start_block) / 16 + 2; |
| | | dev->checkpt_block_list = |
| | | kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); |
| | | |
| | | if (!dev->checkpt_block_list) |
| | | return 0; |
| | | |
| | | for (i = 0; i < dev->checkpt_max_blocks; i++) |
| | | dev->checkpt_block_list[i] = -1; |
| | | |
| | | return 1; |
| | | } |
| | | |
| | | int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) |
| | | { |
| | | u32 composite_sum; |
| | | |
| | | composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff); |
| | | *sum = composite_sum; |
| | | return 1; |
| | | } |
| | | |
| | | static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) |
| | | { |
| | | int chunk; |
| | | int offset_chunk; |
| | | struct yaffs_ext_tags tags; |
| | | |
| | | if (dev->checkpt_cur_block < 0) { |
| | | yaffs2_checkpt_find_erased_block(dev); |
| | | dev->checkpt_cur_chunk = 0; |
| | | } |
| | | |
| | | if (dev->checkpt_cur_block < 0) |
| | | return 0; |
| | | |
| | | tags.is_deleted = 0; |
| | | tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ |
| | | tags.chunk_id = dev->checkpt_page_seq + 1; |
| | | tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; |
| | | tags.n_bytes = dev->data_bytes_per_chunk; |
| | | if (dev->checkpt_cur_chunk == 0) { |
| | | /* First chunk we write for the block? Set block state to |
| | | checkpoint */ |
| | | struct yaffs_block_info *bi = |
| | | yaffs_get_block_info(dev, dev->checkpt_cur_block); |
| | | bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; |
| | | dev->blocks_in_checkpt++; |
| | | } |
| | | |
| | | chunk = |
| | | dev->checkpt_cur_block * dev->param.chunks_per_block + |
| | | dev->checkpt_cur_chunk; |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", |
| | | chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, |
| | | tags.obj_id, tags.chunk_id); |
| | | |
| | | offset_chunk = apply_chunk_offset(dev, chunk); |
| | | |
| | | dev->n_page_writes++; |
| | | |
| | | dev->param.write_chunk_tags_fn(dev, offset_chunk, |
| | | dev->checkpt_buffer, &tags); |
| | | dev->checkpt_page_seq++; |
| | | dev->checkpt_cur_chunk++; |
| | | if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { |
| | | dev->checkpt_cur_chunk = 0; |
| | | dev->checkpt_cur_block = -1; |
| | | } |
| | | memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); |
| | | |
| | | yaffs2_checkpt_init_chunk_hdr(dev); |
| | | |
| | | |
| | | return 1; |
| | | } |
| | | |
| | | int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) |
| | | { |
| | | int i = 0; |
| | | int ok = 1; |
| | | u8 *data_bytes = (u8 *) data; |
| | | |
| | | if (!dev->checkpt_buffer) |
| | | return 0; |
| | | |
| | | if (!dev->checkpt_open_write) |
| | | return -1; |
| | | |
| | | while (i < n_bytes && ok) { |
| | | dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; |
| | | dev->checkpt_sum += *data_bytes; |
| | | dev->checkpt_xor ^= *data_bytes; |
| | | |
| | | dev->checkpt_byte_offs++; |
| | | i++; |
| | | data_bytes++; |
| | | dev->checkpt_byte_count++; |
| | | |
| | | if (dev->checkpt_byte_offs < 0 || |
| | | dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) |
| | | ok = yaffs2_checkpt_flush_buffer(dev); |
| | | } |
| | | |
| | | return i; |
| | | } |
| | | |
| | | int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) |
| | | { |
| | | int i = 0; |
| | | int ok = 1; |
| | | struct yaffs_ext_tags tags; |
| | | int chunk; |
| | | int offset_chunk; |
| | | u8 *data_bytes = (u8 *) data; |
| | | |
| | | if (!dev->checkpt_buffer) |
| | | return 0; |
| | | |
| | | if (dev->checkpt_open_write) |
| | | return -1; |
| | | |
| | | while (i < n_bytes && ok) { |
| | | |
| | | if (dev->checkpt_byte_offs < 0 || |
| | | dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { |
| | | |
| | | if (dev->checkpt_cur_block < 0) { |
| | | yaffs2_checkpt_find_block(dev); |
| | | dev->checkpt_cur_chunk = 0; |
| | | } |
| | | |
| | | if (dev->checkpt_cur_block < 0) { |
| | | ok = 0; |
| | | break; |
| | | } |
| | | |
| | | chunk = dev->checkpt_cur_block * |
| | | dev->param.chunks_per_block + |
| | | dev->checkpt_cur_chunk; |
| | | |
| | | offset_chunk = apply_chunk_offset(dev, chunk); |
| | | dev->n_page_reads++; |
| | | |
| | | /* read in the next chunk */ |
| | | dev->param.read_chunk_tags_fn(dev, |
| | | offset_chunk, |
| | | dev->checkpt_buffer, |
| | | &tags); |
| | | |
| | | if (tags.chunk_id != (dev->checkpt_page_seq + 1) || |
| | | tags.ecc_result > YAFFS_ECC_RESULT_FIXED || |
| | | tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) { |
| | | ok = 0; |
| | | break; |
| | | } |
| | | if(!yaffs2_checkpt_check_chunk_hdr(dev)) { |
| | | ok = 0; |
| | | break; |
| | | } |
| | | |
| | | dev->checkpt_page_seq++; |
| | | dev->checkpt_cur_chunk++; |
| | | |
| | | if (dev->checkpt_cur_chunk >= |
| | | dev->param.chunks_per_block) |
| | | dev->checkpt_cur_block = -1; |
| | | |
| | | } |
| | | |
| | | *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; |
| | | dev->checkpt_sum += *data_bytes; |
| | | dev->checkpt_xor ^= *data_bytes; |
| | | dev->checkpt_byte_offs++; |
| | | i++; |
| | | data_bytes++; |
| | | dev->checkpt_byte_count++; |
| | | } |
| | | |
| | | return i; |
| | | } |
| | | |
| | | int yaffs_checkpt_close(struct yaffs_dev *dev) |
| | | { |
| | | int i; |
| | | |
| | | if (dev->checkpt_open_write) { |
| | | if (dev->checkpt_byte_offs != |
| | | sizeof(sizeof(struct yaffs_checkpt_chunk_hdr))) |
| | | yaffs2_checkpt_flush_buffer(dev); |
| | | } else if (dev->checkpt_block_list) { |
| | | for (i = 0; |
| | | i < dev->blocks_in_checkpt && |
| | | dev->checkpt_block_list[i] >= 0; i++) { |
| | | int blk = dev->checkpt_block_list[i]; |
| | | struct yaffs_block_info *bi = NULL; |
| | | |
| | | if (dev->internal_start_block <= blk && |
| | | blk <= dev->internal_end_block) |
| | | bi = yaffs_get_block_info(dev, blk); |
| | | if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) |
| | | bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; |
| | | } |
| | | kfree(dev->checkpt_block_list); |
| | | dev->checkpt_block_list = NULL; |
| | | } |
| | | |
| | | dev->n_free_chunks -= |
| | | dev->blocks_in_checkpt * dev->param.chunks_per_block; |
| | | dev->n_erased_blocks -= dev->blocks_in_checkpt; |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d", |
| | | dev->checkpt_byte_count); |
| | | |
| | | if (dev->checkpt_buffer) { |
| | | /* free the buffer */ |
| | | kfree(dev->checkpt_buffer); |
| | | dev->checkpt_buffer = NULL; |
| | | return 1; |
| | | } else { |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) |
| | | { |
| | | /* Erase the checkpoint data */ |
| | | |
| | | yaffs_trace(YAFFS_TRACE_CHECKPOINT, |
| | | "checkpoint invalidate of %d blocks", |
| | | dev->blocks_in_checkpt); |
| | | |
| | | return yaffs_checkpt_erase(dev); |
| | | } |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_CHECKPTRW_H__ |
| | | #define __YAFFS_CHECKPTRW_H__ |
| | | |
| | | #include "yaffs_guts.h" |
| | | |
| | | int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); |
| | | |
| | | int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); |
| | | |
| | | int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); |
| | | |
| | | int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); |
| | | |
| | | int yaffs_checkpt_close(struct yaffs_dev *dev); |
| | | |
| | | int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * 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. |
| | | */ |
| | | |
| | | /* |
| | | * This code implements the ECC algorithm used in SmartMedia. |
| | | * |
| | | * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. |
| | | * The two unused bit are set to 1. |
| | | * The ECC can correct single bit errors in a 256-byte page of data. Thus, two |
| | | * such ECC blocks are used on a 512-byte NAND page. |
| | | * |
| | | */ |
| | | |
| | | #include "yportenv.h" |
| | | |
| | | #include "yaffs_ecc.h" |
| | | |
| | | /* Table generated by gen-ecc.c |
| | | * Using a table means we do not have to calculate p1..p4 and p1'..p4' |
| | | * for each byte of data. These are instead provided in a table in bits7..2. |
| | | * Bit 0 of each entry indicates whether the entry has an odd or even parity, |
| | | * and therefore this bytes influence on the line parity. |
| | | */ |
| | | |
| | | static const unsigned char column_parity_table[] = { |
| | | 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, |
| | | 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, |
| | | 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, |
| | | 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, |
| | | 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, |
| | | 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, |
| | | 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, |
| | | 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, |
| | | 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, |
| | | 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, |
| | | 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, |
| | | 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, |
| | | 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, |
| | | 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, |
| | | 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, |
| | | 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, |
| | | 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, |
| | | 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, |
| | | 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, |
| | | 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, |
| | | 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, |
| | | 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, |
| | | 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, |
| | | 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, |
| | | 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, |
| | | 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, |
| | | 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, |
| | | 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, |
| | | 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, |
| | | 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, |
| | | 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, |
| | | 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, |
| | | }; |
| | | |
| | | |
| | | /* Calculate the ECC for a 256-byte block of data */ |
| | | void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc) |
| | | { |
| | | unsigned int i; |
| | | unsigned char col_parity = 0; |
| | | unsigned char line_parity = 0; |
| | | unsigned char line_parity_prime = 0; |
| | | unsigned char t; |
| | | unsigned char b; |
| | | |
| | | for (i = 0; i < 256; i++) { |
| | | b = column_parity_table[*data++]; |
| | | col_parity ^= b; |
| | | |
| | | if (b & 0x01) { /* odd number of bits in the byte */ |
| | | line_parity ^= i; |
| | | line_parity_prime ^= ~i; |
| | | } |
| | | } |
| | | |
| | | ecc[2] = (~col_parity) | 0x03; |
| | | |
| | | t = 0; |
| | | if (line_parity & 0x80) |
| | | t |= 0x80; |
| | | if (line_parity_prime & 0x80) |
| | | t |= 0x40; |
| | | if (line_parity & 0x40) |
| | | t |= 0x20; |
| | | if (line_parity_prime & 0x40) |
| | | t |= 0x10; |
| | | if (line_parity & 0x20) |
| | | t |= 0x08; |
| | | if (line_parity_prime & 0x20) |
| | | t |= 0x04; |
| | | if (line_parity & 0x10) |
| | | t |= 0x02; |
| | | if (line_parity_prime & 0x10) |
| | | t |= 0x01; |
| | | ecc[1] = ~t; |
| | | |
| | | t = 0; |
| | | if (line_parity & 0x08) |
| | | t |= 0x80; |
| | | if (line_parity_prime & 0x08) |
| | | t |= 0x40; |
| | | if (line_parity & 0x04) |
| | | t |= 0x20; |
| | | if (line_parity_prime & 0x04) |
| | | t |= 0x10; |
| | | if (line_parity & 0x02) |
| | | t |= 0x08; |
| | | if (line_parity_prime & 0x02) |
| | | t |= 0x04; |
| | | if (line_parity & 0x01) |
| | | t |= 0x02; |
| | | if (line_parity_prime & 0x01) |
| | | t |= 0x01; |
| | | ecc[0] = ~t; |
| | | |
| | | } |
| | | |
| | | /* Correct the ECC on a 256 byte block of data */ |
| | | |
| | | int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, |
| | | const unsigned char *test_ecc) |
| | | { |
| | | unsigned char d0, d1, d2; /* deltas */ |
| | | |
| | | d0 = read_ecc[0] ^ test_ecc[0]; |
| | | d1 = read_ecc[1] ^ test_ecc[1]; |
| | | d2 = read_ecc[2] ^ test_ecc[2]; |
| | | |
| | | if ((d0 | d1 | d2) == 0) |
| | | return 0; /* no error */ |
| | | |
| | | if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && |
| | | ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && |
| | | ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { |
| | | /* Single bit (recoverable) error in data */ |
| | | |
| | | unsigned byte; |
| | | unsigned bit; |
| | | |
| | | bit = byte = 0; |
| | | |
| | | if (d1 & 0x80) |
| | | byte |= 0x80; |
| | | if (d1 & 0x20) |
| | | byte |= 0x40; |
| | | if (d1 & 0x08) |
| | | byte |= 0x20; |
| | | if (d1 & 0x02) |
| | | byte |= 0x10; |
| | | if (d0 & 0x80) |
| | | byte |= 0x08; |
| | | if (d0 & 0x20) |
| | | byte |= 0x04; |
| | | if (d0 & 0x08) |
| | | byte |= 0x02; |
| | | if (d0 & 0x02) |
| | | byte |= 0x01; |
| | | |
| | | if (d2 & 0x80) |
| | | bit |= 0x04; |
| | | if (d2 & 0x20) |
| | | bit |= 0x02; |
| | | if (d2 & 0x08) |
| | | bit |= 0x01; |
| | | |
| | | data[byte] ^= (1 << bit); |
| | | |
| | | return 1; /* Corrected the error */ |
| | | } |
| | | |
| | | if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { |
| | | /* Reccoverable error in ecc */ |
| | | |
| | | read_ecc[0] = test_ecc[0]; |
| | | read_ecc[1] = test_ecc[1]; |
| | | read_ecc[2] = test_ecc[2]; |
| | | |
| | | return 1; /* Corrected the error */ |
| | | } |
| | | |
| | | /* Unrecoverable error */ |
| | | |
| | | return -1; |
| | | |
| | | } |
| | | |
| | | /* |
| | | * ECCxxxOther does ECC calcs on arbitrary n bytes of data |
| | | */ |
| | | void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, |
| | | struct yaffs_ecc_other *ecc_other) |
| | | { |
| | | unsigned int i; |
| | | unsigned char col_parity = 0; |
| | | unsigned line_parity = 0; |
| | | unsigned line_parity_prime = 0; |
| | | unsigned char b; |
| | | |
| | | for (i = 0; i < n_bytes; i++) { |
| | | b = column_parity_table[*data++]; |
| | | col_parity ^= b; |
| | | |
| | | if (b & 0x01) { |
| | | /* odd number of bits in the byte */ |
| | | line_parity ^= i; |
| | | line_parity_prime ^= ~i; |
| | | } |
| | | |
| | | } |
| | | |
| | | ecc_other->col_parity = (col_parity >> 2) & 0x3f; |
| | | ecc_other->line_parity = line_parity; |
| | | ecc_other->line_parity_prime = line_parity_prime; |
| | | } |
| | | |
| | | int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, |
| | | struct yaffs_ecc_other *read_ecc, |
| | | const struct yaffs_ecc_other *test_ecc) |
| | | { |
| | | unsigned char delta_col; /* column parity delta */ |
| | | unsigned delta_line; /* line parity delta */ |
| | | unsigned delta_line_prime; /* line parity delta */ |
| | | unsigned bit; |
| | | |
| | | delta_col = read_ecc->col_parity ^ test_ecc->col_parity; |
| | | delta_line = read_ecc->line_parity ^ test_ecc->line_parity; |
| | | delta_line_prime = |
| | | read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; |
| | | |
| | | if ((delta_col | delta_line | delta_line_prime) == 0) |
| | | return 0; /* no error */ |
| | | |
| | | if (delta_line == ~delta_line_prime && |
| | | (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { |
| | | /* Single bit (recoverable) error in data */ |
| | | |
| | | bit = 0; |
| | | |
| | | if (delta_col & 0x20) |
| | | bit |= 0x04; |
| | | if (delta_col & 0x08) |
| | | bit |= 0x02; |
| | | if (delta_col & 0x02) |
| | | bit |= 0x01; |
| | | |
| | | if (delta_line >= n_bytes) |
| | | return -1; |
| | | |
| | | data[delta_line] ^= (1 << bit); |
| | | |
| | | return 1; /* corrected */ |
| | | } |
| | | |
| | | if ((hweight32(delta_line) + |
| | | hweight32(delta_line_prime) + |
| | | hweight8(delta_col)) == 1) { |
| | | /* Reccoverable error in ecc */ |
| | | |
| | | *read_ecc = *test_ecc; |
| | | return 1; /* corrected */ |
| | | } |
| | | |
| | | /* Unrecoverable error */ |
| | | |
| | | return -1; |
| | | } |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | /* |
| | | * This code implements the ECC algorithm used in SmartMedia. |
| | | * |
| | | * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. |
| | | * The two unused bit are set to 1. |
| | | * The ECC can correct single bit errors in a 256-byte page of data. |
| | | * Thus, two such ECC blocks are used on a 512-byte NAND page. |
| | | * |
| | | */ |
| | | |
| | | #ifndef __YAFFS_ECC_H__ |
| | | #define __YAFFS_ECC_H__ |
| | | |
| | | struct yaffs_ecc_other { |
| | | unsigned char col_parity; |
| | | unsigned line_parity; |
| | | unsigned line_parity_prime; |
| | | }; |
| | | |
| | | void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc); |
| | | int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, |
| | | const unsigned char *test_ecc); |
| | | |
| | | void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, |
| | | struct yaffs_ecc_other *ecc); |
| | | int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, |
| | | struct yaffs_ecc_other *read_ecc, |
| | | const struct yaffs_ecc_other *test_ecc); |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another FFS. A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Timothy Manning <timothy@yaffs.net> |
| | | * |
| | | * 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. |
| | | */ |
| | | |
| | | #include "yaffsfs.h" |
| | | |
| | | struct error_entry { |
| | | int code; |
| | | const char *text; |
| | | }; |
| | | |
| | | static const struct error_entry error_list[] = { |
| | | { ENOMEM , "ENOMEM" }, |
| | | { EBUSY , "EBUSY"}, |
| | | { ENODEV , "ENODEV"}, |
| | | { EINVAL , "EINVAL"}, |
| | | { EBADF , "EBADF"}, |
| | | { EACCES , "EACCES"}, |
| | | { EXDEV , "EXDEV" }, |
| | | { ENOENT , "ENOENT"}, |
| | | { ENOSPC , "ENOSPC"}, |
| | | { ERANGE , "ERANGE"}, |
| | | { ENODATA, "ENODATA"}, |
| | | { ENOTEMPTY, "ENOTEMPTY"}, |
| | | { ENAMETOOLONG, "ENAMETOOLONG"}, |
| | | { ENOMEM , "ENOMEM"}, |
| | | { EEXIST , "EEXIST"}, |
| | | { ENOTDIR , "ENOTDIR"}, |
| | | { EISDIR , "EISDIR"}, |
| | | { ENFILE, "ENFILE"}, |
| | | { EROFS, "EROFS"}, |
| | | { EFAULT, "EFAULT"}, |
| | | { 0, NULL } |
| | | }; |
| | | |
| | | const char *yaffs_error_to_str(int err) |
| | | { |
| | | const struct error_entry *e = error_list; |
| | | |
| | | if (err < 0) |
| | | err = -err; |
| | | |
| | | while (e->code && e->text) { |
| | | if (err == e->code) |
| | | return e->text; |
| | | e++; |
| | | } |
| | | return "Unknown error code"; |
| | | } |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_FLASH_H__ |
| | | #define __YAFFS_FLASH_H__ |
| | | |
| | | |
| | | #include "yaffs_guts.h" |
| | | int yflash_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber); |
| | | int yflash_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | const u8 *data, const struct yaffs_spare *spare); |
| | | int yflash_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | const u8 *data, const struct yaffs_ext_tags *tags); |
| | | int yflash_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | u8 *data, struct yaffs_spare *spare); |
| | | int yflash_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | u8 *data, struct yaffs_ext_tags *tags); |
| | | int yflash_InitialiseNAND(struct yaffs_dev *dev); |
| | | int yflash_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no); |
| | | int yflash_QueryNANDBlock(struct yaffs_dev *dev, int block_no, |
| | | enum yaffs_block_state *state, u32 *seq_number); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_FLASH2_H__ |
| | | #define __YAFFS_FLASH2_H__ |
| | | |
| | | |
| | | #include "yaffs_guts.h" |
| | | int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber); |
| | | int yflash2_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | const u8 *data, const struct yaffs_spare *spare); |
| | | int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | const u8 *data, const struct yaffs_ext_tags *tags); |
| | | int yflash2_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | u8 *data, struct yaffs_spare *spare); |
| | | int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk, |
| | | u8 *data, struct yaffs_ext_tags *tags); |
| | | int yflash2_InitialiseNAND(struct yaffs_dev *dev); |
| | | int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no); |
| | | int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no, |
| | | enum yaffs_block_state *state, u32 *seq_number); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_GETBLOCKINFO_H__ |
| | | #define __YAFFS_GETBLOCKINFO_H__ |
| | | |
| | | #include "yaffs_guts.h" |
| | | #include "yaffs_trace.h" |
| | | |
| | | /* Function to manipulate block info */ |
| | | static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev |
| | | *dev, int blk) |
| | | { |
| | | if (blk < dev->internal_start_block || blk > dev->internal_end_block) { |
| | | yaffs_trace(YAFFS_TRACE_ERROR, |
| | | "**>> yaffs: get_block_info block %d is not valid", |
| | | blk); |
| | | BUG(); |
| | | } |
| | | return &dev->block_info[blk - dev->internal_start_block]; |
| | | } |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| | | * |
| | | * Copyright (C) 2002-2011 Aleph One Ltd. |
| | | * for Toby Churchill Ltd and Brightstar Engineering |
| | | * |
| | | * Created by Charles Manning <charles@aleph1.co.uk> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License version 2.1 as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| | | */ |
| | | |
| | | #ifndef __YAFFS_GUTS_H__ |
| | | #define __YAFFS_GUTS_H__ |
| | | |
| | | #include "yportenv.h" |
| | | |
| | | #define YAFFS_OK 1 |
| | | #define YAFFS_FAIL 0 |
| | | |
| | | /* Give us a Y=0x59, |
| | | * Give us an A=0x41, |
| | | * Give us an FF=0xff |
| | | * Give us an S=0x53 |
| | | * And what have we got... |
| | | */ |
| | | #define YAFFS_MAGIC 0x5941ff53 |
| | | |
| | | /* |
| | | * Tnodes form a tree with the tnodes in "levels" |
| | | * Levels greater than 0 hold 8 slots which point to other tnodes. |
| | | * Those at level 0 hold 16 slots which point to chunks in NAND. |
| | | * |
| | | * A maximum level of 8 thust supports files of size up to: |
| | | * |
| | | * 2^(3*MAX_LEVEL+4) |
| | | * |
| | | * Thus a max level of 8 supports files with up to 2^^28 chunks which gives |
| | | * a maximum file size of arounf 51Gbytees with 2k chunks. |
| | | */ |
| | | #define YAFFS_NTNODES_LEVEL0 16 |
| | | #define YAFFS_TNODES_LEVEL0_BITS 4 |
| | | #define YAFFS_TNODES_LEVEL0_MASK 0xf |
| | | |
| | | #define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) |
| | | #define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) |
| | | #define YAFFS_TNODES_INTERNAL_MASK 0x7 |
| | | #define YAFFS_TNODES_MAX_LEVEL 8 |
| | | #define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \ |
| | | YAFFS_TNODES_INTERNAL_BITS * \ |
| | | YAFFS_TNODES_MAX_LEVEL) |
| | | #define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1) |
| | | |
| | | #define YAFFS_MAX_FILE_SIZE_32 0x7fffffff |
| | | |
| | | /* Constants for YAFFS1 mode */ |
| | | #define YAFFS_BYTES_PER_SPARE 16 |
| | | #define YAFFS_BYTES_PER_CHUNK 512 |
| | | #define YAFFS_CHUNK_SIZE_SHIFT 9 |
| | | #define YAFFS_CHUNKS_PER_BLOCK 32 |
| | | #define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) |
| | | |
| | | #define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 |
| | | #define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 |
| | | |
| | | |
| | | |
| | | #define YAFFS_ALLOCATION_NOBJECTS 100 |
| | | #define YAFFS_ALLOCATION_NTNODES 100 |
| | | #define YAFFS_ALLOCATION_NLINKS 100 |
| | | |
| | | #define YAFFS_NOBJECT_BUCKETS 256 |
| | | |
| | | #define YAFFS_OBJECT_SPACE 0x40000 |
| | | #define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1) |
| | | |
| | | /* Binary data version stamps */ |
| | | #define YAFFS_SUMMARY_VERSION 1 |
| | | #define YAFFS_CHECKPOINT_VERSION 7 |
| | | |
| | | #ifdef CONFIG_YAFFS_UNICODE |
| | | #define YAFFS_MAX_NAME_LENGTH 127 |
| | | #define YAFFS_MAX_ALIAS_LENGTH 79 |
| | | #else |
| | | #define YAFFS_MAX_NAME_LENGTH 255 |
| | | #define YAFFS_MAX_ALIAS_LENGTH 159 |
| | | #endif |
| | | |
| | | #define YAFFS_SHORT_NAME_LENGTH 15 |
| | | |
| | | /* Some special object ids for pseudo objects */ |
| | | #define YAFFS_OBJECTID_ROOT 1 |
| | | #define YAFFS_OBJECTID_LOSTNFOUND 2 |
| | | #define YAFFS_OBJECTID_UNLINKED 3 |
| | | #define YAFFS_OBJECTID_DELETED 4 |
| | | |
| | | /* Fake object Id for summary data */ |
| | | #define YAFFS_OBJECTID_SUMMARY 0x10 |
| | | |
| | | /* Pseudo object ids for checkpointing */ |
| | | #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 |
| | | #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 |
| | | |
| | | #define YAFFS_MAX_SHORT_OP_CACHES 20 |
| | | |
| | | #define YAFFS_N_TEMP_BUFFERS 6 |
| | | |
| | | /* We limit the number attempts at sucessfully saving a chunk of data. |
| | | * Small-page devices have 32 pages per block; large-page devices have 64. |
| | | * Default to something in the order of 5 to 10 blocks worth of chunks. |
| | | */ |
| | | #define YAFFS_WR_ATTEMPTS (5*64) |
| | | |
| | | /* Sequence numbers are used in YAFFS2 to determine block allocation order. |
| | | * The range is limited slightly to help distinguish bad numbers from good. |
| | | * This also allows us to perhaps in the future use special numbers for |
| | | * special purposes. |
| | | * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years, |
| | | * and is a larger number than the lifetime of a 2GB device. |
| | | */ |
| | | #define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 |
| | | #define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00 |
| | | |
| | | /* Special sequence number for bad block that failed to be marked bad */ |
| | | #define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000 |
| | | |
| | | /* ChunkCache is used for short read/write operations.*/ |
| | | struct yaffs_cache { |
| | | struct yaffs_obj *object; |
| | | int chunk_id; |
| | | int last_use; |
| | | int dirty; |
| | | int n_bytes; /* Only valid if the cache is dirty */ |
| | | int locked; /* Can't push out or flush while locked. */ |
| | | u8 *data; |
| | | }; |
| | | |
| | | /* yaffs1 tags structures in RAM |
| | | * NB This uses bitfield. Bitfields should not straddle a u32 boundary |
| | | * otherwise the structure size will get blown out. |
| | | */ |
| | | |
| | | struct yaffs_tags { |
| | | unsigned chunk_id:20; |
| | | unsigned serial_number:2; |
| | | unsigned n_bytes_lsb:10; |
| | | unsigned obj_id:18; |
| | | unsigned ecc:12; |
| | | unsigned n_bytes_msb:2; |
| | | }; |
| | | |
| | | union yaffs_tags_union { |
| | | struct yaffs_tags as_tags; |
| | | u8 as_bytes[8]; |
| | | }; |
| | | |
| | | |
| | | /* Stuff used for extended tags in YAFFS2 */ |
| | | |
| | | enum yaffs_ecc_result { |
| | | YAFFS_ECC_RESULT_UNKNOWN, |
| | | YAFFS_ECC_RESULT_NO_ERROR, |
| | | YAFFS_ECC_RESULT_FIXED, |
| | | YAFFS_ECC_RESULT_UNFIXED |
| | | }; |
| | | |
| | | enum yaffs_obj_type { |
| | | YAFFS_OBJECT_TYPE_UNKNOWN, |
| | | YAFFS_OBJECT_TYPE_FILE, |
| | | YAFFS_OBJECT_TYPE_SYMLINK, |
| | | YAFFS_OBJECT_TYPE_DIRECTORY, |
| | | YAFFS_OBJECT_TYPE_HARDLINK, |
| | | YAFFS_OBJECT_TYPE_SPECIAL |
| | | }; |
| | | |
| | | #define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL |
| | | |
| | | struct yaffs_ext_tags { |
| | | unsigned chunk_used; /* Status of the chunk: used or unused */ |
| | | unsigned obj_id; /* If 0 this is not used */ |
| | | unsigned chunk_id; /* If 0 this is a header, else a data chunk */ |
| | | unsigned n_bytes; /* Only valid for data chunks */ |
| | | |
| | | /* The following stuff only has meaning when we read */ |
| | | enum yaffs_ecc_result ecc_result; |
| | | unsigned block_bad; |
| | | |
| | | /* YAFFS 1 stuff */ |
| | | unsigned is_deleted; /* The chunk is marked deleted */ |
| | | unsigned serial_number; /* Yaffs1 2-bit serial number */ |
| | | |
| | | /* YAFFS2 stuff */ |
| | | unsigned seq_number; /* The sequence number of this block */ |
| | | |
| | | /* Extra info if this is an object header (YAFFS2 only) */ |
| | | |
| | | unsigned extra_available; /* Extra info available if not zero */ |
| | | unsigned extra_parent_id; /* The parent object */ |
| | | unsigned extra_is_shrink; /* Is it a shrink header? */ |
| | | unsigned extra_shadows; /* Does this shadow another object? */ |
| | | |
| | | enum yaffs_obj_type extra_obj_type; /* What object type? */ |
| | | |
| | | loff_t extra_file_size; /* Length if it is a file */ |
| | | unsigned extra_equiv_id; /* Equivalent object for a hard link */ |
| | | }; |
| | | |
| | | /* Spare structure for YAFFS1 */ |
| | | struct yaffs_spare { |
| | | u8 tb0; |
| | | u8 tb1; |
| | | u8 tb2; |
| | | u8 tb3; |
| | | u8 page_status; /* set to 0 to delete the chunk */ |
| | | u8 block_status; |
| | | u8 tb4; |
| | | u8 tb5; |
| | | u8 ecc1[3]; |
| | | u8 tb6; |
| | | u8 tb7; |
| | | u8 ecc2[3]; |
| | | }; |
| | | |
| | | /*Special structure for passing through to mtd */ |
| | | struct yaffs_nand_spare { |
| | | struct yaffs_spare spare; |
| | | int eccres1; |
| | | int eccres2; |
| | | }; |
| | | |
| | | /* Block data in RAM */ |
| | | |
| | | enum yaffs_block_state { |
| | | YAFFS_BLOCK_STATE_UNKNOWN = 0, |
| | | |
| | | YAFFS_BLOCK_STATE_SCANNING, |
| | | /* Being scanned */ |
| | | |
| | | YAFFS_BLOCK_STATE_NEEDS_SCAN, |
| | | /* The block might have something on it (ie it is allocating or full, |
| | | * perhaps empty) but it needs to be scanned to determine its true |
| | | * state. |
| | | * This state is only valid during scanning. |
| | | * NB We tolerate empty because the pre-scanner might be incapable of |
| | | * deciding |
| | | * However, if this state is returned on a YAFFS2 device, |
| | | * then we expect a sequence number |
| | | */ |
| | | |
| | | YAFFS_BLOCK_STATE_EMPTY, |
| | | /* This block is empty */ |
| | | |
| | | YAFFS_BLOCK_STATE_ALLOCATING, |
| | | /* This block is partially allocated. |
| | | * At least one page holds valid data. |
| | | * This is the one currently being used for page |
| | | * allocation. Should never be more than one of these. |
| | | * If a block is only partially allocated at mount it is treated as |
| | | * full. |
| | | */ |
| | | |
| | | YAFFS_BLOCK_STATE_FULL, |
| | | /* All the pages in this block have been allocated. |
| | | * If a block was only partially allocated when mounted we treat |
| | | * it as fully allocated. |
| | | */ |
| | | |
| | | YAFFS_BLOCK_STATE_DIRTY, |
| | | /* The block was full and now all chunks have been deleted. |
| | | * Erase me, reuse me. |
| | | */ |
| | | |
| | | YAFFS_BLOCK_STATE_CHECKPOINT, |
| | | /* This block is assigned to holding checkpoint data. */ |
| | | |
| | | YAFFS_BLOCK_STATE_COLLECTING, |
| | | /* This block is being garbage collected */ |
| | | |
| | | YAFFS_BLOCK_STATE_DEAD |
| | | /* This block has failed and is not in use */ |
| | | }; |
| | | |
| | | #define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) |
| | | |
| | | struct yaffs_block_info { |
| | | |
| | | int soft_del_pages:10; /* number of soft deleted pages */ |
| | | int pages_in_use:10; /* number of pages in use */ |
| | | unsigned block_state:4; /* One of the above block states. */ |
| | | /* NB use unsigned because enum is sometimes |
| | | * an int */ |
| | | u32 needs_retiring:1; /* Data has failed on this block, */ |
| | | /*need to get valid data off and retire*/ |
| | | u32 skip_erased_check:1;/* Skip the erased check on this block */ |
| | | u32 gc_prioritise:1; /* An ECC check or blank check has failed. |
| | | Block should be prioritised for GC */ |
| | | u32 chunk_error_strikes:3; /* How many times we've had ecc etc |
| | | failures on this block and tried to reuse it */ |
| | | u32 has_summary:1; /* The block has a summary */ |
| | | |
| | | u32 has_shrink_hdr:1; /* This block has at least one shrink header */ |
| | | u32 seq_number; /* block sequence number for yaffs2 */ |
| | | |
| | | }; |
| | | |
| | | /* -------------------------- Object structure -------------------------------*/ |
| | | /* This is the object structure as stored on NAND */ |
| | | |
| | | struct yaffs_obj_hdr { |
| | | enum yaffs_obj_type type; |
| | | |
| | | /* Apply to everything */ |
| | | int parent_obj_id; |
| | | u16 sum_no_longer_used; /* checksum of name. No longer used */ |
| | | YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; |
| | | |
| | | /* The following apply to all object types except for hard links */ |
| | | u32 yst_mode; /* protection */ |
| | | |
| | | u32 yst_uid; |
| | | u32 yst_gid; |
| | | u32 yst_atime; |
| | | u32 yst_mtime; |
| | | u32 yst_ctime; |
| | | |
| | | /* File size applies to files only */ |
| | | u32 file_size_low; |
| | | |
| | | /* Equivalent object id applies to hard links only. */ |
| | | int equiv_id; |
| | | |
| | | /* Alias is for symlinks only. */ |
| | | YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; |
| | | |
| | | u32 yst_rdev; /* stuff for block and char devices (major/min) */ |
| | | |
| | | u32 win_ctime[2]; |
| | | u32 win_atime[2]; |
| | | u32 win_mtime[2]; |
| | | |
| | | u32 inband_shadowed_obj_id; |
| | | u32 inband_is_shrink; |
| | | |
| | | u32 file_size_high; |
| | | u32 reserved[1]; |
| | | int shadows_obj; /* This object header shadows the |
| | | specified object if > 0 */ |
| | | |
| | | /* is_shrink applies to object headers written when wemake a hole. */ |
| | | u32 is_shrink; |
| | | |
| | | }; |
| | | |
| | | /*--------------------------- Tnode -------------------------- */ |
| | | |
| | | struct yaffs_tnode { |
| | | struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; |
| | | }; |
| | | |
| | | /*------------------------ Object -----------------------------*/ |
| | | /* An object can be one of: |
| | | * - a directory (no data, has children links |
| | | * - a regular file (data.... not prunes :->). |
| | | * - a symlink [symbolic link] (the alias). |
| | | * - a hard link |
| | | */ |
| | | |
| | | struct yaffs_file_var { |
| | | loff_t file_size; |
| | | loff_t scanned_size; |
| | | loff_t shrink_size; |
| | | int top_level; |
| | | struct yaffs_tnode *top; |
| | | }; |
| | | |
| | | struct yaffs_dir_var { |
| | | struct list_head children; /* list of child links */ |
| | | struct list_head dirty; /* Entry for list of dirty directories */ |
| | | }; |
| | | |
| | | struct yaffs_symlink_var { |
| | | YCHAR *alias; |
| | | }; |
| | | |
| | | struct yaffs_hardlink_var { |
| | | struct yaffs_obj *equiv_obj; |
| | | u32 equiv_id; |
| | | }; |
| | | |
| | | union yaffs_obj_var { |
| | | struct yaffs_file_var file_variant; |
| | | struct yaffs_dir_var dir_variant; |
| | | struct yaffs_symlink_var symlink_variant; |
| | | struct yaffs_hardlink_var hardlink_variant; |
| | | }; |
| | | |
| | | struct yaffs_obj { |
| | | u8 deleted:1; /* This should only apply to unlinked files. */ |
| | | u8 soft_del:1; /* it has also been soft deleted */ |
| | | u8 unlinked:1; /* An unlinked file.*/ |
| | | u8 fake:1; /* A fake object has no presence on NAND. */ |
| | | u8 rename_allowed:1; /* Some objects cannot be renamed. */ |
| | | u8 unlink_allowed:1; |
| | | u8 dirty:1; /* the object needs to be written to flash */ |
| | | u8 valid:1; /* When the file system is being loaded up, this |
| | | * object might be created before the data |
| | | * is available |
| | | * ie. file data chunks encountered before |
| | | * the header. |
| | | */ |
| | | u8 lazy_loaded:1; /* This object has been lazy loaded and |
| | | * is missing some detail */ |
| | | |
| | | u8 defered_free:1; /* Object is removed from NAND, but is |
| | | * still in the inode cache. |
| | | * Free of object is defered. |
| | | * until the inode is released. |
| | | */ |
| | | u8 being_created:1; /* This object is still being created |
| | | * so skip some verification checks. */ |
| | | u8 is_shadowed:1; /* This object is shadowed on the way |
| | | * to being renamed. */ |
| | | |
| | | u8 xattr_known:1; /* We know if this has object has xattribs |
| | | * or not. */ |
| | | u8 has_xattr:1; /* This object has xattribs. |
| | | * Only valid if xattr_known. */ |
| | | |
| | | u8 serial; /* serial number of chunk in NAND.*/ |
| | | u16 sum; /* sum of the name to speed searching */ |
| | | |
| | | struct yaffs_dev *my_dev; /* The device I'm on */ |
| | | |
| | | struct list_head hash_link; /* list of objects in hash bucket */ |
| | | |
| | | struct list_head hard_links; /* hard linked object chain*/ |
| | | |
| | | /* directory structure stuff */ |
| | | /* also used for linking up the free list */ |
| | | struct yaffs_obj *parent; |
| | | struct list_head siblings; |
| | | |
| | | /* Where's my object header in NAND? */ |
| | | int hdr_chunk; |
| | | |
| | | int n_data_chunks; /* Number of data chunks for this file. */ |
| | | |
| | | u32 obj_id; /* the object id value */ |
| | | |
| | | u32 yst_mode; |
| | | |
| | | YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; |
| | | |
| | | #ifdef CONFIG_YAFFS_WINCE |
| | | u32 win_ctime[2]; |
| | | u32 win_mtime[2]; |
| | | u32 win_atime[2]; |
| | | #else |
| | | u32 yst_uid; |
| | | u32 yst_gid; |
| | | u32 yst_atime; |
| | | u32 yst_mtime; |
| | | u32 yst_ctime; |
| | | #endif |
| | | |
| | | u32 yst_rdev; |
| | | |
| | | void *my_inode; |
| | | |
| | | enum yaffs_obj_type variant_type; |
| | | |
| | | union yaffs_obj_var variant; |
| | | |
| | | }; |
| | | |
| | | struct yaffs_obj_bucket { |
| | | struct list_head list; |
| | | int count; |
| | | }; |
| | | |
| | | /* yaffs_checkpt_obj holds the definition of an object as dumped |
| | | * by checkpointing. |
| | | */ |
| | | |
| | | struct yaffs_checkpt_obj { |
| | | int struct_type; |
| | | u32 obj_id; |
| | | u32 parent_id; |
| | | int hdr_chunk; |
| | | enum yaffs_obj_type variant_type:3; |
| | | u8 deleted:1; |
| | | u8 soft_del:1; |
| | | u8 unlinked:1; |
| | | u8 fake:1; |
| | | u8 rename_allowed:1; |
| | | u8 unlink_allowed:1; |
| | | u8 serial; |
| | | int n_data_chunks; |
| | | loff_t size_or_equiv_obj; |
| | | }; |
| | | |
| | | /*--------------------- Temporary buffers ---------------- |
| | | * |
| | | * These are chunk-sized working buffers. Each device has a few. |
| | | */ |
| | | |
| | | struct yaffs_buffer { |
| | | u8 *buffer; |
| | | int in_use; |
| | | }; |
| | | |
| | | /*----------------- Device ---------------------------------*/ |
| | | |
| | | struct yaffs_param { |
| | | const YCHAR *name; |
| | | |
| | | /* |
| | | * Entry parameters set up way early. Yaffs sets up the rest. |
| | | * The structure should be zeroed out before use so that unused |
| | | * and defualt values are zero. |
| | | */ |
| | | |
| | | int inband_tags; /* Use unband tags */ |
| | | u32 total_bytes_per_chunk; /* Should be >= 512, does not need to |
| | | be a power of 2 */ |
| | | int chunks_per_block; /* does not need to be a power of 2 */ |
| | | int spare_bytes_per_chunk; /* spare area size */ |
| | | int start_block; /* Start block we're allowed to use */ |
| | | int end_block; /* End block we're allowed to use */ |
| | | int n_reserved_blocks; /* Tuneable so that we can reduce |
| | | * reserved blocks on NOR and RAM. */ |
| | | |
| | | int n_caches; /* If <= 0, then short op caching is disabled, |
| | | * else the number of short op caches. |
| | | */ |
| | | int use_nand_ecc; /* Flag to decide whether or not to use |
| | | * NAND driver ECC on data (yaffs1) */ |
| | | int tags_9bytes; /* Use 9 byte tags */ |
| | | int no_tags_ecc; /* Flag to decide whether or not to do ECC |
| | | * on packed tags (yaffs2) */ |
| | | |
| | | int is_yaffs2; /* Use yaffs2 mode on this device */ |
| | | |
| | | int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ |
| | | |
| | | int refresh_period; /* How often to check for a block refresh */ |
| | | |
| | | /* Checkpoint control. Can be set before or after initialisation */ |
| | | u8 skip_checkpt_rd; |
| | | u8 skip_checkpt_wr; |
| | | |
| | | int enable_xattr; /* Enable xattribs */ |
| | | |
| | | /* NAND access functions (Must be set before calling YAFFS) */ |
| | | |
| | | int (*write_chunk_fn) (struct yaffs_dev *dev, |
| | | int nand_chunk, const u8 *data, |
| | | const struct yaffs_spare *spare); |
| | | int (*read_chunk_fn) (struct yaffs_dev *dev, |
| | | int nand_chunk, u8 *data, |
| | | struct yaffs_spare *spare); |
| | | int (*erase_fn) (struct yaffs_dev *dev, int flash_block); |
| | | int (*initialise_flash_fn) (struct yaffs_dev *dev); |
| | | int (*deinitialise_flash_fn) (struct yaffs_dev *dev); |
| | | |
| | | /* yaffs2 mode functions */ |
| | | int (*write_chunk_tags_fn) (struct yaffs_dev *dev, |
| | | int nand_chunk, const u8 *data, |
| | | const struct yaffs_ext_tags *tags); |
| | | int (*read_chunk_tags_fn) (struct yaffs_dev *dev, |
| | | int nand_chunk, u8 *data, |
| | | struct yaffs_ext_tags *tags); |
| | | int (*bad_block_fn) (struct yaffs_dev *dev, int block_no); |
| | | int (*query_block_fn) (struct yaffs_dev *dev, int block_no, |
| | | enum yaffs_block_state *state, |
| | | u32 *seq_number); |
| | | |
| | | /* The remove_obj_fn function must be supplied by OS flavours that |
| | | * need it. |
| | | * yaffs direct uses it to implement the faster readdir. |
| | | * Linux uses it to protect the directory during unlocking. |
| | | */ |
| | | void (*remove_obj_fn) (struct yaffs_obj *obj); |
| | | |
| | | /* Callback to mark the superblock dirty */ |
| | | void (*sb_dirty_fn) (struct yaffs_dev *dev); |
| | | |
| | | /* Callback to control garbage collection. */ |
| | | unsigned (*gc_control) (struct yaffs_dev *dev); |
| | | |
| | | /* Debug control flags. Don't use unless you know what you're doing */ |
| | | int use_header_file_size; /* Flag to determine if we should use |
| | | * file sizes from the header */ |
| | | int disable_lazy_load; /* Disable lazy loading on this device */ |
| | | int wide_tnodes_disabled; /* Set to disable wide tnodes */ |
| | | int disable_soft_del; /* yaffs 1 only: Set to disable the use of |
| | | * softdeletion. */ |
| | | |
| | | int defered_dir_update; /* Set to defer directory updates */ |
| | | |
| | | #ifdef CONFIG_YAFFS_AUTO_UNICODE |
| | | int auto_unicode; |
| | | #endif |
| | | int always_check_erased; /* Force chunk erased check always on */ |
| | | |
| | | int disable_summary; |
| | | |
| | | int max_objects; /* |
| | | * Set to limit the number of objects created. |
| | | * 0 = no limit. |
| | | */ |
| | | }; |
| | | |
| | | struct yaffs_dev { |
| | | struct yaffs_param param; |
| | | |
| | | /* Context storage. Holds extra OS specific data for this device */ |
| | | |
| | | void *os_context; |
| | | void *driver_context; |
| | | |
| | | struct list_head dev_list; |
| | | |
| | | /* Runtime parameters. Set up by YAFFS. */ |
| | | int data_bytes_per_chunk; |
| | | |
| | | /* Non-wide tnode stuff */ |
| | | u16 chunk_grp_bits; /* Number of bits that need to be resolved if |
| | | * the tnodes are not wide enough. |
| | | */ |
| | | u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ |
| | | |
| | | /* Stuff to support wide tnodes */ |
| | | u32 tnode_width; |
| | | u32 tnode_mask; |
| | | u32 tnode_size; |
| | | |
| | | /* Stuff for figuring out file offset to chunk conversions */ |
| | | u32 chunk_shift; /* Shift value */ |
| | | u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ |
| | | u32 chunk_mask; /* Mask to use for power-of-2 case */ |
| | | |
| | | int is_mounted; |
| | | int read_only; |
| | | int is_checkpointed; |
| | | |
| | | /* Stuff to support block offsetting to support start block zero */ |
| | | int internal_start_block; |
| | | int internal_end_block; |
| | | int block_offset; |
| | | int chunk_offset; |
| | | |
| | | /* Runtime checkpointing stuff */ |
| | | int checkpt_page_seq; /* running sequence number of checkpt pages */ |
| | | int checkpt_byte_count; |
| | | int checkpt_byte_offs; |
| | | u8 *checkpt_buffer; |
| | | int checkpt_open_write; |
| | | int blocks_in_checkpt; |
| | | int checkpt_cur_chunk; |
| | | int checkpt_cur_block; |
| | | int checkpt_next_block; |
| | | int *checkpt_block_list; |
| | | int checkpt_max_blocks; |
| | | u32 checkpt_sum; |
| | | u32 checkpt_xor; |
| | | |
| | | int checkpoint_blocks_required; /* Number of blocks needed to store |
| | | * current checkpoint set */ |
| | | |
| | | /* Block Info */ |
| | | struct yaffs_block_info *block_info; |
| | | u8 *chunk_bits; /* bitmap of chunks in use */ |
| | | unsigned block_info_alt:1; /* allocated using alternative alloc */ |
| | | unsigned chunk_bits_alt:1; /* allocated using alternative alloc */ |
| | | int chunk_bit_stride; /* Number of bytes of chunk_bits per block. |
| | | * Must be consistent with chunks_per_block. |
| | | */ |
| | | |
| | | int n_erased_blocks; |
| | | int alloc_block; /* Current block being allocated off */ |
| | | u32 alloc_page; |
| | | int alloc_block_finder; /* Used to search for next allocation block */ |
| | | |
| | | /* Object and Tnode memory management */ |
| | | void *allocator; |
| | | int n_obj; |
| | | int n_tnodes; |
| | | |
| | | int n_hardlinks; |
| | | |
| | | struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; |
| | | u32 bucket_finder; |
| | | |
| | | int n_free_chunks; |
| | | |
| | | /* Garbage collection control */ |
| | | u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ |
| | | u32 n_clean_ups; |
| | | |
| | | unsigned has_pending_prioritised_gc; /* We think this device might |
| | | have pending prioritised gcs */ |
| | | unsigned gc_disable; |
| | | unsigned gc_block_finder; |
| | | unsigned gc_dirtiest; |
| | | unsigned gc_pages_in_use; |
| | | unsigned gc_not_done; |
| | | unsigned gc_block; |
| | | unsigned gc_chunk; |
| | | unsigned gc_skip; |
| | | struct yaffs_summary_tags *gc_sum_tags; |
| | | |
| | | /* Special directories */ |
| | | struct yaffs_obj *root_dir; |
| | | struct yaffs_obj *lost_n_found; |
| | | |
| | | int buffered_block; /* Which block is buffered here? */ |
| | | int doing_buffered_block_rewrite; |
| | | |
| | | struct yaffs_cache *cache; |
| | | int cache_last_use; |
| | | |
| | | /* Stuff for background deletion and unlinked files. */ |
| | | struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted |
| | | files live. */ |
| | | struct yaffs_obj *del_dir; /* Directory where deleted objects are |
| | | sent to disappear. */ |
| | | struct yaffs_obj *unlinked_deletion; /* Current file being |
| | | background deleted. */ |
| | | int n_deleted_files; /* Count of files awaiting deletion; */ |
| | | int n_unlinked_files; /* Count of unlinked files. */ |
| | | int n_bg_deletions; /* Count of background deletions. */ |
| | | |
| | | /* Temporary buffer management */ |
| | | struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; |
| | | int max_temp; |
| | | int temp_in_use; |
| | | int unmanaged_buffer_allocs; |
| | | int unmanaged_buffer_deallocs; |
| | | |
| | | /* yaffs2 runtime stuff */ |
| | | unsigned seq_number; /* Sequence number of currently |
| | | allocating block */ |
| | | unsigned oldest_dirty_seq; |
| | | unsigned oldest_dirty_block; |
| | | |
| | | /* Block refreshing */ |
| | | int refresh_skip; /* A skip down counter. |
| | | * Refresh happens when this gets to zero. */ |
| | | |
| | | /* Dirty directory handling */ |
| | | struct list_head dirty_dirs; /* List of dirty directories */ |
| | | |
| | | /* Summary */ |
| | | int chunks_per_summary; |
| | | struct yaffs_summary_tags *sum_tags; |
| | | |
| | | /* Statistics */ |
| | | u32 n_page_writes; |
| | | u32 n_page_reads; |
| | | u32 n_erasures; |
| | | u32 n_erase_failures; |
| | | u32 n_gc_copies; |
| | | u32 all_gcs; |
| | | u32 passive_gc_count; |
| | | u32 oldest_dirty_gc_count; |
| | | u32 n_gc_blocks; |
| | | u32 bg_gcs; |
| | | u32 n_retried_writes; |
| | | u32 n_retired_blocks; |
| | | u32 n_ecc_fixed; |
| | | u32 n_ecc_unfixed; |
| | | u32 n_tags_ecc_fixed; |
| | | u32 n_tags_ecc_unfixed; |
| | | u32 n_deletions; |
| | | u32 n_unmarked_deletions; |
| | | u32 refresh_count; |
| | | u32 cache_hits; |
| | | u32 tags_used; |
| | | u32 summary_used; |
| | | |
| | | }; |
| | | |
| | | /* The CheckpointDevice structure holds the device information that changes |
| | | *at runtime and must be preserved over unmount/mount cycles. |
| | | */ |
| | | struct yaffs_checkpt_dev { |
| | | int struct_type; |
| | | int n_erased_blocks; |
| | | int alloc_block; /* Current block being allocated off */ |
| | | u32 alloc_page; |
| | | int n_free_chunks; |
| | | |
| | | int n_deleted_files; /* Count of files awaiting deletion; */ |
| | | int n_unlinked_files; /* Count of unlinked files. */ |
| | | int n_bg_deletions; /* Count of background deletions. */ |
| | | |
| | | /* yaffs2 runtime stuff */ |
| | | unsigned seq_number; /* Sequence number of currently |
| | | * allocating block */ |
| | | |
| | | }; |
| | | |
| | | struct yaffs_checkpt_validity { |
| | | int struct_type; |
| | | u32 magic; |
| | | u32 version; |
| | | u32 head; |
| | | }; |
| | | |
| | | struct yaffs_shadow_fixer { |
| | | int obj_id; |
| | | int shadowed_id; |
| | | struct yaffs_shadow_fixer *next; |
| | | }; |
| | | |
| | | /* Structure for doing xattr modifications */ |
| | | struct yaffs_xattr_mod { |
| | | int set; /* If 0 then this is a deletion */ |
| | | const YCHAR *name; |
| | | const void *data; |
| | | int size; |
| | | int flags; |
| | | int result; |
| | | }; |
| | | |
| | | /*----------------------- YAFFS Functions -----------------------*/ |
| | | |
| | | int yaffs_guts_initialise(struct yaffs_dev *dev); |
| | | void yaffs_deinitialise(struct yaffs_dev *dev); |
| | | |
| | | int yaffs_get_n_free_chunks(struct yaffs_dev *dev); |
| | | |
| | | int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, |
| | | struct yaffs_obj *new_dir, const YCHAR * new_name); |
| | | |
| | | int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); |
| | | int yaffs_del_obj(struct yaffs_obj *obj); |
| | | |
| | | int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); |
| | | loff_t yaffs_get_obj_length(struct yaffs_obj *obj); |
| | | int yaffs_get_obj_inode(struct yaffs_obj *obj); |
| | | unsigned yaffs_get_obj_type(struct yaffs_obj *obj); |
| | | int yaffs_get_obj_link_count(struct yaffs_obj *obj); |
| | | |
| | | /* File operations */ |
| | | int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, |
| | | int n_bytes); |
| | | int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, |
| | | int n_bytes, int write_trhrough); |
| | | int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); |
| | | |
| | | struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, |
| | | const YCHAR *name, u32 mode, u32 uid, |
| | | u32 gid); |
| | | |
| | | int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync); |
| | | |
| | | /* Flushing and checkpointing */ |
| | | void yaffs_flush_whole_cache(struct yaffs_dev *dev); |
| | | |
| | | int yaffs_checkpoint_save(struct yaffs_dev *dev); |
| | | int yaffs_checkpoint_restore(struct yaffs_dev *dev); |
| | | |
| | | /* Directory operations */ |
| | | struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, |
| | | u32 mode, u32 uid, u32 gid); |
| | | struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, |
| | | const YCHAR *name); |
| | | struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); |
| | | |
| | | /* Link operations */ |
| | | struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name, |
| | | struct yaffs_obj *equiv_obj); |
| | | |
| | | struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); |
| | | |
| | | /* Symlink operations */ |
| | | struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, |
| | | const YCHAR *name, u32 mode, u32 uid, |
| | | u32 gid, const YCHAR *alias); |
| | | YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); |
| | | |
| | | /* Special inodes (fifos, sockets and devices) */ |
| | | struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, |
| | | const YCHAR *name, u32 mode, u32 uid, |
| | | u32 gid, u32 rdev); |
| | | |
| | | int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, |
| | | const void *value, int size, int flags); |
| | | int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, |
| | | int size); |
| | | int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); |
| | | int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); |
| | | |
| | | /* Special directories */ |
| | | struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); |
| | | struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); |
| | | |
| | | void yaffs_handle_defered_free(struct yaffs_obj *obj); |
| | | |
| | | void yaffs_update_dirty_dirs(struct yaffs_dev *dev); |
| | | |
| | | int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); |
| | | |
| | | /* Debug dump */ |
| | | int yaffs_dump_obj(struct yaffs_obj *obj); |
| | | |
| | | void yaffs_guts_test(struct yaffs_dev *dev); |
| | | |
| | | /* A few useful functions to be used within the core files*/ |
| | | void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, |
| | | int lyn); |
| | | int yaffs_check_ff(u8 *buffer, int n_bytes); |
| | | void yaffs_handle_chunk_error(struct yaffs_dev *dev, |
| | | struct yaffs_block_info *bi); |
| | | |
| | | u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev); |
| | | void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer); |
| | | |
| | | struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, |
| | | int number, |
| | | enum yaffs_obj_type type); |
| | | int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, |
| | | int nand_chunk, int in_scan); |
| | | void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name); |
| | | void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, |
| | | const struct yaffs_obj_hdr *oh); |
| | | void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); |
| | | YCHAR *yaffs_clone_str(const YCHAR *str); |
| | | void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list); |
| | | void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); |
| | | int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, |
| | | int force, int is_shrink, int shadows, |
| | | struct yaffs_xattr_mod *xop); |
| | | void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, |
| | | int backward_scanning); |
| | | int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); |
| | | struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); |
| | | struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, |
| | | struct yaffs_file_var *file_struct, |
| | | u32 chunk_id, |
| | | struct yaffs_tnode *passed_tn); |
| | | |
| | | int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, |
| | | int n_bytes, int write_trhrough); |
| | | void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); |
| | | void yaffs_skip_rest_of_block(struct yaffs_dev *dev); |
| | | |
| | | int yaffs_count_free_chunks(struct yaffs_dev *dev); |
| | | |
| | | struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, |
| | | struct yaffs_file_var *file_struct, |
| | | u32 chunk_id); |
| | | |
| | | u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, |
| | | unsigned pos); |
| | | |
| | | int yaffs_is_non_empty_dir(struct yaffs_obj *obj); |
| | | |
| | | int yaffs_format_dev(struct yaffs_dev *dev); |
| | | |
| | | void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, |
| | | int *chunk_out, u32 *offset_out); |
| | | /* |
| | | * Marshalling functions to get loff_t file sizes into aand out of |
| | | * object headers. |
| | | */ |
| | | void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize); |
| | | loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh); |
| | | loff_t yaffs_max_file_size(struct yaffs_dev *dev); |
| | | |
| | | |
| | | #endif |
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h
linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c
linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h
linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h
linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h
linux-bsp/bootstrap/bootstrap.S
linux-bsp/bootstrap/bootstrap.h
linux-bsp/bootstrap/build.sh
linux-bsp/bootstrap/makefile
linux-bsp/build.sh
linux-bsp/driver/Makefile
linux-bsp/driver/kernel_hello.c
linux-bsp/driver/platdev_led.c
linux-bsp/driver/platdev_led.h
linux-bsp/driver/platdrv_key.c
linux-bsp/driver/platdrv_led.c
linux-bsp/driver/s3c_led.c
linux-bsp/driver/test/makefile
linux-bsp/driver/test/test_plat_key.c
linux-bsp/driver/test/test_plat_led.c
linux-bsp/driver/test/test_s3c_led.c
linux-bsp/driver/x86/Makefile
linux-bsp/driver/x86/kernel_hello.c
linux-bsp/patches/gen_patch.sh
linux-bsp/patches/linux-3.0-fl2440.patch
linux-bsp/patches/u-boot-2010.09-fl2440.patch
linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch
linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch
linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch
linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch
linux-bsp/tarballs/rootfs.tar.bz2 |