Re: ppc manual paging question
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
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
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
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
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
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
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
-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
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
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);