ARM Linux static ing Analysis

Source: Internet
Author: User

ARM Linux static ing Analysis

Source Address: http://www.embedu.org/Column/Column225.htm

During the Hua Qing foresight course, it was found that it was difficult for beginners to master and understand static ing, next we will analyze the principle of static ing and use the static ing of gpio, USB, LCD, and so on as an example to illustrate how to access peripheral resources through this static ing method.

The kernel provides an important struct machine_desc, which plays a very important role in internal nuclear transfer. The kernel uses the machine_desc struct to control the initialization of the system architecture. Members of the machine_desc struct contain several important initialization functions related to the architecture, including map_io, init_irq, init_machine, phys_io, and timer.

The machine_desc struct is defined as follows:

Struct machine_desc {
/*
* Note! The first four elements are used
* By Cycler code in head-armv.S
*/
Unsigned int NR;/* architecture Number */
Unsigned int phys_io;/* Start of physical Io */
Unsigned int io_pg_offst;/* byte offset for Io
* Page tabe entry */
Const char * Name;/* architecture name */
Unsigned long boot_params;/* tagged list */
Unsigned int video_start;/* Start of video RAM */
Unsigned int video_end;/* end of video RAM */
Unsigned int reserve_lp0: 1;/* Never has lp0 */
Unsigned int reserve_lp1: 1;/* Never has lp1 */
Unsigned int reserve_lp2: 1;/* Never has lp2 */
Unsigned int soft_reboot: 1;/* Soft reboot */
Void (* fixup) (struct machine_desc *,
Struct tag *, char **,
Struct meminfo *);
Void (* map_io) (void);/* IO mapping function */
Void (* init_irq) (void );
Struct sys_timer * timer;/* system tick timer */
Void (* init_machine) (void );
};

The machine_desc struct is initialized using the machine_start macro. Here we use the S3C2410 platform as an example:

The structure of the S3C2410 machine_desc is defined as follows:
/* ARCH/ARM/mach-s3c2410/mach-smdk2410.c */
Machine_start (smdk2410, "smdk2410")/* @ todo: request a new identifier and switch
* To smdk2410 */
/* Maintainer: Jonas dietsche */
. Phys_io = s3c2410_pa_uart,
. Io_pg_offst = (u32) s3c24xx_va_uart)> 18) & 0 xfffc,
. Boot_params = s3c2410_sdram_pa + 0x100,
. Map_io = smdk2410_map_io,
. Init_irq = s3c24xx_init_irq,
. Init_machine = smdk2410_init,
. Timer = & s3c24xx_timer,
Machine_end

The macro machine_start and machine_end are defined as follows:
/*
* Set of macros to define architecture features. This is built
* A table by the linker.
*/
# Define machine_start (_ type, _ name )\
Const struct machine_desc _ mach_desc _ ###_ Type \
_ Attribute _ (_ Section _ (".arch.info. init") = {\
. Nr = mach_type _ ##_ type ,\
. Name = _ name,

# Define machine_end \
};

Mach_type _ # _ type is the character concatenation identifier in the GCC extension syntax. It will be replaced by real characters during pre-compilation. For example, mach_type_smdk2410 is used here.

The use of machine_start and placement of each member function and the calling process are as follows:
The mach_type_smdk2410 value is the type value of the target board, defined in arch/include/ASM-arm/mach-types.h, and 193.

/* ARCH/include/ASM-arm/mach-types.h */
# Define mach_type_smdk2410 193

From the above, we found that machine_start mainly defines the type of "struct machine_desc", which is placed in section (".arch.info. init ") is the initialization data, which is occupied by the kernel and will be released.

Here, map_io members are the interface functions provided by the kernel for users to create a static ing table from peripheral I/O resources to kernel virtual addresses. The map_io member function is called during system initialization. The process is as follows:
Start_kernel-> setup_arch () --> called in paging_init ()
Each member function of the struct machine_desc struct is called at different times:
1 .. init_machine in arch/ARM/kernel/setup. in C, it is called by mimize_machine and placed in the arch_initcall () segment. It is automatically called in order (for blog analysis, please stay tuned ).
2. init_irq is called in start_kernel () --> init_irq () --> init_arch_irq ()
3. map_io is called in setup_arch () --> paging_init ()

Others are mainly used in setup_arch.

You can specify the map_io interface function when defining the machine_desc struct. This is exactly what we do.

Next, we will continue to analyze the execution process of smdk2410_map_io. The process is as follows:

Smdk2410_map_io-> s3c24xx_init_io (smdk2410_iodesc, array_size (smdk2410_iodesc ))

Let's take a look at the s3c24xx_init_io function:

Void _ init s3c24xx_init_io (struct map_desc * mach_desc, int mach_size)
{
/* Register our io-tables */
Iotable_init (cloud_iodesc, array_size (cloud_iodesc ));
......
}

The iotable_init kernel is provided and defined as follows:

/*
* Create the architecture specific ings
*/
Void _ init iotable_init (struct map_desc * io_desc, int nr)
{
Int I;
For (I = 0; I Nr; I ++)
Create_mapping (io_desc + I );
}

As you can see, smdk2410_map_io finally calls iotable_init to create a ing table.

The iotable_init function has two parameters: one is a structure of the map_desc type, and the other is the number of NR struct. The most important thing here is struct map_desc. The map_desc struct is defined as follows:

/* Include/ASM-arm/Mach/map. H */
Struct map_desc {
Unsigned long virtual;
Unsigned long physical;
Unsigned long length;
Unsigned int type;
};

The create_mapping () function creates a linear ing table based on the information provided by map_desc.

In this way, we know that the general process for creating an I/O ing table is: as long as the map_desc struct of the corresponding I/O resources is defined and the struct is passed to the iotable_init function for execution, you can create a ing table from the corresponding I/O resources to the kernel virtual address space.

Let's take a look at how S3C2410 defines the structure of the map_desc (that is, the initiat_iodesc in the iotable_init () function above ).

[ARCH/ARM/mach-s3c2410/CPU. C]
/* Minimal Io mapping */
Static struct map_desc initi_iodesc [] _ initdata = {
Iodesc_ent (gpio ),
Iodesc_ent (IRQ ),
Iodesc_ent (memctrl ),
Iodesc_ent (UART)
};

Iodesc_ent macro:

# Define iodesc_ent (x) {(unsigned long) s3c24xx_va _ # X, s3c2410_pa _ # X, s3c24xx_sz _ # X, mt_device}

Expansion is equivalent:

Static struct map_desc initi_iodesc [] _ initdata = {
{
. Virtual = s3c24xx_va_gpio,
. Physical = s3c24xx_pa_gpio,
. Length = s3c24xx_sz_gpio,
. Type = mt_device
},
......
};

So far, we can clearly see that the gpio is statically mapped, because we have prepared the gpio ing in the previous static ing, that is why we can configure the following pins when writing gpio-related drivers:
S3c2410_gpio_cfgpin (XXX, XXX );

In fact, the definition of s3c2410_gpio_cfgpin is as follows:

Void s3c2410_gpio_cfgpin (unsigned int pin, unsigned int function)
{
Void _ iomem * base = s3c2410_gpio_base (PIN );
Unsigned long mask;
Unsigned long con;
Unsigned long flags;

If (PIN <s3c2410_gpio_bankb ){
Mask = 1 <s3c2410_gpio_offset (PIN );
} Else {
Mask = 3 <s3c2410_gpio_offset (PIN) * 2;
}

Local_irq_save (flags );

Con = _ raw_readl (base + 0x00 );
Con & = ~ Mask;
Con | = function;

_ Raw_writel (con, base + 0x00 );

Local_irq_restore (flags );
}

One of the key points is:
Void _ iomem * base = s3c2410_gpio_base (PIN );
In this line, s3c2410_gpio_base is defined as follows:

# Define s3c2410_gpio_base (PIN )&~ 31)> 1) + s3c24xx_va_gpio)

So far, the static gpiing of gpio is quite clear.

The following describes the static ing of other peripherals:

In the s3c24xx_init_io () function, in addition to iotable_init,
(CPU-> map_io) (mach_desc, size );

The CPU map_io is defined in arch/ARM/mach-s3c2410/CPU. C as follows:

Static struct cpu_table cpu_ids [] _ initdata = {
{
. Idcode = 0x32410000,
. Idmask = 0 xffffffff,
. Map_io = s3c2410_map_io,
. Init_clocks = s3c2410_init_clocks,
. Init_uarts = s3c2410_init_uarts,
. Init = s3c2410_init,
. Name = name_s3c2410
},
...
}

Then, check s3c2410_map_io (). The function code is as follows:

Void _ init s3c2410_map_io (struct map_desc * mach_desc, int mach_size)
{
/* Register our io-tables */

Iotable_init (s3c2410_iodesc, array_size (s3c2410_iodesc ));
Iotable_init (mach_desc, mach_size );
}

Next look at the structure of s3c2410_iodesc [ARCH/ARM/mach-s3c2410/S3C2410. C], the Code is as follows,

/* Initial Io mappings */
Static struct map_desc s3c2410_iodesc [] _ initdata = {
Iodesc_ent (usbhost ),
Iodesc_ent (usbdev ),
Iodesc_ent (clkpwr ),
Iodesc_ent (LCD ),
Iodesc_ent (timer ),
Iodesc_ent (ADC ),
Iodesc_ent (watchdog ),
};

The iodesc_ent (timer) line was found. Combined with the similar analysis of gpio, The iodesc_ent macro is as follows:
# Define iodesc_ent (x) {(unsigned long) s3c24xx_va _ # X, s3c2410_pa _ # X, s3c24xx_sz _ # X, mt_device}

So far, static mappings such as timer, usbhost, usbdev, LCD, ADC, and watchdog are all well understood.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.