www.pudn.com > 4k_bootloader.rar > main.c
#define COMMAND_LINE_SIZE 1024
#define SZ_64M 0x04000000
#define DRAM_SIZE SZ_64M
/*#define DRAM_BASE 0x30000000 */
#define KERNEL_ROM_ADDR 0x00030000 /*kernel zImage ÔÚ nand flash ÖеÄλÖÃ. */
#define KERNEL_SIZE 0x001d0000
#define MACH_TYPE 193
#define MT_SMC_S3C2410 3
#define LINUX_KERNEL_OFFSET 0x8000
#define LINUX_PARAM_OFFSET 0x100
#define SZ_4K 0x00001000
#define LINUX_PAGE_SIZE SZ_4K
#define LINUX_PAGE_SHIFT 12
#define LINUX_ZIMAGE_MAGIC 0x016f2818
int printk(const char *fmt, ...);
/* This is the old deprecated way to pass parameters to the kernel */
struct param_struct {
union {
struct {
unsigned long page_size; /* 0 */
unsigned long nr_pages; /* 4 */
unsigned long ramdisk_size; /* 8 */
unsigned long flags; /* 12 */
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
unsigned long rootdev; /* 16 */
unsigned long video_num_cols; /* 20 */
unsigned long video_num_rows; /* 24 */
unsigned long video_x; /* 28 */
unsigned long video_y; /* 32 */
unsigned long memc_control_reg; /* 36 */
unsigned char sounddefault; /* 40 */
unsigned char adfsdrives; /* 41 */
unsigned char bytes_per_char_h; /* 42 */
unsigned char bytes_per_char_v; /* 43 */
unsigned long pages_in_bank[4]; /* 44 */
unsigned long pages_in_vram; /* 60 */
unsigned long initrd_start; /* 64 */
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
} u1;
union {
char paths[8][128];
struct {
unsigned long magic;
char n[1024 - sizeof(unsigned long)];
} s;
} u2;
char commandline[COMMAND_LINE_SIZE];
};
#define UART_CTL_BASE 0x50000000
#define oUTRSTAT 0x10
#define oUTXHL 0x20
#define __REGl(x) (*(volatile unsigned long *)(x))
#define __REGb(x) (*(volatile unsigned char *)(x))
#define bUART(x, Nb) __REGl(UART_CTL_BASE + (x)*0x4000 + (Nb))
#define bUARTb(x, Nb) __REGb(UART_CTL_BASE + (x)*0x4000 + (Nb))
#define UTRSTAT0 bUART(0, oUTRSTAT)
#define UTXH0 bUARTb(0, oUTXHL)
#define UTRSTAT_TX_EMPTY (1 << 2)
#define SERIAL_WRITE_READY() ((UTRSTAT0) & UTRSTAT_TX_EMPTY)
#define SERIAL_WRITE_CHAR(c) ((UTXH0) = (c))
#define PROC_SERIAL_PUTC(c) \
({ while (!SERIAL_WRITE_READY()); \
SERIAL_WRITE_CHAR(c); })
void putc(char c)
{
PROC_SERIAL_PUTC(c);
}
void putnstr(const char *str, int n)
{
if (str == "")
return;
while (n && *str != '\0') {
putc(*str);
str++;
n--;
}
}
int strlen(const char* str)
{
int i=0;
while(*str++) i++;
return i;
}
void putstr(const char *str)
{
putnstr(str, strlen(str));
}
#define MAX_PART_NAME 16
typedef struct mtd_partiton {
char name[MAX_PART_NAME]; /* partition name */
unsigned long offset;
unsigned long size;
unsigned long flag;
} mtd_partition_t;
#define MF_BONFS 0x00000004
mtd_partition_t default_mtd_partitions[] = {
{
name: "vi",
offset: 0,
size: 0x00020000,
flag: 0
}, {
name: "param",
offset: 0x00020000,
size: 0x00010000,
flag: 0
}, {
name: "kernel",
offset: 0x00030000,
size: 0x001d0000,
flag: 0
}, {
name: "root",
offset: 0x00200000,
size: 0x02300000,
flag: MF_BONFS
},{
name: "yaffs",
offset: 0x02500000,
size: 0x01b00000,
flag: 0
}
};
#define SZ_1M 0x00100000
#define SZ_16K 0x00004000
#define SZ_64M 0x04000000
#define DRAM_BASE0 0x30000000 /* base address of dram bank 0 */
#define DRAM_BASE DRAM_BASE0
#define DRAM_SIZE SZ_64M
#define VIVI_RAM_SIZE SZ_1M
#define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)
#define HEAP_SIZE SZ_1M
#define HEAP_BASE (VIVI_RAM_BASE - HEAP_SIZE)
#define MMU_TABLE_SIZE SZ_16K
#define MTD_PART_SIZE SZ_16K
#define PARAMETER_TLB_SIZE SZ_16K
#define LINUX_CMD_SIZE SZ_16K
#define MMU_TABLE_BASE (HEAP_BASE - MMU_TABLE_SIZE)
#define VIVI_PRIV_SIZE (MTD_PART_SIZE + PARAMETER_TLB_SIZE + LINUX_CMD_SIZE)
#define VIVI_PRIV_RAM_BASE (MMU_TABLE_BASE - VIVI_PRIV_SIZE)
#define MTD_PART_OFFSET 0x00000000
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
int default_nb_part = ARRAY_SIZE(default_mtd_partitions);
int *nb_mtd_parts = (int *)(VIVI_PRIV_RAM_BASE + MTD_PART_OFFSET + 8);
const char mtd_part_magic[8] = {'V', 'I', 'V', 'I', 'M', 'T', 'D', 'P'};
int get_default_mtd_partition(void)
{
char *src_parts = (char *)&default_mtd_partitions;
char *dst_parts = (char *)(VIVI_PRIV_RAM_BASE + MTD_PART_OFFSET);
int num = default_nb_part;
putstr("begin to transfer mtd partition table \n");
if (src_parts == "") return -1;
/* printk("number of mtd partitions: %d\n", num); */
*(nb_mtd_parts) = num;
if ((sizeof(mtd_partition_t)*num + 16) > MTD_PART_SIZE) {
/*printk("too large mtd partition table\n"); */
return -1;
}
memcpy(dst_parts, mtd_part_magic, 8); /* copy mtd magic */
dst_parts += 16;
/* copy partition table */
memcpy(dst_parts, src_parts, (sizeof(mtd_partition_t)*num));
return 0;
}
#include
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCMD __REGb(NF_BASE + 0x4)
#define NFADDR __REGb(NF_BASE + 0x8)
#define NFDATA __REGb(NF_BASE + 0xc)
#define NFSTAT __REGb(NF_BASE + 0x10)
#define BUSY 1
inline void wait_idle(void) {
int i;
while(!(NFSTAT & BUSY))
for(i=0; i<10; i++);
}
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
/* chip Enable */
NFCONF &= ~0x800;
for(i=0; i<10; i++);
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
NFCMD = 0;
/* Write Address */
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = (NFDATA & 0xff);
buf++;
}
}
/* chip Disable */
NFCONF |= 0x800; /* chip disable */
return 0;
}
static inline void cpu_arm920_cache_clean_invalidate_all(void)
{
__asm__(
" mov r1, #0\n"
" mov r1, #7 << 5\n" /* 8 segments */
"1: orr r3, r1, #63 << 26\n" /* 64 entries */
"2: mcr p15, 0, r3, c7, c14, 2\n" /* clean & invalidate D index */
" subs r3, r3, #1 << 26\n"
" bcs 2b\n" /* entries 64 to 0 */
" subs r1, r1, #1 << 5\n"
" bcs 1b\n" /* segments 7 to 0 */
" mcr p15, 0, r1, c7, c5, 0\n" /* invalidate I cache */
" mcr p15, 0, r1, c7, c10, 4\n" /* drain WB */
);
}
void cache_clean_invalidate(void)
{
cpu_arm920_cache_clean_invalidate_all();
}
static inline void cpu_arm920_tlb_invalidate_all(void)
{
__asm__(
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c10, 4\n" /* drain WB */
"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate I & D TLBs */
);
}
void tlb_invalidate(void)
{
cpu_arm920_tlb_invalidate_all();
}
void call_linux(long a0, long a1, long a2)
{
cache_clean_invalidate();
tlb_invalidate();
__asm__(
"mov r0, %0\n"
"mov r1, %1\n"
"mov r2, %2\n"
"mov ip, #0\n"
"mcr p15, 0, ip, c13, c0, 0\n" /* zero PID */
"mcr p15, 0, ip, c7, c7, 0\n" /* invalidate I,D caches */
"mcr p15, 0, ip, c7, c10, 4\n" /* drain write buffer */
"mcr p15, 0, ip, c8, c7, 0\n" /* invalidate I,D TLBs */
"mrc p15, 0, ip, c1, c0, 0\n" /* get control register */
"bic ip, ip, #0x0001\n" /* disable MMU */
"mcr p15, 0, ip, c1, c0, 0\n" /* write control register */
"mov pc, r2\n"
"nop\n"
"nop\n"
: /* no outpus */
: "r" (a0), "r" (a1), "r" (a2)
);
}
/*
* pram_base: base address of linux paramter
*/
static void setup_linux_param(long param_base)
{
struct param_struct *params = (struct param_struct *)param_base;
char *linux_cmd;
/*printk("Setup linux parameters at 0x%08lx\n", param_base);*/
memset(params, 0, sizeof(struct param_struct));
/* ²¿¿À¿Á ÇØÁà¾ß µÉ °Íµé.. ³µð°¡ °æÇèÀûÀ¸·Î ´ëÃæ ÂïÀº °Í.. */
params->u1.s.page_size = LINUX_PAGE_SIZE;
params->u1.s.nr_pages = (DRAM_SIZE >> LINUX_PAGE_SHIFT);
#if 0
params->u1.s.page_size = LINUX_PAGE_SIZE;
params->u1.s.nr_pages = (dram_size >> LINUX_PAGE_SHIFT);
params->u1.s.ramdisk_size = 0;
params->u1.s.rootdev = rootdev;
params->u1.s.flags = 0;
/* TODO */
/* If use ramdisk */
/*
params->u1.s.initrd_start = ?;
params->u1.s.initrd_size = ?;
params->u1.s.rd_start = ?;
*/
#endif
/* set linux command line */
/*linux_cmd = get_linux_cmd_line();*/
linux_cmd= "noinitrd root=/dev/mtdblock/1 init=/linuxrc confole=ttyS0";
if (linux_cmd == "") {
putstr("boot args is null");
} else {
memcpy(params->commandline, linux_cmd, strlen(linux_cmd) + 1);
putstr("loading linux boot args is ok !");
}
}
int boot_kernel(void)
{
unsigned long boot_mem_base;
unsigned long mach_type;
unsigned long dst;
boot_mem_base = 0x30000000;
dst = 0x30008000;
mach_type = MACH_TYPE;
setup_linux_param(boot_mem_base + LINUX_PARAM_OFFSET);
/* get_default_mtd_partition(); */
putstr ("MACH_TYPE = 193 \n");
putstr("NOW, Booting Linux......\n");
call_linux(0, mach_type, dst);
return 0;
}
/*static void
error(void)
{
putstr("Sorry. We can not run vivi\n");
for (;;)
} */
int main(int argc, char *argv[])
{
boot_kernel();
return 0;
}