* The current strategy is to grab hold of 2MB chunks at a time as long * as they fit below 16MB, and as soon as that fail, give back the * last one and allocate the rest above 16MB.  That should guarantee * at least 2MB below 16MB left for DMA buffers. */
* The current strategy is to grab hold of one 3MB chunk below 16MB * first, which we are saving for DMA buffers, then try to get * one chunk at a time for fs buffers, until that is not possible * anymore, at which point we get the rest wherever we may find it. * After that we give our saved area back. That will guarantee at * least 3MB below 16MB left for drivers' attach routines, among * them isadma.  However we still have a potential problem of PCI * devices attached earlier snatching that memory.  This can be * solved by making the PCI DMA memory allocation routines go for * memory above 16MB first. */   TAILQ_INIT(&saved_pgs);
char *	intel686_cpu_name __P((int));#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)static __inline u_charcyrix_read_reg(u_char reg){	outb(0x22, reg);	return inb(0x23);}static __inline voidcyrix_write_reg(u_char reg, u_char data){	outb(0x22, reg);	outb(0x23, data);}#endif/* * Machine-dependent startup code */voidcpu_startup(){	unsigned i;	caddr_t v;	int sz;	vm_offset_t minaddr, maxaddr, pa;	struct pcb *pcb;	int x;	/*	 * Initialize error message buffer (at end of core).	 */	pa = avail_end;	/* avail_end was pre-decremented in pmap_bootstrap to compensate */	for (i = 0; i < btoc(sizeof(struct msgbuf)); i++, pa += NBPG)		pmap_enter(pmap_kernel(),		    (vm_offset_t)((caddr_t)msgbufp + i * NBPG), pa,		    VM_PROT_READ|VM_PROT_WRITE, TRUE,		    VM_PROT_READ|VM_PROT_WRITE);	msgbufmapped = 1;	/* Boot arguments are in page 1 */	if (bootapiver >= 2) {		pa = (vm_offset_t)bootargv;		for (i = 0; i < btoc(bootargc); i++, pa += NBPG)			pmap_enter(pmap_kernel(),			    (vm_offset_t)((caddr_t)bootargp + i * NBPG), pa,			    VM_PROT_READ|VM_PROT_WRITE, TRUE,			    VM_PROT_READ|VM_PROT_WRITE);	} else		bootargp = NULL;	printf(version);	startrtclock();		identifycpu();	printf("BIOS mem  = %ld conventional, %ld extended\n",		1024 * cnvmem, 1024 * extmem);	printf("real mem  = %d\n", ctob(physmem));	/*	 * Find out how much space we need, allocate it,	 * and then give everything true virtual addresses.	 */	sz = (int)allocsys((caddr_t)0);#if defined(UVM)	if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0)#else	if ((v = (caddr_t)kmem_alloc(kernel_map, round_page(sz))) == 0)#endif		panic("startup: no room for tables");	if (allocsys(v) - v != sz)		panic("startup: table size inconsistency");	/*	 * Now allocate buffers proper.  They are different than the above	 * in that they usually occupy more virtual memory than physical.	 */	setup_buffers(&maxaddr);	/*	 * Allocate a submap for exec arguments.  This map effectively	 * limits the number of processes exec'ing at any time.	 */#if defined(UVM)	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,				   16*NCARGS, TRUE, FALSE, NULL);#else	exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, 16*NCARGS,	    TRUE);#endif	/*	 * Allocate a submap for physio	 */#if defined(UVM)	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,				   VM_PHYS_SIZE, TRUE, FALSE, NULL);#else	phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, VM_PHYS_SIZE,	    TRUE);#endif	/*	 * Finally, allocate mbuf pool.  Since mclrefcnt is an off-size	 * we use the more space efficient malloc in place of kmem_alloc.	 */	mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, M_MBUF,	    M_NOWAIT);	bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);#if defined(UVM)	mb_map = uvm_km_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr,	    VM_MBUF_SIZE, FALSE, FALSE, NULL);#else	mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr,	    VM_MBUF_SIZE, FALSE);#endif	/*	 * Initialize callouts	 */	callfree = callout;	for (i = 1; i < ncallout; i++)		callout[i-1].c_next = &callout[i];#if defined(UVM)	printf("avail mem = %ld\n", ptoa(uvmexp.free));#else	printf("avail mem = %ld\n", ptoa(cnt.v_free_count));#endif	printf("using %d buffers containing %d bytes of memory\n",		nbuf, bufpages * CLBYTES);	/*	 * Set up buffers, so they can be used to read disk labels.	 */	bufinit();	/*	 * Configure the system.	 */	if (boothowto & RB_CONFIG) {#ifdef BOOT_CONFIG		user_config();#else		printf("kernel does not support -c; continuing..\n");#endif	}	ioport_malloc_safe = 1;	configure();	/*	 * Set up proc0's TSS and LDT.	 */	curpcb = pcb = &proc0.p_addr->u_pcb;	pcb->pcb_flags = 0;	pcb->pcb_tss.tss_ioopt =	    ((caddr_t)pcb->pcb_iomap - (caddr_t)&pcb->pcb_tss) << 16;	for (x = 0; x < sizeof(pcb->pcb_iomap) / 4; x++)		pcb->pcb_iomap[x] = 0xffffffff;	pcb->pcb_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);	pcb->pcb_cr0 = rcr0();	pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);	pcb->pcb_tss.tss_esp0 = (int)proc0.p_addr + USPACE - 16;	tss_alloc(pcb);	ltr(pcb->pcb_tss_sel);	lldt(pcb->pcb_ldt_sel);	proc0.p_md.md_regs = (struct trapframe *)pcb->pcb_tss.tss_esp0 - 1;}/* * Allocate space for system data structures.  We are given * a starting virtual address and we return a final virtual * address; along the way we set each data structure pointer. * * We call allocsys() with 0 to find out how much space we want, * allocate that much and fill it with zeroes, and then call * allocsys() again with the correct base virtual address. */caddr_tallocsys(v)	register caddr_t v;{#define	valloc(name, type, num) \	    v = (caddr_t)(((name) = (type *)v) + (num))#ifdef REAL_CLISTS	valloc(cfree, struct cblock, nclist);#endif	valloc(callout, struct callout, ncallout);#ifdef SYSVSHM	valloc(shmsegs, struct shmid_ds, shminfo.shmmni);#endif#ifdef SYSVSEM	valloc(sema, struct semid_ds, seminfo.semmni);	valloc(sem, struct sem, seminfo.semmns);	/* This is pretty disgusting! */	valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int));#endif#ifdef SYSVMSG	valloc(msgpool, char, msginfo.msgmax);	valloc(msgmaps, struct msgmap, msginfo.msgseg);	valloc(msghdrs, struct msg, msginfo.msgtql);	valloc(msqids, struct msqid_ds, msginfo.msgmni);#endif#ifndef BUFCACHEPERCENT#define BUFCACHEPERCENT 5#endif	/*	 * Determine how many buffers to allocate.  We use 10% of the	 * first 2MB of memory, and 5% of the rest, with a minimum of 16	 * buffers.  We allocate 1/2 as many swap buffer headers as file	 * i/o buffers.	 */	if (bufpages == 0) {		if (physmem < btoc(2 * 1024 * 1024))			bufpages = physmem / (10 * CLSIZE);		else			bufpages = (btoc(2 * 1024 * 1024) + physmem) /			    ((100/BUFCACHEPERCENT) * CLSIZE);	}	if (nbuf == 0) {		nbuf = bufpages;		if (nbuf < 16)			nbuf = 16;	}	/* Restrict to at most 70% filled kvm */	if (nbuf * MAXBSIZE >	    (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) * 7 / 10)		nbuf = (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) /		    MAXBSIZE * 7 / 10;	/* More buffer pages than fits into the buffers is senseless.  */	if (bufpages > nbuf * MAXBSIZE / CLBYTES)		bufpages = nbuf * MAXBSIZE / CLBYTES;	if (nswbuf == 0) {		nswbuf = (nbuf / 2) &~ 1;	/* force even */		if (nswbuf > 256)			nswbuf = 256;		/* sanity */	}#if !defined(UVM)	valloc(swbuf, struct buf, nswbuf);#endif	valloc(buf, struct buf, nbuf);	return v;}voidsetup_buffers(maxaddr)	vm_offset_t *maxaddr;{	vm_size_t size;	vm_offset_t addr;	int base, residual, left, i;	struct pglist pgs, freepgs;	vm_page_t pg, *last, *last2;	size = MAXBSIZE * nbuf;#if defined(UVM)	if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size),		    NULL, UVM_UNKNOWN_OFFSET,		    UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,				UVM_ADV_NORMAL, 0)) != KERN_SUCCESS)		panic("cpu_startup: cannot allocate VM for buffers");	addr = (vaddr_t)buffers;#else	buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers,	    maxaddr, size, TRUE);	addr = (vm_offset_t)buffers;	if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0,	    &addr, size, FALSE) != KERN_SUCCESS)		panic("startup: cannot allocate buffers");#endif	base = bufpages / nbuf;	residual = bufpages % nbuf;	if (base >= MAXBSIZE / CLBYTES) {		/* don't want to alloc more physical mem than needed */		base = MAXBSIZE / CLBYTES;		residual = 0;	}	/*	 * In case we might need DMA bouncing we have to make sure there	 * is some memory below 16MB available.  On machines with many	 * pages reserved for the buffer cache we risk filling all of that	 * area with buffer pages.  We still want much of the buffers	 * reside there as that lowers the probability of them needing to	 * bounce, but we have to set aside some space for DMA buffers too.	 *	 * The current strategy is to grab hold of 2MB chunks at a time as long	 * as they fit below 16MB, and as soon as that fail, give back the	 * last one and allocate the rest above 16MB.  That should guarantee	 * at least 2MB below 16MB left for DMA buffers.	 */	TAILQ_INIT(&pgs);	last = last2 = 0;	addr = 0;	for (left = bufpages; left > 2 * 1024 * 1024 / CLBYTES;	    left -= 2 * 1024 * 1024 / CLBYTES) {#if defined(UVM)		if (uvm_pglistalloc(2 * 1024 * 1024, 0, 16 * 1024 * 1024,		    CLBYTES, 0, &pgs, 1, 0)) {#else		if (vm_page_alloc_memory(2 * 1024 * 1024, 0, 16 * 1024 * 1024,		    CLBYTES, 0, &pgs, 1, 0)) {#endif			if (last2) {				TAILQ_INIT(&freepgs);				freepgs.tqh_first = *last2;				freepgs.tqh_last = pgs.tqh_last;				(*last2)->pageq.tqe_prev = &freepgs.tqh_first;				pgs.tqh_last = last2;				*last2 = NULL;#if defined(UVM)				uvm_pglistfree(&freepgs);#else				vm_page_free_memory(&freepgs);#endif				left += 2 * 1024 * 1024 / CLBYTES;				addr = 16 * 1024 * 1024;			}			break;		}		last2 = last ? last : &pgs.tqh_first;		last = pgs.tqh_last;	}	if (left > 0)#if defined(UVM)		if (uvm_pglistalloc(left * CLBYTES, addr, avail_end,		    CLBYTES, 0, &pgs, 1, 0))#else		if (vm_page_alloc_memory(left * CLBYTES, addr, avail_end,		    CLBYTES, 0, &pgs, 1, 0))#endif			panic("cannot get physical memory for buffer cache");	pg = pgs.tqh_first;	for (i = 0; i < nbuf; i++) {		/*		 * First <residual> buffers get (base+1) physical pages		 * allocated for them.  The rest get (base) physical pages.		 *		 * The rest of each buffer occupies virtual space,		 * but has no physical memory allocated for it.		 */		addr = (vm_offset_t)buffers + i * MAXBSIZE;		for (size = CLBYTES * (i < residual ? base + 1 : base);		     size > 0; size -= NBPG, addr += NBPG) {			pmap_enter(pmap_kernel(), addr, pg->phys_addr,			    VM_PROT_READ|VM_PROT_WRITE, TRUE,			    VM_PROT_READ|VM_PROT_WRITE);			pg = pg->pageq.tqe_next;		}	}}/*   * Info for CTL_HW */char	cpu_model[120];extern	char version[];/* * Note: these are just the ones that may not have a cpuid instruction. * We deal with the rest in a different way. */struct cpu_nocpuid_nameclass i386_nocpuid_cpus[] = {	{ CPUVENDOR_INTEL, "Intel", "386SX",	CPUCLASS_386,		NULL},				/* CPU_386SX */	{ CPUVENDOR_INTEL, "Intel", "386DX",	CPUCLASS_386,		NULL},				/* CPU_386   */	{ CPUVENDOR_INTEL, "Intel", "486SX",	CPUCLASS_486,		NULL},				/* CPU_486SX */	{ CPUVENDOR_INTEL, "Intel", "486DX",	CPUCLASS_486,		NULL},				/* CPU_486   */	{ CPUVENDOR_CYRIX, "Cyrix", "486DLC",	CPUCLASS_486,		NULL},				/* CPU_486DLC */	{ CPUVENDOR_CYRIX, "Cyrix", "6x86",		CPUCLASS_486,		cyrix6x86_cpu_setup},	/* CPU_6x86 */	{ CPUVENDOR_NEXGEN,"NexGen","586",      CPUCLASS_386,		NULL},				/* CPU_NX586 */};const char *classnames[] = {	"386",	"486",	"586",	"686"};const char *modifiers[] = {	"",	"OverDrive ",	"Dual ",	""};struct cpu_cpuid_nameclass i386_cpuid_cpus[] = {	{		"GenuineIntel",		CPUVENDOR_INTEL,		"Intel",		/* Family 4 */		{ {			CPUCLASS_486, 			{				"486DX", "486DX", "486SX", "486DX2", "486SL",				"486SX2", 0, "486DX2 W/B Enhanced",				"486DX4", 0, 0, 0, 0, 0, 0, 0,				"486"		/* Default */			},			NULL		},		/* Family 5 */		{			CPUCLASS_586,			{				"Pentium (P5 A-step)", "Pentium (P5)",				"Pentium (P54C)", "Pentium (P24T)",				"Pentium/MMX", "Pentium", 0,				"Pentium (P54C)", "Pentium/MMX (Tillamook)",				0, 0, 0, 0, 0, 0, 0,				"Pentium"	/* Default */			},			intel586_cpu_setup		},		/* Family 6 */		{			CPUCLASS_686,			{				"Pentium Pro (A-step)", "Pentium Pro", 0,				"Pentium II (Klamath)", "Pentium Pro",				"Pentium II (Deschutes)",				"Pentium II (Celeron)",				"Pentium III", 0, 0, 0, 0, 0, 0, 0, 0,				"Pentium Pro"	/* Default */			},			intel686_cpu_setup		} }	},	{		"AuthenticAMD",		CPUVENDOR_AMD,		"AMD",		/* Family 4 */		{ {			CPUCLASS_486, 			{				0, 0, 0, "Am486DX2 W/T",				0, 0, 0, "Am486DX2 W/B",				"Am486DX4 W/T or Am5x86 W/T 150",				"Am486DX4 W/B or Am5x86 W/B 150", 0, 0,				0, 0, "Am5x86 W/T 133/160",				"Am5x86 W/B 133/160",				"Am486 or Am5x86"	/* Default */			},			NULL		},		/* Family 5 */		{			CPUCLASS_586,			{				"K5", "K5", "K5", "K5", 0, 0, "K6",				"K6", "K6-2", "K6-3", 0, 0, 0, 0, 0, 0,				"K5 or K6"		/* Default */			},			NULL		},		/* Family 6 */		{			CPUCLASS_686,			{				0, "K7 (Athlon)", 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0, 0, 0, 0,				"K7 (Athlon)"		/* Default */			},			NULL		} }	},	{		"CyrixInstead",		CPUVENDOR_CYRIX,		"Cyrix",		/* Family 4 */		{ {			CPUCLASS_486,			{				0, 0, 0, "MediaGX", 0, 0, 0, 0, "5x86", 0, 0,				0, 0, 0, 0,				"486 class"	/* Default */			},			NULL		},		/* Family 5 */		{			CPUCLASS_586,			{				0, 0, "6x86 (M1)", 0, "GXm", 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0,				"M1 class"	/* Default */			},			cyrix6x86_cpu_setup		},		/* Family 6 */		{			CPUCLASS_686,			{				"6x86MX (M2)", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,				0, 0, 0, 0,				"M2 class"	/* Default */			},			NULL		} }	},	{		"CentaurHauls",		CPUVENDOR_IDT,		"IDT",		/* Family 4, not yet available from IDT */		{ {			CPUCLASS_486, 			{				0, 0, 0, 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0, 0, 0,				"486 class"		/* Default */			},			NULL		},		/* Family 5 */		{			CPUCLASS_586,			{				0, 0, 0, 0, "WinChip C6", 0, 0, 0,				"WinChip 2", "WinChip 3", 0, 0, 0, 0, 0, 0,				"WinChip"		/* Default */			},			NULL		},		/* Family 6, not yet available from IDT */		{			CPUCLASS_686,			{				0, 0, 0, 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0, 0, 0,				"686 class"		/* Default */			},			NULL		} }	},	{		"RiseRiseRise",		CPUVENDOR_RISE,		"Rise",		/* Family 4, not yet available from Rise */		{ {			CPUCLASS_486, 			{				0, 0, 0, 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0, 0, 0,				"486 class"		/* Default */			},			NULL		},		/* Family 5 */		{			CPUCLASS_586,			{				"mP6", 0, "mP6", 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0, 0, 0,				"mP6"			/* Default */			},			NULL		},		/* Family 6, not yet available from Rise */		{			CPUCLASS_686,			{				0, 0, 0, 0, 0, 0, 0, 0,				0, 0, 0, 0, 0, 0, 0, 0,				"686 class"		/* Default */			},			NULL		} }	}};struct cpu_cpuid_feature i386_cpuid_features[] = {	{ CPUID_FPU,	"FPU" },	{ CPUID_VME,	"V86" },	{ CPUID_DE,	"DE" },	{ CPUID_PSE,	"PSE" },	{ CPUID_TSC,	"TSC" },	{ CPUID_MSR,	"MSR" },	{ CPUID_PAE,	"PAE" },	{ CPUID_MCE,	"MCE" },	{ CPUID_CX8,	"CX8" },	{ CPUID_APIC,	"APIC" },	{ CPUID_SYS1,	"SYS" },	{ CPUID_SYS2,	"SYS" },	{ CPUID_MTRR,	"MTRR" },	{ CPUID_PGE,	"PGE" },	{ CPUID_MCA,	"MCA" },	{ CPUID_CMOV,	"CMOV" },	{ CPUID_PAT,	"PAT" },	{ CPUID_PSE36,	"PSE36" },	{ CPUID_SER,	"SER" },	{ CPUID_MMX,	"MMX" },	{ CPUID_FXSR,	"FXSR" },	{ CPUID_SIMD,	"SIMD" },	{ CPUID_3DNOW,	"3DNOW" },};voidcyrix6x86_cpu_setup(cpu_device, model, step)	const char *cpu_device;	int model, step;{#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)	extern int cpu_feature;	switch (model) {	case -1: /* M1 w/o cpuid */	case 2:	/* M1 */		/* set up various cyrix registers */		/* Enable suspend on halt */		cyrix_write_reg(0xc2, cyrix_read_reg(0xc2) | 0x08);		/* enable access to ccr4/ccr5 */		cyrix_write_reg(0xC3, cyrix_read_reg(0xC3) | 0x10);		/* cyrix's workaround  for the "coma bug" */		cyrix_write_reg(0x31, cyrix_read_reg(0x31) | 0xf8);		cyrix_write_reg(0x32, cyrix_read_reg(0x32) | 0x7f);		cyrix_write_reg(0x33, cyrix_read_reg(0x33) & ~0xff);		cyrix_write_reg(0x3c, cyrix_read_reg(0x3c) | 0x87);		/* disable access to ccr4/ccr5 */		cyrix_write_reg(0xC3, cyrix_read_reg(0xC3) & ~0x10);		printf("%s: xchg bug workaround performed\n", cpu_device);		break;	/* fallthrough? */	case 4:	/* GXm */		/* Unset the TSC bit until calibrate_delay() gets fixed. */		cpu_feature &= ~CPUID_TSC;		break;	}#endif}voidintel586_cpu_setup(cpu_device, model, step)	const char *cpu_device;	int model, step;{#if defined(I586_CPU)	fix_f00f();	printf("%s: F00F bug workaround installed\n", cpu_device);#endif}voidintel686_cpu_setup(cpu_device, model, step)	const char *cpu_device;	int model, step;{	extern int cpu_feature, cpuid_level;	u_quad_t msr119;#define rdmsr(msr)	\({			\	u_quad_t v;	\	__asm __volatile (".byte 0xf, 0x32" : "=A" (v) : "c" (msr));	\	v;		\})#define wrmsr(msr, v)	\	__asm __volatile (".byte 0xf, 0x30" :: "A" ((u_quad_t) (v)), "c" (msr));	/*	 * Original PPro returns SYSCALL in CPUID but is non-functional.	 * From Intel Application Note #485.	 */	if ((model == 1) && (step < 3))		cpu_feature &= ~CPUID_SYS2;	/*	 * Disable the Pentium3 serial number.	 */	if ((model == 7) && (cpu_feature & CPUID_SER)) {		msr119 = rdmsr(0x119);		msr119 |= 0x0000000000200000;		wrmsr(0x119, msr119);		printf("%s: disabling processor serial number\n", cpu_device);		cpu_feature &= ~CPUID_SER;		cpuid_level = 2;	}#undef rdmsr#undef wrmsr}char *intel686_cpu_name(model)	int model;{	extern int cpu_cache_edx;	char *ret = NULL;	switch (model) {	case 5:		switch (cpu_cache_edx & 0xFF) {		case 0x40:		case 0x41:			ret = "Celeron";			break;		/* 0x42 should not exist in this model. */		case 0x43:			ret = "Pentium II";			break;		case 0x44:		case 0x45:			ret = "Pentium II Xeon";			break;		}		break;	case 7:		switch (cpu_cache_edx & 0xFF) {		/* 0x40 - 0x42 should not exist in this model. */		case 0x43:			ret = "Pentium III";			break;		case 0x44:		case 0x45:			ret = "Pentium III Xeon";			break;		}		break;	}	return (ret);}