Multitasking...

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
nullify

Re:Multitasking...

Post by nullify »

For a full task switch, the task structures are usually located in kernel memory, which is mapped into the address space of every task.

Threads of a task all share a common address space, so there is no need to reload CR3. The thread structures should be mapped into the address space also. Details depend on whether your threading implementation is in kernel space or user space.
BI lazy

Re:Multitasking...

Post by BI lazy »

To avoid misunderstanding, use clear language *Mister* FlashBurn!

To solve your problem do as nullify recommends: map kernel space into each process adress space.

further - a process may own a *page directory*

stay safe
kaos

Re:Multitasking...

Post by kaos »

I think that the following method could be used to determine whether or not a hardware task switch that does not change the value of CR3 would cause a TLB flush:

1. Enable paging, etc.
2. Do a task switch via interrupt though a task gate in the IDT without changing the value of CR3.
3. Immediately do a TLB lookup on the address of the instruction that actually triggered the interrupt. The procedure for doing TLB lookups is described in 10.6.3 of the 80386 Programmer's Reference Manual.
4. If the TLB entry exists then the TLB has not been flushed. Otherwise, the TLB has been flushed.

This is only intended to apply to the 80386 processor.

Any thoughts?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Multitasking...

Post by Pype.Clicker »

another trick would be to modify one of the page entries just after you switched to another task (for instance making it not present), and then try to reference it without having done the required pginvld command on that page.

1. if the task switch did not flush the TLB (and if the page has been referenced before the switch and not yet referenced in the new task), the old entry should still be there and your reference is correct.

2. if the task switch did flush the TLB, the MMU will reload the new entry and discover it is not a present page, so you'll get a page fault.

Afaik, this test should work on any processor.
kaos

Re:Multitasking...

Post by kaos »

Pype.Clicker wrote: another trick would be to modify one of the page entries just after you switched to another task (for instance making it not present), and then try to reference it without having done the required pginvld command on that page.

1. if the task switch did not flush the TLB (and if the page has been referenced before the switch and not yet referenced in the new task), the old entry should still be there and your reference is correct.

2. if the task switch did flush the TLB, the MMU will reload the new entry and discover it is not a present page, so you'll get a page fault.

Afaik, this test should work on any processor.
Pype.Clicker: I thought your idea was a good one, so I wrote the following test:

Code: Select all

#define TLB_TEST_PAGE_VADDR ((void *) 0x10000000)

void tlb_test_interrupt(void)
{
  char *p = TLB_TEST_PAGE_VADDR;

  *p = 1;
  kprintf("The test was successful!\n");
  for(;;);
}

void tlb_test(void)
{
  void *page = page_alloc();
  thread_t *t;
  char *stack = page_alloc();
  char *p = TLB_TEST_PAGE_VADDR;
  uint ptdi, ptei;            /* pagetable directory and entry indexes */
  machine_pagetable_t *pagetable;

  /* install the interrupt */
  t = systhread_new (stack + PAGE_SIZE - 4, tlb_test_interrupt);
  I386_GATE_INIT_SYS (idt[0xff], t->tss_sel, 0);

  /* map the page */
  page_map(kernel_pdir, page, TLB_TEST_PAGE_VADDR, 1, 0);
  __asm__ __volatile__ ("mov %cr3, %eax");
  __asm__ __volatile__ ("mov %eax,%cr3");

  /* access *p just to make sure that everything is cool */
  *p = 1;

  /* do the test */
  kprintf("Time for the TLB flush test!\n");

  /* unmap the page, accessing *p at the last possible moment */
  ptdi = I386_VADDR_GET_PTDI (p);
  ptei = I386_VADDR_GET_PTEI (p);
  pagetable = I386_PTE_GET_PADDR (kernel_pdir[ptdi]);
  *p = 0;
  I386_PTE_CLEAR_PRESENT (pagetable[ptei]);

  /* interrupt */
  __asm__ __volatile__ ("int $0xff");
}
When I ran this in Bochs, the test failed. I am not sure how accurately Bochs emulates the i386 TLB, so I will be interested in seeing this run on actual processors. A floppy disk image of the kernel that was used for testing is attached. The entire source can be made available if someone is interested.



[attachment deleted by admin]
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Multitasking...

Post by Pype.Clicker »

good job. I'll try to test it on my own CPU asap.
Post Reply