Skip to contentSkip to conversation

Basic infrastructure patches for a paravirtualized kernel

PATCH In review Jeremy Fitzhardinge 6 participants 34 messages Aug 1, 2006 – Aug 22, 2006

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Basic infrastructure patches for a paravirtualized kernel

[ REPOST: Apologies to anyone who has seen this before. It
didn't make it onto any of the lists it should have. -J ]

Hi Andrew,

This series of patches lays the basic ground work for the paravirtualized kernel patches coming later on. I think this lot is ready for the rough-and-tumble world of the -mm tree.

For the most part, these patches do nothing or very little. The patches should be self explanatory, but the overview is:

Helper functions for later use:
1/13: Add apply_to_page_range()...
3/13: Implement always-locked bit ops...
13/13: Put .note.* sections into a PT_NOTE segment in vmlinux

Cleanups:
2/13: Remove locally-defined ldt structure in favour of standard type 4/13: Allow a kernel to not be in ring 0
6/13: Roll all the cpuid asm into one __cpuid call
9/13: Remove the read hazard from the COW path in copy_one_pte 10/13: Change pte_clear_full to a more appropriately named...

Hooks:
5/13: Replace sensitive instructions with macros 7/13: Make __FIXADDR_TOP variable to allow it to make space... 8/13: Add a bootparameter to reserve high linear address... 11/13: Add lazy MMU mode hooks for batching PTE updates 12/13: Pass the mm struct into the pgd_free code so the mm...

Probably the most subtle changes here are 11/13 and 9/13, since they add a new constraint to page-table manipulation code. In a paravirtualized system, pte updates may be batched and performed lazily, so their effects will not be immediately visible on the pte itself. To avoid this, code which modifies ptes in a loop needs to avoid looking at the modified ptes. 9/13 fixes the one place where it happens.

11/13 depends on removing these read hazards for correctness when running under a direct page table hypervisor which batches updates. However, it is generally agreed that using an _explicit_, rather than an _implicit_ notion of batching makes it easy to find and reason about the paths which are doing batching. This allows easy inspection to remove read hazards from the code.

13/13 "Put .note.* sections into a PT_NOTE segment in vmlinux" is mostly here to shake out problems early. It slightly changes the way the vmlinux image is linked together, and it uses the somewhat esoteric PHDRS command in vmlinux.lds. I want to make sure that this doesn't provoke any problems in the various binutils people are using.

Thanks,
J

30 files changed, 609 insertions(+), 92 deletions(-)
arch/i386/Kconfig                 |    1 
arch/i386/kernel/entry.S          |   43 +++++-----
arch/i386/kernel/process.c        |    2 
arch/i386/kernel/reboot.c         |   12 --
arch/i386/kernel/setup.c          |   13 +++
arch/i386/kernel/vmlinux.lds.S    |   12 ++
arch/i386/mm/extable.c            |    2 
arch/i386/mm/fault.c              |   11 --
arch/i386/mm/init.c               |   42 +++++++++
arch/i386/mm/pgtable.c            |   21 ++++
include/asm-generic/pgtable.h     |   24 +++++
include/asm-generic/vmlinux.lds.h |    3 
include/asm-i386/fixmap.h         |    7 +
include/asm-i386/page.h           |    2 
include/asm-i386/pgalloc.h        |    4 
include/asm-i386/pgtable.h        |    1 
include/asm-i386/processor.h      |   74 ++++++++---------
include/asm-i386/ptrace.h         |    5 -
include/asm-i386/segment.h        |   10 ++
include/asm-i386/spinlock.h       |    7 +
include/asm-i386/sync_bitops.h    |  156 +++++++++++++++++++++++++++++++++++++
include/asm-i386/system.h         |   36 ++++++++
include/linux/elfnote.h           |   88 ++++++++++++++++++++
include/linux/mm.h                |    9 ++
kernel/fork.c                     |    2 
mm/fremap.c                       |    2 
mm/memory.c                       |  106 ++++++++++++++++++++++++-
mm/mprotect.c                     |    2 
mm/mremap.c                       |    2 
mm/msync.c                        |    2 

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#1 lore raw

PATCH 1/1 Add apply_to_page_range() which applies a function to a pte range

2 files changed, 99 insertions(+)

include/linux/mm.h | 5 ++
mm/memory.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++

Add a new mm function apply_to_page_range() which applies a given function to every pte in a given virtual address range in a given mm structure. This is a generic alternative to cut-and-pasting the Linux idiomatic pagetable walking code in every place that a sequence of PTEs must be accessed.

Although this interface is intended to be useful in a wide range of situations, it is currently used specifically by several Xen subsystems, for example: to ensure that pagetables have been allocated for a virtual address range, and to construct batched special pagetable update requests to map I/O memory (in ioremap()).

===================================================================

include/linux/mm.h +5 -0
diff -r 521d1bcdaa86 -r 79a98a10911f include/linux/mm.h
@@ -1026,6 +1026,11 @@ struct page *follow_page(struct vm_area_
 #define FOLL_GET	0x04	/* do get_page on page */
 #define FOLL_ANON	0x08	/* give ZERO_PAGE if no pgtable */
 
+typedef int (*pte_fn_t)(pte_t *pte, struct page *pmd_page, unsigned long addr,
+			void *data);
+extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
+			       unsigned long size, pte_fn_t fn, void *data);
+
 #ifdef CONFIG_PROC_FS
 void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
 #else
mm/memory.c +94 -0

100 lines not on this page · raw message

#2 lore raw

PATCH 1/1 Remove locally-defined ldt structure in favour of standard type

In reply to Jeremy Fitzhardinge
1 file changed, 4 insertions(+), 8 deletions(-)

arch/i386/kernel/reboot.c | 12 ++++--------

arch/i386/kernel/reboot.c defines its own struct to describe an ldt
entry: it should use struct Xgt_desc_struct (currently load_ldt is a macro, so doesn't complain: paravirt patches make it warn).

===================================================================

arch/i386/kernel/reboot.c +4 -8
diff -r 79a98a10911f -r ffccb62e9244 arch/i386/kernel/reboot.c
@@ -145,14 +145,10 @@ real_mode_gdt_entries [3] =
 	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
 };
 
-static struct
-{
-	unsigned short       size __attribute__ ((packed));
-	unsigned long long * base __attribute__ ((packed));
-}
-real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
-real_mode_idt = { 0x3ff, NULL },
-no_idt = { 0, NULL };
+static struct Xgt_desc_struct
+real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
+real_mode_idt = { 0x3ff, 0 },
+no_idt = { 0, 0 };
 
 
 /* This is 16-bit protected mode code to disable paging and the cache,
#3 lore raw

PATCH 1/1 Implement always-locked bit ops, for memory shared with an SMP hypervisor

In reply to Jeremy Fitzhardinge
2 files changed, 192 insertions(+)

include/asm-i386/sync_bitops.h | 156 ++++++++++++++++++++++++++++++++++++++++
include/asm-i386/system.h | 36 +++++++++

Add "always lock'd" implementations of set_bit, clear_bit and change_bit and the corresponding test_and_ functions. Also add "always lock'd" implementation of cmpxchg. These give guaranteed strong synchronisation and are required for non-SMP kernels running on an SMP hypervisor.

===================================================================

include/asm-i386/system.h +36 -0
diff -r ffccb62e9244 -r 85e7eadfaea1 include/asm-i386/system.h
@@ -261,6 +261,9 @@ static inline unsigned long __xchg(unsig
 #define cmpxchg(ptr,o,n)\
 	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
+#define sync_cmpxchg(ptr,o,n)\
+	((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
 #endif
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
@@ -282,6 +285,39 @@ static inline unsigned long __cmpxchg(vo
 		return prev;
 	case 4:
 		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
+/*
+ * Always use locked operations when touching memory shared with a
+ * hypervisor, since the system may be SMP even if the guest kernel
+ * isn't.
+ */
+static inline unsigned long __sync_cmpxchg(volatile void *ptr,
+					    unsigned long old,
+					    unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__("lock; cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__("lock; cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__("lock; cmpxchgl %1,%2"
 				     : "=a"(prev)
 				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
 				     : "memory");
include/asm-i386/sync_bitops.h new file +156 -0

156 lines not on this page · raw message

#4 lore raw

PATCH 1/1 Allow a kernel to not be in ring 0

In reply to Jeremy Fitzhardinge
6 files changed, 22 insertions(+), 13 deletions(-)
arch/i386/kernel/entry.S   |    5 +++--
arch/i386/kernel/process.c |    2 +-
arch/i386/mm/extable.c     |    2 +-
arch/i386/mm/fault.c       |   11 ++++-------
include/asm-i386/ptrace.h  |    5 +++--
include/asm-i386/segment.h |   10 ++++++++++

We allow for the fact that the guest kernel may not run in ring 0. This requires some abstraction in a few places when setting %cs or checking privilege level (user vs kernel).

This is Chris' [RFC PATCH 15/33] move segment checks to subarch, except rather than using #define USER_MODE_MASK which depends on a config option, we use Zach's more flexible approach of assuming ring 3 == userspace. I also used "get_kernel_rpl()" over "get_kernel_cs()" because I think it reads better in the code...

1) Remove the hardcoded 3 and introduce #define SEGMENT_RPL_MASK 3
2) Add a get_kernel_rpl() macro, and don't assume it's zero.

===================================================================

arch/i386/kernel/entry.S +3 -2
diff -r 85e7eadfaea1 -r cf6767d9babb arch/i386/kernel/entry.S
@@ -229,8 +229,9 @@ check_userspace:
 check_userspace:
 	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
 	movb CS(%esp), %al
-	testl $(VM_MASK | 3), %eax
-	jz resume_kernel
+	andl $(VM_MASK | SEGMENT_RPL_MASK), %eax
+	cmpl $SEGMENT_RPL_MASK, %eax
+	jb resume_kernel		# not returning to v8086 or userspace
 ENTRY(resume_userspace)
  	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
arch/i386/kernel/process.c +1 -1
diff -r 85e7eadfaea1 -r cf6767d9babb arch/i386/kernel/process.c
@@ -346,7 +346,7 @@ int kernel_thread(int (*fn)(void *), voi
 	regs.xes = __USER_DS;
 	regs.orig_eax = -1;
 	regs.eip = (unsigned long) kernel_thread_helper;
-	regs.xcs = __KERNEL_CS;
+	regs.xcs = __KERNEL_CS | get_kernel_rpl();
 	regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
 
 	/* Ok, create the new process.. */
arch/i386/mm/extable.c +1 -1
diff -r 85e7eadfaea1 -r cf6767d9babb arch/i386/mm/extable.c
@@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs
 	const struct exception_table_entry *fixup;
 
 #ifdef CONFIG_PNPBIOS
-	if (unlikely((regs->xcs & ~15) == (GDT_ENTRY_PNPBIOS_BASE << 3)))
+	if (unlikely(SEGMENT_IS_PNP_CODE(regs->xcs)))
 	{
 		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
 		extern u32 pnp_bios_is_utter_crap;
arch/i386/mm/fault.c +4 -7
diff -r 85e7eadfaea1 -r cf6767d9babb arch/i386/mm/fault.c
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/desc.h>
 #include <asm/kdebug.h>
+#include <asm/segment.h>
 
 extern void die(const char *,struct pt_regs *,long);
 
@@ -119,10 +120,10 @@ static inline unsigned long get_segment_
 	}
 
 	/* The standard kernel/user address space limit. */
-	*eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg;
+	*eip_limit = user_mode(regs) ? USER_DS.seg : KERNEL_DS.seg;
 	
 	/* By far the most common cases. */
-	if (likely(seg == __USER_CS || seg == __KERNEL_CS))
+	if (likely(SEGMENT_IS_FLAT_CODE(seg)))
 		return eip;
 
 	/* Check the segment exists, is within the current LDT/GDT size,
@@ -436,11 +437,7 @@ good_area:
 	write = 0;
 	switch (error_code & 3) {
 		default:	/* 3: write, present */
-#ifdef TEST_VERIFY_AREA
-			if (regs->cs == KERNEL_CS)
-				printk("WP fault at %08lx\n", regs->eip);
-#endif
-			/* fall through */
+				/* fall through */
 		case 2:		/* write, not present */
 			if (!(vma->vm_flags & VM_WRITE))
 				goto bad_area;
include/asm-i386/ptrace.h +3 -2
diff -r 85e7eadfaea1 -r cf6767d9babb include/asm-i386/ptrace.h
@@ -60,6 +60,7 @@ struct pt_regs {
 #ifdef __KERNEL__
 
 #include <asm/vm86.h>
+#include <asm/segment.h>
 
 struct task_struct;
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
@@ -73,11 +74,11 @@ extern void send_sigtrap(struct task_str
  */
 static inline int user_mode(struct pt_regs *regs)
 {
-	return (regs->xcs & 3) != 0;
+	return (regs->xcs & SEGMENT_RPL_MASK) == 3;
 }
 static inline int user_mode_vm(struct pt_regs *regs)
 {
-	return ((regs->xcs & 3) | (regs->eflags & VM_MASK)) != 0;
+	return (((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= 3);
 }
 #define instruction_pointer(regs) ((regs)->eip)
 #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
include/asm-i386/segment.h +10 -0
diff -r 85e7eadfaea1 -r cf6767d9babb include/asm-i386/segment.h
@@ -83,6 +83,12 @@
 
 #define GDT_SIZE (GDT_ENTRIES * 8)
 
+/*
+ * Some tricky tests to match code segments after a fault
+ */
+#define SEGMENT_IS_FLAT_CODE(x)  (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8)
+#define SEGMENT_IS_PNP_CODE(x)   (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8)
+
 /* Simple and small GDT entries for booting only */
 
 #define GDT_ENTRY_BOOT_CS		2
@@ -112,4 +118,8 @@
  */
 #define IDT_ENTRIES 256
 
+/* Bottom three bits of xcs give the ring privilege level */
+#define SEGMENT_RPL_MASK 0x3
+
+#define get_kernel_rpl()  0
 #endif
#5 lore raw

PATCH 1/1 Replace sensitive instructions with macros

In reply to Jeremy Fitzhardinge
2 files changed, 27 insertions(+), 18 deletions(-)

arch/i386/kernel/entry.S | 38 ++++++++++++++++++++++----------------
include/asm-i386/spinlock.h | 7 +++++--

Abstract sensitive instructions in assembler code, replacing them with macros (which currently are #defined to the native versions). We use long names: assembler is case-insensitive, so if something goes wrong and macros do not expand, it would assemble anyway.

Resulting object files are exactly the same as before.

===================================================================

arch/i386/kernel/entry.S +22 -16
diff -r cf6767d9babb -r 09b35e6bc0ca arch/i386/kernel/entry.S
@@ -76,8 +76,15 @@ NT_MASK		= 0x00004000
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
+/* These are replaces for paravirtualization */
+#define DISABLE_INTERRUPTS		cli
+#define ENABLE_INTERRUPTS		sti
+#define ENABLE_INTERRUPTS_SYSEXIT	sti; sysexit
+#define INTERRUPT_RETURN		iret
+#define GET_CR0_INTO_EAX		movl %cr0, %eax
+
 #ifdef CONFIG_PREEMPT
-#define preempt_stop		cli; TRACE_IRQS_OFF
+#define preempt_stop		DISABLE_INTERRUPTS; TRACE_IRQS_OFF
 #else
 #define preempt_stop
 #define resume_kernel		restore_nocheck
@@ -233,7 +240,7 @@ check_userspace:
 	cmpl $SEGMENT_RPL_MASK, %eax
 	jb resume_kernel		# not returning to v8086 or userspace
 ENTRY(resume_userspace)
- 	cli				# make sure we don't miss an interrupt
+ 	DISABLE_INTERRUPTS		# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -244,7 +251,7 @@ ENTRY(resume_userspace)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-	cli
+	DISABLE_INTERRUPTS
 	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
 	jnz restore_nocheck
 need_resched:
@@ -272,7 +279,7 @@ sysenter_past_esp:
 	 * No need to follow this irqs on/off section: the syscall
 	 * disabled irqs and here we enable it straight after entry:
 	 */
-	sti
+	ENABLE_INTERRUPTS
 	pushl $(__USER_DS)
 	CFI_ADJUST_CFA_OFFSET 4
 	/*CFI_REL_OFFSET ss, 0*/
@@ -317,7 +324,7 @@ 1:	movl (%ebp),%ebp
 	jae syscall_badsys
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)
-	cli
+	DISABLE_INTERRUPTS
 	TRACE_IRQS_OFF
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
@@ -327,8 +334,7 @@ 1:	movl (%ebp),%ebp
 	movl OLDESP(%esp), %ecx
 	xorl %ebp,%ebp
 	TRACE_IRQS_ON
-	sti
-	sysexit
+	ENABLE_INTERRUPTS_SYSEXIT
 	CFI_ENDPROC
 
 
@@ -353,7 +359,7 @@ syscall_call:
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)		# store the return value
 syscall_exit:
-	cli				# make sure we don't miss an interrupt
+	DISABLE_INTERRUPTS		# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	TRACE_IRQS_OFF
@@ -378,11 +384,11 @@ restore_nocheck_notrace:
 	RESTORE_REGS
 	addl $4, %esp
 	CFI_ADJUST_CFA_OFFSET -4
-1:	iret
+1:	INTERRUPT_RETURN
 .section .fixup,"ax"
 iret_exc:
 	TRACE_IRQS_ON
-	sti
+	ENABLE_INTERRUPTS
 	pushl $0			# no error code
 	pushl $do_iret_error
 	jmp error_code
@@ -406,7 +412,7 @@ ldt_ss:
 	 * dosemu and wine happy. */
 	subl $8, %esp		# reserve space for switch16 pointer
 	CFI_ADJUST_CFA_OFFSET 8
-	cli
+	DISABLE_INTERRUPTS
 	TRACE_IRQS_OFF
 	movl %esp, %eax
 	/* Set up the 16bit stack frame with switch32 pointer on top,
@@ -416,7 +422,7 @@ ldt_ss:
 	TRACE_IRQS_IRET
 	RESTORE_REGS
 	lss 20+4(%esp), %esp	# switch to 16bit stack
-1:	iret
+1:	INTERRUPT_RETURN
 .section __ex_table,"a"
 	.align 4
 	.long 1b,iret_exc
@@ -431,7 +437,7 @@ work_pending:
 	jz work_notifysig
 work_resched:
 	call schedule
-	cli				# make sure we don't miss an interrupt
+	DISABLE_INTERRUPTS		# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	TRACE_IRQS_OFF
@@ -487,7 +493,7 @@ syscall_exit_work:
 	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
 	jz work_pending
 	TRACE_IRQS_ON
-	sti				# could let do_syscall_trace() call
+	ENABLE_INTERRUPTS		# could let do_syscall_trace() call
 					# schedule() instead
 	movl %esp, %eax
 	movl $1, %edx
@@ -666,7 +672,7 @@ ENTRY(device_not_available)
 	pushl $-1			# mark this as an int
 	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
-	movl %cr0, %eax
+	GET_CR0_INTO_EAX
 	testl $0x4, %eax		# EM (math emulation bit)
 	jne device_not_available_emulate
 	preempt_stop
@@ -796,7 +802,7 @@ nmi_16bit_stack:
 	call do_nmi
 	RESTORE_REGS
 	lss 12+4(%esp), %esp		# back to 16bit stack
-1:	iret
+1:	INTERRUPT_RETURN
 	CFI_ENDPROC
 .section __ex_table,"a"
 	.align 4
include/asm-i386/spinlock.h +5 -2
diff -r cf6767d9babb -r 09b35e6bc0ca include/asm-i386/spinlock.h
@@ -16,6 +16,9 @@
  *
  * (the type definitions are in asm/spinlock_types.h)
  */
+
+#define CLI_STRING	"cli"
+#define STI_STRING	"sti"
 
 #define __raw_spin_is_locked(x) \
 		(*(volatile signed char *)(&(x)->slock) <= 0)
@@ -43,12 +46,12 @@
 	"2:\t" \
 	"testl $0x200, %1\n\t" \
 	"jz 4f\n\t" \
-	"sti\n" \
+	STI_STRING "\n" \
 	"3:\t" \
 	"rep;nop\n\t" \
 	"cmpb $0, %0\n\t" \
 	"jle 3b\n\t" \
-	"cli\n\t" \
+	CLI_STRING "\n\t" \
 	"jmp 1b\n" \
 	"4:\t" \
 	"rep;nop\n\t" \
#6 lore raw

PATCH 1/1 Roll all the cpuid asm into one __cpuid call

In reply to Jeremy Fitzhardinge
1 file changed, 34 insertions(+), 40 deletions(-)

include/asm-i386/processor.h | 74 +++++++++++++++++++-----------------------

It's a little neater, and also means only one place to patch for paravirtualization.

===================================================================

include/asm-i386/processor.h +34 -40
diff -r 09b35e6bc0ca -r 730b4fe6bc1e include/asm-i386/processor.h
@@ -143,31 +143,37 @@ static inline void detect_ht(struct cpui
 #define X86_EFLAGS_VIP	0x00100000 /* Virtual Interrupt Pending */
 #define X86_EFLAGS_ID	0x00200000 /* CPUID detection flag */
 
-/*
- * Generic CPUID function
- * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
- * resulting in stale register contents being returned.
- */
-static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
-{
+static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
+			   unsigned int *ecx, unsigned int *edx)
+{
+	/* ecx is often an input as well as an output. */
 	__asm__("cpuid"
 		: "=a" (*eax),
 		  "=b" (*ebx),
 		  "=c" (*ecx),
 		  "=d" (*edx)
-		: "0" (op), "c"(0));
+		: "0" (*eax), "2" (*ecx));
+}
+
+/*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+ * resulting in stale register contents being returned.
+ */
+static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
+{
+	*eax = op;
+	*ecx = 0;
+	__cpuid(eax, ebx, ecx, edx);
 }
 
 /* Some CPUID calls want 'count' to be placed in ecx */
 static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
-	       	int *edx)
-{
-	__asm__("cpuid"
-		: "=a" (*eax),
-		  "=b" (*ebx),
-		  "=c" (*ecx),
-		  "=d" (*edx)
-		: "0" (op), "c" (count));
+			       int *edx)
+{
+	*eax = op;
+	*ecx = count;
+	__cpuid(eax, ebx, ecx, edx);
 }
 
 /*
@@ -175,42 +181,30 @@ static inline void cpuid_count(int op, i
  */
 static inline unsigned int cpuid_eax(unsigned int op)
 {
-	unsigned int eax;
-
-	__asm__("cpuid"
-		: "=a" (eax)
-		: "0" (op)
-		: "bx", "cx", "dx");
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid(op, &eax, &ebx, &ecx, &edx);
 	return eax;
 }
 static inline unsigned int cpuid_ebx(unsigned int op)
 {
-	unsigned int eax, ebx;
-
-	__asm__("cpuid"
-		: "=a" (eax), "=b" (ebx)
-		: "0" (op)
-		: "cx", "dx" );
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid(op, &eax, &ebx, &ecx, &edx);
 	return ebx;
 }
 static inline unsigned int cpuid_ecx(unsigned int op)
 {
-	unsigned int eax, ecx;
-
-	__asm__("cpuid"
-		: "=a" (eax), "=c" (ecx)
-		: "0" (op)
-		: "bx", "dx" );
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid(op, &eax, &ebx, &ecx, &edx);
 	return ecx;
 }
 static inline unsigned int cpuid_edx(unsigned int op)
 {
-	unsigned int eax, edx;
-
-	__asm__("cpuid"
-		: "=a" (eax), "=d" (edx)
-		: "0" (op)
-		: "bx", "cx");
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid(op, &eax, &ebx, &ecx, &edx);
 	return edx;
 }
#7 lore raw

PATCH 1/1 Make __FIXADDR_TOP variable to allow it to make space for a hypervisor

In reply to Jeremy Fitzhardinge
5 files changed, 68 insertions(+), 2 deletions(-)
arch/i386/Kconfig         |    1 +
arch/i386/mm/init.c       |   42 ++++++++++++++++++++++++++++++++++++++++++
arch/i386/mm/pgtable.c    |   18 ++++++++++++++++++
include/asm-i386/fixmap.h |    7 ++++++-
include/asm-i386/page.h   |    2 +-

Make __FIXADDR_TOP a variable, so that it can be set to not get in the way of address space a hypervisor may want to reserve.

Original patch by Gerd Hoffmann <[email protected]>

===================================================================

arch/i386/Kconfig +1 -0
diff -r 730b4fe6bc1e -r b6c100bb5ca5 arch/i386/Kconfig
@@ -792,6 +792,7 @@ config COMPAT_VDSO
 config COMPAT_VDSO
 	bool "Compat VDSO support"
 	default y
+	depends on !PARAVIRT
 	help
 	  Map the VDSO to the predictable old-style address too.
 	---help---
arch/i386/mm/init.c +42 -0

48 lines not on this page · raw message

arch/i386/mm/pgtable.c +18 -0
diff -r 730b4fe6bc1e -r b6c100bb5ca5 arch/i386/mm/pgtable.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -137,6 +138,12 @@ void set_pmd_pfn(unsigned long vaddr, un
 	__flush_tlb_one(vaddr);
 }
 
+static int fixmaps = 0;
+#ifndef CONFIG_COMPAT_VDSO
+unsigned long __FIXADDR_TOP = 0xfffff000;
+EXPORT_SYMBOL(__FIXADDR_TOP);
+#endif
+
 void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 {
 	unsigned long address = __fix_to_virt(idx);
@@ -146,6 +153,17 @@ void __set_fixmap (enum fixed_addresses 
 		return;
 	}
 	set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
+	fixmaps++;
+}
+
+void set_fixaddr_top(unsigned long top)
+{
+	BUG_ON(fixmaps > 0);
+#ifdef CONFIG_COMPAT_VDSO
+	BUG_ON(top - PAGE_SIZE != __FIXADDR_TOP);
+#else
+	__FIXADDR_TOP = top - PAGE_SIZE;
+#endif
 }
 
 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
include/asm-i386/fixmap.h +6 -1
diff -r 730b4fe6bc1e -r b6c100bb5ca5 include/asm-i386/fixmap.h
@@ -19,7 +19,11 @@
  * Leave one empty page between vmalloc'ed areas and
  * the start of the fixmap.
  */
-#define __FIXADDR_TOP	0xfffff000
+#ifndef CONFIG_COMPAT_VDSO
+extern unsigned long __FIXADDR_TOP;
+#else
+#define __FIXADDR_TOP  0xfffff000
+#endif
 
 #ifndef __ASSEMBLY__
 #include <linux/kernel.h>
@@ -93,6 +97,7 @@ enum fixed_addresses {
 
 extern void __set_fixmap (enum fixed_addresses idx,
 					unsigned long phys, pgprot_t flags);
+extern void set_fixaddr_top(unsigned long top);
 
 #define set_fixmap(idx, phys) \
 		__set_fixmap(idx, phys, PAGE_KERNEL)
include/asm-i386/page.h +1 -1
diff -r 730b4fe6bc1e -r b6c100bb5ca5 include/asm-i386/page.h
@@ -122,7 +122,7 @@ extern int page_is_ram(unsigned long pag
 
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
 #define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
-#define MAXMEM			(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+#define MAXMEM			(__FIXADDR_TOP-__PAGE_OFFSET-__VMALLOC_RESERVE)
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
#8 lore raw

PATCH 1/1 Add a bootparameter to reserve high linear address space for hypervisors

In reply to Jeremy Fitzhardinge
1 file changed, 13 insertions(+)

arch/i386/kernel/setup.c | 13 +++++++++++++

This is necessary to allow dynamically loaded hypervisor modules, which might not happen until userspace is already running, and also provides a useful tool to benchmark the performance impact of reduced lowmem address space.

===================================================================

arch/i386/kernel/setup.c +13 -0
diff -r b6c100bb5ca5 -r 0adfc39039c7 arch/i386/kernel/setup.c
@@ -917,6 +917,19 @@ static void __init parse_cmdline_early (
 		else if (!memcmp(from, "vmalloc=", 8))
 			__VMALLOC_RESERVE = memparse(from+8, &from);
 
+		/*
+		 * reservedtop=size reserves a hole at the top of the kernel
+		 * address space which a hypervisor can load into later.
+		 * Needed for dynamically loaded hypervisors, so relocating
+		 * the fixmap can be done before paging initialization.
+		 * This hole must be a multiple of 4M.
+		 */
+		else if (!memcmp(from, "reservedtop=", 12)) {
+			unsigned long reserved = memparse(from+12, &from);
+			reserved &= ~0x3fffff;
+			set_fixaddr_top(-reserved);
+		}
+
 	next_char:
 		c = *(from++);
 		if (!c)
#9 lore raw

Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

arch/i386/kernel/setup.c static void __init parse_cmdline_early ( · line 931

Quoted 13 lines
arch/i386/kernel/setup.c +12 -0
+		/*
+		 * reservedtop=size reserves a hole at the top of the kernel
+		 * address space which a hypervisor can load into later.
+		 * Needed for dynamically loaded hypervisors, so relocating
+		 * the fixmap can be done before paging initialization.
+		 * This hole must be a multiple of 4M.
+		 */
+		else if (!memcmp(from, "reservedtop=", 12)) {
+			unsigned long reserved = memparse(from+12, &from);
+			reserved &= ~0x3fffff;
+			set_fixaddr_top(-reserved);
+		}

You need to add a dummy __setup for it, otherwise it will end up in init's environments or be warned about.

Also it should be documented somewhere in Documentation

-Andi

#10 lore raw

Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 7 lines · Andi Kleen
Quoted 7 lines
arch/i386/kernel/setup.c +7 -0
+		/*
+		 * reservedtop=size reserves a hole at the top of the kernel
+		 * address space which a hypervisor can load into later.
+		 * Needed for dynamically loaded hypervisors, so relocating
+		 * the fixmap can be done before paging initialization.
+		 * This hole must be a multiple of 4M.
+		 */
Quoted 8 lines

arch/i386/kernel/setup.c static void __init parse_cmdline_early ( · line 931

Quoted 5 lines
arch/i386/kernel/setup.c +5 -0
+		else if (!memcmp(from, "reservedtop=", 12)) {
+			unsigned long reserved = memparse(from+12, &from);
+			reserved &= ~0x3fffff;
+			set_fixaddr_top(-reserved);
+		}

You need to add a dummy __setup for it, otherwise it will end up in init's environments or be warned about.

Ewww, it's not the only one. This whole function should be replaced with a whole heap of early_param()s and a call to parse_early_param().

I only implemented parse_early_param two years ago; maybe it is time for i386 to use it...

I'll create a patch,
Rusty.

Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
#11 lore raw

Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 3 lines · Rusty Russell

I only implemented parse_early_param two years ago; maybe it is time for i386 to use it...

Problem is that it's too late. Some of the stuff is already needed in setup_arch. You would need to move it before it first.

Unfortunately touching the order might cause very subtle problem on other architectures - this tends to be fragile.

-Andi

#12 lore raw

Re: [Xen-devel] Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 7 lines · Andi Kleen
Quoted 3 lines · Rusty Russell

I only implemented parse_early_param two years ago; maybe it is time for i386 to use it...

Problem is that it's too late. Some of the stuff is already needed in setup_arch. You would need to move it before it first.

Hi Andi!

I think you misunderstand the purpose of parse_early_param? It is
designed to be called directly by the arch at some point (it is idempotent, so the second call in init/main.c does nothing if the arch has called it). ie. in i386, it replaces parse_cmdline_early().

Here's the patch against 2.6.18-rc2-mm1. Tested with various configurations, but it's still possible I broke something.

Subject: Replace i386 open-coded cmdline parsing with early_param/parse_early_param

This patch replaces the open-coded early commandline parsing throughout the i386 boot code with the generic mechanism (already used by ppc, powerpc, ia64 and s390). The replaced code is inconsistent with whether it deletes the option from the cmdline or not, meaning some of these will get passed through the environment into init.

This transformation is mainly mechanical, but there are some notable parts:

1) Grammar: s/linux never set's it up/linux never sets it up/

2) Remove hacked-in earlyprintk= option scanning. When someone actually implements CONFIG_EARLY_PRINTK, then they can use early_param().

3) Move declaration of generic_apic_probe() from setup.c into asm/apic.h

4) "crashkernel" param can now be handled directly in machine_kexec.c

5) I left "pci=noacpi" as a manual hack, because there's a __setup("pci") already, and so an early_param("pci") would (depending in link order!) override it entirely.

arch/i386/kernel/machine_kexec.c +23 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/kernel/machine_kexec.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/kernel/machine_kexec.c
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -209,3 +210,25 @@ NORET_TYPE void machine_kexec(struct kim
 	rnk = (relocate_new_kernel_t) reboot_code_buffer;
 	(*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
 }
+
+/* crashkernel=size@addr specifies the location to reserve for
+ * a crash kernel.  By reserving this memory we guarantee
+ * that linux never sets it up as a DMA target.
+ * Useful for holding code to do something appropriate
+ * after a kernel panic.
+ */
+static int __init parse_crashkernel(char *arg)
+{
+	unsigned long size, base;
+	size = memparse(arg, &arg);
+	if (*arg == '@') {
+		base = memparse(arg+1, &arg);
+		/* FIXME: Do I want a sanity check
+		 * to validate the memory range?
+		 */
+		crashk_res.start = base;
+		crashk_res.end   = base + size - 1;
+	}
+	return 0;
+}
+early_param("crashkernel", parse_crashkernel);
arch/i386/kernel/setup.c +195 -215

464 lines not on this page · raw message

arch/i386/mach-generic/probe.c +25 -30

78 lines not on this page · raw message

arch/i386/mm/init.c +3 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/mm/init.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/mm/init.c
@@ -435,7 +435,7 @@ u64 __supported_pte_mask __read_mostly =
  * on      Enable
  * off     Disable
  */
-void __init noexec_setup(const char *str)
+static int __init noexec_setup(char *str)
 {
 	if (!strncmp(str, "on",2) && cpu_has_nx) {
 		__supported_pte_mask |= _PAGE_NX;
@@ -444,7 +444,9 @@ void __init noexec_setup(const char *str
 		disable_nx = 1;
 		__supported_pte_mask &= ~_PAGE_NX;
 	}
+	return 0;
 }
+early_param("noexec", noexec_setup);
 
 int nx_enabled = 0;
 #ifdef CONFIG_X86_PAE
include/asm-i386/apic.h +2 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/include/asm-i386/apic.h working-2.6.18-rc2-mm1-i386-parse_early_param/include/asm-i386/apic.h
@@ -42,6 +42,8 @@ static inline void lapic_enable(void)
 	} while (0)
 
 
+extern void generic_apic_probe(void);
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 /*
include/asm-i386/pgtable.h +0 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/include/asm-i386/pgtable.h working-2.6.18-rc2-mm1-i386-parse_early_param/include/asm-i386/pgtable.h
@@ -391,8 +391,6 @@ extern pte_t *lookup_address(unsigned lo
  static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;}
 #endif
 
-extern void noexec_setup(const char *str);
-
 #if defined(CONFIG_HIGHPTE)
 #define pte_offset_map(dir, address) \
 	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
#13 lore raw

Re: [Xen-devel] Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 5 lines

I think you misunderstand the purpose of parse_early_param? It is
designed to be called directly by the arch at some point (it is idempotent, so the second call in init/main.c does nothing if the arch has called it). ie. in i386, it replaces parse_cmdline_early().

Ah I didn't realize that. But why is there a second call in init/main.c? Looks like a big hack to me. Someone was too lazy to add it to all architectures?

-Andi

#14 lore raw

Re: [Xen-devel] Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 7 lines · Andi Kleen
Quoted 4 lines

I think you misunderstand the purpose of parse_early_param? It is
designed to be called directly by the arch at some point (it is idempotent, so the second call in init/main.c does nothing if the arch has called it). ie. in i386, it replaces parse_cmdline_early().

Ah I didn't realize that. But why is there a second call in init/main.c? Looks like a big hack to me. Someone was too lazy to add it to all architectures?

Yes. Someone == me. I didn't want to hack it into all archs, I wanted archs to actually use it, and you can see that's not a trivial patch...

Once all archs use it, we can probably clean up setup_arch() not to take the char** and simply use the global saved_command_line directly. At this rate, that'll be around 2012 8)

Rusty.

Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
#15 lore raw

Re: [Xen-devel] Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 9 lines · Rusty Russell
Quoted 7 lines · Andi Kleen
Quoted 4 lines

I think you misunderstand the purpose of parse_early_param? It is
designed to be called directly by the arch at some point (it is idempotent, so the second call in init/main.c does nothing if the arch has called it). ie. in i386, it replaces parse_cmdline_early().

Ah I didn't realize that. But why is there a second call in init/main.c? Looks like a big hack to me. Someone was too lazy to add it to all architectures?

Quoted 6 lines

Yes. Someone == me. I didn't want to hack it into all archs, I wanted archs to actually use it, and you can see that's not a trivial patch...

Once all archs use it, we can probably clean up setup_arch() not to take the char** and simply use the global saved_command_line directly. At this rate, that'll be around 2012 8)

Please just make a proper patch - either add a call to it to all setup_archs, or add a call to before setup_arch in init/main.c. While such ifdefs
for specific architecture hacks are more popular lately it doesn't mean they are a good idea.

I hope there aren't any existing architectures that use it in the middle of setup_arch or rely on it being after setup_arch.

-Andi

#16 lore raw

Re: [Xen-devel] Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 3 lines · Andi Kleen

Please just make a proper patch - either add a call to it to all setup_archs, or add a call to before setup_arch in init/main.c. While such ifdefs
for specific architecture hacks are more popular lately it doesn't mean they are a good idea.

It's been around for two years, but if you fix x86_64 to use early_param(), and I'll patch the other setup_archs to call parse_early_param and remove the init/main.c call 8)

Quoted 2 lines

I hope there aren't any existing architectures that use it in the middle of setup_arch or rely on it being after setup_arch.

setup_arch is responsible for grabbing the command line, so that has to happen first. Even on x86, functions later in setup_arch rely on cmdline parsing having happened. So for the moment setup_arch has to call parse_early_param.

Maybe one day we can create a new "char *arch_get_cmdline()", implement that everywhere, then call it and parse_early_param from core code. But baby steps...

Rusty.

Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
#17 lore raw

Re: [Xen-devel] Re: [PATCH 8 of 13] Add a bootparameter to reserve high linear address space for hypervisors

Quoted 8 lines · Rusty Russell
Quoted 3 lines · Andi Kleen

Please just make a proper patch - either add a call to it to all setup_archs, or add a call to before setup_arch in init/main.c. While such ifdefs
for specific architecture hacks are more popular lately it doesn't mean they are a good idea.

It's been around for two years, but if you fix x86_64 to use early_param(), and I'll patch the other setup_archs to call parse_early_param and remove the init/main.c call 8)

Ok. I will do x86-64.

I can also merge the i386 patch (which is really independent from the paravirt patchkit)

-Andi

#18 lore raw

PATCH 1/2 Allow early_param and identical __setup to exist

We currently assume that boot parameters which are handled by early_param() will not overlap boot parameters handled by __setup: if they do, behaviour is dependent on link order, usually meaning __setup will not get called.

ACPI wants to use early_param("pci"), and pci uses __setup("pci="), so we modify the core to let them coexist: "pci=noacpi" will now get passed to both.

init/main.c +8 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/init/main.c working-2.6.18-rc2-mm1-i386-parse_early_param/init/main.c
@@ -182,16 +182,19 @@ extern struct obs_kernel_param __setup_s
 static int __init obsolete_checksetup(char *line)
 {
 	struct obs_kernel_param *p;
+	int had_early_param = 0;
 
 	p = __setup_start;
 	do {
 		int n = strlen(p->str);
 		if (!strncmp(line, p->str, n)) {
 			if (p->early) {
-				/* Already done in parse_early_param?  (Needs
-				 * exact match on param part) */
+				/* Already done in parse_early_param?
+				 * (Needs exact match on param part).
+				 * Keep iterating, as we can have early
+				 * params and __setups of same names 8( */
 				if (line[n] == '\0' || line[n] == '=')
-					return 1;
+					had_early_param = 1;
 			} else if (!p->setup_func) {
 				printk(KERN_WARNING "Parameter %s is obsolete,"
 				       " ignored\n", p->str);
@@ -201,7 +204,8 @@ static int __init obsolete_checksetup(ch
 		}
 		p++;
 	} while (p < __setup_end);
-	return 0;
+
+	return had_early_param;
 }
 
 /*
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
#19 lore raw

PATCH 2/2 Replace i386 open-coded cmdline parsing with early_param/parse_early_param

In reply to Andi Kleen

This patch replaces the open-coded early commandline parsing throughout the i386 boot code with the generic mechanism (already used by ppc, powerpc, ia64 and s390). The code was inconsistent with whether it deletes the option from the cmdline or not, meaning some of these will get passed through the environment into init.

This transformation is mainly mechanical, but there are some notable parts:

1) Grammar: s/linux never set's it up/linux never sets it up/

2) Remove hacked-in earlyprintk= option scanning. When someone actually implements CONFIG_EARLY_PRINTK, then they can use early_param().

3) Move declaration of generic_apic_probe() from setup.c into asm/apic.h

4) Various parameters now moved into their appropriate files (thanks Andi).

5) All parse functions which examine arg need to check for NULL, except one where it has subtle humor value.

arch/i386/kernel/acpi/boot.c +54 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/kernel/acpi/boot.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/kernel/acpi/boot.c
@@ -1216,3 +1216,57 @@ int __init acpi_boot_init(void)
 
 	return 0;
 }
+
+static int __init parse_acpi(char *arg)
+{
+	if (!arg)
+		return -EINVAL;
+
+	/* "acpi=off" disables both ACPI table parsing and interpreter */
+	if (strcmp(arg, "off") == 0) {
+		disable_acpi();
+	} 
+	/* acpi=force to over-ride black-list */
+	else if (strcmp(arg, "force") == 0) {
+		acpi_force = 1;
+		acpi_ht = 1;
+		acpi_disabled = 0;
+	}
+	/* acpi=strict disables out-of-spec workarounds */
+	else if (strcmp(arg, "strict") == 0) {
+		acpi_strict = 1;
+	}
+	/* Limit ACPI just to boot-time to enable HT */
+	else if (strcmp(arg, "ht") == 0) {
+		if (!acpi_force)
+			disable_acpi();
+		acpi_ht = 1;
+	}
+	/* "acpi=noirq" disables ACPI interrupt routing */
+	else if (strcmp(arg, "noirq") == 0) {
+		acpi_noirq_set();
+	} else {
+		/* Core will printk when we return error. */
+		return -EINVAL;
+	}
+	return 0;
+}
+early_param("acpi", parse_acpi);
+
+/* FIXME: Using pci= for an ACPI parameter is a travesty. */
+static int __init parse_pci(char *arg)
+{
+	if (arg && strcmp(arg, "noacpi") == 0)
+		acpi_disable_pci();
+	return 0;
+}
+early_param("pci", parse_pci);
+
+#ifdef CONFIG_X86_IO_APIC
+static int __init parse_acpi_skip_timer_override(char *arg)
+{
+	acpi_skip_timer_override = 1;
+	return 0;
+}
+early_param("acpi_skip_timer_override", parse_acpi_skip_timer_override);
+#endif /* CONFIG_X86_IO_APIC */
arch/i386/kernel/apic.c +15 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/kernel/apic.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/kernel/apic.c
@@ -1372,3 +1372,18 @@ int __init APIC_init_uniprocessor (void)
 
 	return 0;
 }
+
+static int __init parse_lapic(char *arg)
+{
+	lapic_enable();
+	return 0;
+}
+early_param("lapic", parse_lapic);
+
+static int __init parse_nolapic(char *arg)
+{
+	lapic_disable();
+	return 0;
+}
+early_param("nolapic", parse_nolapic);
+
arch/i386/kernel/io_apic.c +23 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/kernel/io_apic.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/kernel/io_apic.c
@@ -69,7 +69,7 @@ int sis_apic_bug = -1;
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
-int disable_timer_pin_1 __initdata;
+static int disable_timer_pin_1 __initdata;
 
 /*
  * Rough estimation of how many shared IRQs there are, can
@@ -2767,3 +2767,25 @@ int io_apic_set_pci_routing (int ioapic,
 }
 
 #endif /* CONFIG_ACPI */
+
+static int __init parse_disable_timer_pin_1(char *arg)
+{
+	disable_timer_pin_1 = 1;
+	return 0;
+}
+early_param("disable_timer_pin_1", parse_disable_timer_pin_1);
+
+static int __init parse_enable_timer_pin_1(char *arg)
+{
+	disable_timer_pin_1 = -1;
+	return 0;
+}
+early_param("enable_timer_pin_1", parse_enable_timer_pin_1);
+
+static int __init parse_noapic(char *arg)
+{
+	/* disable IO-APIC */
+	disable_ioapic_setup();
+	return 0;
+}
+early_param("noapic", parse_noapic);
arch/i386/kernel/machine_kexec.c +23 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/kernel/machine_kexec.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/kernel/machine_kexec.c
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -209,3 +210,25 @@ NORET_TYPE void machine_kexec(struct kim
 	rnk = (relocate_new_kernel_t) reboot_code_buffer;
 	(*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
 }
+
+/* crashkernel=size@addr specifies the location to reserve for
+ * a crash kernel.  By reserving this memory we guarantee
+ * that linux never sets it up as a DMA target.
+ * Useful for holding code to do something appropriate
+ * after a kernel panic.
+ */
+static int __init parse_crashkernel(char *arg)
+{
+	unsigned long size, base;
+	size = memparse(arg, &arg);
+	if (*arg == '@') {
+		base = memparse(arg+1, &arg);
+		/* FIXME: Do I want a sanity check
+		 * to validate the memory range?
+		 */
+		crashk_res.start = base;
+		crashk_res.end   = base + size - 1;
+	}
+	return 0;
+}
+early_param("crashkernel", parse_crashkernel);
arch/i386/kernel/setup.c +118 -227

387 lines not on this page · raw message

arch/i386/kernel/smpboot.c +13 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/kernel/smpboot.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/kernel/smpboot.c
@@ -1490,3 +1490,16 @@ void __init smp_intr_init(void)
 	/* IPI for generic function call */
 	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 }
+
+/*
+ * If the BIOS enumerates physical processors before logical,
+ * maxcpus=N at enumeration-time can be used to disable HT.
+ */
+static int __init parse_maxcpus(char *arg)
+{
+	extern unsigned int maxcpus;
+
+	maxcpus = simple_strtoul(arg, NULL, 0);
+	return 0;
+}
+early_param("maxcpus", parse_maxcpus);
arch/i386/mach-generic/probe.c +28 -30

81 lines not on this page · raw message

arch/i386/mm/init.c +12 -6
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/arch/i386/mm/init.c working-2.6.18-rc2-mm1-i386-parse_early_param/arch/i386/mm/init.c
@@ -435,16 +435,22 @@ u64 __supported_pte_mask __read_mostly =
  * on      Enable
  * off     Disable
  */
-void __init noexec_setup(const char *str)
+static int __init noexec_setup(char *str)
 {
-	if (!strncmp(str, "on",2) && cpu_has_nx) {
-		__supported_pte_mask |= _PAGE_NX;
-		disable_nx = 0;
-	} else if (!strncmp(str,"off",3)) {
+	if (!str || !strcmp(str, "on")) {
+		if (cpu_has_nx) {
+			__supported_pte_mask |= _PAGE_NX;
+			disable_nx = 0;
+		}
+	} else if (!strcmp(str,"off")) {
 		disable_nx = 1;
 		__supported_pte_mask &= ~_PAGE_NX;
-	}
+	} else
+		return -EINVAL;
+
+	return 0;
 }
+early_param("noexec", noexec_setup);
 
 int nx_enabled = 0;
 #ifdef CONFIG_X86_PAE
include/asm-i386/acpi.h +0 -14
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/include/asm-i386/acpi.h working-2.6.18-rc2-mm1-i386-parse_early_param/include/asm-i386/acpi.h
@@ -131,21 +131,7 @@ static inline void disable_acpi(void) 
 extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
 
 #ifdef CONFIG_X86_IO_APIC
-extern int skip_ioapic_setup;
 extern int acpi_skip_timer_override;
-
-static inline void disable_ioapic_setup(void)
-{
-	skip_ioapic_setup = 1;
-}
-
-static inline int ioapic_setup_disabled(void)
-{
-	return skip_ioapic_setup;
-}
-
-#else
-static inline void disable_ioapic_setup(void) { }
 #endif
 
 static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
include/asm-i386/apic.h +2 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/include/asm-i386/apic.h working-2.6.18-rc2-mm1-i386-parse_early_param/include/asm-i386/apic.h
@@ -42,6 +42,8 @@ static inline void lapic_enable(void)
 	} while (0)
 
 
+extern void generic_apic_probe(void);
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 /*
@@ -117,8 +119,6 @@ extern void enable_APIC_timer(void);
 
 extern void enable_NMI_through_LVT0 (void * dummy);
 
-extern int disable_timer_pin_1;
-
 void smp_send_timer_broadcast_ipi(struct pt_regs *regs);
 void switch_APIC_timer_to_ipi(void *cpumask);
 void switch_ipi_to_APIC_timer(void *cpumask);
include/asm-i386/io_apic.h +11 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/include/asm-i386/io_apic.h working-2.6.18-rc2-mm1-i386-parse_early_param/include/asm-i386/io_apic.h
@@ -148,6 +148,16 @@ static inline void io_apic_modify(unsign
 /* 1 if "noapic" boot option passed */
 extern int skip_ioapic_setup;
 
+static inline void disable_ioapic_setup(void)
+{
+	skip_ioapic_setup = 1;
+}
+
+static inline int ioapic_setup_disabled(void)
+{
+	return skip_ioapic_setup;
+}
+
 /*
  * If we use the IO-APIC for IRQ routing, disable automatic
  * assignment of PCI IRQ's.
@@ -166,6 +176,7 @@ extern int (*ioapic_renumber_irq)(int io
 
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
+static inline void disable_ioapic_setup(void) { }
 #endif
 
 #endif
include/asm-i386/pgtable.h +0 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.6.18-rc2-mm1/include/asm-i386/pgtable.h working-2.6.18-rc2-mm1-i386-parse_early_param/include/asm-i386/pgtable.h
@@ -391,8 +391,6 @@ extern pte_t *lookup_address(unsigned lo
  static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;}
 #endif
 
-extern void noexec_setup(const char *str);
-
 #if defined(CONFIG_HIGHPTE)
 #define pte_offset_map(dir, address) \
 	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
#20 lore raw

Re: [PATCH 2/2] Replace i386 open-coded cmdline parsing with early_param/parse_early_param

Quoted 5 lines · Rusty Russell

This patch replaces the open-coded early commandline parsing throughout the i386 boot code with the generic mechanism (already used by ppc, powerpc, ia64 and s390). The code was inconsistent with whether it deletes the option from the cmdline or not, meaning some of these will get passed through the environment into init.

Both merged now thanks.

-Andi

#21 lore raw

PATCH 1/1 Remove the read hazard from the COW path in copy_one_pte

In reply to Jeremy Fitzhardinge
1 file changed, 1 insertion(+), 1 deletion(-)

mm/memory.c | 2 +-

We don't want to read PTEs directly like this after they have been modified, as a lazy MMU implementation of direct page tables may not have written the updated PTE back to memory yet.

===================================================================

mm/memory.c +1 -1
diff -r 0adfc39039c7 -r 20f9c0c451af mm/memory.c
@@ -466,7 +466,7 @@ copy_one_pte(struct mm_struct *dst_mm, s
 	 */
 	if (is_cow_mapping(vm_flags)) {
 		ptep_set_wrprotect(src_mm, addr, src_pte);
-		pte = *src_pte;
+		pte = pte_wrprotect(pte);
 	}
 
 	/*
#22 lore raw

PATCH 1/1 Change pte_clear_full to a more appropriately named pte_clear_not_present,

In reply to Jeremy Fitzhardinge
3 files changed, 4 insertions(+), 4 deletions(-)
include/asm-generic/pgtable.h |    4 ++--
mm/fremap.c                   |    2 +-
mm/memory.c                   |    2 +-

allowing optimizations when not-present mapping changes need not be reflected in the hardware TLB for protected page table modes. There is also another case that can use it in the fremap code.

===================================================================

include/asm-generic/pgtable.h +2 -2
diff -r 20f9c0c451af -r 553154516a1b include/asm-generic/pgtable.h
@@ -110,8 +110,8 @@ do {				  					  \
 })
 #endif
 
-#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
-#define pte_clear_full(__mm, __address, __ptep, __full)			\
+#ifndef __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
+#define pte_clear_not_present_full(__mm, __address, __ptep, __full)	\
 do {									\
 	pte_clear((__mm), (__address), (__ptep));			\
 } while (0)
mm/fremap.c +1 -1
diff -r 20f9c0c451af -r 553154516a1b mm/fremap.c
@@ -39,7 +39,7 @@ static int zap_pte(struct mm_struct *mm,
 	} else {
 		if (!pte_file(pte))
 			free_swap_and_cache(pte_to_swp_entry(pte));
-		pte_clear(mm, addr, ptep);
+		pte_clear_not_present_full(mm, addr, ptep, 0);
 	}
 	return !!page;
 }
mm/memory.c +1 -1
diff -r 20f9c0c451af -r 553154516a1b mm/memory.c
@@ -689,7 +689,7 @@ static unsigned long zap_pte_range(struc
 			continue;
 		if (!pte_file(ptent))
 			free_swap_and_cache(pte_to_swp_entry(ptent));
-		pte_clear_full(mm, addr, pte, tlb->fullmm);
+		pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
 	} while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
 
 	add_mm_rss(mm, file_rss, anon_rss);
#23 lore raw

Re: [PATCH 10 of 13] Change pte_clear_full to a more appropriately named pte_clear_not_present,

include/asm-generic/pgtable.h do { \ · line 117

Quoted 8 lines
include/asm-generic/pgtable.h +2 -2
-#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
-#define pte_clear_full(__mm, __address, __ptep, __full)			\
+#ifndef __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
+#define pte_clear_not_present_full(__mm, __address, __ptep, __full)	\
 do {									\
 	pte_clear((__mm), (__address), (__ptep));			\
 } while (0)

Needs comments I guess

-Andi

#24 lore raw

PATCH 1/1 Implement lazy MMU update hooks which are SMP safe for both direct and

In reply to Jeremy Fitzhardinge
5 files changed, 34 insertions(+)
include/asm-generic/pgtable.h |   20 ++++++++++++++++++++
mm/memory.c                   |    8 ++++++++
mm/mprotect.c                 |    2 ++
mm/mremap.c                   |    2 ++
mm/msync.c                    |    2 ++

shadow page tables. The idea is that PTE updates and page invalidations while in lazy mode can be batched into a single hypercall. We use this in VMI for shadow page table synchronization, and it is a win. It also can be used by PPC and for direct page tables on Xen.

For SMP, the enter / leave must happen under protection of the page table locks for page tables which are being modified. This is because otherwise, you end up with stale state in the batched hypercall, which other CPUs can race ahead of. Doing this under the protection of the locks guarantees the synchronization is correct, and also means that spurious faults which are generated during this window by remote CPUs are properly handled, as the page fault handler must re-check the PTE under protection of the same lock.

===================================================================

include/asm-generic/pgtable.h +20 -0
diff -r 553154516a1b -r 398f8fd6b334 include/asm-generic/pgtable.h
@@ -164,6 +164,26 @@ static inline void ptep_set_wrprotect(st
 #endif
 
 /*
+ * A facility to provide lazy MMU batching.  This allows PTE updates and
+ * page invalidations to be delayed until a call to leave lazy MMU mode
+ * is issued.  Some architectures may benefit from doing this, and it is
+ * beneficial for both shadow and direct mode hypervisors, which may batch
+ * the PTE updates which happen during this window.  Note that using this
+ * interface requires that read hazards be removed from the code.  A read
+ * hazard could result in the direct mode hypervisor case, since the actual
+ * write to the page tables may not yet have taken place, so reads though
+ * a raw PTE pointer after it has been modified are not guaranteed to be
+ * up to date.  This mode can only be entered and left under the protection of
+ * the page table locks for all page tables which may be modified.  In the UP
+ * case, this is required so that preemption is disabled, and in the SMP case,
+ * it must synchronize the delayed page table writes properly on other CPUs.
+ */
+#ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+#define arch_enter_lazy_mmu_mode()	do {} while (0)
+#define arch_leave_lazy_mmu_mode()	do {} while (0)
+#endif
+
+/*
  * When walking page tables, get the address of the next boundary,
  * or the end address of the range if that comes earlier.  Although no
  * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout.
mm/memory.c +8 -0
diff -r 553154516a1b -r 398f8fd6b334 mm/memory.c
@@ -505,6 +505,7 @@ again:
 	src_pte = pte_offset_map_nested(src_pmd, addr);
 	src_ptl = pte_lockptr(src_mm, src_pmd);
 	spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
+	arch_enter_lazy_mmu_mode();
 
 	do {
 		/*
@@ -526,6 +527,7 @@ again:
 		progress += 8;
 	} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
 
+	arch_leave_lazy_mmu_mode();
 	spin_unlock(src_ptl);
 	pte_unmap_nested(src_pte - 1);
 	add_mm_rss(dst_mm, rss[0], rss[1]);
@@ -627,6 +629,7 @@ static unsigned long zap_pte_range(struc
 	int anon_rss = 0;
 
 	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+	arch_enter_lazy_mmu_mode();
 	do {
 		pte_t ptent = *pte;
 		if (pte_none(ptent)) {
@@ -693,6 +696,7 @@ static unsigned long zap_pte_range(struc
 	} while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
 
 	add_mm_rss(mm, file_rss, anon_rss);
+	arch_leave_lazy_mmu_mode();
 	pte_unmap_unlock(pte - 1, ptl);
 
 	return addr;
@@ -1108,6 +1112,7 @@ static int zeromap_pte_range(struct mm_s
 	pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
 	if (!pte)
 		return -ENOMEM;
+	arch_enter_lazy_mmu_mode();
 	do {
 		struct page *page = ZERO_PAGE(addr);
 		pte_t zero_pte = pte_wrprotect(mk_pte(page, prot));
@@ -1117,6 +1122,7 @@ static int zeromap_pte_range(struct mm_s
 		BUG_ON(!pte_none(*pte));
 		set_pte_at(mm, addr, pte, zero_pte);
 	} while (pte++, addr += PAGE_SIZE, addr != end);
+	arch_leave_lazy_mmu_mode();
 	pte_unmap_unlock(pte - 1, ptl);
 	return 0;
 }
@@ -1269,11 +1275,13 @@ static int remap_pte_range(struct mm_str
 	pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
 	if (!pte)
 		return -ENOMEM;
+	arch_enter_lazy_mmu_mode();
 	do {
 		BUG_ON(!pte_none(*pte));
 		set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
 		pfn++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
+	arch_leave_lazy_mmu_mode();
 	pte_unmap_unlock(pte - 1, ptl);
 	return 0;
 }
mm/mprotect.c +2 -0
diff -r 553154516a1b -r 398f8fd6b334 mm/mprotect.c
@@ -33,6 +33,7 @@ static void change_pte_range(struct mm_s
 	spinlock_t *ptl;
 
 	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+	arch_enter_lazy_mmu_mode();
 	do {
 		oldpte = *pte;
 		if (pte_present(oldpte)) {
@@ -62,6 +63,7 @@ static void change_pte_range(struct mm_s
 		}
 
 	} while (pte++, addr += PAGE_SIZE, addr != end);
+	arch_leave_lazy_mmu_mode();
 	pte_unmap_unlock(pte - 1, ptl);
 }
 
mm/mremap.c +2 -0
diff -r 553154516a1b -r 398f8fd6b334 mm/mremap.c
@@ -98,6 +98,7 @@ static void move_ptes(struct vm_area_str
 	new_ptl = pte_lockptr(mm, new_pmd);
 	if (new_ptl != old_ptl)
 		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+	arch_enter_lazy_mmu_mode();
 
 	for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
 				   new_pte++, new_addr += PAGE_SIZE) {
@@ -109,6 +110,7 @@ static void move_ptes(struct vm_area_str
 		set_pte_at(mm, new_addr, new_pte, pte);
 	}
 
+	arch_leave_lazy_mmu_mode();
 	if (new_ptl != old_ptl)
 		spin_unlock(new_ptl);
 	pte_unmap_nested(new_pte - 1);
mm/msync.c +2 -0
diff -r 553154516a1b -r 398f8fd6b334 mm/msync.c
@@ -30,6 +30,7 @@ static unsigned long msync_pte_range(str
 
 again:
 	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+	arch_enter_lazy_mmu_mode();
 	do {
 		struct page *page;
 
@@ -51,6 +52,7 @@ again:
 			ret += set_page_dirty(page);
 		progress += 3;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
+	arch_leave_lazy_mmu_mode();
 	pte_unmap_unlock(pte - 1, ptl);
 	cond_resched();
 	if (addr != end)
#25 lore raw

PATCH 1/1 Pass the mm struct into the pgd_free code so the mm is available here

In reply to Jeremy Fitzhardinge
5 files changed, 10 insertions(+), 4 deletions(-)
arch/i386/mm/pgtable.c     |    3 ++-
include/asm-i386/pgalloc.h |    4 ++--
include/asm-i386/pgtable.h |    1 +
include/linux/mm.h         |    4 ++++
kernel/fork.c              |    2 +-

===================================================================

arch/i386/mm/pgtable.c +2 -1
diff -r 398f8fd6b334 -r 8235caea9d68 arch/i386/mm/pgtable.c
@@ -275,9 +275,10 @@ out_oom:
 	return NULL;
 }
 
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm)
 {
 	int i;
+	pgd_t *pgd = mm->pgd;
 
 	/* in the PAE case user pgd entries are overwritten before usage */
 	if (PTRS_PER_PMD > 1)
include/asm-i386/pgalloc.h +2 -2
diff -r 398f8fd6b334 -r 8235caea9d68 include/asm-i386/pgalloc.h
@@ -3,7 +3,6 @@
 
 #include <asm/fixmap.h>
 #include <linux/threads.h>
-#include <linux/mm.h>		/* for struct page */
 
 #define pmd_populate_kernel(mm, pmd, pte) \
 		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
@@ -16,7 +15,8 @@
  * Allocate and free page tables.
  */
 extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *);
+#define pgd_free_mm(mm) pgd_free(mm)
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
 extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
include/asm-i386/pgtable.h +1 -0
diff -r 398f8fd6b334 -r 8235caea9d68 include/asm-i386/pgtable.h
@@ -393,6 +393,7 @@ extern pte_t *lookup_address(unsigned lo
 
 extern void noexec_setup(const char *str);
 
+#include <asm/pgalloc.h>
 #if defined(CONFIG_HIGHPTE)
 #define pte_offset_map(dir, address) \
 	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
include/linux/mm.h +4 -0
diff -r 398f8fd6b334 -r 8235caea9d68 include/linux/mm.h
@@ -1077,5 +1077,9 @@ extern int randomize_va_space;
 
 const char *arch_vma_name(struct vm_area_struct *vma);
 
+#ifndef pgd_free_mm
+#define pgd_free_mm(mm) pgd_free((mm)->pgd)
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
kernel/fork.c +1 -1
diff -r 398f8fd6b334 -r 8235caea9d68 kernel/fork.c
@@ -299,7 +299,7 @@ static inline int mm_alloc_pgd(struct mm
 
 static inline void mm_free_pgd(struct mm_struct * mm)
 {
-	pgd_free(mm->pgd);
+	pgd_free_mm(mm);
 }
 #else
 #define dup_mmap(mm, oldmm)	(0)
#26 lore raw

Re: [PATCH 12 of 13] Pass the mm struct into the pgd_free code so the mm is available here

nst char *arch_vma_name(struct vm_area_struct *vma);

include/linux/mm.h extern int randomize_va_space; · line 1082

Quoted 4 lines
include/linux/mm.h +3 -0
+#ifndef pgd_free_mm
+#define pgd_free_mm(mm) pgd_free((mm)->pgd)
+#endif

Sorry, but these ifdefs are too ugly. I would prefer if you just updated all architectures, even though it will make the patch somewhat bigger

-Andi

#27 lore raw

Re: [Xen-devel] Re: [PATCH 12 of 13] Pass the mm struct into the pgd_free code so the mm is available here

Quoted 11 lines · Andi Kleen

nst char *arch_vma_name(struct vm_area_struct *vma);

include/linux/mm.h extern int randomize_va_space; · line 1082

Quoted 5 lines
include/linux/mm.h +3 -0
+#ifndef pgd_free_mm
+#define pgd_free_mm(mm) pgd_free((mm)->pgd)
+#endif

Sorry, but these ifdefs are too ugly. I would prefer if you just updated all architectures, even though it will make the patch somewhat bigger

I'm fine with doing that, and yes this is ugly. Will take awhile though - for efficiency of mercurial patch tools, I deprecated all architectures but i386, x86_64, and um from my local tree. <Slaps head>.

Zach

#28 lore raw

Re: [Xen-devel] Re: [PATCH 12 of 13] Pass the mm struct into the pgd_free code so the mm is available here

Quoted 13 lines · * Zachary Amsden ([email protected]) wrote:
Quoted 12 lines · Andi Kleen

nst char *arch_vma_name(struct vm_area_struct *vma);

include/linux/mm.h extern int randomize_va_space; · line 1082

Quoted 5 lines
include/linux/mm.h +3 -0
+#ifndef pgd_free_mm
+#define pgd_free_mm(mm) pgd_free((mm)->pgd)
+#endif

Sorry, but these ifdefs are too ugly. I would prefer if you just updated all architectures, even though it will make the patch somewhat bigger

Quoted 3 lines

I'm fine with doing that, and yes this is ugly. Will take awhile though
- for efficiency of mercurial patch tools, I deprecated all architectures but i386, x86_64, and um from my local tree. <Slaps head>.

While you're at it, can you please make sure there's some nice changelog comments. The current one only has diffstat.

thanks,
-chris

#29 lore raw

PATCH 1/1 Put .note.* sections into a PT_NOTE segment in vmlinux

In reply to Jeremy Fitzhardinge
3 files changed, 101 insertions(+), 2 deletions(-)
arch/i386/kernel/vmlinux.lds.S    |   12 ++++-
include/asm-generic/vmlinux.lds.h |    3 +
include/linux/elfnote.h           |   88 +++++++++++++++++++++++++++++++++++++

This patch will pack any .note.* section into a PT_NOTE segment in the output file.

To do this, we tell ld that we need a PT_NOTE segment. This requires us to start explicitly mapping sections to segments, so we also need to explicitly create PT_LOAD segments for text and data, and map the sections to them appropriately. Fortunately, each section will default to its previous section's segment, so it doesn't take many changes to vmlinux.lds.S.

This only changes i386 for now, but I presume the corresponding changes for other architectures will be as simple.

This change also adds <linux/elfnote.h>, which defines C and Assembler macros for actually creating ELF notes.

Cc Eric W. Biederman <[email protected]>
Cc Hollis Blanchard <[email protected]>

===================================================================

arch/i386/kernel/vmlinux.lds.S +10 -2
diff -r 8235caea9d68 -r 2bf2abf6e970 arch/i386/kernel/vmlinux.lds.S
@@ -13,6 +13,12 @@ OUTPUT_ARCH(i386)
 OUTPUT_ARCH(i386)
 ENTRY(phys_startup_32)
 jiffies = jiffies_64;
+
+PHDRS {
+	text PT_LOAD FLAGS(5);	/* R_E */
+	data PT_LOAD FLAGS(7);	/* RWE */
+	note PT_NOTE FLAGS(4);	/* R__ */
+}
 SECTIONS
 {
   . = __KERNEL_START;
@@ -26,7 +32,7 @@ SECTIONS
 	KPROBES_TEXT
 	*(.fixup)
 	*(.gnu.warning)
-	} = 0x9090
+	} :text = 0x9090
 
   _etext = .;			/* End of text section */
 
@@ -48,7 +54,7 @@ SECTIONS
   .data : AT(ADDR(.data) - LOAD_OFFSET) {	/* Data */
 	*(.data)
 	CONSTRUCTORS
-	}
+	} :data
 
   . = ALIGN(4096);
   __nosave_begin = .;
@@ -184,4 +190,6 @@ SECTIONS
   STABS_DEBUG
 
   DWARF_DEBUG
+
+  NOTES
 }
include/asm-generic/vmlinux.lds.h +3 -0
diff -r 8235caea9d68 -r 2bf2abf6e970 include/asm-generic/vmlinux.lds.h
@@ -194,3 +194,6 @@
 		.stab.index 0 : { *(.stab.index) }			\
 		.stab.indexstr 0 : { *(.stab.indexstr) }		\
 		.comment 0 : { *(.comment) }
+
+#define NOTES								\
+		.notes : { *(.note.*) } :note
include/linux/elfnote.h new file +88 -0

88 lines not on this page · raw message

#30 lore raw

PATCH 1/1 x86_43: Put .note.* sections into a PT_NOTE segment in vmlinux

Quoted 2 lines · Jeremy Fitzhardinge

This patch will pack any .note.* section into a PT_NOTE segment in the output file.

[...]

Quoted 2 lines

This only changes i386 for now, but I presume the corresponding changes for other architectures will be as simple.

Here is the patch for x86_64.

arch/x86_64/kernel/vmlinux.lds.S +9 -2
diff -urN ref-linux-2.6.16.13/arch/x86_64/kernel/vmlinux.lds.S x86-64_elfnotes/arch/x86_64/kernel/vmlinux.lds.S
@@ -14,6 +14,11 @@
 OUTPUT_ARCH(i386:x86-64)
 ENTRY(phys_startup_64)
 jiffies_64 = jiffies;
+PHDRS {
+	text PT_LOAD FLAGS(5);	/* R_E */
+	data PT_LOAD FLAGS(7);	/* RWE */
+	note PT_NOTE FLAGS(4);	/* R__ */
+}
 SECTIONS
 {
   . = __START_KERNEL;
@@ -26,7 +31,7 @@
 	KPROBES_TEXT
 	*(.fixup)
 	*(.gnu.warning)
-	} = 0x9090
+	} :text = 0x9090
   				/* out-of-line lock text */
   .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
 
@@ -43,7 +48,7 @@
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
 	*(.data)
 	CONSTRUCTORS
-	}
+	} :data
 
   _edata = .;			/* End of data section */
 
@@ -201,4 +206,6 @@
   STABS_DEBUG
 
   DWARF_DEBUG
+
+  NOTES
 }
#31 lore raw

Re: [PATCH 1 of 1] x86_43: Put .note.* sections into a PT_NOTE segment in vmlinux

Quoted 8 lines · On Tue, 22 Aug 2006 12:14:18 +0100 Ian Campbell <[email protected]>…
Quoted 2 lines · Jeremy Fitzhardinge

This patch will pack any .note.* section into a PT_NOTE segment in the output file.

[...]

Quoted 2 lines

This only changes i386 for now, but I presume the corresponding changes for other architectures will be as simple.

Here is the patch for x86_64.

Ok, but can you please resubmit with complete changelog/rationale?

Thanks,

-Andi

#32 lore raw

Re: [PATCH 1 of 1] x86_43: Put .note.* sections into a PT_NOTE segment in vmlinux

Quoted 6 lines · Andi Kleen
Quoted 3 lines · On Tue, 22 Aug 2006 12:14:18 +0100 Ian Campbell <[email protected]>…
Quoted 2 lines · Jeremy Fitzhardinge

This patch will pack any .note.* section into a PT_NOTE segment in the output file.

Quoted 7 lines
Quoted 5 lines

[...]

Quoted 2 lines

This only changes i386 for now, but I presume the corresponding changes for other architectures will be as simple.

Here is the patch for x86_64.

Ok, but can you please resubmit with complete changelog/rationale?

Will do.

I've just noticed a bunch of sections (.vsyscall_*, .xtime and others) which aren't getting put into segments for some reason. I'll figure that out first...

Ian.

#33 lore raw
In reply to Jeremy Fitzhardinge
Quoted 2 lines · Jeremy Fitzhardinge

[ REPOST: Apologies to anyone who has seen this before. It
didn't make it onto any of the lists it should have. -J ]

I tried to apply these patches (except the ones I didn't like:
8, 10, 12) to my tree, but couldn't because they are all MIME demaged:

+ pte =3D (mm =3D=3D &init_mm) ?

etc.

Can you please repost a version without that (and ideally fix 8, 10, 12)?

-Andi