1 / 36

SE3208 uCLinux Porting

SE3208 uCLinux Porting. B.H.Lee. 目录. uClinux 构成以及编译器 BOOTLOAD 的构成 Arch/ 和 include/ 目录的构成 uClinux Porting. 目录的构成. uClinux-2.4.6/ => uClinux 2.4. 6 版本 Linux Kernel uClibc/ => uClinux 优化过的 libc 库 forJupiter/ => Jupiter chip 的监控程序 (gdb 用 ) 和 Bootloader

sef
Télécharger la présentation

SE3208 uCLinux Porting

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. SE3208 uCLinux Porting B.H.Lee

  2. 目录 • uClinux 构成以及编译器 • BOOTLOAD的构成 • Arch/和include/目录的构成 • uClinux Porting

  3. 目录的构成 uClinux-2.4.6/ => uClinux 2.4.6版本Linux Kernel uClibc/ => uClinux优化过的libc库 forJupiter/ => Jupiter chip的监控程序(gdb用)和Bootloader forVirgine/ => virgine chip的监控程序和Bootloader forAmazon/ => amazon chip的监控程序和Bootloader app/ => Shell以及测试程序 sash/ => 嵌入式Shell程序 busybox/ => 嵌入式应用程序(ls等) se3208-elf2flt/=> 文件格式变换程序, 把elf格式转换成flat格式

  4. 编译方法 > make mrproper > make jupiter_config #或make amazon_config > make oldconfig > make dep > make 最终romimage.bin文件生成以后结构如下 seloader.bin (Bootloader Image) linux.bin (Linux Kernel Image) rdgz.bin (压缩的Ramdisk Image)

  5. Kernel的运行 seloader> reload kernel # 把位于ROM的Kernel程序下载到RAM seloader> reload ramdisk # 把位于ROM的Ramdisk下载到RAM seloader> boot Booting之前可以用memcmp命令检查下载是否正确完成

  6. 制作应用程序 1) se3208-elf2flt (elf执行文件) => 生成.bflt文件 2) 把RamdiskImage连接到设备以后安装 ############################### gunzip rd.gz losetup /dev/loop1 rd mount /dev/loop1 ./ramdisk_root ############################### 在ramdisk_root目录生成Ramdisk的内容 3)把bflt文件复制到ramdisk_root/bin目录 4)解除文件系统移除设备,生成rdgz.bin文件 ############################## unmount ./ramdisk_root losetup -d /dev/loop1 gzip rd cp rd.gz rdgz.bin ##############################

  7. Make的执行过程 make mrproper : 删除所有的目的文,件相关文件和设置文件等 make jupiter_config: /arch/eiscnommu/def-configs/Jupiter 把Jupiter用defconfig设置 make oldconfig : 用/arch/eiscnommu/defconfig进行设置 把Include/asm-eiscnommu连接到asm Make dep : 确认构成Kernel源的文件之间的相互关系 把Include/asm/arch连接到arch-jupiter ( 设置板的相关参数)

  8. Menuconfig 设置Arch/eiscnommu/config.in文件 Defconfig 文件里存储基本的设置参数 CONFIG_SE3208=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_UCLINUX=y CONFIG_EXPERIMENTAL=y CONFIG_ARCH_JUPITER=y CONFIG_NO_PGT_CACHE=y CONFIG_CPU_32=y CONFIG_NO_MMU_LARGE_ALLOCS=y DRAM_BASE=0C200000 DRAM_SIZE=00E00000 CONFIG_JUPITER_DEBUG=y CONFIG_NET=y CONFIG_KCORE_ELF=y CONFIG_BINFMT_FLAT=y CONFIG_KERNEL_ELF=y …. CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y

  9. Mach-jupiter目录的构成 Arch.c : 设置Ramdisk起始地址和大小,IO data r/w 函数(peek,poke),初始化中断控制器 Irq.c : 与中断控制相关的函数( mask_irq, unmask_irq ..) Timer.c : Jupiter_timer_interrupt的定义

  10. Arch-jupiter目录的构成 Hardware.h : 设置和宏定义各peripheral的control register Irq.h: 定义中断控制初始化inline函数 Irqs.h : 定义中断号码 Time.h : 登录TIMER中断处理者以及设置TIMER初始化

  11. Bootloader的动作原理

  12. Bootloader流程 设置PLL、RAM,复制DATA SECTION 初始化cache、serial以及输入命令 连接bootp(获得IP地址) 利用以太网从HOST复制Kernel和Ramdisk image到指定的板上 利用serial从HOST复制Kernel和Ramdisk image到指定的板上 把位于内存的Kernel和Ramdisk Image移到Flash领域 Bootloader的命令的Debugging操作

  13. Bootloader的构成图 Bootp packet生成和通信。CMD_RBL的桥接函数 CMD_RBL的登录和命令执行所需函数 Flash erase,write,lock,unlock 编译时,为了管理Section而设置的script 在tb loader驱动别的函数时使用的基本函数 用C语言编写的main函数。寻找和运行CMD_TLB里要执行的函数 初始化ethernet以及传送接收函数 连接mac_in.c和boot.c,tftp.c的桥接函数 Serial输入输出。驱动其他函数时实现输入输出的基本函数 运行tb loader所需的基本设备的初始化 Tftp packet的生成和传送接收 连接CMD_TBL和istring.c的桥接函数

  14. /Arch的构成 ꊱ kernel/ : 代表如下核心代码 - Kernel的初始化代码 - 中断、Exception Handler代码 - Processor相关代码 - Signal相关代码 - 基于Processor的系统呼叫代码 ꊲ mm/ : 与虚拟存储器管理相关的代码,主要由控制MMU的代码构成 - 存储器初始化代码 - Page FaultHandler代码 - tlb, cache相关代码 - exception table code

  15. /Arch的构成2 ꊳ lib/ : 为了提高速度把Kernel经常使用的函数用汇编语言编写的代码 - User mode 存储器复制代码 - string 处理代码 - TCP/IP checksum 代码 ꊴ boot/ : 装载Kernel用的代码。Kernel的解压以及移动Kernel到指定的位置

  16. Include/asm-eiscnommu的构成 . Kernel使用的头文件中的Processor相关的文件构成 . Kernel使用的宏和Inline函数中,由Processor相关的代码构成 代码内容 ꊱ 用Inline汇编语言编写的代码(比如Semaphore函数,TCP/IP checksum函数等) ꊲ 与CPU以及板资源相关的宏(Cache / TLB的大小, 主存储器大小等) ꊳ SoC以及目标板的固有信息相关的宏(memory map, 周遍设备控制以及状态寄存器等)

  17. Makefile以及Config.in文件 Linux Kernel通过Makefile来设置环境和进行编译 mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_SE3208 y define_bool CONFIG_SBUS n define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y # Begin uclinux additions ----------------------------------------------------- define_bool CONFIG_UCLINUX y define_bool CONFIG_FULLDEBUG n # End uclinux additions ------------------------------------------------------- ...... (略) ...... mainmenu_option next_comment comment 'System Type'

  18. Makefile以及Config.in文件 choice 'EISC system type'\ "JupiterCONFIG_ARCH_JUPITER \ Amazon CONFIG_ARCH_AMAZON \ VirgineG2CONFIG_ARCH_VIRGINE" Jupiter if [ "$CONFIG_ARCH_JUPITER" = "y" ]; then define_bool CONFIG_NO_PGT_CACHE y define_bool CONFIG_CPU_32 y define_bool CONFIG_NO_MMU_LARGE_ALLOCS y hex 'jupiter DRAM Base address' DRAM_BASE 0x0C000000 hex 'jupiter DRAM Size' DRAM_SIZE 0x01000000 # define_hex FLASH_MEM_BASE 0x08400000 # define_hex FLASH_SIZE 0x00200000 define_bool CONFIG_JUPITER_DEBUG y fi ...... (略) ...... <List 1> arch/se3208/config.in 文件的一部分

  19. uClinux的Porting arch/eiscnommu/目录 include/asm-eiscnommu)/目录的内容 SE3208的特点 * SE3208核的CPU模式只有一个, 所以SP(堆栈指针) 寄存器只有一个 * 系统Boot设备为ROM, CPU的exception table必须位在ROM的0x0地址

  20. arch/se3208/目录和include/asm-se3208/目录的构成 1) arch/se3208/kernel/head.S : kernel最初运行的代码 - 初始化堆栈指针 - 初始化存储器控制器 - 初始化临时serial设备驱动 - 呼叫start_kernel() 函数 2) arch/se3208/kernel/debug-se3208asm.S, debug-se3208.c : 临时serial设备驱动 Linux Kernel在Booting的时候利用printk()函数传递信息,但printk()实际上是在console_init()函数运行以后才能工作,为了确认console_init()以前的代码工作与否,制作了向serial设备输送文字队列的代码 3) 为了Kernel同步化而设计的代码 - 中断禁止/允许代码:cli(),sti(),save_flags(),save_flags_cli() restore_flags() - 与semaphore相关的代码: down() down_interruptible(), up()

  21. setup_arch()函数 1) Processor特有初始化代码 2) 获得物理存储器大小和位置信息以后, 根据得到的信息初始化Paging系统 * 得到系统信息中存储器大小和位置信息 * 初始化bootmem分配器 * bootmem分配器是为了在Paging系统工作之前有效使用物理存储器而设置的,起分配存储器的功能 * 一般在初始化Paging系统时使用,实际上调用init_bootmem()函数即可 * 初始化Paging系统。具体是初始化zone分配器,调用paging_init()函数,在这里调用free_area_init_node()函数来初始化系统的所有Page

  22. Setup_arch() void __init setup_arch(char **cmdline_p) { ...... (略) ...... if (meminfo.nr_banks == 0) { meminfo.nr_banks = 1; meminfo.bank[0].start = PAGE_OFFSET;//PHYS_OFFSET; meminfo.bank[0].size = MEM_SIZE; } ...... (略) ...... bootmap_size= init_bootmem_node( NODE_DATA(0), memory_start >> PAGE_SHIFT, PAGE_OFFSET >> PAGE_SHIFT, END_MEM >> PAGE_SHIFT);

  23. Setup_arch() free_bootmem(memory_start, END_MEM - memory_start); reserve_bootmem(memory_start, bootmap_size); paging_init(&meminfo, mdesc); ...... (略) ...... if (mdesc->fixup) mdesc->fixup(mdesc, (struct param_struct *) tag, &from, &meminfo); }

  24. trap_init()函数 * 组成exception table。 ENTRY(trap_init) push %r1 - %r4 ldi HANDLER_START, %r3 ldi irq_start, %r1 ldi irq_end, %r2 .L1: ldb (%r1), %r4 stb %r4, (%r3) add %r1, 1, %r1 add %r3, 1, %r3 cmp %r2, %r1 jnz .L1 pop %r1 - %r4, %pc

  25. init_IRQ()函数 * 起初始化和驱动中断控制器的作用 void jupiter_init_aic() { __DISABLE_INT();// 设置sr寄存器来禁止中断 __SET_VECTORED();// 用向量方式处理中断 __SET_INTVGR(0x01); __SET_INTEN(0x0);// 设置INTEN寄存器来禁止中断 __ENABLE_INT();// 设置sr寄存器来允许中断 }

  26. time_init()函数 • * 初始化系统Timer,初始化Timer Device Driver • 在time_init()函数中调用setup_timer()函数 • 把jupiter_timer_interrupt()函数设置为Timer中断处理者(Handler),初始化及驱动JUPITER SoC 内部的Timer控制器 • extern __inline__ void setup_timer (void) • { • int olden; • gettimeoffset = jupiter_gettimeoffset; • timer_irq.handler = jupiter_timer_interrupt;//设置Timer中断处理者函数 • setup_eisc_irq(IRQ_TIMER0, &timer_irq); • __SET_TIMCNT0( TIMER_CNT );// 初始化Timer控制器 • __SET_TIMCON0( (TIMER_PDC<<8) | (TIMER_MD<<1) | TIMER_EN ); • __GET_INTEN(olden); • __SET_INTEN( olden | TIMER0_BIT );// 驱动Timer }

  27. console_init() • 是初始化终端设备驱动以及初始化CONSOLE设备(VGA、serial等)的函数 • 编写Serial设备驱动程序后,在此函数的下段增加初始化系统Serial设备的驱动 • 在console_init()调用se3208_console_init()函数 • 用叫做se3208_console的console结构体的地址为Factor来调用register_console()函数=> 以后可以使用printk

  28. calibrate_delay() 取得处理器BogoMIPS (简单的MIPS)的函数 如果函数正常终止,可以确认entry.S中中断处理者的正常动作与否

  29. kernel_thread()宏 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { pid_t __ret; __asm__ __volatile__( " mov%1, %%r0 or%%r0, %2, %%r0# 在sys_clone()的flagsfactor里设置CLONE_VM ldi0x0, %%r1 ldi%5, %%r6# 把sys_clone()代号作为factor来传送 swi0x2# 调用系统呼叫 mov %%r6, %%r0 mov%%r0, %0# 调查母或子 cmp%%r0, 0x0 jnz1f# 如果是母终止kernel_thread

  30. kernel_thread()宏 mov%4, %%r1#如果是子复归地址设置为2f ldi2f, %%r0# 跳转到fn push%%r0, %%r1 jr%3 2:jmp_sys_exit 1:" : "=r" (__ret) : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg), "I" (__NR_clone) : "%r0", "%r1", "%r6"); return __ret; }

  31. switch_to() • 在Linux中,Kernel thread除了共享Kernel和存储器空间以外跟Process视为相同,成为Scheduling对象 • 运行kernel_thread(init, ...)以后, init thread不会马上执行而是先运行0号Process(start_kernel() 运行中生成的kernel thread) • 0号Process在kernel_thread结束以后执行cpu_idle()函数,此时运行schedule()函数来选择和执行init thread • 在schedule()函数内起Task Swiching功能的代码就是switch_to()

  32. Switch_to()函数 /* * r0 = previous, r1 = next, return previous. *previous and next are guaranteed not to be the same. */ ENTRY(_switch_to) push%r2-%r7, %er, %sr# 把prev process的寄存器值储存到自己的Kernel堆栈里 lea(%sp),%r2 mov%r0,%r3 st%r2,(%r3, TSS_SAVE) ld(%r1, TSS_SAVE),%r2 lea(%r2),%sp pop%r2-%r7, %er, %sr, %pc# 把next process的寄存器值从自己的Kernel堆栈中还原 <List 6> switch_to 函数

  33. Process执行环境相关的代码 ꊱ 程序装载代码: 在uClinux,应用程序的形式采用“flat”(在Linux里是“elf”, “coff”等) 根据应用程序类型的不同提供不同的装载代码,flat形式采用load_flat_binary()函数 ꊲ start_thread()宏: load_(文件形式)_binary()函数中最后使用的宏。设置User Mode的堆栈指针和程序Counter,设置argc, argv, envp等地址

  34. Start_thread() #define start_thread(regs,pc,sp)\ ({\ unsigned long *stack = (unsigned long *)sp;\ set_fs(USER_DS);\ memzero(regs, sizeof(struct pt_regs));\ regs->SE_sp = sp;/* user sp */\ regs->SE_pc = pc;/* user pc */\ regs->SE_sr = 0x3000;/* user sr */\ regs->SE_er = 0x0;/* user er */\ regs->SE_r2 = stack[2];/* r2 (envp) */\ regs->SE_r1 = stack[1];/* r1 (argv) */\ regs->SE_r0 = stack[0];/* r0 (argc) */\ }) <List7> start_thread() 宏的实现

  35. copy_thread()函数 * 和execve一样在Linux被认为Process操作中非常重要的系统呼叫之一fork()函数中调用此函数 * 在Linux中fork()的类似函数共有三个 - fork(), vfork(), clone() 三个函数都调用Kernel内部的do_fork()函数,函数的最后部分调用copy_thread() int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; struct context_save_struct * save; atomic_set(&p->thread.refcount, 0x1); childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1;

  36. Copy_thread()函数 /*下面if-else语句用软件方式实现了CPU mode */ if (regs->SE_prev_mode == KERNEL_MODE) { childregs = (struct pt_regs *) ((unsigned long)childregs - 12); *childregs = *regs; childregs->SE_sp = ((unsigned long)p + 8192) ; childregs->SE_r6 = 0; } else { /* regs->SE_prev_mode == USER_MODE时. */ *childregs = *regs; childregs->SE_r6 = 0; if (esp) { childregs->SE_sp = esp; } } save = ((struct context_save_struct *)(childregs)) - 1; *save = INIT_CSS; save->pc |= (unsigned long)__ret_from_fork; p->thread.save = save; return 0; } <List 8> copy_thread 函数的实现

More Related