A question about function split_mem_range

valdis.kletnieks at vt.edu valdis.kletnieks at vt.edu
Sun Mar 25 16:48:43 EDT 2018


On Sun, 25 Mar 2018 22:32:42 +0800, Hao Lee said:

> In arch/x86/mm/init.c, there is a function called split_mem_range[0].
> Its logic is very complicated and I can't figure out what it does. I
> have added some debug statements in this function to print all
> variable, but I still can't understand it. I have also searched it on
> Google and couldn't find any helpful articles. Could someone give me
> some help about what on earth this function does? Many thanks!

Step 0: kernel functions are usually given somewhat descriptive names.
So what can we guess based on the function name?  That it performs some
sort of slicing and dicing of a memory range...

Step 1:  Use what you already know about the function. For example, it's under
arch/x86 - which means it has architecture dependencies. It's marked 'static
__meminit' - which means that (a) there's no direct calls from other files, and
(b) there probably isn't a call through an address pointer (because this code
may get freed and the memory reclaimed after __miminit is done).  And indeed,
'git grep' (or "grep -r') confirms the only other use is also in mm/init.c (and we
see no sign of an &split_mem_range() so it can't be called via pointer passed
elsewhere).

Step 2: look at the call site in init_memory_swapping(), which provides us this
nice block comment:

/*
 * Setup the direct mapping of the physical memory at PAGE_OFFSET.
 * This runs before bootmem is initialized and gets pages directly from
 * the physical memory. To access them they are temporarily mapped.
 */

Step 3: look at the code around the call site:

        memset(mr, 0, sizeof(mr));
        nr_range = split_mem_range(mr, 0, start, end);

        for (i = 0; i < nr_range; i++)
                ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
                                                   mr[i].page_size_mask);

So  before the call, mr[] is a whole lot of zeros.  After the call, the array
has a series of start/end/mask entries suitable for setting up a temporary
physical mapping.

>From this we can conclude that split_mem_range() is a helper function that
takes a range (for example "starting at the 0M address line and ending at the
512M address line") and returns a list of suitable ranges for mappings, while
applying some rules like "Don't use a hugepage for the first 4M on 32-bit".  So
what comes back is an array that basically says something like "Use a 4K page
at 0, a 4K page at 4K, a 4K at 8/12/... up to "4K at (2M-4))", a 2M hugepage at
2M, 4M... 508M. Or something else suitable for the kernel config (32/64 bit,
etc, look at the #ifdefs to figure out exactly what it does for a given address
location)

 (Actual  start and end are whatever the rest of the kernel decides, I couldn't
be bothered to chase down code that has a pr_debug() to print the numbers out
for anybody who care).

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 486 bytes
Desc: not available
URL: <http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20180325/d41bd9b8/attachment.sig>


More information about the Kernelnewbies mailing list