Linux Kernel high-low-side memory setup code tracking (ARM architecture)

Source: Internet
Author: User

For the core in arm, how to set the dividing line of high and low memory at startup (also the logical address and virtual address boundary (virtual address) minus that fixed offset), here I slightly boot (kernel analysis using Linux-3.0):

First locate the file that sets the starting location of the kernel virtual address (that is, the address at the end of the kernel logical address): Init.c (arch\arm\mm), the void __init bootmem_init (void) function in this file is as follows

void __init bootmem_init (void)

{

unsigned long min, max_low, Max_high;

Max_low = Max_high = 0;

Find_limits (&min, &max_low, &max_high);

Arm_bootmem_init (min, max_low);

/*

* 1118.www.qixoo.qixoo.com Sparsemem tries to allocate Bootmem in Memory_present (),

* So must is done after the fixed reservations

*/

Arm_memory_present ();

/*

* Sparse_init () needs the Bootmem allocator up and running.

*/

Sparse_init ();

/*

* Now free the Memory-free_area_init_node needs

* The sparse mem_map arrays initialized by Sparse_init ()

* for Memmap_init_zone (), otherwise all PFNS is invalid.

*/

Arm_bootmem_free (Min, Max_low, Max_high);

High_memory = __va (((phys_addr_t) Max_low << page_shift)-1) + 1;

/*

* This doesn ' t seem to being used by the Linux memory manager any

* More, but was used by Ll_rw_block. If we can get rid of it, we

* Also get rid of some of the stuff above as well.

*

* NOTE:MAX_LOW_PFN and MAX_PFN reflect the number of _pages_ in

* The system, not the maximum PFN.

*/

MAX_LOW_PFN = Max_low-phys_pfn_offset;

MAX_PFN = Max_high-phys_pfn_offset;

}


This high_memory = __va ((((phys_addr_t) Max_low << page_shift) + 1; statement is the key. From here we can know that Max_low is the starting address (physical address) of high-end memory. So how did this max_low get it? Actually look at the above code can be measured, he is actually in Find_limits (&min, &max_low, &max_high); (in the same file) is set:


static void __init find_limits (unsigned long *min, unsigned long *max_low,

unsigned long *max_high)

{

struct Meminfo *mi = &meminfo;

int i;


*min = -1ul;

*max_low = *max_high = 0;

For_each_bank (i, MI) {

struct Membank *bank = &mi->bank[i];

Unsigned long start, end;

Start = Bank_pfn_start (bank);

End = Bank_pfn_end (bank);

if (*min > Start)

*min = start;

if (*max_high < end)

*max_high = end;

if (BANK->HIGHMEM)

Continue

if (*max_low < end)

*max_low = end;

}
}


The meaning of this function is obvious: by scanning all the information in the struct meminfo *mi = &meminfo; (an array of struct meminfo), set the variables referred to by three pointers:

Min: Memory Physical Address start
Max_low: End of physical address of low-end memory area
Max_high: Upper memory Area Physical Address end


As can be seen from the above, Max_low and Max_high Save the address is due to BANK->HIGHMEM caused, it is the memory bank is set as the basis for high-end memory:

"If this memory bank is high-end memory (Bank->highmem!) = 0), skip Max_low = end; statements, Max_low and Max_high will be different (results are actually max_high > Max_low);
Otherwise, assume that no memory bank is high-end memory (all Bank->highmem = = 0) Max_low and Max_high must be the same (high memory size is 0) "


Of course, in order to realize the function, it is necessary to ensure that all banks in the Meminfo index group are sorted according to the address data from small to large well. But don't worry about this, you'll see later:)

Following the above trace, the focus is on the global variables (in the same file):

/*
* This keeps memory configuration data used by a couple memory
* Initialization functions, as well as Show_mem () for the skipping
* of holes in the memory map. It is populated by Arm_add_memory ().
*/
struct Meminfo meminfo;


The definition of this struct (Setup.h (arch\arm\include\asm)):

/*

* Memory Map Description

*/
#define NR_BANKS 8/* Now arm Max only to 8 bank Oh ~*/

struct Membank {

phys_addr_t start;

unsigned long size;

unsigned int highmem; /* Variables We care about */

};

struct Meminfo {

int nr_banks;

struct Membank bank[nr_banks]; /* The array we care about */

};

extern struct Meminfo meminfo;

#define For_each_bank (ITER,MI) \

for (iter = 0; iter < (MI)->nr_banks; iter++)

#define BANK_PFN_START (Bank) __PHYS_TO_PFN (bank)->start

#define BANK_PFN_END (Bank) __PHYS_TO_PFN (Bank)->start + (bank)->size)

#define BANK_PFN_SIZE (Bank)->size >> Page_shift)

#define BANK_PHYS_START (Bank)->start

#define BANK_PHYS_END (Bank)->start + (bank)->size)

#define BANK_PHYS_SIZE (Bank)->size


Just find the place to initialize this global variable and complete the sorting, you can know how high-end memory is configured!! OK, clear target, go on~~~

By looking up the code, we can find the relevant code in the SETUP.C (arch\arm\kernel) file. Functions that will run in the early stages of the system startup (in specific order you can analyze the startup process of the arm kernel yourself, and I will write it later):

void __init Setup_arch (char **cmdline_p)

{

struct MACHINE_DESC *mdesc;

Unwind_init ();

Setup_processor ();

Mdesc = SETUP_MACHINE_FDT (__atags_pointer);

if (!MDESC)

Mdesc = Setup_machine_tags (Machine_arch_type);

Machine_desc = Mdesc;

Machine_Name = mdesc->name;

if (mdesc->soft_reboot)

Reboot_setup ("s");

Init_mm.start_code = (unsigned long) _text;

Init_mm.end_code = (unsigned long) _etext;

Init_mm.end_data = (unsigned long) _edata;

INIT_MM.BRK = (unsigned long) _end;

/* Fill Cmd_line for later use, maintain Boot_command_line */

strlcpy (Cmd_line, Boot_command_line, command_line_size); /* Copy data from Boot_command_line to Cmd_line */

*cmdline_p = Cmd_line;

Parse_early_param (); /* Parse the data in the Boot_command_line (kernel boot parameter string),

* The analysis of the [email protected] parameter initialization of the struct meminfo meminfo;

* At the same time, if the vmalloc=size parameter is also initialized Vmalloc_min */

Sanity_check_meminfo (); /* Set the HIGHMEM variable in each bank in the struct meminfo meminfo here,

* Determine if the memory in each bank belongs to high-end memory by Vmalloc_min */

Arm_memblock_init (&meminfo, Mdesc); /* Sort here sort by address data from small to large */

Paging_init (MDESC);

Request_standard_resources (MDESC);

Unflatten_device_tree ();

#ifdef CONFIG_SMP

if (IS_SMP ())

Smp_init_cpus ();

#endif

Reserve_crashkernel ();

Cpu_init ();

Tcm_init ();

#ifdef Config_multi_irq_handler

HANDLE_ARCH_IRQ = mdesc->handle_irq;

#endif

#ifdef CONFIG_VT

#if defined (config_vga_console)

CONSWITCHP = &vga_con;

#elif defined (config_dummy_console)

CONSWITCHP = &dummy_con;

#endif

#endif

Early_trap_init ();

if (mdesc->init_early)

Mdesc->init_early ();

}


In the comments above, I have indicated the emphasis and parsing, below which I refine:

(1) Get the Parameters section

by Parse_early_param (), the function can parse many strings in the kernel startup parameters, but for our analysis of memory, the following two parameters are analyzed:


[email protected] parameter, she is to initialize the struct meminfo meminfo; (We have been concerned about the memory information Oh ~) to provide information. Specific functions for obtaining information (also located in Setup.c (Arch\arm\kernel)):

Vmalloc=size parameter, she provides information for initializing the vmalloc_min (the size of the kernel virtual address space that needs to be preserved, that is, the address space that is removed from the logical address space in the kernel virtual address space and the necessary protection holes to prevent out of bounds). Specific implementation functions (in MMU.C (ARCH\ARM\MM)):

(2) After obtaining the necessary information (initialize the good struct meminfo meminfo and vmalloc_min), the kernel passes through the Sanity_check_meminfo function automatically through the VMALLOC_ Min information to initialize each meminfo.bank[? ] in the HIGHMEM member. If necessary in this procedure, the bank array in the Meminfo may be changed. The handler function is located in Mmu.c (ARCH\ARM\MM):

(3) The last thing to do is to sort, complete this work can be fully used by the Find_limits function we mentioned above, and this work is placed in the next Arm_memblock_init (&meminfo, Mdesc); In the beginning:

Through the above analysis, the whole high and low end memory is how to determine the basic is clear, here to summarize:

In the ARM architecture, the high-low segment memory is automatically configured by kernel boot parameters ([email protected] and vmalloc=size), and there is no high-end memory in the normal arm system without special configuration. Unless your system has large RAM or Vmalloc configuration, high-end memory is likely to occur.

Above is my high-low-end memory learning tracking code of the memo, if you find what is wrong in the place, welcome to shoot bricks, correct ~ ~ Thank you ~

Linux Kernel high-low-side memory setup code tracking (ARM architecture)

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.