machdep.c revision 5035
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 1992 Terrence R. Lambert. 3219820Sjeff * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. 4219820Sjeff * All rights reserved. 5219820Sjeff * 6219820Sjeff * This code is derived from software contributed to Berkeley by 7219820Sjeff * William Jolitz. 8219820Sjeff * 9219820Sjeff * Redistribution and use in source and binary forms, with or without 10219820Sjeff * modification, are permitted provided that the following conditions 11219820Sjeff * are met: 12219820Sjeff * 1. Redistributions of source code must retain the above copyright 13219820Sjeff * notice, this list of conditions and the following disclaimer. 14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 15219820Sjeff * notice, this list of conditions and the following disclaimer in the 16219820Sjeff * documentation and/or other materials provided with the distribution. 17219820Sjeff * 3. All advertising materials mentioning features or use of this software 18219820Sjeff * must display the following acknowledgement: 19219820Sjeff * This product includes software developed by the University of 20219820Sjeff * California, Berkeley and its contributors. 21219820Sjeff * 4. Neither the name of the University nor the names of its contributors 22219820Sjeff * may be used to endorse or promote products derived from this software 23219820Sjeff * without specific prior written permission. 24219820Sjeff * 25219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35219820Sjeff * SUCH DAMAGE. 36219820Sjeff * 37219820Sjeff * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 38219820Sjeff * $Id: machdep.c,v 1.95 1994/11/27 01:49:39 phk Exp $ 39219820Sjeff */ 40219820Sjeff 41219820Sjeff#include "npx.h" 42219820Sjeff#include "isa.h" 43219820Sjeff 44219820Sjeff#include <sys/param.h> 45219820Sjeff#include <sys/systm.h> 46219820Sjeff#include <sys/signalvar.h> 47219820Sjeff#include <sys/kernel.h> 48219820Sjeff#include <sys/proc.h> 49219820Sjeff#include <sys/user.h> 50219820Sjeff#include <sys/buf.h> 51219820Sjeff#include <sys/reboot.h> 52219820Sjeff#include <sys/conf.h> 53219820Sjeff#include <sys/file.h> 54219820Sjeff#include <sys/callout.h> 55219820Sjeff#include <sys/malloc.h> 56219820Sjeff#include <sys/mbuf.h> 57219820Sjeff#include <sys/msgbuf.h> 58219820Sjeff#include <sys/ioctl.h> 59219820Sjeff#include <sys/sysent.h> 60219820Sjeff#include <sys/tty.h> 61219820Sjeff#include <sys/sysctl.h> 62219820Sjeff 63219820Sjeff#ifdef SYSVSHM 64219820Sjeff#include <sys/shm.h> 65219820Sjeff#endif 66219820Sjeff 67219820Sjeff#ifdef SYSVMSG 68219820Sjeff#include <sys/msg.h> 69219820Sjeff#endif 70219820Sjeff 71219820Sjeff#ifdef SYSVSEM 72219820Sjeff#include <sys/sem.h> 73219820Sjeff#endif 74219820Sjeff 75219820Sjeff#include <vm/vm.h> 76219820Sjeff#include <vm/vm_kern.h> 77219820Sjeff#include <vm/vm_page.h> 78219820Sjeff 79219820Sjeff#include <sys/exec.h> 80219820Sjeff#include <sys/vnode.h> 81219820Sjeff 82219820Sjeff#include <net/netisr.h> 83219820Sjeff 84219820Sjeffextern vm_offset_t avail_start, avail_end; 85219820Sjeff 86219820Sjeff#include "ether.h" 87219820Sjeff 88219820Sjeff#include <machine/cpu.h> 89219820Sjeff#include <machine/npx.h> 90219820Sjeff#include <machine/reg.h> 91219820Sjeff#include <machine/psl.h> 92219820Sjeff#include <machine/clock.h> 93219820Sjeff#include <machine/specialreg.h> 94219820Sjeff#include <machine/sysarch.h> 95219820Sjeff#include <machine/cons.h> 96219820Sjeff#include <machine/devconf.h> 97219820Sjeff#include <machine/bootinfo.h> 98219820Sjeff 99219820Sjeff#include <i386/isa/isa.h> 100219820Sjeff#include <i386/isa/isa_device.h> 101219820Sjeff#include <i386/isa/rtc.h> 102219820Sjeff 103219820Sjeffstatic void identifycpu(void); 104219820Sjeffstatic void initcpu(void); 105219820Sjeffstatic int test_page(int *, int); 106219820Sjeff 107219820Sjeffchar machine[] = "i386"; 108219820Sjeffchar cpu_model[sizeof("Cy486DLC") + 1]; 109219820Sjeff 110219820Sjeff#ifndef PANIC_REBOOT_WAIT_TIME 111219820Sjeff#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 112219820Sjeff#endif 113219820Sjeff 114219820Sjeff/* 115219820Sjeff * Declare these as initialized data so we can patch them. 116219820Sjeff */ 117219820Sjeffint nswbuf = 0; 118219820Sjeff#ifdef NBUF 119219820Sjeffint nbuf = NBUF; 120219820Sjeff#else 121219820Sjeffint nbuf = 0; 122219820Sjeff#endif 123219820Sjeff#ifdef BUFPAGES 124219820Sjeffint bufpages = BUFPAGES; 125219820Sjeff#else 126219820Sjeffint bufpages = 0; 127219820Sjeff#endif 128219820Sjeff 129219820Sjeff#ifdef BOUNCE_BUFFERS 130219820Sjeffextern char *bouncememory; 131219820Sjeffextern int maxbkva; 132219820Sjeff#ifdef BOUNCEPAGES 133219820Sjeffint bouncepages = BOUNCEPAGES; 134219820Sjeff#else 135219820Sjeffint bouncepages = 0; 136219820Sjeff#endif 137219820Sjeff#endif /* BOUNCE_BUFFERS */ 138219820Sjeff 139219820Sjeffextern int freebufspace; 140219820Sjeffint msgbufmapped = 0; /* set when safe to use msgbuf */ 141219820Sjeffint _udatasel, _ucodesel; 142219820Sjeff 143219820Sjeff 144219820Sjeff/* 145219820Sjeff * Machine-dependent startup code 146219820Sjeff */ 147219820Sjeffint boothowto = 0, bootverbose = 0, Maxmem = 0, badpages = 0, physmem = 0; 148219820Sjefflong dumplo; 149219820Sjeffextern int bootdev; 150219820Sjeffint biosmem; 151219820Sjeff 152219820Sjeffvm_offset_t phys_avail[6]; 153219820Sjeff 154219820Sjeffint cpu_class; 155219820Sjeff 156219820Sjeffvoid dumpsys __P((void)); 157219820Sjeffvm_offset_t buffer_sva, buffer_eva; 158219820Sjeffvm_offset_t clean_sva, clean_eva; 159219820Sjeffvm_offset_t pager_sva, pager_eva; 160219820Sjeffextern int pager_map_size; 161219820Sjeff 162219820Sjeff#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 163219820Sjeff 164219820Sjeffvoid 165219820Sjeffcpu_startup() 166219820Sjeff{ 167219820Sjeff register unsigned i; 168219820Sjeff register caddr_t v; 169219820Sjeff extern void (*netisrs[32])(void); 170219820Sjeff vm_offset_t maxaddr; 171219820Sjeff vm_size_t size = 0; 172219820Sjeff int firstaddr; 173219820Sjeff#ifdef BOUNCE_BUFFERS 174219820Sjeff vm_offset_t minaddr; 175219820Sjeff#endif /* BOUNCE_BUFFERS */ 176219820Sjeff 177219820Sjeff if (boothowto & RB_VERBOSE) 178219820Sjeff bootverbose++; 179219820Sjeff 180219820Sjeff /* 181219820Sjeff * Initialize error message buffer (at end of core). 182219820Sjeff */ 183219820Sjeff 184219820Sjeff /* avail_end was pre-decremented in init_386() to compensate */ 185219820Sjeff for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) 186219820Sjeff pmap_enter(pmap_kernel(), (vm_offset_t)msgbufp, 187219820Sjeff avail_end + i * NBPG, 188219820Sjeff VM_PROT_ALL, TRUE); 189219820Sjeff msgbufmapped = 1; 190219820Sjeff 191219820Sjeff /* 192219820Sjeff * Good {morning,afternoon,evening,night}. 193219820Sjeff */ 194219820Sjeff printf(version); 195219820Sjeff startrtclock(); 196219820Sjeff identifycpu(); 197219820Sjeff printf("real memory = %d (%d pages)\n", ptoa(physmem), physmem); 198219820Sjeff if (badpages) 199219820Sjeff printf("bad memory = %d (%d pages)\n", ptoa(badpages), badpages); 200219820Sjeff 201219820Sjeff /* 202219820Sjeff * Quickly wire in netisrs. 203219820Sjeff */ 204219820Sjeff#define DONET(isr, n) do { extern void isr(void); netisrs[n] = isr; } while(0) 205219820Sjeff#ifdef INET 206219820Sjeff#if NETHER > 0 207219820Sjeff DONET(arpintr, NETISR_ARP); 208219820Sjeff#endif 209219820Sjeff DONET(ipintr, NETISR_IP); 210219820Sjeff#endif 211219820Sjeff#ifdef NS 212219820Sjeff DONET(nsintr, NETISR_NS); 213219820Sjeff#endif 214219820Sjeff#ifdef ISO 215219820Sjeff DONET(clnlintr, NETISR_ISO); 216219820Sjeff#endif 217219820Sjeff#ifdef CCITT 218219820Sjeff DONET(ccittintr, NETISR_CCITT); 219219820Sjeff#endif 220219820Sjeff#undef DONET 221219820Sjeff 222219820Sjeff /* 223219820Sjeff * Allocate space for system data structures. 224219820Sjeff * The first available kernel virtual address is in "v". 225219820Sjeff * As pages of kernel virtual memory are allocated, "v" is incremented. 226219820Sjeff * As pages of memory are allocated and cleared, 227219820Sjeff * "firstaddr" is incremented. 228219820Sjeff * An index into the kernel page table corresponding to the 229219820Sjeff * virtual memory address maintained in "v" is kept in "mapaddr". 230219820Sjeff */ 231219820Sjeff 232219820Sjeff /* 233219820Sjeff * Make two passes. The first pass calculates how much memory is 234219820Sjeff * needed and allocates it. The second pass assigns virtual 235219820Sjeff * addresses to the various data structures. 236219820Sjeff */ 237219820Sjeff firstaddr = 0; 238219820Sjeffagain: 239219820Sjeff v = (caddr_t)firstaddr; 240219820Sjeff 241219820Sjeff#define valloc(name, type, num) \ 242219820Sjeff (name) = (type *)v; v = (caddr_t)((name)+(num)) 243219820Sjeff#define valloclim(name, type, num, lim) \ 244219820Sjeff (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) 245219820Sjeff valloc(callout, struct callout, ncallout); 246219820Sjeff#ifdef SYSVSHM 247219820Sjeff valloc(shmsegs, struct shmid_ds, shminfo.shmmni); 248219820Sjeff#endif 249219820Sjeff#ifdef SYSVSEM 250219820Sjeff valloc(sema, struct semid_ds, seminfo.semmni); 251219820Sjeff valloc(sem, struct sem, seminfo.semmns); 252219820Sjeff /* This is pretty disgusting! */ 253219820Sjeff valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); 254219820Sjeff#endif 255219820Sjeff#ifdef SYSVMSG 256219820Sjeff valloc(msgpool, char, msginfo.msgmax); 257219820Sjeff valloc(msgmaps, struct msgmap, msginfo.msgseg); 258219820Sjeff valloc(msghdrs, struct msg, msginfo.msgtql); 259219820Sjeff valloc(msqids, struct msqid_ds, msginfo.msgmni); 260219820Sjeff#endif 261219820Sjeff /* 262219820Sjeff * Determine how many buffers to allocate. 263219820Sjeff * Use 20% of memory of memory beyond the first 2MB 264219820Sjeff * Insure a minimum of 16 fs buffers. 265219820Sjeff * We allocate 1/2 as many swap buffer headers as file i/o buffers. 266219820Sjeff */ 267219820Sjeff if (bufpages == 0) 268219820Sjeff bufpages = ((physmem << PGSHIFT) - 2048*1024) / NBPG / 6; 269219820Sjeff if (bufpages < 64) 270219820Sjeff bufpages = 64; 271219820Sjeff 272219820Sjeff /* 273219820Sjeff * We must still limit the maximum number of buffers to be no 274219820Sjeff * more than 750 because we'll run out of kernel VM otherwise. 275219820Sjeff */ 276219820Sjeff bufpages = min(bufpages, 1500); 277219820Sjeff if (nbuf == 0) { 278219820Sjeff nbuf = bufpages / 2; 279219820Sjeff if (nbuf < 32) 280219820Sjeff nbuf = 32; 281219820Sjeff } 282219820Sjeff freebufspace = bufpages * NBPG; 283219820Sjeff if (nswbuf == 0) { 284219820Sjeff nswbuf = (nbuf / 2) &~ 1; /* force even */ 285219820Sjeff if (nswbuf > 64) 286219820Sjeff nswbuf = 64; /* sanity */ 287219820Sjeff } 288219820Sjeff valloc(swbuf, struct buf, nswbuf); 289219820Sjeff valloc(buf, struct buf, nbuf); 290219820Sjeff 291219820Sjeff#ifdef BOUNCE_BUFFERS 292219820Sjeff /* 293219820Sjeff * If there is more than 16MB of memory, allocate some bounce buffers 294219820Sjeff */ 295219820Sjeff if (Maxmem > 4096) { 296219820Sjeff if (bouncepages == 0) 297219820Sjeff bouncepages = 96; /* largest physio size + extra */ 298219820Sjeff v = (caddr_t)((vm_offset_t)((vm_offset_t)v + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); 299219820Sjeff valloc(bouncememory, char, bouncepages * PAGE_SIZE); 300219820Sjeff } 301219820Sjeff#endif 302219820Sjeff 303219820Sjeff /* 304219820Sjeff * End of first pass, size has been calculated so allocate memory 305219820Sjeff */ 306219820Sjeff if (firstaddr == 0) { 307219820Sjeff size = (vm_size_t)(v - firstaddr); 308219820Sjeff firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); 309219820Sjeff if (firstaddr == 0) 310219820Sjeff panic("startup: no room for tables"); 311219820Sjeff goto again; 312219820Sjeff } 313219820Sjeff 314219820Sjeff /* 315219820Sjeff * End of second pass, addresses have been assigned 316219820Sjeff */ 317219820Sjeff if ((vm_size_t)(v - firstaddr) != size) 318219820Sjeff panic("startup: table size inconsistency"); 319219820Sjeff 320219820Sjeff#ifdef BOUNCE_BUFFERS 321219820Sjeff clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, 322219820Sjeff (nbuf*MAXBSIZE) + (nswbuf*MAXPHYS) + 323219820Sjeff maxbkva + pager_map_size, TRUE); 324219820Sjeff io_map = kmem_suballoc(clean_map, &minaddr, &maxaddr, maxbkva, FALSE); 325219820Sjeff#else 326219820Sjeff clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, 327219820Sjeff (nbuf*MAXBSIZE) + (nswbuf*MAXPHYS) + pager_map_size, TRUE); 328219820Sjeff#endif 329219820Sjeff buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, 330219820Sjeff (nbuf*MAXBSIZE), TRUE); 331219820Sjeff pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, 332219820Sjeff (nswbuf*MAXPHYS) + pager_map_size, TRUE); 333219820Sjeff 334219820Sjeff /* 335219820Sjeff * Finally, allocate mbuf pool. Since mclrefcnt is an off-size 336219820Sjeff * we use the more space efficient malloc in place of kmem_alloc. 337219820Sjeff */ 338219820Sjeff mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, 339219820Sjeff M_MBUF, M_NOWAIT); 340219820Sjeff bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); 341219820Sjeff mb_map = kmem_suballoc(kmem_map, (vm_offset_t *)&mbutl, &maxaddr, 342219820Sjeff VM_MBUF_SIZE, FALSE); 343219820Sjeff /* 344219820Sjeff * Initialize callouts 345219820Sjeff */ 346219820Sjeff callfree = callout; 347219820Sjeff for (i = 1; i < ncallout; i++) 348219820Sjeff callout[i-1].c_next = &callout[i]; 349219820Sjeff 350219820Sjeff if (boothowto & RB_CONFIG) 351219820Sjeff userconfig(); 352219820Sjeff printf("avail memory = %d (%d pages)\n", ptoa(cnt.v_free_count), cnt.v_free_count); 353219820Sjeff printf("using %d buffers containing %d bytes of memory\n", 354219820Sjeff nbuf, bufpages * CLBYTES); 355219820Sjeff 356219820Sjeff#ifdef BOUNCE_BUFFERS 357219820Sjeff /* 358219820Sjeff * init bounce buffers 359219820Sjeff */ 360219820Sjeff vm_bounce_init(); 361219820Sjeff#endif 362219820Sjeff 363219820Sjeff /* 364219820Sjeff * Set up CPU-specific registers, cache, etc. 365219820Sjeff */ 366219820Sjeff initcpu(); 367219820Sjeff 368219820Sjeff /* 369219820Sjeff * Set up buffers, so they can be used to read disk labels. 370219820Sjeff */ 371219820Sjeff bufinit(); 372219820Sjeff vm_pager_bufferinit(); 373219820Sjeff 374219820Sjeff /* 375255932Salfred * Configure the system. 376255932Salfred */ 377255932Salfred configure(); 378255932Salfred if (bootverbose) { 379255932Salfred printf("BIOS Geometries:"); 380255932Salfred for (i=0; i < N_BIOS_GEOM; i++) 381255932Salfred printf(" %x:%x\n", i, bootinfo.bios_geom[i]); 382255932Salfred printf(" %d accounted for\n",bootinfo.n_bios_used); 383255932Salfred } 384255932Salfred} 385255932Salfred 386255932Salfred 387255932Salfredstruct cpu_nameclass i386_cpus[] = { 388255932Salfred { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */ 389255932Salfred { "i386SX", CPUCLASS_386 }, /* CPU_386SX */ 390255932Salfred { "i386DX", CPUCLASS_386 }, /* CPU_386 */ 391255932Salfred { "i486SX", CPUCLASS_486 }, /* CPU_486SX */ 392255932Salfred { "i486DX", CPUCLASS_486 }, /* CPU_486 */ 393255932Salfred { "Pentium", CPUCLASS_586 }, /* CPU_586 */ 394255932Salfred { "Cy486DLC", CPUCLASS_486 }, /* CPU_486DLC */ 395255932Salfred}; 396255932Salfred 397219820Sjeffstatic void 398219820Sjeffidentifycpu() 399219820Sjeff{ 400219820Sjeff extern u_long cpu_id; 401219820Sjeff extern char cpu_vendor[]; 402219820Sjeff printf("CPU: "); 403219820Sjeff if (cpu >= 0 404219820Sjeff && cpu < (sizeof i386_cpus/sizeof(struct cpu_nameclass))) { 405219820Sjeff printf("%s", i386_cpus[cpu].cpu_name); 406219820Sjeff cpu_class = i386_cpus[cpu].cpu_class; 407219820Sjeff strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model); 408219820Sjeff } else { 409219820Sjeff printf("unknown cpu type %d\n", cpu); 410219820Sjeff panic("startup: bad cpu id"); 411219820Sjeff } 412219820Sjeff printf(" ("); 413219820Sjeff switch(cpu_class) { 414219820Sjeff case CPUCLASS_286: 415219820Sjeff printf("286"); 416219820Sjeff break; 417219820Sjeff case CPUCLASS_386: 418219820Sjeff printf("386"); 419219820Sjeff break; 420219820Sjeff case CPUCLASS_486: 421219820Sjeff printf("486"); 422219820Sjeff break; 423219820Sjeff case CPUCLASS_586: 424219820Sjeff printf("Pentium"); 425219820Sjeff break; 426219820Sjeff default: 427219820Sjeff printf("unknown"); /* will panic below... */ 428219820Sjeff } 429219820Sjeff printf("-class CPU)"); 430219820Sjeff#ifdef I586_CPU 431219820Sjeff if(cpu_class == CPUCLASS_586) { 432219820Sjeff calibrate_cyclecounter(); 433219820Sjeff printf(" %d MHz", pentium_mhz); 434219820Sjeff } 435219820Sjeff#endif 436219820Sjeff if(cpu_id) 437219820Sjeff printf(" Id = 0x%lx",cpu_id); 438219820Sjeff if(*cpu_vendor) 439219820Sjeff printf(" Origin = \"%s\"",cpu_vendor); 440219820Sjeff printf("\n"); /* cpu speed would be nice, but how? */ 441219820Sjeff 442219820Sjeff /* 443219820Sjeff * Now that we have told the user what they have, 444219820Sjeff * let them know if that machine type isn't configured. 445219820Sjeff */ 446219820Sjeff switch (cpu_class) { 447219820Sjeff case CPUCLASS_286: /* a 286 should not make it this far, anyway */ 448219820Sjeff#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) 449219820Sjeff#error This kernel is not configured for one of the supported CPUs 450219820Sjeff#endif 451219820Sjeff#if !defined(I386_CPU) 452219820Sjeff case CPUCLASS_386: 453219820Sjeff#endif 454219820Sjeff#if !defined(I486_CPU) 455219820Sjeff case CPUCLASS_486: 456219820Sjeff#endif 457219820Sjeff#if !defined(I586_CPU) 458219820Sjeff case CPUCLASS_586: 459219820Sjeff#endif 460219820Sjeff panic("CPU class not configured"); 461219820Sjeff default: 462219820Sjeff break; 463219820Sjeff } 464219820Sjeff} 465219820Sjeff 466219820Sjeff#ifdef PGINPROF 467219820Sjeff/* 468219820Sjeff * Return the difference (in microseconds) 469219820Sjeff * between the current time and a previous 470219820Sjeff * time as represented by the arguments. 471219820Sjeff * If there is a pending clock interrupt 472219820Sjeff * which has not been serviced due to high 473219820Sjeff * ipl, return error code. 474219820Sjeff */ 475219820Sjeff/*ARGSUSED*/ 476219820Sjeffvmtime(otime, olbolt, oicr) 477219820Sjeff register int otime, olbolt, oicr; 478219820Sjeff{ 479219820Sjeff 480219820Sjeff return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667); 481219820Sjeff} 482219820Sjeff#endif 483219820Sjeff 484219820Sjeffextern int kstack[]; 485219820Sjeff 486219820Sjeff/* 487219820Sjeff * Send an interrupt to process. 488219820Sjeff * 489219820Sjeff * Stack is set up to allow sigcode stored 490219820Sjeff * in u. to call routine, followed by kcall 491219820Sjeff * to sigreturn routine below. After sigreturn 492219820Sjeff * resets the signal mask, the stack, and the 493219820Sjeff * frame pointer, it returns to the user 494219820Sjeff * specified pc, psl. 495219820Sjeff */ 496219820Sjeffvoid 497219820Sjeffsendsig(catcher, sig, mask, code) 498219820Sjeff sig_t catcher; 499219820Sjeff int sig, mask; 500219820Sjeff unsigned code; 501219820Sjeff{ 502219820Sjeff register struct proc *p = curproc; 503219820Sjeff register int *regs; 504219820Sjeff register struct sigframe *fp; 505219820Sjeff struct sigacts *psp = p->p_sigacts; 506219820Sjeff int oonstack; 507219820Sjeff 508219820Sjeff regs = p->p_md.md_regs; 509219820Sjeff oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; 510219820Sjeff /* 511219820Sjeff * Allocate and validate space for the signal handler 512219820Sjeff * context. Note that if the stack is in P0 space, the 513219820Sjeff * call to grow() is a nop, and the useracc() check 514219820Sjeff * will fail if the process has not already allocated 515219820Sjeff * the space with a `brk'. 516219820Sjeff */ 517219820Sjeff if ((psp->ps_flags & SAS_ALTSTACK) && 518219820Sjeff (psp->ps_sigstk.ss_flags & SA_ONSTACK) == 0 && 519219820Sjeff (psp->ps_sigonstack & sigmask(sig))) { 520219820Sjeff fp = (struct sigframe *)(psp->ps_sigstk.ss_base + 521219820Sjeff psp->ps_sigstk.ss_size - sizeof(struct sigframe)); 522219820Sjeff psp->ps_sigstk.ss_flags |= SA_ONSTACK; 523219820Sjeff } else { 524219820Sjeff fp = (struct sigframe *)(regs[tESP] 525219820Sjeff - sizeof(struct sigframe)); 526219820Sjeff } 527219820Sjeff 528219820Sjeff /* 529219820Sjeff * grow() will return FALSE if the fp will not fit inside the stack 530219820Sjeff * and the stack can not be grown. useracc will return FALSE 531219820Sjeff * if access is denied. 532219820Sjeff */ 533219820Sjeff if ((grow(p, (int)fp) == FALSE) || 534219820Sjeff (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == FALSE)) { 535219820Sjeff /* 536219820Sjeff * Process has trashed its stack; give it an illegal 537219820Sjeff * instruction to halt it in its tracks. 538219820Sjeff */ 539219820Sjeff SIGACTION(p, SIGILL) = SIG_DFL; 540219820Sjeff sig = sigmask(SIGILL); 541219820Sjeff p->p_sigignore &= ~sig; 542219820Sjeff p->p_sigcatch &= ~sig; 543219820Sjeff p->p_sigmask &= ~sig; 544219820Sjeff psignal(p, SIGILL); 545219820Sjeff return; 546219820Sjeff } 547219820Sjeff 548219820Sjeff /* 549219820Sjeff * Build the argument list for the signal handler. 550219820Sjeff */ 551219820Sjeff if (p->p_sysent->sv_sigtbl) { 552219820Sjeff if (sig < p->p_sysent->sv_sigsize) 553219820Sjeff sig = p->p_sysent->sv_sigtbl[sig]; 554219820Sjeff else 555219820Sjeff sig = p->p_sysent->sv_sigsize + 1; 556219820Sjeff } 557219820Sjeff fp->sf_signum = sig; 558219820Sjeff fp->sf_code = code; 559219820Sjeff fp->sf_scp = &fp->sf_sc; 560219820Sjeff fp->sf_addr = (char *) regs[tERR]; 561219820Sjeff fp->sf_handler = catcher; 562219820Sjeff 563219820Sjeff /* save scratch registers */ 564219820Sjeff fp->sf_sc.sc_eax = regs[tEAX]; 565219820Sjeff fp->sf_sc.sc_ebx = regs[tEBX]; 566219820Sjeff fp->sf_sc.sc_ecx = regs[tECX]; 567219820Sjeff fp->sf_sc.sc_edx = regs[tEDX]; 568219820Sjeff fp->sf_sc.sc_esi = regs[tESI]; 569219820Sjeff fp->sf_sc.sc_edi = regs[tEDI]; 570219820Sjeff fp->sf_sc.sc_cs = regs[tCS]; 571219820Sjeff fp->sf_sc.sc_ds = regs[tDS]; 572219820Sjeff fp->sf_sc.sc_ss = regs[tSS]; 573219820Sjeff fp->sf_sc.sc_es = regs[tES]; 574219820Sjeff fp->sf_sc.sc_isp = regs[tISP]; 575219820Sjeff 576219820Sjeff /* 577219820Sjeff * Build the signal context to be used by sigreturn. 578219820Sjeff */ 579219820Sjeff fp->sf_sc.sc_onstack = oonstack; 580219820Sjeff fp->sf_sc.sc_mask = mask; 581255932Salfred fp->sf_sc.sc_sp = regs[tESP]; 582255932Salfred fp->sf_sc.sc_fp = regs[tEBP]; 583255932Salfred fp->sf_sc.sc_pc = regs[tEIP]; 584255932Salfred fp->sf_sc.sc_ps = regs[tEFLAGS]; 585255932Salfred regs[tESP] = (int)fp; 586255932Salfred regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc; 587255932Salfred regs[tEFLAGS] &= ~PSL_VM; 588255932Salfred regs[tCS] = _ucodesel; 589255932Salfred regs[tDS] = _udatasel; 590255932Salfred regs[tES] = _udatasel; 591255932Salfred regs[tSS] = _udatasel; 592255932Salfred} 593219820Sjeff 594/* 595 * System call to cleanup state after a signal 596 * has been taken. Reset signal mask and 597 * stack state from context left by sendsig (above). 598 * Return to previous pc and psl as specified by 599 * context left by sendsig. Check carefully to 600 * make sure that the user has not modified the 601 * psl to gain improper privileges or to cause 602 * a machine fault. 603 */ 604struct sigreturn_args { 605 struct sigcontext *sigcntxp; 606}; 607 608int 609sigreturn(p, uap, retval) 610 struct proc *p; 611 struct sigreturn_args *uap; 612 int *retval; 613{ 614 register struct sigcontext *scp; 615 register struct sigframe *fp; 616 register int *regs = p->p_md.md_regs; 617 int eflags; 618 619 /* 620 * (XXX old comment) regs[tESP] points to the return address. 621 * The user scp pointer is above that. 622 * The return address is faked in the signal trampoline code 623 * for consistency. 624 */ 625 scp = uap->sigcntxp; 626 fp = (struct sigframe *) 627 ((caddr_t)scp - offsetof(struct sigframe, sf_sc)); 628 629 if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) 630 return(EINVAL); 631 632 eflags = scp->sc_ps; 633 if ((eflags & PSL_USERCLR) != 0 || 634 (eflags & PSL_USERSET) != PSL_USERSET || 635 (eflags & PSL_IOPL) < (regs[tEFLAGS] & PSL_IOPL)) { 636#ifdef DEBUG 637 printf("sigreturn: eflags=0x%x\n", eflags); 638#endif 639 return(EINVAL); 640 } 641 642 /* 643 * Sanity check the user's selectors and error if they 644 * are suspect. 645 */ 646#define max_ldt_sel(pcb) \ 647 ((pcb)->pcb_ldt ? (pcb)->pcb_ldt_len : (sizeof(ldt) / sizeof(ldt[0]))) 648 649#define valid_ldt_sel(sel) \ 650 (ISLDT(sel) && ISPL(sel) == SEL_UPL && \ 651 IDXSEL(sel) < max_ldt_sel(&p->p_addr->u_pcb)) 652 653#define null_sel(sel) \ 654 (!ISLDT(sel) && IDXSEL(sel) == 0) 655 656 if (((scp->sc_cs&0xffff) != _ucodesel && !valid_ldt_sel(scp->sc_cs)) || 657 ((scp->sc_ss&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ss)) || 658 ((scp->sc_ds&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ds) && 659 !null_sel(scp->sc_ds)) || 660 ((scp->sc_es&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_es) && 661 !null_sel(scp->sc_es))) { 662#ifdef DEBUG 663 printf("sigreturn: cs=0x%x ss=0x%x ds=0x%x es=0x%x\n", 664 scp->sc_cs, scp->sc_ss, scp->sc_ds, scp->sc_es); 665#endif 666 trapsignal(p, SIGBUS, T_PROTFLT); 667 return(EINVAL); 668 } 669 670#undef max_ldt_sel 671#undef valid_ldt_sel 672#undef null_sel 673 674 /* restore scratch registers */ 675 regs[tEAX] = scp->sc_eax; 676 regs[tEBX] = scp->sc_ebx; 677 regs[tECX] = scp->sc_ecx; 678 regs[tEDX] = scp->sc_edx; 679 regs[tESI] = scp->sc_esi; 680 regs[tEDI] = scp->sc_edi; 681 regs[tCS] = scp->sc_cs; 682 regs[tDS] = scp->sc_ds; 683 regs[tES] = scp->sc_es; 684 regs[tSS] = scp->sc_ss; 685 regs[tISP] = scp->sc_isp; 686 687 if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0) 688 return(EINVAL); 689 690 if (scp->sc_onstack & 01) 691 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; 692 else 693 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; 694 p->p_sigmask = scp->sc_mask &~ 695 (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP)); 696 regs[tEBP] = scp->sc_fp; 697 regs[tESP] = scp->sc_sp; 698 regs[tEIP] = scp->sc_pc; 699 regs[tEFLAGS] = eflags; 700 return(EJUSTRETURN); 701} 702 703/* 704 * a simple function to make the system panic (and dump a vmcore) 705 * in a predictable fashion 706 */ 707void diediedie() 708{ 709 panic("because you said to!"); 710} 711 712int waittime = -1; 713struct pcb dumppcb; 714 715__dead void 716boot(arghowto) 717 int arghowto; 718{ 719 register long dummy; /* r12 is reserved */ 720 register int howto; /* r11 == how to boot */ 721 register int devtype; /* r10 == major of root dev */ 722 extern int cold; 723 724 if (cold) { 725 printf("hit reset please"); 726 for(;;); 727 } 728 howto = arghowto; 729 if ((howto&RB_NOSYNC) == 0 && waittime < 0) { 730 register struct buf *bp; 731 int iter, nbusy; 732 733 waittime = 0; 734 printf("\nsyncing disks... "); 735 /* 736 * Release inodes held by texts before update. 737 */ 738 if (panicstr == 0) 739 vnode_pager_umount(NULL); 740 sync(curproc, NULL, NULL); 741 742 for (iter = 0; iter < 20; iter++) { 743 nbusy = 0; 744 for (bp = &buf[nbuf]; --bp >= buf; ) 745 if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY) 746 nbusy++; 747 if (nbusy == 0) 748 break; 749 printf("%d ", nbusy); 750 DELAY(40000 * iter); 751 } 752 if (nbusy) { 753 /* 754 * Failed to sync all blocks. Indicate this and don't 755 * unmount filesystems (thus forcing an fsck on reboot). 756 */ 757 printf("giving up\n"); 758 } else { 759 printf("done\n"); 760 /* 761 * Unmount filesystems 762 */ 763 if (panicstr == 0) 764 vfs_unmountall(); 765 } 766 DELAY(100000); /* wait for console output to finish */ 767 } 768 splhigh(); 769 devtype = major(rootdev); 770 if (howto&RB_HALT) { 771 printf("\n"); 772 printf("The operating system has halted.\n"); 773 printf("Please press any key to reboot.\n\n"); 774 cngetc(); 775 } else { 776 if (howto & RB_DUMP) { 777 savectx(&dumppcb, 0); 778 dumppcb.pcb_ptd = rcr3(); 779 dumpsys(); 780 781 if (PANIC_REBOOT_WAIT_TIME != 0) { 782 if (PANIC_REBOOT_WAIT_TIME != -1) { 783 int loop; 784 printf("Automatic reboot in %d seconds - press a key on the console to abort\n", 785 PANIC_REBOOT_WAIT_TIME); 786 for (loop = PANIC_REBOOT_WAIT_TIME; loop > 0; --loop) { 787 DELAY(1000 * 1000); /* one second */ 788 if (cncheckc()) /* Did user type a key? */ 789 break; 790 } 791 if (!loop) 792 goto die; 793 } 794 } else { /* zero time specified - reboot NOW */ 795 goto die; 796 } 797 printf("--> Press a key on the console to reboot <--\n"); 798 cngetc(); 799 } 800 } 801#ifdef lint 802 dummy = 0; dummy = dummy; 803 printf("howto %d, devtype %d\n", arghowto, devtype); 804#endif 805die: 806 printf("Rebooting...\n"); 807 DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 808 cpu_reset(); 809 for(;;) ; 810 /* NOTREACHED */ 811} 812 813unsigned long dumpmag = 0x8fca0101UL; /* magic number for savecore */ 814int dumpsize = 0; /* also for savecore */ 815 816#ifdef DODUMP 817int dodump = 1; 818#else 819int dodump = 0; 820#endif 821/* 822 * Doadump comes here after turning off memory management and 823 * getting on the dump stack, either when called above, or by 824 * the auto-restart code. 825 */ 826void 827dumpsys() 828{ 829 830 if (!dodump) 831 return; 832 if (dumpdev == NODEV) 833 return; 834 if ((minor(dumpdev)&07) != 1) 835 return; 836 dumpsize = Maxmem; 837 printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo); 838 printf("dump "); 839 switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { 840 841 case ENXIO: 842 printf("device bad\n"); 843 break; 844 845 case EFAULT: 846 printf("device not ready\n"); 847 break; 848 849 case EINVAL: 850 printf("area improper\n"); 851 break; 852 853 case EIO: 854 printf("i/o error\n"); 855 break; 856 857 case EINTR: 858 printf("aborted from console\n"); 859 break; 860 861 default: 862 printf("succeeded\n"); 863 break; 864 } 865} 866 867static void 868initcpu() 869{ 870} 871 872/* 873 * Clear registers on exec 874 */ 875void 876setregs(p, entry, stack) 877 struct proc *p; 878 u_long entry; 879 u_long stack; 880{ 881 int *regs = p->p_md.md_regs; 882 883 bzero(regs, sizeof(struct trapframe)); 884 regs[tEIP] = entry; 885 regs[tESP] = stack; 886 regs[tEFLAGS] = PSL_USERSET | (regs[tEFLAGS] & PSL_T); 887 regs[tSS] = _udatasel; 888 regs[tDS] = _udatasel; 889 regs[tES] = _udatasel; 890 regs[tCS] = _ucodesel; 891 892 p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */ 893 load_cr0(rcr0() | CR0_TS); /* start emulating */ 894#if NNPX > 0 895 npxinit(__INITIAL_NPXCW__); 896#endif /* NNPX > 0 */ 897} 898 899/* 900 * machine dependent system variables. 901 */ 902int 903cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 904 int *name; 905 u_int namelen; 906 void *oldp; 907 size_t *oldlenp; 908 void *newp; 909 size_t newlen; 910 struct proc *p; 911{ 912 int error; 913 914 /* all sysctl names at this level are terminal */ 915 if (namelen != 1) 916 return (ENOTDIR); /* overloaded */ 917 918 switch (name[0]) { 919 case CPU_CONSDEV: 920 return (sysctl_rdstruct(oldp, oldlenp, newp, &cn_tty->t_dev, 921 sizeof cn_tty->t_dev)); 922 case CPU_ADJKERNTZ: 923 error = sysctl_int(oldp, oldlenp, newp, newlen, &adjkerntz); 924 if (!error && newp) 925 resettodr(); 926 return error; 927 case CPU_DISRTCSET: 928 return (sysctl_int(oldp, oldlenp, newp, newlen, &disable_rtc_set)); 929 default: 930 return (EOPNOTSUPP); 931 } 932 /* NOTREACHED */ 933} 934 935/* 936 * Initialize 386 and configure to run kernel 937 */ 938 939/* 940 * Initialize segments & interrupt table 941 */ 942 943int currentldt; 944int _default_ldt; 945union descriptor gdt[NGDT]; /* global descriptor table */ 946struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */ 947union descriptor ldt[NLDT]; /* local descriptor table */ 948 949struct i386tss tss, panic_tss; 950 951extern struct user *proc0paddr; 952 953/* software prototypes -- in more palatable form */ 954struct soft_segment_descriptor gdt_segs[] = { 955/* GNULL_SEL 0 Null Descriptor */ 956{ 0x0, /* segment base address */ 957 0x0, /* length */ 958 0, /* segment type */ 959 0, /* segment descriptor priority level */ 960 0, /* segment descriptor present */ 961 0, 0, 962 0, /* default 32 vs 16 bit size */ 963 0 /* limit granularity (byte/page units)*/ }, 964/* GCODE_SEL 1 Code Descriptor for kernel */ 965{ 0x0, /* segment base address */ 966 0xfffff, /* length - all address space */ 967 SDT_MEMERA, /* segment type */ 968 0, /* segment descriptor priority level */ 969 1, /* segment descriptor present */ 970 0, 0, 971 1, /* default 32 vs 16 bit size */ 972 1 /* limit granularity (byte/page units)*/ }, 973/* GDATA_SEL 2 Data Descriptor for kernel */ 974{ 0x0, /* segment base address */ 975 0xfffff, /* length - all address space */ 976 SDT_MEMRWA, /* segment type */ 977 0, /* segment descriptor priority level */ 978 1, /* segment descriptor present */ 979 0, 0, 980 1, /* default 32 vs 16 bit size */ 981 1 /* limit granularity (byte/page units)*/ }, 982/* GLDT_SEL 3 LDT Descriptor */ 983{ (int) ldt, /* segment base address */ 984 sizeof(ldt)-1, /* length - all address space */ 985 SDT_SYSLDT, /* segment type */ 986 0, /* segment descriptor priority level */ 987 1, /* segment descriptor present */ 988 0, 0, 989 0, /* unused - default 32 vs 16 bit size */ 990 0 /* limit granularity (byte/page units)*/ }, 991/* GTGATE_SEL 4 Null Descriptor - Placeholder */ 992{ 0x0, /* segment base address */ 993 0x0, /* length - all address space */ 994 0, /* segment type */ 995 0, /* segment descriptor priority level */ 996 0, /* segment descriptor present */ 997 0, 0, 998 0, /* default 32 vs 16 bit size */ 999 0 /* limit granularity (byte/page units)*/ }, 1000/* GPANIC_SEL 5 Panic Tss Descriptor */ 1001{ (int) &panic_tss, /* segment base address */ 1002 sizeof(tss)-1, /* length - all address space */ 1003 SDT_SYS386TSS, /* segment type */ 1004 0, /* segment descriptor priority level */ 1005 1, /* segment descriptor present */ 1006 0, 0, 1007 0, /* unused - default 32 vs 16 bit size */ 1008 0 /* limit granularity (byte/page units)*/ }, 1009/* GPROC0_SEL 6 Proc 0 Tss Descriptor */ 1010{ (int) kstack, /* segment base address */ 1011 sizeof(tss)-1, /* length - all address space */ 1012 SDT_SYS386TSS, /* segment type */ 1013 0, /* segment descriptor priority level */ 1014 1, /* segment descriptor present */ 1015 0, 0, 1016 0, /* unused - default 32 vs 16 bit size */ 1017 0 /* limit granularity (byte/page units)*/ }, 1018/* GUSERLDT_SEL 7 User LDT Descriptor per process */ 1019{ (int) ldt, /* segment base address */ 1020 (512 * sizeof(union descriptor)-1), /* length */ 1021 SDT_SYSLDT, /* segment type */ 1022 0, /* segment descriptor priority level */ 1023 1, /* segment descriptor present */ 1024 0, 0, 1025 0, /* unused - default 32 vs 16 bit size */ 1026 0 /* limit granularity (byte/page units)*/ }, 1027/* GAPMCODE32_SEL 8 APM BIOS 32-bit interface (32bit Code) */ 1028{ 0, /* segment base address (overwritten by APM) */ 1029 0xfffff, /* length */ 1030 SDT_MEMERA, /* segment type */ 1031 0, /* segment descriptor priority level */ 1032 1, /* segment descriptor present */ 1033 0, 0, 1034 1, /* default 32 vs 16 bit size */ 1035 1 /* limit granularity (byte/page units)*/ }, 1036/* GAPMCODE16_SEL 9 APM BIOS 32-bit interface (16bit Code) */ 1037{ 0, /* segment base address (overwritten by APM) */ 1038 0xfffff, /* length */ 1039 SDT_MEMERA, /* segment type */ 1040 0, /* segment descriptor priority level */ 1041 1, /* segment descriptor present */ 1042 0, 0, 1043 0, /* default 32 vs 16 bit size */ 1044 1 /* limit granularity (byte/page units)*/ }, 1045/* GAPMDATA_SEL 10 APM BIOS 32-bit interface (Data) */ 1046{ 0, /* segment base address (overwritten by APM) */ 1047 0xfffff, /* length */ 1048 SDT_MEMRWA, /* segment type */ 1049 0, /* segment descriptor priority level */ 1050 1, /* segment descriptor present */ 1051 0, 0, 1052 1, /* default 32 vs 16 bit size */ 1053 1 /* limit granularity (byte/page units)*/ }, 1054}; 1055 1056struct soft_segment_descriptor ldt_segs[] = { 1057 /* Null Descriptor - overwritten by call gate */ 1058{ 0x0, /* segment base address */ 1059 0x0, /* length - all address space */ 1060 0, /* segment type */ 1061 0, /* segment descriptor priority level */ 1062 0, /* segment descriptor present */ 1063 0, 0, 1064 0, /* default 32 vs 16 bit size */ 1065 0 /* limit granularity (byte/page units)*/ }, 1066 /* Null Descriptor - overwritten by call gate */ 1067{ 0x0, /* segment base address */ 1068 0x0, /* length - all address space */ 1069 0, /* segment type */ 1070 0, /* segment descriptor priority level */ 1071 0, /* segment descriptor present */ 1072 0, 0, 1073 0, /* default 32 vs 16 bit size */ 1074 0 /* limit granularity (byte/page units)*/ }, 1075 /* Null Descriptor - overwritten by call gate */ 1076{ 0x0, /* segment base address */ 1077 0x0, /* length - all address space */ 1078 0, /* segment type */ 1079 0, /* segment descriptor priority level */ 1080 0, /* segment descriptor present */ 1081 0, 0, 1082 0, /* default 32 vs 16 bit size */ 1083 0 /* limit granularity (byte/page units)*/ }, 1084 /* Code Descriptor for user */ 1085{ 0x0, /* segment base address */ 1086 0xfffff, /* length - all address space */ 1087 SDT_MEMERA, /* segment type */ 1088 SEL_UPL, /* segment descriptor priority level */ 1089 1, /* segment descriptor present */ 1090 0, 0, 1091 1, /* default 32 vs 16 bit size */ 1092 1 /* limit granularity (byte/page units)*/ }, 1093 /* Data Descriptor for user */ 1094{ 0x0, /* segment base address */ 1095 0xfffff, /* length - all address space */ 1096 SDT_MEMRWA, /* segment type */ 1097 SEL_UPL, /* segment descriptor priority level */ 1098 1, /* segment descriptor present */ 1099 0, 0, 1100 1, /* default 32 vs 16 bit size */ 1101 1 /* limit granularity (byte/page units)*/ }, 1102}; 1103 1104void 1105setidt(idx, func, typ, dpl) 1106 int idx; 1107 inthand_t *func; 1108 int typ; 1109 int dpl; 1110{ 1111 struct gate_descriptor *ip = idt + idx; 1112 1113 ip->gd_looffset = (int)func; 1114 ip->gd_selector = 8; 1115 ip->gd_stkcpy = 0; 1116 ip->gd_xx = 0; 1117 ip->gd_type = typ; 1118 ip->gd_dpl = dpl; 1119 ip->gd_p = 1; 1120 ip->gd_hioffset = ((int)func)>>16 ; 1121} 1122 1123#define IDTVEC(name) __CONCAT(X,name) 1124 1125extern inthand_t 1126 IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), 1127 IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm), 1128 IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), 1129 IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0), 1130 IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4), 1131 IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8), 1132 IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12), 1133 IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(syscall); 1134 1135void 1136sdtossd(sd, ssd) 1137 struct segment_descriptor *sd; 1138 struct soft_segment_descriptor *ssd; 1139{ 1140 ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; 1141 ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; 1142 ssd->ssd_type = sd->sd_type; 1143 ssd->ssd_dpl = sd->sd_dpl; 1144 ssd->ssd_p = sd->sd_p; 1145 ssd->ssd_def32 = sd->sd_def32; 1146 ssd->ssd_gran = sd->sd_gran; 1147} 1148 1149void 1150init386(first) 1151 int first; 1152{ 1153 extern char etext[]; 1154 int x; 1155 unsigned biosbasemem, biosextmem; 1156 struct gate_descriptor *gdp; 1157 int gsel_tss; 1158 extern int sigcode,szsigcode; 1159 /* table descriptors - used to load tables by microp */ 1160 struct region_descriptor r_gdt, r_idt; 1161 int pagesinbase, pagesinext; 1162 int target_page; 1163 extern struct pte *CMAP1; 1164 extern caddr_t CADDR1; 1165 1166 proc0.p_addr = proc0paddr; 1167 1168 /* 1169 * Initialize the console before we print anything out. 1170 */ 1171 1172 cninit (); 1173 1174 /* 1175 * make gdt memory segments, the code segment goes up to end of the 1176 * page with etext in it, the data segment goes to the end of 1177 * the address space 1178 */ 1179 /* 1180 * XXX text protection is temporarily (?) disabled. The limit was 1181 * i386_btop(i386_round_page(etext)) - 1. 1182 */ 1183 gdt_segs[GCODE_SEL].ssd_limit = i386_btop(0) - 1; 1184 gdt_segs[GDATA_SEL].ssd_limit = i386_btop(0) - 1; 1185 for (x = 0; x < NGDT; x++) 1186 ssdtosd(&gdt_segs[x], &gdt[x].sd); 1187 1188 /* make ldt memory segments */ 1189 /* 1190 * The data segment limit must not cover the user area because we 1191 * don't want the user area to be writable in copyout() etc. (page 1192 * level protection is lost in kernel mode on 386's). Also, we 1193 * don't want the user area to be writable directly (page level 1194 * protection of the user area is not available on 486's with 1195 * CR0_WP set, because there is no user-read/kernel-write mode). 1196 * 1197 * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it 1198 * should be spelled ...MAX_USER... 1199 */ 1200#define VM_END_USER_RW_ADDRESS VM_MAXUSER_ADDRESS 1201 /* 1202 * The code segment limit has to cover the user area until we move 1203 * the signal trampoline out of the user area. This is safe because 1204 * the code segment cannot be written to directly. 1205 */ 1206#define VM_END_USER_R_ADDRESS (VM_END_USER_RW_ADDRESS + UPAGES * NBPG) 1207 ldt_segs[LUCODE_SEL].ssd_limit = i386_btop(VM_END_USER_R_ADDRESS) - 1; 1208 ldt_segs[LUDATA_SEL].ssd_limit = i386_btop(VM_END_USER_RW_ADDRESS) - 1; 1209 /* Note. eventually want private ldts per process */ 1210 for (x = 0; x < NLDT; x++) 1211 ssdtosd(&ldt_segs[x], &ldt[x].sd); 1212 1213 /* exceptions */ 1214 setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL); 1215 setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL); 1216 setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL); 1217 setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL); 1218 setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL); 1219 setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL); 1220 setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL); 1221 setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL); 1222 setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL); 1223 setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL); 1224 setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL); 1225 setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL); 1226 setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL); 1227 setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL); 1228 setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL); 1229 setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); 1230 setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL); 1231 setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL); 1232 setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL); 1233 setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL); 1234 setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL); 1235 setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL); 1236 setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL); 1237 setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL); 1238 setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL); 1239 setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL); 1240 setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL); 1241 setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL); 1242 setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL); 1243 setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL); 1244 setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL); 1245 setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL); 1246 1247#include "isa.h" 1248#if NISA >0 1249 isa_defaultirq(); 1250#endif 1251 1252 r_gdt.rd_limit = sizeof(gdt) - 1; 1253 r_gdt.rd_base = (int) gdt; 1254 lgdt(&r_gdt); 1255 1256 r_idt.rd_limit = sizeof(idt) - 1; 1257 r_idt.rd_base = (int) idt; 1258 lidt(&r_idt); 1259 1260 _default_ldt = GSEL(GLDT_SEL, SEL_KPL); 1261 lldt(_default_ldt); 1262 currentldt = _default_ldt; 1263 1264#ifdef DDB 1265 kdb_init(); 1266 if (boothowto & RB_KDB) 1267 Debugger("Boot flags requested debugger"); 1268#endif 1269 1270 /* Use BIOS values stored in RTC CMOS RAM, since probing 1271 * breaks certain 386 AT relics. 1272 */ 1273 biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8); 1274 biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8); 1275 1276 /* 1277 * If BIOS tells us that it has more than 640k in the basemem, 1278 * don't believe it - set it to 640k. 1279 */ 1280 if (biosbasemem > 640) 1281 biosbasemem = 640; 1282 1283 /* 1284 * Some 386 machines might give us a bogus number for extended 1285 * mem. If this happens, stop now. 1286 */ 1287#ifndef LARGEMEM 1288 if (biosextmem > 65536) { 1289 panic("extended memory beyond limit of 64MB"); 1290 /* NOTREACHED */ 1291 } 1292#endif 1293 1294 pagesinbase = biosbasemem * 1024 / NBPG; 1295 pagesinext = biosextmem * 1024 / NBPG; 1296 1297 /* 1298 * Special hack for chipsets that still remap the 384k hole when 1299 * there's 16MB of memory - this really confuses people that 1300 * are trying to use bus mastering ISA controllers with the 1301 * "16MB limit"; they only have 16MB, but the remapping puts 1302 * them beyond the limit. 1303 * XXX - this should be removed when bounce buffers are 1304 * implemented. 1305 */ 1306 /* 1307 * If extended memory is between 15-16MB (16-17MB phys address range), 1308 * chop it to 15MB. 1309 */ 1310 if ((pagesinext > 3840) && (pagesinext < 4096)) 1311 pagesinext = 3840; 1312 1313 /* 1314 * Maxmem isn't the "maximum memory", it's one larger than the 1315 * highest page of of the physical address space. It should be 1316 * called something like "Maxphyspage". 1317 */ 1318 Maxmem = pagesinext + 0x100000/PAGE_SIZE; 1319 1320#ifdef MAXMEM 1321 Maxmem = MAXMEM/4; 1322#endif 1323 /* 1324 * Calculate number of physical pages, but account for Maxmem 1325 * adjustment above. 1326 */ 1327 physmem = pagesinbase + Maxmem - 0x100000/PAGE_SIZE; 1328 1329 /* call pmap initialization to make new kernel address space */ 1330 pmap_bootstrap (first, 0); 1331 1332 /* 1333 * Do simple memory test over range of extended memory that BIOS 1334 * indicates exists. Adjust Maxmem to the highest page of 1335 * good memory. 1336 */ 1337 printf("Testing memory (%dMB)...", ptoa(Maxmem)/1024/1024); 1338 1339 for (target_page = Maxmem - 2; target_page >= atop(first); target_page--) { 1340 1341 /* 1342 * map page into kernel: valid, read/write, non-cacheable 1343 */ 1344 *(int *)CMAP1 = PG_V | PG_KW | PG_N | ptoa(target_page); 1345 pmap_update(); 1346 1347 /* 1348 * Test for alternating 1's and 0's 1349 */ 1350 filli(0xaaaaaaaa, CADDR1, PAGE_SIZE/sizeof(int)); 1351 if (test_page((int *)CADDR1, 0xaaaaaaaa)) { 1352 Maxmem = target_page; 1353 badpages++; 1354 continue; 1355 } 1356 /* 1357 * Test for alternating 0's and 1's 1358 */ 1359 filli(0x55555555, CADDR1, PAGE_SIZE/sizeof(int)); 1360 if (test_page((int *)CADDR1, 0x55555555)) { 1361 Maxmem = target_page; 1362 badpages++; 1363 continue; 1364 } 1365 /* 1366 * Test for all 1's 1367 */ 1368 filli(0xffffffff, CADDR1, PAGE_SIZE/sizeof(int)); 1369 if (test_page((int *)CADDR1, 0xffffffff)) { 1370 Maxmem = target_page; 1371 badpages++; 1372 continue; 1373 } 1374 /* 1375 * Test zeroing of page 1376 */ 1377 bzero(CADDR1, PAGE_SIZE); 1378 if (test_page((int *)CADDR1, 0)) { 1379 /* 1380 * test of page failed 1381 */ 1382 Maxmem = target_page; 1383 badpages++; 1384 continue; 1385 } 1386 } 1387 printf("done.\n"); 1388 1389 *(int *)CMAP1 = 0; 1390 pmap_update(); 1391 1392 avail_end = (Maxmem << PAGE_SHIFT) 1393 - i386_round_page(sizeof(struct msgbuf)); 1394 1395 /* 1396 * Initialize pointers to the two chunks of memory; for use 1397 * later in vm_page_startup. 1398 */ 1399 /* avail_start is initialized in pmap_bootstrap */ 1400 x = 0; 1401 if (pagesinbase > 1) { 1402 phys_avail[x++] = NBPG; /* skip first page of memory */ 1403 phys_avail[x++] = pagesinbase * NBPG; /* memory up to the ISA hole */ 1404 } 1405 phys_avail[x++] = avail_start; /* memory up to the end */ 1406 phys_avail[x++] = avail_end; 1407 phys_avail[x++] = 0; /* no more chunks */ 1408 phys_avail[x++] = 0; 1409 1410 /* now running on new page tables, configured,and u/iom is accessible */ 1411 1412 /* make a initial tss so microp can get interrupt stack on syscall! */ 1413 proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG; 1414 proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; 1415 gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); 1416 1417 ((struct i386tss *)gdt_segs[GPROC0_SEL].ssd_base)->tss_ioopt = 1418 (sizeof(tss))<<16; 1419 1420 ltr(gsel_tss); 1421 1422 /* make a call gate to reenter kernel with */ 1423 gdp = &ldt[LSYS5CALLS_SEL].gd; 1424 1425 x = (int) &IDTVEC(syscall); 1426 gdp->gd_looffset = x++; 1427 gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); 1428 gdp->gd_stkcpy = 1; 1429 gdp->gd_type = SDT_SYS386CGT; 1430 gdp->gd_dpl = SEL_UPL; 1431 gdp->gd_p = 1; 1432 gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16; 1433 1434 /* transfer to user mode */ 1435 1436 _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); 1437 _udatasel = LSEL(LUDATA_SEL, SEL_UPL); 1438 1439 /* setup proc 0's pcb */ 1440 bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode); 1441 proc0.p_addr->u_pcb.pcb_flags = 0; 1442 proc0.p_addr->u_pcb.pcb_ptd = IdlePTD; 1443} 1444 1445int 1446test_page(address, pattern) 1447 int *address; 1448 int pattern; 1449{ 1450 int *x; 1451 1452 for (x = address; x < (int *)((char *)address + PAGE_SIZE); x++) { 1453 if (*x != pattern) 1454 return (1); 1455 } 1456 return(0); 1457} 1458 1459/* 1460 * The registers are in the frame; the frame is in the user area of 1461 * the process in question; when the process is active, the registers 1462 * are in "the kernel stack"; when it's not, they're still there, but 1463 * things get flipped around. So, since p->p_md.md_regs is the whole address 1464 * of the register set, take its offset from the kernel stack, and 1465 * index into the user block. Don't you just *love* virtual memory? 1466 * (I'm starting to think seymour is right...) 1467 */ 1468 1469int 1470ptrace_set_pc (struct proc *p, unsigned int addr) { 1471 void *regs = (char*)p->p_addr + 1472 ((char*) p->p_md.md_regs - (char*) kstack); 1473 1474 ((struct trapframe *)regs)->tf_eip = addr; 1475 return 0; 1476} 1477 1478int 1479ptrace_single_step (struct proc *p) { 1480 void *regs = (char*)p->p_addr + 1481 ((char*) p->p_md.md_regs - (char*) kstack); 1482 1483 ((struct trapframe *)regs)->tf_eflags |= PSL_T; 1484 return 0; 1485} 1486 1487/* 1488 * Copy the registers to user-space. 1489 */ 1490 1491int 1492ptrace_getregs (struct proc *p, unsigned int *addr) { 1493 int error; 1494 struct reg regs = {0}; 1495 1496 error = fill_regs (p, ®s); 1497 if (error) 1498 return error; 1499 1500 return copyout (®s, addr, sizeof (regs)); 1501} 1502 1503int 1504ptrace_setregs (struct proc *p, unsigned int *addr) { 1505 int error; 1506 struct reg regs = {0}; 1507 1508 error = copyin (addr, ®s, sizeof(regs)); 1509 if (error) 1510 return error; 1511 1512 return set_regs (p, ®s); 1513} 1514 1515int 1516fill_regs(struct proc *p, struct reg *regs) { 1517 struct trapframe *tp; 1518 void *ptr = (char*)p->p_addr + 1519 ((char*) p->p_md.md_regs - (char*) kstack); 1520 1521 tp = ptr; 1522 regs->r_es = tp->tf_es; 1523 regs->r_ds = tp->tf_ds; 1524 regs->r_edi = tp->tf_edi; 1525 regs->r_esi = tp->tf_esi; 1526 regs->r_ebp = tp->tf_ebp; 1527 regs->r_ebx = tp->tf_ebx; 1528 regs->r_edx = tp->tf_edx; 1529 regs->r_ecx = tp->tf_ecx; 1530 regs->r_eax = tp->tf_eax; 1531 regs->r_eip = tp->tf_eip; 1532 regs->r_cs = tp->tf_cs; 1533 regs->r_eflags = tp->tf_eflags; 1534 regs->r_esp = tp->tf_esp; 1535 regs->r_ss = tp->tf_ss; 1536 return 0; 1537} 1538 1539int 1540set_regs (struct proc *p, struct reg *regs) { 1541 struct trapframe *tp; 1542 void *ptr = (char*)p->p_addr + 1543 ((char*) p->p_md.md_regs - (char*) kstack); 1544 1545 tp = ptr; 1546 tp->tf_es = regs->r_es; 1547 tp->tf_ds = regs->r_ds; 1548 tp->tf_edi = regs->r_edi; 1549 tp->tf_esi = regs->r_esi; 1550 tp->tf_ebp = regs->r_ebp; 1551 tp->tf_ebx = regs->r_ebx; 1552 tp->tf_edx = regs->r_edx; 1553 tp->tf_ecx = regs->r_ecx; 1554 tp->tf_eax = regs->r_eax; 1555 tp->tf_eip = regs->r_eip; 1556 tp->tf_cs = regs->r_cs; 1557 tp->tf_eflags = regs->r_eflags; 1558 tp->tf_esp = regs->r_esp; 1559 tp->tf_ss = regs->r_ss; 1560 return 0; 1561} 1562 1563#ifndef DDB 1564void 1565Debugger(const char *msg) 1566{ 1567 printf("Debugger(\"%s\") called.\n", msg); 1568} 1569#endif /* no DDB */ 1570 1571#include <sys/disklabel.h> 1572#define b_cylin b_resid 1573/* 1574 * Determine the size of the transfer, and make sure it is 1575 * within the boundaries of the partition. Adjust transfer 1576 * if needed, and signal errors or early completion. 1577 */ 1578int 1579bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel) 1580{ 1581 struct partition *p = lp->d_partitions + dkpart(bp->b_dev); 1582 int labelsect = lp->d_partitions[0].p_offset; 1583 int maxsz = p->p_size, 1584 sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 1585 1586 /* overwriting disk label ? */ 1587 /* XXX should also protect bootstrap in first 8K */ 1588 if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect && 1589#if LABELSECTOR != 0 1590 bp->b_blkno + p->p_offset + sz > LABELSECTOR + labelsect && 1591#endif 1592 (bp->b_flags & B_READ) == 0 && wlabel == 0) { 1593 bp->b_error = EROFS; 1594 goto bad; 1595 } 1596 1597#if defined(DOSBBSECTOR) && defined(notyet) 1598 /* overwriting master boot record? */ 1599 if (bp->b_blkno + p->p_offset <= DOSBBSECTOR && 1600 (bp->b_flags & B_READ) == 0 && wlabel == 0) { 1601 bp->b_error = EROFS; 1602 goto bad; 1603 } 1604#endif 1605 1606 /* beyond partition? */ 1607 if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { 1608 /* if exactly at end of disk, return an EOF */ 1609 if (bp->b_blkno == maxsz) { 1610 bp->b_resid = bp->b_bcount; 1611 return(0); 1612 } 1613 /* or truncate if part of it fits */ 1614 sz = maxsz - bp->b_blkno; 1615 if (sz <= 0) { 1616 bp->b_error = EINVAL; 1617 goto bad; 1618 } 1619 bp->b_bcount = sz << DEV_BSHIFT; 1620 } 1621 1622 /* calculate cylinder for disksort to order transfers with */ 1623 bp->b_pblkno = bp->b_blkno + p->p_offset; 1624 bp->b_cylin = bp->b_pblkno / lp->d_secpercyl; 1625 return(1); 1626 1627bad: 1628 bp->b_flags |= B_ERROR; 1629 return(-1); 1630} 1631 1632int 1633disk_externalize(int drive, void *userp, size_t *maxlen) 1634{ 1635 if(*maxlen < sizeof drive) { 1636 return ENOMEM; 1637 } 1638 1639 *maxlen -= sizeof drive; 1640 return copyout(&drive, userp, sizeof drive); 1641} 1642 1643