Home | History | Annotate | Line # | Download | only in ia64
      1 /*	$NetBSD: machdep.c,v 1.46 2025/03/16 15:34:59 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003,2004 Marcel Moolenaar
      5  * Copyright (c) 2000,2001 Doug Rabson
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 /*-
     31  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
     32  * All rights reserved.
     33  *
     34  * This code is derived from software contributed to The NetBSD Foundation
     35  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
     36  * NASA Ames Research Center and by Chris G. Demetriou.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  *
     47  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     57  * POSSIBILITY OF SUCH DAMAGE.
     58  */
     59 
     60 /*
     61  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
     62  * All rights reserved.
     63  *
     64  * Author: Chris G. Demetriou
     65  *
     66  * Permission to use, copy, modify and distribute this software and
     67  * its documentation is hereby granted, provided that both the copyright
     68  * notice and this permission notice appear in all copies of the
     69  * software, derivative works or modified versions, and any portions
     70  * thereof, and that both notices appear in supporting documentation.
     71  *
     72  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     73  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     74  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     75  *
     76  * Carnegie Mellon requests users of this software to return to
     77  *
     78  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     79  *  School of Computer Science
     80  *  Carnegie Mellon University
     81  *  Pittsburgh PA 15213-3890
     82  *
     83  * any improvements or extensions that they make and grant Carnegie the
     84  * rights to redistribute these changes.
     85  */
     86 
     87 #include <sys/cdefs.h>
     88 /*__FBSDID("$FreeBSD: src/sys/ia64/ia64/machdep.c,v 1.203 2005/10/14 12:43:45 davidxu Exp $"); */
     89 
     90 #include "opt_modular.h"
     91 
     92 #include <sys/param.h>
     93 #include <sys/cpu.h>
     94 #include <sys/exec.h>
     95 #include <sys/ksyms.h>
     96 #include <sys/msgbuf.h>
     97 #include <sys/mutex.h>
     98 #include <sys/proc.h>
     99 #include <sys/reboot.h>
    100 #include <sys/systm.h>
    101 
    102 #include <machine/ia64_cpu.h>
    103 #include <machine/pal.h>
    104 #include <machine/sal.h>
    105 #include <machine/ssc.h>
    106 
    107 #include <machine/md_var.h>
    108 #include <machine/fpu.h>
    109 #include <machine/efi.h>
    110 #include <machine/bootinfo.h>
    111 #include <machine/vmparam.h>
    112 
    113 #include <machine/atomic.h>
    114 #include <machine/pte.h>
    115 #include <machine/pcb.h>
    116 
    117 #include <uvm/uvm.h>
    118 
    119 #include <dev/cons.h>
    120 #include <dev/mm.h>
    121 
    122 #ifdef DEBUG
    123 #define	DPRINTF(fmt, args...)	printf("%s: " fmt, __func__, ##args)
    124 #else
    125 #define	DPRINTF(fmt, args...)	((void)0)
    126 #endif
    127 
    128 /* the following is used externally (sysctl_hw) */
    129 char	machine[] = MACHINE;		/* from <machine/param.h> */
    130 char	machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
    131 
    132 #if NKSYMS || defined(DDB) || defined(MODULAR)
    133 /* start and end of kernel symbol table */
    134 void	*ksym_start, *ksym_end;
    135 vaddr_t ia64_unwindtab;
    136 vsize_t ia64_unwindtablen;
    137 #endif
    138 
    139 struct vm_map *phys_map = NULL;
    140 
    141 void *msgbufaddr;
    142 
    143 vaddr_t kernstart, kernend;
    144 
    145 /* XXX: Move this stuff to cpu_info */
    146 
    147 uint64_t processor_frequency;
    148 uint64_t bus_frequency;
    149 uint64_t itc_frequency;
    150 uint64_t ia64_pal_base;
    151 uint64_t ia64_pal_size;
    152 uint64_t ia64_port_base;
    153 
    154 int ia64_sync_icache_needed = 0;
    155 
    156 extern uint64_t ia64_gateway_page[];
    157 
    158 uint64_t pa_bootinfo;
    159 struct bootinfo bootinfo;
    160 
    161 extern vaddr_t kstack, kstack_top;
    162 extern vaddr_t kernel_text, end;
    163 
    164 struct fpswa_iface *fpswa_iface;
    165 
    166 
    167 /*
    168  * Machine-dependent startup code
    169  */
    170 void
    171 cpu_startup(void)
    172 {
    173 	vaddr_t minaddr, maxaddr;
    174 
    175 	/* XXX: startrtclock(); */
    176 #ifdef PERFMON
    177 	perfmon_init();
    178 #endif
    179 	printf("Detected memory  = %ld (%ld MB)\n", ia64_ptob(physmem),
    180 	    ptoa(physmem) / 1048576);
    181 
    182 	/*
    183 	 * Display any holes after the first chunk of extended memory.
    184 	 */
    185 	if (bootverbose) {
    186 		int sizetmp, vm_nphysseg;
    187 		uvm_physseg_t upm;
    188 
    189 		printf("Physical memory chunk(s):\n");
    190 		for (vm_nphysseg = 0, upm = uvm_physseg_get_first();
    191 		     uvm_physseg_valid_p(upm);
    192 		     vm_nphysseg++, upm = uvm_physseg_get_next(upm)) {
    193 			sizetmp = uvm_physseg_get_avail_end(upm) -
    194 			    uvm_physseg_get_avail_start(upm);
    195 
    196 			printf("0x%016lx - 0x%016lx, %ld bytes (%d pages)\n",
    197 			    ptoa(uvm_physseg_get_avail_start(upm)),
    198 			    ptoa(uvm_physseg_get_avail_end(upm)) - 1,
    199 				    ptoa(sizetmp), sizetmp);
    200 		}
    201 		printf("Total number of segments: vm_nphysseg = %d \n",
    202 		    vm_nphysseg);
    203 	}
    204 
    205  	minaddr = 0;
    206 
    207 	/*
    208 	 * Allocate a submap for physio
    209 	 */
    210 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
    211 				   VM_PHYS_SIZE, 0, false, NULL);
    212 
    213 	/*
    214 	 * No need to allocate an mbuf cluster submap.  Mbuf clusters
    215 	 * are allocated via the pool allocator, and we use RR7 to
    216 	 * map those pages.
    217 	 */
    218 
    219 	banner();
    220 
    221 	if (fpswa_iface == NULL)
    222 		printf("Warning: no FPSWA package supplied\n");
    223 	else
    224 		printf("FPSWA Revision = 0x%lx, Entry = %p\n",
    225 		    (long)fpswa_iface->if_rev, (void *)fpswa_iface->if_fpswa);
    226 
    227 
    228 	/*
    229 	 * Traverse the MADT to discover IOSAPIC and Local SAPIC
    230 	 * information.
    231 	 */
    232 	ia64_probe_sapics();
    233 }
    234 
    235 void
    236 cpu_reboot(int howto, char *bootstr)
    237 {
    238 
    239 	efi_reset_system();
    240 
    241 	panic("XXX: Reset didn't work ? \n");
    242 	/*NOTREACHED*/
    243 }
    244 
    245 bool
    246 cpu_intr_p(void)
    247 {
    248 	return 0;
    249 }
    250 
    251 /*
    252  * This is called by main to set dumplo and dumpsize.
    253  * Dumps always skip the first PAGE_SIZE of disk space
    254  * in case there might be a disk label stored there.
    255  * If there is extra space, put dump at the end to
    256  * reduce the chance that swapping trashes it.
    257  */
    258 void
    259 cpu_dumpconf(void)
    260 {
    261 	return;
    262 }
    263 
    264 void
    265 map_vhpt(uintptr_t vhpt)
    266 {
    267         pt_entry_t pte;
    268         uint64_t psr;
    269 
    270 	/*
    271 	 * XXX read pmap_vhpt_log2size before any memory translation
    272 	 * instructions to avoid "Data Nested TLB faults".  Not
    273 	 * exactly sure why this is needed with GCC 7.4
    274 	 */
    275 	register uint64_t log2size = pmap_vhpt_log2size << 2;
    276 
    277         pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
    278 		PTE_PL_KERN | PTE_AR_RW;
    279         pte |= vhpt & PTE_PPN_MASK;
    280 
    281         __asm __volatile("ptr.d %0,%1" :: "r"(vhpt), "r"(log2size));
    282 
    283         __asm __volatile("mov   %0=psr" : "=r"(psr));
    284         __asm __volatile("rsm   psr.ic|psr.i");
    285         ia64_srlz_i();
    286         ia64_set_ifa(vhpt);
    287 	ia64_set_itir(log2size);
    288         ia64_srlz_d();
    289         __asm __volatile("itr.d dtr[%0]=%1" :: "r"(3), "r"(pte));
    290         __asm __volatile("mov   psr.l=%0" :: "r" (psr));
    291         ia64_srlz_i();
    292 }
    293 
    294 void
    295 map_pal_code(void)
    296 {
    297 	pt_entry_t pte;
    298 	uint64_t psr;
    299 
    300 	if (ia64_pal_base == 0)
    301 		return;
    302 
    303 	pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
    304 	    PTE_PL_KERN | PTE_AR_RWX;
    305 	pte |= ia64_pal_base & PTE_PPN_MASK;
    306 
    307 	__asm __volatile("ptr.d %0,%1; ptr.i %0,%1" ::
    308 			 "r"(IA64_PHYS_TO_RR7(ia64_pal_base)),
    309 			 "r"(IA64_ID_PAGE_SHIFT<<2));
    310 
    311 	__asm __volatile("mov	%0=psr" : "=r"(psr));
    312 	__asm __volatile("rsm	psr.ic|psr.i");
    313 	ia64_srlz_i();
    314 	ia64_set_ifa(IA64_PHYS_TO_RR7(ia64_pal_base));
    315 	ia64_set_itir(IA64_ID_PAGE_SHIFT << 2);
    316 	ia64_srlz_d();
    317  	__asm __volatile("itr.d	dtr[%0]=%1" ::
    318 			 "r"(1), "r"(*(pt_entry_t *)&pte));
    319 	ia64_srlz_d();
    320  	__asm __volatile("itr.i	itr[%0]=%1" ::
    321 			 "r"(1), "r"(*(pt_entry_t *)&pte));
    322 	__asm __volatile("mov	psr.l=%0" :: "r" (psr));
    323 	ia64_srlz_i();
    324 }
    325 
    326 void
    327 map_gateway_page(void)
    328 {
    329 	pt_entry_t pte;
    330 	uint64_t psr;
    331 
    332 	pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
    333 	    PTE_PL_KERN | PTE_AR_X_RX;
    334 	pte |= (uint64_t)ia64_gateway_page & PTE_PPN_MASK;
    335 
    336 	__asm __volatile("ptr.d %0,%1; ptr.i %0,%1" ::
    337 	    "r"(VM_MAX_ADDRESS), "r"(PAGE_SHIFT << 2));
    338 
    339 	__asm __volatile("mov	%0=psr" : "=r"(psr));
    340 	__asm __volatile("rsm	psr.ic|psr.i");
    341 	ia64_srlz_i();
    342 	ia64_set_ifa(VM_MAX_ADDRESS);
    343 	ia64_set_itir(PAGE_SHIFT << 2);
    344 	ia64_srlz_d();
    345 	__asm __volatile("itr.d	dtr[%0]=%1" :: "r"(3), "r"(*(pt_entry_t*)&pte));
    346 	ia64_srlz_d();
    347 	__asm __volatile("itr.i	itr[%0]=%1" :: "r"(3), "r"(*(pt_entry_t*)&pte));
    348 	__asm __volatile("mov	psr.l=%0" :: "r" (psr));
    349 	ia64_srlz_i();
    350 
    351 	/* Expose the mapping to userland in ar.k5 */
    352 	ia64_set_k5(VM_MAX_ADDRESS);
    353 }
    354 
    355 static void
    356 calculate_frequencies(void)
    357 {
    358 	struct ia64_sal_result sal;
    359 	struct ia64_pal_result pal;
    360 
    361 	sal = ia64_sal_entry(SAL_FREQ_BASE, 0, 0, 0, 0, 0, 0, 0);
    362 	pal = ia64_call_pal_static(PAL_FREQ_RATIOS, 0, 0, 0);
    363 	if (sal.sal_status == 0 && pal.pal_status == 0) {
    364 		if (bootverbose) {
    365 			printf("Platform clock frequency %ld Hz\n",
    366 			    sal.sal_result[0]);
    367 			printf("Processor ratio %ld/%ld, Bus ratio %ld/%ld, "
    368 			       "ITC ratio %ld/%ld\n",
    369 			    pal.pal_result[0] >> 32,
    370 			    pal.pal_result[0] & ((1L << 32) - 1),
    371 			    pal.pal_result[1] >> 32,
    372 			    pal.pal_result[1] & ((1L << 32) - 1),
    373 			    pal.pal_result[2] >> 32,
    374 			    pal.pal_result[2] & ((1L << 32) - 1));
    375 		}
    376 		processor_frequency =
    377 			sal.sal_result[0] * (pal.pal_result[0] >> 32)
    378 			/ (pal.pal_result[0] & ((1L << 32) - 1));
    379 		bus_frequency =
    380 			sal.sal_result[0] * (pal.pal_result[1] >> 32)
    381 			/ (pal.pal_result[1] & ((1L << 32) - 1));
    382 		itc_frequency =
    383 			sal.sal_result[0] * (pal.pal_result[2] >> 32)
    384 			/ (pal.pal_result[2] & ((1L << 32) - 1));
    385 	}
    386 
    387 }
    388 
    389 
    390 /* XXXX: Don't allocate 'ci' on stack. */
    391 register struct cpu_info *ci __asm__("r13");
    392 struct ia64_init_return
    393 ia64_init(void)
    394 {
    395 	struct ia64_init_return ret;
    396 	paddr_t kernstartpfn, kernendpfn, pfn0, pfn1;
    397 	struct pcb *pcb0;
    398 	struct efi_md *md;
    399 	vaddr_t v;
    400 
    401 	/* NO OUTPUT ALLOWED UNTIL FURTHER NOTICE */
    402 	ia64_set_fpsr(IA64_FPSR_DEFAULT);
    403 
    404 	/*
    405 	 * Region 6 is direct mapped UC and region 7 is direct mapped
    406 	 * WC. The details of this is controlled by the Alt {I,D}TLB
    407 	 * handlers. Here we just make sure that they have the largest
    408 	 * possible page size to minimise TLB usage.
    409 	 */
    410 	ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (LOG2_ID_PAGE_SIZE << 2));
    411 	ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (LOG2_ID_PAGE_SIZE << 2));
    412 	ia64_srlz_d();
    413 
    414 	/*
    415 	 * TODO: Get critical system information (if possible, from the
    416 	 * information provided by the boot program).
    417 	 */
    418 
    419 	/*
    420 	 * pa_bootinfo is the physical address of the bootinfo block as
    421 	 * passed to us by the loader and set in locore.s.
    422 	 */
    423 	bootinfo = *(struct bootinfo *)(IA64_PHYS_TO_RR7(pa_bootinfo));
    424 
    425 	if (bootinfo.bi_magic != BOOTINFO_MAGIC || bootinfo.bi_version != 1) {
    426 		memset(&bootinfo, 0, sizeof(bootinfo));
    427 		bootinfo.bi_kernend = (vaddr_t) round_page((vaddr_t)&end);
    428 	}
    429 
    430 
    431 	/*
    432 	 * Look for the I/O ports first - we need them for console
    433 	 * probing.
    434 	 */
    435 	for (md = efi_md_first(); md != NULL; md = efi_md_next(md)) {
    436 		switch (md->md_type) {
    437 		case EFI_MD_TYPE_IOPORT:
    438 			ia64_port_base = IA64_PHYS_TO_RR6(md->md_phys);
    439 			break;
    440 		case EFI_MD_TYPE_PALCODE:
    441 			ia64_pal_base = md->md_phys;
    442 			break;
    443 		}
    444 	}
    445 
    446 
    447 	/* XXX: We need to figure out whether/how much of the FreeBSD
    448 	 *      getenv/setenv stuff we need. The info we get from ski
    449 	 *      is too trivial to go to the hassle of importing the
    450 	 *	FreeBSD environment stuff.
    451 	 */
    452 
    453 	/*
    454 	 * Look at arguments passed to us and compute boothowto.
    455 	 */
    456 	boothowto = bootinfo.bi_boothowto;
    457 
    458 	/* XXX: Debug: Override to verbose */
    459 	boothowto |= AB_VERBOSE;
    460 
    461 
    462 	/*
    463 	 * Initialize the console before we print anything out.
    464 	 */
    465 	cninit();
    466 
    467 	/* OUTPUT NOW ALLOWED */
    468 
    469 	if (ia64_pal_base != 0) {
    470 		ia64_pal_base &= ~IA64_ID_PAGE_MASK;
    471 		/*
    472 		 * We use a TR to map the first 256M of memory - this might
    473 		 * cover the palcode too.
    474 		 */
    475 		if (ia64_pal_base == 0)
    476 			printf("PAL code mapped by the kernel's TR\n");
    477 	} else
    478 		printf("PAL code not found\n");
    479 
    480 	/*
    481 	 * Wire things up so we can call the firmware.
    482 	 */
    483 	map_pal_code();
    484 	efi_boot_minimal(bootinfo.bi_systab);
    485 	ia64_sal_init();
    486 	calculate_frequencies();
    487 
    488 	/*
    489 	 * Find the beginning and end of the kernel.
    490 	 */
    491 
    492 	kernstart = trunc_page((vaddr_t) &kernel_text);
    493 #ifdef DDB
    494 	ia64_unwindtab = (uint64_t)bootinfo.bi_unwindtab;
    495 	ia64_unwindtablen = (uint64_t)bootinfo.bi_unwindtablen;
    496 	ksym_start = (void *)bootinfo.bi_symtab;
    497 	ksym_end   = (void *)bootinfo.bi_esymtab;
    498 	kernend = (vaddr_t)round_page((vaddr_t)bootinfo.bi_kernend);
    499 #else
    500 	kernend = (vaddr_t)round_page(bootinfo.bi_kernend);
    501 #endif
    502 	kernstartpfn = atop(IA64_RR_MASK(kernstart));
    503 	kernendpfn = atop(IA64_RR_MASK(kernend));
    504 
    505 	/*
    506 	 * Find out this system's page size, and initialize
    507 	 * PAGE_SIZE-dependent variables.
    508 	 */
    509 
    510 	uvmexp.pagesize = PAGE_SIZE;
    511 	uvm_md_init();
    512 
    513 
    514 	/*
    515 	 * Find out how much memory is available, by looking at
    516 	 * the memory descriptors.
    517 	 */
    518 
    519 	physmem = 0;
    520 
    521 	for (md = efi_md_first(); md != NULL; md = efi_md_next(md)) {
    522 
    523 		DPRINTF("MD %p: type %d pa 0x%lx cnt 0x%lx\n", md,
    524 			md->md_type, md->md_phys, md->md_pages);
    525 
    526 		pfn0 = ia64_btop(round_page(md->md_phys));
    527 		pfn1 = ia64_btop(trunc_page(md->md_phys + md->md_pages * 4096));
    528 		if (pfn1 <= pfn0)
    529 			continue;
    530 
    531 		if (md->md_type != EFI_MD_TYPE_FREE)
    532 			continue;
    533 
    534 		/*
    535 		 * Wimp out for now since we do not DTRT here with
    536 		 * pci bus mastering (no bounce buffering, for example).
    537 		 */
    538 		if (pfn0 >= ia64_btop(0x100000000UL)) {
    539 			printf("Skipping memory chunk start 0x%lx\n",
    540 			    md->md_phys);
    541 			continue;
    542 		}
    543 		if (pfn1 >= ia64_btop(0x100000000UL)) {
    544 			printf("Skipping memory chunk end 0x%lx\n",
    545 			    md->md_phys + md->md_pages * 4096);
    546 			continue;
    547 		}
    548 
    549 		/*
    550 		 * We have a memory descriptor that describes conventional
    551 		 * memory that is for general use. We must determine if the
    552 		 * loader has put the kernel in this region.
    553 		 */
    554 		physmem += (pfn1 - pfn0);
    555 		if (pfn0 <= kernendpfn && kernstartpfn <= pfn1) {
    556 			/*
    557 			 * Must compute the location of the kernel
    558 			 * within the segment.
    559 			 */
    560 			DPRINTF("Descriptor %p contains kernel\n", md);
    561 
    562 			if (pfn0 < kernstartpfn) {
    563 				/*
    564 				 * There is a chunk before the kernel.
    565 				 */
    566 				DPRINTF("Loading chunk before kernel: "
    567 					"0x%lx / 0x%lx\n", pfn0, kernstartpfn);
    568 
    569 				uvm_page_physload(pfn0, kernstartpfn,
    570 				    pfn0, kernstartpfn, VM_FREELIST_DEFAULT);
    571 
    572 			}
    573 			if (kernendpfn < pfn1) {
    574 				/*
    575 				 * There is a chunk after the kernel.
    576 				 */
    577 				DPRINTF("Loading chunk after kernel: "
    578 					"0x%lx / 0x%lx\n", kernendpfn, pfn1);
    579 
    580 				uvm_page_physload(kernendpfn, pfn1,
    581 				    kernendpfn, pfn1, VM_FREELIST_DEFAULT);
    582 
    583 			}
    584 		} else {
    585 			/*
    586 			 * Just load this cluster as one chunk.
    587 			 */
    588 			DPRINTF("Loading descriptor %p: 0x%lx / 0x%lx\n",
    589 				md, pfn0, pfn1);
    590 
    591 			uvm_page_physload(pfn0, pfn1, pfn0, pfn1,
    592 			    VM_FREELIST_DEFAULT);
    593 
    594 		}
    595 	}
    596 
    597 	if (physmem == 0)
    598 		panic("can't happen: system seems to have no memory!");
    599 
    600 	/*
    601 	 * Initialize error message buffer (at end of core).
    602 	 */
    603 	msgbufaddr = (void *) uvm_pageboot_alloc(MSGBUFSIZE);
    604 	initmsgbuf(msgbufaddr, MSGBUFSIZE);
    605 
    606 	/*
    607 	 * Init mapping for u page(s) for proc 0.  use memory area
    608 	 * already set up in locore.S
    609 	 */
    610 	v = (vaddr_t)&kstack;
    611 	uvm_lwp_setuarea(&lwp0, v);
    612 
    613 	/*
    614 	 * Set the kernel sp, reserving space for an (empty) trapframe,
    615 	 * and make lwp0's trapframe pointer point to it for sanity.
    616 	 */
    617 	lwp0.l_md.md_tf = (struct trapframe *)(v + UAREA_TF_OFFSET);
    618 	lwp0.l_md.md_tf->tf_length = sizeof(struct trapframe);
    619 	lwp0.l_md.md_tf->tf_flags = FRAME_SYSCALL;
    620 
    621 	lwp0.l_md.user_stack = NULL;
    622 	lwp0.l_md.user_stack_size = 0;
    623 
    624 	pcb0 = lwp_getpcb(&lwp0);
    625 	pcb0->pcb_special.sp = v + UAREA_SP_OFFSET;
    626 	pcb0->pcb_special.bspstore = v + UAREA_BSPSTORE_OFFSET;
    627 
    628 	/*
    629 	 * Setup global data for the bootstrap cpu.
    630 	 */
    631 	ci = curcpu();
    632 
    633 	/* ar.k4 contains the cpu_info pointer to the
    634 	 * current cpu.
    635 	 */
    636 	ia64_set_k4((uint64_t) ci);
    637 	ci->ci_cpuid = cpu_number();
    638 
    639 	/*
    640 	 * Initialise process context. XXX: This should really be in cpu_switchto
    641 	 *
    642 	 * No membar needed because we're not switching from a
    643 	 * previous lwp, and the idle lwp we're switching to can't be
    644 	 * holding locks already; see cpu_switchto.
    645 	 */
    646 	ci->ci_curlwp = &lwp0;
    647 
    648 	/*
    649 	 * Initialize the primary CPU's idle PCB to proc0's.  In a
    650 	 * MULTIPROCESSOR configuration, each CPU will later get
    651 	 * its own idle PCB when autoconfiguration runs.
    652 	 */
    653 	ci->ci_idle_pcb = pcb0;
    654 
    655 	/* Indicate that proc0 has a CPU. */
    656 	lwp0.l_cpu = ci;
    657 
    658 	ia64_set_tpr(0);
    659 	ia64_srlz_d();
    660 
    661 	mutex_init(&pcb0->pcb_fpcpu_slock, MUTEX_DEFAULT, 0);
    662 
    663 	/*
    664 	 * Save our current context so that we have a known (maybe even
    665 	 * sane) context as the initial context for new threads that are
    666 	 * forked from us.
    667 	 */
    668 	if (savectx(pcb0))
    669 		panic("savectx failed");
    670 
    671 	/*
    672 	 * Initialize the virtual memory system.
    673 	 */
    674 	pmap_bootstrap();
    675 
    676 	/*
    677 	 * Initialize debuggers, and break into them if appropriate.
    678 	 */
    679 #if NKSYMS || defined(DDB) || defined(MODULAR)
    680 	ksyms_addsyms_elf((int)((uint64_t)ksym_end - (uint64_t)ksym_start),
    681 	    ksym_start, ksym_end);
    682 #endif
    683 
    684 #ifdef DDB
    685 	if (boothowto & RB_KDB)
    686 		Debugger();
    687 #endif
    688 
    689 	ret.bspstore = pcb0->pcb_special.bspstore;
    690 	ret.sp = pcb0->pcb_special.sp;
    691 
    692 	return (ret);
    693 }
    694 
    695 uint64_t
    696 ia64_get_hcdp(void)
    697 {
    698 
    699 	return bootinfo.bi_hcdp;
    700 }
    701 
    702 /*
    703  * Set registers on exec.
    704  */
    705 void
    706 setregs(register struct lwp *l, struct exec_package *pack, vaddr_t stack)
    707 {
    708 	struct trapframe *tf;
    709 	uint64_t *ksttop, *kst, regstkp;
    710 	vaddr_t uv = uvm_lwp_getuarea(l);
    711 
    712 	tf = l->l_md.md_tf;
    713 	memset(tf, 0, sizeof(*tf));
    714 
    715 	regstkp = uv + sizeof(struct pcb);
    716 
    717 	ksttop =
    718 	    (uint64_t*)(regstkp + tf->tf_special.ndirty +
    719 					(tf->tf_special.bspstore & 0x1ffUL));
    720 
    721 	/* XXX: tf_special.ndirty on a new stack frame ??? */
    722 
    723 	/*
    724 	 * We can ignore up to 8KB of dirty registers by masking off the
    725 	 * lower 13 bits in exception_restore() or epc_syscall(). This
    726 	 * should be enough for a couple of years, but if there are more
    727 	 * than 8KB of dirty registers, we lose track of the bottom of
    728 	 * the kernel stack. The solution is to copy the active part of
    729 	 * the kernel stack down 1 page (or 2, but not more than that)
    730 	 * so that we always have less than 8KB of dirty registers.
    731 	 */
    732 	KASSERT((tf->tf_special.ndirty & ~PAGE_MASK) == 0);
    733 
    734 	memset(&tf->tf_special, 0, sizeof(tf->tf_special));
    735 	if ((tf->tf_flags & FRAME_SYSCALL) == 0) {	/* break syscalls. */
    736 		memset(&tf->tf_scratch, 0, sizeof(tf->tf_scratch));
    737 		memset(&tf->tf_scratch_fp, 0, sizeof(tf->tf_scratch_fp));
    738 		tf->tf_special.cfm = (1UL<<63) | (3UL<<7) | 3UL;
    739 		tf->tf_special.bspstore = IA64_BACKINGSTORE;
    740 		/*
    741 		 * Copy the arguments onto the kernel register stack so that
    742 		 * they get loaded by the loadrs instruction. Skip over the
    743 		 * NaT collection points.
    744 		 */
    745 		kst = ksttop - 1;
    746 		if (((uintptr_t)kst & 0x1ff) == 0x1f8)
    747 			*kst-- = 0;
    748 		*kst-- = stack;				/* in3 = sp */
    749 		if (((uintptr_t)kst & 0x1ff) == 0x1f8)
    750 			*kst-- = 0;
    751 		*kst-- = l->l_proc->p_psstrp;		/* in2 = ps_strings */
    752 		if (((uintptr_t)kst & 0x1ff) == 0x1f8)
    753 			*kst-- = 0;
    754 		*kst-- = 0;				/* in1 = *obj */
    755 		if (((uintptr_t)kst & 0x1ff) == 0x1f8)
    756 			*kst-- = 0;
    757 		*kst = 0;				/* in0 = *cleanup */
    758 		tf->tf_special.ndirty = (ksttop - kst) << 3;
    759 	} else {				/* epc syscalls (default). */
    760 		tf->tf_special.cfm = (3UL<<62) | (3UL<<7) | 3UL;
    761 		tf->tf_special.bspstore = IA64_BACKINGSTORE + 24;
    762 		/*
    763 		 * Write values for out0, out1, out2 and out3 to the user's
    764 		 * backing store and arrange for them to be restored into
    765 		 * the user's initial register frame.
    766 		 * Assumes that (bspstore & 0x1f8) < 0x1e0.
    767 		 */
    768 
    769 		/* in0 = *cleanup */
    770 		ustore_long((u_long *)(tf->tf_special.bspstore - 32), 0);
    771 
    772 		/* in1 == *obj */
    773 		ustore_long((u_long *)(tf->tf_special.bspstore -  24), 0);
    774 
    775 		/* in2 == ps_strings */
    776 		ustore_long((u_long *)(tf->tf_special.bspstore -  16),
    777 		    l->l_proc->p_psstrp);
    778 
    779 		/* in3 = sp */
    780 		ustore_long((u_long *)(tf->tf_special.bspstore - 8),
    781 		    stack);
    782 
    783 	}
    784 
    785 	tf->tf_special.iip = pack->ep_entry;
    786 	tf->tf_special.sp = (stack & ~15) - 16;
    787 	tf->tf_special.rsc = 0xf;
    788 	tf->tf_special.fpsr = IA64_FPSR_DEFAULT;
    789 	tf->tf_special.psr = IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT |
    790 	    IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | IA64_PSR_BN |
    791 	    IA64_PSR_CPL_USER;
    792 	return;
    793 }
    794 
    795 void
    796 sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
    797 {
    798 	return;
    799 }
    800 
    801 void
    802 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
    803 {
    804 	return;
    805 }
    806 
    807 int
    808 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
    809 {
    810 	return EINVAL;
    811 }
    812 
    813 int
    814 cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
    815 {
    816 	return EINVAL;
    817 }
    818 
    819 int
    820 mm_md_physacc(paddr_t pa, vm_prot_t prot)
    821 {
    822 
    823 	return 0; /* TODO: Implement. */
    824 }
    825 
    826 void
    827 ia64_sync_icache(vaddr_t va, vsize_t sz)
    828 {
    829 	vaddr_t lim;
    830 
    831         if (!ia64_sync_icache_needed)
    832                 return;
    833 
    834         lim = va + sz;
    835         while (va < lim) {
    836                 ia64_fc_i(va);
    837                 va += 32;       /* XXX */
    838         }
    839 
    840         ia64_sync_i();
    841         ia64_srlz_i();
    842 }
    843 
    844 /*
    845  * Construct a PCB from a trapframe. This is called from kdb_trap() where
    846  * we want to start a backtrace from the function that caused us to enter
    847  * the debugger. We have the context in the trapframe, but base the trace
    848  * on the PCB. The PCB doesn't have to be perfect, as long as it contains
    849  * enough for a backtrace.
    850  */
    851 void
    852 makectx(struct trapframe *tf, struct pcb *pcb)
    853 {
    854         pcb->pcb_special = tf->tf_special;
    855         pcb->pcb_special.__spare = ~0UL;        /* XXX see unwind.c */
    856         save_callee_saved(&pcb->pcb_preserved);
    857         save_callee_saved_fp(&pcb->pcb_preserved_fp);
    858 }
    859