Re: ppc manual paging question

2007-10-26 Thread Wang, Baojun
On Monday 22 October 2007 16:04:14, Benjamin Herrenschmidt wrote:
  Yup, I've found how does the kernel handle tlbs, I think the most
  important thing is I forgot read/write the SPRN_SPRG3 register as _switch
  does.

 SPRG3 is for use by the operating system for whatever you want... if you
 are copying linux code, then you probably indeed want to get that right
 but you don't have to use SPRG3.

  I've add the _PAGE_PRESENT flag to the related PTE

 Hrm.. that has nothing ot do with the PTE. Bolting is more a property of
 your replacement algorithm in the TLB miss handler.

 Ben.

Hi,

  First thanks a lot for your help I've finish the tlb code, now I can 
manually translate the virtual address correctly, I verified this by printing 
out the data within the virtual address and it's fine. now the only thing 
left is jump to that address (the address is point to _start function), But I 
got an error about unable to access the stack (0xd100fc60 ...), but it is 
valid before the instruction:

/**
 * XXX: should not defined here
 */
#define EVENTS_USER_ADDR_OFFSET 36

_GLOBAL(jump_xm_dom)
stwur1,-INT_FRAME_SIZE(r1)
mflrr0
stw r0,INT_FRAME_SIZE+4(r1)

stw r31,INT_FRAME_SIZE+128(r1)

lwz r5,EVENTS_USER_ADDR_OFFSET(r4)
mr  r31,r5  /* new_domain-events_user_addr */

cmpwi   r3,0
beq 1f

mtctr   r3  /* jump to entry_point */
bctrl

li  r3,0
1:
lwz r31,INT_FRAME_SIZE+128(r1)

lwz r0,INT_FRAME_SIZE+4(r1)
addir1,r1,INT_FRAME_SIZE
mtlrr0
blr

the SP is valid before `bctrl', while exec bctrl, I got the error said unable 
to access address SP ($r1) from bdigdb, without bdigbd (running directly), an 
error is print out while the system is dead: 

insn: 94 21 ff 40 7c 08 02 a6 90 01 00 c4 7f e3 fb 78 3d 20 10 01 90 69 07 a0 
48 00 02 55 80 01 00 c4
$T0440:1094;01:d1072e60;#ee

address d1072e60 is the address of SP ($r1) before bctrl.

NOTE entry_point($r3) is address like 0x10a0 which is loaded from the 
userspace by a loader program (it loads all section marked as PT_LOAD, such 
as .text, the above insn is the entry of .text section, which is _start), but 
the above code is from the kernel space. and here is the _start function:

#define INT_FRAME_SIZE  192

.globl _start
_start:
stwu1, -INT_FRAME_SIZE(1)
mflr0
stw 0, INT_FRAME_SIZE+4(1)

mr  3,31/* new_domain-events_user_addr */

lis 9, [EMAIL PROTECTED]
stw 3, [EMAIL PROTECTED](9)
bl  kmain

lwz 0, INT_FRAME_SIZE+4(1);
mtlr0
addi1, 1, INT_FRAME_SIZE
blr

.size   _start, .-_start

I'm sorry I'm not very familiar with the ppc assembly, is there something 
fundamentally wrong? Thank you very much!

  Regards,
Wang

-- 
Wang, Baojun                                        Lanzhou University
Distributed  Embedded System Lab              http://dslab.lzu.edu.cn
School of Information Science and Engeneering       [EMAIL PROTECTED]
Tianshui South Road 222. Lanzhou 73                     .P.R.China
Tel:+86-931-8912025                                Fax:+86-931-8912022


signature.asc
Description: This is a digitally signed message part.
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Re: ppc manual paging question

2007-10-22 Thread Benjamin Herrenschmidt

 I'm porting an adeos nano kernel named xtratum (http://www.xtratum.org) from 
 x86 to ppc, I think I'm near the ending except the above problem. xtratum is 
 doing things like xen but it's much simpler (it's aimed for realtime), it 
 need provides memory space sperations for it's domains, so I need manually 
 paging. Each domain is loaded by a userspace program (instead of the root 
 domain as a kernel module), the loader will load the domain's (ELF staticly 
 excutable) PT_LOAD section into memory, and then raise a properly system call 
 (passing the structurized loaded data as arguments) to load the domain via 
 load_domain_sys(), and at the last step of loading the domain, xtratum will 
 jump to the entry code of the new domain(asm wrappered start() routine) and 
 then everything should be fine. The problem now is as follow:
 
 under my ppc (440GR/440EP) platform, start() is always at 0x10a0, but I 
 guess there is something wrong with my mm code so after the domain is loaded, 
 the virt addres 0x10a0 just point to garbage instead of the right start() 
 routine. So how can I setup paging properly so that the virtual memory could 
 be translated to proper data?

Are you aware that the 440 MMU doesn't actually know what a page table
is and doesn't load PTEs from memory ?

It's a software loaded TLB, you'll have to put translations in the TLB
yourself. You'll need to design your own data structures for that, tho
you can use a page table for tracking, like we do in linux, and then
have your own TLB miss handler to fill the TLB from that.

Your initial code probably need to bolt a TLB entry for the kernel
itself.

Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: ppc manual paging question

2007-10-22 Thread Wang, Baojun
On Monday 22 October 2007 14:01:33, Benjamin Herrenschmidt wrote:
  I'm porting an adeos nano kernel named xtratum (http://www.xtratum.org)
  from x86 to ppc, I think I'm near the ending except the above problem.
  xtratum is doing things like xen but it's much simpler (it's aimed for
  realtime), it need provides memory space sperations for it's domains, so
  I need manually paging. Each domain is loaded by a userspace program
  (instead of the root domain as a kernel module), the loader will load the
  domain's (ELF staticly excutable) PT_LOAD section into memory, and then
  raise a properly system call (passing the structurized loaded data as
  arguments) to load the domain via load_domain_sys(), and at the last step
  of loading the domain, xtratum will jump to the entry code of the new
  domain(asm wrappered start() routine) and then everything should be fine.
  The problem now is as follow:
 
  under my ppc (440GR/440EP) platform, start() is always at 0x10a0, but
  I guess there is something wrong with my mm code so after the domain is
  loaded, the virt addres 0x10a0 just point to garbage instead of the
  right start() routine. So how can I setup paging properly so that the
  virtual memory could be translated to proper data?

 Are you aware that the 440 MMU doesn't actually know what a page table
 is and doesn't load PTEs from memory ?
Sorry I didn't realized that. I've finished looking pem64b.pdf, but it's 
almost nothing like in ppc 4xx/44x.
 It's a software loaded TLB, you'll have to put translations in the TLB
 yourself. You'll need to design your own data structures for that, tho
 you can use a page table for tracking, like we do in linux, and then
 have your own TLB miss handler to fill the TLB from that.
OK, Shall I look for the DataTLBError code in head.S? I realized that I've got 
DataTLBError sometimes via BDI2000/kgdb (the fault address is within 
DataTLBError), Shall I should also look for arch/ppc/mm/fault.c?
 Your initial code probably need to bolt a TLB entry for the kernel
 itself.
I don't understand this clearly, how can I do this?
 Ben.

  Regards,
Wang


-- 
Wang, Baojun                                        Lanzhou University
Distributed  Embedded System Lab              http://dslab.lzu.edu.cn
School of Information Science and Engeneering       [EMAIL PROTECTED]
Tianshui South Road 222. Lanzhou 73                     .P.R.China
Tel:+86-931-8912025                                Fax:+86-931-8912022
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Re: ppc manual paging question

2007-10-22 Thread Benjamin Herrenschmidt

 Sorry I didn't realized that. I've finished looking pem64b.pdf, but it's 
 almost nothing like in ppc 4xx/44x.

You'll have to get yourself a 44x manual :-)

  It's a software loaded TLB, you'll have to put translations in the TLB
  yourself. You'll need to design your own data structures for that, tho
  you can use a page table for tracking, like we do in linux, and then
  have your own TLB miss handler to fill the TLB from that.

 OK, Shall I look for the DataTLBError code in head.S? I realized that I've 
 got 
 DataTLBError sometimes via BDI2000/kgdb (the fault address is within 
 DataTLBError), Shall I should also look for arch/ppc/mm/fault.c?

head_44x.S is where you'll find some guidance

  Your initial code probably need to bolt a TLB entry for the kernel
  itself.
 I don't understand this clearly, how can I do this?

Well, you insert a TLB entry manually and avoid replacing it later on

Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: ppc manual paging question

2007-10-22 Thread Wang, Baojun
On Monday 22 October 2007 15:34:24, Benjamin Herrenschmidt wrote:
  Sorry I didn't realized that. I've finished looking pem64b.pdf, but it's
  almost nothing like in ppc 4xx/44x.

 You'll have to get yourself a 44x manual :-)

   It's a software loaded TLB, you'll have to put translations in the TLB
   yourself. You'll need to design your own data structures for that, tho
   you can use a page table for tracking, like we do in linux, and then
   have your own TLB miss handler to fill the TLB from that.
 
  OK, Shall I look for the DataTLBError code in head.S? I realized that
  I've got DataTLBError sometimes via BDI2000/kgdb (the fault address is
  within DataTLBError), Shall I should also look for arch/ppc/mm/fault.c?

 head_44x.S is where you'll find some guidance
Yup, I've found how does the kernel handle tlbs, I think the most important 
thing is I forgot read/write the SPRN_SPRG3 register as _switch does.
   Your initial code probably need to bolt a TLB entry for the kernel
   itself.
 
  I don't understand this clearly, how can I do this?

 Well, you insert a TLB entry manually and avoid replacing it later on
I've add the _PAGE_PRESENT flag to the related PTE
 Ben.

Thanks very much I'm now getting much clearer about my question:)


  Regards,
Wang

-- 
Wang, Baojun                                        Lanzhou University
Distributed  Embedded System Lab              http://dslab.lzu.edu.cn
School of Information Science and Engeneering       [EMAIL PROTECTED]
Tianshui South Road 222. Lanzhou 73                     .P.R.China
Tel:+86-931-8912025                                Fax:+86-931-8912022


signature.asc
Description: This is a digitally signed message part.
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Re: ppc manual paging question

2007-10-22 Thread Benjamin Herrenschmidt

 Yup, I've found how does the kernel handle tlbs, I think the most important 
 thing is I forgot read/write the SPRN_SPRG3 register as _switch does.

SPRG3 is for use by the operating system for whatever you want... if you
are copying linux code, then you probably indeed want to get that right
but you don't have to use SPRG3.

 I've add the _PAGE_PRESENT flag to the related PTE

Hrm.. that has nothing ot do with the PTE. Bolting is more a property of
your replacement algorithm in the TLB miss handler.

Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


ppc manual paging question

2007-10-21 Thread Wang, Baojun
hi,

  I've got some qeustion about ppc(ppc44x) paging: 

how can I manually map a virtual address to a physical address through a 
specific pgd? How does ppc translate virt address to physical one? I think 
besides from tlb, the CPU will search the page table entries via the pgd, can 
I alter the pgd value to change the memory translation? under i386, it's very 
simple, we can just rewrite %%cr3, it even could invalidate all tlb entries 
automatically, how can I do this under ppc? I've tried rewrite 
current-mm-pgd and current-thread.pgdir, but sounds like it still not 
insufficiant, am I missing something vital? 

Any hint will be greatly approciated.

  Regards,
Wang

P.S:

here is the code:

#define save_pd(pd) ((pd) = (unsigned long)(current-mm-pgd))
#define load_pd(pd) (current-mm-pgd = (pd))

...

static inline pgd_t* __pgd_offset(unsigned long pgd_base, unsigned long va)
{
return (pgd_t*)((pgd_t*)pgd_base + pgd_index(va));
}

static inline pte_t* pte_offset(pmd_t* pte_base, unsigned long va)
{
return (pte_t*)((pte_t*)pte_base + pte_index(va));
}

static inline unsigned long get_free_pages_atomic(int order)
{
return __get_free_pages(GFP_ATOMIC, order);
}

...

unsigned long create_page_directory (unsigned long (*alloc_page) (void)) {
  unsigned long pd, c_pd;
  unsigned long idx;

  save_pd(c_pd);

  pd = get_free_pages_atomic(PGD_ORDER);
  if(!pd)   return 0;

  memset((void*)pd, 0, PGD_ORDER  PAGE_SHIFT);

  /*
   * copy kernel page directies
   */
  idx = pgd_index(PAGE_OFFSET);
  memcpy((pgd_t*)pd + idx, (pgd_t*)c_pd + idx, (PTRS_PER_PGD - idx) * 
sizeof(pgd_t));

  printk(KERN_EMERGcreate_page_directory return: 0x%lx, c_pd: 0x%lx\n, pd, 
c_pd);

  return pd;
}

/*
 * allocate a user page at @vaddress if possible
 * TODO: add tlb/slb/bat for fast page/block address translation
 */
unsigned long allocate_user_page (unsigned long pd,
unsigned long vaddress,
unsigned long (*alloc_page) (void)) {
pgd_t* pgd;
pud_t* pud;
pmd_t* pmd;
pte_t* pte;
unsigned long page = 0;

#define mm_debugprintk
mm_debug(allocate_user_page(0x%lx, 0x%lx, 0x%lx)\n, pd, vaddress, 
alloc_page);

pgd = __pgd_offset(pd, vaddress);
if(!pgd_present(*pgd) || !(*pgd)){
pud_t* pud_entry = (pud_t*)get_free_pages_atomic(PUD_ORDER);
if(!pud_entry)  return 0;
*pgd = __pa(pud_entry)  PAGE_MASK;
mm_debug(!pgd_present, pgd: 0x%lx, *pgd: 0x%lx\n, pgd, 
*pgd);
}

pud = pud_offset(pgd, vaddress);
if(!pud_present(*pud) || !(*pud)){
pmd_t* pmd_entry = (pmd_t*)get_free_pages_atomic(PMD_ORDER);
if(!pmd_entry)  return 0;
*pud = __pa(pmd_entry)  PAGE_MASK;
mm_debug(!pud_present, pud: 0x%lx, *pud: 0x%lx\n, pud, 
*pud);
}

pmd = pmd_offset(pud, vaddress);
if(!pmd_present(*pmd) || !(*pmd)){
pte_t* pte_entry = (pte_t*)get_free_pages_atomic(PTE_ORDER);
if(!pte_entry)  return 0;
*pmd = __pa(pte_entry)  PAGE_MASK;
*pmd |= _PMD_PRESENT;
mm_debug(!pmd_present, pmd: 0x%lx, *pmd: 0x%lx\n, pmd, 
*pmd);
}

pte = pte_offset(pmd, vaddress);
if(!pte_present(*pte) || !(*pte) || pte_none(*pte)){
unsigned long pfn;

page = get_free_pages_atomic(PAGE_ORDER);
mm_debug(page: 0x%lx\n, page);
pfn = __pa(page)  PAGE_MASK;
mm_debug(pfn: 0x%lx\n, pfn);
set_pte_at(current-mm, page, pte, pfn_pte(pfn  PAGE_SHIFT, 
__pgprot(PAGE_SHARED_X)));
mm_debug(pte_present now?: %lld\n, pte_present(*pte));
mm_debug(!pte_present, pte: 0x%lx\n, pte);
}

mm_debug(allocate_user_page: return 0x%lx\n, page);

#undef  mm_debug
return page;
}

-- 
Wang, Baojun                                        Lanzhou University
Distributed  Embedded System Lab              http://dslab.lzu.edu.cn
School of Information Science and Engeneering       [EMAIL PROTECTED]
Tianshui South Road 222. Lanzhou 73                     .P.R.China
Tel:+86-931-8912025                                Fax:+86-931-8912022
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: ppc manual paging question

2007-10-21 Thread Nicholas Mc Guire
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1


  I've got some qeustion about ppc(ppc44x) paging:

 how can I manually map a virtual address to a physical address through a
 specific pgd? How does ppc translate virt address to physical one? I think
 besides from tlb, the CPU will search the page table entries via the pgd, can
 I alter the pgd value to change the memory translation? under i386, it's very
 simple, we can just rewrite %%cr3, it even could invalidate all tlb entries
 automatically, how can I do this under ppc? I've tried rewrite
 current-mm-pgd and current-thread.pgdir, but sounds like it still not
 insufficiant, am I missing something vital?


sur ! same thing flush the tlb 
or you will be totally inconsistant - actually the box should not
have survived this treatment in a stable manner. You might want to
look at kernel/ppc-stub.c as a good reference - its a similar problem
gdb also writes into memory without the kernel knowing about it - that
is comparable to what XM is doing - the solution flush the cache/tlb
all over the place - now flushing the cache is evil - but I would do
it for now and we can check alternatives and optimizations later - for
now brute force is the way to go.

for 4xx dont forget to isync after fidling with pgd/pte (see set_context
in entry_4xx.S . As far as I understand 4xx all you would really need to
do is clear the TLB entry and then you get an exception and that is
handled via 0x1100/0x1200 D/I respectively (head_4xx.S) - admitedly Im
not up to this task - need to give the manuals a lock my self to 
understand whats going on there ;)

hofrat
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFHHCmpnU7rXZKfY2oRAjLmAJ90QwCBHLaglOfJ5QAnJyCCIZDmGwCgh/fD
E76Ki1FdfofUSuVBXL1tG0M=
=/1C5
-END PGP SIGNATURE-
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: ppc manual paging question

2007-10-21 Thread Benjamin Herrenschmidt

On Mon, 2007-10-22 at 12:03 +0800, Wang, Baojun wrote:
 hi,
 
   I've got some qeustion about ppc(ppc44x) paging: 
 
 how can I manually map a virtual address to a physical address through a 
 specific pgd? How does ppc translate virt address to physical one? I think 
 besides from tlb, the CPU will search the page table entries via the pgd, can 
 I alter the pgd value to change the memory translation? under i386, it's very 
 simple, we can just rewrite %%cr3, it even could invalidate all tlb entries 
 automatically, how can I do this under ppc? I've tried rewrite 
 current-mm-pgd and current-thread.pgdir, but sounds like it still not 
 insufficiant, am I missing something vital? 

What the heck are you trying to do ? Please explain and I'll tell you
how to do it properly :-)

Cheers,
Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: ppc manual paging question

2007-10-21 Thread Wang, Baojun
On Monday 22 October 2007 12:50:52, Benjamin Herrenschmidt wrote:
 On Mon, 2007-10-22 at 12:03 +0800, Wang, Baojun wrote:
  hi,
 
I've got some qeustion about ppc(ppc44x) paging:
 
  how can I manually map a virtual address to a physical address through a
  specific pgd? How does ppc translate virt address to physical one? I
  think besides from tlb, the CPU will search the page table entries via
  the pgd, can I alter the pgd value to change the memory translation?
  under i386, it's very simple, we can just rewrite %%cr3, it even could
  invalidate all tlb entries automatically, how can I do this under ppc?
  I've tried rewrite
  current-mm-pgd and current-thread.pgdir, but sounds like it still not
  insufficiant, am I missing something vital?

 What the heck are you trying to do ? Please explain and I'll tell you
 how to do it properly :-)

I'm porting an adeos nano kernel named xtratum (http://www.xtratum.org) from 
x86 to ppc, I think I'm near the ending except the above problem. xtratum is 
doing things like xen but it's much simpler (it's aimed for realtime), it 
need provides memory space sperations for it's domains, so I need manually 
paging. Each domain is loaded by a userspace program (instead of the root 
domain as a kernel module), the loader will load the domain's (ELF staticly 
excutable) PT_LOAD section into memory, and then raise a properly system call 
(passing the structurized loaded data as arguments) to load the domain via 
load_domain_sys(), and at the last step of loading the domain, xtratum will 
jump to the entry code of the new domain(asm wrappered start() routine) and 
then everything should be fine. The problem now is as follow:

under my ppc (440GR/440EP) platform, start() is always at 0x10a0, but I 
guess there is something wrong with my mm code so after the domain is loaded, 
the virt addres 0x10a0 just point to garbage instead of the right start() 
routine. So how can I setup paging properly so that the virtual memory could 
be translated to proper data?

I can describe in more detail if neccessary.

Thanks very much for take care.

  Regards,
Wang

P.S:

The orignal xtratum (x86) code:

#define load_pd(pd) {\
  __asm__ __volatile__ (movl %0,%%cr3: :r (__pa(pd))); \
}

#define save_pd(pd) {\
  __asm__ __volatile__ (movl %%cr3, %0\n\t: =r (pd) :); \
  pd = (unsigned long) __va (pd); \
}

...

// Virtual address to page directory entry
#define va2pd(vaddress) ((vaddress)  PGDIR_SHIFT)

// Virtual address to page table entry
#define va2pt(vaddress) (((vaddress)  0x3FF000)  PAGE_SHIFT)

// Page directory and page table to virtual address
#define pdpt2va(pd, pt) (((pd)  PGDIR_SHIFT) | ((pt)  PAGE_SHIFT))

// Next macro allows to obtain a pt address through the page directory
#define get_pd_addr(pd, pd_entry) \
  ((unsigned long) __va (((unsigned long *)(pd)) [(pd_entry)]  PAGE_MASK))

// And the following one allows to  obtain a page address via the page
// table
#define get_pt_addr(pt, pt_entry) \
  ((unsigned long)__va (((unsigned long *)*(pt)) [(pt_entry)]  PAGE_MASK))

...

static inline void fill_pd_entry (unsigned long pd,
 unsigned long pd_entry,
 unsigned long pt,
 unsigned long flags) {
  ((unsigned long *)pd) [pd_entry] =
((__pa (pt)  PAGE_MASK) | (flags  0xFFF));
}

static inline void fill_pt_entry (unsigned long pt,
 unsigned long pt_entry,
 unsigned long page,
 unsigned long flags) {
  ((unsigned long *)pt) [pt_entry] =
((__pa (page)  PAGE_MASK) | (flags  0xFFF));
}

...

static inline unsigned long create_page_directory (unsigned long
   (*alloc_page) (void)) {
  unsigned long pd = (*alloc_page) (), c_pd;

  if (!pd) return pd;
  save_pd(c_pd);

  memset  ((unsigned char *) ((unsigned long *) pd)[0],
   0, 1024 * sizeof (unsigned long));

  memcpy ((unsigned char *) ((unsigned long *) pd)[va2pd(PAGE_OFFSET)],
  (unsigned char *) ((unsigned long *) c_pd)[va2pd(PAGE_OFFSET)],
  (1024 - va2pd(PAGE_OFFSET)) * sizeof (unsigned long));

  return pd;
}

static inline unsigned long allocate_user_page (unsigned long pd,
unsigned long vaddress,
unsigned long (*alloc_page)
(void)) {
  unsigned long pt_entry = va2pt(vaddress),
pd_entry = va2pd(vaddress), pt, page = 0;

  if (vaddress = PAGE_OFFSET) return 0;

  // Check if there is already an allocated pt in the pd table
  if (!(((unsigned long *)pd) [pd_entry]  _PAGE_PRESENT)) {
if (!(pt = (unsigned long) (*alloc_page) ())) return 0;
fill_pd_entry (pd, pd_entry,
   pt, _PAGE_PRESENT | _PAGE_RW | _PAGE_USER);
  } else
pt = get_pd_addr(pd, pd_entry);