* Increase UPAGES from 3 to 4. This is the kernel thread stack size.
* Add infrastructure to make it possible to allocate a guard page along
with a kmem allocation and use it when allocating kernel thread stacks.
The first page of stacks allocated this way will be non-accessible
(hence the increase in UPAGES).
#define MAXDUMPPGS (DFLTPHYS/PAGE_SIZE)
#define IOPAGES 2 /* pages of i/o permission bitmap */
-#define UPAGES 3 /* pages of u-area */
+#define UPAGES 4 /* pages of u-area */
/*
* Ceiling on amount of swblock kva space, can be changed via
#define MAXDUMPPGS (DFLTPHYS/PAGE_SIZE)
#define IOPAGES 2 /* pages of i/o permission bitmap */
-#define UPAGES 3 /* pages of u-area */
+#define UPAGES 4 /* pages of u-area */
/*
* Ceiling on amount of swblock kva space, can be changed via
#define MODE_DDB "ddb"
#define MODE_GDB "gdb"
+/*
+ * This sysctl forces the kernel to enter the debugger.
+ */
static int
sysctl_debug_enter_debugger(SYSCTL_HANDLER_ARGS)
{
}
return error;
}
+SYSCTL_PROC(_debug, OID_AUTO, enter_debugger, CTLTYPE_STRING | CTLFLAG_RW,
+ 0, 0, sysctl_debug_enter_debugger, "A", DESCRIPTION);
+/*
+ * This sysctl forces a kernel panic.
+ */
static int
sysctl_debug_panic(SYSCTL_HANDLER_ARGS)
{
panic("sysctl_debug_panic");
return err;
}
-
-SYSCTL_PROC(_debug, OID_AUTO, enter_debugger, CTLTYPE_STRING | CTLFLAG_RW,
- 0, 0, sysctl_debug_enter_debugger, "A", DESCRIPTION);
-
SYSCTL_PROC(_debug, OID_AUTO, panic, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
sysctl_debug_panic, "I", "Set to panic the system");
+
+/*
+ * This sysctl forces a kernel stack guard panic. If you don't get
+ * a nice clean page-fault guard panic message then the guard isn't
+ * working.
+ */
+static void
+stack_guard_panic2(void)
+{
+ volatile char dummy[128];
+
+ stack_guard_panic2();
+ /* NOT REACHED */
+ kprintf("%p", dummy); /* dummy to force dummy[] to be allocated */
+}
+
+static int
+sysctl_debug_panic2(SYSCTL_HANDLER_ARGS)
+{
+ int err;
+ int val = 0;
+
+ err = sysctl_handle_int(oidp, &val, sizeof(val), req);
+ if (val == 1)
+ stack_guard_panic2();
+ return err;
+}
+SYSCTL_PROC(_debug, OID_AUTO, panic2, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+ sysctl_debug_panic2, "I", "Set to panic the system w/stack guard");
}
}
if (stack == NULL) {
- stack = (void *)kmem_alloc(&kernel_map, stksize);
+ stack = (void *)kmem_alloc_stack(&kernel_map, stksize);
flags |= TDF_ALLOCATED_STACK;
}
if (cpu < 0)
#ifndef _VM_VM_MAP_H_
#include <vm/vm_map.h>
#endif
+#ifndef _VM_VM_KERN_H_
+#include <vm/vm_kern.h>
+#endif
#ifndef _MACHINE_TYPES_H_
#include <machine/types.h>
#endif
return(kmem_alloc3(map, size, 0));
}
+static __inline
+vm_offset_t
+kmem_alloc_stack (vm_map_t map, vm_size_t size)
+{
+ return(kmem_alloc3(map, size, KM_STACK));
+}
+
#endif /* _KERNEL */
#endif /* !_VM_VM_EXTERN_H_ */
*/
fs.map_generation = fs.map->timestamp;
- if (fs.entry->eflags & MAP_ENTRY_NOFAULT) {
- panic("vm_fault: fault on nofault entry, addr: %lx",
- (u_long)vaddr);
+ if (fs.entry->eflags & (MAP_ENTRY_NOFAULT | MAP_ENTRY_KSTACK)) {
+ if (fs.entry->eflags & MAP_ENTRY_NOFAULT) {
+ panic("vm_fault: fault on nofault entry, addr: %p",
+ (void *)vaddr);
+ }
+ if ((fs.entry->eflags & MAP_ENTRY_KSTACK) &&
+ vaddr >= fs.entry->start &&
+ vaddr < fs.entry->start + PAGE_SIZE) {
+ panic("vm_fault: fault on stack guard, addr: %p",
+ (void *)vaddr);
+ }
}
/*
end = entry->end;
fictitious = entry->object.vm_object &&
(entry->object.vm_object->type == OBJT_DEVICE);
-
+ if (entry->eflags & MAP_ENTRY_KSTACK)
+ start += PAGE_SIZE;
lwkt_gettoken(&vm_token);
vm_map_unlock(map);
map->timestamp++;
end = entry->end;
fictitious = entry->object.vm_object &&
(entry->object.vm_object->type == OBJT_DEVICE);
+ if (entry->eflags & MAP_ENTRY_KSTACK)
+ start += PAGE_SIZE;
/*
* Since the pages are wired down, we must be able to get their
kmem_alloc3(vm_map_t map, vm_size_t size, int kmflags)
{
vm_offset_t addr;
+ vm_offset_t gstart;
vm_offset_t i;
int count;
+ int cow;
size = round_page(size);
else
count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
+ if (kmflags & KM_STACK) {
+ cow = MAP_IS_KSTACK;
+ gstart = PAGE_SIZE;
+ } else {
+ cow = 0;
+ gstart = 0;
+ }
+
/*
* Use the kernel object for wired-down kernel pages. Assume that no
* region of the kernel object is referenced more than once.
&kernel_object, addr, addr, addr + size,
VM_MAPTYPE_NORMAL,
VM_PROT_ALL, VM_PROT_ALL,
- 0);
+ cow);
vm_map_unlock(map);
if (kmflags & KM_KRESERVE)
vm_map_entry_krelease(count);
* We're intentionally not activating the pages we allocate to prevent a
* race with page-out. vm_map_wire will wire the pages.
*/
-
lwkt_gettoken(&vm_token);
- for (i = 0; i < size; i += PAGE_SIZE) {
+ for (i = gstart; i < size; i += PAGE_SIZE) {
vm_page_t mem;
mem = vm_page_grab(&kernel_object, OFF_TO_IDX(addr + i),
/*
* And finally, mark the data as non-pageable.
+ *
+ * NOTE: vm_map_wire() handles any kstack guard.
*/
vm_map_wire(map, (vm_offset_t)addr, addr + size, kmflags);
*/
#define KM_PAGEABLE 0x0001
#define KM_KRESERVE 0x0002
+#define KM_STACK 0x0004
/* Kernel memory management definitions. */
extern struct vm_map buffer_map;
protoeflags |= MAP_ENTRY_NOCOREDUMP;
if (cow & MAP_IS_STACK)
protoeflags |= MAP_ENTRY_STACK;
+ if (cow & MAP_IS_KSTACK)
+ protoeflags |= MAP_ENTRY_KSTACK;
lwkt_gettoken(&vm_token);
lwkt_gettoken(&vmobj_token);
#define MAP_ENTRY_IN_TRANSITION 0x0100 /* entry being changed */
#define MAP_ENTRY_NEEDS_WAKEUP 0x0200 /* waiter's in transition */
#define MAP_ENTRY_NOCOREDUMP 0x0400 /* don't include in a core */
+#define MAP_ENTRY_KSTACK 0x0800 /* guarded kernel stack */
/*
* flags for vm_map_[un]clip_range()
#define MAP_PREFAULT_PARTIAL 0x0010
#define MAP_DISABLE_SYNCER 0x0020
#define MAP_IS_STACK 0x0040
+#define MAP_IS_KSTACK 0x0080
#define MAP_DISABLE_COREDUMP 0x0100
#define MAP_PREFAULT_MADVISE 0x0200 /* from (user) madvise request */