diff options
-rw-r--r-- | sys/conf/files.ia64 | 1 | ||||
-rw-r--r-- | sys/conf/ldscript.ia64 | 10 | ||||
-rw-r--r-- | sys/ia64/ia64/efi.c | 6 | ||||
-rw-r--r-- | sys/ia64/ia64/exception.S | 36 | ||||
-rw-r--r-- | sys/ia64/ia64/genassym.c | 4 | ||||
-rw-r--r-- | sys/ia64/ia64/locore.S | 125 | ||||
-rw-r--r-- | sys/ia64/ia64/machdep.c | 93 | ||||
-rw-r--r-- | sys/ia64/ia64/mp_locore.S | 275 | ||||
-rw-r--r-- | sys/ia64/ia64/mp_machdep.c | 189 | ||||
-rw-r--r-- | sys/ia64/ia64/pmap.c | 44 | ||||
-rw-r--r-- | sys/ia64/ia64/sal.c | 12 | ||||
-rw-r--r-- | sys/ia64/include/ia64_cpu.h | 6 | ||||
-rw-r--r-- | sys/ia64/include/smp.h | 18 | ||||
-rw-r--r-- | sys/ia64/include/vmparam.h | 16 |
14 files changed, 527 insertions, 308 deletions
diff --git a/sys/conf/files.ia64 b/sys/conf/files.ia64 index a746cbb2b5e6..15ef939097fe 100644 --- a/sys/conf/files.ia64 +++ b/sys/conf/files.ia64 @@ -92,6 +92,7 @@ ia64/ia64/locore.S standard no-obj ia64/ia64/machdep.c standard ia64/ia64/mca.c standard ia64/ia64/mem.c optional mem +ia64/ia64/mp_locore.S optional smp ia64/ia64/mp_machdep.c optional smp ia64/ia64/nexus.c standard ia64/ia64/pal.S standard diff --git a/sys/conf/ldscript.ia64 b/sys/conf/ldscript.ia64 index 5d31ff44742c..8e0b297cc2f4 100644 --- a/sys/conf/ldscript.ia64 +++ b/sys/conf/ldscript.ia64 @@ -3,7 +3,7 @@ OUTPUT_FORMAT("elf64-ia64-freebsd", "elf64-ia64-freebsd", "elf64-ia64-freebsd") OUTPUT_ARCH(ia64) ENTRY(__start) SEARCH_DIR(/usr/lib); -kernel_text = 0xe000000004000000; +kernel_text = 0x9ffc000000000000; SECTIONS { /* Read-only sections, merged into text segment: */ @@ -11,10 +11,10 @@ SECTIONS .interp : { *(.interp) } PROVIDE (btext = .); - .ivt : { *(.ivt) } .text : { - *(.text.ivt) + *(.ivt) + *(.ivt.text) *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) @@ -60,9 +60,11 @@ SECTIONS page in the loader virtual memory. */ . = ALIGN(65536); + PROVIDE (bdata = .); .data : { - *(.data.kstack .data .data.* .gnu.linkonce.d.*) + *(.ivt.data) + *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } diff --git a/sys/ia64/ia64/efi.c b/sys/ia64/ia64/efi.c index 1ab86ede6339..5cd4518bcbe5 100644 --- a/sys/ia64/ia64/efi.c +++ b/sys/ia64/ia64/efi.c @@ -129,7 +129,7 @@ efi_boot_minimal(uint64_t systbl) setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual); status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size, bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version, - bootinfo->bi_memmap); + ia64_tpa(bootinfo->bi_memmap)); return ((status < 0) ? EFAULT : 0); } @@ -164,7 +164,7 @@ efi_md_first(void) if (bootinfo->bi_memmap == 0) return (NULL); - return ((struct efi_md *)IA64_PHYS_TO_RR7(bootinfo->bi_memmap)); + return ((struct efi_md *)bootinfo->bi_memmap); } struct efi_md * @@ -172,7 +172,7 @@ efi_md_next(struct efi_md *md) { uint64_t plim; - plim = IA64_PHYS_TO_RR7(bootinfo->bi_memmap + bootinfo->bi_memmap_size); + plim = bootinfo->bi_memmap + bootinfo->bi_memmap_size; md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size); return ((md >= (struct efi_md *)plim) ? NULL : md); } diff --git a/sys/ia64/ia64/exception.S b/sys/ia64/ia64/exception.S index cd1b15592c1a..7ff771a460bf 100644 --- a/sys/ia64/ia64/exception.S +++ b/sys/ia64/ia64/exception.S @@ -48,9 +48,16 @@ __FBSDID("$FreeBSD$"); * ar.k4 = PCPU data */ + .section .ivt.data, "aw" + + .global pmap_ptc_g_sem +pmap_ptc_g_sem: data8 0 + + .global ia64_kptdir +ia64_kptdir: data8 0 + #ifdef EXCEPTION_TRACING - .data .global xtrace, xhead xtrace: .space 1024*5*8 xhead: data8 xtrace @@ -101,7 +108,7 @@ xhead: data8 xtrace #endif - .section .text.ivt, "ax" + .section .ivt.text, "ax" /* * exception_save: save interrupted state @@ -129,7 +136,7 @@ ENTRY_NOPROFILE(exception_save, 0) ;; } { .mmi - cmp.le p14,p15=5,r31 + cmp.le p14,p15=IA64_VM_MINKERN_REGION,r31 ;; (p15) mov r23=ar.k7 // kernel memory stack (p14) mov r23=sp @@ -233,7 +240,7 @@ exception_save_restart: { .mmi st8 [r30]=r19,16 // rnat st8 [r31]=r0,16 // __spare - cmp.le p12,p13=5,r24 + cmp.le p12,p13=IA64_VM_MINKERN_REGION,r24 ;; } { .mmi @@ -602,7 +609,7 @@ ENTRY_NOPROFILE(exception_restore, 0) { .mmi ld8.fill r1=[r30],16 // gp ld8 r27=[r31],16 // ndirty - cmp.le p14,p15=5,r28 + cmp.le p14,p15=IA64_VM_MINKERN_REGION,r28 ;; } { .mmi @@ -915,7 +922,7 @@ IVT_ENTRY(Alternate_Instruction_TLB, 0x0c00) extr.u r17=r16,61,3 // get region number mov r19=PTE_PRESENT+PTE_ACCESSED+PTE_DIRTY+PTE_PL_KERN+PTE_AR_RWX ;; - cmp.eq p13,p0=4,r17 // RR4? + cmp.eq p13,p0=IA64_PBVM_RR,r17 // RR4? (p13) br.cond.sptk.few 4f ;; cmp.ge p13,p0=5,r17 // RR0-RR5? @@ -958,7 +965,7 @@ IVT_ENTRY(Alternate_Data_TLB, 0x1000) extr.u r17=r16,61,3 // get region number mov r19=PTE_PRESENT+PTE_ACCESSED+PTE_DIRTY+PTE_PL_KERN+PTE_AR_RWX ;; - cmp.eq p13,p0=4,r17 // RR4? + cmp.eq p13,p0=IA64_PBVM_RR,r17 // RR4? (p13) br.cond.sptk.few 4f ;; cmp.ge p13,p0=5,r17 // RR0-RR5? @@ -1007,21 +1014,22 @@ IVT_ENTRY(Data_Nested_TLB, 0x1400) // double nested faults. Since all virtual addresses we encounter // here are direct mapped region 7 addresses, we have no problem // constructing physical addresses. + { .mlx - rsm psr.dt + nop 0 movl r27=ia64_kptdir ;; } { .mii - srlz.d - dep r27=0,r27,61,3 - ;; + ld8 r27=[r27] extr.u r28=r30,3*PAGE_SHIFT-8, PAGE_SHIFT-3 // dir L0 index -} -{ .mii - ld8 r27=[r27] // dir L0 page extr.u r26=r30,2*PAGE_SHIFT-5, PAGE_SHIFT-3 // dir L1 index ;; +} +{ .mmi + rsm psr.dt + ;; + srlz.d dep r27=0,r27,61,3 ;; } diff --git a/sys/ia64/ia64/genassym.c b/sys/ia64/ia64/genassym.c index c8899a664be0..6adaa3386455 100644 --- a/sys/ia64/ia64/genassym.c +++ b/sys/ia64/ia64/genassym.c @@ -77,13 +77,13 @@ ASSYM(ERESTART, ERESTART); ASSYM(FRAME_SYSCALL, FRAME_SYSCALL); -ASSYM(IA64_ID_PAGE_SHIFT, IA64_ID_PAGE_SHIFT); - ASSYM(IA64_PBVM_BASE, IA64_PBVM_BASE); ASSYM(IA64_PBVM_PAGE_SHIFT, IA64_PBVM_PAGE_SHIFT); ASSYM(IA64_PBVM_PGTBL, IA64_PBVM_PGTBL); ASSYM(IA64_PBVM_RR, IA64_PBVM_RR); +ASSYM(IA64_VM_MINKERN_REGION, IA64_VM_MINKERN_REGION); + ASSYM(KSTACK_PAGES, KSTACK_PAGES); ASSYM(MC_PRESERVED, offsetof(mcontext_t, mc_preserved)); diff --git a/sys/ia64/ia64/locore.S b/sys/ia64/ia64/locore.S index b7b981c94ec3..b2d096953c66 100644 --- a/sys/ia64/ia64/locore.S +++ b/sys/ia64/ia64/locore.S @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2001-2011 Marcel Moolenaar * Copyright (c) 1998 Doug Rabson * All rights reserved. * @@ -26,12 +27,10 @@ * $FreeBSD$ */ -#include <sys/syscall.h> #include <machine/asm.h> #include <machine/ia64_cpu.h> #include <machine/intrcnt.h> #include <machine/pte.h> -#include <machine/intrcnt.h> #include <assym.s> /* @@ -40,7 +39,7 @@ */ #define FW_STACK_SIZE 3*PAGE_SIZE - .section .data.kstack, "aw" + .section .ivt.data, "aw" .align PAGE_SIZE .global kstack kstack: .space FW_STACK_SIZE @@ -82,7 +81,7 @@ ENTRY_NOPROFILE(__start, 1) } { .mlx mov ar.bspstore=r16 // switch backing store - movl r16=pa_bootinfo + movl r16=bootinfo ;; } { .mmi @@ -187,124 +186,6 @@ enter_userland: } END(fork_trampoline) -#ifdef SMP -/* - * AP wake-up entry point. The handoff state is similar as for the BSP, - * as described on page 3-9 of the IPF SAL Specification. The difference - * lies in the contents of register b0. For APs this register holds the - * return address into the SAL rendezvous routine. - * - * Note that we're responsible for clearing the IRR bit by reading cr.ivr - * and issuing the EOI to the local SAPIC. - */ - .align 32 -ENTRY_NOPROFILE(os_boot_rendez,0) - mov r16=cr.ivr // clear IRR bit - ;; - srlz.d - mov cr.eoi=r0 // ACK the wake-up - ;; - srlz.d - rsm IA64_PSR_IC|IA64_PSR_I - ;; - mov r16 = (5<<8)|(PAGE_SHIFT<<2)|1 - movl r17 = 5<<61 - ;; - mov rr[r17] = r16 - ;; - srlz.d - mov r16 = (6<<8)|(IA64_ID_PAGE_SHIFT<<2) - movl r17 = 6<<61 - ;; - mov rr[r17] = r16 - ;; - srlz.d - mov r16 = (7<<8)|(IA64_ID_PAGE_SHIFT<<2) - movl r17 = 7<<61 - ;; - mov rr[r17] = r16 - ;; - srlz.d - mov r18 = 28<<2 - movl r16 = PTE_PRESENT+PTE_MA_WB+PTE_ACCESSED+PTE_DIRTY+ \ - PTE_PL_KERN+PTE_AR_RWX+PTE_ED - ;; - mov cr.ifa = r17 - mov cr.itir = r18 - ptr.d r17, r18 - ptr.i r17, r18 - ;; - srlz.i - ;; - itr.d dtr[r0] = r16 - mov r18 = IA64_DCR_DEFAULT - ;; - itr.i itr[r0] = r16 - mov cr.dcr = r18 - ;; - srlz.i - ;; -1: mov r16 = ip - add r17 = 2f-1b, r17 - movl r18 = (IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_DFH|IA64_PSR_DT|IA64_PSR_IC|IA64_PSR_IT|IA64_PSR_RT) - ;; - add r17 = r17, r16 - mov cr.ipsr = r18 - mov cr.ifs = r0 - ;; - mov cr.iip = r17 - ;; - rfi - - .align 32 -2: -{ .mlx - mov ar.rsc = 0 - movl r16 = ia64_vector_table // set up IVT early - ;; -} -{ .mlx - mov cr.iva = r16 - movl r16 = ap_stack - ;; -} -{ .mmi - srlz.i - ;; - ld8 r16 = [r16] - mov r18 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16 - ;; -} -{ .mlx - mov ar.bspstore = r16 - movl gp = __gp - ;; -} -{ .mmi - loadrs - ;; - alloc r17 = ar.pfs, 0, 0, 0, 0 - add sp = r18, r16 - ;; -} -{ .mib - mov ar.rsc = 3 - nop 0 - br.call.sptk.few rp = ia64_ap_startup - ;; -} - /* NOT REACHED */ -9: -{ .mib - nop 0 - nop 0 - br.sptk 9b - ;; -} -END(os_boot_rendez) - -#endif /* !SMP */ - /* * Create a default interrupt name table. The first entry (vector 0) is * hardwaired to the clock interrupt. diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c index 49a49bba9005..41d2211bd124 100644 --- a/sys/ia64/ia64/machdep.c +++ b/sys/ia64/ia64/machdep.c @@ -115,7 +115,6 @@ SYSCTL_UINT(_hw_freq, OID_AUTO, itc, CTLFLAG_RD, &itc_freq, 0, int cold = 1; -u_int64_t pa_bootinfo; struct bootinfo *bootinfo; struct pcpu pcpu0; @@ -128,8 +127,9 @@ extern u_int64_t epc_sigtramp[]; struct fpswa_iface *fpswa_iface; -u_int64_t ia64_pal_base; -u_int64_t ia64_port_base; +vm_size_t ia64_pal_size; +vm_paddr_t ia64_pal_base; +vm_offset_t ia64_port_base; u_int64_t ia64_lapic_addr = PAL_PIB_DEFAULT_ADDR; @@ -548,15 +548,15 @@ map_vhpt(uintptr_t vhpt) pte |= vhpt & PTE_PPN_MASK; __asm __volatile("ptr.d %0,%1" :: "r"(vhpt), - "r"(IA64_ID_PAGE_SHIFT<<2)); + "r"(pmap_vhpt_log2size << 2)); __asm __volatile("mov %0=psr" : "=r"(psr)); __asm __volatile("rsm psr.ic|psr.i"); ia64_srlz_i(); ia64_set_ifa(vhpt); - ia64_set_itir(IA64_ID_PAGE_SHIFT << 2); + ia64_set_itir(pmap_vhpt_log2size << 2); ia64_srlz_d(); - __asm __volatile("itr.d dtr[%0]=%1" :: "r"(2), "r"(pte)); + __asm __volatile("itr.d dtr[%0]=%1" :: "r"(3), "r"(pte)); __asm __volatile("mov psr.l=%0" :: "r" (psr)); ia64_srlz_i(); } @@ -565,25 +565,36 @@ void map_pal_code(void) { pt_entry_t pte; + vm_offset_t va; + vm_size_t sz; uint64_t psr; + u_int shft; - if (ia64_pal_base == 0) + if (ia64_pal_size == 0) return; + va = IA64_PHYS_TO_RR7(ia64_pal_base); + + sz = ia64_pal_size; + shft = 0; + while (sz > 1) { + shft++; + sz >>= 1; + } + pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RWX; pte |= ia64_pal_base & PTE_PPN_MASK; - __asm __volatile("ptr.d %0,%1; ptr.i %0,%1" :: - "r"(IA64_PHYS_TO_RR7(ia64_pal_base)), "r"(IA64_ID_PAGE_SHIFT<<2)); + __asm __volatile("ptr.d %0,%1; ptr.i %0,%1" :: "r"(va), "r"(shft<<2)); __asm __volatile("mov %0=psr" : "=r"(psr)); __asm __volatile("rsm psr.ic|psr.i"); ia64_srlz_i(); - ia64_set_ifa(IA64_PHYS_TO_RR7(ia64_pal_base)); - ia64_set_itir(IA64_ID_PAGE_SHIFT << 2); + ia64_set_ifa(va); + ia64_set_itir(shft << 2); ia64_srlz_d(); - __asm __volatile("itr.d dtr[%0]=%1" :: "r"(1), "r"(pte)); + __asm __volatile("itr.d dtr[%0]=%1" :: "r"(4), "r"(pte)); ia64_srlz_d(); __asm __volatile("itr.i itr[%0]=%1" :: "r"(1), "r"(pte)); __asm __volatile("mov psr.l=%0" :: "r" (psr)); @@ -598,7 +609,7 @@ map_gateway_page(void) pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_X_RX; - pte |= (uint64_t)ia64_gateway_page & PTE_PPN_MASK; + pte |= ia64_tpa((uint64_t)ia64_gateway_page) & PTE_PPN_MASK; __asm __volatile("ptr.d %0,%1; ptr.i %0,%1" :: "r"(VM_MAXUSER_ADDRESS), "r"(PAGE_SHIFT << 2)); @@ -609,9 +620,9 @@ map_gateway_page(void) ia64_set_ifa(VM_MAXUSER_ADDRESS); ia64_set_itir(PAGE_SHIFT << 2); ia64_srlz_d(); - __asm __volatile("itr.d dtr[%0]=%1" :: "r"(3), "r"(pte)); + __asm __volatile("itr.d dtr[%0]=%1" :: "r"(5), "r"(pte)); ia64_srlz_d(); - __asm __volatile("itr.i itr[%0]=%1" :: "r"(3), "r"(pte)); + __asm __volatile("itr.i itr[%0]=%1" :: "r"(2), "r"(pte)); __asm __volatile("mov psr.l=%0" :: "r" (psr)); ia64_srlz_i(); @@ -681,17 +692,6 @@ ia64_init(void) */ /* - * pa_bootinfo is the physical address of the bootinfo block as - * passed to us by the loader and set in locore.s. - */ - bootinfo = (struct bootinfo *)(IA64_PHYS_TO_RR7(pa_bootinfo)); - - if (bootinfo->bi_magic != BOOTINFO_MAGIC || bootinfo->bi_version != 1) { - bzero(bootinfo, sizeof(*bootinfo)); - bootinfo->bi_kernend = (vm_offset_t)round_page(_end); - } - - /* * Look for the I/O ports first - we need them for console * probing. */ @@ -702,6 +702,7 @@ ia64_init(void) md->md_pages * EFI_PAGE_SIZE); break; case EFI_MD_TYPE_PALCODE: + ia64_pal_size = md->md_pages * EFI_PAGE_SIZE; ia64_pal_base = md->md_phys; break; } @@ -742,6 +743,25 @@ ia64_init(void) kernend = round_page(bootinfo->bi_kernend); /* + * Region 6 is direct mapped UC and region 7 is direct mapped + * WC. The details of this is controlled by the Alt {I,D}TLB + * handlers. Here we just make sure that they have the largest + * possible page size to minimise TLB usage. + */ + ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (PAGE_SHIFT << 2)); + ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (PAGE_SHIFT << 2)); + ia64_srlz_d(); + + /* + * Wire things up so we can call the firmware. + */ + map_pal_code(); + efi_boot_minimal(bootinfo->bi_systab); + ia64_xiv_init(); + ia64_sal_init(); + calculate_frequencies(); + + /* * Setup the PCPU data for the bootstrap processor. It is needed * by printf(). Also, since printf() has critical sections, we * need to initialize at least pc_curthread. @@ -750,6 +770,7 @@ ia64_init(void) ia64_set_k4((u_int64_t)pcpup); pcpu_init(pcpup, 0, sizeof(pcpu0)); dpcpu_init((void *)kernend, 0); + PCPU_SET(md.lid, ia64_get_lid()); kernend += DPCPU_SIZE; PCPU_SET(curthread, &thread0); @@ -760,26 +781,6 @@ ia64_init(void) /* OUTPUT NOW ALLOWED */ - if (ia64_pal_base != 0) { - ia64_pal_base &= ~IA64_ID_PAGE_MASK; - /* - * We use a TR to map the first 256M of memory - this might - * cover the palcode too. - */ - if (ia64_pal_base == 0) - printf("PAL code mapped by the kernel's TR\n"); - } else - printf("PAL code not found\n"); - - /* - * Wire things up so we can call the firmware. - */ - map_pal_code(); - efi_boot_minimal(bootinfo->bi_systab); - ia64_xiv_init(); - ia64_sal_init(); - calculate_frequencies(); - if (metadata_missing) printf("WARNING: loader(8) metadata is missing!\n"); diff --git a/sys/ia64/ia64/mp_locore.S b/sys/ia64/ia64/mp_locore.S new file mode 100644 index 000000000000..75f75a958c2f --- /dev/null +++ b/sys/ia64/ia64/mp_locore.S @@ -0,0 +1,275 @@ +/*- + * Copyright (c) 2011 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <machine/asm.h> +#include <machine/ia64_cpu.h> +#include <machine/pte.h> +#include <assym.s> + +/* + * AP wake-up entry point. The handoff state is similar as for the BSP, + * as described on page 3-9 of the IPF SAL Specification. The difference + * lies in the contents of register b0. For APs this register holds the + * return address into the SAL rendezvous routine. + * + * Note that we're responsible for clearing the IRR bit by reading cr.ivr + * and issuing the EOI to the local SAPIC. + */ + .align 32 +ENTRY_NOPROFILE(os_boot_rendez,0) +{ .mmi + st8 [gp] = gp // trace = 0x00 + mov r8 = cr.ivr // clear IRR bit + add r2 = 8, gp + ;; +} +{ .mmi + srlz.d + mov cr.eoi = r0 // ACK the wake-up + add r3 = 16, gp + ;; +} +{ .mmi + srlz.d + rsm IA64_PSR_IC | IA64_PSR_I + mov r16 = (IA64_PBVM_RR << 8) | (IA64_PBVM_PAGE_SHIFT << 2) + ;; +} +{ .mmi + srlz.d + st8 [gp] = r2 // trace = 0x08 + dep.z r17 = IA64_PBVM_RR, 61, 3 + ;; +} +{ .mlx + mov rr[r17] = r16 + movl r18 = IA64_PBVM_PGTBL + ;; +} +{ .mmi + srlz.i + ;; + st8 [gp] = r3 // trace = 0x10 + nop 0 + ;; +} +{ .mmi + ld8 r16 = [r2], 16 // as_pgtbl_pte + ld8 r17 = [r3], 16 // as_pgtbl_itir + nop 0 + ;; +} +{ .mmi + mov cr.itir = r17 + mov cr.ifa = r18 + nop 0 + ;; +} +{ .mmi + srlz.d + ptr.d r18, r17 + nop 0 + ;; +} +{ .mmi + srlz.d + st8 [gp] = r2 // trace = 0x18 + mov r8 = r0 + ;; +} +{ .mmi + itr.d dtr[r8] = r16 + ;; + srlz.d + mov r9 = r0 + ;; +} +{ .mmi + ld8 r16 = [r2], 16 // as_text_va + st8 [gp] = r3 // trace = 0x20 + add r8 = 1, r8 + ;; +} +{ .mmi + ld8 r17 = [r3], 16 // as_text_pte + ld8 r18 = [r2], 16 // as_text_itir + nop 0 + ;; +} +{ .mmi + mov cr.ifa = r16 + mov cr.itir = r18 + nop 0 + ;; +} +{ .mmi + srlz.d + ptr.d r16, r18 + nop 0 + ;; +} +{ .mmi + srlz.d + st8 [gp] = r3 // trace = 0x30 + nop 0 + ;; +} +{ .mmi + itr.d dtr[r8] = r17 + ;; + srlz.d + nop 0 +} +{ .mmi + st8 [gp] = r2 // trace = 0x38 + ptr.i r16, r18 + add r8 = 1, r8 + ;; +} +{ .mmi + srlz.i + ;; + itr.i itr[r9] = r17 + nop 0 + ;; +} +{ .mmi + srlz.i + ;; + ld8 r16 = [r3], 16 // as_data_va + add r9 = 1, r9 + ;; +} +{ .mmi + st8 [gp] = r3 // trace = 0x40 + ld8 r17 = [r2], 16 // as_data_pte + nop 0 + ;; +} +{ .mmi + mov cr.ifa = r16 + ld8 r18 = [r3], 16 // as_data_itir + nop 0 + ;; +} +{ .mmi + mov cr.itir = r18 + ;; + srlz.d + nop 0 + ;; +} +{ .mmi + ptr.d r16, r18 + ;; + srlz.d + mov r19 = IA64_DCR_DEFAULT + ;; +} +{ .mmi + itr.d dtr[r8] = r17 + ;; + srlz.d + add r8 = 1, r8 + ;; +} +{ .mmi + st8 [gp] = r2 // trace = 0x48 + ;; + ld8 r16 = [r2], 16 // as_kstack + nop 0 +} +{ .mmi + ld8 r17 = [r3], 16 // as_kstack_top + mov cr.dcr = r19 + nop 0 + ;; +} +{ .mlx + srlz.i + movl r18 = IA64_PSR_BN | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_IC | \ + IA64_PSR_RT | IA64_PSR_DFH + ;; +} +{ .mlx + mov cr.ipsr = r18 + movl r19 = ia64_vector_table // set up IVT early + ;; +} +{ .mlx + mov cr.iva = r19 + movl r18 = 1f + ;; +} +{ .mmi + mov cr.iip = r18 + mov cr.ifs = r0 + nop 0 + ;; +} +{ .mmb + srlz.d + st8 [gp] = r2 // trace = 0x58 + rfi + ;; +} + + .align 32 +1: +{ .mlx + mov ar.bspstore = r16 + movl gp = __gp + ;; +} +{ .mmi + loadrs + add sp = -16, r17 + nop 0 + ;; +} +{ .mmi + mov ar.rsc = 3 + ;; + alloc r18 = ar.pfs, 0, 0, 0, 0 + ;; +} +{ .mib + nop 0 + nop 0 + br.call.sptk.few rp = ia64_ap_startup + ;; +} + /* NOT REACHED */ +9: +{ .mib + nop 0 + nop 0 + br.sptk 9b + ;; +} +END(os_boot_rendez) diff --git a/sys/ia64/ia64/mp_machdep.c b/sys/ia64/ia64/mp_machdep.c index aef41087034b..5804f8cd69b7 100644 --- a/sys/ia64/ia64/mp_machdep.c +++ b/sys/ia64/ia64/mp_machdep.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/uuid.h> #include <machine/atomic.h> +#include <machine/bootinfo.h> #include <machine/cpu.h> #include <machine/fpu.h> #include <machine/intr.h> @@ -62,22 +63,18 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_extern.h> #include <vm/vm_kern.h> +extern uint64_t bdata[]; + MALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations"); void ia64_ap_startup(void); -#define LID_SAPIC(x) ((u_int)((x) >> 16)) -#define LID_SAPIC_ID(x) ((u_int)((x) >> 24) & 0xff) -#define LID_SAPIC_EID(x) ((u_int)((x) >> 16) & 0xff) -#define LID_SAPIC_SET(id,eid) (((id & 0xff) << 8 | (eid & 0xff)) << 16); -#define LID_SAPIC_MASK 0xffff0000UL +#define SAPIC_ID_GET_ID(x) ((u_int)((x) >> 8) & 0xff) +#define SAPIC_ID_GET_EID(x) ((u_int)(x) & 0xff) +#define SAPIC_ID_SET(id, eid) ((u_int)(((id) & 0xff) << 8) | ((eid) & 0xff)) -/* Variables used by os_boot_rendez and ia64_ap_startup */ -struct pcpu *ap_pcpu; -void *ap_stack; -volatile int ap_delay; -volatile int ap_awake; -volatile int ap_spin; +/* State used to wake and bootstrap APs. */ +struct ia64_ap_state ia64_ap_state; int ia64_ipi_ast; int ia64_ipi_highfp; @@ -87,6 +84,21 @@ int ia64_ipi_rndzvs; int ia64_ipi_stop; static u_int +sz2shft(uint64_t sz) +{ + uint64_t s; + u_int shft; + + shft = 12; /* Start with 4K */ + s = 1 << shft; + while (s < sz) { + shft++; + s <<= 1; + } + return (shft); +} + +static u_int ia64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf) { @@ -180,16 +192,27 @@ ia64_ap_startup(void) { uint64_t vhpt; - pcpup = ap_pcpu; + ia64_ap_state.as_trace = 0x100; + + ia64_set_rr(IA64_RR_BASE(5), (5 << 8) | (PAGE_SHIFT << 2) | 1); + ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (PAGE_SHIFT << 2)); + ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (PAGE_SHIFT << 2)); + ia64_srlz_d(); + + pcpup = ia64_ap_state.as_pcpu; ia64_set_k4((intptr_t)pcpup); + ia64_ap_state.as_trace = 0x108; + vhpt = PCPU_GET(md.vhpt); map_vhpt(vhpt); ia64_set_pta(vhpt + (1 << 8) + (pmap_vhpt_log2size << 2) + 1); ia64_srlz_i(); - ap_awake = 1; - ap_delay = 0; + ia64_ap_state.as_trace = 0x110; + + ia64_ap_state.as_awake = 1; + ia64_ap_state.as_delay = 0; map_pal_code(); map_gateway_page(); @@ -197,14 +220,14 @@ ia64_ap_startup(void) ia64_set_fpsr(IA64_FPSR_DEFAULT); /* Wait until it's time for us to be unleashed */ - while (ap_spin) + while (ia64_ap_state.as_spin) cpu_spinwait(); /* Initialize curthread. */ KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread")); PCPU_SET(curthread, PCPU_GET(idlethread)); - atomic_add_int(&ap_awake, 1); + atomic_add_int(&ia64_ap_state.as_awake, 1); while (!smp_started) cpu_spinwait(); @@ -253,18 +276,18 @@ cpu_mp_probe(void) } void -cpu_mp_add(u_int acpiid, u_int apicid, u_int apiceid) +cpu_mp_add(u_int acpi_id, u_int id, u_int eid) { struct pcpu *pc; - u_int64_t lid; void *dpcpu; - u_int cpuid; + u_int cpuid, sapic_id; - lid = LID_SAPIC_SET(apicid, apiceid); - cpuid = ((ia64_get_lid() & LID_SAPIC_MASK) == lid) ? 0 : smp_cpus++; + sapic_id = SAPIC_ID_SET(id, eid); + cpuid = (IA64_LID_GET_SAPIC_ID(ia64_get_lid()) == sapic_id) + ? 0 : smp_cpus++; KASSERT((all_cpus & (1UL << cpuid)) == 0, - ("%s: cpu%d already in CPU map", __func__, acpiid)); + ("%s: cpu%d already in CPU map", __func__, acpi_id)); if (cpuid != 0) { pc = (struct pcpu *)malloc(sizeof(*pc), M_SMP, M_WAITOK); @@ -274,23 +297,26 @@ cpu_mp_add(u_int acpiid, u_int apicid, u_int apiceid) } else pc = pcpup; - pc->pc_acpi_id = acpiid; - pc->pc_md.lid = lid; - all_cpus |= (1UL << cpuid); + pc->pc_acpi_id = acpi_id; + pc->pc_md.lid = IA64_LID_SET_SAPIC_ID(sapic_id); + + all_cpus |= (1UL << pc->pc_cpuid); } void cpu_mp_announce() { struct pcpu *pc; + uint32_t sapic_id; int i; for (i = 0; i <= mp_maxid; i++) { pc = pcpu_find(i); if (pc != NULL) { + sapic_id = IA64_LID_GET_SAPIC_ID(pc->pc_md.lid); printf("cpu%d: ACPI Id=%x, SAPIC Id=%x, SAPIC Eid=%x", - i, pc->pc_acpi_id, LID_SAPIC_ID(pc->pc_md.lid), - LID_SAPIC_EID(pc->pc_md.lid)); + i, pc->pc_acpi_id, SAPIC_ID_GET_ID(sapic_id), + SAPIC_ID_GET_EID(sapic_id)); if (i == 0) printf(" (BSP)\n"); else @@ -302,41 +328,76 @@ cpu_mp_announce() void cpu_mp_start() { + struct ia64_sal_result result; + struct ia64_fdesc *fd; struct pcpu *pc; - - ap_spin = 1; + uintptr_t state; + u_char *stp; + + state = ia64_tpa((uintptr_t)&ia64_ap_state); + fd = (struct ia64_fdesc *) os_boot_rendez; + result = ia64_sal_entry(SAL_SET_VECTORS, SAL_OS_BOOT_RENDEZ, + ia64_tpa(fd->func), state, 0, 0, 0, 0); + + ia64_ap_state.as_pgtbl_pte = PTE_PRESENT | PTE_MA_WB | + PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW | + (bootinfo->bi_pbvm_pgtbl & PTE_PPN_MASK); + ia64_ap_state.as_pgtbl_itir = sz2shft(bootinfo->bi_pbvm_pgtblsz) << 2; + ia64_ap_state.as_text_va = IA64_PBVM_BASE; + ia64_ap_state.as_text_pte = PTE_PRESENT | PTE_MA_WB | + PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RX | + (ia64_tpa(IA64_PBVM_BASE) & PTE_PPN_MASK); + ia64_ap_state.as_text_itir = bootinfo->bi_text_mapped << 2; + ia64_ap_state.as_data_va = (uintptr_t)bdata; + ia64_ap_state.as_data_pte = PTE_PRESENT | PTE_MA_WB | + PTE_ACCESSED | PTE_DIRTY | PTE_PL_KERN | PTE_AR_RW | + (ia64_tpa((uintptr_t)bdata) & PTE_PPN_MASK); + ia64_ap_state.as_data_itir = bootinfo->bi_data_mapped << 2; + + /* Keep 'em spinning until we unleash them... */ + ia64_ap_state.as_spin = 1; SLIST_FOREACH(pc, &cpuhead, pc_allcpu) { pc->pc_md.current_pmap = kernel_pmap; pc->pc_other_cpus = all_cpus & ~pc->pc_cpumask; - if (pc->pc_cpuid > 0) { - ap_pcpu = pc; - pc->pc_md.vhpt = pmap_alloc_vhpt(); - if (pc->pc_md.vhpt == 0) { - printf("SMP: WARNING: unable to allocate VHPT" - " for cpu%d", pc->pc_cpuid); - continue; - } - ap_stack = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP, - M_WAITOK); - ap_delay = 2000; - ap_awake = 0; - - if (bootverbose) - printf("SMP: waking up cpu%d\n", pc->pc_cpuid); - - ipi_send(pc, ia64_ipi_wakeup); - - do { - DELAY(1000); - } while (--ap_delay > 0); - pc->pc_md.awake = ap_awake; - - if (!ap_awake) - printf("SMP: WARNING: cpu%d did not wake up\n", - pc->pc_cpuid); - } else + /* The BSP is obviously running already. */ + if (pc->pc_cpuid == 0) { pc->pc_md.awake = 1; + continue; + } + + ia64_ap_state.as_pcpu = pc; + pc->pc_md.vhpt = pmap_alloc_vhpt(); + if (pc->pc_md.vhpt == 0) { + printf("SMP: WARNING: unable to allocate VHPT" + " for cpu%d", pc->pc_cpuid); + continue; + } + + stp = malloc(KSTACK_PAGES * PAGE_SIZE, M_SMP, M_WAITOK); + ia64_ap_state.as_kstack = stp; + ia64_ap_state.as_kstack_top = stp + KSTACK_PAGES * PAGE_SIZE; + + ia64_ap_state.as_trace = 0; + ia64_ap_state.as_delay = 2000; + ia64_ap_state.as_awake = 0; + + if (bootverbose) + printf("SMP: waking up cpu%d\n", pc->pc_cpuid); + + /* Here she goes... */ + ipi_send(pc, ia64_ipi_wakeup); + do { + DELAY(1000); + } while (--ia64_ap_state.as_delay > 0); + + pc->pc_md.awake = ia64_ap_state.as_awake; + + if (!ia64_ap_state.as_awake) { + printf("SMP: WARNING: cpu%d did not wake up (code " + "%#lx)\n", pc->pc_cpuid, + ia64_ap_state.as_trace - state); + } } } @@ -372,10 +433,10 @@ cpu_mp_unleash(void *dummy) } } - ap_awake = 1; - ap_spin = 0; + ia64_ap_state.as_awake = 1; + ia64_ap_state.as_spin = 0; - while (ap_awake != smp_cpus) + while (ia64_ap_state.as_awake != smp_cpus) cpu_spinwait(); if (smp_cpus != cpus || cpus != mp_ncpus) { @@ -432,21 +493,19 @@ ipi_all_but_self(int ipi) } /* - * Send an IPI to the specified processor. The lid parameter holds the - * cr.lid (CR64) contents of the target processor. Only the id and eid - * fields are used here. + * Send an IPI to the specified processor. */ void ipi_send(struct pcpu *cpu, int xiv) { - u_int lid; + u_int sapic_id; KASSERT(xiv != 0, ("ipi_send")); - lid = LID_SAPIC(cpu->pc_md.lid); + sapic_id = IA64_LID_GET_SAPIC_ID(cpu->pc_md.lid); ia64_mf(); - ia64_st8(&(ia64_pib->ib_ipi[lid][0]), xiv); + ia64_st8(&(ia64_pib->ib_ipi[sapic_id][0]), xiv); ia64_mf_a(); CTR3(KTR_SMP, "ipi_send(%p, %d): cpuid=%d", cpu, xiv, PCPU_GET(cpuid)); } diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c index 5e0689c7ad88..a1606422d0de 100644 --- a/sys/ia64/ia64/pmap.c +++ b/sys/ia64/ia64/pmap.c @@ -159,7 +159,8 @@ vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ * Kernel virtual memory management. */ static int nkpt; -struct ia64_lpte ***ia64_kptdir; +extern struct ia64_lpte ***ia64_kptdir; + #define KPTE_DIR0_INDEX(va) \ (((va) >> (3*PAGE_SHIFT-8)) & ((1<<(PAGE_SHIFT-3))-1)) #define KPTE_DIR1_INDEX(va) \ @@ -177,7 +178,7 @@ static uint64_t pmap_ptc_e_count2 = 2; static uint64_t pmap_ptc_e_stride1 = 0x2000; static uint64_t pmap_ptc_e_stride2 = 0x100000000; -volatile u_long pmap_ptc_g_sem; +extern volatile u_long pmap_ptc_g_sem; /* * Data for the RID allocator @@ -390,13 +391,18 @@ pmap_bootstrap() ; count = i+2; + /* + * Determine a valid (mappable) VHPT size. + */ TUNABLE_INT_FETCH("machdep.vhpt.log2size", &pmap_vhpt_log2size); if (pmap_vhpt_log2size == 0) pmap_vhpt_log2size = 20; - else if (pmap_vhpt_log2size < 15) - pmap_vhpt_log2size = 15; - else if (pmap_vhpt_log2size > 61) - pmap_vhpt_log2size = 61; + else if (pmap_vhpt_log2size < 16) + pmap_vhpt_log2size = 16; + else if (pmap_vhpt_log2size > 28) + pmap_vhpt_log2size = 28; + if (pmap_vhpt_log2size & 1) + pmap_vhpt_log2size--; base = 0; size = 1UL << pmap_vhpt_log2size; @@ -454,16 +460,6 @@ pmap_bootstrap() ia64_set_rr(IA64_RR_BASE(5), (5 << 8) | (PAGE_SHIFT << 2) | 1); /* - * Region 6 is direct mapped UC and region 7 is direct mapped - * WC. The details of this is controlled by the Alt {I,D}TLB - * handlers. Here we just make sure that they have the largest - * possible page size to minimise TLB usage. - */ - ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (IA64_ID_PAGE_SHIFT << 2)); - ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (IA64_ID_PAGE_SHIFT << 2)); - ia64_srlz_d(); - - /* * Clear out any random TLB entries left over from booting. */ pmap_invalidate_all(); @@ -1210,7 +1206,6 @@ vm_paddr_t pmap_kextract(vm_offset_t va) { struct ia64_lpte *pte; - vm_offset_t gwpage; KASSERT(va >= VM_MAXUSER_ADDRESS, ("Must be kernel VA")); @@ -1218,19 +1213,16 @@ pmap_kextract(vm_offset_t va) if (va >= IA64_RR_BASE(6)) return (IA64_RR_MASK(va)); - /* EPC gateway page? */ - gwpage = (vm_offset_t)ia64_get_k5(); - if (va >= gwpage && va < gwpage + PAGE_SIZE) - return (IA64_RR_MASK((vm_offset_t)ia64_gateway_page)); - /* Bail out if the virtual address is beyond our limits. */ if (va >= kernel_vm_end) return (0); - pte = pmap_find_kpte(va); - if (!pmap_present(pte)) - return (0); - return (pmap_ppn(pte) | (va & PAGE_MASK)); + if (va >= VM_MIN_KERNEL_ADDRESS) { + pte = pmap_find_kpte(va); + return (pmap_present(pte) ? pmap_ppn(pte)|(va&PAGE_MASK) : 0); + } + + return (0); } /* diff --git a/sys/ia64/ia64/sal.c b/sys/ia64/ia64/sal.c index 6f081be8601a..249113cc4623 100644 --- a/sys/ia64/ia64/sal.c +++ b/sys/ia64/ia64/sal.c @@ -101,10 +101,6 @@ ia64_sal_init(void) } case 5: { struct sal_ap_wakeup_descriptor *dp; -#ifdef SMP - struct ia64_sal_result result; - struct ia64_fdesc *fd; -#endif dp = (struct sal_ap_wakeup_descriptor*)p; if (dp->sale_mechanism != 0) { @@ -126,14 +122,6 @@ ia64_sal_init(void) if (bootverbose) printf("SAL: AP wake-up XIV: %#x\n", ia64_ipi_wakeup); - -#ifdef SMP - fd = (struct ia64_fdesc *) os_boot_rendez; - result = ia64_sal_entry(SAL_SET_VECTORS, - SAL_OS_BOOT_RENDEZ, ia64_tpa(fd->func), - ia64_tpa(fd->gp), 0, 0, 0, 0); -#endif - break; } } diff --git a/sys/ia64/include/ia64_cpu.h b/sys/ia64/include/ia64_cpu.h index d75fb1e94f72..92614fce628a 100644 --- a/sys/ia64/include/ia64_cpu.h +++ b/sys/ia64/include/ia64_cpu.h @@ -31,6 +31,12 @@ #define _MACHINE_IA64_CPU_H_ /* + * Local Interrupt ID. + */ +#define IA64_LID_GET_SAPIC_ID(x) ((u_int)((x) >> 16) & 0xffff) +#define IA64_LID_SET_SAPIC_ID(x) ((u_int)((x) & 0xffff) << 16) + +/* * Definition of DCR bits. */ #define IA64_DCR_PP 0x0000000000000001 diff --git a/sys/ia64/include/smp.h b/sys/ia64/include/smp.h index b1e54ee4a6d4..26557a712705 100644 --- a/sys/ia64/include/smp.h +++ b/sys/ia64/include/smp.h @@ -16,6 +16,24 @@ struct pcpu; +struct ia64_ap_state { + uint64_t as_trace; + uint64_t as_pgtbl_pte; + uint64_t as_pgtbl_itir; + uint64_t as_text_va; + uint64_t as_text_pte; + uint64_t as_text_itir; + uint64_t as_data_va; + uint64_t as_data_pte; + uint64_t as_data_itir; + void *as_kstack; + void *as_kstack_top; + struct pcpu *as_pcpu; + volatile int as_delay; + volatile u_int as_awake; + volatile u_int as_spin; +}; + extern int ia64_ipi_ast; extern int ia64_ipi_highfp; extern int ia64_ipi_nmi; diff --git a/sys/ia64/include/vmparam.h b/sys/ia64/include/vmparam.h index 5f4b09227c10..8cf3130f5be4 100644 --- a/sys/ia64/include/vmparam.h +++ b/sys/ia64/include/vmparam.h @@ -124,8 +124,8 @@ #define IA64_RR_BASE(n) (((uint64_t) (n)) << 61) #define IA64_RR_MASK(x) ((x) & ((1L << 61) - 1)) -#define IA64_PHYS_TO_RR6(x) ((x) | IA64_RR_BASE(6)) -#define IA64_PHYS_TO_RR7(x) ((x) | IA64_RR_BASE(7)) +#define IA64_PHYS_TO_RR6(x) ((x) | IA64_RR_BASE(6)) +#define IA64_PHYS_TO_RR7(x) ((x) | IA64_RR_BASE(7)) /* * The Itanium architecture defines that all implementations support at @@ -139,18 +139,6 @@ #define IA64_REGION_GAP_EXTEND 0x1ffc000000000000 /* - * Page size of the identity mappings in region 7. - */ -#ifndef LOG2_ID_PAGE_SIZE -#define LOG2_ID_PAGE_SIZE 28 /* 256M */ -#endif - -#define IA64_ID_PAGE_SHIFT (LOG2_ID_PAGE_SIZE) -#define IA64_ID_PAGE_SIZE (1<<(LOG2_ID_PAGE_SIZE)) -#define IA64_ID_PAGE_MASK (IA64_ID_PAGE_SIZE-1) - - -/* * Parameters for Pre-Boot Virtual Memory (PBVM). * The kernel, its modules and metadata are loaded in the PBVM by the loader. * The PBVM consists of pages for which the mapping is maintained in a page |