Mailing List Archive


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [tlug] about sanitize_e820_map()



On 15/01/06, Stephen J. Turnbull <stephen@example.com> wrote:

> >>>>> "Toshiyuki" == Toshiyuki Ishii <psbfan@example.com> writes:
>
>     Toshiyuki> I am a beginner of kernel source code, so sorry if I am
>     Toshiyuki> misunderstanding.
>
> This isn't exactly a kernel hackers group.  There are a few such here,
> but it's unlikely that they're familiar with every little bit.

I for one would like to see more hardcore C questions on this list, so
I will endeavor to help you out here.

You should, however, take Steve's advise about what info you need to
provide so that we can help you.

I will assume that you are concerned with the 2.6 kernel.

I first made an identifier search on LXR against the 2.6.11 source
tree to find the relevant code:

http://lxr.linux.no/ident?i=sanitize_e820_map

Then I performed a search on Safari[1] for 'e820', which led me to an
excellent section in "Understanding the Linux Kernel (3rd
Edition)"[2]: "A.3. Middle Ages: the setup( ) Function". I promptly
added the book to my Safari bookshelf so that I could read the whole
section (don't worry, I wanted to evaluate this book before buying
it[2] anyway).

A-ha! Now I know that sanitize_e820_map() has something to do with
ACPI, for the BIOS e820 map is a table describing the layout of a
system's physical memory, according to UtLK3e:

"setup( ) performs essentially the following operations:

   1.

      In ACPI -compliant systems, it invokes a BIOS routine that
builds a table in RAM describing the layout of the system's physical
memory (the table can be seen in the boot kernel messages by looking
for the "BIOS-e820" label). In older systems, it invokes a BIOS
routine that just returns the amount of RAM available in the system."

OK, back to the code. arch/i386/kernel/setup.c looks like the logical
place to start, based on the results of my LXR identifier search. It
looks like the section that you are referring to in your email starts
at line 517, right?

http://lxr.linux.no/source/arch/i386/kernel/setup.c#L517

Again, as Steve pointed out, tell us *where*: version of code, source
filename, line! And if there exists online a browseable version of the
code, link to it.

OK, for a little context, the BIOS e820 map (which is a map of
physical memory locations as reported by an ACPI-compliant BIOS) may
contain overlapping entries. The Linux kernel hates this, so it wants
to reconfigure the map as shown by the comment at lines 446-480[3]:

446         /*
447                 Visually we're performing the following (1,2,3,4 =
memory types)...
448
449                 Sample memory map (w/overlaps):
450                    ____22__________________
451                    ______________________4_
452                    ____1111________________
453                    _44_____________________
454                    11111111________________
455                    ____________________33__
456                    ___________44___________
457                    __________33333_________
458                    ______________22________
459                    ___________________2222_
460                    _________111111111______
461                    _____________________11_
462                    _________________4______
463
464                 Sanitized equivalent (no overlap):
465                    1_______________________
466                    _44_____________________
467                    ___1____________________
468                    ____22__________________
469                    ______11________________
470                    _________1______________
471                    __________3_____________
472                    ___________44___________
473                    _____________33_________
474                    _______________2________
475                    ________________1_______
476                    _________________4______
477                    ___________________2____
478                    ____________________33__
479                    ______________________4_
480         */

OK, so the section of code relevant to your question is:

514                 for (i=1; i < chg_nr; i++)  {
515                         /* if <current_addr> > <last_addr>, swap */
516                         /* or, if current=<start_addr> &
last=<end_addr>, swap */
517                         if ((change_point[i]->addr <
change_point[i-1]->addr) ||
518                                 ((change_point[i]->addr ==
change_point[i-1]->addr) &&
519                                  (change_point[i]->addr ==
change_point[i]->pbios->addr) &&
520                                  (change_point[i-1]->addr !=
change_point[i-1]->pbios->addr))
521                            )
522                         {
523                                 change_tmp = change_point[i];
524                                 change_point[i] = change_point[i-1];
525                                 change_point[i-1] = change_tmp;
526                                 still_changing=1;
527                         }
528                 }

We also need to know a little about the structures contained in the
change_point[] array[4]:

426 struct change_member {
427         struct e820entry *pbios; /* pointer to original bios entry */
428         unsigned long long addr; /* address for this change point */
429 };

So the 'addr' field of the struct refers to the address in our new
map, and pbios->addr is the address in the original e820 map.

I read this conditional as follows:

1) Line 517 checks to see if the address at the current index in our
map is less than the address at the previous index in our map. This
would be the most obvious way to detect an overlap. Short circuit,
jump to lines 523-526, where the overlap is repaired.
2a) Line 518 is the beginning of a logical condition with three parts;
the first part being: is the address (new) at the current index of the
map the same as the address (new) at the previous part? If not,
short-circuit, move to the next iteration of the for loop.
2b) Line 519 is the second part of the three-part condition. Is the
address (new) at the current index of the map the same as the address
(*old*; in the original e820 BIOS map) at the *current index*? If not,
short-circuit, move to the next iteration of the for loop.
2c) Line 520 is the third and final part of the condition. Is the
address (new) at the previous index different from the address (old)
at the previous index? If so, repair the overlap in the body of the if
condition.

So, let me try to show this in some sort of visual way. Note that
memory addresses are obviously wrong (I wanted a simple example, not
an accurate one). :)

Case 1 (covered by line 517):

change_point[]
                                    0        1        ...        i-1  
     i        ...        n
addr                                                           0x81    0x80
pbios->addr                                             ???      ???

In this case, we don't care what the addresses in the original e820
map are, since the address at index [i] is lower than the address at
index [i-1] (an obvious overlap).

But what if the addresses are the same? That is why we need case 2
(lines 518-520):

change_point[]
                                    0        1        ...        i-1  
     i        ...        n
addr                                                           0x80   
0x80                  <== (2a)
pbios->addr                                                         
0x80                  <== (2b)

The addresses at [i] and [i-1] in the current map are the same (2a),
so we have to look at the second line. Sure enough, the address at [i]
in the current map is the same as the address in the original BIOS map
(2b). And now to reveal the final bit of the diagram to evaluate
condition (2c):

change_point[]
                                    0        1        ...        i-1  
     i        ...        n
addr                                                           0x80    0x80
pbios->addr                            (2c) ==>  0x79    0x80

The address at [i-1] in the current map is *not* the same as the
address at [i-1] in the original BIOS map, so we have detected an
overlap and must repair it.

I hope this helped to answer your question.

Cheers,
Josh

[1] http://safari.oreilly.com/
[2] http://www.amazon.com/gp/product/0596005652/ref=wl_it_dp/103-0893130-9345430?%5Fencoding=UTF8&colid=220Z673P6NRWV&coliid=I38BV9O3U0AU2Y&v=glance&n=283155
[3] http://lxr.linux.no/source/arch/i386/kernel/setup.c#L446
[4] http://lxr.linux.no/source/arch/i386/kernel/setup.c#L426

Home | Main Index | Thread Index

Home Page Mailing List Linux and Japan TLUG Members Links