Song Baohua talks about arm's embedded Linux porting experience 3: Operating System
In the Article C language embedded system programming practices written by the author, the main software architecture that Chen complained about is a single task without an operating system platform, this article focuses on the software architecture embedded in the operating system. The differences between the two are as follows:
Embedded operating systems are not always necessary because programs can run on bare boards. However, for complex systems, to provide multi-task processing capabilities, such as task management, timer management, memory management, resource management, event management, system management, Message Management, queue management, and interrupt processing, to better allocate system resources, it is necessary to port the operating system to specific hardware platforms and applications. Given the open source code of Linux, it has become a good choice in the field of embedded operating systems. Many well-known universities, companies, and research institutions at home and abroad have joined the research of Embedded Linux and launched some famous versions:
· RT-Linux provides a sophisticated Real-Time Kernel that uses the standard Linux core as a real-time core process for scheduling together with the user's real-time process. RT-Linux has been successfully applied to a wide range of application fields such as space data collection, scientific instrument measurement and control, and film stunt image processing. For example, NASA places RT-Linux devices on an airplane to measure the wind speed of the Georage wind;
· UClinux (micro-control-Linux, u indicates micro, C indicates control) removes the MMU (memory management) function and applies it to microprocessor/microcontroller without virtual memory management, it has been successfully transplanted to many platforms.
The mizi-Linux mentioned in this chapter is transplanted from South Korea's mizi according to the Linux 2.4 kernel and supports the S3C2410A processor.
1. Linux kernel highlights
Like other operating systems, Linux includes process scheduling and inter-process communication (IPC), memory management (MMU), Virtual File System (VFS), and network interfaces, the Linux components and their relationships are given:
The Linux kernel source code contains multiple directories:
(1) arch: hardware-specific kernel code, such as arm, MIPS, and i386;
(2) Drivers: contains hardware driver code, such as char, CDROM, SCSI, MTD, etc;
(3) include: General header files and specific header files for different platforms, such as asm-i386, ASM-arm;
(4) Init: Kernel initialization code;
(5) IPC: inter-process communication code;
(6) kernel: Core kernel code;
(7) mm: Memory Management Code;
(8) Net: Code related to the network protocol stack, such as IPv4, IPv6, And ethernet;
(9) FS: File System related code, such as NFS and vfat;
(10) Lib: library file, strlen and strcpy that are not related to the platform, for example, include in string. C:
Char * strcpy (char * DEST, const char * SRC) <br/>{< br/> char * TMP = DEST; <br/> while (* DEST ++ = * SRC ++ )! = '/0') <br/>/* nothing */; <br/> return TMP; <br/>}
(11) Documentation: Documentation
In the implementation of the Linux kernel, some data structures are frequently used, which is critical to those who study the kernel. They are:
1. task_struct
The Linux kernel uses the task_struct data structure to represent a process and uses the task_struct pointer to form a task array. When a new process is created, Linux allocates a task_struct structure for the new process and stores the pointer in the task array. The scheduler maintains the current pointer, pointing to the currently running process.
2. mm_struct
The virtual memory of each process is represented by the mm_struct structure. This structure contains a set of pointers to the vm-area_struct structure that describes an area of virtual memory.
3. inode
Files and directories in the Linux Virtual File System are represented by the corresponding inode.
2. Linux porting Project
Mizi-Linux has targeted the S3C2410A chip based on the Linux 2.4 kernel, including:
(1) modify the MAKEFILE file in the root directory
A. Specify the target platform as arm:
# Arch: = $ (shell uname-M | sed-e s/I .86/i386/-E S/sun4u/sparc64/-E S/arm. */ARM/-e s/sa110/ARM/) <br/> arch: = arm
B. Specify the cross compiler:
Cross_compile = arm-Linux-
(2) modify files in the arch directory
According to section 1 of this chapter, we can see that the Linux arch directory stores kernel code related to hardware. Therefore, we need to increase the Linux kernel's support for S3C2410 by modifying files in the arch directory.
A. Add the following to the ARCH/ARM/MAKEFILE file:
Ifeq ($ (config_arch_s3c2410), Y) <br/> textaddr = 0xc0008000 <br/> machine = S3C2410 <br/> endif
B. Add the following to the ARCH/ARM/config. In file:
If ["$ config_arch_s3c2410" = "Y"]; then <br/> comment 's3c2410 implementation' <br/> dep_bool 'smdk (Meri Tech board) 'prop $ config_arch_s3c2410 <br/> dep_bool 'change aiji' restart <br/> dep_tristate' S3C2410 USB Function Support 'config_s3c2410_usb $ config_arch_s3c2100 <br/> dep_tristate' support for USB S3C2410 character device emulation 'config_s3c2410_usb_char $ config_s3c2410_usb <br/> fi #/* config_arch_s3c2410 */
The arch/ARM/config. In file also contains several modifications to the S3C2410 file.
C. Add the following to the ARCH/ARM/boot/MAKEFILE file:
Ifeq ($ (config_arch_s3c2410), Y) <br/> ztextaddr = 0x30008000 <br/> zreladdr = 0x30008000 <br/> endif
D. Add the following content to the Linux/ARCH/ARM/boot/compressed/MAKEFILE file:
Ifeq ($ (config_arch_s3c2410), Y) <br/> objs + = head-s3c2410.o <br/> endif
The added result is that the head-s3c2410.S file is compiled into a head-s3c2410.o.
E. Add ARCH/ARM/boot/compressed/head-s3c2410.S files
# Include <Linux/config. h> <br/> # include <Linux/linkage. h> <br/> # include <ASM/mach-types.h> </P> <p>. section ". start ", # alloc, # execinstr </P> <p >__ s3c2410_start: </P> <p> @ preserve R8/R7 I. e. kernel entry values <br/> @ what is it? <Br/> @ Nandy </P> <p> @ data cache, intstruction cache, MMU might be active. <br/> @ Be sure to flush kernel binary out of the cache, <br/> @ whatever state it is, before it is turned off. <br/> @ this is done by fetching through currently executed <br/> @ memory to be sure we hit the same cache </P> <p> Bic R2, PC, # 0x1f <br/> Add R3, R2, #0X4000 @ 16 KB is quite enough... <br/> 1: LDR r0, [R2], #32 <br/> TEQ R2, R3 <br/> BNE 1B <br/> MCR P15, 0, R0, c7, C10, 4 @ drain WB <br/> MCR P15, 0, R0, C7, C7, 0 @ flush I & D caches </P> <p> # If 0 <br/> @ disabling MMU and caches <br/> MRC P15, 0, R0, C1, c0, 0 @ read control register <br/> Bic r0, R0, #0x05 @ disable D cache and MMU <br/> Bic r0, R0, #1000 @ disable I cache <br/> MCR P15, 0, R0, C1, C0, 0 <br/> # endif </P> <p>/* <br/> * pause for a short time so that we give enough time <br/> * for the host to start a terminal up. <br/> */<br/> mov r0, #0x00200000 <br/> 1: subs r0, R0, #1 <br/> BNE 1b
The assembly code in this file initializes the specific hardware of S3c2410.
F. Add the configuration file to the ARCH/ARM/def-configs directory.
G. Added support for S3C2410 in arch/ARM/kernel/makefile.
No-IRQ-arch: = $ (config_arch_integrator) $ (config_arch_clps711x)/<br/> $ (config_footbridge) $ (config_arch_ebsa110)/<br/> $ (config_arch_sa1100) $ (config_arch_camelot)/<br/> $ (config_arch_s3c2400) $ (config_arch_s3c2410)/<br/> $ (config_arch_mx1ads) $ (config_arch_pxa) <br/> obj-$ (config_mizi) + = event. O <br/> obj-$ (config_apm) + = apm2.o
H. Modify the ARCH/ARM/kernel/debug-armv.S file and add the following code about the S3C2410 at the appropriate location:
# Elif defined (config_arch_s3c2410) </P> <p>. macro addruart, RX <br/> MRC P15, 0,/RX, C1, C0 <br/> TST/RX, #1 @ MMU enabled? <Br/> moveq/RX, #0x50000000 @ physical base address <br/> movne/RX, #0xf0000000 @ virtual address <br/>. endm </P> <p>. macro senduart, RD, RX <br/> str/RD, [/RX, #0x20] @ utxh <br/>. endm </P> <p>. macro waituart, RD, RX <br/>. endm </P> <p>. macro busyuart, RD, RX <br/> 1001: LDR/RD, [/RX, #0x10] @ read utrstat <br/> TST/RD, #1 <2 @ tx_empty? <Br/> beq 1001b <br/>. endm
I. Modify the ARCH/ARM/kernel/setup. c file
The setup_arch in this file is critical for completing initialization related to the architecture:
Void _ init setup_arch (char ** cmdline_p) <br/>{< br/> struct tag * tags = NULL; <br/> struct machine_desc * mdesc; <br/> char * From = default_command_line; </P> <p> root_dev = mkdev (0,255); </P> <p> setup_processor (); <br/> mdesc = setup_machine (machine_arch_type); <br/> machine_name = mdesc-> name; </P> <p> If (mdesc-> soft_reboot) <br/> reboot_setup ("S"); </P> <p> If (mdesc-> param_offset) <br/> tags = phys_to_virt (MDE SC-> param_offset); </P> <p>/* <br/> * Do the machine-specific fixups Before We parse the <br/> * parameters or tags. <br/> */<br/> If (mdesc-> fixup) <br/> mdesc-> fixup (mdesc, (struct param_struct *) tags, <br/> & from, & meminfo); </P> <p>/* <br/> * if we have the old style parameters, convert them to <br/> * a tag list before. <br/> */<br/> If (tags & tags-> HDR. tag! = Atag_core) <br/> convert_to_tag_list (struct param_struct *) tags, <br/> meminfo. nr_banks = 0); </P> <p> If (tags & tags-> HDR. tag = atag_core) <br/> parse_tags (TAGS); </P> <p> If (meminfo. nr_banks = 0) {<br/> meminfo. nr_banks = 1; <br/> meminfo. bank [0]. start = phys_offset; <br/> meminfo. bank [0]. size = mem_size; <br/>}</P> <p> init_mm.start_code = (unsigned long) & _ text; <br/> init_mm.end_code = (unsigned long) & _ etext; <br/> init_mm.end_data = (unsigned long) & _ edata; <br/> init_mm.brk = (unsigned long) & _ end; </P> <p> memcpy (saved_command_line, from, command_line_size); <br/> saved_command_line [COMMAND_LINE_SIZE-1] = '/0'; <br/> parse_cmdline (& meminfo, cmdline_p, from ); <br/> bootmem_init (& meminfo); <br/> paging_init (& meminfo, mdesc); <br/> request_standard_resources (& meminfo, mdesc ); </P> <p>/* <br/> * set up various architecture-specific pointers <br/> */<br/> init_arch_irq = mdesc-> init_irq; </P> <p> # ifdef config_vt <br/> # If defined (config_vga_console) <br/> conswitchp = & vga_con; <br/> # Elif defined (config_dummy_console) <br/> conswitchp = & dummy_con; <br/> # endif <br/>}
J. Modify ARCH/ARM/MM/mm-armv.c files (files in the arch/ARM/MM/directory complete arm-related MMU processing)
Modify
Init_maps-> bufferable = 0;
Is
Init_maps-> bufferable = 1;
It is not easy to easily transplant the above-mentioned marathon kernel. You need to have a good grasp of the Linux kernel and have a good grasp of hardware-specific knowledge and related compilation. Fortunately, the developers of mizi have joined hands to complete the above work for us. This allows our younger siblings to focus only on the following points when porting mizi-Linux to their own developed circuit boards:
(1) kernel initialization: the Linux kernel entry point is the start_kernel () function. It initializes other parts of the kernel, including capture, IRQ channel, scheduling, device driver, calibration delay loop, and most importantly, the fork "init" process to start the entire multi-task environment.
We can add some specific content in init.
(2) device drivers: Device Drivers occupy a large part of the Linux kernel. Like other operating systems, device drivers provide interfaces for the hardware devices and operating systems they control.
In chapter 4, we will explain how to write the driver separately.
(3) file system: one of the most important features of Linux is support for multiple file systems. This feature makes it easy for Linux to coexist with other operating systems. The file system concept allows users to view files and paths on storage devices without considering the types of file systems on physical devices. Linux transparently supports many different file systems and presents various installed files and file systems to users in the form of a complete virtual file system.
We can port cramfs, jfss2, yaffs and other flash file systems on k9s1208 NAND Flash.
3. INIT process
In the init function, "adding" can enable Linux to do something when it is started. For example, the demo board of the Guangzhou friendly arm company adds company information to it:
Static int Init (void * unused) <br/>{< br/> lock_kernel (); <br/> do_basic_setup (); </P> <p> prepare_namespace (); </P> <p>/* <br/> * OK, we have completed the initial bootup, and <br/> * We're re essential up and running. get rid of the <br/> * initmem segments and start the user-mode stuff .. <br/> */<br/> free_initmem (); <br/> unlock_kernel (); </P> <p> If (open ("/dev/console ", o_rdwr, 0) <0) <br/> printk ("Warning: Unable to open an initial console. /n "); </P> <p> (void) DUP (0); <br/> (void) DUP (0 ); </P> <p>/* <br/> * We try each of these until one succeeds. <br/> * The Bourne shell can be used instead of init if we are <br/> * trying to recover a really broken machine. <br/> */</P> <p> printk ("====================== =========================/N "); <br/> printk ("= friendly-arm tech. ltd. =/N "); <br/> printk (" = http://www.arm9.net =/N "); <br/> printk (" = http://www.arm9.com.cn =/N "); <br/> printk ("================================== =========/N "); </P> <p> If (execute_command) <br/> execve (execute_command, argv_init, envp_init); <br/> execve ("/sbin/init", argv_init, envp_init); <br/> execve ("/etc/init", argv_init, envp_init); <br/> execve ("/bin/init", argv_init, envp_init ); <br/> execve ("/bin/sh", argv_init, envp_init); <br/> panic ("No init found. try passing init = option to kernel. "); <br/>}
In this way, additional output will be made during Linux Startup:
========================================================== <Br/> = friendly-arm tech. ltd. = <br/> = http://www.arm9.net = <br/> = http://www.arm9.com.cn = <br/> =================== ==============================
4. File System migration
A file system is a method that defines the name, storage, organization, and retrieval of files based on logical units on the partitioned storage devices. If a Linux system does not have a root file system, it cannot be correctly started. Therefore, we need to create the root file system for Linux, and we will create it on k9s1208 NAND Flash.
The linux root file system may include the following directories (or more Directories ):
(1)/bin (Binary): contains all the Standard Commands and applications;
(2)/dev (device): A file interface containing peripherals. in Linux, files and devices are accessed in the same way, each device on the system has a corresponding device file in/dev;
(3)/etc (etce1_): This directory contains the system setting file and other system files, such as/etc/fstab (File System Table) records the filesystem to be mounted at startup;
(4)/Home: stores the user's home directory;
(5)/lib (Library): stores the most basic library files of the system;
(6)/mnt: the location where the user temporarily mounts the file system;
(7)/proc: a virtual system provided by Linux, which is generated in memory during system startup. Users can directly access these files to obtain system information;
(8)/root: main directory of the super user;
(9)/sbin: This directory stores system management programs, such as fsck and mount;
(10)/tmp (temporary): stores temporary files generated during execution of different programs;
(11)/usr (User): stores user applications and files.
Busybox is a good way to narrow down the root file system, because it provides many basic commands of the system, but its size is small. As we all know, Swiss Army Knife is world-renowned for its small and light size and many functions. It has become a necessary tool for military personnel in various countries and is widely used in the civil society. busybox is also known as the "Swiss Army Knife" in the field of embedded Linux ".
This address can download busybox: http://www.busybox.net, the latest version is 1.1.3. After compiling busybox, put it into the/bin directory. To use the command, you only need to create a link, such:
Ln-S./busybox ls <br/> ln-S./busybox mkdir
4.1 cramfs
In the root file system, cramfs format can be used to protect the basic settings of the system from being changed. It is a read-only Flash file system. To create a cramfs file system, create a directory and copy the files to be stored in the file system to this directory, run "mkcramfs directory name image name" to generate an image file for the cramfs file system. For example, if the directory name is rootfs, the correct command is:
Mkcramfs rootfs. ramfs
Run the following command to mount the generated rootfs. ramfs file and view the content:
Mount-o loop-T cramfs rootfs. ramfs/Mount/Point
You can download the mkcramfs tool at http://sourceforge.net/projects/cramfs /.
4.2 jfss2
For the cramfs FLASH file system, data can only be read without ramfs support, while the jfss2 (the Journalling FLASH file system version 2) file system can directly read and write data in the flash memory. Jfss2 is a log-structured file system. nodes that contain data and original data (meta-data) are stored in sequence on flash memory. Jfss2 records the number of writes to each write block. When the number of writes to each block on the flash memory exceeds a predetermined threshold, the wear balance is adjusted. The adjusted policy is to migrate the data on the write block with a small number of writes to the write block with a large number of writes during garbage collection to achieve the goal of wear and tear balance.
Similar to mkcramfs, there is also a mkfs. jffs2 tool that can create a directory as a jffs2 file system. Suppose you want to create the/bin directory as a jffs2 file system, and run the following command:
Mkfs. jffs2-D/bin-O jffs2.img
4.3 yaffs
Yaffs is a kind of file system that can be read and written specially designed for flash Devices commonly used in embedded systems. It has faster startup speed than jffs2 file system, provides better protection for the life of flash memory. To enable Linux to support the yaffs file system, we need to add the corresponding driver to the FS/yaffs/kernel and modify the Kernel configuration file. We can use the mkyaffs tool to format the partitions in NAND flash into the yaffs format (for example, the/bin/mkyaffs/dev/mtdblock/0 command can format 1st MTD block device partitions into yaffs), the use of mkyaffsimage (similar to mkcramfs, mkfs. jffs2) to generate a directory as a yaffs file system image.
In Embedded Linux, you can also use NFS (Network File System) to mount the root file system over Ethernet. This is a file system boot method that is often used for debugging. Through the network-mounted root file system, you can generate a target file or binary executable file of the arm cross-compiled version on the host, and then directly load or execute it, instead of writing flash files frequently.
When using different file systems to start, you must use the bootloader introduced in chapter 2 to modify the startup parameters. For example, the demo of Guangzhou's friendly arm provides the following three startup methods:
(1) mount the root file system from cramfs: Root =/dev/bon/2 ();
(2) mount the root file system from the transplanted yaffs: Root =/dev/mtdblock/0;
(3) mount the root file system from the Ethernet: Root =/dev/NFS.
5. Summary
This chapter describes the background, migration project, INIT process modification, and file system transplantation of embedded Linux. Through these steps, we can start a basic Linux system.
Original article: http://dev.yesky.com/153/2527653.shtml.