Index: sun4v/Makefile =================================================================== RCS file: sun4v/Makefile diff -N sun4v/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/Makefile 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= boot1 loader + +.include Index: sun4v/Makefile.inc =================================================================== RCS file: sun4v/Makefile.inc diff -N sun4v/Makefile.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/Makefile.inc 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,5 @@ +# $FreeBSD$ + +BINDIR?= /boot +CFLAGS+= -ffreestanding +LDFLAGS+= -nostdlib Index: sun4v/boot1/Makefile =================================================================== RCS file: sun4v/boot1/Makefile diff -N sun4v/boot1/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/boot1/Makefile 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PROG= boot1.elf +INTERNALPROG= +NO_MAN= +FILES= boot1 +SRCS= _start.s boot1.c + +BOOTBLOCKBASE= 0x4000 + +CFLAGS= -mcmodel=medlow -Os -I${.CURDIR}/../../common +LDFLAGS=-N -Ttext ${BOOTBLOCKBASE} + +# Construct boot1. sunlabel expects it to contain zeroed-out space for the +# label, and to be of the correct size. +boot1: boot1.aout + dd if=/dev/zero of=${.TARGET} bs=512 count=16 + dd if=boot1.aout of=${.TARGET} bs=512 oseek=1 conv=notrunc + +CLEANFILES= boot1.aout + +boot1.aout: boot1.elf + elf2aout -o ${.TARGET} ${.ALLSRC} + +boot1.o: ${.CURDIR}/../../common/ufsread.c + +.include Index: sun4v/boot1/_start.s =================================================================== RCS file: sun4v/boot1/_start.s diff -N sun4v/boot1/_start.s --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/boot1/_start.s 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,10 @@ +/* + * $FreeBSD$ + */ + + .text + .globl _start +_start: + call ofw_init + nop + sir Index: sun4v/boot1/_start.s~ =================================================================== RCS file: sun4v/boot1/_start.s~ diff -N sun4v/boot1/_start.s~ --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/boot1/_start.s~ 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,8 @@ +/* $FreeBSD$ + + .text + .globl _start +_start: + call ofw_init + nop + sir Index: sun4v/boot1/boot1.c =================================================================== RCS file: sun4v/boot1/boot1.c diff -N sun4v/boot1/boot1.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/boot1/boot1.c 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,664 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * Copyright (c) 2001 Robert Drehmel + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#define _PATH_LOADER "/boot/loader" +#define _PATH_KERNEL "/boot/kernel/kernel" + +#define BSIZEMAX 16384 + +typedef int putc_func_t(int c, void *arg); +typedef int32_t ofwh_t; + +struct sp_data { + char *sp_buf; + u_int sp_len; + u_int sp_size; +}; + +static const char digits[] = "0123456789abcdef"; + +static char bootpath[128]; +static char bootargs[128]; + +static ofwh_t bootdev; + +static struct fs fs; +static ino_t inomap; +static char blkbuf[BSIZEMAX]; +static unsigned int fsblks; + +static uint32_t fs_off; + +int main(int ac, char **av); + +static void exit(int) __dead2; +static void load(const char *); +static int dskread(void *, u_int64_t, int); + +static void usage(void); + +static void bcopy(const void *src, void *dst, size_t len); +static void bzero(void *b, size_t len); + +static int mount(const char *device); + +static void panic(const char *fmt, ...) __dead2; +static int printf(const char *fmt, ...); +static int putchar(int c, void *arg); +static int vprintf(const char *fmt, va_list ap); +static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); + +static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); +static int __putc(int c, void *arg); +static int __puts(const char *s, putc_func_t *putc, void *arg); +static int __sputc(int c, void *arg); +static char *__uitoa(char *buf, u_int val, int base); +static char *__ultoa(char *buf, u_long val, int base); + +/* + * Open Firmware interface functions + */ +typedef u_int64_t ofwcell_t; +typedef u_int32_t u_ofwh_t; +typedef int (*ofwfp_t)(ofwcell_t []); +ofwfp_t ofw; /* the prom Open Firmware entry */ + +void ofw_init(int, int, int, int, ofwfp_t); +ofwh_t ofw_finddevice(const char *); +ofwh_t ofw_open(const char *); +int ofw_getprop(ofwh_t, const char *, void *, size_t); +int ofw_read(ofwh_t, void *, size_t); +int ofw_write(ofwh_t, const void *, size_t); +int ofw_seek(ofwh_t, u_int64_t); +void ofw_exit(void) __dead2; + +ofwh_t bootdevh; +ofwh_t stdinh, stdouth; + +/* + * This has to stay here, as the PROM seems to ignore the + * entry point specified in the a.out header. (or elftoaout is broken) + */ + +void +ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) +{ + ofwh_t chosenh; + char *av[16]; + char *p; + int ac; + + ofw = ofwaddr; + + chosenh = ofw_finddevice("/chosen"); + ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); + ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); + ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs)); + ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); + + bootargs[sizeof(bootargs) - 1] = '\0'; + bootpath[sizeof(bootpath) - 1] = '\0'; + + ac = 0; + p = bootargs; + for (;;) { + while (*p == ' ' && *p != '\0') + p++; + if (*p == '\0' || ac >= 16) + break; + av[ac++] = p; + while (*p != ' ' && *p != '\0') + p++; + if (*p != '\0') + *p++ = '\0'; + } + + exit(main(ac, av)); +} + +ofwh_t +ofw_finddevice(const char *name) +{ + ofwcell_t args[] = { + (ofwcell_t)"finddevice", + 1, + 1, + (ofwcell_t)name, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_finddevice: name=\"%s\"\n", name); + return (1); + } + return (args[4]); +} + +int +ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"getprop", + 4, + 1, + (u_ofwh_t)ofwh, + (ofwcell_t)name, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", + ofwh, buf, len); + return (1); + } + return (0); +} + +ofwh_t +ofw_open(const char *path) +{ + ofwcell_t args[] = { + (ofwcell_t)"open", + 1, + 1, + (ofwcell_t)path, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_open: path=\"%s\"\n", path); + return (-1); + } + return (args[4]); +} + +int +ofw_close(ofwh_t devh) +{ + ofwcell_t args[] = { + (ofwcell_t)"close", + 1, + 0, + (u_ofwh_t)devh + }; + + if ((*ofw)(args)) { + printf("ofw_close: devh=0x%x\n", devh); + return (1); + } + return (0); +} + +int +ofw_read(ofwh_t devh, void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"read", + 4, + 1, + (u_ofwh_t)devh, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); + return (1); + } + return (0); +} + +int +ofw_write(ofwh_t devh, const void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"write", + 3, + 1, + (u_ofwh_t)devh, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); + return (1); + } + return (0); +} + +int +ofw_seek(ofwh_t devh, u_int64_t off) +{ + ofwcell_t args[] = { + (ofwcell_t)"seek", + 4, + 1, + (u_ofwh_t)devh, + off >> 32, + off, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); + return (1); + } + return (0); +} + +void +ofw_exit(void) +{ + ofwcell_t args[3]; + + args[0] = (ofwcell_t)"exit"; + args[1] = 0; + args[2] = 0; + + for (;;) + (*ofw)(args); +} + +static void +bcopy(const void *src, void *dst, size_t len) +{ + const char *s = src; + char *d = dst; + + while (len-- != 0) + *d++ = *s++; +} + +static void +memcpy(void *dst, const void *src, size_t len) +{ + bcopy(src, dst, len); +} + +static void +bzero(void *b, size_t len) +{ + char *p = b; + + while (len-- != 0) + *p++ = 0; +} + +static int +strcmp(const char *s1, const char *s2) +{ + for (; *s1 == *s2 && *s1; s1++, s2++) + ; + return ((u_char)*s1 - (u_char)*s2); +} + +#include "ufsread.c" + +int +main(int ac, char **av) +{ + const char *path; + int i; + + path = _PATH_LOADER; + for (i = 0; i < ac; i++) { + switch (av[i][0]) { + case '-': + switch (av[i][1]) { + default: + usage(); + } + break; + default: + path = av[i]; + break; + } + } + + printf(" \n>> FreeBSD/sparc64 boot block\n" + " Boot path: %s\n" + " Boot loader: %s\n", bootpath, path); + + if (mount(bootpath) == -1) + panic("mount"); + + load(path); + return (1); +} + +static void +usage(void) +{ + + printf("usage: boot device [/path/to/loader]\n"); + exit(1); +} + +static void +exit(int code) +{ + + ofw_exit(); +} + +static struct dmadat __dmadat; + +static int +mount(const char *device) +{ + + dmadat = &__dmadat; + if ((bootdev = ofw_open(device)) == -1) { + printf("mount: can't open device\n"); + return (-1); + } + if (fsread(0, NULL, 0)) { + printf("mount: can't read superblock\n"); + return (-1); + } + return (0); +} + +static void +load(const char *fname) +{ + Elf64_Ehdr eh; + Elf64_Phdr ph; + caddr_t p; + ino_t ino; + int i; + + if ((ino = lookup(fname)) == 0) { + printf("File %s not found\n", fname); + return; + } + if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { + printf("Can't read elf header\n"); + return; + } + if (!IS_ELF(eh)) { + printf("Not an ELF file\n"); + return; + } + for (i = 0; i < eh.e_phnum; i++) { + fs_off = eh.e_phoff + i * eh.e_phentsize; + if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { + printf("Can't read program header %d\n", i); + return; + } + if (ph.p_type != PT_LOAD) + continue; + fs_off = ph.p_offset; + p = (caddr_t)ph.p_vaddr; + if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { + printf("Can't read content of section %d\n", i); + return; + } + if (ph.p_filesz != ph.p_memsz) + bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); + } + ofw_close(bootdev); + (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); +} + +static int +dskread(void *buf, u_int64_t lba, int nblk) +{ + /* + * The Open Firmware should open the correct partition for us. + * That means, if we read from offset zero on an open instance handle, + * we should read from offset zero of that partition. + */ + ofw_seek(bootdev, lba * DEV_BSIZE); + ofw_read(bootdev, buf, nblk * DEV_BSIZE); + return (0); +} + +static void +panic(const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof buf, fmt, ap); + printf("panic: %s\n", buf); + va_end(ap); + + exit(1); +} + +static int +printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vprintf(fmt, ap); + va_end(ap); + return (ret); +} + +static int +putchar(int c, void *arg) +{ + char buf; + + if (c == '\n') { + buf = '\r'; + ofw_write(stdouth, &buf, 1); + } + buf = c; + ofw_write(stdouth, &buf, 1); + return (1); +} + +static int +vprintf(const char *fmt, va_list ap) +{ + int ret; + + ret = __printf(fmt, putchar, 0, ap); + return (ret); +} + +static int +vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) +{ + struct sp_data sp; + int ret; + + sp.sp_buf = str; + sp.sp_len = 0; + sp.sp_size = sz; + ret = __printf(fmt, __sputc, &sp, ap); + return (ret); +} + +static int +__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) +{ + char buf[(sizeof(long) * 8) + 1]; + char *nbuf; + u_long ul; + u_int ui; + int lflag; + int sflag; + char *s; + int pad; + int ret; + int c; + + nbuf = &buf[sizeof buf - 1]; + ret = 0; + while ((c = *fmt++) != 0) { + if (c != '%') { + ret += putc(c, arg); + continue; + } + lflag = 0; + sflag = 0; + pad = 0; +reswitch: c = *fmt++; + switch (c) { + case '#': + sflag = 1; + goto reswitch; + case '%': + ret += putc('%', arg); + break; + case 'c': + c = va_arg(ap, int); + ret += putc(c, arg); + break; + case 'd': + if (lflag == 0) { + ui = (u_int)va_arg(ap, int); + if (ui < (int)ui) { + ui = -ui; + ret += putc('-', arg); + } + s = __uitoa(nbuf, ui, 10); + } else { + ul = (u_long)va_arg(ap, long); + if (ul < (long)ul) { + ul = -ul; + ret += putc('-', arg); + } + s = __ultoa(nbuf, ul, 10); + } + ret += __puts(s, putc, arg); + break; + case 'l': + lflag = 1; + goto reswitch; + case 'o': + if (lflag == 0) { + ui = (u_int)va_arg(ap, u_int); + s = __uitoa(nbuf, ui, 8); + } else { + ul = (u_long)va_arg(ap, u_long); + s = __ultoa(nbuf, ul, 8); + } + ret += __puts(s, putc, arg); + break; + case 'p': + ul = (u_long)va_arg(ap, void *); + s = __ultoa(nbuf, ul, 16); + ret += __puts("0x", putc, arg); + ret += __puts(s, putc, arg); + break; + case 's': + s = va_arg(ap, char *); + ret += __puts(s, putc, arg); + break; + case 'u': + if (lflag == 0) { + ui = va_arg(ap, u_int); + s = __uitoa(nbuf, ui, 10); + } else { + ul = va_arg(ap, u_long); + s = __ultoa(nbuf, ul, 10); + } + ret += __puts(s, putc, arg); + break; + case 'x': + if (lflag == 0) { + ui = va_arg(ap, u_int); + s = __uitoa(nbuf, ui, 16); + } else { + ul = va_arg(ap, u_long); + s = __ultoa(nbuf, ul, 16); + } + if (sflag) + ret += __puts("0x", putc, arg); + ret += __puts(s, putc, arg); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + pad = pad * 10 + c - '0'; + goto reswitch; + default: + break; + } + } + return (ret); +} + +static int +__sputc(int c, void *arg) +{ + struct sp_data *sp; + + sp = arg; + if (sp->sp_len < sp->sp_size) + sp->sp_buf[sp->sp_len++] = c; + sp->sp_buf[sp->sp_len] = '\0'; + return (1); +} + +static int +__puts(const char *s, putc_func_t *putc, void *arg) +{ + const char *p; + int ret; + + ret = 0; + for (p = s; *p != '\0'; p++) + ret += putc(*p, arg); + return (ret); +} + +static char * +__uitoa(char *buf, u_int ui, int base) +{ + char *p; + + p = buf; + *p = '\0'; + do + *--p = digits[ui % base]; + while ((ui /= base) != 0); + return (p); +} + +static char * +__ultoa(char *buf, u_long ul, int base) +{ + char *p; + + p = buf; + *p = '\0'; + do + *--p = digits[ul % base]; + while ((ul /= base) != 0); + return (p); +} Index: sun4v/loader/Makefile =================================================================== RCS file: sun4v/loader/Makefile diff -N sun4v/loader/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/loader/Makefile 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,86 @@ +# $FreeBSD$ + +PROG= loader +NEWVERSWHAT= "bootstrap loader" sparc64 +INSTALLFLAGS= -b + +# Architecture-specific loader code +SRCS= locore.S main.c metadata.c vers.c + +LOADER_DISK_SUPPORT?= yes +LOADER_UFS_SUPPORT?= yes +LOADER_CD9660_SUPPORT?= yes +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes +LOADER_TFTP_SUPPORT?= yes +LOADER_GZIP_SUPPORT?= yes +LOADER_BZIP2_SUPPORT?= no + +.if ${LOADER_DISK_SUPPORT} == "yes" +CFLAGS+= -DLOADER_DISK_SUPPORT +.endif +.if ${LOADER_UFS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_UFS_SUPPORT +.endif +.if ${LOADER_CD9660_SUPPORT} == "yes" +CFLAGS+= -DLOADER_CD9660_SUPPORT +.endif +.if ${LOADER_GZIP_SUPPORT} == "yes" +CFLAGS+= -DLOADER_GZIP_SUPPORT +.endif +.if ${LOADER_BZIP2_SUPPORT} == "yes" +CFLAGS+= -DLOADER_BZIP2_SUPPORT +.endif +.if ${LOADER_NET_SUPPORT} == "yes" +CFLAGS+= -DLOADER_NET_SUPPORT +.endif +.if ${LOADER_NFS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_NFS_SUPPORT +.endif +.if ${LOADER_TFTP_SUPPORT} == "yes" +CFLAGS+= -DLOADER_TFTP_SUPPORT +.endif + +.if !defined(NO_FORTH) +# Enable BootForth +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/sparc64 +LIBFICL= ${.OBJDIR}/../../ficl/libficl.a +.endif + +# Always add MI sources +.PATH: ${.CURDIR}/../../common +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I. + +CLEANFILES+= vers.c loader.help + +LDFLAGS= -static + +# Open Firmware standalone support library +LIBOFW= ${.OBJDIR}/../../ofw/libofw/libofw.a +CFLAGS+= -I${.CURDIR}/../../ofw/libofw/ + +# where to get libstand from +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ + +DPADD= ${LIBFICL} ${LIBOFW} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBOFW} -lstand + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +loader.help: help.common help.sparc64 + cat ${.ALLSRC} | \ + awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +.PATH: ${.CURDIR}/../../forth +FILES= loader.help loader.4th support.4th loader.conf +FILESDIR_loader.conf= /boot/defaults + +.if !exists(${DESTDIR}/boot/loader.rc) +FILES+= loader.rc +.endif + +.include Index: sun4v/loader/hcall.S =================================================================== RCS file: sun4v/loader/hcall.S diff -N sun4v/loader/hcall.S --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/loader/hcall.S 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,986 @@ +/* + * $FreeBSD$ + */ + +/* + * Hypervisor calls + */ +#define LOCORE +#define _ASM + +#include +#include +#include +#include + /* + * %o0 - character + */ + ENTRY(hv_cnputchar) + mov CONS_WRITE, %o5 + ta FAST_TRAP + tst %o0 + retl + movnz %xcc, -1, %o0 + SET_SIZE(hv_cnputchar) + + /* + * %o0 pointer to character buffer + * return values: + * 0 success + * hv_errno failure + */ + ENTRY(hv_cngetchar) + mov %o0, %o2 + mov CONS_READ, %o5 + ta FAST_TRAP + brnz,a %o0, 1f ! failure, just return error + mov 1, %o0 + + cmp %o1, H_BREAK + be 1f + mov %o1, %o0 + + cmp %o1, H_HUP + be 1f + mov %o1, %o0 + + stb %o1, [%o2] ! success, save character and return 0 + mov 0, %o0 +1: + retl + nop + SET_SIZE(hv_cngetchar) + + ENTRY(hv_tod_get) + mov %o0, %o4 + mov TOD_GET, %o5 + ta FAST_TRAP + retl + stx %o1, [%o4] + SET_SIZE(hv_tod_get) + + ENTRY(hv_tod_set) + mov TOD_SET, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_tod_set) + + /* + * Map permanent address + * arg0 vaddr (%o0) + * arg1 context (%o1) + * arg2 tte (%o2) + * arg3 flags (%o3) 0x1=d 0x2=i + */ + ENTRY(hv_mmu_map_perm_addr) + mov MAP_PERM_ADDR, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_mmu_map_perm_addr) + + /* + * Unmap permanent address + * arg0 vaddr (%o0) + * arg1 context (%o1) + * arg2 flags (%o2) 0x1=d 0x2=i + */ + ENTRY(hv_mmu_unmap_perm_addr) + mov UNMAP_PERM_ADDR, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_mmu_unmap_perm_addr) + + /* + * Set TSB for context 0 + * arg0 ntsb_descriptor (%o0) + * arg1 desc_ra (%o1) + */ + ENTRY(hv_set_ctx0) + mov MMU_TSB_CTX0, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_set_ctx0) + + /* + * Set TSB for context non0 + * arg0 ntsb_descriptor (%o0) + * arg1 desc_ra (%o1) + */ + ENTRY(hv_set_ctxnon0) + mov MMU_TSB_CTXNON0, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_set_ctxnon0) + +#ifdef SET_MMU_STATS + /* + * Returns old stat area on success + */ + ENTRY(hv_mmu_set_stat_area) + mov MMU_STAT_AREA, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_mmu_set_stat_area) +#endif /* SET_MMU_STATS */ + + /* + * CPU Q Configure + * arg0 queue (%o0) + * arg1 Base address RA (%o1) + * arg2 Size (%o2) + */ + ENTRY(hv_cpu_qconf) + mov CPU_QCONF, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_cpu_qconf) + + /* + * arg0 - devhandle + * arg1 - pci_device + * arg2 - pci_config_offset + * arg3 - pci_config_size + * + * ret0 - status + * ret1 - error_flag + * ret2 - pci_cfg_data + */ + ENTRY(hvio_config_get) + mov HVIO_CONFIG_GET, %o5 + ta FAST_TRAP + brnz %o0, 1f + movrnz %o1, -1, %o2 + brz,a %o1, 1f + stuw %o2, [%o4] +1: retl + nop + SET_SIZE(hvio_config_get) + + /* + * arg0 - devhandle + * arg1 - pci_device + * arg2 - pci_config_offset + * arg3 - pci_config_size + * arg4 - pci_cfg_data + * + * ret0 - status + * ret1 - error_flag + */ + ENTRY(hvio_config_put) + mov HVIO_CONFIG_PUT, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_config_put) + + /* + * arg0 - devhandle + * arg1 - devino + * + * ret0 - status + * ret1 - sysino + */ + ENTRY(hvio_intr_devino_to_sysino) + mov HVIO_INTR_DEVINO2SYSINO, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_intr_devino_to_sysino) + + /* + * arg0 - sysino + * + * ret0 - status + * ret1 - intr_valid_state + */ + ENTRY(hvio_intr_getvalid) + mov %o1, %o2 + mov HVIO_INTR_GETVALID, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_intr_getvalid) + + /* + * arg0 - sysino + * arg1 - intr_valid_state + * + * ret0 - status + */ + ENTRY(hvio_intr_setvalid) + mov HVIO_INTR_SETVALID, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_intr_setvalid) + + /* + * arg0 - sysino + * + * ret0 - status + * ret1 - intr_state + */ + ENTRY(hvio_intr_getstate) + mov %o1, %o2 + mov HVIO_INTR_GETSTATE, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_intr_getstate) + + /* + * arg0 - sysino + * arg1 - intr_state + * + * ret0 - status + */ + ENTRY(hvio_intr_setstate) + mov HVIO_INTR_SETSTATE, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_intr_setstate) + + /* + * arg0 - sysino + * + * ret0 - status + * ret1 - cpu_id + */ + ENTRY(hvio_intr_gettarget) + mov %o1, %o2 + mov HVIO_INTR_GETTARGET, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_intr_gettarget) + + /* + * arg0 - sysino + * arg1 - cpu_id + * + * ret0 - status + */ + ENTRY(hvio_intr_settarget) + mov HVIO_INTR_SETTARGET, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_intr_settarget) + + /* + * arg0 - devhandle + * arg1 - tsbid + * arg2 - pages + * arg3 - io_attributes + * arg4 - io_page_list_p + * + * ret1 - pages_mapped + */ + ENTRY(hvio_iommu_map) + save %sp, -SA(MINFRAME64), %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + mov %i4, %o4 + mov HVIO_IOMMU_MAP, %o5 + ta FAST_TRAP + brnz %o0, 1f + mov %o0, %i0 + stuw %o1, [%i5] +1: + ret + restore + SET_SIZE(hvio_iommu_map) + + /* + * arg0 - devhandle + * arg1 - tsbid + * arg2 - pages + * + * ret1 - pages_demapped + */ + ENTRY(hvio_iommu_demap) + mov HVIO_IOMMU_DEMAP, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o3] +1: retl + nop + SET_SIZE(hvio_iommu_demap) + + /* + * arg0 - devhandle + * arg1 - tsbid + * + * + * ret0 - status + * ret1 - io_attributes + * ret2 - r_addr + */ + ENTRY(hvio_iommu_getmap) + mov %o2, %o4 + mov HVIO_IOMMU_GETMAP, %o5 + ta FAST_TRAP + brnz %o0, 1f + nop + stx %o2, [%o3] + st %o1, [%o4] +1: + retl + nop + SET_SIZE(hvio_iommu_getmap) + + /* + * arg0 - devhandle + * arg1 - r_addr + * arg2 - io_attributes + * + * + * ret0 - status + * ret1 - io_addr + */ + ENTRY(hvio_iommu_getbypass) + mov HVIO_IOMMU_GETBYPASS, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o3] +1: retl + nop + SET_SIZE(hvio_iommu_getbypass) + + /* + * arg0 - devhandle + * arg1 - r_addr + * arg2 - size + * + * ret1 - error_flag + * ret2 - data + */ + ENTRY(hvio_peek) + mov HVIO_PEEK, %o5 + ta FAST_TRAP + brnz %o0, 1f + nop + stx %o2, [%o4] + st %o1, [%o3] +1: + retl + nop + SET_SIZE(hvio_peek) + + /* + * arg0 - devhandle + * arg1 - r_addr + * arg2 - sizes + * arg3 - data + * arg4 - r_addr2 + * + * ret1 - error_flag + */ + ENTRY(hvio_poke) + save %sp, -SA(MINFRAME64), %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + mov %i4, %o4 + mov HVIO_POKE, %o5 + ta FAST_TRAP + brnz %o0, 1f + mov %o0, %i0 + stuw %o1, [%i5] +1: + ret + restore + SET_SIZE(hvio_poke) + + /* + * arg0 - devhandle + * arg1 - r_addr + * arg2 - num_bytes + * arg3 - io_sync_direction + * + * ret0 - status + * ret1 - bytes_synched + */ + ENTRY(hvio_dma_sync) + mov HVIO_DMA_SYNC, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o4] +1: retl + nop + SET_SIZE(hvio_dma_sync) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * arg2 - r_addr + * arg3 - nentries + * + * ret0 - status + */ + ENTRY(hvio_msiq_conf) + mov HVIO_MSIQ_CONF, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msiq_conf) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * + * ret0 - status + * ret1 - r_addr + * ret1 - nentries + */ + ENTRY(hvio_msiq_info) + mov %o2, %o4 + mov HVIO_MSIQ_INFO, %o5 + ta FAST_TRAP + brnz %o0, 1f + nop + stx %o1, [%o4] + stuw %o2, [%o3] +1: retl + nop + SET_SIZE(hvio_msiq_info) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * + * ret0 - status + * ret1 - msiq_valid_state + */ + ENTRY(hvio_msiq_getvalid) + mov HVIO_MSIQ_GETVALID, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msiq_getvalid) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * arg2 - msiq_valid_state + * + * ret0 - status + */ + ENTRY(hvio_msiq_setvalid) + mov HVIO_MSIQ_SETVALID, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msiq_setvalid) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * + * ret0 - status + * ret1 - msiq_state + */ + ENTRY(hvio_msiq_getstate) + mov HVIO_MSIQ_GETSTATE, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msiq_getstate) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * arg2 - msiq_state + * + * ret0 - status + */ + ENTRY(hvio_msiq_setstate) + mov HVIO_MSIQ_SETSTATE, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msiq_setstate) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * + * ret0 - status + * ret1 - msiq_head + */ + ENTRY(hvio_msiq_gethead) + mov HVIO_MSIQ_GETHEAD, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msiq_gethead) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * arg2 - msiq_head + * + * ret0 - status + */ + ENTRY(hvio_msiq_sethead) + mov HVIO_MSIQ_SETHEAD, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msiq_sethead) + + /* + * arg0 - devhandle + * arg1 - msiq_id + * + * ret0 - status + * ret1 - msiq_tail + */ + ENTRY(hvio_msiq_gettail) + mov HVIO_MSIQ_GETTAIL, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msiq_gettail) + + /* + * arg0 - devhandle + * arg1 - msi_num + * + * ret0 - status + * ret1 - msiq_id + */ + ENTRY(hvio_msi_getmsiq) + mov HVIO_MSI_GETMSIQ, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msi_getmsiq) + + /* + * arg0 - devhandle + * arg1 - msi_num + * arg2 - msiq_id + * arg2 - msitype + * + * ret0 - status + */ + ENTRY(hvio_msi_setmsiq) + mov HVIO_MSI_SETMSIQ, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msi_setmsiq) + + /* + * arg0 - devhandle + * arg1 - msi_num + * + * ret0 - status + * ret1 - msi_valid_state + */ + ENTRY(hvio_msi_getvalid) + mov HVIO_MSI_GETVALID, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msi_getvalid) + + /* + * arg0 - devhandle + * arg1 - msi_num + * arg2 - msi_valid_state + * + * ret0 - status + */ + ENTRY(hvio_msi_setvalid) + mov HVIO_MSI_SETVALID, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msi_setvalid) + + /* + * arg0 - devhandle + * arg1 - msi_num + * + * ret0 - status + * ret1 - msi_state + */ + ENTRY(hvio_msi_getstate) + mov HVIO_MSI_GETSTATE, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msi_getstate) + + /* + * arg0 - devhandle + * arg1 - msi_num + * arg2 - msi_state + * + * ret0 - status + */ + ENTRY(hvio_msi_setstate) + mov HVIO_MSI_SETSTATE, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msi_setstate) + + /* + * arg0 - devhandle + * arg1 - msg_type + * + * ret0 - status + * ret1 - msiq_id + */ + ENTRY(hvio_msg_getmsiq) + mov HVIO_MSG_GETMSIQ, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msg_getmsiq) + + /* + * arg0 - devhandle + * arg1 - msg_type + * arg2 - msiq_id + * + * ret0 - status + */ + ENTRY(hvio_msg_setmsiq) + mov HVIO_MSG_SETMSIQ, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msg_setmsiq) + + /* + * arg0 - devhandle + * arg1 - msg_type + * + * ret0 - status + * ret1 - msg_valid_state + */ + ENTRY(hvio_msg_getvalid) + mov HVIO_MSG_GETVALID, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stuw %o1, [%o2] +1: retl + nop + SET_SIZE(hvio_msg_getvalid) + + /* + * arg0 - devhandle + * arg1 - msg_type + * arg2 - msg_valid_state + * + * ret0 - status + */ + ENTRY(hvio_msg_setvalid) + mov HVIO_MSG_SETVALID, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hvio_msg_setvalid) + + /* + * hv_cpu_yield(void) + */ + ENTRY(hv_cpu_yield) + mov HV_CPU_YIELD, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_cpu_yield) + + /* + * hv_service_recv(uint64_t s_id, uint64_t buf_pa, + * uint64_t size, uint64_t *recv_bytes); + */ + ENTRY(hv_service_recv) + save %sp, -SA(MINFRAME), %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + mov SVC_RECV, %o5 + ta FAST_TRAP + brnz %o0, 1f + mov %o0, %i0 + stx %o1, [%i3] +1: + ret + restore + SET_SIZE(hv_service_recv) + + /* + * hv_service_send(uint64_t s_id, uint64_t buf_pa, + * uint64_t size, uint64_t *recv_bytes); + */ + ENTRY(hv_service_send) + save %sp, -SA(MINFRAME), %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + mov SVC_SEND, %o5 + ta FAST_TRAP + brnz %o0, 1f + mov %o0, %i0 + stx %o1, [%i3] +1: + ret + restore + SET_SIZE(hv_service_send) + + /* + * hv_service_getstatus(uint64_t s_id, uint64_t *vreg); + */ + ENTRY(hv_service_getstatus) + mov %o1, %o4 ! save datap + mov SVC_GETSTATUS, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o4] +1: + retl + nop + SET_SIZE(hv_service_getstatus) + + /* + * hv_service_setstatus(uint64_t s_id, uint64_t bits); + */ + ENTRY(hv_service_setstatus) + mov SVC_SETSTATUS, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_service_setstatus) + + /* + * hv_service_clrstatus(uint64_t s_id, uint64_t bits); + */ + ENTRY(hv_service_clrstatus) + mov SVC_CLRSTATUS, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_service_clrstatus) + + /* + * int hv_cpu_state(uint64_t cpuid, uint64_t *cpu_state); + */ + ENTRY(hv_cpu_state) + mov %o1, %o4 ! save datap + mov HV_CPU_STATE, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o4] +1: + retl + nop + SET_SIZE(hv_cpu_state) + + /* + * HV state dump zone Configure + * arg0 real adrs of dump buffer (%o0) + * arg1 size of dump buffer (%o1) + * ret0 status (%o0) + * ret1 size of buffer on success and min size on EINVAL (%o1) + * hv_dump_buf_update(uint64_t paddr, uint64_t size, uint64_t *ret_size) + */ + ENTRY(hv_dump_buf_update) + mov DUMP_BUF_UPDATE, %o5 + ta FAST_TRAP + retl + stx %o1, [%o2] + SET_SIZE(hv_dump_buf_update) + + + /* + * For memory scrub + * int hv_mem_scrub(uint64_t real_addr, uint64_t length, + * uint64_t *scrubbed_len); + * Retun %o0 -- status + * %o1 -- bytes scrubbed + */ + ENTRY(hv_mem_scrub) + mov %o2, %o4 + mov HV_MEM_SCRUB, %o5 + ta FAST_TRAP + retl + stx %o1, [%o4] + SET_SIZE(hv_mem_scrub) + + /* + * Flush ecache + * int hv_mem_sync(uint64_t real_addr, uint64_t length, + * uint64_t *flushed_len); + * Retun %o0 -- status + * %o1 -- bytes flushed + */ + ENTRY(hv_mem_sync) + mov %o2, %o4 + mov HV_MEM_SYNC, %o5 + ta FAST_TRAP + retl + stx %o1, [%o4] + SET_SIZE(hv_mem_sync) + + /* + * TTRACE_BUF_CONF Configure + * arg0 RA base of buffer (%o0) + * arg1 buf size in no. of entries (%o1) + * ret0 status (%o0) + * ret1 minimum size in no. of entries on failure, + * actual size in no. of entries on success (%o1) + */ + ENTRY(hv_ttrace_buf_conf) + mov TTRACE_BUF_CONF, %o5 + ta FAST_TRAP + retl + stx %o1, [%o2] + SET_SIZE(hv_ttrace_buf_conf) + + /* + * TTRACE_BUF_INFO + * ret0 status (%o0) + * ret1 RA base of buffer (%o1) + * ret2 size in no. of entries (%o2) + */ + ENTRY(hv_ttrace_buf_info) + mov %o0, %o3 + mov %o1, %o4 + mov TTRACE_BUF_INFO, %o5 + ta FAST_TRAP + stx %o1, [%o3] + retl + stx %o2, [%o4] + SET_SIZE(hv_ttrace_buf_info) + + /* + * TTRACE_ENABLE + * arg0 enable/ disable (%o0) + * ret0 status (%o0) + * ret1 previous enable state (%o1) + */ + ENTRY(hv_ttrace_enable) + mov %o1, %o2 + mov TTRACE_ENABLE, %o5 + ta FAST_TRAP + retl + stx %o1, [%o2] + SET_SIZE(hv_ttrace_enable) + + /* + * TTRACE_FREEZE + * arg0 enable/ freeze (%o0) + * ret0 status (%o0) + * ret1 previous freeze state (%o1) + */ + ENTRY(hv_ttrace_freeze) + mov %o1, %o2 + mov TTRACE_FREEZE, %o5 + ta FAST_TRAP + retl + stx %o1, [%o2] + SET_SIZE(hv_ttrace_freeze) + + /* + * MACH_DESC + * arg0 buffer real address + * arg1 pointer to uint64_t for size of buffer + * ret0 status + * ret1 return required size of buffer / returned data size + */ + ENTRY(hv_mach_desc) + mov %o1, %o4 ! save datap + ldx [%o1], %o1 + mov HV_MACH_DESC, %o5 + ta FAST_TRAP + retl + stx %o1, [%o4] + SET_SIZE(hv_mach_desc) + + /* + * hv_ncs_request(int cmd, uint64_t realaddr, size_t sz) + */ + ENTRY(hv_ncs_request) + mov HV_NCS_REQUEST, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_ncs_request) + + /* + * hv_ra2pa(uint64_t ra) + * + * MACH_DESC + * arg0 Real address to convert + * ret0 Returned physical address or -1 on error + */ + ENTRY(hv_ra2pa) + mov HV_RA2PA, %o5 + ta FAST_TRAP + cmp %o0, 0 + move %xcc, %o1, %o0 + movne %xcc, -1, %o0 + retl + nop + SET_SIZE(hv_ra2pa) + + /* + * hv_hpriv(void *func, uint64_t arg1, uint64_t arg2, uint64_t arg3) + * + * MACH_DESC + * arg0 OS function to call + * arg1 First arg to OS function + * arg2 Second arg to OS function + * arg3 Third arg to OS function + * ret0 Returned value from function + */ + + ENTRY(hv_hpriv) + mov HV_HPRIV, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_hpriv) Index: sun4v/loader/help.sparc64 =================================================================== RCS file: sun4v/loader/help.sparc64 diff -N sun4v/loader/help.sparc64 Index: sun4v/loader/locore.S =================================================================== RCS file: sun4v/loader/locore.S diff -N sun4v/loader/locore.S --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/loader/locore.S 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,113 @@ +/*- + * Initial implementation: + * Copyright (c) 2001 Robert Drehmel + * All rights reserved. + * + * As long as the above copyright statement and this notice remain + * unchanged, you can do what ever you want with this file. + * + * $FreeBSD$ + */ + +#define LOCORE + +#include +#include +#include +#include +#include + +#define PAGE_SIZE 8192 +#define PAGE_SHIFT 13 + +#define SPOFF 2047 +#define STACK_SIZE (2 * PAGE_SIZE) + +ENTRY(_start) + /* limit interrupts */ + wrpr %g0, 13, %pil + + /* + * PSTATE: privileged, interrupts enabled, floating point + * unit enabled + */ + wrpr %g0, PSTATE_PRIV|PSTATE_IE|PSTATE_PEF, %pstate + wr %g0, 0x4, %fprs + + setx stack + STACK_SIZE - SPOFF - CCFSZ, %l7, %l6 + mov %l6, %sp + call main + mov %o4, %o0 + sir +#if 0 +/* + * %o0 input VA constant + * %o1 current iTLB offset + * %o2 current iTLB TTE tag + */ +ENTRY(itlb_va_to_pa) + clr %o1 +0: ldxa [%o1] ASI_ITLB_TAG_READ_REG, %o2 + cmp %o2, %o0 + bne,a %xcc, 1f + nop + /* return PA of matching entry */ + ldxa [%o1] ASI_ITLB_DATA_ACCESS_REG, %o0 + sllx %o0, 23, %o0 + srlx %o0, PAGE_SHIFT+23, %o0 + sllx %o0, PAGE_SHIFT, %o0 + retl + mov %o0, %o1 +1: cmp %o1, 63<<3 + blu %xcc, 0b + add %o1, 8, %o1 + clr %o0 + retl + not %o0 + +ENTRY(dtlb_va_to_pa) + clr %o1 +0: ldxa [%o1] ASI_DTLB_TAG_READ_REG, %o2 + cmp %o2, %o0 + bne,a %xcc, 1f + nop + /* return PA of matching entry */ + ldxa [%o1] ASI_DTLB_DATA_ACCESS_REG, %o0 + sllx %o0, 23, %o0 + srlx %o0, PAGE_SHIFT+23, %o0 + sllx %o0, PAGE_SHIFT, %o0 + retl + mov %o0, %o1 +1: cmp %o1, 63<<3 + blu %xcc, 0b + add %o1, 8, %o1 + clr %o0 + retl + not %o0 + +/* + * %o0 = vpn + * %o1 = tte data + */ +ENTRY(itlb_enter) + rdpr %pstate, %o4 + wrpr %o4, PSTATE_IE, %pstate + mov AA_IMMU_TAR, %o3 + stxa %o0, [%o3] ASI_IMMU + stxa %o1, [%g0] ASI_ITLB_DATA_IN_REG + membar #Sync + retl + wrpr %o4, 0, %pstate + +ENTRY(dtlb_enter) + rdpr %pstate, %o4 + wrpr %o4, PSTATE_IE, %pstate + mov AA_DMMU_TAR, %o3 + stxa %o0, [%o3] ASI_DMMU + stxa %o1, [%g0] ASI_DTLB_DATA_IN_REG + membar #Sync + retl + wrpr %o4, 0, %pstate +#endif + .comm stack, STACK_SIZE, 32 + .comm smp_stack, STACK_SIZE, 32 Index: sun4v/loader/main.c =================================================================== RCS file: sun4v/loader/main.c diff -N sun4v/loader/main.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/loader/main.c 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,620 @@ +/*- + * Initial implementation: + * Copyright (c) 2001 Robert Drehmel + * All rights reserved. + * + * As long as the above copyright statement and this notice remain + * unchanged, you can do what ever you want with this file. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * FreeBSD/sparc64 kernel loader - machine dependent part + * + * - implements copyin and readin functions that map kernel + * pages on demand. The machine independent code does not + * know the size of the kernel early enough to pre-enter + * TTEs and install just one 4MB mapping seemed to limiting + * to me. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libofw.h" +#include "dev_net.h" + +enum { + HEAPVA = 0x800000, + HEAPSZ = 0x1000000, + LOADSZ = 0x1000000 /* for kernel and modules */ +}; + +struct memory_slice { + vm_offset_t pstart; + vm_offset_t size; +}; + +struct mmu_ops { + void (*tlb_init)(void); + int (*mmu_mapin)(vm_offset_t va, vm_size_t len); +} *mmu_ops; + + + +#define UNIMPLEMENTED printf("%s function not implemented\n", __FUNCTION__); + +typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, + void *openfirmware); + +extern void itlb_enter(u_long vpn, u_long data); +extern void dtlb_enter(u_long vpn, u_long data); +extern vm_offset_t itlb_va_to_pa(vm_offset_t); +extern vm_offset_t dtlb_va_to_pa(vm_offset_t); +extern vm_offset_t md_load(char *, vm_offset_t *); +static int __elfN(exec)(struct preloaded_file *); +static int sparc64_autoload(void); +static int mmu_mapin_sun4u(vm_offset_t, vm_size_t); +static int mmu_mapin_sun4v(vm_offset_t, vm_size_t); +static void tlb_init_sun4u(void); +static void tlb_init_sun4v(void); + +struct mmu_ops mmu_ops_sun4u = { tlb_init_sun4u, mmu_mapin_sun4u }; +struct mmu_ops mmu_ops_sun4v = { tlb_init_sun4v, mmu_mapin_sun4v }; + +extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; + +/* sun4u */ +struct tlb_entry *dtlb_store; +struct tlb_entry *itlb_store; +int dtlb_slot; +int itlb_slot; +int dtlb_slot_max; +int itlb_slot_max; + +/* sun4v */ +struct tlb_entry *tlb_store; +/* + * no direct TLB access on sun4v + * we somewhat arbitrarily declare enough + * slots to cover a 4GB AS with 4MB pages + */ +#define SUN4V_TLB_SLOT_MAX (1 << 10) + + +extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; + +struct tlb_entry *dtlb_store; +struct tlb_entry *itlb_store; + +int dtlb_slot; +int itlb_slot; +int dtlb_slot_max; +int itlb_slot_max; + +vm_offset_t curkva = 0; +vm_offset_t heapva; +phandle_t pmemh; /* OFW memory handle */ + +struct memory_slice memslices[18]; + +/* + * Machine dependent structures that the machine independent + * loader part uses. + */ +struct devsw *devsw[] = { +#ifdef LOADER_DISK_SUPPORT + &ofwdisk, +#endif +#ifdef LOADER_NET_SUPPORT + &netdev, +#endif + 0 +}; +struct arch_switch archsw; + +struct file_format sparc64_elf = { + __elfN(loadfile), + __elfN(exec) +}; +struct file_format *file_formats[] = { + &sparc64_elf, + 0 +}; +struct fs_ops *file_system[] = { +#ifdef LOADER_UFS_SUPPORT + &ufs_fsops, +#endif +#ifdef LOADER_CD9660_SUPPORT + &cd9660_fsops, +#endif +#ifdef LOADER_ZIP_SUPPORT + &zipfs_fsops, +#endif +#ifdef LOADER_GZIP_SUPPORT + &gzipfs_fsops, +#endif +#ifdef LOADER_BZIP2_SUPPORT + &bzipfs_fsops, +#endif +#ifdef LOADER_NFS_SUPPORT + &nfs_fsops, +#endif +#ifdef LOADER_TFTP_SUPPORT + &tftp_fsops, +#endif + 0 +}; +struct netif_driver *netif_drivers[] = { +#ifdef LOADER_NET_SUPPORT + &ofwnet, +#endif + 0 +}; + +extern struct console ofwconsole; +struct console *consoles[] = { + &ofwconsole, + 0 +}; + +#ifdef LOADER_DEBUG +static int +watch_phys_set_mask(vm_offset_t pa, u_long mask) +{ + u_long lsucr; + + stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); + lsucr = ldxa(0, ASI_LSU_CTL_REG); + lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | + (mask << LSU_PM_SHIFT); + stxa(0, ASI_LSU_CTL_REG, lsucr); + return (0); +} + +static int +watch_phys_set(vm_offset_t pa, int sz) +{ + u_long off; + + off = (u_long)pa & 7; + /* Test for misaligned watch points. */ + if (off + sz > 8) + return (-1); + return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); +} + + +static int +watch_virt_set_mask(vm_offset_t va, u_long mask) +{ + u_long lsucr; + + stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); + lsucr = ldxa(0, ASI_LSU_CTL_REG); + lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | + (mask << LSU_VM_SHIFT); + stxa(0, ASI_LSU_CTL_REG, lsucr); + return (0); +} + +static int +watch_virt_set(vm_offset_t va, int sz) +{ + u_long off; + + off = (u_long)va & 7; + /* Test for misaligned watch points. */ + if (off + sz > 8) + return (-1); + return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); +} +#endif + +/* + * archsw functions + */ +static int +sparc64_autoload(void) +{ + printf("nothing to autoload yet.\n"); + return 0; +} + +static ssize_t +sparc64_readin(const int fd, vm_offset_t va, const size_t len) +{ + mmu_ops->mmu_mapin(va, len); + return read(fd, (void *)va, len); +} + +static ssize_t +sparc64_copyin(const void *src, vm_offset_t dest, size_t len) +{ + mmu_ops->mmu_mapin(dest, len); + memcpy((void *)dest, src, len); + return len; +} + +/* + * other MD functions + */ +static int +__elfN(exec)(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t mdp; + Elf_Addr entry; + Elf_Ehdr *e; + int error; + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { + return EFTYPE; + } + e = (Elf_Ehdr *)&fmp->md_data; + + if ((error = md_load(fp->f_args, &mdp)) != 0) + return error; + + printf("jumping to kernel entry at %#lx.\n", e->e_entry); +#if 0 + pmap_print_tlb('i'); + pmap_print_tlb('d'); +#endif + + entry = e->e_entry; + + OF_release(heapva, HEAPSZ); + + ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); + + panic("exec returned"); +} + +static int +mmu_mapin_sun4u(vm_offset_t va, vm_size_t len) +{ + vm_offset_t pa, mva; + u_long data; +#if 0 + if (va + len > curkva) + curkva = va + len; + + pa = (vm_offset_t)-1; + len += va & PAGE_MASK_4M; + va &= ~PAGE_MASK_4M; + while (len) { + if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || + itlb_va_to_pa(va) == (vm_offset_t)-1) { + /* Allocate a physical page, claim the virtual area */ + if (pa == (vm_offset_t)-1) { + pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, + PAGE_SIZE_4M); + if (pa == (vm_offset_t)-1) + panic("out of memory"); + mva = (vm_offset_t)OF_claim_virt(va, + PAGE_SIZE_4M, 0); + if (mva != va) { + panic("can't claim virtual page " + "(wanted %#lx, got %#lx)", + va, mva); + } + /* The mappings may have changed, be paranoid. */ + continue; + } + /* + * Actually, we can only allocate two pages less at + * most (depending on the kernel TSB size). + */ + if (dtlb_slot >= dtlb_slot_max) + panic("mmu_mapin: out of dtlb_slots"); + if (itlb_slot >= itlb_slot_max) + panic("mmu_mapin: out of itlb_slots"); + data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | + TD_CV | TD_P | TD_W; + dtlb_store[dtlb_slot].te_pa = pa; + dtlb_store[dtlb_slot].te_va = va; + itlb_store[itlb_slot].te_pa = pa; + itlb_store[itlb_slot].te_va = va; + dtlb_slot++; + itlb_slot++; + dtlb_enter(va, data); + itlb_enter(va, data); + pa = (vm_offset_t)-1; + } + len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; + va += PAGE_SIZE_4M; + } + if (pa != (vm_offset_t)-1) + OF_release_phys(pa, PAGE_SIZE_4M); +#endif + return 0; +} + +static int +mmu_mapin_sun4v(vm_offset_t va, vm_size_t len) +{ + + vm_offset_t pa, mva; + u_long data; + int ret; + + if (va + len > curkva) + curkva = va + len; + + pa = (vm_offset_t)-1; + len += va & PAGE_MASK_4M; + va &= ~PAGE_MASK_4M; + while (len) { + if ((va >> 22) > SUN4V_TLB_SLOT_MAX) + panic("trying to map more than 4GB"); + if (tlb_store[va >> 22].te_pa == -1) { + /* Allocate a physical page, claim the virtual area */ + if (pa == (vm_offset_t)-1) { + pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, + PAGE_SIZE_4M); + if (pa == (vm_offset_t)-1) + panic("out of memory"); + mva = (vm_offset_t)OF_claim_virt(va, + PAGE_SIZE_4M, 0); + if (mva != va) { + panic("can't claim virtual page " + "(wanted %#lx, got %#lx)", + va, mva); + } + } + + tlb_store[va >> 22].te_pa = pa; + if ((ret = OF_map_phys(-1, PAGE_SIZE_4M, va, pa)) != 0) + printf("OF_map_phys failed: %d\n", ret); + pa = (vm_offset_t)-1; + } + len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; + va += PAGE_SIZE_4M; + } + if (pa != (vm_offset_t)-1) + OF_release_phys(pa, PAGE_SIZE_4M); + return 0; +} + +static vm_offset_t +init_heap(void) +{ + if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) + OF_exit(); + if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) + OF_exit(); + + /* There is no need for continuous physical heap memory. */ + heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); + return heapva; +} + +static void +tlb_init_sun4u(void) +{ +#if 0 + phandle_t child; + phandle_t root; + char buf[128]; + u_int bootcpu; + u_int cpu; + + bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); + if ((root = OF_peer(0)) == -1) + panic("main: OF_peer"); + for (child = OF_child(root); child != 0; child = OF_peer(child)) { + if (child == -1) + panic("main: OF_child"); + if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && + strcmp(buf, "cpu") == 0) { + if (OF_getprop(child, "upa-portid", &cpu, + sizeof(cpu)) == -1 && OF_getprop(child, "portid", + &cpu, sizeof(cpu)) == -1) + panic("main: OF_getprop"); + if (cpu == bootcpu) + break; + } + } + if (cpu != bootcpu) + panic("init_tlb: no node for bootcpu?!?!"); + if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, + sizeof(dtlb_slot_max)) == -1 || + OF_getprop(child, "#itlb-entries", &itlb_slot_max, + sizeof(itlb_slot_max)) == -1) + panic("init_tlb: OF_getprop"); + dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); + itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); + if (dtlb_store == NULL || itlb_store == NULL) + panic("init_tlb: malloc"); +#endif +} + +static void +tlb_init_sun4v(void) +{ + tlb_store = malloc(SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store)); + memset(tlb_store, 0xFF, SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store)); +} + +int +main(int (*openfirm)(void *)) +{ + char bootpath[64]; + char compatible[32]; + struct devsw **dp; + phandle_t rooth; + phandle_t chosenh; + + /* + * Tell the Open Firmware functions where they find the ofw gate. + */ + OF_init(openfirm); + + archsw.arch_getdev = ofw_getdev; + archsw.arch_copyin = sparc64_copyin; + archsw.arch_copyout = ofw_copyout; + archsw.arch_readin = sparc64_readin; + archsw.arch_autoload = sparc64_autoload; + + init_heap(); + setheap((void *)heapva, (void *)(heapva + HEAPSZ)); + /* + * Probe for a console. + */ + cons_probe(); + + rooth = OF_peer(0); + OF_getprop(rooth, "compatible", compatible, sizeof(compatible)); + if (!strcmp(compatible, "sun4v")) { + printf("\nnice machine\n"); + mmu_ops = &mmu_ops_sun4v; + } else { + printf("\nHere's a quarter kid. Go buy yourself a new computer.\n"); + mmu_ops = &mmu_ops_sun4u; + } + + mmu_ops->tlb_init(); + + bcache_init(32, 512); + + /* + * Initialize devices. + */ + for (dp = devsw; *dp != 0; dp++) { + if ((*dp)->dv_init != 0) + (*dp)->dv_init(); + } + + /* + * Set up the current device. + */ + chosenh = OF_finddevice("/chosen"); + OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); + + /* + * Sun compatible bootable CD-ROMs have a disk label placed + * before the cd9660 data, with the actual filesystem being + * in the first partition, while the other partitions contain + * pseudo disk labels with embedded boot blocks for different + * architectures, which may be followed by UFS filesystems. + * The firmware will set the boot path to the partition it + * boots from ('f' in the sun4u case), but we want the kernel + * to be loaded from the cd9660 fs ('a'), so the boot path + * needs to be altered. + */ + if (bootpath[strlen(bootpath) - 2] == ':' && + bootpath[strlen(bootpath) - 1] == 'f') { + bootpath[strlen(bootpath) - 1] = 'a'; + printf("Boot path set to %s\n", bootpath); + } + + env_setenv("currdev", EV_VOLATILE, bootpath, + ofw_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, bootpath, + env_noset, env_nounset); + + printf("\n"); + printf("%s, Revision %s\n", bootprog_name, bootprog_rev); + printf("(%s, %s)\n", bootprog_maker, bootprog_date); + printf("bootpath=\"%s\"\n", bootpath); + + /* Give control to the machine independent loader code. */ + interact(); + return 1; +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc, char *argv[]) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + printf("Rebooting...\n"); + OF_exit(); +} + +/* provide this for panic, as it's not in the startup code */ +void +exit(int code) +{ + OF_exit(); +} + +#ifdef LOADER_DEBUG +typedef u_int64_t tte_t; + +const char *page_sizes[] = { + " 8k", " 64k", "512k", " 4m" +}; + +static void +pmap_print_tte(tte_t tag, tte_t tte) +{ + printf("%s %s ", + page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], + tag & TD_G ? "G" : " "); + printf(tte & TD_W ? "W " : " "); + printf(tte & TD_P ? "\e[33mP\e[0m " : " "); + printf(tte & TD_E ? "E " : " "); + printf(tte & TD_CV ? "CV " : " "); + printf(tte & TD_CP ? "CP " : " "); + printf(tte & TD_L ? "\e[32mL\e[0m " : " "); + printf(tte & TD_IE ? "IE " : " "); + printf(tte & TD_NFO ? "NFO " : " "); + printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), + TT_VA(tag), TT_CTX(tag)); +} +void +pmap_print_tlb(char which) +{ + int i; + tte_t tte, tag; + + for (i = 0; i < 64*8; i += 8) { + if (which == 'i') { + __asm__ __volatile__("ldxa [%1] %2, %0\n" : + "=r" (tag) : "r" (i), + "i" (ASI_ITLB_TAG_READ_REG)); + __asm__ __volatile__("ldxa [%1] %2, %0\n" : + "=r" (tte) : "r" (i), + "i" (ASI_ITLB_DATA_ACCESS_REG)); + } + else { + __asm__ __volatile__("ldxa [%1] %2, %0\n" : + "=r" (tag) : "r" (i), + "i" (ASI_DTLB_TAG_READ_REG)); + __asm__ __volatile__("ldxa [%1] %2, %0\n" : + "=r" (tte) : "r" (i), + "i" (ASI_DTLB_DATA_ACCESS_REG)); + } + if (!(tte & TD_V)) + continue; + printf("%cTLB-%2u: ", which, i>>3); + pmap_print_tte(tag, tte); + } +} +#endif Index: sun4v/loader/metadata.c =================================================================== RCS file: sun4v/loader/metadata.c diff -N sun4v/loader/metadata.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/loader/metadata.c 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: FreeBSD: src/sys/boot/i386/libi386/bootinfo.c,v 1.29 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#include "bootstrap.h" +#include "libofw.h" + +extern struct tlb_entry *dtlb_store; +extern struct tlb_entry *itlb_store; + +extern int dtlb_slot; +extern int itlb_slot; + +static int md_bootserial(void); + +/* + * Return a 'boothowto' value corresponding to the kernel arguments in + * (kargs) and any relevant environment variables. + */ +static struct +{ + const char *ev; + int mask; +} howto_names[] = { + {"boot_askname", RB_ASKNAME}, + {"boot_cdrom", RB_CDROM}, + {"boot_ddb", RB_KDB}, + {"boot_dfltroot", RB_DFLTROOT}, + {"boot_gdb", RB_GDB}, + {"boot_multicons", RB_MULTIPLE}, + {"boot_mute", RB_MUTE}, + {"boot_pause", RB_PAUSE}, + {"boot_serial", RB_SERIAL}, + {"boot_single", RB_SINGLE}, + {"boot_verbose", RB_VERBOSE}, + {NULL, 0} +}; + +int +md_getboothowto(char *kargs) +{ + char *cp; + int howto; + int active; + int i; + + /* Parse kargs */ + howto = 0; + if (kargs != NULL) { + cp = kargs; + active = 0; + while (*cp != 0) { + if (!active && (*cp == '-')) { + active = 1; + } else if (active) + switch (*cp) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'C': + howto |= RB_CDROM; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'g': + howto |= RB_GDB; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'v': + howto |= RB_VERBOSE; + break; + default: + active = 0; + break; + } + cp++; + } + } + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + if (md_bootserial() != -1) + howto |= RB_SERIAL; + return(howto); +} + +static int +md_bootserial(void) +{ + char buf[64]; + ihandle_t inst; + phandle_t input; + phandle_t node; + phandle_t output; + + if ((node = OF_finddevice("/options")) == -1) + return(-1); + if (OF_getprop(node, "input-device", buf, sizeof(buf)) == -1) + return(-1); + input = OF_finddevice(buf); + if (OF_getprop(node, "output-device", buf, sizeof(buf)) == -1) + return(-1); + output = OF_finddevice(buf); + if (input == -1 || output == -1 || OF_getproplen(input, "keyboard") >= 0) { + if ((node = OF_finddevice("/chosen")) == -1) + return(-1); + if (OF_getprop(node, "stdin", &inst, sizeof(inst)) == -1) + return(-1); + if ((input = OF_instance_to_package(inst)) == -1) + return(-1); + if (OF_getprop(node, "stdout", &inst, sizeof(inst)) == -1) + return(-1); + if ((output = OF_instance_to_package(inst)) == -1) + return(-1); + } + if (input != output) + return(-1); + if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) + return(-1); + if (strcmp(buf, "serial") != 0) + return(-1); + return(0); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as =, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +md_copyenv(vm_offset_t addr) +{ + struct env_var *ep; + + /* traverse the environment */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); + addr += strlen(ep->ev_name); + archsw.arch_copyin("=", addr, 1); + addr++; + if (ep->ev_value != NULL) { + archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); + addr += strlen(ep->ev_value); + } + archsw.arch_copyin("", addr, 1); + addr++; + } + archsw.arch_copyin("", addr, 1); + addr++; + return(addr); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + archsw.arch_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c) \ + if (c) \ + archsw.arch_copyin(s, a, strlen(s) + 1);\ + a += roundup(strlen(s) + 1, sizeof(u_long));\ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + archsw.arch_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_long)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c);\ + COPY32(mm->md_size, a, c); \ + if (c) \ + archsw.arch_copyin(mm->md_data, a, mm->md_size);\ + a += roundup(mm->md_size, sizeof(u_long)); \ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +vm_offset_t +md_copymodules(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + MOD_ADDR(addr, fp->f_addr, c); + MOD_SIZE(addr, fp->f_size, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) { + if (!(md->md_type & MODINFOMD_NOCOPY)) { + MOD_METADATA(addr, md, c); + } + } + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by a sparc64 kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +md_load(char *args, vm_offset_t *modulep) +{ + struct preloaded_file *kfp; + struct preloaded_file *xp; + struct file_metadata *md; + vm_offset_t kernend; + vm_offset_t addr; + vm_offset_t envp; + vm_offset_t size; + char *rootdevname; + int howto; + + howto = md_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + if ((rootdevname = getenv("rootdev")) == NULL) + rootdevname = getenv("currdev"); + getrootmount(rootdevname); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = md_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + kernend = 0; + kfp = file_findfile(NULL, "elf64 kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS, sizeof dtlb_slot, &dtlb_slot); + file_addmetadata(kfp, MODINFOMD_ITLB_SLOTS, sizeof itlb_slot, &itlb_slot); + file_addmetadata(kfp, MODINFOMD_DTLB, + dtlb_slot * sizeof(*dtlb_store), dtlb_store); + file_addmetadata(kfp, MODINFOMD_ITLB, + itlb_slot * sizeof(*itlb_store), itlb_store); + + *modulep = addr; + size = md_copymodules(0); + kernend = roundup(addr + size, PAGE_SIZE); + + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + + (void)md_copymodules(addr); + + return(0); +} Index: sun4v/loader/version =================================================================== RCS file: sun4v/loader/version diff -N sun4v/loader/version --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sun4v/loader/version 8 Oct 2006 03:04:26 -0000 @@ -0,0 +1,6 @@ +$FreeBSD: src/sys/boot/sparc64/loader/version,v 1.1 2002/07/07 18:23:10 jake Exp $ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +1.0: I hate the loader.