1996-06-14 10:04:54 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1992 Terrence R. Lambert.
|
|
|
|
* Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* William Jolitz.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1996-06-14 10:04:54 +00:00
|
|
|
*/
|
|
|
|
|
1998-06-03 08:48:00 +00:00
|
|
|
#include "opt_atalk.h"
|
1999-10-13 11:03:41 +00:00
|
|
|
#include "opt_compat.h"
|
1997-12-05 11:48:53 +00:00
|
|
|
#include "opt_cpu.h"
|
|
|
|
#include "opt_ddb.h"
|
1998-06-03 08:48:00 +00:00
|
|
|
#include "opt_inet.h"
|
|
|
|
#include "opt_ipx.h"
|
2001-01-29 09:38:39 +00:00
|
|
|
#include "opt_isa.h"
|
1997-09-01 10:42:03 +00:00
|
|
|
#include "opt_maxmem.h"
|
1998-05-19 12:58:05 +00:00
|
|
|
#include "opt_msgbuf.h"
|
2001-01-19 13:19:02 +00:00
|
|
|
#include "opt_npx.h"
|
1996-06-14 10:04:54 +00:00
|
|
|
#include "opt_perfmon.h"
|
1996-09-12 11:12:18 +00:00
|
|
|
#include "opt_userconfig.h"
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/sysproto.h>
|
|
|
|
#include <sys/signalvar.h>
|
2000-10-18 09:05:09 +00:00
|
|
|
#include <sys/ipl.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#include <sys/kernel.h>
|
2000-09-07 13:35:44 +00:00
|
|
|
#include <sys/ktr.h>
|
1998-10-09 12:36:25 +00:00
|
|
|
#include <sys/linker.h>
|
2001-04-01 06:40:45 +00:00
|
|
|
#include <sys/lock.h>
|
1999-12-06 04:53:08 +00:00
|
|
|
#include <sys/malloc.h>
|
2000-10-20 10:17:26 +00:00
|
|
|
#include <sys/mutex.h>
|
2001-05-10 17:45:49 +00:00
|
|
|
#include <sys/pcpu.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#include <sys/proc.h>
|
2000-05-05 09:59:14 +00:00
|
|
|
#include <sys/bio.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/reboot.h>
|
2001-05-02 13:48:39 +00:00
|
|
|
#include <sys/smp.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#include <sys/callout.h>
|
|
|
|
#include <sys/msgbuf.h>
|
|
|
|
#include <sys/sysent.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/vmmeter.h>
|
1999-04-18 14:42:20 +00:00
|
|
|
#include <sys/bus.h>
|
2000-09-22 12:54:50 +00:00
|
|
|
#include <sys/eventhandler.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/vm_param.h>
|
1997-02-10 11:53:20 +00:00
|
|
|
#include <sys/lock.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#include <vm/vm_kern.h>
|
|
|
|
#include <vm/vm_object.h>
|
|
|
|
#include <vm/vm_page.h>
|
|
|
|
#include <vm/vm_map.h>
|
|
|
|
#include <vm/vm_pager.h>
|
|
|
|
#include <vm/vm_extern.h>
|
|
|
|
|
|
|
|
#include <sys/user.h>
|
|
|
|
#include <sys/exec.h>
|
1999-08-09 10:35:05 +00:00
|
|
|
#include <sys/cons.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
#include <ddb/ddb.h>
|
|
|
|
|
|
|
|
#include <net/netisr.h>
|
|
|
|
|
|
|
|
#include <machine/cpu.h>
|
2000-08-14 07:27:10 +00:00
|
|
|
#include <machine/cputypes.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#include <machine/reg.h>
|
|
|
|
#include <machine/clock.h>
|
|
|
|
#include <machine/specialreg.h>
|
|
|
|
#include <machine/bootinfo.h>
|
|
|
|
#include <machine/md_var.h>
|
2000-10-02 08:57:21 +00:00
|
|
|
#include <machine/pc/bios.h>
|
1997-10-12 11:58:09 +00:00
|
|
|
#include <machine/pcb_ext.h> /* pcb.h included via sys/user.h */
|
2000-09-07 13:35:44 +00:00
|
|
|
#include <machine/globals.h>
|
2001-03-23 08:57:22 +00:00
|
|
|
#include <machine/intrcnt.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#ifdef PERFMON
|
|
|
|
#include <machine/perfmon.h>
|
|
|
|
#endif
|
|
|
|
|
1999-04-18 14:42:20 +00:00
|
|
|
#ifdef OLD_BUS_ARCH
|
1996-09-03 10:24:29 +00:00
|
|
|
#include <i386/isa/isa_device.h>
|
1999-04-18 14:42:20 +00:00
|
|
|
#endif
|
2000-09-07 13:35:44 +00:00
|
|
|
#include <i386/isa/icu.h>
|
1997-06-02 15:45:40 +00:00
|
|
|
#include <i386/isa/intr_machdep.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#ifdef PC98
|
1996-07-23 07:46:59 +00:00
|
|
|
#include <pc98/pc98/pc98_machdep.h>
|
1997-12-16 10:22:49 +00:00
|
|
|
#include <pc98/pc98/pc98.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#else
|
1999-11-25 12:43:07 +00:00
|
|
|
#include <isa/rtc.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
#endif
|
1999-06-03 13:49:52 +00:00
|
|
|
#include <machine/vm86.h>
|
1998-05-19 12:58:05 +00:00
|
|
|
#include <sys/ptrace.h>
|
1999-09-29 15:06:27 +00:00
|
|
|
#include <machine/sigframe.h>
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
extern void init386 __P((int first));
|
|
|
|
extern void dblfault_handler __P((void));
|
|
|
|
|
1997-03-22 18:54:54 +00:00
|
|
|
extern void printcpuinfo(void); /* XXX header file */
|
1996-07-23 07:46:59 +00:00
|
|
|
extern void earlysetcpuclass(void); /* same header file */
|
1997-03-22 18:54:54 +00:00
|
|
|
extern void finishidentcpu(void);
|
|
|
|
extern void panicifcpuunsupported(void);
|
|
|
|
extern void initializecpu(void);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
|
|
|
|
#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
static void cpu_startup __P((void *));
|
|
|
|
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL)
|
|
|
|
|
1997-03-22 18:54:54 +00:00
|
|
|
#ifdef PC98
|
1999-04-18 14:42:20 +00:00
|
|
|
int need_pre_dma_flush; /* If 1, use wbinvd befor DMA transfer. */
|
1997-03-22 18:54:54 +00:00
|
|
|
int need_post_dma_flush; /* If 1, use invd after DMA transfer. */
|
|
|
|
#endif
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1998-05-19 12:58:05 +00:00
|
|
|
int _udatasel, _ucodesel;
|
1996-06-14 10:04:54 +00:00
|
|
|
u_int atdevbase;
|
|
|
|
|
1997-12-14 12:31:44 +00:00
|
|
|
#if defined(SWTCH_OPTIM_STATS)
|
|
|
|
extern int swtch_optim_stats;
|
|
|
|
SYSCTL_INT(_debug, OID_AUTO, swtch_optim_stats,
|
|
|
|
CTLFLAG_RD, &swtch_optim_stats, 0, "");
|
|
|
|
SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count,
|
|
|
|
CTLFLAG_RD, &tlb_flush_count, 0, "");
|
|
|
|
#endif
|
|
|
|
|
1998-08-31 08:41:58 +00:00
|
|
|
#ifdef PC98
|
1999-04-18 14:42:20 +00:00
|
|
|
static int ispc98 = 1;
|
1998-08-31 08:41:58 +00:00
|
|
|
#else
|
1999-04-18 14:42:20 +00:00
|
|
|
static int ispc98 = 0;
|
1998-08-31 08:41:58 +00:00
|
|
|
#endif
|
1998-09-01 02:04:17 +00:00
|
|
|
SYSCTL_INT(_machdep, OID_AUTO, ispc98, CTLFLAG_RD, &ispc98, 0, "");
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
int physmem = 0;
|
|
|
|
int cold = 1;
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
static void osendsig __P((sig_t catcher, int sig, sigset_t *mask, u_long code));
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
|
|
|
int error = sysctl_handle_int(oidp, 0, ctob(physmem), req);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD,
|
|
|
|
0, 0, sysctl_hw_physmem, "I", "");
|
|
|
|
|
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_hw_usermem(SYSCTL_HANDLER_ARGS)
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
|
|
|
int error = sysctl_handle_int(oidp, 0,
|
|
|
|
ctob(physmem - cnt.v_wire_count), req);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD,
|
|
|
|
0, 0, sysctl_hw_usermem, "I", "");
|
|
|
|
|
1998-07-02 12:39:32 +00:00
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_hw_availpages(SYSCTL_HANDLER_ARGS)
|
1998-07-02 12:39:32 +00:00
|
|
|
{
|
|
|
|
int error = sysctl_handle_int(oidp, 0,
|
|
|
|
i386_btop(avail_end - avail_start), req);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_INT|CTLFLAG_RD,
|
|
|
|
0, 0, sysctl_hw_availpages, "I", "");
|
|
|
|
|
1998-09-15 03:50:08 +00:00
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_machdep_msgbuf(SYSCTL_HANDLER_ARGS)
|
1998-09-15 03:50:08 +00:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
1998-09-30 13:21:44 +00:00
|
|
|
/* Unwind the buffer, so that it's linear (possibly starting with
|
|
|
|
* some initial nulls).
|
1998-09-15 03:50:08 +00:00
|
|
|
*/
|
|
|
|
error=sysctl_handle_opaque(oidp,msgbufp->msg_ptr+msgbufp->msg_bufr,
|
|
|
|
msgbufp->msg_size-msgbufp->msg_bufr,req);
|
|
|
|
if(error) return(error);
|
|
|
|
if(msgbufp->msg_bufr>0) {
|
|
|
|
error=sysctl_handle_opaque(oidp,msgbufp->msg_ptr,
|
|
|
|
msgbufp->msg_bufr,req);
|
|
|
|
}
|
|
|
|
return(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_machdep, OID_AUTO, msgbuf, CTLTYPE_STRING|CTLFLAG_RD,
|
1998-09-30 13:21:44 +00:00
|
|
|
0, 0, sysctl_machdep_msgbuf, "A","Contents of kernel message buffer");
|
|
|
|
|
|
|
|
static int msgbuf_clear;
|
|
|
|
|
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_machdep_msgbuf_clear(SYSCTL_HANDLER_ARGS)
|
1998-09-30 13:21:44 +00:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,
|
|
|
|
req);
|
|
|
|
if (!error && req->newptr) {
|
|
|
|
/* Clear the buffer and reset write pointer */
|
|
|
|
bzero(msgbufp->msg_ptr,msgbufp->msg_size);
|
|
|
|
msgbufp->msg_bufr=msgbufp->msg_bufx=0;
|
|
|
|
msgbuf_clear=0;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_machdep, OID_AUTO, msgbuf_clear, CTLTYPE_INT|CTLFLAG_RW,
|
|
|
|
&msgbuf_clear, 0, sysctl_machdep_msgbuf_clear, "I",
|
|
|
|
"Clear kernel message buffer");
|
1998-09-15 03:50:08 +00:00
|
|
|
|
1997-11-25 09:54:36 +00:00
|
|
|
int bootverbose = 0, Maxmem = 0;
|
1996-06-14 10:04:54 +00:00
|
|
|
#ifdef PC98
|
|
|
|
int Maxmem_under16M = 0;
|
|
|
|
#endif
|
|
|
|
long dumplo;
|
|
|
|
|
|
|
|
vm_offset_t phys_avail[10];
|
|
|
|
|
|
|
|
/* must be 2 less so 0 0 can signal end of chunks */
|
|
|
|
#define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2)
|
|
|
|
|
|
|
|
static vm_offset_t buffer_sva, buffer_eva;
|
|
|
|
vm_offset_t clean_sva, clean_eva;
|
|
|
|
static vm_offset_t pager_sva, pager_eva;
|
2000-08-12 07:35:12 +00:00
|
|
|
static struct trapframe proc0_tf;
|
2001-01-07 07:59:19 +00:00
|
|
|
#ifndef SMP
|
|
|
|
static struct globaldata __globaldata;
|
|
|
|
#endif
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2001-01-21 07:52:20 +00:00
|
|
|
struct mtx sched_lock;
|
|
|
|
struct mtx Giant;
|
2000-09-07 13:35:44 +00:00
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
static void
|
|
|
|
cpu_startup(dummy)
|
|
|
|
void *dummy;
|
|
|
|
{
|
|
|
|
register unsigned i;
|
|
|
|
register caddr_t v;
|
|
|
|
vm_offset_t maxaddr;
|
|
|
|
vm_size_t size = 0;
|
|
|
|
int firstaddr;
|
|
|
|
vm_offset_t minaddr;
|
2000-12-16 03:25:08 +00:00
|
|
|
int physmem_est;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
if (boothowto & RB_VERBOSE)
|
|
|
|
bootverbose++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Good {morning,afternoon,evening,night}.
|
|
|
|
*/
|
2000-07-10 07:13:36 +00:00
|
|
|
printf("%s", version);
|
1996-07-23 07:46:59 +00:00
|
|
|
earlysetcpuclass();
|
1996-06-14 10:04:54 +00:00
|
|
|
startrtclock();
|
1997-03-22 18:54:54 +00:00
|
|
|
printcpuinfo();
|
|
|
|
panicifcpuunsupported();
|
1996-07-23 07:46:59 +00:00
|
|
|
#ifdef PERFMON
|
|
|
|
perfmon_init();
|
|
|
|
#endif
|
1999-02-04 09:55:42 +00:00
|
|
|
printf("real memory = %u (%uK bytes)\n", ptoa(Maxmem), ptoa(Maxmem) / 1024);
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Display any holes after the first chunk of extended memory.
|
|
|
|
*/
|
1997-09-05 10:14:36 +00:00
|
|
|
if (bootverbose) {
|
|
|
|
int indx;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1997-09-05 10:14:36 +00:00
|
|
|
printf("Physical memory chunk(s):\n");
|
|
|
|
for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
|
2000-10-03 13:27:31 +00:00
|
|
|
unsigned int size1 = phys_avail[indx + 1] - phys_avail[indx];
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1999-02-04 09:55:42 +00:00
|
|
|
printf("0x%08x - 0x%08x, %u bytes (%u pages)\n",
|
1998-07-11 17:00:33 +00:00
|
|
|
phys_avail[indx], phys_avail[indx + 1] - 1, size1,
|
|
|
|
size1 / PAGE_SIZE);
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-09-22 12:20:42 +00:00
|
|
|
/*
|
|
|
|
* Calculate callout wheel size
|
|
|
|
*/
|
|
|
|
for (callwheelsize = 1, callwheelbits = 0;
|
|
|
|
callwheelsize < ncallout;
|
|
|
|
callwheelsize <<= 1, ++callwheelbits)
|
|
|
|
;
|
|
|
|
callwheelmask = callwheelsize - 1;
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Allocate space for system data structures.
|
|
|
|
* The first available kernel virtual address is in "v".
|
|
|
|
* As pages of kernel virtual memory are allocated, "v" is incremented.
|
|
|
|
* As pages of memory are allocated and cleared,
|
|
|
|
* "firstaddr" is incremented.
|
|
|
|
* An index into the kernel page table corresponding to the
|
|
|
|
* virtual memory address maintained in "v" is kept in "mapaddr".
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make two passes. The first pass calculates how much memory is
|
|
|
|
* needed and allocates it. The second pass assigns virtual
|
|
|
|
* addresses to the various data structures.
|
|
|
|
*/
|
|
|
|
firstaddr = 0;
|
|
|
|
again:
|
|
|
|
v = (caddr_t)firstaddr;
|
|
|
|
|
|
|
|
#define valloc(name, type, num) \
|
|
|
|
(name) = (type *)v; v = (caddr_t)((name)+(num))
|
|
|
|
#define valloclim(name, type, num, lim) \
|
|
|
|
(name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
|
1998-01-30 12:03:13 +00:00
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
valloc(callout, struct callout, ncallout);
|
1997-09-22 12:20:42 +00:00
|
|
|
valloc(callwheel, struct callout_tailq, callwheelsize);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2000-12-16 03:25:08 +00:00
|
|
|
/*
|
|
|
|
* Discount the physical memory larger than the size of kernel_map
|
|
|
|
* to avoid eating up all of KVA space.
|
|
|
|
*/
|
|
|
|
if (kernel_map->first_free == NULL) {
|
|
|
|
printf("Warning: no free entries in kernel_map.\n");
|
|
|
|
physmem_est = physmem;
|
|
|
|
} else
|
|
|
|
physmem_est = min(physmem, kernel_map->max_offset - kernel_map->min_offset);
|
|
|
|
|
2000-03-28 15:04:29 +00:00
|
|
|
/*
|
|
|
|
* The nominal buffer size (and minimum KVA allocation) is BKVASIZE.
|
|
|
|
* For the first 64MB of ram nominally allocate sufficient buffers to
|
|
|
|
* cover 1/4 of our ram. Beyond the first 64MB allocate additional
|
|
|
|
* buffers to cover 1/20 of our ram over 64MB.
|
|
|
|
*
|
|
|
|
* factor represents the 1/4 x ram conversion.
|
|
|
|
*/
|
1996-06-14 10:04:54 +00:00
|
|
|
if (nbuf == 0) {
|
2000-03-28 15:04:29 +00:00
|
|
|
int factor = 4 * BKVASIZE / PAGE_SIZE;
|
|
|
|
|
1999-11-03 08:25:40 +00:00
|
|
|
nbuf = 50;
|
2000-12-16 03:25:08 +00:00
|
|
|
if (physmem_est > 1024)
|
|
|
|
nbuf += min((physmem_est - 1024) / factor, 16384 / factor);
|
|
|
|
if (physmem_est > 16384)
|
|
|
|
nbuf += (physmem_est - 16384) * 2 / (factor * 5);
|
2000-03-28 15:04:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not allow the buffer_map to be more then 1/2 the size of the
|
|
|
|
* kernel_map.
|
|
|
|
*/
|
|
|
|
if (nbuf > (kernel_map->max_offset - kernel_map->min_offset) /
|
|
|
|
(BKVASIZE * 2)) {
|
|
|
|
nbuf = (kernel_map->max_offset - kernel_map->min_offset) /
|
|
|
|
(BKVASIZE * 2);
|
|
|
|
printf("Warning: nbufs capped at %d\n", nbuf);
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
2000-03-28 15:04:29 +00:00
|
|
|
|
1999-07-08 12:48:53 +00:00
|
|
|
nswbuf = max(min(nbuf/4, 256), 16);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
valloc(swbuf, struct buf, nswbuf);
|
|
|
|
valloc(buf, struct buf, nbuf);
|
1999-07-08 12:48:53 +00:00
|
|
|
v = bufhashinit(v);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* End of first pass, size has been calculated so allocate memory
|
|
|
|
*/
|
|
|
|
if (firstaddr == 0) {
|
|
|
|
size = (vm_size_t)(v - firstaddr);
|
|
|
|
firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
|
|
|
|
if (firstaddr == 0)
|
|
|
|
panic("startup: no room for tables");
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End of second pass, addresses have been assigned
|
|
|
|
*/
|
|
|
|
if ((vm_size_t)(v - firstaddr) != size)
|
|
|
|
panic("startup: table size inconsistency");
|
|
|
|
|
|
|
|
clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva,
|
1998-01-24 03:15:37 +00:00
|
|
|
(nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size);
|
1996-06-14 10:04:54 +00:00
|
|
|
buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva,
|
1998-01-24 03:15:37 +00:00
|
|
|
(nbuf*BKVASIZE));
|
2001-02-04 07:00:47 +00:00
|
|
|
buffer_map->system_map = 1;
|
1996-06-14 10:04:54 +00:00
|
|
|
pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva,
|
1998-01-24 03:15:37 +00:00
|
|
|
(nswbuf*MAXPHYS) + pager_map_size);
|
1997-08-06 09:43:45 +00:00
|
|
|
pager_map->system_map = 1;
|
1996-06-14 10:04:54 +00:00
|
|
|
exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
|
1998-03-02 10:02:01 +00:00
|
|
|
(16*(ARG_MAX+(PAGE_SIZE*3))));
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
/*
|
Big mbuf subsystem diff #1: incorporate mutexes and fix things up somewhat
to accomodate the changes.
Here's a list of things that have changed (I may have left out a few); for a
relatively complete list, see http://people.freebsd.org/~bmilekic/mtx_journal
* Remove old (once useful) mcluster code for MCLBYTES > PAGE_SIZE which
nobody uses anymore. It was great while it lasted, but now we're moving
onto bigger and better things (Approved by: wollman).
* Practically re-wrote the allocation macros in sys/sys/mbuf.h to accomodate
new allocations which grab the necessary lock.
* Make sure that necessary mbstat variables are manipulated with
corresponding atomic() routines.
* Changed the "wait" routines, cleaned it up, made one routine that does
the job.
* Generalized MWAKEUP() macro. Got rid of m_retry and m_retryhdr, as they
are now included in the generalized "wait" routines.
* Sleep routines now use msleep().
* Free lists have locks.
* etc... probably other stuff I'm missing...
Things to look out for and work on later:
* find a better way to (dynamically) adjust EXT_COUNTERS
* move necessity to recurse on a lock from drain routines by providing
lock-free lower-level version of MFREE() (and possibly m_free()?).
* checkout include of mutex.h in sys/sys/mbuf.h - probably violating
general philosophy here.
The code has been reviewed quite a bit, but problems may arise... please,
don't panic! Send me Emails: bmilekic@freebsd.org
Reviewed by: jlemon, cp, alfred, others?
2000-09-30 06:30:39 +00:00
|
|
|
* XXX: Mbuf system machine-specific initializations should
|
|
|
|
* go here, if anywhere.
|
1996-06-14 10:04:54 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize callouts
|
|
|
|
*/
|
1997-09-22 12:20:42 +00:00
|
|
|
SLIST_INIT(&callfree);
|
|
|
|
for (i = 0; i < ncallout; i++) {
|
2000-11-26 06:29:33 +00:00
|
|
|
callout_init(&callout[i], 0);
|
1999-03-06 09:43:01 +00:00
|
|
|
callout[i].c_flags = CALLOUT_LOCAL_ALLOC;
|
1997-09-22 12:20:42 +00:00
|
|
|
SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < callwheelsize; i++) {
|
|
|
|
TAILQ_INIT(&callwheel[i]);
|
|
|
|
}
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2001-01-19 01:59:14 +00:00
|
|
|
mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE);
|
2000-11-20 12:06:08 +00:00
|
|
|
|
1996-12-15 09:18:48 +00:00
|
|
|
#if defined(USERCONFIG)
|
1998-11-06 08:07:32 +00:00
|
|
|
userconfig();
|
1999-01-16 11:38:03 +00:00
|
|
|
cninit(); /* the preferred console may have changed */
|
1996-12-15 09:18:48 +00:00
|
|
|
#endif
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1999-02-04 09:55:42 +00:00
|
|
|
printf("avail memory = %u (%uK bytes)\n", ptoa(cnt.v_free_count),
|
1996-06-14 10:04:54 +00:00
|
|
|
ptoa(cnt.v_free_count) / 1024);
|
|
|
|
|
1997-08-27 08:43:21 +00:00
|
|
|
/*
|
|
|
|
* Set up buffers, so they can be used to read disk labels.
|
|
|
|
*/
|
|
|
|
bufinit();
|
|
|
|
vm_pager_bufferinit();
|
|
|
|
|
2001-04-27 19:28:25 +00:00
|
|
|
globaldata_register(GLOBALDATA);
|
2001-05-10 17:45:49 +00:00
|
|
|
#ifndef SMP
|
2001-05-02 13:48:39 +00:00
|
|
|
/* For SMP, we delay the cpu_setregs() until after SMP startup. */
|
2000-08-12 07:35:12 +00:00
|
|
|
cpu_setregs();
|
2001-05-02 13:48:39 +00:00
|
|
|
#endif
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send an interrupt to process.
|
|
|
|
*
|
|
|
|
* Stack is set up to allow sigcode stored
|
|
|
|
* at top to call routine, followed by kcall
|
|
|
|
* to sigreturn routine below. After sigreturn
|
|
|
|
* resets the signal mask, the stack, and the
|
|
|
|
* frame pointer, it returns to the user
|
|
|
|
* specified pc, psl.
|
|
|
|
*/
|
1999-09-29 15:06:27 +00:00
|
|
|
static void
|
2000-06-06 08:21:59 +00:00
|
|
|
osendsig(catcher, sig, mask, code)
|
|
|
|
sig_t catcher;
|
|
|
|
int sig;
|
|
|
|
sigset_t *mask;
|
|
|
|
u_long code;
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
1999-09-29 15:06:27 +00:00
|
|
|
struct osigframe sf;
|
2000-06-06 08:21:59 +00:00
|
|
|
struct osigframe *fp;
|
|
|
|
struct proc *p;
|
|
|
|
struct sigacts *psp;
|
|
|
|
struct trapframe *regs;
|
1996-06-14 10:04:54 +00:00
|
|
|
int oonstack;
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
p = curproc;
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
2000-06-06 08:21:59 +00:00
|
|
|
psp = p->p_sigacts;
|
1996-06-14 10:04:54 +00:00
|
|
|
regs = p->p_md.md_regs;
|
2000-11-30 05:23:49 +00:00
|
|
|
oonstack = sigonstack(regs->tf_esp);
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
/* Allocate and validate space for the signal handler context. */
|
1999-10-11 20:33:17 +00:00
|
|
|
if ((p->p_flag & P_ALTSTACK) && !oonstack &&
|
1999-09-29 15:06:27 +00:00
|
|
|
SIGISMEMBER(psp->ps_sigonstack, sig)) {
|
1999-10-11 20:33:17 +00:00
|
|
|
fp = (struct osigframe *)(p->p_sigstk.ss_sp +
|
|
|
|
p->p_sigstk.ss_size - sizeof(struct osigframe));
|
2000-11-30 05:23:49 +00:00
|
|
|
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
|
1999-10-11 20:33:17 +00:00
|
|
|
p->p_sigstk.ss_flags |= SS_ONSTACK;
|
2000-11-30 05:23:49 +00:00
|
|
|
#endif
|
2000-06-06 08:21:59 +00:00
|
|
|
} else
|
1999-09-29 15:06:27 +00:00
|
|
|
fp = (struct osigframe *)regs->tf_esp - 1;
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
/*
|
2000-06-06 08:21:59 +00:00
|
|
|
* grow_stack() will return 0 if *fp does not fit inside the stack
|
|
|
|
* and the stack can not be grown.
|
|
|
|
* useracc() will return FALSE if access is denied.
|
1996-06-14 10:04:54 +00:00
|
|
|
*/
|
2000-06-06 08:21:59 +00:00
|
|
|
if (grow_stack(p, (int)fp) == 0 ||
|
|
|
|
!useracc((caddr_t)fp, sizeof(*fp), VM_PROT_WRITE)) {
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Process has trashed its stack; give it an illegal
|
|
|
|
* instruction to halt it in its tracks.
|
|
|
|
*/
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
1996-06-14 10:04:54 +00:00
|
|
|
SIGACTION(p, SIGILL) = SIG_DFL;
|
1999-09-29 15:06:27 +00:00
|
|
|
SIGDELSET(p->p_sigignore, SIGILL);
|
|
|
|
SIGDELSET(p->p_sigcatch, SIGILL);
|
|
|
|
SIGDELSET(p->p_sigmask, SIGILL);
|
1996-06-14 10:04:54 +00:00
|
|
|
psignal(p, SIGILL);
|
2001-03-07 03:37:06 +00:00
|
|
|
PROC_UNLOCK(p);
|
1996-06-14 10:04:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Translate the signal if appropriate. */
|
|
|
|
if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
|
|
|
|
sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
/* Build the argument list for the signal handler. */
|
1996-06-14 10:04:54 +00:00
|
|
|
sf.sf_signum = sig;
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
|
|
|
|
/* Signal handler installed with SA_SIGINFO. */
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_arg2 = (register_t)&fp->sf_siginfo;
|
|
|
|
sf.sf_siginfo.si_signo = sig;
|
|
|
|
sf.sf_siginfo.si_code = code;
|
1999-09-29 15:06:27 +00:00
|
|
|
sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher;
|
2000-06-06 08:21:59 +00:00
|
|
|
} else {
|
1999-09-29 15:06:27 +00:00
|
|
|
/* Old FreeBSD-style arguments. */
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_arg2 = code;
|
1999-12-04 12:35:05 +00:00
|
|
|
sf.sf_addr = regs->tf_err;
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_ahu.sf_handler = catcher;
|
|
|
|
}
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
1999-07-08 12:48:53 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Save most if not all of trap frame. */
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax;
|
|
|
|
sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx;
|
|
|
|
sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx;
|
|
|
|
sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx;
|
|
|
|
sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi;
|
|
|
|
sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi;
|
|
|
|
sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs;
|
|
|
|
sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds;
|
|
|
|
sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss;
|
|
|
|
sf.sf_siginfo.si_sc.sc_es = regs->tf_es;
|
|
|
|
sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs;
|
1999-09-09 09:58:05 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_gs = rgs();
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Build the signal context to be used by osigreturn(). */
|
2000-11-30 05:23:49 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0;
|
1999-09-29 15:06:27 +00:00
|
|
|
SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask);
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp;
|
|
|
|
sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp;
|
|
|
|
sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip;
|
|
|
|
sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags;
|
|
|
|
sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
|
|
|
|
sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
|
1997-08-09 01:56:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're a vm86 process, we want to save the segment registers.
|
|
|
|
* We also change eflags to be our emulated eflags, not the actual
|
|
|
|
* eflags.
|
|
|
|
*/
|
|
|
|
if (regs->tf_eflags & PSL_VM) {
|
2000-06-06 08:21:59 +00:00
|
|
|
/* XXX confusing names: `tf' isn't a trapframe; `regs' is. */
|
1997-08-09 01:56:34 +00:00
|
|
|
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
|
|
|
|
struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
|
|
|
|
|
1999-07-08 12:48:53 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs;
|
|
|
|
sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs;
|
|
|
|
sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es;
|
|
|
|
sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds;
|
1997-08-09 01:56:34 +00:00
|
|
|
|
|
|
|
if (vm86->vm86_has_vme == 0)
|
1999-09-29 15:06:27 +00:00
|
|
|
sf.sf_siginfo.si_sc.sc_ps =
|
2000-06-06 08:21:59 +00:00
|
|
|
(tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
|
|
|
|
(vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
|
|
|
|
|
|
|
|
/* See sendsig() for comments. */
|
|
|
|
tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP);
|
1999-09-29 15:06:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the sigframe out to the user's stack. */
|
2000-06-06 08:21:59 +00:00
|
|
|
if (copyout(&sf, fp, sizeof(*fp)) != 0) {
|
1999-09-29 15:06:27 +00:00
|
|
|
/*
|
|
|
|
* Something is wrong with the stack pointer.
|
|
|
|
* ...Kill the process.
|
|
|
|
*/
|
2001-03-07 03:37:06 +00:00
|
|
|
PROC_LOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
sigexit(p, SIGILL);
|
2001-03-07 03:37:06 +00:00
|
|
|
/* NOTREACHED */
|
1999-09-29 15:06:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
regs->tf_esp = (int)fp;
|
1999-12-04 12:35:05 +00:00
|
|
|
regs->tf_eip = PS_STRINGS - szosigcode;
|
1999-09-29 15:06:27 +00:00
|
|
|
regs->tf_cs = _ucodesel;
|
|
|
|
regs->tf_ds = _udatasel;
|
|
|
|
regs->tf_es = _udatasel;
|
|
|
|
regs->tf_fs = _udatasel;
|
1999-10-08 09:20:56 +00:00
|
|
|
load_gs(_udatasel);
|
1999-09-29 15:06:27 +00:00
|
|
|
regs->tf_ss = _udatasel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sendsig(catcher, sig, mask, code)
|
|
|
|
sig_t catcher;
|
|
|
|
int sig;
|
|
|
|
sigset_t *mask;
|
|
|
|
u_long code;
|
|
|
|
{
|
2000-06-06 08:21:59 +00:00
|
|
|
struct sigframe sf;
|
|
|
|
struct proc *p;
|
|
|
|
struct sigacts *psp;
|
1999-09-29 15:06:27 +00:00
|
|
|
struct trapframe *regs;
|
2000-06-06 08:21:59 +00:00
|
|
|
struct sigframe *sfp;
|
1999-10-11 20:33:17 +00:00
|
|
|
int oonstack;
|
1999-09-29 15:06:27 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
p = curproc;
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
2000-06-06 08:21:59 +00:00
|
|
|
psp = p->p_sigacts;
|
1999-10-11 20:33:17 +00:00
|
|
|
if (SIGISMEMBER(psp->ps_osigset, sig)) {
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
osendsig(catcher, sig, mask, code);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
regs = p->p_md.md_regs;
|
2000-11-30 05:23:49 +00:00
|
|
|
oonstack = sigonstack(regs->tf_esp);
|
1999-09-29 15:06:27 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Save user context. */
|
|
|
|
bzero(&sf, sizeof(sf));
|
1999-09-29 15:06:27 +00:00
|
|
|
sf.sf_uc.uc_sigmask = *mask;
|
1999-10-11 20:33:17 +00:00
|
|
|
sf.sf_uc.uc_stack = p->p_sigstk;
|
2000-11-30 05:23:49 +00:00
|
|
|
sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
|
|
|
|
? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
|
|
|
|
sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
|
1999-09-29 15:06:27 +00:00
|
|
|
sf.sf_uc.uc_mcontext.mc_gs = rgs();
|
2000-06-06 08:21:59 +00:00
|
|
|
bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
/* Allocate and validate space for the signal handler context. */
|
2000-06-06 08:21:59 +00:00
|
|
|
if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack &&
|
1999-09-29 15:06:27 +00:00
|
|
|
SIGISMEMBER(psp->ps_sigonstack, sig)) {
|
1999-10-11 20:33:17 +00:00
|
|
|
sfp = (struct sigframe *)(p->p_sigstk.ss_sp +
|
|
|
|
p->p_sigstk.ss_size - sizeof(struct sigframe));
|
2000-11-30 05:23:49 +00:00
|
|
|
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
|
1999-10-11 20:33:17 +00:00
|
|
|
p->p_sigstk.ss_flags |= SS_ONSTACK;
|
2000-11-30 05:23:49 +00:00
|
|
|
#endif
|
2000-06-06 08:21:59 +00:00
|
|
|
} else
|
1999-09-29 15:06:27 +00:00
|
|
|
sfp = (struct sigframe *)regs->tf_esp - 1;
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
/*
|
2000-06-06 08:21:59 +00:00
|
|
|
* grow_stack() will return 0 if *sfp does not fit inside the stack
|
|
|
|
* and the stack can not be grown.
|
|
|
|
* useracc() will return FALSE if access is denied.
|
1999-09-29 15:06:27 +00:00
|
|
|
*/
|
2000-06-06 08:21:59 +00:00
|
|
|
if (grow_stack(p, (int)sfp) == 0 ||
|
|
|
|
!useracc((caddr_t)sfp, sizeof(*sfp), VM_PROT_WRITE)) {
|
1999-09-29 15:06:27 +00:00
|
|
|
/*
|
|
|
|
* Process has trashed its stack; give it an illegal
|
|
|
|
* instruction to halt it in its tracks.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("process %d has trashed its stack\n", p->p_pid);
|
|
|
|
#endif
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
SIGACTION(p, SIGILL) = SIG_DFL;
|
|
|
|
SIGDELSET(p->p_sigignore, SIGILL);
|
|
|
|
SIGDELSET(p->p_sigcatch, SIGILL);
|
|
|
|
SIGDELSET(p->p_sigmask, SIGILL);
|
|
|
|
psignal(p, SIGILL);
|
2001-03-07 03:37:06 +00:00
|
|
|
PROC_UNLOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Translate the signal if appropriate. */
|
|
|
|
if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
|
|
|
|
sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
/* Build the argument list for the signal handler. */
|
|
|
|
sf.sf_signum = sig;
|
|
|
|
sf.sf_ucontext = (register_t)&sfp->sf_uc;
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
|
|
|
|
/* Signal handler installed with SA_SIGINFO. */
|
|
|
|
sf.sf_siginfo = (register_t)&sfp->sf_si;
|
|
|
|
sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Fill siginfo structure. */
|
1999-09-29 15:06:27 +00:00
|
|
|
sf.sf_si.si_signo = sig;
|
|
|
|
sf.sf_si.si_code = code;
|
2000-06-06 08:21:59 +00:00
|
|
|
sf.sf_si.si_addr = (void *)regs->tf_err;
|
|
|
|
} else {
|
1999-09-29 15:06:27 +00:00
|
|
|
/* Old FreeBSD-style arguments. */
|
|
|
|
sf.sf_siginfo = code;
|
1999-12-04 12:35:05 +00:00
|
|
|
sf.sf_addr = regs->tf_err;
|
1999-09-29 15:06:27 +00:00
|
|
|
sf.sf_ahu.sf_handler = catcher;
|
|
|
|
}
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're a vm86 process, we want to save the segment registers.
|
|
|
|
* We also change eflags to be our emulated eflags, not the actual
|
|
|
|
* eflags.
|
|
|
|
*/
|
|
|
|
if (regs->tf_eflags & PSL_VM) {
|
|
|
|
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
|
|
|
|
struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
|
|
|
|
|
|
|
|
sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
|
1999-10-08 09:20:56 +00:00
|
|
|
sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
|
|
|
|
sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
|
|
|
|
sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
if (vm86->vm86_has_vme == 0)
|
1999-10-08 09:20:56 +00:00
|
|
|
sf.sf_uc.uc_mcontext.mc_eflags =
|
1999-09-29 15:06:27 +00:00
|
|
|
(tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
|
|
|
|
(vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
|
1997-08-09 01:56:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We should never have PSL_T set when returning from vm86
|
|
|
|
* mode. It may be set here if we deliver a signal before
|
|
|
|
* getting to vm86 mode, so turn it off.
|
1999-02-16 11:07:06 +00:00
|
|
|
*
|
|
|
|
* Clear PSL_NT to inhibit T_TSSFLT faults on return from
|
|
|
|
* syscalls made by the signal handler. This just avoids
|
|
|
|
* wasting time for our lazy fixup of such faults. PSL_NT
|
|
|
|
* does nothing in vm86 mode, but vm86 programs can set it
|
|
|
|
* almost legitimately in probes for old cpu types.
|
1997-08-09 01:56:34 +00:00
|
|
|
*/
|
2000-06-06 08:21:59 +00:00
|
|
|
tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP);
|
1997-08-09 01:56:34 +00:00
|
|
|
}
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Copy the sigframe out to the user's stack. */
|
|
|
|
if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Something is wrong with the stack pointer.
|
|
|
|
* ...Kill the process.
|
|
|
|
*/
|
2001-03-07 03:37:06 +00:00
|
|
|
PROC_LOCK(p);
|
1996-06-14 10:04:54 +00:00
|
|
|
sigexit(p, SIGILL);
|
2001-03-07 03:37:06 +00:00
|
|
|
/* NOTREACHED */
|
1997-08-09 01:56:34 +00:00
|
|
|
}
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1999-09-29 15:06:27 +00:00
|
|
|
regs->tf_esp = (int)sfp;
|
1998-12-16 16:28:58 +00:00
|
|
|
regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
|
1997-05-08 09:34:16 +00:00
|
|
|
regs->tf_cs = _ucodesel;
|
|
|
|
regs->tf_ds = _udatasel;
|
|
|
|
regs->tf_es = _udatasel;
|
|
|
|
regs->tf_ss = _udatasel;
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* System call to cleanup state after a signal
|
|
|
|
* has been taken. Reset signal mask and
|
|
|
|
* stack state from context left by sendsig (above).
|
|
|
|
* Return to previous pc and psl as specified by
|
|
|
|
* context left by sendsig. Check carefully to
|
|
|
|
* make sure that the user has not modified the
|
|
|
|
* state to gain improper privileges.
|
|
|
|
*/
|
|
|
|
int
|
1999-09-29 15:06:27 +00:00
|
|
|
osigreturn(p, uap)
|
1996-06-14 10:04:54 +00:00
|
|
|
struct proc *p;
|
1999-09-29 15:06:27 +00:00
|
|
|
struct osigreturn_args /* {
|
|
|
|
struct osigcontext *sigcntxp;
|
1996-06-14 10:04:54 +00:00
|
|
|
} */ *uap;
|
|
|
|
{
|
2000-06-06 08:21:59 +00:00
|
|
|
struct trapframe *regs;
|
|
|
|
struct osigcontext *scp;
|
1996-06-14 10:04:54 +00:00
|
|
|
int eflags;
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
regs = p->p_md.md_regs;
|
1996-06-14 10:04:54 +00:00
|
|
|
scp = uap->sigcntxp;
|
2000-06-06 08:21:59 +00:00
|
|
|
if (!useracc((caddr_t)scp, sizeof(*scp), VM_PROT_READ))
|
|
|
|
return (EFAULT);
|
1996-06-14 10:04:54 +00:00
|
|
|
eflags = scp->sc_ps;
|
1997-08-09 01:56:34 +00:00
|
|
|
if (eflags & PSL_VM) {
|
|
|
|
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
|
|
|
|
struct vm86_kernel *vm86;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if pcb_ext == 0 or vm86_inited == 0, the user hasn't
|
|
|
|
* set up the vm86 area, and we can't enter vm86 mode.
|
|
|
|
*/
|
|
|
|
if (p->p_addr->u_pcb.pcb_ext == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
|
|
|
|
if (vm86->vm86_inited == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Go back to user mode if both flags are set. */
|
1997-08-09 01:56:34 +00:00
|
|
|
if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
|
|
|
|
trapsignal(p, SIGBUS, 0);
|
|
|
|
|
|
|
|
if (vm86->vm86_has_vme) {
|
|
|
|
eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
|
|
|
|
(eflags & VME_USERCHANGE) | PSL_VM;
|
|
|
|
} else {
|
|
|
|
vm86->vm86_eflags = eflags; /* save VIF, VIP */
|
|
|
|
eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM;
|
|
|
|
}
|
|
|
|
tf->tf_vm86_ds = scp->sc_ds;
|
|
|
|
tf->tf_vm86_es = scp->sc_es;
|
|
|
|
tf->tf_vm86_fs = scp->sc_fs;
|
|
|
|
tf->tf_vm86_gs = scp->sc_gs;
|
|
|
|
tf->tf_ds = _udatasel;
|
|
|
|
tf->tf_es = _udatasel;
|
1999-04-28 08:03:54 +00:00
|
|
|
tf->tf_fs = _udatasel;
|
1997-08-09 01:56:34 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Don't allow users to change privileged or reserved flags.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* XXX do allow users to change the privileged flag PSL_RF.
|
|
|
|
* The cpu sets PSL_RF in tf_eflags for faults. Debuggers
|
|
|
|
* should sometimes set it there too. tf_eflags is kept in
|
|
|
|
* the signal context during signal handling and there is no
|
|
|
|
* other place to remember it, so the PSL_RF bit may be
|
|
|
|
* corrupted by the signal handler without us knowing.
|
|
|
|
* Corruption of the PSL_RF bit at worst causes one more or
|
|
|
|
* one less debugger trap, so allowing it is fairly harmless.
|
|
|
|
*/
|
1999-09-29 15:06:27 +00:00
|
|
|
if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
|
2000-06-06 08:21:59 +00:00
|
|
|
return (EINVAL);
|
1997-08-09 01:56:34 +00:00
|
|
|
}
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1997-08-09 01:56:34 +00:00
|
|
|
/*
|
|
|
|
* Don't allow users to load a valid privileged %cs. Let the
|
|
|
|
* hardware check for invalid selectors, excess privilege in
|
|
|
|
* other selectors, invalid %eip's and invalid %esp's.
|
|
|
|
*/
|
|
|
|
if (!CS_SECURE(scp->sc_cs)) {
|
|
|
|
trapsignal(p, SIGBUS, T_PROTFLT);
|
2000-06-06 08:21:59 +00:00
|
|
|
return (EINVAL);
|
1997-08-09 01:56:34 +00:00
|
|
|
}
|
|
|
|
regs->tf_ds = scp->sc_ds;
|
|
|
|
regs->tf_es = scp->sc_es;
|
1999-04-28 08:03:54 +00:00
|
|
|
regs->tf_fs = scp->sc_fs;
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
1998-02-04 10:19:33 +00:00
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Restore remaining registers. */
|
1997-05-08 09:34:16 +00:00
|
|
|
regs->tf_eax = scp->sc_eax;
|
|
|
|
regs->tf_ebx = scp->sc_ebx;
|
|
|
|
regs->tf_ecx = scp->sc_ecx;
|
|
|
|
regs->tf_edx = scp->sc_edx;
|
|
|
|
regs->tf_esi = scp->sc_esi;
|
|
|
|
regs->tf_edi = scp->sc_edi;
|
|
|
|
regs->tf_cs = scp->sc_cs;
|
|
|
|
regs->tf_ss = scp->sc_ss;
|
|
|
|
regs->tf_isp = scp->sc_isp;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
2000-11-30 05:23:49 +00:00
|
|
|
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
|
|
|
|
if (scp->sc_onstack & 1)
|
1999-10-11 20:33:17 +00:00
|
|
|
p->p_sigstk.ss_flags |= SS_ONSTACK;
|
1996-06-14 10:04:54 +00:00
|
|
|
else
|
1999-10-11 20:33:17 +00:00
|
|
|
p->p_sigstk.ss_flags &= ~SS_ONSTACK;
|
2000-11-30 05:23:49 +00:00
|
|
|
#endif
|
|
|
|
|
1999-10-11 20:33:17 +00:00
|
|
|
SIGSETOLD(p->p_sigmask, scp->sc_mask);
|
1999-09-29 15:06:27 +00:00
|
|
|
SIG_CANTMASK(p->p_sigmask);
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
1997-05-08 09:34:16 +00:00
|
|
|
regs->tf_ebp = scp->sc_fp;
|
|
|
|
regs->tf_esp = scp->sc_sp;
|
|
|
|
regs->tf_eip = scp->sc_pc;
|
|
|
|
regs->tf_eflags = eflags;
|
2000-06-06 08:21:59 +00:00
|
|
|
return (EJUSTRETURN);
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
|
1999-09-29 15:06:27 +00:00
|
|
|
int
|
|
|
|
sigreturn(p, uap)
|
|
|
|
struct proc *p;
|
|
|
|
struct sigreturn_args /* {
|
|
|
|
ucontext_t *sigcntxp;
|
|
|
|
} */ *uap;
|
|
|
|
{
|
|
|
|
struct trapframe *regs;
|
|
|
|
ucontext_t *ucp;
|
1999-10-01 12:46:08 +00:00
|
|
|
int cs, eflags;
|
1999-09-29 15:06:27 +00:00
|
|
|
|
|
|
|
ucp = uap->sigcntxp;
|
1999-11-25 12:43:07 +00:00
|
|
|
if (!useracc((caddr_t)ucp, sizeof(struct osigcontext), VM_PROT_READ))
|
|
|
|
return (EFAULT);
|
|
|
|
if (((struct osigcontext *)ucp)->sc_trapno == 0x01d516)
|
|
|
|
return (osigreturn(p, (struct osigreturn_args *)uap));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since ucp is not an osigcontext but a ucontext_t, we have to
|
|
|
|
* check again if all of it is accessible. A ucontext_t is
|
|
|
|
* much larger, so instead of just checking for the pointer
|
|
|
|
* being valid for the size of an osigcontext, now check for
|
|
|
|
* it being valid for a whole, new-style ucontext_t.
|
|
|
|
*/
|
2000-06-06 08:21:59 +00:00
|
|
|
if (!useracc((caddr_t)ucp, sizeof(*ucp), VM_PROT_READ))
|
1999-11-25 12:43:07 +00:00
|
|
|
return (EFAULT);
|
|
|
|
|
|
|
|
regs = p->p_md.md_regs;
|
|
|
|
eflags = ucp->uc_mcontext.mc_eflags;
|
1999-09-29 15:06:27 +00:00
|
|
|
if (eflags & PSL_VM) {
|
|
|
|
struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
|
|
|
|
struct vm86_kernel *vm86;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if pcb_ext == 0 or vm86_inited == 0, the user hasn't
|
|
|
|
* set up the vm86 area, and we can't enter vm86 mode.
|
|
|
|
*/
|
|
|
|
if (p->p_addr->u_pcb.pcb_ext == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
|
|
|
|
if (vm86->vm86_inited == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
/* Go back to user mode if both flags are set. */
|
1999-09-29 15:06:27 +00:00
|
|
|
if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
|
|
|
|
trapsignal(p, SIGBUS, 0);
|
|
|
|
|
|
|
|
if (vm86->vm86_has_vme) {
|
|
|
|
eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
|
|
|
|
(eflags & VME_USERCHANGE) | PSL_VM;
|
|
|
|
} else {
|
|
|
|
vm86->vm86_eflags = eflags; /* save VIF, VIP */
|
|
|
|
eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM;
|
|
|
|
}
|
1999-10-13 11:03:41 +00:00
|
|
|
bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
|
|
|
|
tf->tf_eflags = eflags;
|
1999-09-29 15:06:27 +00:00
|
|
|
tf->tf_vm86_ds = tf->tf_ds;
|
|
|
|
tf->tf_vm86_es = tf->tf_es;
|
|
|
|
tf->tf_vm86_fs = tf->tf_fs;
|
|
|
|
tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
|
|
|
|
tf->tf_ds = _udatasel;
|
|
|
|
tf->tf_es = _udatasel;
|
|
|
|
tf->tf_fs = _udatasel;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Don't allow users to change privileged or reserved flags.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* XXX do allow users to change the privileged flag PSL_RF.
|
|
|
|
* The cpu sets PSL_RF in tf_eflags for faults. Debuggers
|
|
|
|
* should sometimes set it there too. tf_eflags is kept in
|
|
|
|
* the signal context during signal handling and there is no
|
|
|
|
* other place to remember it, so the PSL_RF bit may be
|
|
|
|
* corrupted by the signal handler without us knowing.
|
|
|
|
* Corruption of the PSL_RF bit at worst causes one more or
|
|
|
|
* one less debugger trap, so allowing it is fairly harmless.
|
|
|
|
*/
|
|
|
|
if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
|
|
|
|
printf("sigreturn: eflags = 0x%x\n", eflags);
|
2000-06-06 08:21:59 +00:00
|
|
|
return (EINVAL);
|
1999-09-29 15:06:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't allow users to load a valid privileged %cs. Let the
|
|
|
|
* hardware check for invalid selectors, excess privilege in
|
|
|
|
* other selectors, invalid %eip's and invalid %esp's.
|
|
|
|
*/
|
1999-10-08 09:20:56 +00:00
|
|
|
cs = ucp->uc_mcontext.mc_cs;
|
1999-10-01 12:46:08 +00:00
|
|
|
if (!CS_SECURE(cs)) {
|
|
|
|
printf("sigreturn: cs = 0x%x\n", cs);
|
1999-09-29 15:06:27 +00:00
|
|
|
trapsignal(p, SIGBUS, T_PROTFLT);
|
2000-06-06 08:21:59 +00:00
|
|
|
return (EINVAL);
|
1999-09-29 15:06:27 +00:00
|
|
|
}
|
|
|
|
|
2000-06-06 08:21:59 +00:00
|
|
|
bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
|
|
|
|
}
|
2000-11-30 05:23:49 +00:00
|
|
|
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_LOCK(p);
|
2000-11-30 05:23:49 +00:00
|
|
|
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
|
1999-10-04 19:33:58 +00:00
|
|
|
if (ucp->uc_mcontext.mc_onstack & 1)
|
1999-10-11 20:33:17 +00:00
|
|
|
p->p_sigstk.ss_flags |= SS_ONSTACK;
|
1999-10-04 19:33:58 +00:00
|
|
|
else
|
1999-10-11 20:33:17 +00:00
|
|
|
p->p_sigstk.ss_flags &= ~SS_ONSTACK;
|
2000-11-30 05:23:49 +00:00
|
|
|
#endif
|
1999-10-04 19:33:58 +00:00
|
|
|
|
1999-09-29 15:06:27 +00:00
|
|
|
p->p_sigmask = ucp->uc_sigmask;
|
|
|
|
SIG_CANTMASK(p->p_sigmask);
|
2001-01-28 11:06:28 +00:00
|
|
|
PROC_UNLOCK(p);
|
2000-06-06 08:21:59 +00:00
|
|
|
return (EJUSTRETURN);
|
1999-09-29 15:06:27 +00:00
|
|
|
}
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
1997-02-25 16:36:48 +00:00
|
|
|
* Machine dependent boot() routine
|
1996-06-14 10:04:54 +00:00
|
|
|
*
|
1997-02-25 16:36:48 +00:00
|
|
|
* I haven't seen anything to put here yet
|
1996-08-30 10:43:14 +00:00
|
|
|
* Possibly some stuff might be grafted back here from boot()
|
1996-06-14 10:04:54 +00:00
|
|
|
*/
|
1996-08-30 10:43:14 +00:00
|
|
|
void
|
|
|
|
cpu_boot(int howto)
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1996-11-02 10:41:28 +00:00
|
|
|
/*
|
|
|
|
* Shutdown the CPU as much as possible
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cpu_halt(void)
|
|
|
|
{
|
|
|
|
for (;;)
|
|
|
|
__asm__ ("hlt");
|
|
|
|
}
|
|
|
|
|
2000-09-22 12:54:50 +00:00
|
|
|
/*
|
|
|
|
* Hook to idle the CPU when possible. This currently only works in
|
|
|
|
* the !SMP case, as there is no clean way to ensure that a CPU will be
|
|
|
|
* woken when there is work available for it.
|
|
|
|
*/
|
|
|
|
static int cpu_idle_hlt = 1;
|
2000-10-18 09:05:09 +00:00
|
|
|
SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW,
|
|
|
|
&cpu_idle_hlt, 0, "Idle loop HLT enable");
|
2000-09-22 12:54:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that we have to be careful here to avoid a race between checking
|
|
|
|
* procrunnable() and actually halting. If we don't do this, we may waste
|
|
|
|
* the time between calling hlt and the next interrupt even though there
|
|
|
|
* is a runnable process.
|
|
|
|
*/
|
2000-10-20 10:17:26 +00:00
|
|
|
void
|
|
|
|
cpu_idle(void)
|
2000-09-22 12:54:50 +00:00
|
|
|
{
|
2000-10-20 10:17:26 +00:00
|
|
|
#ifndef SMP
|
2000-10-18 09:05:09 +00:00
|
|
|
if (cpu_idle_hlt) {
|
2000-09-22 12:54:50 +00:00
|
|
|
disable_intr();
|
2000-10-18 09:05:09 +00:00
|
|
|
if (procrunnable())
|
2000-09-22 12:54:50 +00:00
|
|
|
enable_intr();
|
2000-10-18 09:05:09 +00:00
|
|
|
else {
|
2000-09-22 12:54:50 +00:00
|
|
|
enable_intr();
|
2000-10-18 09:05:09 +00:00
|
|
|
__asm __volatile("hlt");
|
2000-09-22 12:54:50 +00:00
|
|
|
}
|
|
|
|
}
|
2000-10-20 10:17:26 +00:00
|
|
|
#endif
|
2000-09-22 12:54:50 +00:00
|
|
|
}
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Clear registers on exec
|
|
|
|
*/
|
|
|
|
void
|
1999-04-03 22:20:03 +00:00
|
|
|
setregs(p, entry, stack, ps_strings)
|
1996-06-14 10:04:54 +00:00
|
|
|
struct proc *p;
|
|
|
|
u_long entry;
|
|
|
|
u_long stack;
|
1999-04-03 22:20:03 +00:00
|
|
|
u_long ps_strings;
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
1997-05-08 09:34:16 +00:00
|
|
|
struct trapframe *regs = p->p_md.md_regs;
|
1996-06-14 10:04:54 +00:00
|
|
|
struct pcb *pcb = &p->p_addr->u_pcb;
|
|
|
|
|
2001-02-23 01:25:02 +00:00
|
|
|
if (pcb->pcb_ldt)
|
|
|
|
user_ldt_free(pcb);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1997-05-08 09:34:16 +00:00
|
|
|
bzero((char *)regs, sizeof(struct trapframe));
|
|
|
|
regs->tf_eip = entry;
|
|
|
|
regs->tf_esp = stack;
|
|
|
|
regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T);
|
|
|
|
regs->tf_ss = _udatasel;
|
|
|
|
regs->tf_ds = _udatasel;
|
|
|
|
regs->tf_es = _udatasel;
|
1999-04-28 08:03:54 +00:00
|
|
|
regs->tf_fs = _udatasel;
|
1997-05-08 09:34:16 +00:00
|
|
|
regs->tf_cs = _ucodesel;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1999-04-18 14:42:20 +00:00
|
|
|
/* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */
|
|
|
|
regs->tf_ebx = ps_strings;
|
|
|
|
|
1999-04-28 08:03:54 +00:00
|
|
|
/* reset %gs as well */
|
2001-01-12 13:39:50 +00:00
|
|
|
if (pcb == PCPU_GET(curpcb))
|
1999-04-28 08:03:54 +00:00
|
|
|
load_gs(_udatasel);
|
1999-10-08 09:20:56 +00:00
|
|
|
else
|
|
|
|
pcb->pcb_gs = _udatasel;
|
1998-08-19 09:32:15 +00:00
|
|
|
|
2000-03-01 08:53:59 +00:00
|
|
|
/*
|
|
|
|
* Reset the hardware debug registers if they were in use.
|
|
|
|
* They won't have any meaning for the newly exec'd process.
|
|
|
|
*/
|
|
|
|
if (pcb->pcb_flags & PCB_DBREGS) {
|
|
|
|
pcb->pcb_dr0 = 0;
|
|
|
|
pcb->pcb_dr1 = 0;
|
|
|
|
pcb->pcb_dr2 = 0;
|
|
|
|
pcb->pcb_dr3 = 0;
|
|
|
|
pcb->pcb_dr6 = 0;
|
|
|
|
pcb->pcb_dr7 = 0;
|
2001-01-12 13:39:50 +00:00
|
|
|
if (pcb == PCPU_GET(curpcb)) {
|
2000-03-01 08:53:59 +00:00
|
|
|
/*
|
|
|
|
* Clear the debug registers on the running
|
|
|
|
* CPU, otherwise they will end up affecting
|
|
|
|
* the next process we switch to.
|
|
|
|
*/
|
|
|
|
reset_dbregs();
|
|
|
|
}
|
|
|
|
pcb->pcb_flags &= ~PCB_DBREGS;
|
|
|
|
}
|
|
|
|
|
1997-01-25 06:42:19 +00:00
|
|
|
/*
|
|
|
|
* Initialize the math emulator (if any) for the current process.
|
|
|
|
* Actually, just clear the bit that says that the emulator has
|
|
|
|
* been initialized. Initialization is delayed until the process
|
|
|
|
* traps to the emulator (if it is done at all) mainly because
|
|
|
|
* emulators don't provide an entry point for initialization.
|
|
|
|
*/
|
|
|
|
p->p_addr->u_pcb.pcb_flags &= ~FP_SOFTFP;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Arrange to trap the next npx or `fwait' instruction (see npx.c
|
|
|
|
* for why fwait must be trapped at least if there is an npx or an
|
|
|
|
* emulator). This is mainly to handle the case where npx0 is not
|
|
|
|
* configured, since the npx routines normally set up the trap
|
|
|
|
* otherwise. It should be done only at boot time, but doing it
|
|
|
|
* here allows modifying `npx_exists' for testing the emulator on
|
|
|
|
* systems with an npx.
|
|
|
|
*/
|
|
|
|
load_cr0(rcr0() | CR0_MP | CR0_TS);
|
|
|
|
|
2001-01-19 13:19:02 +00:00
|
|
|
#ifdef DEV_NPX
|
1997-01-25 06:42:19 +00:00
|
|
|
/* Initialize the npx (if any) for the current process. */
|
1996-06-14 10:04:54 +00:00
|
|
|
npxinit(__INITIAL_NPXCW__);
|
1997-01-25 06:42:19 +00:00
|
|
|
#endif
|
1999-02-12 09:15:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX - Linux emulator
|
|
|
|
* Make sure sure edx is 0x0 on entry. Linux binaries depend
|
|
|
|
* on it.
|
|
|
|
*/
|
|
|
|
p->p_retval[1] = 0;
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 07:35:12 +00:00
|
|
|
void
|
|
|
|
cpu_setregs(void)
|
|
|
|
{
|
|
|
|
unsigned int cr0;
|
|
|
|
|
|
|
|
cr0 = rcr0();
|
|
|
|
cr0 |= CR0_NE; /* Done by npxinit() */
|
|
|
|
cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */
|
Stop doing runtime checking on i386 cpus for cpu class. The cpu is
slow enough as it is, without having to constantly check that it really
is an i386 still. It was possible to compile out the conditionals for
faster cpus by leaving out 'I386_CPU', but it was not possible to
unconditionally compile for the i386. You got the runtime checking whether
you wanted it or not. This makes I386_CPU mutually exclusive with the
other cpu types, and tidies things up a little in the process.
Reviewed by: alfred, markm, phk, benno, jlemon, jhb, jake, grog, msmith,
jasone, dcs, des (and a bunch more people who encouraged it)
2001-01-16 09:10:34 +00:00
|
|
|
#ifndef I386_CPU
|
|
|
|
cr0 |= CR0_WP | CR0_AM;
|
2000-08-12 07:35:12 +00:00
|
|
|
#endif
|
|
|
|
load_cr0(cr0);
|
|
|
|
load_gs(_udatasel);
|
|
|
|
}
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS)
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,
|
|
|
|
req);
|
|
|
|
if (!error && req->newptr)
|
|
|
|
resettodr();
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW,
|
|
|
|
&adjkerntz, 0, sysctl_machdep_adjkerntz, "I", "");
|
|
|
|
|
|
|
|
SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set,
|
|
|
|
CTLFLAG_RW, &disable_rtc_set, 0, "");
|
|
|
|
|
|
|
|
SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo,
|
|
|
|
CTLFLAG_RD, &bootinfo, bootinfo, "");
|
|
|
|
|
|
|
|
SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock,
|
|
|
|
CTLFLAG_RW, &wall_cmos_clock, 0, "");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize 386 and configure to run kernel
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize segments & interrupt table
|
|
|
|
*/
|
|
|
|
|
|
|
|
int _default_ldt;
|
2000-09-23 06:38:59 +00:00
|
|
|
union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */
|
1999-06-21 11:14:27 +00:00
|
|
|
static struct gate_descriptor idt0[NIDT];
|
|
|
|
struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */
|
1996-06-14 10:04:54 +00:00
|
|
|
union descriptor ldt[NLDT]; /* local descriptor table */
|
1997-04-27 13:22:09 +00:00
|
|
|
#ifdef SMP
|
|
|
|
/* table descriptors - used to load tables by microp */
|
|
|
|
struct region_descriptor r_gdt, r_idt;
|
|
|
|
#endif
|
|
|
|
|
1999-04-28 08:03:54 +00:00
|
|
|
int private_tss; /* flag indicating private tss */
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1997-12-05 11:48:53 +00:00
|
|
|
#if defined(I586_CPU) && !defined(NO_F00F_HACK)
|
|
|
|
extern int has_f00f_bug;
|
1997-12-03 09:46:34 +00:00
|
|
|
#endif
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
static struct i386tss dblfault_tss;
|
|
|
|
static char dblfault_stack[PAGE_SIZE];
|
|
|
|
|
|
|
|
extern struct user *proc0paddr;
|
|
|
|
|
1997-04-07 11:00:48 +00:00
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/* software prototypes -- in more palatable form */
|
1999-04-28 08:03:54 +00:00
|
|
|
struct soft_segment_descriptor gdt_segs[] = {
|
1996-06-14 10:04:54 +00:00
|
|
|
/* GNULL_SEL 0 Null Descriptor */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0x0, /* length */
|
|
|
|
0, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
0, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* GCODE_SEL 1 Code Descriptor for kernel */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0xfffff, /* length - all address space */
|
|
|
|
SDT_MEMERA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* GDATA_SEL 2 Data Descriptor for kernel */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0xfffff, /* length - all address space */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1999-04-28 08:03:54 +00:00
|
|
|
/* GPRIV_SEL 3 SMP Per-Processor Private Data Descriptor */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0xfffff, /* length - all address space */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* GPROC0_SEL 4 Proc 0 Tss Descriptor */
|
|
|
|
{
|
|
|
|
0x0, /* segment base address */
|
|
|
|
sizeof(struct i386tss)-1,/* length - all address space */
|
|
|
|
SDT_SYS386TSS, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* unused - default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* GLDT_SEL 5 LDT Descriptor */
|
1996-06-14 10:04:54 +00:00
|
|
|
{ (int) ldt, /* segment base address */
|
|
|
|
sizeof(ldt)-1, /* length - all address space */
|
|
|
|
SDT_SYSLDT, /* segment type */
|
1997-04-07 11:00:48 +00:00
|
|
|
SEL_UPL, /* segment descriptor priority level */
|
1996-06-14 10:04:54 +00:00
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* unused - default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
1999-04-28 08:03:54 +00:00
|
|
|
/* GUSERLDT_SEL 6 User LDT Descriptor per process */
|
|
|
|
{ (int) ldt, /* segment base address */
|
|
|
|
(512 * sizeof(union descriptor)-1), /* length */
|
|
|
|
SDT_SYSLDT, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* unused - default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* GTGATE_SEL 7 Null Descriptor - Placeholder */
|
1996-06-14 10:04:54 +00:00
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0x0, /* length - all address space */
|
|
|
|
0, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
0, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
1999-08-18 08:22:10 +00:00
|
|
|
/* GBIOSLOWMEM_SEL 8 BIOS access to realmode segment 0x40, must be #8 in GDT */
|
|
|
|
{ 0x400, /* segment base address */
|
|
|
|
0xfffff, /* length */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* GPANIC_SEL 9 Panic Tss Descriptor */
|
1996-06-14 10:04:54 +00:00
|
|
|
{ (int) &dblfault_tss, /* segment base address */
|
|
|
|
sizeof(struct i386tss)-1,/* length - all address space */
|
|
|
|
SDT_SYS386TSS, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* unused - default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
1999-08-18 08:22:10 +00:00
|
|
|
/* GBIOSCODE32_SEL 10 BIOS 32-bit interface (32bit Code) */
|
1999-07-30 11:42:05 +00:00
|
|
|
{ 0, /* segment base address (overwritten) */
|
1996-06-14 10:04:54 +00:00
|
|
|
0xfffff, /* length */
|
|
|
|
SDT_MEMERA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
1999-08-18 08:22:10 +00:00
|
|
|
0, /* default 32 vs 16 bit size */
|
1996-06-14 10:04:54 +00:00
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1999-08-18 08:22:10 +00:00
|
|
|
/* GBIOSCODE16_SEL 11 BIOS 32-bit interface (16bit Code) */
|
1999-07-30 11:42:05 +00:00
|
|
|
{ 0, /* segment base address (overwritten) */
|
1996-06-14 10:04:54 +00:00
|
|
|
0xfffff, /* length */
|
|
|
|
SDT_MEMERA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1999-08-18 08:22:10 +00:00
|
|
|
/* GBIOSDATA_SEL 12 BIOS 32-bit interface (Data) */
|
1999-07-30 11:42:05 +00:00
|
|
|
{ 0, /* segment base address (overwritten) */
|
1996-06-14 10:04:54 +00:00
|
|
|
0xfffff, /* length */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1999-08-18 08:22:10 +00:00
|
|
|
/* GBIOSUTIL_SEL 13 BIOS 16-bit interface (Utility) */
|
1999-07-30 11:42:05 +00:00
|
|
|
{ 0, /* segment base address (overwritten) */
|
|
|
|
0xfffff, /* length */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1999-08-18 08:22:10 +00:00
|
|
|
/* GBIOSARGS_SEL 14 BIOS 16-bit interface (Arguments) */
|
1999-07-30 11:42:05 +00:00
|
|
|
{ 0, /* segment base address (overwritten) */
|
|
|
|
0xfffff, /* length */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1996-06-14 10:04:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct soft_segment_descriptor ldt_segs[] = {
|
|
|
|
/* Null Descriptor - overwritten by call gate */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0x0, /* length - all address space */
|
|
|
|
0, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
0, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* Null Descriptor - overwritten by call gate */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0x0, /* length - all address space */
|
|
|
|
0, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
0, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* Null Descriptor - overwritten by call gate */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0x0, /* length - all address space */
|
|
|
|
0, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
0, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
|
|
|
/* Code Descriptor for user */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0xfffff, /* length - all address space */
|
|
|
|
SDT_MEMERA, /* segment type */
|
|
|
|
SEL_UPL, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
1999-01-29 10:43:09 +00:00
|
|
|
/* Null Descriptor - overwritten by call gate */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0x0, /* length - all address space */
|
|
|
|
0, /* segment type */
|
|
|
|
0, /* segment descriptor priority level */
|
|
|
|
0, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
0, /* default 32 vs 16 bit size */
|
|
|
|
0 /* limit granularity (byte/page units)*/ },
|
1996-06-14 10:04:54 +00:00
|
|
|
/* Data Descriptor for user */
|
|
|
|
{ 0x0, /* segment base address */
|
|
|
|
0xfffff, /* length - all address space */
|
|
|
|
SDT_MEMRWA, /* segment type */
|
|
|
|
SEL_UPL, /* segment descriptor priority level */
|
|
|
|
1, /* segment descriptor present */
|
|
|
|
0, 0,
|
|
|
|
1, /* default 32 vs 16 bit size */
|
|
|
|
1 /* limit granularity (byte/page units)*/ },
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
setidt(idx, func, typ, dpl, selec)
|
|
|
|
int idx;
|
|
|
|
inthand_t *func;
|
|
|
|
int typ;
|
|
|
|
int dpl;
|
|
|
|
int selec;
|
|
|
|
{
|
1998-03-07 15:42:54 +00:00
|
|
|
struct gate_descriptor *ip;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1998-03-07 15:42:54 +00:00
|
|
|
ip = idt + idx;
|
1996-06-14 10:04:54 +00:00
|
|
|
ip->gd_looffset = (int)func;
|
|
|
|
ip->gd_selector = selec;
|
|
|
|
ip->gd_stkcpy = 0;
|
|
|
|
ip->gd_xx = 0;
|
|
|
|
ip->gd_type = typ;
|
|
|
|
ip->gd_dpl = dpl;
|
|
|
|
ip->gd_p = 1;
|
|
|
|
ip->gd_hioffset = ((int)func)>>16 ;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define IDTVEC(name) __CONCAT(X,name)
|
|
|
|
|
|
|
|
extern inthand_t
|
|
|
|
IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
|
|
|
|
IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm),
|
|
|
|
IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
|
1996-08-30 10:43:14 +00:00
|
|
|
IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
|
2001-02-25 08:00:35 +00:00
|
|
|
IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
sdtossd(sd, ssd)
|
|
|
|
struct segment_descriptor *sd;
|
|
|
|
struct soft_segment_descriptor *ssd;
|
|
|
|
{
|
|
|
|
ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase;
|
|
|
|
ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit;
|
|
|
|
ssd->ssd_type = sd->sd_type;
|
|
|
|
ssd->ssd_dpl = sd->sd_dpl;
|
|
|
|
ssd->ssd_p = sd->sd_p;
|
|
|
|
ssd->ssd_def32 = sd->sd_def32;
|
|
|
|
ssd->ssd_gran = sd->sd_gran;
|
|
|
|
}
|
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
#define PHYSMAP_SIZE (2 * 8)
|
1998-03-24 08:27:21 +00:00
|
|
|
|
1999-07-03 08:31:32 +00:00
|
|
|
/*
|
1999-07-08 12:48:53 +00:00
|
|
|
* Populate the (physmap) array with base/bound pairs describing the
|
1999-07-03 08:31:32 +00:00
|
|
|
* available physical memory in the system, then test this memory and
|
|
|
|
* build the phys_avail array describing the actually-available memory.
|
|
|
|
*
|
1999-07-08 12:48:53 +00:00
|
|
|
* If we cannot accurately determine the physical memory map, then use
|
|
|
|
* value from the 0xE801 call, and failing that, the RTC.
|
1999-07-03 08:31:32 +00:00
|
|
|
*
|
1999-07-08 12:48:53 +00:00
|
|
|
* Total memory size may be set by the kernel environment variable
|
|
|
|
* hw.physmem or the compile-time define MAXMEM.
|
1999-07-03 08:31:32 +00:00
|
|
|
*/
|
2000-03-16 12:14:00 +00:00
|
|
|
#ifdef PC98
|
1999-06-03 13:49:52 +00:00
|
|
|
static void
|
2000-03-16 12:14:00 +00:00
|
|
|
getmemsize(int first)
|
1999-06-03 13:49:52 +00:00
|
|
|
{
|
|
|
|
u_int biosbasemem, biosextmem;
|
|
|
|
u_int pagesinbase, pagesinext;
|
|
|
|
int pa_indx;
|
2000-03-16 12:14:00 +00:00
|
|
|
int pg_n;
|
1999-06-03 13:49:52 +00:00
|
|
|
int speculative_mprobe;
|
2001-01-19 13:19:02 +00:00
|
|
|
#ifdef DEV_NPX
|
1999-06-03 13:49:52 +00:00
|
|
|
int msize;
|
1998-03-24 08:27:21 +00:00
|
|
|
#endif
|
2000-03-16 12:14:00 +00:00
|
|
|
unsigned under16;
|
1999-06-03 13:49:52 +00:00
|
|
|
vm_offset_t target_page;
|
1998-03-24 08:27:21 +00:00
|
|
|
|
2000-03-16 12:14:00 +00:00
|
|
|
pc98_getmemsize(&biosbasemem, &biosextmem, &under16);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1997-04-27 13:22:09 +00:00
|
|
|
#ifdef SMP
|
|
|
|
/* make hole for AP bootstrap code */
|
|
|
|
pagesinbase = mp_bootaddress(biosbasemem) / PAGE_SIZE;
|
|
|
|
#else
|
1996-06-14 10:04:54 +00:00
|
|
|
pagesinbase = biosbasemem * 1024 / PAGE_SIZE;
|
1997-04-27 13:22:09 +00:00
|
|
|
#endif
|
1996-06-14 10:04:54 +00:00
|
|
|
pagesinext = biosextmem * 1024 / PAGE_SIZE;
|
|
|
|
|
2000-03-16 12:14:00 +00:00
|
|
|
Maxmem_under16M = under16 * 1024 / PAGE_SIZE;
|
|
|
|
|
2000-04-30 08:52:47 +00:00
|
|
|
#ifndef MAXMEM
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Maxmem isn't the "maximum memory", it's one larger than the
|
1996-07-23 07:46:59 +00:00
|
|
|
* highest page of the physical address space. It should be
|
|
|
|
* called something like "Maxphyspage".
|
1996-06-14 10:04:54 +00:00
|
|
|
*/
|
|
|
|
Maxmem = pagesinext + 0x100000/PAGE_SIZE;
|
1997-09-05 10:14:36 +00:00
|
|
|
/*
|
|
|
|
* Indicate that we wish to do a speculative search for memory beyond
|
|
|
|
* the end of the reported size if the indicated amount is 64MB (0x4000
|
|
|
|
* pages) - which is the largest amount that the BIOS/bootblocks can
|
|
|
|
* currently report. If a specific amount of memory is indicated via
|
|
|
|
* the MAXMEM option or the npx0 "msize", then don't do the speculative
|
|
|
|
* memory probe.
|
|
|
|
*/
|
1997-09-26 09:47:04 +00:00
|
|
|
if (Maxmem >= 0x4000)
|
1997-09-05 10:14:36 +00:00
|
|
|
speculative_mprobe = TRUE;
|
|
|
|
else
|
|
|
|
speculative_mprobe = FALSE;
|
2000-04-30 08:52:47 +00:00
|
|
|
#else
|
1996-06-14 10:04:54 +00:00
|
|
|
Maxmem = MAXMEM/4;
|
1997-09-05 10:14:36 +00:00
|
|
|
speculative_mprobe = FALSE;
|
1996-06-14 10:04:54 +00:00
|
|
|
#endif
|
|
|
|
|
2001-01-19 13:19:02 +00:00
|
|
|
#ifdef DEV_NPX
|
1999-04-18 14:42:20 +00:00
|
|
|
if (resource_int_value("npx", 0, "msize", &msize) == 0) {
|
|
|
|
if (msize != 0) {
|
|
|
|
Maxmem = msize / 4;
|
|
|
|
speculative_mprobe = FALSE;
|
|
|
|
}
|
1997-09-05 10:14:36 +00:00
|
|
|
}
|
1997-01-25 06:42:19 +00:00
|
|
|
#endif
|
1996-12-04 04:21:30 +00:00
|
|
|
|
1997-06-23 09:35:47 +00:00
|
|
|
#ifdef SMP
|
|
|
|
/* look for the MP hardware - needed for apic addresses */
|
|
|
|
mp_probe();
|
|
|
|
#endif
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/* call pmap initialization to make new kernel address space */
|
|
|
|
pmap_bootstrap (first, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Size up each available chunk of physical memory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We currently don't bother testing base memory.
|
|
|
|
* XXX ...but we probably should.
|
|
|
|
*/
|
|
|
|
pa_indx = 0;
|
|
|
|
if (pagesinbase > 1) {
|
|
|
|
phys_avail[pa_indx++] = PAGE_SIZE; /* skip first page of memory */
|
|
|
|
phys_avail[pa_indx] = ptoa(pagesinbase);/* memory up to the ISA hole */
|
|
|
|
physmem = pagesinbase - 1;
|
|
|
|
} else {
|
|
|
|
/* point at first chunk end */
|
|
|
|
pa_indx++;
|
|
|
|
}
|
|
|
|
|
2000-03-16 12:14:00 +00:00
|
|
|
/* XXX - some of EPSON machines can't use PG_N */
|
|
|
|
pg_n = PG_N;
|
|
|
|
if (pc98_machine_type & M_EPSON_PC98) {
|
|
|
|
switch (epson_machine_id) {
|
|
|
|
#ifdef WB_CACHE
|
|
|
|
default:
|
|
|
|
#endif
|
|
|
|
case 0x34: /* PC-486HX */
|
|
|
|
case 0x35: /* PC-486HG */
|
|
|
|
case 0x3B: /* PC-486HA */
|
|
|
|
pg_n = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
speculative_mprobe = FALSE;
|
|
|
|
#ifdef notdef /* XXX - see below */
|
|
|
|
/*
|
|
|
|
* Certain 'CPU accelerator' supports over 16MB memory on the machines
|
|
|
|
* whose BIOS doesn't store true size.
|
2000-10-28 11:16:42 +00:00
|
|
|
* To support this, we don't trust BIOS values if Maxmem <= 16MB (0x1000
|
2000-03-16 12:14:00 +00:00
|
|
|
* pages) - which is the largest amount that the OLD PC-98 can report.
|
|
|
|
*
|
|
|
|
* OK: PC-9801NS/R(9.6M)
|
|
|
|
* OK: PC-9801DA(5.6M)+EUD-H(32M)+Cyrix 5x86
|
|
|
|
* OK: PC-9821Ap(14.6M)+EUA-T(8M)+Cyrix 5x86-100
|
|
|
|
* NG: PC-9821Ap(14.6M)+EUA-T(8M)+AMD DX4-100 -> freeze
|
|
|
|
*/
|
2000-10-28 11:16:42 +00:00
|
|
|
if (Maxmem <= 0x1000) {
|
2000-03-16 12:14:00 +00:00
|
|
|
int tmp, page_bad;
|
|
|
|
|
|
|
|
page_bad = FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For Max14.6MB machines, the 0x10f0 page is same as 0x00f0,
|
|
|
|
* which is BIOS ROM, by overlapping.
|
|
|
|
* So, we check that page's ability of writing.
|
|
|
|
*/
|
|
|
|
target_page = ptoa(0x10f0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* map page into kernel: valid, read/write, non-cacheable
|
|
|
|
*/
|
|
|
|
*(int *)CMAP1 = PG_V | PG_RW | pg_n | target_page;
|
|
|
|
invltlb();
|
|
|
|
|
|
|
|
tmp = *(int *)CADDR1;
|
|
|
|
/*
|
|
|
|
* Test for alternating 1's and 0's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0xaaaaaaaa;
|
|
|
|
if (*(volatile int *)CADDR1 != 0xaaaaaaaa)
|
|
|
|
page_bad = TRUE;
|
|
|
|
/*
|
|
|
|
* Test for alternating 0's and 1's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0x55555555;
|
|
|
|
if (*(volatile int *)CADDR1 != 0x55555555)
|
|
|
|
page_bad = TRUE;
|
|
|
|
/*
|
|
|
|
* Test for all 1's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0xffffffff;
|
|
|
|
if (*(volatile int *)CADDR1 != 0xffffffff)
|
|
|
|
page_bad = TRUE;
|
|
|
|
/*
|
|
|
|
* Test for all 0's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0x0;
|
|
|
|
if (*(volatile int *)CADDR1 != 0x0) {
|
|
|
|
/*
|
|
|
|
* test of page failed
|
|
|
|
*/
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Restore original value.
|
|
|
|
*/
|
|
|
|
*(int *)CADDR1 = tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust Maxmem if valid/good page.
|
|
|
|
*/
|
|
|
|
if (page_bad == FALSE) {
|
|
|
|
/* '+ 2' is needed to make speculative_mprobe sure */
|
|
|
|
Maxmem = 0x1000 + 2;
|
|
|
|
speculative_mprobe = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
for (target_page = avail_start; target_page < ptoa(Maxmem); target_page += PAGE_SIZE) {
|
1997-09-05 10:14:36 +00:00
|
|
|
int tmp, page_bad;
|
|
|
|
|
|
|
|
page_bad = FALSE;
|
2000-03-16 12:14:00 +00:00
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/* skip system area */
|
2000-03-16 12:14:00 +00:00
|
|
|
if (target_page >= ptoa(Maxmem_under16M) &&
|
1996-06-14 10:04:54 +00:00
|
|
|
target_page < ptoa(4096))
|
1999-12-26 04:22:27 +00:00
|
|
|
continue;
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* map page into kernel: valid, read/write, non-cacheable
|
|
|
|
*/
|
2000-03-16 12:14:00 +00:00
|
|
|
*(int *)CMAP1 = PG_V | PG_RW | pg_n | target_page;
|
1996-10-09 21:47:16 +00:00
|
|
|
invltlb();
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
tmp = *(int *)CADDR1;
|
|
|
|
/*
|
|
|
|
* Test for alternating 1's and 0's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0xaaaaaaaa;
|
|
|
|
if (*(volatile int *)CADDR1 != 0xaaaaaaaa) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test for alternating 0's and 1's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0x55555555;
|
|
|
|
if (*(volatile int *)CADDR1 != 0x55555555) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test for all 1's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0xffffffff;
|
|
|
|
if (*(volatile int *)CADDR1 != 0xffffffff) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test for all 0's
|
|
|
|
*/
|
|
|
|
*(volatile int *)CADDR1 = 0x0;
|
|
|
|
if (*(volatile int *)CADDR1 != 0x0) {
|
|
|
|
/*
|
|
|
|
* test of page failed
|
|
|
|
*/
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Restore original value.
|
|
|
|
*/
|
|
|
|
*(int *)CADDR1 = tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust array of valid/good pages.
|
|
|
|
*/
|
|
|
|
if (page_bad == FALSE) {
|
|
|
|
/*
|
|
|
|
* If this good page is a continuation of the
|
|
|
|
* previous set of good pages, then just increase
|
|
|
|
* the end pointer. Otherwise start a new chunk.
|
|
|
|
* Note that "end" points one higher than end,
|
|
|
|
* making the range >= start and < end.
|
1997-09-05 10:14:36 +00:00
|
|
|
* If we're also doing a speculative memory
|
|
|
|
* test and we at or past the end, bump up Maxmem
|
|
|
|
* so that we keep going. The first bad page
|
|
|
|
* will terminate the loop.
|
1996-06-14 10:04:54 +00:00
|
|
|
*/
|
|
|
|
if (phys_avail[pa_indx] == target_page) {
|
|
|
|
phys_avail[pa_indx] += PAGE_SIZE;
|
1997-09-05 10:14:36 +00:00
|
|
|
if (speculative_mprobe == TRUE &&
|
2000-03-16 12:14:00 +00:00
|
|
|
phys_avail[pa_indx] >= (16*1024*1024))
|
1997-09-05 10:14:36 +00:00
|
|
|
Maxmem++;
|
1996-06-14 10:04:54 +00:00
|
|
|
} else {
|
|
|
|
pa_indx++;
|
|
|
|
if (pa_indx == PHYS_AVAIL_ARRAY_END) {
|
|
|
|
printf("Too many holes in the physical address space, giving up\n");
|
|
|
|
pa_indx--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
phys_avail[pa_indx++] = target_page; /* start */
|
|
|
|
phys_avail[pa_indx] = target_page + PAGE_SIZE; /* end */
|
|
|
|
}
|
|
|
|
physmem++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*(int *)CMAP1 = 0;
|
1996-10-09 21:47:16 +00:00
|
|
|
invltlb();
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX
|
|
|
|
* The last chunk must contain at least one page plus the message
|
|
|
|
* buffer to avoid complicating other code (message buffer address
|
|
|
|
* calculation, etc.).
|
|
|
|
*/
|
|
|
|
while (phys_avail[pa_indx - 1] + PAGE_SIZE +
|
1998-05-19 12:58:05 +00:00
|
|
|
round_page(MSGBUF_SIZE) >= phys_avail[pa_indx]) {
|
1996-06-14 10:04:54 +00:00
|
|
|
physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]);
|
|
|
|
phys_avail[pa_indx--] = 0;
|
|
|
|
phys_avail[pa_indx--] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Maxmem = atop(phys_avail[pa_indx]);
|
|
|
|
|
|
|
|
/* Trim off space for the message buffer. */
|
1998-05-19 12:58:05 +00:00
|
|
|
phys_avail[pa_indx] -= round_page(MSGBUF_SIZE);
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
avail_end = phys_avail[pa_indx];
|
1999-06-03 13:49:52 +00:00
|
|
|
}
|
2000-03-16 12:14:00 +00:00
|
|
|
#else
|
1999-06-03 13:49:52 +00:00
|
|
|
static void
|
|
|
|
getmemsize(int first)
|
|
|
|
{
|
|
|
|
int i, physmap_idx, pa_indx;
|
|
|
|
u_int basemem, extmem;
|
|
|
|
struct vm86frame vmf;
|
|
|
|
struct vm86context vmc;
|
|
|
|
vm_offset_t pa, physmap[PHYSMAP_SIZE];
|
|
|
|
pt_entry_t pte;
|
1999-07-08 12:48:53 +00:00
|
|
|
const char *cp;
|
2000-10-02 08:57:21 +00:00
|
|
|
struct bios_smap *smap;
|
1998-05-19 12:58:05 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
bzero(&vmf, sizeof(struct vm86frame));
|
|
|
|
bzero(physmap, sizeof(physmap));
|
1996-11-13 02:00:17 +00:00
|
|
|
|
1999-07-03 08:31:32 +00:00
|
|
|
/*
|
|
|
|
* Perform "base memory" related probes & setup
|
|
|
|
*/
|
1999-06-03 13:49:52 +00:00
|
|
|
vm86_intcall(0x12, &vmf);
|
|
|
|
basemem = vmf.vmf_ax;
|
|
|
|
if (basemem > 640) {
|
|
|
|
printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
|
|
|
|
basemem);
|
|
|
|
basemem = 640;
|
|
|
|
}
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
1999-07-03 08:31:32 +00:00
|
|
|
* XXX if biosbasemem is now < 640, there is a `hole'
|
1999-06-03 13:49:52 +00:00
|
|
|
* between the end of base memory and the start of
|
|
|
|
* ISA memory. The hole may be empty or it may
|
|
|
|
* contain BIOS code or data. Map it read/write so
|
|
|
|
* that the BIOS can write to it. (Memory from 0 to
|
|
|
|
* the physical end of the kernel is mapped read-only
|
|
|
|
* to begin with and then parts of it are remapped.
|
|
|
|
* The parts that aren't remapped form holes that
|
|
|
|
* remain read-only and are unused by the kernel.
|
|
|
|
* The base memory area is below the physical end of
|
|
|
|
* the kernel and right now forms a read-only hole.
|
|
|
|
* The part of it from PAGE_SIZE to
|
|
|
|
* (trunc_page(biosbasemem * 1024) - 1) will be
|
|
|
|
* remapped and used by the kernel later.)
|
|
|
|
*
|
|
|
|
* This code is similar to the code used in
|
|
|
|
* pmap_mapdev, but since no memory needs to be
|
|
|
|
* allocated we simply change the mapping.
|
|
|
|
*/
|
|
|
|
for (pa = trunc_page(basemem * 1024);
|
|
|
|
pa < ISA_HOLE_START; pa += PAGE_SIZE) {
|
|
|
|
pte = (pt_entry_t)vtopte(pa + KERNBASE);
|
|
|
|
*pte = pa | PG_RW | PG_V;
|
|
|
|
}
|
1996-06-14 10:04:54 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
|
|
|
* if basemem != 640, map pages r/w into vm86 page table so
|
|
|
|
* that the bios can scribble on it.
|
|
|
|
*/
|
|
|
|
pte = (pt_entry_t)vm86paddr;
|
|
|
|
for (i = basemem / 4; i < 160; i++)
|
|
|
|
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
|
1996-10-09 21:47:16 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
|
|
|
* map page 1 R/W into the kernel page table so we can use it
|
|
|
|
* as a buffer. The kernel will unmap this page later.
|
|
|
|
*/
|
|
|
|
pte = (pt_entry_t)vtopte(KERNBASE + (1 << PAGE_SHIFT));
|
|
|
|
*pte = (1 << PAGE_SHIFT) | PG_RW | PG_V;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get memory map with INT 15:E820
|
|
|
|
*/
|
|
|
|
vmc.npages = 0;
|
|
|
|
smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT));
|
|
|
|
vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di);
|
|
|
|
|
|
|
|
physmap_idx = 0;
|
|
|
|
vmf.vmf_ebx = 0;
|
|
|
|
do {
|
|
|
|
vmf.vmf_eax = 0xE820;
|
|
|
|
vmf.vmf_edx = SMAP_SIG;
|
2000-10-02 08:57:21 +00:00
|
|
|
vmf.vmf_ecx = sizeof(struct bios_smap);
|
1999-06-03 13:49:52 +00:00
|
|
|
i = vm86_datacall(0x15, &vmf, &vmc);
|
|
|
|
if (i || vmf.vmf_eax != SMAP_SIG)
|
|
|
|
break;
|
|
|
|
if (boothowto & RB_VERBOSE)
|
|
|
|
printf("SMAP type=%02x base=%08x %08x len=%08x %08x\n",
|
|
|
|
smap->type,
|
|
|
|
*(u_int32_t *)((char *)&smap->base + 4),
|
|
|
|
(u_int32_t)smap->base,
|
|
|
|
*(u_int32_t *)((char *)&smap->length + 4),
|
|
|
|
(u_int32_t)smap->length);
|
2000-10-02 08:57:21 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
if (smap->type != 0x01)
|
|
|
|
goto next_run;
|
|
|
|
|
|
|
|
if (smap->length == 0)
|
|
|
|
goto next_run;
|
|
|
|
|
1999-07-08 12:48:53 +00:00
|
|
|
if (smap->base >= 0xffffffff) {
|
|
|
|
printf("%uK of memory above 4GB ignored\n",
|
|
|
|
(u_int)(smap->length / 1024));
|
1999-06-28 13:08:59 +00:00
|
|
|
goto next_run;
|
|
|
|
}
|
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
for (i = 0; i <= physmap_idx; i += 2) {
|
|
|
|
if (smap->base < physmap[i + 1]) {
|
|
|
|
if (boothowto & RB_VERBOSE)
|
|
|
|
printf(
|
|
|
|
"Overlapping or non-montonic memory region, ignoring second region\n");
|
|
|
|
goto next_run;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (smap->base == physmap[physmap_idx + 1]) {
|
|
|
|
physmap[physmap_idx + 1] += smap->length;
|
|
|
|
goto next_run;
|
|
|
|
}
|
|
|
|
|
|
|
|
physmap_idx += 2;
|
|
|
|
if (physmap_idx == PHYSMAP_SIZE) {
|
|
|
|
printf(
|
|
|
|
"Too many segments in the physical address map, giving up\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
physmap[physmap_idx] = smap->base;
|
|
|
|
physmap[physmap_idx + 1] = smap->base + smap->length;
|
|
|
|
next_run:
|
|
|
|
} while (vmf.vmf_ebx != 0);
|
|
|
|
|
1999-07-08 12:48:53 +00:00
|
|
|
if (physmap[1] != 0)
|
|
|
|
goto physmap_done;
|
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
1999-07-03 08:31:32 +00:00
|
|
|
* If we failed above, try memory map with INT 15:E801
|
1999-06-03 13:49:52 +00:00
|
|
|
*/
|
1999-07-08 12:48:53 +00:00
|
|
|
vmf.vmf_ax = 0xE801;
|
|
|
|
if (vm86_intcall(0x15, &vmf) == 0) {
|
|
|
|
extmem = vmf.vmf_cx + vmf.vmf_dx * 64;
|
|
|
|
} else {
|
1999-06-03 13:49:52 +00:00
|
|
|
#if 0
|
1999-07-08 12:48:53 +00:00
|
|
|
vmf.vmf_ah = 0x88;
|
|
|
|
vm86_intcall(0x15, &vmf);
|
|
|
|
extmem = vmf.vmf_ax;
|
1999-06-03 13:49:52 +00:00
|
|
|
#else
|
|
|
|
/*
|
1999-07-08 12:48:53 +00:00
|
|
|
* Prefer the RTC value for extended memory.
|
1999-06-03 13:49:52 +00:00
|
|
|
*/
|
1999-07-08 12:48:53 +00:00
|
|
|
extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8);
|
|
|
|
#endif
|
1999-07-03 08:31:32 +00:00
|
|
|
}
|
1999-06-03 13:49:52 +00:00
|
|
|
|
|
|
|
/*
|
1999-07-08 12:48:53 +00:00
|
|
|
* Special hack for chipsets that still remap the 384k hole when
|
|
|
|
* there's 16MB of memory - this really confuses people that
|
|
|
|
* are trying to use bus mastering ISA controllers with the
|
|
|
|
* "16MB limit"; they only have 16MB, but the remapping puts
|
|
|
|
* them beyond the limit.
|
|
|
|
*
|
|
|
|
* If extended memory is between 15-16MB (16-17MB phys address range),
|
|
|
|
* chop it to 15MB.
|
1999-06-03 13:49:52 +00:00
|
|
|
*/
|
1999-07-08 12:48:53 +00:00
|
|
|
if ((extmem > 15 * 1024) && (extmem < 16 * 1024))
|
|
|
|
extmem = 15 * 1024;
|
|
|
|
|
|
|
|
physmap[0] = 0;
|
|
|
|
physmap[1] = basemem * 1024;
|
|
|
|
physmap_idx = 2;
|
|
|
|
physmap[physmap_idx] = 0x100000;
|
|
|
|
physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024;
|
|
|
|
|
|
|
|
physmap_done:
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
|
|
|
* Now, physmap contains a map of physical memory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef SMP
|
|
|
|
/* make hole for AP bootstrap code */
|
|
|
|
physmap[1] = mp_bootaddress(physmap[1] / 1024);
|
|
|
|
|
|
|
|
/* look for the MP hardware - needed for apic addresses */
|
2001-05-02 13:48:39 +00:00
|
|
|
i386_mp_probe();
|
1999-06-03 13:49:52 +00:00
|
|
|
#endif
|
1999-07-08 12:48:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Maxmem isn't the "maximum memory", it's one larger than the
|
|
|
|
* highest page of the physical address space. It should be
|
|
|
|
* called something like "Maxphyspage". We may adjust this
|
|
|
|
* based on ``hw.physmem'' and the results of the memory test.
|
|
|
|
*/
|
|
|
|
Maxmem = atop(physmap[physmap_idx + 1]);
|
|
|
|
|
|
|
|
#ifdef MAXMEM
|
|
|
|
Maxmem = MAXMEM / 4;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hw.maxmem is a size in bytes; we also allow k, m, and g suffixes
|
|
|
|
* for the appropriate modifiers. This overrides MAXMEM.
|
|
|
|
*/
|
|
|
|
if ((cp = getenv("hw.physmem")) != NULL) {
|
|
|
|
u_int64_t AllowMem, sanity;
|
1999-11-24 01:03:08 +00:00
|
|
|
char *ep;
|
1999-07-08 12:48:53 +00:00
|
|
|
|
|
|
|
sanity = AllowMem = strtouq(cp, &ep, 0);
|
|
|
|
if ((ep != cp) && (*ep != 0)) {
|
|
|
|
switch(*ep) {
|
|
|
|
case 'g':
|
|
|
|
case 'G':
|
|
|
|
AllowMem <<= 10;
|
|
|
|
case 'm':
|
|
|
|
case 'M':
|
|
|
|
AllowMem <<= 10;
|
|
|
|
case 'k':
|
|
|
|
case 'K':
|
|
|
|
AllowMem <<= 10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
AllowMem = sanity = 0;
|
|
|
|
}
|
|
|
|
if (AllowMem < sanity)
|
|
|
|
AllowMem = 0;
|
|
|
|
}
|
|
|
|
if (AllowMem == 0)
|
|
|
|
printf("Ignoring invalid memory size of '%s'\n", cp);
|
|
|
|
else
|
|
|
|
Maxmem = atop(AllowMem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atop(physmap[physmap_idx + 1]) != Maxmem &&
|
|
|
|
(boothowto & RB_VERBOSE))
|
|
|
|
printf("Physical memory use set to %uK\n", Maxmem * 4);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If Maxmem has been increased beyond what the system has detected,
|
|
|
|
* extend the last memory segment to the new limit.
|
|
|
|
*/
|
|
|
|
if (atop(physmap[physmap_idx + 1]) < Maxmem)
|
|
|
|
physmap[physmap_idx + 1] = ptoa(Maxmem);
|
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/* call pmap initialization to make new kernel address space */
|
|
|
|
pmap_bootstrap(first, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Size up each available chunk of physical memory.
|
|
|
|
*/
|
|
|
|
physmap[0] = PAGE_SIZE; /* mask off page 0 */
|
|
|
|
pa_indx = 0;
|
|
|
|
phys_avail[pa_indx++] = physmap[0];
|
|
|
|
phys_avail[pa_indx] = physmap[0];
|
|
|
|
#if 0
|
|
|
|
pte = (pt_entry_t)vtopte(KERNBASE);
|
|
|
|
#else
|
|
|
|
pte = (pt_entry_t)CMAP1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* physmap is in bytes, so when converting to page boundaries,
|
|
|
|
* round up the start address and round down the end address.
|
|
|
|
*/
|
|
|
|
for (i = 0; i <= physmap_idx; i += 2) {
|
1999-06-17 11:09:39 +00:00
|
|
|
vm_offset_t end;
|
1999-06-03 13:49:52 +00:00
|
|
|
|
|
|
|
end = ptoa(Maxmem);
|
|
|
|
if (physmap[i + 1] < end)
|
|
|
|
end = trunc_page(physmap[i + 1]);
|
|
|
|
for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) {
|
|
|
|
int tmp, page_bad;
|
|
|
|
#if 0
|
|
|
|
int *ptr = 0;
|
|
|
|
#else
|
|
|
|
int *ptr = (int *)CADDR1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* block out kernel memory as not available.
|
|
|
|
*/
|
|
|
|
if (pa >= 0x100000 && pa < first)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
page_bad = FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* map page into kernel: valid, read/write,non-cacheable
|
|
|
|
*/
|
|
|
|
*pte = pa | PG_V | PG_RW | PG_N;
|
|
|
|
invltlb();
|
|
|
|
|
|
|
|
tmp = *(int *)ptr;
|
|
|
|
/*
|
|
|
|
* Test for alternating 1's and 0's
|
|
|
|
*/
|
|
|
|
*(volatile int *)ptr = 0xaaaaaaaa;
|
|
|
|
if (*(volatile int *)ptr != 0xaaaaaaaa) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test for alternating 0's and 1's
|
|
|
|
*/
|
|
|
|
*(volatile int *)ptr = 0x55555555;
|
|
|
|
if (*(volatile int *)ptr != 0x55555555) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test for all 1's
|
|
|
|
*/
|
|
|
|
*(volatile int *)ptr = 0xffffffff;
|
|
|
|
if (*(volatile int *)ptr != 0xffffffff) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Test for all 0's
|
|
|
|
*/
|
|
|
|
*(volatile int *)ptr = 0x0;
|
|
|
|
if (*(volatile int *)ptr != 0x0) {
|
|
|
|
page_bad = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Restore original value.
|
|
|
|
*/
|
|
|
|
*(int *)ptr = tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust array of valid/good pages.
|
|
|
|
*/
|
|
|
|
if (page_bad == TRUE) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If this good page is a continuation of the
|
|
|
|
* previous set of good pages, then just increase
|
|
|
|
* the end pointer. Otherwise start a new chunk.
|
|
|
|
* Note that "end" points one higher than end,
|
|
|
|
* making the range >= start and < end.
|
|
|
|
* If we're also doing a speculative memory
|
|
|
|
* test and we at or past the end, bump up Maxmem
|
|
|
|
* so that we keep going. The first bad page
|
|
|
|
* will terminate the loop.
|
|
|
|
*/
|
|
|
|
if (phys_avail[pa_indx] == pa) {
|
|
|
|
phys_avail[pa_indx] += PAGE_SIZE;
|
|
|
|
} else {
|
|
|
|
pa_indx++;
|
|
|
|
if (pa_indx == PHYS_AVAIL_ARRAY_END) {
|
|
|
|
printf("Too many holes in the physical address space, giving up\n");
|
|
|
|
pa_indx--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
phys_avail[pa_indx++] = pa; /* start */
|
|
|
|
phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */
|
|
|
|
}
|
|
|
|
physmem++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*pte = 0;
|
|
|
|
invltlb();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX
|
|
|
|
* The last chunk must contain at least one page plus the message
|
|
|
|
* buffer to avoid complicating other code (message buffer address
|
|
|
|
* calculation, etc.).
|
|
|
|
*/
|
|
|
|
while (phys_avail[pa_indx - 1] + PAGE_SIZE +
|
|
|
|
round_page(MSGBUF_SIZE) >= phys_avail[pa_indx]) {
|
|
|
|
physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]);
|
|
|
|
phys_avail[pa_indx--] = 0;
|
|
|
|
phys_avail[pa_indx--] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Maxmem = atop(phys_avail[pa_indx]);
|
|
|
|
|
|
|
|
/* Trim off space for the message buffer. */
|
|
|
|
phys_avail[pa_indx] -= round_page(MSGBUF_SIZE);
|
|
|
|
|
|
|
|
avail_end = phys_avail[pa_indx];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
init386(first)
|
|
|
|
int first;
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
struct gate_descriptor *gdp;
|
|
|
|
int gsel_tss;
|
|
|
|
#ifndef SMP
|
|
|
|
/* table descriptors - used to load tables by microp */
|
|
|
|
struct region_descriptor r_gdt, r_idt;
|
|
|
|
#endif
|
|
|
|
int off;
|
|
|
|
|
|
|
|
proc0.p_addr = proc0paddr;
|
|
|
|
|
|
|
|
atdevbase = ISA_HOLE_START + KERNBASE;
|
|
|
|
|
|
|
|
#ifdef PC98
|
|
|
|
/*
|
|
|
|
* Initialize DMAC
|
|
|
|
*/
|
|
|
|
pc98_init_dmac();
|
|
|
|
#endif
|
|
|
|
|
1999-07-03 08:31:32 +00:00
|
|
|
if (bootinfo.bi_modulep) {
|
|
|
|
preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE;
|
|
|
|
preload_bootstrap_relocate(KERNBASE);
|
2000-09-03 15:55:34 +00:00
|
|
|
} else {
|
|
|
|
printf("WARNING: loader(8) metadata is missing!\n");
|
1999-07-03 08:31:32 +00:00
|
|
|
}
|
|
|
|
if (bootinfo.bi_envp)
|
|
|
|
kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE;
|
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
|
|
|
* make gdt memory segments, the code segment goes up to end of the
|
|
|
|
* page with etext in it, the data segment goes to the end of
|
|
|
|
* the address space
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* XXX text protection is temporarily (?) disabled. The limit was
|
|
|
|
* i386_btop(round_page(etext)) - 1.
|
|
|
|
*/
|
|
|
|
gdt_segs[GCODE_SEL].ssd_limit = i386_btop(0) - 1;
|
|
|
|
gdt_segs[GDATA_SEL].ssd_limit = i386_btop(0) - 1;
|
|
|
|
#ifdef SMP
|
|
|
|
gdt_segs[GPRIV_SEL].ssd_limit =
|
|
|
|
i386_btop(sizeof(struct privatespace)) - 1;
|
|
|
|
gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[0];
|
|
|
|
gdt_segs[GPROC0_SEL].ssd_base =
|
|
|
|
(int) &SMP_prvspace[0].globaldata.gd_common_tss;
|
2001-01-07 07:59:19 +00:00
|
|
|
SMP_prvspace[0].globaldata.gd_prvspace = &SMP_prvspace[0].globaldata;
|
1999-06-03 13:49:52 +00:00
|
|
|
#else
|
2001-01-07 07:59:19 +00:00
|
|
|
gdt_segs[GPRIV_SEL].ssd_limit =
|
|
|
|
i386_btop(sizeof(struct globaldata)) - 1;
|
|
|
|
gdt_segs[GPRIV_SEL].ssd_base = (int) &__globaldata;
|
|
|
|
gdt_segs[GPROC0_SEL].ssd_base =
|
|
|
|
(int) &__globaldata.gd_common_tss;
|
|
|
|
__globaldata.gd_prvspace = &__globaldata;
|
1999-06-03 13:49:52 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (x = 0; x < NGDT; x++) {
|
|
|
|
#ifdef BDE_DEBUGGER
|
|
|
|
/* avoid overwriting db entries with APM ones */
|
|
|
|
if (x >= GAPMCODE32_SEL && x <= GAPMDATA_SEL)
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
ssdtosd(&gdt_segs[x], &gdt[x].sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1;
|
|
|
|
r_gdt.rd_base = (int) gdt;
|
|
|
|
lgdt(&r_gdt);
|
|
|
|
|
2000-09-07 13:35:44 +00:00
|
|
|
/* setup curproc so that mutexes work */
|
|
|
|
PCPU_SET(curproc, &proc0);
|
2001-04-01 06:40:45 +00:00
|
|
|
PCPU_SET(spinlocks, NULL);
|
2000-09-07 13:35:44 +00:00
|
|
|
|
2001-01-28 11:06:28 +00:00
|
|
|
LIST_INIT(&proc0.p_contested);
|
|
|
|
|
|
|
|
mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE);
|
|
|
|
#ifdef SMP
|
|
|
|
/*
|
|
|
|
* Interrupts can happen very early, so initialize imen_mtx here, rather
|
|
|
|
* than in init_locks().
|
|
|
|
*/
|
|
|
|
mtx_init(&imen_mtx, "imen", MTX_SPIN);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Giant is used early for at least debugger traps and unexpected traps.
|
|
|
|
*/
|
|
|
|
mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE);
|
2001-02-09 16:25:16 +00:00
|
|
|
mtx_init(&proc0.p_mtx, "process lock", MTX_DEF);
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_lock(&Giant);
|
2001-01-28 11:06:28 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/* make ldt memory segments */
|
|
|
|
/*
|
|
|
|
* The data segment limit must not cover the user area because we
|
|
|
|
* don't want the user area to be writable in copyout() etc. (page
|
|
|
|
* level protection is lost in kernel mode on 386's). Also, we
|
|
|
|
* don't want the user area to be writable directly (page level
|
|
|
|
* protection of the user area is not available on 486's with
|
|
|
|
* CR0_WP set, because there is no user-read/kernel-write mode).
|
|
|
|
*
|
|
|
|
* XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it
|
|
|
|
* should be spelled ...MAX_USER...
|
|
|
|
*/
|
|
|
|
#define VM_END_USER_RW_ADDRESS VM_MAXUSER_ADDRESS
|
|
|
|
/*
|
|
|
|
* The code segment limit has to cover the user area until we move
|
|
|
|
* the signal trampoline out of the user area. This is safe because
|
|
|
|
* the code segment cannot be written to directly.
|
|
|
|
*/
|
|
|
|
#define VM_END_USER_R_ADDRESS (VM_END_USER_RW_ADDRESS + UPAGES * PAGE_SIZE)
|
|
|
|
ldt_segs[LUCODE_SEL].ssd_limit = i386_btop(VM_END_USER_R_ADDRESS) - 1;
|
|
|
|
ldt_segs[LUDATA_SEL].ssd_limit = i386_btop(VM_END_USER_RW_ADDRESS) - 1;
|
|
|
|
for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++)
|
|
|
|
ssdtosd(&ldt_segs[x], &ldt[x].sd);
|
|
|
|
|
|
|
|
_default_ldt = GSEL(GLDT_SEL, SEL_KPL);
|
|
|
|
lldt(_default_ldt);
|
2000-09-08 11:20:04 +00:00
|
|
|
PCPU_SET(currentldt, _default_ldt);
|
1999-06-03 13:49:52 +00:00
|
|
|
|
|
|
|
/* exceptions */
|
|
|
|
for (x = 0; x < NIDT; x++)
|
|
|
|
setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(8, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL));
|
|
|
|
setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(14, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(18, &IDTVEC(mchk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(0x80, &IDTVEC(int0x80_syscall),
|
|
|
|
SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
|
1999-06-21 11:14:27 +00:00
|
|
|
r_idt.rd_limit = sizeof(idt0) - 1;
|
1999-06-03 13:49:52 +00:00
|
|
|
r_idt.rd_base = (int) idt;
|
|
|
|
lidt(&r_idt);
|
|
|
|
|
2000-10-06 11:43:51 +00:00
|
|
|
/*
|
|
|
|
* We need this mutex before the console probe.
|
|
|
|
*/
|
2001-01-21 07:52:20 +00:00
|
|
|
mtx_init(&clock_lock, "clk", MTX_SPIN | MTX_RECURSE);
|
2000-10-06 11:43:51 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/*
|
|
|
|
* Initialize the console before we print anything out.
|
|
|
|
*/
|
|
|
|
cninit();
|
|
|
|
|
2001-01-29 09:38:39 +00:00
|
|
|
#ifdef DEV_ISA
|
1999-06-03 13:49:52 +00:00
|
|
|
isa_defaultirq();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DDB
|
|
|
|
kdb_init();
|
|
|
|
if (boothowto & RB_KDB)
|
|
|
|
Debugger("Boot flags requested debugger");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
finishidentcpu(); /* Final stage of CPU initialization */
|
|
|
|
setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
|
|
|
initializecpu(); /* Initialize CPU registers */
|
|
|
|
|
|
|
|
/* make an initial tss so cpu can get interrupt stack on syscall! */
|
2001-01-12 13:39:50 +00:00
|
|
|
PCPU_SET(common_tss.tss_esp0,
|
|
|
|
(int) proc0.p_addr + UPAGES*PAGE_SIZE - 16);
|
|
|
|
PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL));
|
1999-06-03 13:49:52 +00:00
|
|
|
gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
|
|
|
|
private_tss = 0;
|
2001-01-12 13:39:50 +00:00
|
|
|
PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd);
|
|
|
|
PCPU_SET(common_tssd, *PCPU_GET(tss_gdt));
|
|
|
|
PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16);
|
1999-06-30 13:30:10 +00:00
|
|
|
ltr(gsel_tss);
|
1999-06-03 13:49:52 +00:00
|
|
|
|
|
|
|
dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 =
|
|
|
|
dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)];
|
|
|
|
dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
|
|
|
|
dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
|
|
|
|
dblfault_tss.tss_cr3 = (int)IdlePTD;
|
|
|
|
dblfault_tss.tss_eip = (int) dblfault_handler;
|
|
|
|
dblfault_tss.tss_eflags = PSL_KERNEL;
|
|
|
|
dblfault_tss.tss_ds = dblfault_tss.tss_es =
|
|
|
|
dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
|
|
|
|
dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL);
|
|
|
|
dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
|
|
|
|
dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
|
|
|
|
|
|
|
|
vm86_initialize();
|
|
|
|
getmemsize(first);
|
2000-04-30 08:52:47 +00:00
|
|
|
|
1999-06-03 13:49:52 +00:00
|
|
|
/* now running on new page tables, configured,and u/iom is accessible */
|
|
|
|
|
|
|
|
/* Map the message buffer. */
|
|
|
|
for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE)
|
1999-06-17 11:09:39 +00:00
|
|
|
pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off);
|
1999-06-03 13:49:52 +00:00
|
|
|
|
|
|
|
msgbufinit(msgbufp, MSGBUF_SIZE);
|
|
|
|
|
|
|
|
/* make a call gate to reenter kernel with */
|
|
|
|
gdp = &ldt[LSYS5CALLS_SEL].gd;
|
|
|
|
|
2001-02-25 08:00:35 +00:00
|
|
|
x = (int) &IDTVEC(lcall_syscall);
|
|
|
|
gdp->gd_looffset = x;
|
1999-06-03 13:49:52 +00:00
|
|
|
gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
|
|
|
|
gdp->gd_stkcpy = 1;
|
|
|
|
gdp->gd_type = SDT_SYS386CGT;
|
|
|
|
gdp->gd_dpl = SEL_UPL;
|
|
|
|
gdp->gd_p = 1;
|
2001-02-25 08:00:35 +00:00
|
|
|
gdp->gd_hioffset = x >> 16;
|
1999-06-03 13:49:52 +00:00
|
|
|
|
|
|
|
/* XXX does this work? */
|
|
|
|
ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL];
|
|
|
|
ldt[LSOL26CALLS_SEL] = ldt[LSYS5CALLS_SEL];
|
|
|
|
|
|
|
|
/* transfer to user mode */
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
_ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
|
|
|
|
_udatasel = LSEL(LUDATA_SEL, SEL_UPL);
|
|
|
|
|
|
|
|
/* setup proc 0's pcb */
|
|
|
|
proc0.p_addr->u_pcb.pcb_flags = 0;
|
1997-06-23 09:35:47 +00:00
|
|
|
proc0.p_addr->u_pcb.pcb_cr3 = (int)IdlePTD;
|
1997-08-09 01:56:34 +00:00
|
|
|
proc0.p_addr->u_pcb.pcb_ext = 0;
|
2000-08-12 07:35:12 +00:00
|
|
|
proc0.p_md.md_regs = &proc0_tf;
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
|
1997-12-05 11:48:53 +00:00
|
|
|
#if defined(I586_CPU) && !defined(NO_F00F_HACK)
|
1998-02-09 15:04:39 +00:00
|
|
|
static void f00f_hack(void *unused);
|
1997-12-03 09:46:34 +00:00
|
|
|
SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL);
|
|
|
|
|
1998-02-09 15:04:39 +00:00
|
|
|
static void
|
|
|
|
f00f_hack(void *unused) {
|
1999-06-21 11:14:27 +00:00
|
|
|
struct gate_descriptor *new_idt;
|
1998-03-08 03:55:35 +00:00
|
|
|
#ifndef SMP
|
1997-12-03 09:46:34 +00:00
|
|
|
struct region_descriptor r_idt;
|
1998-03-08 03:55:35 +00:00
|
|
|
#endif
|
1998-02-09 15:04:39 +00:00
|
|
|
vm_offset_t tmp;
|
1997-12-03 09:46:34 +00:00
|
|
|
|
|
|
|
if (!has_f00f_bug)
|
|
|
|
return;
|
|
|
|
|
1998-12-11 08:04:33 +00:00
|
|
|
printf("Intel Pentium detected, installing workaround for F00F bug\n");
|
1997-12-03 09:46:34 +00:00
|
|
|
|
1999-06-21 11:14:27 +00:00
|
|
|
r_idt.rd_limit = sizeof(idt0) - 1;
|
1997-12-03 09:46:34 +00:00
|
|
|
|
|
|
|
tmp = kmem_alloc(kernel_map, PAGE_SIZE * 2);
|
|
|
|
if (tmp == 0)
|
|
|
|
panic("kmem_alloc returned 0");
|
|
|
|
if (((unsigned int)tmp & (PAGE_SIZE-1)) != 0)
|
|
|
|
panic("kmem_alloc returned non-page-aligned memory");
|
|
|
|
/* Put the first seven entries in the lower page */
|
1999-06-21 11:14:27 +00:00
|
|
|
new_idt = (struct gate_descriptor*)(tmp + PAGE_SIZE - (7*8));
|
|
|
|
bcopy(idt, new_idt, sizeof(idt0));
|
|
|
|
r_idt.rd_base = (int)new_idt;
|
1997-12-03 09:46:34 +00:00
|
|
|
lidt(&r_idt);
|
1999-06-21 11:14:27 +00:00
|
|
|
idt = new_idt;
|
1997-12-03 09:46:34 +00:00
|
|
|
if (vm_map_protect(kernel_map, tmp, tmp + PAGE_SIZE,
|
|
|
|
VM_PROT_READ, FALSE) != KERN_SUCCESS)
|
|
|
|
panic("vm_map_protect failed");
|
|
|
|
return;
|
|
|
|
}
|
1997-12-05 11:48:53 +00:00
|
|
|
#endif /* defined(I586_CPU) && !NO_F00F_HACK */
|
1997-12-03 09:46:34 +00:00
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
int
|
|
|
|
ptrace_set_pc(p, addr)
|
|
|
|
struct proc *p;
|
1998-06-08 08:55:47 +00:00
|
|
|
unsigned long addr;
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
1997-05-08 09:34:16 +00:00
|
|
|
p->p_md.md_regs->tf_eip = addr;
|
1996-06-14 10:04:54 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ptrace_single_step(p)
|
|
|
|
struct proc *p;
|
|
|
|
{
|
1997-05-08 09:34:16 +00:00
|
|
|
p->p_md.md_regs->tf_eflags |= PSL_T;
|
1996-06-14 10:04:54 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1998-05-19 12:58:05 +00:00
|
|
|
int ptrace_read_u_check(p, addr, len)
|
|
|
|
struct proc *p;
|
|
|
|
vm_offset_t addr;
|
|
|
|
size_t len;
|
|
|
|
{
|
|
|
|
vm_offset_t gap;
|
|
|
|
|
|
|
|
if ((vm_offset_t) (addr + len) < addr)
|
|
|
|
return EPERM;
|
|
|
|
if ((vm_offset_t) (addr + len) <= sizeof(struct user))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
gap = (char *) p->p_md.md_regs - (char *) p->p_addr;
|
|
|
|
|
|
|
|
if ((vm_offset_t) addr < gap)
|
|
|
|
return EPERM;
|
|
|
|
if ((vm_offset_t) (addr + len) <=
|
|
|
|
(vm_offset_t) (gap + sizeof(struct trapframe)))
|
|
|
|
return 0;
|
|
|
|
return EPERM;
|
|
|
|
}
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
int ptrace_write_u(p, off, data)
|
|
|
|
struct proc *p;
|
|
|
|
vm_offset_t off;
|
1998-06-08 08:55:47 +00:00
|
|
|
long data;
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
|
|
|
struct trapframe frame_copy;
|
|
|
|
vm_offset_t min;
|
|
|
|
struct trapframe *tp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Privileged kernel state is scattered all over the user area.
|
|
|
|
* Only allow write access to parts of regs and to fpregs.
|
|
|
|
*/
|
1997-04-07 11:00:48 +00:00
|
|
|
min = (char *)p->p_md.md_regs - (char *)p->p_addr;
|
1996-06-14 10:04:54 +00:00
|
|
|
if (off >= min && off <= min + sizeof(struct trapframe) - sizeof(int)) {
|
1997-05-08 09:34:16 +00:00
|
|
|
tp = p->p_md.md_regs;
|
1996-06-14 10:04:54 +00:00
|
|
|
frame_copy = *tp;
|
|
|
|
*(int *)((char *)&frame_copy + (off - min)) = data;
|
1999-09-29 15:06:27 +00:00
|
|
|
if (!EFL_SECURE(frame_copy.tf_eflags, tp->tf_eflags) ||
|
1996-06-14 10:04:54 +00:00
|
|
|
!CS_SECURE(frame_copy.tf_cs))
|
|
|
|
return (EINVAL);
|
|
|
|
*(int*)((char *)p->p_addr + off) = data;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
min = offsetof(struct user, u_pcb) + offsetof(struct pcb, pcb_savefpu);
|
|
|
|
if (off >= min && off <= min + sizeof(struct save87) - sizeof(int)) {
|
|
|
|
*(int*)((char *)p->p_addr + off) = data;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (EFAULT);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fill_regs(p, regs)
|
|
|
|
struct proc *p;
|
|
|
|
struct reg *regs;
|
|
|
|
{
|
1997-06-09 13:38:21 +00:00
|
|
|
struct pcb *pcb;
|
1996-06-14 10:04:54 +00:00
|
|
|
struct trapframe *tp;
|
|
|
|
|
1997-05-08 09:34:16 +00:00
|
|
|
tp = p->p_md.md_regs;
|
1999-04-28 08:03:54 +00:00
|
|
|
regs->r_fs = tp->tf_fs;
|
1996-06-14 10:04:54 +00:00
|
|
|
regs->r_es = tp->tf_es;
|
|
|
|
regs->r_ds = tp->tf_ds;
|
|
|
|
regs->r_edi = tp->tf_edi;
|
|
|
|
regs->r_esi = tp->tf_esi;
|
|
|
|
regs->r_ebp = tp->tf_ebp;
|
|
|
|
regs->r_ebx = tp->tf_ebx;
|
|
|
|
regs->r_edx = tp->tf_edx;
|
|
|
|
regs->r_ecx = tp->tf_ecx;
|
|
|
|
regs->r_eax = tp->tf_eax;
|
|
|
|
regs->r_eip = tp->tf_eip;
|
|
|
|
regs->r_cs = tp->tf_cs;
|
|
|
|
regs->r_eflags = tp->tf_eflags;
|
|
|
|
regs->r_esp = tp->tf_esp;
|
|
|
|
regs->r_ss = tp->tf_ss;
|
1997-06-09 13:38:21 +00:00
|
|
|
pcb = &p->p_addr->u_pcb;
|
|
|
|
regs->r_gs = pcb->pcb_gs;
|
1996-06-14 10:04:54 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
set_regs(p, regs)
|
|
|
|
struct proc *p;
|
|
|
|
struct reg *regs;
|
|
|
|
{
|
1997-06-09 13:38:21 +00:00
|
|
|
struct pcb *pcb;
|
1996-06-14 10:04:54 +00:00
|
|
|
struct trapframe *tp;
|
|
|
|
|
1997-05-08 09:34:16 +00:00
|
|
|
tp = p->p_md.md_regs;
|
1999-09-29 15:06:27 +00:00
|
|
|
if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) ||
|
1996-06-14 10:04:54 +00:00
|
|
|
!CS_SECURE(regs->r_cs))
|
|
|
|
return (EINVAL);
|
1999-04-28 08:03:54 +00:00
|
|
|
tp->tf_fs = regs->r_fs;
|
1996-06-14 10:04:54 +00:00
|
|
|
tp->tf_es = regs->r_es;
|
|
|
|
tp->tf_ds = regs->r_ds;
|
|
|
|
tp->tf_edi = regs->r_edi;
|
|
|
|
tp->tf_esi = regs->r_esi;
|
|
|
|
tp->tf_ebp = regs->r_ebp;
|
|
|
|
tp->tf_ebx = regs->r_ebx;
|
|
|
|
tp->tf_edx = regs->r_edx;
|
|
|
|
tp->tf_ecx = regs->r_ecx;
|
|
|
|
tp->tf_eax = regs->r_eax;
|
|
|
|
tp->tf_eip = regs->r_eip;
|
|
|
|
tp->tf_cs = regs->r_cs;
|
|
|
|
tp->tf_eflags = regs->r_eflags;
|
|
|
|
tp->tf_esp = regs->r_esp;
|
|
|
|
tp->tf_ss = regs->r_ss;
|
1997-06-09 13:38:21 +00:00
|
|
|
pcb = &p->p_addr->u_pcb;
|
|
|
|
pcb->pcb_gs = regs->r_gs;
|
1996-06-14 10:04:54 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1998-09-15 03:50:08 +00:00
|
|
|
int
|
|
|
|
fill_fpregs(p, fpregs)
|
|
|
|
struct proc *p;
|
|
|
|
struct fpreg *fpregs;
|
|
|
|
{
|
|
|
|
bcopy(&p->p_addr->u_pcb.pcb_savefpu, fpregs, sizeof *fpregs);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
set_fpregs(p, fpregs)
|
|
|
|
struct proc *p;
|
|
|
|
struct fpreg *fpregs;
|
|
|
|
{
|
|
|
|
bcopy(fpregs, &p->p_addr->u_pcb.pcb_savefpu, sizeof *fpregs);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1999-07-09 12:51:11 +00:00
|
|
|
int
|
|
|
|
fill_dbregs(p, dbregs)
|
|
|
|
struct proc *p;
|
|
|
|
struct dbreg *dbregs;
|
|
|
|
{
|
|
|
|
struct pcb *pcb;
|
|
|
|
|
|
|
|
pcb = &p->p_addr->u_pcb;
|
|
|
|
dbregs->dr0 = pcb->pcb_dr0;
|
|
|
|
dbregs->dr1 = pcb->pcb_dr1;
|
|
|
|
dbregs->dr2 = pcb->pcb_dr2;
|
|
|
|
dbregs->dr3 = pcb->pcb_dr3;
|
|
|
|
dbregs->dr4 = 0;
|
|
|
|
dbregs->dr5 = 0;
|
|
|
|
dbregs->dr6 = pcb->pcb_dr6;
|
|
|
|
dbregs->dr7 = pcb->pcb_dr7;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
set_dbregs(p, dbregs)
|
|
|
|
struct proc *p;
|
|
|
|
struct dbreg *dbregs;
|
|
|
|
{
|
|
|
|
struct pcb *pcb;
|
2000-08-18 09:22:01 +00:00
|
|
|
int i;
|
|
|
|
u_int32_t mask1, mask2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't let an illegal value for dr7 get set. Specifically,
|
|
|
|
* check for undefined settings. Setting these bit patterns
|
|
|
|
* result in undefined behaviour and can lead to an unexpected
|
|
|
|
* TRCTRAP.
|
|
|
|
*/
|
|
|
|
for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8;
|
|
|
|
i++, mask1 <<= 2, mask2 <<= 2)
|
|
|
|
if ((dbregs->dr7 & mask1) == mask2)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
if (dbregs->dr7 & 0x0000fc00)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
|
1999-07-09 12:51:11 +00:00
|
|
|
|
|
|
|
pcb = &p->p_addr->u_pcb;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't let a process set a breakpoint that is not within the
|
|
|
|
* process's address space. If a process could do this, it
|
|
|
|
* could halt the system by setting a breakpoint in the kernel
|
|
|
|
* (if ddb was enabled). Thus, we need to check to make sure
|
|
|
|
* that no breakpoints are being enabled for addresses outside
|
|
|
|
* process's address space, unless, perhaps, we were called by
|
|
|
|
* uid 0.
|
|
|
|
*
|
|
|
|
* XXX - what about when the watched area of the user's
|
|
|
|
* address space is written into from within the kernel
|
|
|
|
* ... wouldn't that still cause a breakpoint to be generated
|
|
|
|
* from within kernel mode?
|
|
|
|
*/
|
|
|
|
|
2001-01-28 11:06:28 +00:00
|
|
|
if (suser(p) != 0) {
|
1999-07-09 12:51:11 +00:00
|
|
|
if (dbregs->dr7 & 0x3) {
|
|
|
|
/* dr0 is enabled */
|
|
|
|
if (dbregs->dr0 >= VM_MAXUSER_ADDRESS)
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dbregs->dr7 & (0x3<<2)) {
|
|
|
|
/* dr1 is enabled */
|
|
|
|
if (dbregs->dr1 >= VM_MAXUSER_ADDRESS)
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dbregs->dr7 & (0x3<<4)) {
|
|
|
|
/* dr2 is enabled */
|
|
|
|
if (dbregs->dr2 >= VM_MAXUSER_ADDRESS)
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dbregs->dr7 & (0x3<<6)) {
|
|
|
|
/* dr3 is enabled */
|
|
|
|
if (dbregs->dr3 >= VM_MAXUSER_ADDRESS)
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pcb->pcb_dr0 = dbregs->dr0;
|
|
|
|
pcb->pcb_dr1 = dbregs->dr1;
|
|
|
|
pcb->pcb_dr2 = dbregs->dr2;
|
|
|
|
pcb->pcb_dr3 = dbregs->dr3;
|
|
|
|
pcb->pcb_dr6 = dbregs->dr6;
|
|
|
|
pcb->pcb_dr7 = dbregs->dr7;
|
|
|
|
|
|
|
|
pcb->pcb_flags |= PCB_DBREGS;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2000-03-01 08:53:59 +00:00
|
|
|
/*
|
|
|
|
* Return > 0 if a hardware breakpoint has been hit, and the
|
|
|
|
* breakpoint was in user space. Return 0, otherwise.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
user_dbreg_trap(void)
|
|
|
|
{
|
|
|
|
u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */
|
|
|
|
u_int32_t bp; /* breakpoint bits extracted from dr6 */
|
|
|
|
int nbp; /* number of breakpoints that triggered */
|
|
|
|
caddr_t addr[4]; /* breakpoint addresses */
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dr7 = rdr7();
|
|
|
|
if ((dr7 & 0x000000ff) == 0) {
|
|
|
|
/*
|
|
|
|
* all GE and LE bits in the dr7 register are zero,
|
|
|
|
* thus the trap couldn't have been caused by the
|
|
|
|
* hardware debug registers
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
nbp = 0;
|
|
|
|
dr6 = rdr6();
|
|
|
|
bp = dr6 & 0x0000000f;
|
|
|
|
|
|
|
|
if (!bp) {
|
|
|
|
/*
|
|
|
|
* None of the breakpoint bits are set meaning this
|
|
|
|
* trap was not caused by any of the debug registers
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* at least one of the breakpoints were hit, check to see
|
|
|
|
* which ones and if any of them are user space addresses
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (bp & 0x01) {
|
|
|
|
addr[nbp++] = (caddr_t)rdr0();
|
|
|
|
}
|
|
|
|
if (bp & 0x02) {
|
|
|
|
addr[nbp++] = (caddr_t)rdr1();
|
|
|
|
}
|
|
|
|
if (bp & 0x04) {
|
|
|
|
addr[nbp++] = (caddr_t)rdr2();
|
|
|
|
}
|
|
|
|
if (bp & 0x08) {
|
|
|
|
addr[nbp++] = (caddr_t)rdr3();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<nbp; i++) {
|
|
|
|
if (addr[i] <
|
|
|
|
(caddr_t)VM_MAXUSER_ADDRESS) {
|
|
|
|
/*
|
|
|
|
* addr[i] is in user space
|
|
|
|
*/
|
|
|
|
return nbp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* None of the breakpoints are in user space.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
#ifndef DDB
|
|
|
|
void
|
|
|
|
Debugger(const char *msg)
|
|
|
|
{
|
|
|
|
printf("Debugger(\"%s\") called.\n", msg);
|
|
|
|
}
|
|
|
|
#endif /* no DDB */
|
|
|
|
|
|
|
|
#include <sys/disklabel.h>
|
1996-12-01 16:34:41 +00:00
|
|
|
|
1996-06-14 10:04:54 +00:00
|
|
|
/*
|
|
|
|
* Determine the size of the transfer, and make sure it is
|
|
|
|
* within the boundaries of the partition. Adjust transfer
|
|
|
|
* if needed, and signal errors or early completion.
|
|
|
|
*/
|
|
|
|
int
|
2000-04-15 05:54:02 +00:00
|
|
|
bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel)
|
1996-06-14 10:04:54 +00:00
|
|
|
{
|
2000-04-15 05:54:02 +00:00
|
|
|
struct partition *p = lp->d_partitions + dkpart(bp->bio_dev);
|
1996-06-14 10:04:54 +00:00
|
|
|
int labelsect = lp->d_partitions[0].p_offset;
|
|
|
|
int maxsz = p->p_size,
|
2000-04-15 05:54:02 +00:00
|
|
|
sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
|
1996-06-14 10:04:54 +00:00
|
|
|
|
|
|
|
/* overwriting disk label ? */
|
|
|
|
/* XXX should also protect bootstrap in first 8K */
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect &&
|
1996-06-14 10:04:54 +00:00
|
|
|
#if LABELSECTOR != 0
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect &&
|
1996-06-14 10:04:54 +00:00
|
|
|
#endif
|
2000-04-15 05:54:02 +00:00
|
|
|
(bp->bio_cmd == BIO_WRITE) && wlabel == 0) {
|
|
|
|
bp->bio_error = EROFS;
|
1996-06-14 10:04:54 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(DOSBBSECTOR) && defined(notyet)
|
|
|
|
/* overwriting master boot record? */
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR &&
|
|
|
|
(bp->bio_cmd == BIO_WRITE) && wlabel == 0) {
|
|
|
|
bp->bio_error = EROFS;
|
1996-06-14 10:04:54 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* beyond partition? */
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) {
|
1996-06-14 10:04:54 +00:00
|
|
|
/* if exactly at end of disk, return an EOF */
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_blkno == maxsz) {
|
|
|
|
bp->bio_resid = bp->bio_bcount;
|
1996-06-14 10:04:54 +00:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
/* or truncate if part of it fits */
|
2000-04-15 05:54:02 +00:00
|
|
|
sz = maxsz - bp->bio_blkno;
|
1996-06-14 10:04:54 +00:00
|
|
|
if (sz <= 0) {
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_error = EINVAL;
|
1996-06-14 10:04:54 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_bcount = sz << DEV_BSHIFT;
|
1996-06-14 10:04:54 +00:00
|
|
|
}
|
|
|
|
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_pblkno = bp->bio_blkno + p->p_offset;
|
1996-06-14 10:04:54 +00:00
|
|
|
return(1);
|
|
|
|
|
|
|
|
bad:
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_flags |= BIO_ERROR;
|
1996-06-14 10:04:54 +00:00
|
|
|
return(-1);
|
|
|
|
}
|
1997-03-29 02:48:49 +00:00
|
|
|
|
|
|
|
#ifdef DDB
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Provide inb() and outb() as functions. They are normally only
|
|
|
|
* available as macros calling inlined functions, thus cannot be
|
|
|
|
* called inside DDB.
|
|
|
|
*
|
|
|
|
* The actual code is stolen from <machine/cpufunc.h>, and de-inlined.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#undef inb
|
|
|
|
#undef outb
|
|
|
|
|
|
|
|
/* silence compiler warnings */
|
|
|
|
u_char inb(u_int);
|
|
|
|
void outb(u_int, u_char);
|
|
|
|
|
|
|
|
u_char
|
|
|
|
inb(u_int port)
|
|
|
|
{
|
|
|
|
u_char data;
|
|
|
|
/*
|
|
|
|
* We use %%dx and not %1 here because i/o is done at %dx and not at
|
|
|
|
* %edx, while gcc generates inferior code (movw instead of movl)
|
|
|
|
* if we tell it to load (u_short) port.
|
|
|
|
*/
|
|
|
|
__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
|
|
|
|
return (data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
outb(u_int port, u_char data)
|
|
|
|
{
|
|
|
|
u_char al;
|
|
|
|
/*
|
|
|
|
* Use an unnecessary assignment to help gcc's register allocator.
|
|
|
|
* This make a large difference for gcc-1.40 and a tiny difference
|
|
|
|
* for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
|
|
|
|
* best results. gcc-2.6.0 can't handle this.
|
|
|
|
*/
|
|
|
|
al = data;
|
|
|
|
__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* DDB */
|