#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/machsystm.h>
#include <sys/machparam.h>
#include <sys/cmn_err.h>
#include <sys/cpuvar.h>
#include <sys/note.h>
#include <sys/hypervisor_api.h>
#include <sys/lpad.h>
typedef struct {
uint64_t inuse;
uint64_t buf[LPAD_SIZE / sizeof (uint64_t)];
} lpad_t;
#define LPAD_POOL_SIZE 1
static lpad_t lpad_pool[LPAD_POOL_SIZE];
#ifdef DEBUG
static int lpad_dbg = 0;
#define LPAD_DBG if (lpad_dbg) printf
#define LPAD_DUMP_DATA lpad_dump_data
static void lpad_dump_data(uint64_t *lpd_start, uint64_t *lpd_end);
#else
#define LPAD_DBG _NOTE(CONSTCOND) if (0) printf
#define LPAD_DUMP_DATA
#endif
extern void mach_cpu_startup(uint64_t rabase, uint64_t memsize);
extern void mach_cpu_startup_end(void);
extern int promif_in_cif(void);
static lpad_t *lpad_alloc(void);
uint64_t *
lpad_setup(int cpuid, uint64_t pc, uint64_t arg)
{
lpad_t *lpp;
uint64_t textsz;
uint64_t datasz;
lpad_data_t *lpd;
lpad_map_t *lpm;
extern caddr_t textva;
extern caddr_t datava;
extern tte_t ktext_tte;
extern tte_t kdata_tte;
extern caddr_t mmu_fault_status_area;
LPAD_DBG("lpad_setup...\n");
if ((cpuid < 0) || (cpuid > NCPU)) {
cmn_err(CE_PANIC, "lpad_setup: invalid cpuid");
}
if ((lpp = lpad_alloc()) == NULL) {
cmn_err(CE_PANIC, "lpad_setup: unable to allocate lpad");
}
textsz = (uint64_t)mach_cpu_startup_end - (uint64_t)mach_cpu_startup;
LPAD_DBG("lpad textsz=%ld\n", textsz);
ASSERT(textsz <= LPAD_TEXT_SIZE);
bcopy((void *)mach_cpu_startup, lpp->buf, textsz);
lpd = (lpad_data_t *)(((caddr_t)lpp->buf) + LPAD_TEXT_SIZE);
lpm = (lpad_map_t *)lpd->map;
ASSERT(mmu_fault_status_area);
bzero(lpd, LPAD_TEXT_SIZE);
lpd->magic = LPAD_MAGIC_VAL;
lpd->inuse = &(lpp->inuse);
lpd->mmfsa_ra = va_to_pa(mmu_fault_status_area) + (MMFSA_SIZE * cpuid);
lpd->pc = pc;
lpd->arg = arg;
lpd->nmap = 3;
datasz = sizeof (lpad_data_t);
datasz += (lpd->nmap - 1) * sizeof (lpad_map_t);
ASSERT(datasz <= LPAD_DATA_SIZE);
lpm->va = (uint64_t)textva;
lpm->tte = ktext_tte;
lpm->flag_mmuflags = (MAP_ITLB | MAP_DTLB);
lpm->flag_perm = 1;
lpm++;
lpm->va = (uint64_t)datava;
lpm->tte = kdata_tte;
lpm->flag_mmuflags = MAP_DTLB;
lpm->flag_perm = 1;
lpm++;
lpm->va = (uint64_t)datava;
lpm->tte = kdata_tte;
lpm->flag_mmuflags = MAP_ITLB;
lpm->flag_perm = 0;
lpm++;
ASSERT(((uint64_t)lpm - (uint64_t)lpd) == datasz);
LPAD_DBG("copied %ld bytes of data into lpad\n", datasz);
LPAD_DUMP_DATA((uint64_t *)lpd, (uint64_t *)lpm);
return (lpp->buf);
}
static lpad_t *
lpad_alloc(void)
{
int idx;
ASSERT(promif_in_cif());
for (;;) {
LPAD_DBG("checking lpad pool:\n");
for (idx = 0; idx < LPAD_POOL_SIZE; idx++) {
LPAD_DBG("\tchecking lpad_pool[%d]\n", idx);
if (lpad_pool[idx].inuse == 0) {
LPAD_DBG("found empty lpad (%d)\n", idx);
lpad_pool[idx].inuse = 1;
return (&lpad_pool[idx]);
}
}
}
}
#ifdef DEBUG
static void
lpad_dump_data(uint64_t *lpd_start, uint64_t *lpd_end)
{
uint64_t *lp;
uint_t offset = 0;
if (lpad_dbg == 0)
return;
printf("lpad data:\n");
for (lp = lpd_start; lp < lpd_end; lp++) {
printf("\t0x%02x 0x%016lx\n", offset, *lp);
offset += sizeof (uint64_t);
}
}
#endif