Skip to contentSkip to conversation

allow kernel to be virtually mapped from any physi

PATCH In review Luck, Tony 1 participant 2 messages Oct 15, 2002 – Oct 16, 2002

Subsystems (2)
lore
Share & tools
lore

Luck, Tony

author
#0 lore raw

PATCH 1/1 allow kernel to be virtually mapped from any physi

The current ia64 kernel expects to be loaded at physical 68MB (KERNEL_START in asm-ia64/system.h). This is a problem for machines that do not guarantee the presence of memory at that address (e.g. ccNUMA platforms that configure memory based on which nodes exist).

I bundled a solution to this in my earlier discontig patch (and included other features like kernel text replication, which made the patch far to large to be accepted).

This patch provides just the code needed to virtually map the kernel to a fixed virtual address from whatever physical address it happened to be loaded at (it is assumed that the bootloader handled the issue of finding a suitably aligned piece of memory).

Almost all of the code is inside CONFIG_IA64_VMAP_KERNEL, there are a few exceptions:

1) the "switch_mode" routine in head.S (which toggles between running in virtual and physical mode) has been split into separate "switch_mode_phys" and "switch_mode_virt" and the callers changed to use the appropriate one.

2) There are new macros "__tpa()" and "__imva()" defined in pgtable.h, versions are provided for the both the 'Y' and 'N' state of CONFIG_IA64_VMAP_KERNEL, so that these may be used freely in code without adding a zillion extra #ifdefs

3) fs/proc/kcore.c is currently broken (and has been for a long time) because ia64 defines VMALLOC_START at a lower address that PAGE_START. Try to access a vmalloc'd address to see the breakage. This patch fixes that in changes *not* bracketed with CONFIG_IA64_VMAP_KERNEL as well as providing the extra ELF Phdr for the virtually mapped kernel inside the #ifdef.

4) I put the empty_zero_page changes inside #ifdef, but they could be generic (avoids calling virt_to_page() a lot, which may be a good thing).

-Tony

arch/ia64/Config.help renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/Config.help +6 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/Config.help aegl/arch/ia64/Config.help
@@ -567,3 +567,9 @@
 
   Select "16MB" for a small granule size.
   Select "64MB" for a large granule size.  This is the current default.
+
+CONFIG_IA64_VMAP_KERNEL
+  If you say Y here, the kernel will be configured to map the kernel
+  to the top 4GB of the 64-bit virtual space.  This is needed for
+  certain ccNUMA machines that do not guarantee the presence of
+  memory at any particular physical address.
arch/ia64/config.in renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/config.in +2 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/config.in aegl/arch/ia64/config.in
@@ -71,6 +71,8 @@
 	define_bool CONFIG_IOSAPIC y
 fi
 
+bool 'Virtual mapped kernel' CONFIG_IA64_VMAP_KERNEL
+
 if [ "$CONFIG_IA64_SGI_SN1" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ]; then
 	define_bool CONFIG_IA64_SGI_SN y
 	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG
arch/ia64/kernel/efi_stub.S renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/efi_stub.S +2 -2
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/efi_stub.S aegl/arch/ia64/kernel/efi_stub.S
@@ -62,7 +62,7 @@
 	mov b6=r2
 	;;
 	andcm r16=loc3,r16		// get psr with IT, DT, and RT bits cleared
-	br.call.sptk.many rp=ia64_switch_mode
+	br.call.sptk.many rp=ia64_switch_mode_phys
 .ret0:	mov out4=in5
 	mov out0=in1
 	mov out1=in2
@@ -73,7 +73,7 @@
 	br.call.sptk.many rp=b6		// call the EFI function
 .ret1:	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3
-	br.call.sptk.many rp=ia64_switch_mode // return to virtual mode
+	br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
 .ret2:	mov ar.rsc=loc4			// restore RSE configuration
 	mov ar.pfs=loc1
 	mov rp=loc0
arch/ia64/kernel/entry.S renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/entry.S +9 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/entry.S aegl/arch/ia64/kernel/entry.S
@@ -175,6 +175,14 @@
 	;;
 	st8 [r22]=sp			// save kernel stack pointer of old task
 	shr.u r26=r20,IA64_GRANULE_SHIFT
+#ifdef CONFIG_IA64_VMAP_KERNEL
+	adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
+	;;
+	/*
+	 * If we've already mapped this task's page, we can skip doing it again.
+	 */
+	cmp.eq p7,p6=r26,r27
+#else
 	shr.u r17=r20,KERNEL_TR_PAGE_SHIFT
 	;;
 	cmp.ne p6,p7=KERNEL_TR_PAGE_NUM,r17
@@ -184,6 +192,7 @@
 	 * If we've already mapped this task's page, we can skip doing it again.
 	 */
 (p6)	cmp.eq p7,p6=r26,r27
+#endif
 (p6)	br.cond.dpnt .map
 	;;
 .done:
arch/ia64/kernel/head.S renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/head.S +101 -13

172 lines not on this page · raw message

arch/ia64/kernel/ia64_ksyms.c renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/ia64_ksyms.c +3 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/ia64_ksyms.c aegl/arch/ia64/kernel/ia64_ksyms.c
@@ -143,3 +143,6 @@
 #endif
 EXPORT_SYMBOL(machvec_noop);
 
+#ifdef CONFIG_IA64_VMAP_KERNEL
+EXPORT_SYMBOL(zero_page_memmap_ptr);
+#endif
arch/ia64/kernel/ivt.S renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/ivt.S +20 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/ivt.S aegl/arch/ia64/kernel/ivt.S
@@ -122,8 +122,18 @@
 	shr.u r18=r22,PGDIR_SHIFT		// get bits 33-63 of the faulting address
 	;;
 (p7)	dep r17=r17,r19,(PAGE_SHIFT-3),3	// put region number bits in place
+#ifdef CONFIG_IA64_VMAP_KERNEL
+	.global ia64_ivt_patch1
+ia64_ivt_patch1:
+{	.mlx // we patch this bundle to include physical address of swapper_pg_dir
+	srlz.d					// ensure "rsm psr.dt" has taken effect
+(p6)	movl r19=swapper_pg_dir			// region 5 is rooted at swapper_pg_dir
+}
+	.pred.rel "mutex", p6, p7
+#else
 	srlz.d					// ensure "rsm psr.dt" has taken effect
 (p6)	movl r19=__pa(swapper_pg_dir)		// region 5 is rooted at swapper_pg_dir
+#endif
 (p6)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT
 (p7)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3
 	;;
@@ -415,8 +425,18 @@
 	shr.u r18=r16,PGDIR_SHIFT		// get bits 33-63 of faulting address
 	;;
 (p7)	dep r17=r17,r19,(PAGE_SHIFT-3),3	// put region number bits in place
+#ifdef CONFIG_IA64_VMAP_KERNEL
+	.global ia64_ivt_patch2
+ia64_ivt_patch2:
+{	.mlx // we patch this bundle to include physical address of swapper_pg_dir
+	srlz.d					// ensure "rsm psr.dt" has taken effect
+(p6)	movl r19=swapper_pg_dir			// region 5 is rooted at swapper_pg_dir
+}
+#else
 	srlz.d
 (p6)	movl r19=__pa(swapper_pg_dir)		// region 5 is rooted at swapper_pg_dir
+#endif
+	.pred.rel "mutex", p6, p7
 (p6)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT
 (p7)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3
 	;;
arch/ia64/kernel/mca.c renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/mca.c +8 -8
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/mca.c aegl/arch/ia64/kernel/mca.c
@@ -434,17 +434,17 @@
 
 	IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n");
 
-	ia64_mc_info.imi_mca_handler        = __pa(mca_hldlr_ptr->fp);
+	ia64_mc_info.imi_mca_handler        = __tpa(mca_hldlr_ptr->fp);
 	/*
 	 * XXX - disable SAL checksum by setting size to 0; should be
-	 *	__pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
+	 *	__tpa(ia64_os_mca_dispatch_end) - __tpa(ia64_os_mca_dispatch);
 	 */
 	ia64_mc_info.imi_mca_handler_size	= 0;
 
 	/* Register the os mca handler with SAL */
 	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
 				       ia64_mc_info.imi_mca_handler,
-				       mca_hldlr_ptr->gp,
+				       __tpa(mca_hldlr_ptr->gp),
 				       ia64_mc_info.imi_mca_handler_size,
 				       0, 0, 0)))
 	{
@@ -454,15 +454,15 @@
 	}
 
 	IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n",
-		       ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp);
+		       ia64_mc_info.imi_mca_handler, __tpa(mca_hldlr_ptr->gp));
 
 	/*
 	 * XXX - disable SAL checksum by setting size to 0, should be
 	 * IA64_INIT_HANDLER_SIZE
 	 */
-	ia64_mc_info.imi_monarch_init_handler		= __pa(mon_init_ptr->fp);
+	ia64_mc_info.imi_monarch_init_handler		= __tpa(mon_init_ptr->fp);
 	ia64_mc_info.imi_monarch_init_handler_size	= 0;
-	ia64_mc_info.imi_slave_init_handler		= __pa(slave_init_ptr->fp);
+	ia64_mc_info.imi_slave_init_handler		= __tpa(slave_init_ptr->fp);
 	ia64_mc_info.imi_slave_init_handler_size	= 0;
 
 	IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n",
@@ -471,10 +471,10 @@
 	/* Register the os init handler with SAL */
 	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
 				       ia64_mc_info.imi_monarch_init_handler,
-				       __pa(ia64_get_gp()),
+				       __tpa(ia64_get_gp()),
 				       ia64_mc_info.imi_monarch_init_handler_size,
 				       ia64_mc_info.imi_slave_init_handler,
-				       __pa(ia64_get_gp()),
+				       __tpa(ia64_get_gp()),
 				       ia64_mc_info.imi_slave_init_handler_size)))
 	{
 		printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n",
arch/ia64/kernel/pal.S renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/pal.S +8 -4
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/pal.S aegl/arch/ia64/kernel/pal.S
@@ -164,7 +164,11 @@
 	;; 
 	mov loc4=ar.rsc			// save RSE configuration
 	dep.z loc2=loc2,0,61		// convert pal entry point to physical
+#ifdef CONFIG_IA64_VMAP_KERNEL
+	tpa r8=r8			// convert rp to physical
+#else
 	dep.z r8=r8,0,61		// convert rp to physical
+#endif
 	;;
 	mov b7 = loc2			// install target to branch reg
 	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
@@ -174,13 +178,13 @@
 	or loc3=loc3,r17		// add in psr the bits to set
 	;;
 	andcm r16=loc3,r16		// removes bits to clear from psr
-	br.call.sptk.many rp=ia64_switch_mode
+	br.call.sptk.many rp=ia64_switch_mode_phys
 .ret1:	mov rp = r8			// install return address (physical)
 	br.cond.sptk.many b7
 1:
 	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3			// r16= original psr
-	br.call.sptk.many rp=ia64_switch_mode // return to virtual mode
+	br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
 .ret2:
 	mov psr.l = loc3		// restore init PSR
 
@@ -228,13 +232,13 @@
 	mov b7 = loc2			// install target to branch reg
 	;;
 	andcm r16=loc3,r16		// removes bits to clear from psr
-	br.call.sptk.many rp=ia64_switch_mode
+	br.call.sptk.many rp=ia64_switch_mode_phys
 .ret6:
 	br.call.sptk.many rp=b7		// now make the call
 .ret7:
 	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3			// r16= original psr
-	br.call.sptk.many rp=ia64_switch_mode	// return to virtual mode
+	br.call.sptk.many rp=ia64_switch_mode_virt	// return to virtual mode
 
 .ret8:	mov psr.l  = loc3		// restore init PSR
 	mov ar.pfs = loc1
arch/ia64/kernel/setup.c renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/setup.c +49 -2

69 lines not on this page · raw message

arch/ia64/kernel/smpboot.c renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/smpboot.c +1 -1
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/kernel/smpboot.c aegl/arch/ia64/kernel/smpboot.c
@@ -522,7 +522,7 @@
 	/* Tell SAL where to drop the AP's.  */
 	ap_startup = (struct fptr *) start_ap;
 	sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
-				       __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0);
+				       __tpa(ap_startup->fp), __tpa(ap_startup->gp), 0, 0, 0, 0);
 	if (sal_ret < 0)
 		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret));
 }
arch/ia64/mm/init.c renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/mm/init.c +14 -5
diff -ru ../../REF/linux-2.5.39-ia64-020928/arch/ia64/mm/init.c aegl/arch/ia64/mm/init.c
@@ -39,6 +39,10 @@
 
 static int pgt_cache_water[2] = { 25, 50 };
 
+#ifdef CONFIG_IA64_VMAP_KERNEL
+struct page *zero_page_memmap_ptr;		/* map entry for zero page */
+#endif
+
 void
 check_pgt_cache (void)
 {
@@ -104,14 +108,16 @@
 void
 free_initmem (void)
 {
-	unsigned long addr;
+	unsigned long addr, eaddr;
 
-	addr = (unsigned long) &__init_begin;
-	for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) {
+	addr = (unsigned long)__imva(&__init_begin);
+	eaddr = (unsigned long)__imva(&__init_end);
+	while (addr < eaddr) {
 		ClearPageReserved(virt_to_page(addr));
 		set_page_count(virt_to_page(addr), 1);
 		free_page(addr);
 		++totalram_pages;
+		addr += PAGE_SIZE;
 	}
 	printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n",
 	       (&__init_end - &__init_begin) >> 10);
@@ -286,7 +292,7 @@
 	ia64_srlz_d();
 
 	ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
-		 pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PAGE_SHIFT);
+		 pte_val(pfn_pte(__tpa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PAGE_SHIFT);
 
 	ia64_set_psr(psr);
 	ia64_srlz_i();
@@ -364,6 +370,9 @@
 		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
 	}
 	free_area_init(zones_size);
+#ifdef CONFIG_IA64_VMAP_KERNEL
+	zero_page_memmap_ptr = virt_to_page(__imva(empty_zero_page));
+#endif
 }
 
 static int
@@ -442,7 +451,7 @@
 		pgt_cache_water[1] = num_pgt_pages;
 
 	/* install the gate page in the global page table: */
-	put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR);
+	put_gate_page(virt_to_page(__imva(__start_gate_section)), GATE_ADDR);
 
 #ifdef CONFIG_IA32_SUPPORT
 	ia32_gdt_init();
arch/ia64/vmlinux.lds.S renamed from ../REF/linux-2.5.39-ia64-020928/arch/ia64/vmlinux.lds.S +33 -27

170 lines not on this page · raw message

fs/proc/kcore.c renamed from ../REF/linux-2.5.39-ia64-020928/fs/proc/kcore.c +50 -9

118 lines not on this page · raw message

include/asm-ia64/page.h renamed from ../REF/linux-2.5.39-ia64-020928/include/asm-ia64/page.h +7 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/include/asm-ia64/page.h aegl/include/asm-ia64/page.h
@@ -106,6 +106,13 @@
  */
 #define __pa(x)		({ia64_va _v; _v.l = (long) (x); _v.f.reg = 0; _v.l;})
 #define __va(x)		({ia64_va _v; _v.l = (long) (x); _v.f.reg = -1; _v.p;})
+#ifdef CONFIG_IA64_VMAP_KERNEL
+#define __tpa(x)	({ia64_va _v; asm("tpa %0=%1" : "=r"(_v.l) : "r"(x)); _v.l;})
+#define __imva(x)	((long)__va(__tpa(x)))
+#else
+#define __tpa(x)	__pa(x)
+#define __imva(x)	(x)
+#endif
 
 #define REGION_NUMBER(x)	({ia64_va _v; _v.l = (long) (x); _v.f.reg;})
 #define REGION_OFFSET(x)	({ia64_va _v; _v.l = (long) (x); _v.f.off;})
include/asm-ia64/pgtable.h renamed from ../REF/linux-2.5.39-ia64-020928/include/asm-ia64/pgtable.h +7 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/include/asm-ia64/pgtable.h aegl/include/asm-ia64/pgtable.h
@@ -415,7 +415,12 @@
  * for zero-mapped memory areas etc..
  */
 extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
+#ifdef CONFIG_IA64_VMAP_KERNEL
+extern struct page *zero_page_memmap_ptr;
+#define ZERO_PAGE(vaddr) (zero_page_memmap_ptr)
+#else
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+#endif
 
 /* We provide our own get_unmapped_area to cope with VA holes for userland */
 #define HAVE_ARCH_UNMAPPED_AREA
@@ -440,7 +445,9 @@
  */
 #define KERNEL_TR_PAGE_SHIFT	_PAGE_SIZE_64M
 #define KERNEL_TR_PAGE_SIZE	(1 << KERNEL_TR_PAGE_SHIFT)
+#ifndef CONFIG_IA64_VMAP_KERNEL
 #define KERNEL_TR_PAGE_NUM	((KERNEL_START - PAGE_OFFSET) / KERNEL_TR_PAGE_SIZE)
+#endif
 
 /*
  * No page table caches to initialise
include/asm-ia64/system.h renamed from ../REF/linux-2.5.39-ia64-020928/include/asm-ia64/system.h +4 -0
diff -ru ../../REF/linux-2.5.39-ia64-020928/include/asm-ia64/system.h aegl/include/asm-ia64/system.h
@@ -18,7 +18,11 @@
 #include <asm/page.h>
 #include <asm/pal.h>
 
+#ifdef	CONFIG_IA64_VMAP_KERNEL
+#define KERNEL_START		(0xffffffff00000000)
+#else
 #define KERNEL_START		(PAGE_OFFSET + 68*1024*1024)
+#endif
 
 #define GATE_ADDR		(0xa000000000000000 + PAGE_SIZE)
 #define PERCPU_ADDR		(0xa000000000000000 + 2*PAGE_SIZE)
author
#1 lore raw

RE: [Linux-ia64] [patch 2.5.39] allow kernel to be virtually mapp

Quoted 4 lines · Yesterday I

This patch provides just the code needed to virtually map the kernel to a fixed virtual address from whatever physical address it happened to be loaded at (it is assumed that the bootloader handled the issue of finding a suitably aligned piece of memory).

Elilo already knows how to find memory, as long as you either use the "relocatable" keyword in elilo.conf, or the "-r" command-line option to let it know that it is OK to relocate.

Using this elilo option means that the changes I provided for vmlinux.ld.S can be very slightly simplified, it isn't necessary to define BASE_KVADDR as "KERNEL_START + KERNEL_TR_PAGE_SIZE", you can just use:

#define BASE_KVADDR KERNEL_START

-Tony