#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_modular.h"
#include "opt_multiprocessor.h"
#include "opt_dec_3000_300.h"
#include "opt_dec_3000_500.h"
#include "opt_execfmt.h"
#define __RWLOCK_PRIVATE
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.385 2026/04/08 04:06:40 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <sys/cpu.h>
#include <sys/proc.h>
#include <sys/ras.h>
#include <sys/sched.h>
#include <sys/reboot.h>
#include <sys/device.h>
#include <sys/module.h>
#include <sys/mman.h>
#include <sys/msgbuf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/exec.h>
#include <sys/exec_aout.h>
#include <sys/exec_ecoff.h>
#include <sys/core.h>
#include <sys/kcore.h>
#include <sys/ucontext.h>
#include <sys/conf.h>
#include <sys/ksyms.h>
#include <sys/kauth.h>
#include <sys/atomic.h>
#include <sys/cpu.h>
#include <sys/rwlock.h>
#include <machine/kcore.h>
#include <machine/fpu.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <uvm/uvm.h>
#include <sys/sysctl.h>
#include <dev/cons.h>
#include <dev/mm.h>
#include <machine/autoconf.h>
#include <machine/reg.h>
#include <machine/rpb.h>
#include <machine/prom.h>
#include <machine/cpuconf.h>
#include <machine/ieeefp.h>
#ifdef DDB
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#include <ddb/db_interface.h>
#endif
#ifdef KGDB
#include <sys/kgdb.h>
#endif
#ifdef DEBUG
#include <machine/sigdebug.h>
int sigdebug = 0x0;
int sigpid = 0;
#endif
__CTASSERT(RW_READER == 0);
__CTASSERT(RW_HAS_WAITERS == 1);
#include <machine/alpha.h>
#include "ksyms.h"
struct vm_map *phys_map = NULL;
void *msgbufaddr;
int maxmem;
int totalphysmem;
int resvmem;
int unusedmem;
int unknownmem;
int cputype;
bool alpha_is_qemu;
int bootdev_debug = 0;
uint32_t no_optimize;
char machine[] = MACHINE;
char machine_arch[] = MACHINE_ARCH;
uint64_t cycles_per_usec;
int ncpus;
struct bootinfo_kernel bootinfo;
#if defined(DEC_3000_300) || defined(DEC_3000_500)
uint8_t dec_3000_scsiid[3], dec_3000_scsifast[3];
#endif
struct platform platform;
#if NKSYMS || defined(DDB) || defined(MODULAR)
void *ksym_start, *ksym_end;
#endif
int alpha_unaligned_print = 1;
int alpha_unaligned_fix = 1;
int alpha_unaligned_sigbus = 0;
int alpha_fp_sync_complete = 0;
int alpha_fp_complete_debug = 0;
phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
int mem_cluster_cnt;
int cpu_dump(void);
int cpu_dumpsize(void);
u_long cpu_dump_mempagecnt(void);
void dumpsys(void);
void identifycpu(void);
void printregs(struct reg *);
const pcu_ops_t fpu_ops = {
.pcu_id = PCU_FPU,
.pcu_state_load = fpu_state_load,
.pcu_state_save = fpu_state_save,
.pcu_state_release = fpu_state_release,
};
const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
[PCU_FPU] = &fpu_ops,
};
static void
alpha_page_physload(unsigned long const start_pfn, unsigned long const end_pfn)
{
if (platform.page_physload != NULL) {
(*platform.page_physload)(start_pfn, end_pfn);
return;
}
uvm_page_physload(start_pfn, end_pfn, start_pfn, end_pfn,
VM_FREELIST_DEFAULT);
}
void
alpha_page_physload_sheltered(unsigned long const start_pfn,
unsigned long const end_pfn, unsigned long const shelter_start_pfn,
unsigned long const shelter_end_pfn)
{
if (end_pfn <= shelter_start_pfn || start_pfn >= shelter_end_pfn) {
uvm_page_physload(start_pfn, end_pfn,
start_pfn, end_pfn, VM_FREELIST_DEFAULT);
return;
}
if (start_pfn < shelter_start_pfn) {
KASSERT(end_pfn > shelter_start_pfn);
uvm_page_physload(start_pfn, shelter_start_pfn,
start_pfn, shelter_start_pfn, VM_FREELIST_DEFAULT);
}
const unsigned long ov_start = MAX(start_pfn, shelter_start_pfn);
const unsigned long ov_end = MIN(end_pfn, shelter_end_pfn);
KASSERT(ov_start >= shelter_start_pfn);
KASSERT(ov_end <= shelter_end_pfn);
uvm_page_physload(ov_start, ov_end, ov_start, ov_end,
VM_FREELIST_SHELTERED);
if (end_pfn > shelter_end_pfn) {
KASSERT(start_pfn < shelter_end_pfn);
uvm_page_physload(shelter_end_pfn, end_pfn,
shelter_end_pfn, end_pfn, VM_FREELIST_DEFAULT);
}
}
void
alpha_init(u_long xxx_pfn __unused, u_long ptb, u_long bim, u_long bip,
u_long biv)
{
extern char kernel_text[], _end[];
struct mddt *mddtp;
struct mddt_cluster *memc;
int i, mddtweird;
struct pcb *pcb0;
vaddr_t kernstart, kernend, v;
paddr_t kernstartpfn, kernendpfn, pfn0, pfn1;
cpuid_t cpu_id;
struct cpu_info *ci;
char *p;
const char *bootinfo_msg;
const struct cpuinit *c;
(void)alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
alpha_pal_wrfen(0);
ALPHA_TBIA();
alpha_pal_imb();
scb_init();
cpu_id = cpu_number();
ci = &cpu_info_primary;
ci->ci_cpuid = cpu_id;
#if defined(MULTIPROCESSOR)
lwp0.l_cpu = ci;
cpu_info[cpu_id] = ci;
alpha_pal_wrval((u_long)&lwp0);
#endif
bootinfo_msg = NULL;
if (bim == BOOTINFO_MAGIC) {
if (biv == 0) {
biv = *(u_long *)bip;
bip += 8;
}
switch (biv) {
case 1: {
struct bootinfo_v1 *v1p = (struct bootinfo_v1 *)bip;
bootinfo.ssym = v1p->ssym;
bootinfo.esym = v1p->esym;
if (v1p->hwrpb != NULL) {
bootinfo.hwrpb_phys =
((struct rpb *)v1p->hwrpb)->rpb_phys;
bootinfo.hwrpb_size = v1p->hwrpbsize;
} else {
bootinfo.hwrpb_phys =
((struct rpb *)HWRPB_ADDR)->rpb_phys;
bootinfo.hwrpb_size =
((struct rpb *)HWRPB_ADDR)->rpb_size;
}
memcpy(bootinfo.boot_flags, v1p->boot_flags,
uimin(sizeof v1p->boot_flags,
sizeof bootinfo.boot_flags));
memcpy(bootinfo.booted_kernel, v1p->booted_kernel,
uimin(sizeof v1p->booted_kernel,
sizeof bootinfo.booted_kernel));
init_prom_interface(ptb, (struct rpb *)
ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys));
prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev,
sizeof bootinfo.booted_dev);
break;
}
default:
bootinfo_msg = "unknown bootinfo version";
goto nobootinfo;
}
} else {
bootinfo_msg = "boot program did not pass bootinfo";
nobootinfo:
bootinfo.ssym = (u_long)_end;
bootinfo.esym = (u_long)_end;
bootinfo.hwrpb_phys = ((struct rpb *)HWRPB_ADDR)->rpb_phys;
bootinfo.hwrpb_size = ((struct rpb *)HWRPB_ADDR)->rpb_size;
init_prom_interface(ptb, (struct rpb *)HWRPB_ADDR);
if (alpha_is_qemu) {
if (! prom_qemu_getenv("flags", bootinfo.boot_flags,
sizeof(bootinfo.boot_flags))) {
strlcpy(bootinfo.boot_flags, "A",
sizeof(bootinfo.boot_flags));
}
} else {
prom_getenv(PROM_E_BOOTED_OSFLAGS, bootinfo.boot_flags,
sizeof bootinfo.boot_flags);
prom_getenv(PROM_E_BOOTED_FILE, bootinfo.booted_kernel,
sizeof bootinfo.booted_kernel);
prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev,
sizeof bootinfo.booted_dev);
}
}
hwrpb = (struct rpb *)ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys);
#if defined(DEC_3000_300) || defined(DEC_3000_500)
if (hwrpb->rpb_type == ST_DEC_3000_300 ||
hwrpb->rpb_type == ST_DEC_3000_500) {
prom_getenv(PROM_E_SCSIID, dec_3000_scsiid,
sizeof(dec_3000_scsiid));
prom_getenv(PROM_E_SCSIFAST, dec_3000_scsifast,
sizeof(dec_3000_scsifast));
}
#endif
cycles_per_usec = (hwrpb->rpb_cc_freq + 999999) / 1000000;
init_bootstrap_console();
if (bootinfo_msg)
printf("WARNING: %s (0x%lx, 0x%lx, 0x%lx)\n",
bootinfo_msg, bim, bip, biv);
trap_init();
if (hwrpb->rpb_page_size != ALPHA_PGBYTES)
panic("page size %lu != %d?!", hwrpb->rpb_page_size,
ALPHA_PGBYTES);
uvmexp.pagesize = hwrpb->rpb_page_size;
uvm_md_init();
KASSERT(prom_interface_initialized);
c = platform_lookup(cputype);
if (c == NULL) {
platform_not_supported();
}
(*c->init)();
cpu_setmodel("%s", platform.model);
(*platform.cons_init)();
#ifdef DIAGNOSTIC
assert(hwrpb->rpb_primary_cpu_id == cpu_id);
if (cputype != ST_DEC_21000)
assert(hwrpb->rpb_primary_cpu_id == 0);
#endif
kernstart = trunc_page((vaddr_t)kernel_text) - 2 * PAGE_SIZE;
#if NKSYMS || defined(DDB) || defined(MODULAR)
ksym_start = (void *)bootinfo.ssym;
ksym_end = (void *)bootinfo.esym;
kernend = (vaddr_t)round_page((vaddr_t)ksym_end);
#else
kernend = (vaddr_t)round_page((vaddr_t)_end);
#endif
kernstartpfn = atop(ALPHA_K0SEG_TO_PHYS(kernstart));
kernendpfn = atop(ALPHA_K0SEG_TO_PHYS(kernend));
mddtp = (struct mddt *)(((char *)hwrpb) + hwrpb->rpb_memdat_off);
mddtweird = 0;
if (mddtp->mddt_cluster_cnt < 2) {
mddtweird = 1;
printf("WARNING: weird number of mem clusters: %lu\n",
mddtp->mddt_cluster_cnt);
}
#if 0
printf("Memory cluster count: %" PRIu64 "\n", mddtp->mddt_cluster_cnt);
#endif
for (i = 0; i < mddtp->mddt_cluster_cnt; i++) {
memc = &mddtp->mddt_clusters[i];
#if 0
printf("MEMC %d: pfn 0x%lx cnt 0x%lx usage 0x%lx\n", i,
memc->mddt_pfn, memc->mddt_pg_cnt, memc->mddt_usage);
#endif
totalphysmem += memc->mddt_pg_cnt;
if (mem_cluster_cnt < VM_PHYSSEG_MAX) {
mem_clusters[mem_cluster_cnt].start =
ptoa(memc->mddt_pfn);
mem_clusters[mem_cluster_cnt].size =
ptoa(memc->mddt_pg_cnt);
if (memc->mddt_usage & MDDT_mbz ||
memc->mddt_usage & MDDT_NONVOLATILE ||
memc->mddt_usage & MDDT_PALCODE)
mem_clusters[mem_cluster_cnt].size |=
PROT_READ;
else
mem_clusters[mem_cluster_cnt].size |=
PROT_READ | PROT_WRITE | PROT_EXEC;
mem_cluster_cnt++;
}
if (memc->mddt_usage & MDDT_mbz) {
mddtweird = 1;
printf("WARNING: mem cluster %d has weird "
"usage 0x%lx\n", i, memc->mddt_usage);
unknownmem += memc->mddt_pg_cnt;
continue;
}
if (memc->mddt_usage & MDDT_NONVOLATILE) {
printf("WARNING: skipping non-volatile mem "
"cluster %d\n", i);
unusedmem += memc->mddt_pg_cnt;
continue;
}
if (memc->mddt_usage & MDDT_PALCODE) {
resvmem += memc->mddt_pg_cnt;
continue;
}
physmem += memc->mddt_pg_cnt;
pfn0 = memc->mddt_pfn;
pfn1 = memc->mddt_pfn + memc->mddt_pg_cnt;
if (pfn0 <= kernstartpfn && kernendpfn <= pfn1) {
#if 0
printf("Cluster %d contains kernel\n", i);
#endif
if (pfn0 < kernstartpfn && !prom_uses_prom_console()) {
#if 0
printf("Loading chunk before kernel: "
"0x%lx / 0x%lx\n", pfn0, kernstartpfn);
#endif
alpha_page_physload(pfn0, kernstartpfn);
}
if (kernendpfn < pfn1) {
#if 0
printf("Loading chunk after kernel: "
"0x%lx / 0x%lx\n", kernendpfn, pfn1);
#endif
alpha_page_physload(kernendpfn, pfn1);
}
} else {
#if 0
printf("Loading cluster %d: 0x%lx / 0x%lx\n", i,
pfn0, pfn1);
#endif
alpha_page_physload(pfn0, pfn1);
}
}
if (mddtweird) {
printf("\n");
printf("complete memory cluster information:\n");
for (i = 0; i < mddtp->mddt_cluster_cnt; i++) {
printf("mddt %d:\n", i);
printf("\tpfn %lx\n",
mddtp->mddt_clusters[i].mddt_pfn);
printf("\tcnt %lx\n",
mddtp->mddt_clusters[i].mddt_pg_cnt);
printf("\ttest %lx\n",
mddtp->mddt_clusters[i].mddt_pg_test);
printf("\tbva %lx\n",
mddtp->mddt_clusters[i].mddt_v_bitaddr);
printf("\tbpa %lx\n",
mddtp->mddt_clusters[i].mddt_p_bitaddr);
printf("\tbcksum %lx\n",
mddtp->mddt_clusters[i].mddt_bit_cksum);
printf("\tusage %lx\n",
mddtp->mddt_clusters[i].mddt_usage);
}
printf("\n");
}
if (totalphysmem == 0)
panic("can't happen: system seems to have no memory!");
maxmem = physmem;
#if 0
printf("totalphysmem = %d\n", totalphysmem);
printf("physmem = %lu\n", physmem);
printf("resvmem = %d\n", resvmem);
printf("unusedmem = %d\n", unusedmem);
printf("unknownmem = %d\n", unknownmem);
#endif
{
paddr_t end;
vsize_t sz = (vsize_t)round_page(MSGBUFSIZE);
vsize_t reqsz = sz;
uvm_physseg_t bank;
bank = uvm_physseg_get_last();
if (uvm_physseg_get_avail_end(bank) - uvm_physseg_get_avail_start(bank) < atop(sz))
sz = ptoa(uvm_physseg_get_avail_end(bank) - uvm_physseg_get_avail_start(bank));
end = uvm_physseg_get_end(bank);
end -= atop(sz);
uvm_physseg_unplug(end, atop(sz));
msgbufaddr = (void *) ALPHA_PHYS_TO_K0SEG(ptoa(end));
initmsgbuf(msgbufaddr, sz);
if (sz != reqsz)
printf("WARNING: %ld bytes not available for msgbuf "
"in last cluster (%ld used)\n", reqsz, sz);
}
v = uvm_pageboot_alloc(UPAGES * PAGE_SIZE);
uvm_lwp_setuarea(&lwp0, v);
pmap_bootstrap(ALPHA_PHYS_TO_K0SEG(ptb << PGSHIFT),
hwrpb->rpb_max_asn, hwrpb->rpb_pcs_cnt);
pcb0 = lwp_getpcb(&lwp0);
lwp0.l_md.md_pcbpaddr = (void *)ALPHA_K0SEG_TO_PHYS((vaddr_t)pcb0);
pcb0->pcb_hw.apcb_ksp = v + USPACE - sizeof(struct trapframe);
lwp0.l_md.md_tf = (struct trapframe *)pcb0->pcb_hw.apcb_ksp;
lwp0.l_cpu = ci;
boothowto = RB_SINGLE;
#ifdef KADB
boothowto |= RB_KDB;
#endif
for (p = bootinfo.boot_flags; p && *p != '\0'; p++) {
switch (*p) {
case 'a':
case 'A':
boothowto &= ~RB_SINGLE;
break;
#ifdef DEBUG
case 'c':
case 'C':
boothowto |= RB_DUMP;
break;
#endif
#if defined(KGDB) || defined(DDB)
case 'd':
case 'D':
boothowto |= RB_KDB;
break;
#endif
case 'h':
case 'H':
boothowto |= RB_HALT;
break;
#if 0
case 'm':
case 'M':
boothowto |= RB_MINIROOT;
break;
#endif
case 'n':
case 'N':
boothowto |= RB_ASKNAME;
break;
case 's':
case 'S':
boothowto |= RB_SINGLE;
break;
case 'q':
case 'Q':
boothowto |= AB_QUIET;
break;
case 'v':
case 'V':
boothowto |= AB_VERBOSE;
break;
case 'x':
case 'X':
boothowto |= AB_DEBUG;
break;
case '-':
break;
default:
printf("Unrecognized boot flag '%c'.\n", *p);
break;
}
}
alpha_patch(false);
for (i = 0; i < hwrpb->rpb_pcs_cnt; i++) {
struct pcs *pcsp;
pcsp = LOCATE_PCS(hwrpb, i);
if ((pcsp->pcs_flags & PCS_PP) != 0)
ncpus++;
}
#if NKSYMS || defined(DDB) || defined(MODULAR)
ksyms_addsyms_elf((int)((uint64_t)ksym_end - (uint64_t)ksym_start),
ksym_start, ksym_end);
#endif
if (boothowto & RB_KDB) {
#if defined(KGDB)
kgdb_debug_init = 1;
kgdb_connect(1);
#elif defined(DDB)
Debugger();
#endif
}
#ifdef DIAGNOSTIC
if ((hwrpb->rpb_intr_freq >> 12) != 1024)
printf("WARNING: unbelievable rpb_intr_freq: %ld (%d hz)\n",
hwrpb->rpb_intr_freq, hz);
#endif
}
void
consinit(void)
{
#if defined(DIAGNOSTIC) && defined(_PROM_MAY_USE_PROM_CONSOLE)
printf("consinit: %susing prom console\n",
prom_uses_prom_console() ? "" : "not ");
#endif
}
void
cpu_startup(void)
{
vaddr_t minaddr, maxaddr;
char pbuf[9];
#if defined(DEBUG)
extern int pmapdebug;
int opmapdebug = pmapdebug;
pmapdebug = 0;
#endif
printf("%s%s", copyright, version);
identifycpu();
format_bytes(pbuf, sizeof(pbuf), ptoa(totalphysmem));
printf("total memory = %s\n", pbuf);
format_bytes(pbuf, sizeof(pbuf), ptoa(resvmem));
printf("(%s reserved for PROM, ", pbuf);
format_bytes(pbuf, sizeof(pbuf), ptoa(physmem));
printf("%s used by NetBSD)\n", pbuf);
if (unusedmem) {
format_bytes(pbuf, sizeof(pbuf), ptoa(unusedmem));
printf("WARNING: unused memory = %s\n", pbuf);
}
if (unknownmem) {
format_bytes(pbuf, sizeof(pbuf), ptoa(unknownmem));
printf("WARNING: %s of memory with unknown purpose\n", pbuf);
}
minaddr = 0;
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, false, NULL);
#if defined(DEBUG)
pmapdebug = opmapdebug;
#endif
format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
printf("avail memory = %s\n", pbuf);
#if 0
{
extern u_long pmap_pages_stolen;
format_bytes(pbuf, sizeof(pbuf), pmap_pages_stolen * PAGE_SIZE);
printf("stolen memory for VM structures = %s\n", pbuf);
}
#endif
hwrpb_primary_init();
alpha_fp_init();
}
const char *
alpha_dsr_sysname(void)
{
struct dsrdb *dsr;
const char *sysname;
if (hwrpb->rpb_version < HWRPB_DSRDB_MINVERS)
return (NULL);
dsr = (struct dsrdb *)(((char *)hwrpb) + hwrpb->rpb_dsrdb_off);
sysname = (const char *)((char *)dsr + (dsr->dsr_sysname_off +
sizeof(uint64_t)));
return (sysname);
}
const char *
alpha_variation_name(uint64_t variation, const struct alpha_variation_table *avtp)
{
int i;
for (i = 0; avtp[i].avt_model != NULL; i++)
if (avtp[i].avt_variation == variation)
return (avtp[i].avt_model);
return (NULL);
}
const char *
alpha_unknown_sysname(void)
{
static char s[128];
snprintf(s, sizeof(s), "%s family, unknown model variation 0x%lx",
platform.family, hwrpb->rpb_variation & SV_ST_MASK);
return ((const char *)s);
}
void
identifycpu(void)
{
const char *s;
int i;
s = cpu_getmodel();
printf("%s", s);
for (; *s != '\0'; s++) {
if (strncasecmp(s, "MHz", 3) == 0) {
goto skipMHz;
}
}
printf(", %ldMHz", hwrpb->rpb_cc_freq / 1000000);
skipMHz:
for (i = 0; i < 10; i++) {
if (! isprint((unsigned char)hwrpb->rpb_ssn[i])) {
break;
}
if (i == 0) {
printf(", s/n ");
}
printf("%c", hwrpb->rpb_ssn[i]);
}
printf("\n");
printf("%ld byte page size, %d processor%s.\n",
hwrpb->rpb_page_size, ncpus, ncpus == 1 ? "" : "s");
}
int waittime = -1;
struct pcb dumppcb;
void
cpu_reboot(int howto, char *bootstr)
{
#if defined(MULTIPROCESSOR)
u_long cpu_id = cpu_number();
u_long wait_mask;
int i;
#endif
if ((boothowto & RB_HALT) != 0)
howto |= RB_HALT;
boothowto = howto;
if (cold) {
boothowto |= RB_HALT;
goto haltsys;
}
if ((boothowto & RB_NOSYNC) == 0 && waittime < 0) {
waittime = 0;
vfs_shutdown();
}
splhigh();
#if defined(MULTIPROCESSOR)
cpu_id = cpu_number();
wait_mask = (1UL << cpu_id) | (1UL << hwrpb->rpb_primary_cpu_id);
alpha_broadcast_ipi(ALPHA_IPI_HALT);
cpus_paused = 0;
for (i = 0; i < 10000; i++) {
alpha_mb();
if (cpus_running == wait_mask)
break;
delay(1000);
}
alpha_mb();
if (cpus_running != wait_mask)
printf("WARNING: Unable to halt secondary CPUs (0x%lx)\n",
cpus_running);
#endif
#if 0
if ((boothowto & (RB_DUMP | RB_HALT)) == RB_DUMP)
#else
if (boothowto & RB_DUMP)
#endif
dumpsys();
haltsys:
doshutdownhooks();
pmf_system_shutdown(boothowto);
#ifdef BOOTKEY
printf("hit any key to %s...\n", howto & RB_HALT ? "halt" : "reboot");
cnpollc(true);
cngetc();
cnpollc(false);
printf("\n");
#endif
if ((boothowto & RB_POWERDOWN) == RB_POWERDOWN &&
platform.powerdown != NULL) {
(*platform.powerdown)();
printf("WARNING: powerdown failed!\n");
}
printf("%s\n\n", (boothowto & RB_HALT) ? "halted." : "rebooting...");
#if defined(MULTIPROCESSOR)
if (cpu_id != hwrpb->rpb_primary_cpu_id)
cpu_halt();
else
#endif
prom_halt(boothowto & RB_HALT);
}
uint32_t dumpmag = 0x8fca0101;
int dumpsize = 0;
long dumplo = 0;
int
cpu_dumpsize(void)
{
int size;
size = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)) +
ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t));
if (roundup(size, dbtob(1)) != dbtob(1))
return -1;
return (1);
}
u_long
cpu_dump_mempagecnt(void)
{
u_long i, n;
n = 0;
for (i = 0; i < mem_cluster_cnt; i++)
n += atop(mem_clusters[i].size);
return (n);
}
int
cpu_dump(void)
{
int (*dump)(dev_t, daddr_t, void *, size_t);
char buf[dbtob(1)];
kcore_seg_t *segp;
cpu_kcore_hdr_t *cpuhdrp;
phys_ram_seg_t *memsegp;
const struct bdevsw *bdev;
int i;
bdev = bdevsw_lookup(dumpdev);
if (bdev == NULL)
return (ENXIO);
dump = bdev->d_dump;
memset(buf, 0, sizeof buf);
segp = (kcore_seg_t *)buf;
cpuhdrp = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(*segp))];
memsegp = (phys_ram_seg_t *)&buf[ ALIGN(sizeof(*segp)) +
ALIGN(sizeof(*cpuhdrp))];
CORE_SETMAGIC(*segp, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
segp->c_size = dbtob(1) - ALIGN(sizeof(*segp));
cpuhdrp->lev1map_pa = ALPHA_K0SEG_TO_PHYS((vaddr_t)kernel_lev1map);
cpuhdrp->page_size = PAGE_SIZE;
cpuhdrp->nmemsegs = mem_cluster_cnt;
for (i = 0; i < mem_cluster_cnt; i++) {
memsegp[i].start = mem_clusters[i].start;
memsegp[i].size = mem_clusters[i].size & ~PAGE_MASK;
}
return (dump(dumpdev, dumplo, (void *)buf, dbtob(1)));
}
void
cpu_dumpconf(void)
{
int nblks, dumpblks;
if (dumpdev == NODEV)
goto bad;
nblks = bdev_size(dumpdev);
if (nblks <= ctod(1))
goto bad;
dumpblks = cpu_dumpsize();
if (dumpblks < 0)
goto bad;
dumpblks += ctod(cpu_dump_mempagecnt());
if (dumpblks > (nblks - ctod(1)))
goto bad;
dumplo = nblks - dumpblks;
dumpsize = cpu_dump_mempagecnt();
return;
bad:
dumpsize = 0;
return;
}
#define BYTES_PER_DUMP PAGE_SIZE
void
dumpsys(void)
{
const struct bdevsw *bdev;
u_long totalbytesleft, bytes, i, n, memcl;
u_long maddr;
int psize;
daddr_t blkno;
int (*dump)(dev_t, daddr_t, void *, size_t);
int error;
savectx(&dumppcb);
if (dumpdev == NODEV)
return;
bdev = bdevsw_lookup(dumpdev);
if (bdev == NULL || bdev->d_psize == NULL)
return;
if (dumpsize == 0)
cpu_dumpconf();
if (dumplo <= 0) {
printf("\ndump to dev %u,%u not possible\n",
major(dumpdev), minor(dumpdev));
return;
}
printf("\ndumping to dev %u,%u offset %ld\n",
major(dumpdev), minor(dumpdev), dumplo);
psize = bdev_size(dumpdev);
printf("dump ");
if (psize == -1) {
printf("area unavailable\n");
return;
}
if ((error = cpu_dump()) != 0)
goto err;
totalbytesleft = ptoa(cpu_dump_mempagecnt());
blkno = dumplo + cpu_dumpsize();
dump = bdev->d_dump;
error = 0;
for (memcl = 0; memcl < mem_cluster_cnt; memcl++) {
maddr = mem_clusters[memcl].start;
bytes = mem_clusters[memcl].size & ~PAGE_MASK;
for (i = 0; i < bytes; i += n, totalbytesleft -= n) {
if ((totalbytesleft % (1024*1024)) == 0)
printf_nolog("%ld ",
totalbytesleft / (1024 * 1024));
n = bytes - i;
if (n > BYTES_PER_DUMP)
n = BYTES_PER_DUMP;
error = (*dump)(dumpdev, blkno,
(void *)ALPHA_PHYS_TO_K0SEG(maddr), n);
if (error)
goto err;
maddr += n;
blkno += btodb(n);
}
}
err:
switch (error) {
case ENXIO:
printf("device bad\n");
break;
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("area improper\n");
break;
case EIO:
printf("i/o error\n");
break;
case EINTR:
printf("aborted from console\n");
break;
case 0:
printf("succeeded\n");
break;
default:
printf("error %d\n", error);
break;
}
printf("\n\n");
delay(1000);
}
void
frametoreg(const struct trapframe *framep, struct reg *regp)
{
regp->r_regs[R_V0] = framep->tf_regs[FRAME_V0];
regp->r_regs[R_T0] = framep->tf_regs[FRAME_T0];
regp->r_regs[R_T1] = framep->tf_regs[FRAME_T1];
regp->r_regs[R_T2] = framep->tf_regs[FRAME_T2];
regp->r_regs[R_T3] = framep->tf_regs[FRAME_T3];
regp->r_regs[R_T4] = framep->tf_regs[FRAME_T4];
regp->r_regs[R_T5] = framep->tf_regs[FRAME_T5];
regp->r_regs[R_T6] = framep->tf_regs[FRAME_T6];
regp->r_regs[R_T7] = framep->tf_regs[FRAME_T7];
regp->r_regs[R_S0] = framep->tf_regs[FRAME_S0];
regp->r_regs[R_S1] = framep->tf_regs[FRAME_S1];
regp->r_regs[R_S2] = framep->tf_regs[FRAME_S2];
regp->r_regs[R_S3] = framep->tf_regs[FRAME_S3];
regp->r_regs[R_S4] = framep->tf_regs[FRAME_S4];
regp->r_regs[R_S5] = framep->tf_regs[FRAME_S5];
regp->r_regs[R_S6] = framep->tf_regs[FRAME_S6];
regp->r_regs[R_A0] = framep->tf_regs[FRAME_A0];
regp->r_regs[R_A1] = framep->tf_regs[FRAME_A1];
regp->r_regs[R_A2] = framep->tf_regs[FRAME_A2];
regp->r_regs[R_A3] = framep->tf_regs[FRAME_A3];
regp->r_regs[R_A4] = framep->tf_regs[FRAME_A4];
regp->r_regs[R_A5] = framep->tf_regs[FRAME_A5];
regp->r_regs[R_T8] = framep->tf_regs[FRAME_T8];
regp->r_regs[R_T9] = framep->tf_regs[FRAME_T9];
regp->r_regs[R_T10] = framep->tf_regs[FRAME_T10];
regp->r_regs[R_T11] = framep->tf_regs[FRAME_T11];
regp->r_regs[R_RA] = framep->tf_regs[FRAME_RA];
regp->r_regs[R_T12] = framep->tf_regs[FRAME_T12];
regp->r_regs[R_AT] = framep->tf_regs[FRAME_AT];
regp->r_regs[R_GP] = framep->tf_regs[FRAME_GP];
regp->r_regs[R_ZERO] = 0;
}
void
regtoframe(const struct reg *regp, struct trapframe *framep)
{
framep->tf_regs[FRAME_V0] = regp->r_regs[R_V0];
framep->tf_regs[FRAME_T0] = regp->r_regs[R_T0];
framep->tf_regs[FRAME_T1] = regp->r_regs[R_T1];
framep->tf_regs[FRAME_T2] = regp->r_regs[R_T2];
framep->tf_regs[FRAME_T3] = regp->r_regs[R_T3];
framep->tf_regs[FRAME_T4] = regp->r_regs[R_T4];
framep->tf_regs[FRAME_T5] = regp->r_regs[R_T5];
framep->tf_regs[FRAME_T6] = regp->r_regs[R_T6];
framep->tf_regs[FRAME_T7] = regp->r_regs[R_T7];
framep->tf_regs[FRAME_S0] = regp->r_regs[R_S0];
framep->tf_regs[FRAME_S1] = regp->r_regs[R_S1];
framep->tf_regs[FRAME_S2] = regp->r_regs[R_S2];
framep->tf_regs[FRAME_S3] = regp->r_regs[R_S3];
framep->tf_regs[FRAME_S4] = regp->r_regs[R_S4];
framep->tf_regs[FRAME_S5] = regp->r_regs[R_S5];
framep->tf_regs[FRAME_S6] = regp->r_regs[R_S6];
framep->tf_regs[FRAME_A0] = regp->r_regs[R_A0];
framep->tf_regs[FRAME_A1] = regp->r_regs[R_A1];
framep->tf_regs[FRAME_A2] = regp->r_regs[R_A2];
framep->tf_regs[FRAME_A3] = regp->r_regs[R_A3];
framep->tf_regs[FRAME_A4] = regp->r_regs[R_A4];
framep->tf_regs[FRAME_A5] = regp->r_regs[R_A5];
framep->tf_regs[FRAME_T8] = regp->r_regs[R_T8];
framep->tf_regs[FRAME_T9] = regp->r_regs[R_T9];
framep->tf_regs[FRAME_T10] = regp->r_regs[R_T10];
framep->tf_regs[FRAME_T11] = regp->r_regs[R_T11];
framep->tf_regs[FRAME_RA] = regp->r_regs[R_RA];
framep->tf_regs[FRAME_T12] = regp->r_regs[R_T12];
framep->tf_regs[FRAME_AT] = regp->r_regs[R_AT];
framep->tf_regs[FRAME_GP] = regp->r_regs[R_GP];
}
void
printregs(struct reg *regp)
{
int i;
for (i = 0; i < 32; i++)
printf("R%d:\t0x%016lx%s", i, regp->r_regs[i],
i & 1 ? "\n" : "\t");
}
void
regdump(struct trapframe *framep)
{
struct reg reg;
frametoreg(framep, ®);
reg.r_regs[R_SP] = alpha_pal_rdusp();
printf("REGISTERS:\n");
printregs(®);
}
void *
getframe(const struct lwp *l, int sig, int *onstack, size_t size, size_t align)
{
uintptr_t frame;
KASSERT((align & (align - 1)) == 0);
*onstack =
(l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
(SIGACTION(l->l_proc, sig).sa_flags & SA_ONSTACK) != 0;
if (*onstack)
frame = (uintptr_t)l->l_sigstk.ss_sp + l->l_sigstk.ss_size;
else
frame = (uintptr_t)alpha_pal_rdusp();
frame -= size;
frame &= ~(STACK_ALIGNBYTES | (align - 1));
return (void *)frame;
}
void
buildcontext(struct lwp *l, const void *catcher, const void *tramp, const void *fp)
{
struct trapframe *tf = l->l_md.md_tf;
tf->tf_regs[FRAME_RA] = (uint64_t)tramp;
tf->tf_regs[FRAME_PC] = (uint64_t)catcher;
tf->tf_regs[FRAME_T12] = (uint64_t)catcher;
alpha_pal_wrusp((unsigned long)fp);
}
void
sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
{
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
struct sigacts *ps = p->p_sigacts;
int onstack, sig = ksi->ksi_signo, error;
struct sigframe_siginfo *fp, frame;
struct trapframe *tf;
sig_t catcher = SIGACTION(p, ksi->ksi_signo).sa_handler;
tf = l->l_md.md_tf;
fp = getframe(l, ksi->ksi_signo, &onstack, sizeof(*fp), _Alignof(*fp));
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sendsig_siginfo(%d): sig %d ssp %p usp %p\n", p->p_pid,
sig, &onstack, fp);
#endif
memset(&frame, 0, sizeof(frame));
frame.sf_si._info = ksi->ksi_info;
frame.sf_uc.uc_flags = _UC_SIGMASK;
frame.sf_uc.uc_sigmask = *mask;
frame.sf_uc.uc_link = l->l_ctxlink;
frame.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK)
? _UC_SETSTACK : _UC_CLRSTACK;
sendsig_reset(l, sig);
mutex_exit(p->p_lock);
cpu_getmcontext(l, &frame.sf_uc.uc_mcontext, &frame.sf_uc.uc_flags);
error = copyout(&frame, fp, sizeof(frame));
mutex_enter(p->p_lock);
if (error != 0) {
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sendsig_siginfo(%d): copyout failed on sig %d\n",
p->p_pid, sig);
#endif
sigexit(l, SIGILL);
}
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sendsig_siginfo(%d): sig %d usp %p code %x\n",
p->p_pid, sig, fp, ksi->ksi_code);
#endif
tf->tf_regs[FRAME_A0] = sig;
tf->tf_regs[FRAME_A1] = (uint64_t)&fp->sf_si;
tf->tf_regs[FRAME_A2] = (uint64_t)&fp->sf_uc;
buildcontext(l,catcher,ps->sa_sigdesc[sig].sd_tramp,fp);
if (onstack)
l->l_sigstk.ss_flags |= SS_ONSTACK;
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sendsig_siginfo(%d): pc %lx, catcher %lx\n", p->p_pid,
tf->tf_regs[FRAME_PC], tf->tf_regs[FRAME_A3]);
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sendsig_siginfo(%d): sig %d returns\n",
p->p_pid, sig);
#endif
}
SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
{
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "machdep", NULL,
NULL, 0, NULL, 0,
CTL_MACHDEP, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRUCT, "console_device", NULL,
sysctl_consdev, 0, NULL, sizeof(dev_t),
CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "root_device", NULL,
sysctl_root_device, 0, NULL, 0,
CTL_MACHDEP, CPU_ROOT_DEVICE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "unaligned_print",
SYSCTL_DESCR("Warn about unaligned accesses"),
NULL, 0, &alpha_unaligned_print, 0,
CTL_MACHDEP, CPU_UNALIGNED_PRINT, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "unaligned_fix",
SYSCTL_DESCR("Fix up unaligned accesses"),
NULL, 0, &alpha_unaligned_fix, 0,
CTL_MACHDEP, CPU_UNALIGNED_FIX, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "unaligned_sigbus",
SYSCTL_DESCR("Do SIGBUS for fixed unaligned accesses"),
NULL, 0, &alpha_unaligned_sigbus, 0,
CTL_MACHDEP, CPU_UNALIGNED_SIGBUS, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "booted_kernel", NULL,
NULL, 0, bootinfo.booted_kernel, 0,
CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "fp_sync_complete", NULL,
NULL, 0, &alpha_fp_sync_complete, 0,
CTL_MACHDEP, CPU_FP_SYNC_COMPLETE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_INT, "cctr", NULL,
NULL, 0, &alpha_use_cctr, 0,
CTL_MACHDEP, CPU_CCTR, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_BOOL, "is_qemu", NULL,
NULL, 0, &alpha_is_qemu, 0,
CTL_MACHDEP, CPU_IS_QEMU, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "fp_complete_debug", NULL,
NULL, 0, &alpha_fp_complete_debug, 0,
CTL_MACHDEP, CPU_FP_COMPLETE_DEBUG, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_QUAD, "rpb_type", NULL,
NULL, 0, &hwrpb->rpb_type, 0,
CTL_MACHDEP, CPU_RPB_TYPE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_QUAD, "rpb_variation", NULL,
NULL, 0, &hwrpb->rpb_variation, 0,
CTL_MACHDEP, CPU_RPB_VARIATION, CTL_EOL);
}
void
setregs(register struct lwp *l, struct exec_package *pack, vaddr_t stack)
{
struct trapframe *tfp = l->l_md.md_tf;
struct pcb *pcb;
#ifdef DEBUG
int i;
#endif
#ifdef DEBUG
if (boothowto & RB_DUMP)
panic("crash requested by boot flags");
#endif
memset(tfp, 0, sizeof(*tfp));
#ifdef DEBUG
for (i = 0; i < FRAME_SIZE; i++)
tfp->tf_regs[i] = 0xbabefacedeadbeef;
#endif
pcb = lwp_getpcb(l);
memset(&pcb->pcb_fp, 0, sizeof(pcb->pcb_fp));
alpha_pal_wrusp(stack);
tfp->tf_regs[FRAME_PS] = ALPHA_PSL_USERSET;
tfp->tf_regs[FRAME_PC] = pack->ep_entry & ~3;
tfp->tf_regs[FRAME_A0] = stack;
tfp->tf_regs[FRAME_A1] = 0;
tfp->tf_regs[FRAME_A2] = 0;
tfp->tf_regs[FRAME_A3] = l->l_proc->p_psstrp;
tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC];
if (__predict_true((l->l_md.md_flags & IEEE_INHERIT) == 0)) {
l->l_md.md_flags =
(l->l_md.md_flags & ~(MDLWP_FP_C | MDLWP_FPACTIVE)) |
FP_C_DEFAULT;
pcb->pcb_fp.fpr_cr = FPCR_DEFAULT;
}
}
void (*alpha_delay_fn)(unsigned long);
void
delay(unsigned long n)
{
unsigned long pcc0, pcc1, curcycle, cycles, usec;
if (n == 0)
return;
if (alpha_delay_fn != NULL) {
(*alpha_delay_fn)(n);
return;
}
lwp_t * const l = curlwp;
KPREEMPT_DISABLE(l);
pcc0 = alpha_rpcc() & 0xffffffffUL;
cycles = 0;
usec = 0;
while (usec <= n) {
pcc1 = alpha_rpcc() & 0xffffffffUL;
if (pcc1 < pcc0)
curcycle = (pcc1 + 0x100000000UL) - pcc0;
else
curcycle = pcc1 - pcc0;
cycles += curcycle;
while (cycles > cycles_per_usec) {
usec++;
cycles -= cycles_per_usec;
}
pcc0 = pcc1;
}
KPREEMPT_ENABLE(l);
}
#ifdef EXEC_ECOFF
void
cpu_exec_ecoff_setregs(struct lwp *l, struct exec_package *epp, vaddr_t stack)
{
struct ecoff_exechdr *execp = (struct ecoff_exechdr *)epp->ep_hdr;
l->l_md.md_tf->tf_regs[FRAME_GP] = execp->a.gp_value;
}
int
cpu_exec_ecoff_probe(struct lwp *l, struct exec_package *epp)
{
struct ecoff_exechdr *execp = (struct ecoff_exechdr *)epp->ep_hdr;
int error;
if (execp->f.f_magic == ECOFF_MAGIC_NETBSD_ALPHA)
error = 0;
else
error = ENOEXEC;
return (error);
}
#endif
int
mm_md_physacc(paddr_t pa, vm_prot_t prot)
{
u_quad_t size;
int i;
for (i = 0; i < mem_cluster_cnt; i++) {
if (pa < mem_clusters[i].start)
continue;
size = mem_clusters[i].size & ~PAGE_MASK;
if (pa >= (mem_clusters[i].start + size))
continue;
if ((prot & mem_clusters[i].size & PAGE_MASK) == prot)
return 0;
}
return EFAULT;
}
bool
mm_md_direct_mapped_io(void *addr, paddr_t *paddr)
{
vaddr_t va = (vaddr_t)addr;
if (va >= ALPHA_K0SEG_BASE && va <= ALPHA_K0SEG_END) {
*paddr = ALPHA_K0SEG_TO_PHYS(va);
return true;
}
return false;
}
bool
mm_md_direct_mapped_phys(paddr_t paddr, vaddr_t *vaddr)
{
*vaddr = ALPHA_PHYS_TO_K0SEG(paddr);
return true;
}
void
cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
{
struct trapframe *frame = l->l_md.md_tf;
struct pcb *pcb = lwp_getpcb(l);
__greg_t *gr = mcp->__gregs;
__greg_t ras_pc;
frametoreg(frame, (struct reg *)gr);
if (l == curlwp) {
gr[_REG_SP] = alpha_pal_rdusp();
gr[_REG_UNIQUE] = alpha_pal_rdunique();
} else {
gr[_REG_SP] = pcb->pcb_hw.apcb_usp;
gr[_REG_UNIQUE] = pcb->pcb_hw.apcb_unique;
}
gr[_REG_PC] = frame->tf_regs[FRAME_PC];
gr[_REG_PS] = frame->tf_regs[FRAME_PS];
if ((ras_pc = (__greg_t)ras_lookup(l->l_proc,
(void *) gr[_REG_PC])) != -1)
gr[_REG_PC] = ras_pc;
*flags |= _UC_CPU | _UC_TLSBASE;
if (fpu_valid_p(l)) {
fpu_save(l);
(void)memcpy(&mcp->__fpregs, &pcb->pcb_fp,
sizeof (mcp->__fpregs));
mcp->__fpregs.__fp_fpcr = alpha_read_fp_c(l);
*flags |= _UC_FPU;
}
}
int
cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
{
const __greg_t *gr = mcp->__gregs;
if ((gr[_REG_PS] & ALPHA_PSL_USERSET) != ALPHA_PSL_USERSET ||
(gr[_REG_PS] & ALPHA_PSL_USERCLR) != 0)
return EINVAL;
return 0;
}
int
cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
{
struct trapframe *frame = l->l_md.md_tf;
struct pcb *pcb = lwp_getpcb(l);
const __greg_t *gr = mcp->__gregs;
int error;
if (flags & _UC_CPU) {
error = cpu_mcontext_validate(l, mcp);
if (error)
return error;
regtoframe((const struct reg *)gr, l->l_md.md_tf);
if (l == curlwp)
alpha_pal_wrusp(gr[_REG_SP]);
else
pcb->pcb_hw.apcb_usp = gr[_REG_SP];
frame->tf_regs[FRAME_PC] = gr[_REG_PC];
frame->tf_regs[FRAME_PS] = gr[_REG_PS];
}
if (flags & _UC_TLSBASE)
lwp_setprivate(l, (void *)(uintptr_t)gr[_REG_UNIQUE]);
if (flags & _UC_FPU) {
fpu_discard(l, true);
(void)memcpy(&pcb->pcb_fp, &mcp->__fpregs,
sizeof (pcb->pcb_fp));
l->l_md.md_flags = mcp->__fpregs.__fp_fpcr & MDLWP_FP_C;
}
mutex_enter(l->l_proc->p_lock);
if (flags & _UC_SETSTACK)
l->l_sigstk.ss_flags |= SS_ONSTACK;
if (flags & _UC_CLRSTACK)
l->l_sigstk.ss_flags &= ~SS_ONSTACK;
mutex_exit(l->l_proc->p_lock);
return (0);
}
static void
cpu_kick(struct cpu_info * const ci)
{
#if defined(MULTIPROCESSOR)
alpha_send_ipi(ci->ci_cpuid, ALPHA_IPI_AST);
#endif
}
void
cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags)
{
KASSERT(kpreempt_disabled());
if ((flags & RESCHED_IDLE) != 0) {
return;
}
KASSERT((flags & RESCHED_UPREEMPT) != 0);
if ((flags & RESCHED_REMOTE) != 0) {
cpu_kick(ci);
} else {
aston(l);
}
}
void
cpu_signotify(struct lwp *l)
{
KASSERT(kpreempt_disabled());
if (l->l_cpu != curcpu()) {
cpu_kick(l->l_cpu);
} else {
aston(l);
}
}
void
cpu_need_proftick(struct lwp *l)
{
KASSERT(kpreempt_disabled());
KASSERT(l->l_cpu == curcpu());
l->l_pflag |= LP_OWEUPC;
aston(l);
}