vtrap.c revision 30f5cf21f0e4186919b67ac48223d09ca110f8fe
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Contains the set of routines that implement the bootops and bsyscall
* vectors for a 64-bit client program.
*/
#include <sys/controlregs.h>
#include <sys/bootsvcs.h>
#include <amd64/bootops64.h>
#include <amd64/bootsvcs64.h>
#include <amd64/machregs.h>
#include <amd64/amd64_page.h>
#if defined(DEBUG)
/* AMD64_TRACE_BOP_VM | XX64 - also too chatty */
/* AMD64_TRACE_BOP_PROP | XX64 - also too chatty */
/* AMD64_TRACE_BOP_BIOS | XX64 - final vestiges of chattyness */
#endif
0;
/*
* Memory page set aside for translation of boot's memory lists into
* "struct memlist64" format
*/
struct memlist64 *amd64_memlistpage;
static void
{
}
static void
{
}
static void
{
}
static const char *
{
switch (type) {
case T_ZERODIV: return ("Divide error (#de)");
case T_SGLSTP: return ("Debug (#db)");
case T_NMIFLT: return ("NMI interrupt");
case T_BPTFLT: return ("Breakpoint (#bp)");
case T_OVFLW: return ("Overflow (#of)");
case T_BOUNDFLT: return ("BOUND range exceeded (#br)");
case T_ILLINST: return ("Invalid opcode (#ud)");
case T_NOEXTFLT: return ("Device not available (#nm)");
case T_DBLFLT: return ("Double fault (#df)");
case T_EXTOVRFLT: return ("(i386 only reserved trap (9))");
case T_TSSFLT: return ("Invalid TSS (#ts)");
case T_SEGFLT: return ("Segment not present (#np)");
case T_STKFLT: return ("Stack segment fault (#ss)");
case T_GPFLT: return ("General protection (#gp)");
case T_PGFLT: return ("Page fault (#pf)");
case 15: return ("Intel reserved trap (15)");
case T_EXTERRFLT: return ("x87 floating point error (#mf)");
case T_ALIGNMENT: return ("Alignment check (#ac)");
case T_MCE: return ("Machine check (#mc)");
case T_SIMDFPE: return ("SIMD floating point exception (#xf)");
default:
/*
* see r_trapno for type. Sorry but amd64
* does not support sprtintf().
*/
return ("reserved, external or soft int");
}
}
/*
* (When we need to get more ambitious with this, we
* can climb the long-mode stack to see how we got here..)
*/
/*PRINTFLIKE2*/
static void
{
}
/*
* We took a real exception thru amd64's IDT.
* Dump state and reset machine.
*/
static void
{
printf("AMD64_BAD_TRAP: %s error=0x%llx\n\n",
printf("resetting ...");
/*NOTREACHED*/
}
extern struct boot_syscalls *entry_boot_syscalls;
#ifdef DEBUG
static void
{
amd64_panic("%s(): unexpected address for %s\n"
" (expected 0x%llx, passed 0x%llx)\n", caller_name,
}
static int
{
amd64_get_cr3()))) {
printf("ERROR: %s(): called with unmapped 32-bit %s @ "
addr);
return (0);
}
return (1);
}
static int
{
type));
}
#endif /* DEBUG */
static void
struct amd64_machregs *rp,
{
extern uint64_t amd64_boot_pml4;
enum tracetype {
} trace = TRACE_NONE_RETURN;
void *retval;
amd64_panic("bop64_alloc() called with wrong 64-bit "
"page table start address\n (caller's cr3: "
if (bop64_trace & AMD64_TRACE_BOP_VM) {
}
#ifdef DEBUG
#endif /* DEBUG */
if (retval != 0)
amd64_panic("bop64_free() called with wrong 64-bit "
"page table start address\n (caller's cr3: "
if (bop64_trace & AMD64_TRACE_BOP_VM) {
}
#ifdef DEBUG
#endif /* DEBUG */
/*
* The property routines are mostly pass-through, but
* we take steps to hide our existence, so that the
* 64-bit kernel really does think it's talking to
* a native booter
*
* XX64 The "real" version of 'whoami' handling should be
* done in boot -- if that booter is asked to boot an
* EM_AMD64 file, it should know to put stretch into
* memory, then tell stretch and the kernel to boot
* that program, then we wouldn't need to fib here,
* because boot would be fibbing for us.
*/
if (bop64_trace & AMD64_TRACE_BOP_PROP) {
}
#ifdef DEBUG
"property name")) {
return_int(rp, 0);
return;
}
#endif /* DEBUG */
} else
if (bop64_trace & AMD64_TRACE_BOP_PROP) {
}
#ifdef DEBUG
"property name")) {
return;
}
/*
* amd64_check_arg() can't be used here because krtld
* does a bop_getprop("whoami") with a buffer that is in stack
* space allocated just above AMD64 in memory, typically on the
* page mapped at 0x100f000), so just check to make sure the
* destination buffer is mapped in a way we can access.
*/
"BOP_GETPROP", "property value buffer")) {
return;
}
#endif /* DEBUG */
int retval;
(void) amd64_update_ml64(bop);
return_int(rp, 0);
} else
if (bop64_trace & AMD64_TRACE_BOP_PROP) {
static const char *string_props[] = {
"backfs-fstype",
"backfs-path",
"bootargs",
"bootpath",
"boot-path",
"boot-message",
"default-name",
"extent",
"frontfs-fstype",
"frontfs-path",
"fstype",
"impl-arch-name",
"mfg-name",
"whoami",
0
};
const char * const *sp;
/*
* (Sigh. This is a rather tawdry hack so that
* we can print out various "well-known" string
* properties as strings.)
*/
break;
}
printf("\n");
}
if (bop64_trace & AMD64_TRACE_BOP_PROP) {
}
#ifdef DEBUG
"BOP_NEXTPROP", "previous property")) {
return_addr(rp, 0);
return;
}
#endif /* DEBUG */
char lnbuf[128];
int lnlen;
#if 0 /* correct code */
#else /* XX64 */
/*
* Technically an ABI violation, gcc 3.2.3 currently
* only does a "mov $0, al" before calling printf, with
* the result that we tripped over this assert due to garbage
* in the upper 8 bytes of what would be ax.
*/
#endif
#ifdef DEBUG
"BOP_PRINTF", "fmt string"))
return;
#endif /* DEBUG */
/*
* (Looks like the -kernel- only does this for pci_check()
*/
if (bop64_trace & AMD64_TRACE_BOP_BIOS) {
printf("+doint(intnum %d "
}
#ifdef DEBUG
"regs"))
return;
#endif /* DEBUG */
void *retval;
amd64_panic("bop64_ealloc() called with wrong 64-bit "
"page table start address\n (caller's cr3: "
if (bop64_trace & AMD64_TRACE_BOP_VM) {
flags);
}
#ifdef DEBUG
if (vahint)
"vahint");
#endif /* DEBUG */
/*
* Don't attempt to create 64-bit mappings for purely physical
* memory reservations or for failed allocations,
*/
if (flags & BOPF_X86_ALLOC_PHYS)
else {
if (retval != 0)
}
} else
switch (trace) {
case TRACE_NONE_RETURN:
break;
case TRACE_INT_RETURN:
break;
case TRACE_ADDR_RETURN:
break;
case TRACE_VOID_RETURN:
printf(" = (void)\n");
break;
}
}
static struct bsys_mem64 *
{
struct memlist64 *);
/*
* amd64_convert_memlist() returns a pointer to the entry one past the
* previous translated list, suitable for the start of the next new
* memlist64, so the assignments below may seem a bit non-intuitive
* at first...
*/
return (bop_ml64);
}
static struct bootops *saved_bootops;
/*
* This is the 64-bit bootops vector that we hand to the 64-bit standalone
*/
struct bootops64 *
{
{ \
}
/* move to main.c or to startup */
amd64_memlistpage = (struct memlist64 *)
saved_bootops = bop;
return (bop64);
}
static void
struct amd64_machregs *rp,
struct boot_syscalls *bsys,
struct boot_syscalls64 *bsys64)
{
} else
}
static struct boot_syscalls *saved_boot_syscallp;
/*
* Return the 64-bit bsyscall vector that we hand to the 64-bit standalone
*/
struct boot_syscalls64 *
{
/*
* This variable is awful; the 'bsys' pointer should be
* the first argument to every bsys handler .. but in the
* meantime, this'll do.
*/
{ \
}
return (bsys64);
}
static void dump_desctbr(const char *, desctbr_t *);
static void dump_desctbr64(const char *, desctbr64_t *);
/*
* After stashing machine state we must convert the tss gdt entry from
* busy to available type.
*/
/*ARGSUSED*/
void
{
#if 0
}
#endif
}
static void
{
}
}
void
{
/*
* __vtrap_common always sets r_trapno to -1
*/
}
} else {
/*
* we took a real exception.
*/
}
}
static const char *
{
switch (type) {
case SDT_SYSNULL:
case SDT_SYSNULL2:
case SDT_SYSNULL3:
case SDT_SYSNULL4: return ("illegal");
case SDT_SYS286TSS: return ("16-bit tss");
case SDT_SYSLDT: return ("ldt");
case SDT_SYS286BSY: return ("16-bit tss busy");
case SDT_SYS286CGT: return ("16-bit call gate");
case SDT_SYSTASKGT: return ("task gate");
case SDT_SYS286IGT: return ("16-bit intr gate");
case SDT_SYS286TGT: return ("16-bit trap gate");
case SDT_SYSTSS: return ("32-bit tss");
case SDT_SYSTSSBSY: return ("32-bit tss busy");
case SDT_SYSCGT: return ("32-bit call gate");
case SDT_SYSIGT: return ("32-bit intr gate");
case SDT_SYSTGT: return ("32-bit trap gate");
case SDT_MEMRO: return ("r-- --");
case SDT_MEMROA: return ("r-- -a");
case SDT_MEMRW: return ("rw- --");
case SDT_MEMRWA: return ("rw- -a");
case SDT_MEMROD: return ("r-- d-");
case SDT_MEMRODA: return ("r-- da");
case SDT_MEMRWD: return ("rw- d-");
case SDT_MEMRWDA: return ("rw- da");
case SDT_MEME: return ("--x --");
case SDT_MEMEA: return ("--x -a");
case SDT_MEMER: return ("r-x --");
case SDT_MEMERA: return ("r-x -a");
case SDT_MEMEC: return ("--x c-");
case SDT_MEMEAC: return ("--x ca");
case SDT_MEMERC: return ("r-x c-");
case SDT_MEMERAC: return ("r-x ca");
default: return ("(unknown)");
}
}
static size_t
{
switch (type) {
case SDT_SYSTASKGT: {
printf("tss sel 0x%x dpl %d %spresent\n",
return (sizeof (*sgd));
}
case SDT_SYSLDT:
case SDT_SYSTSS:
case SDT_SYSTSSBSY: {
printf("base 0x%x lim 0x%x dpl %d %spresent\n",
return (sizeof (*ssd));
}
case SDT_SYSCGT:
case SDT_SYSIGT:
case SDT_SYSTGT: {
printf("target 0x%x:0x%x dpl %d %spresent",
if (type == SDT_SYSCGT)
printf("\n");
return (sizeof (*sgd));
}
case SDT_MEMRO:
case SDT_MEMROA:
case SDT_MEMRW:
case SDT_MEMRWA:
case SDT_MEMROD:
case SDT_MEMRODA:
case SDT_MEMRWD:
case SDT_MEMRWDA:
case SDT_MEME:
case SDT_MEMEA:
case SDT_MEMER:
case SDT_MEMERA:
case SDT_MEMEC:
case SDT_MEMEAC:
case SDT_MEMERC:
case SDT_MEMERAC: {
printf("base 0x%x lim 0x%x dpl %d %spresent\n",
return (sizeof (*usd));
}
default: {
printf("0x%x.%x.%x.%x dpl %d %spresent\n",
return (sizeof (*ssd));
}
}
}
static void
{
printf(" %s [limit %x base %x]\n",
/*
* Hack to print only the hardware entries in the idt
*/
return;
}
}
static void
{
static const char fmt1[] = " %8s %16x\n ";
printf("<null selector>\n");
printf("<selector out of range?>\n");
else {
}
}
void
{
static const char fmt1[] = " %8s %16x\n";
static const char fmt2[] = " %8s %16x %8s %16x\n";
static const char fmtb[] = " %8s %16b\n";
#if defined(__GNUC__)
#else
#endif
printf("}\n");
}
static const char *
{
switch (type) {
case SDT_SYSNULL:
case SDT_SYS286TSS:
case SDT_SYS286BSY:
case SDT_SYS286CGT:
case SDT_SYSTASKGT:
case SDT_SYS286IGT:
case SDT_SYS286TGT:
case SDT_SYSNULL2:
case SDT_SYSNULL3:
case SDT_SYSNULL4: return ("illegal");
case SDT_SYSLDT: return ("64-bit ldt");
case SDT_SYSTSS: return ("64-bit tss");
case SDT_SYSTSSBSY: return ("64-bit tss busy");
case SDT_SYSCGT: return ("64-bit call gate");
case SDT_SYSIGT: return ("64-bit intr gate");
case SDT_SYSTGT: return ("64-bit trap gate");
case SDT_MEMRO: return ("r-- --");
case SDT_MEMROA: return ("r-- -a");
case SDT_MEMRW: return ("rw- --");
case SDT_MEMRWA: return ("rw- -a");
case SDT_MEMROD: return ("r-- d-");
case SDT_MEMRODA: return ("r-- da");
case SDT_MEMRWD: return ("rw- d-");
case SDT_MEMRWDA: return ("rw- da");
case SDT_MEME: return ("--x --");
case SDT_MEMEA: return ("--x -a");
case SDT_MEMER: return ("r-x --");
case SDT_MEMERA: return ("r-x -a");
case SDT_MEMEC: return ("--x c-");
case SDT_MEMEAC: return ("--x ca");
case SDT_MEMERC: return ("r-x c-");
case SDT_MEMERAC: return ("r-x ca");
default: return ("(unknown)");
}
}
static size_t
dump_ssd64(void *desc)
{
switch (type) {
case SDT_SYSLDT:
case SDT_SYSTSS:
case SDT_SYSTSSBSY: {
" lim 0x%x dpl %d %spresent\n",
amd64_warning("zero1 field 0x%x zero2 field "
return (sizeof (*ssd));
}
case SDT_SYSCGT:
case SDT_SYSIGT:
case SDT_SYSTGT: {
amd64_warning("zero field 0x%x\n",
return (sizeof (*sgd));
}
case SDT_MEMRO:
case SDT_MEMROA:
case SDT_MEMRW:
case SDT_MEMRWA:
case SDT_MEMROD:
case SDT_MEMRODA:
case SDT_MEMRWD:
case SDT_MEMRWDA: {
return (sizeof (*usd));
}
case SDT_MEME:
case SDT_MEMEA:
case SDT_MEMER:
case SDT_MEMERA:
case SDT_MEMEC:
case SDT_MEMEAC:
case SDT_MEMERC:
case SDT_MEMERAC: {
printf("%sconforming, dpl %d, %spresent, "
"long %d, defopsz %d\n",
amd64_warning("both the L and D bit are "
"set!\n");
return (sizeof (*usd));
}
default:
printf("\n");
return (sizeof (struct user_segment_descriptor64));
}
}
static void
{
/*
* Hack to print only the hardware entries in the idt
*/
return;
}
}
static void
{
static const char fmt1[] = " %8s %16x\n ";
printf("<null selector>\n");
printf("<selector out of range?>\n");
else {
}
}
void
{
static const char fmtb[] = " %8s %16b\n";
#if !defined(__GNUC__)
#endif
printf("}\n");
}