Page 1 of 1

stack movement in JamesM tutorial

Posted: Mon Apr 23, 2012 4:39 am
by vjain20
Hi,

I am going though the Multitasking section of JamesM tutorial in which
a method is added to move stack from lower address to some higher address.

Code: Select all

void move_stack(void *new_stack_start, u32int size)
{
  u32int i;
  // Allocate some space for the new stack.
  for( i = (u32int)new_stack_start;
       i >= ((u32int)new_stack_start-size);
       i -= 0x1000)
  {
    // General-purpose stack is in user-mode.
    alloc_frame( get_page(i, 1, current_directory), 0 /* User mode */, 1 /* Is writable */ );
  }
  
  // Flush the TLB by reading and writing the page directory address again.
  u32int pd_addr;
  asm volatile("mov %%cr3, %0" : "=r" (pd_addr));
  asm volatile("mov %0, %%cr3" : : "r" (pd_addr));

  // Old ESP and EBP, read from registers.
  u32int old_stack_pointer; asm volatile("mov %%esp, %0" : "=r" (old_stack_pointer));
  u32int old_base_pointer;  asm volatile("mov %%ebp, %0" : "=r" (old_base_pointer));

  // Offset to add to old stack addresses to get a new stack address.
  u32int offset            = (u32int)new_stack_start - initial_esp;          // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  // New ESP and EBP.
  u32int new_stack_pointer = old_stack_pointer + offset;
  u32int new_base_pointer  = old_base_pointer  + offset;

  // Copy the stack.
  memcpy((void*)new_stack_pointer, (void*)old_stack_pointer, initial_esp-old_stack_pointer);

  // Backtrace through the original stack, copying new values into
  // the new stack.  
  for(i = (u32int)new_stack_start; i > (u32int)new_stack_start-size; i -= 4)
  {
    u32int tmp = * (u32int*)i;
    // If the value of tmp is inside the range of the old stack, assume it is a base pointer
    // and remap it. This will unfortunately remap ANY value in this range, whether they are
    // base pointers or not.
    if (( old_stack_pointer < tmp) && (tmp < initial_esp))
    {
      tmp = tmp + offset;
      u32int *tmp2 = (u32int*)i;
      *tmp2 = tmp;
    }
  }

  // Change stacks.
  asm volatile("mov %0, %%esp" : : "r" (new_stack_pointer));
  asm volatile("mov %0, %%ebp" : : "r" (new_base_pointer));
}
This method is called as - move_stack((void*)0xE0000000, 0x2000) while creating the first task.
What I am not able to understand is the calculation of offset (line marked by <<< above).
According to my understanding initial_esp should be the physical address of base of initial stack. However new_stack_start is the
virtual address of the base of new stack which might not be equal to its physical address. So adding the
offset to the current stack pointer might not give the virtual address of the base of the new stack.
Am I correct ?

Re: stack movement in JamesM tutorial

Posted: Mon Apr 23, 2012 8:15 am
by serviper
initial_esp points to the base of main's stack frame. Also, note that it is identity-mapped.

Re: stack movement in JamesM tutorial

Posted: Mon Apr 23, 2012 5:02 pm
by vjain20
serviper wrote:initial_esp points to the base of main's stack frame. Also, note that it is identity-mapped.
I understand that it is the base of main's stack frame and low addresses are identity-mapped. But new base of the stack - 0xE0000000 is around 3GB and
I don't think that it is identity-mapped. So subtracting initial_esp from 0XE0000000 should not give the correct address
as the actual physical address corresponding to 0xE0000000 might be different.
Am I correct?

Re: stack movement in JamesM tutorial

Posted: Tue Apr 24, 2012 9:11 am
by serviper
vjain20 wrote:
serviper wrote:initial_esp points to the base of main's stack frame. Also, note that it is identity-mapped.
I understand that it is the base of main's stack frame and low addresses are identity-mapped. But new base of the stack - 0xE0000000 is around 3GB and
I don't think that it is identity-mapped. So subtracting initial_esp from 0XE0000000 should not give the correct address
as the actual physical address corresponding to 0xE0000000 might be different.
Am I correct?
0xE0000000 is not identity-mapped, but it doesn't matter. initial_esp is identity-mapped so it's a physical address as well as a linear address.
Once you set up an address space, you would spend most of the time on linear address.

+----------------------+
| lower mem |
+----------------------+
| initial stack (lo) | <--- initial_stack (e.g, 0x67ec0)
+----------------------+
| ... |
+----------------------+
| new stack (hi) | <--- 0xE0000000
+----------------------+

The figure above shows what we see in the virtual address space.

Re: stack movement in JamesM tutorial

Posted: Tue Apr 24, 2012 5:33 pm
by vjain20
Got it! Thanks!

Re: stack movement in JamesM tutorial

Posted: Tue Apr 24, 2012 10:22 pm
by serviper
In fact, it is not necessary to perform such complex identity mapping for the kernel image and initial page directory/tables.
The tutorial uses LMA 0x100000 (=1MB) and VMA 0x100000, which may cause some problems when dealing with the higher memory. Using a high VMA (e.g, 3GB+1MB) and a low LMA (e.g, 1MB) may be a better way, I think.