Tuesday, July 27, 2010

Linux kernel decompression

/*
 247 * Check to see if we will overwrite ourselves.
 248 *   r4 = final kernel address
 249 *   r5 = start of this image
 250 *   r2 = end of malloc space (and therefore this image)
 251 * We basically want:
 252 *   r4 >= r2 -> OK
 253 *   r4 + image length <= r5 -> OK
 254 */
We have R4=0x80008000, R5=0x80008000, R2=0x8016E668, R6=0x00555860(imagelen), R7=0x060A
We compare R4 with R2 to see if we ever overwrite. Since we do, we need to adjust it
R0= R4+R6=0x8055D860
cmp r0, r5 and see if we dont overwrite.
In our case, we still fail, so need more adjustment.
We will simply change the decompressing addr. to one above malloc space(R2=0x8016E668)
mov     r5, r2                  @ decompress after malloc space
 264                mov     r0, r5
 265                mov     r3, r7
 266                bl      decompress_kernel
decompress_kernel is a function() defined in linux/arch/arm/boot/compressed/misc.c
 
This function decompresses the kernel. Note that if we have putc and getc defined, we 
see a print of "Uncompressing Linux..." when we start to decompress kernel.
In our case, we have sucn a definition done in 
\linux-2.6\arch\arm\mach-puppybeagle\include\mach\uncompress.h file
 
 
NOT SURE OF BELOW EXPLANATION!
ALL WE KNOW IS WE SAVE ALL ARGS PASSED TO FUNCTION PRINT UNCOMPRESS....JUMP DO_DECOMPRESS
@  
Here, he starts reading certain offset entries found at address 0x80008A60, 0x80008A64, 0x80008A68, 
and 0x80008A68, adds them up to the base address 0x8015D618(GOT START) and save them in the BSS section.
These offset entries are found to be ATAGs passed by the Bootloader.
 
So ATAGS @0x80008A60
GOT START @ 0x8015D618
BSS Entry value = value @ [GOTSTART+ ATAG] 
 
Decompress function is a standard C function that compresses the zImage and returns back.

We have decompressed from 0x8016E668(mallocspace end) till 0x8043B4E8 (Image size of 0x002CCE80)

Now copy relocation code:

reloc_start code addr:  R2=@0x80008380
LC1 label:   R3=@0x80008814
End of Decompxd. kernel: R1@0x8043B4E8

Now copy data from R2(0x80008380) and store it @R1(0x8043B4E8), ie after decompressed image
We do this copying until R2 == R3 (1172 Bytes)

Also, relocate Stack. SP now points to R13=0x8043BA18

Do a cache_clean_flush
    -> Calls call_cache_fn
        -> Searches for appropriate proctype flush call (In our case, its __armv7_mmu_cache_flush)
            ->Jumps to Hierarchial
                loop along loop3 3-4 times
                loop along loop2 2-3 times
                loop along loop1 2 times

            finally pop up, invalidate caches and return to __armv7_mmu_cache_off
            here again, invalidate TLB, BTC, DSB, ISB

We at the end returned to reloc_start:





Now call relocation code:

ARM(           add     pc, r5, r0              ) @ call relocation code
 294 THUMB(         add     r12, r5, r0             )
 295 THUMB(         mov     pc, r12                 ) @ call relocation code
 296
 
 
/*
 537 * All code following this line is relocatable.  It is relocated by
 538 * the above code to the end of the decompressed kernel image and
 539 * executed there.  During this time, we have no stacks.
 540 *
 541 * r0     = decompressed kernel length
 542 * r1-r3  = unused
 543 * r4     = kernel execution address
 544 * r5     = decompressed kernel start
 545 * r7     = architecture ID
 546 * r8     = atags pointer
 547 * r9-r12,r14 = corrupted
 548 */

 Fig: State of the code with only first line of the  relocation code is executed:


From fig, we see that R9 holds the source_end addr. We decrement this addr. by 128 bytes to skip copying stack. So, R9=@0x8043B468. We see that R4 holds the expected kernel execution address.(0x80008000)
R1 = R4
R5=@0x8016E668 holds the start addr of the source.
We start copying this image code from R5 and store it at addr pointed to by R1

After relocating kernel image, relocate stack as ell. New stack is now R13=@0x802D4EE0

With everything relocated, do a cache flush and turn cache off.

    call_kernel:    bl      cache_clean_flush
 567                bl      cache_off


Finally call kernel placed at exact 0x80008000 location!


mov     r0, #0                  @ must be zero
 569                mov     r1, r7                  @ restore architecture number
 570                mov     r2, r8                  @ restore atags pointer
 571                mov     pc, r4                  @ call kernel

Note R4 value, at which control flow jumps to!



After this, we enter start label inside actual kernel code for the first time!
/arch/arm/kernel/head.S
ENTRY(stext)

No comments:

Post a Comment