diff options
Diffstat (limited to 'sys/boot/sparc64')
-rw-r--r-- | sys/boot/sparc64/Makefile | 5 | ||||
-rw-r--r-- | sys/boot/sparc64/boot1/Makefile | 30 | ||||
-rw-r--r-- | sys/boot/sparc64/boot1/_start.S | 8 | ||||
-rw-r--r-- | sys/boot/sparc64/boot1/_start.s | 8 | ||||
-rw-r--r-- | sys/boot/sparc64/boot1/boot1.c | 665 | ||||
-rw-r--r-- | sys/boot/sparc64/loader/Makefile | 113 | ||||
-rw-r--r-- | sys/boot/sparc64/loader/help.sparc64 | 0 | ||||
-rw-r--r-- | sys/boot/sparc64/loader/locore.S | 113 | ||||
-rw-r--r-- | sys/boot/sparc64/loader/main.c | 513 | ||||
-rw-r--r-- | sys/boot/sparc64/loader/metadata.c | 326 | ||||
-rw-r--r-- | sys/boot/sparc64/loader/version | 6 |
11 files changed, 1787 insertions, 0 deletions
diff --git a/sys/boot/sparc64/Makefile b/sys/boot/sparc64/Makefile new file mode 100644 index 0000000..fdc87fd --- /dev/null +++ b/sys/boot/sparc64/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= boot1 loader + +.include <bsd.subdir.mk> diff --git a/sys/boot/sparc64/boot1/Makefile b/sys/boot/sparc64/boot1/Makefile new file mode 100644 index 0000000..b77671b --- /dev/null +++ b/sys/boot/sparc64/boot1/Makefile @@ -0,0 +1,30 @@ +# $FreeBSD$ + +PROG= boot1 +SRCS= _start.S boot1.c +NOMAN= +STRIP= +BINDIR?= /boot +BINMODE= 444 + +BOOTBLOCKBASE= 0x4000 + +CFLAGS= -ffreestanding -mcmodel=medlow -Os -I../.. -I../../common -I${.CURDIR}/../../common + +boot1.elf: _start.o boot1.o + ${LD} -N -Ttext ${BOOTBLOCKBASE} -o ${.TARGET} ${.ALLSRC} + +boot1.aout: boot1.elf + elf2aout -o ${.TARGET} ${.ALLSRC} + +boot1.o: ${.CURDIR}/../../common/ufsread.c + +# Construct boot1. disklabel 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.elf boot1.aout + +.include <bsd.prog.mk> diff --git a/sys/boot/sparc64/boot1/_start.S b/sys/boot/sparc64/boot1/_start.S new file mode 100644 index 0000000..30f8019 --- /dev/null +++ b/sys/boot/sparc64/boot1/_start.S @@ -0,0 +1,8 @@ +/* $FreeBSD$ */ + + .text + .globl _start +_start: + call ofw_init + nop + sir diff --git a/sys/boot/sparc64/boot1/_start.s b/sys/boot/sparc64/boot1/_start.s new file mode 100644 index 0000000..30f8019 --- /dev/null +++ b/sys/boot/sparc64/boot1/_start.s @@ -0,0 +1,8 @@ +/* $FreeBSD$ */ + + .text + .globl _start +_start: + call ofw_init + nop + sir diff --git a/sys/boot/sparc64/boot1/boot1.c b/sys/boot/sparc64/boot1/boot1.c new file mode 100644 index 0000000..1b1c1ec --- /dev/null +++ b/sys/boot/sparc64/boot1/boot1.c @@ -0,0 +1,665 @@ +/* + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/dirent.h> +#include <machine/elf.h> +#include <machine/stdarg.h> + +#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 OpenFirmware 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); +} diff --git a/sys/boot/sparc64/loader/Makefile b/sys/boot/sparc64/loader/Makefile new file mode 100644 index 0000000..b6f02e1 --- /dev/null +++ b/sys/boot/sparc64/loader/Makefile @@ -0,0 +1,113 @@ +# $FreeBSD$ + +BASE= loader +PROG= ${BASE} +STRIP= +NEWVERSWHAT= "bootstrap loader" sparc64 +BINDIR?= /boot +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(NOFORTH) +# Enable BootForth +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/sparc64 +.if exists(${.OBJDIR}/../../ficl/libficl.a) +LIBFICL= ${.OBJDIR}/../../ficl/libficl.a +.else +LIBFICL= ${.CURDIR}/../../ficl/libficl.a +.endif +.endif + +# Always add MI sources +.PATH: ${.CURDIR}/../../common +.include <${.CURDIR}/../../common/Makefile.inc> +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I${.CURDIR}/../../.. -I. + +CLEANFILES+= vers.c ${BASE}.help + +CFLAGS+= -ffreestanding +LDFLAGS= -nostdlib -static + +# Openfirmware standalone support library +LIBOFW= ${.OBJDIR}/../../ofw/libofw/libofw.a +CFLAGS+= -I${.CURDIR}/../../ofw/libofw/ + +# where to get libstand from +#XXX need a better way to do this +LIBSTAND= ${.CURDIR}/../../../../lib/libstand/libstand.a +.if !exists(${LIBSTAND}) +LIBSTAND= ${.OBJDIR}/../../../../lib/libstand/libstand.a +.if !exists(${LIBSTAND}) +LIBSTAND= -lstand +.endif +.endif +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ + +LDADD= ${LIBFICL} ${LIBOFW} ${LIBSTAND} + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +${BASE}.help: help.common help.sparc64 + cat ${.ALLSRC} | \ + awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +.PATH: ${.CURDIR}/../../forth +FILES= ${BASE}.help loader.4th support.4th loader.conf +FILESDIR_loader.conf= /boot/defaults + +.if !exists(${DESTDIR}/boot/loader.rc) +FILES+= loader.rc +.endif + +# There are no things relevant to all boot parts of FreeBSD/sparc64 yet. +#.include <${.CURDIR}/../Makefile.inc> + +.include <bsd.prog.mk> + +.if exists(${.CURDIR}/../../../sparc64/include) +beforedepend ${OBJS}: machine + +machine: + ln -sf ${.CURDIR}/../../../sparc64/include machine +.endif + +CLEANFILES+= machine diff --git a/sys/boot/sparc64/loader/help.sparc64 b/sys/boot/sparc64/loader/help.sparc64 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/sys/boot/sparc64/loader/help.sparc64 diff --git a/sys/boot/sparc64/loader/locore.S b/sys/boot/sparc64/loader/locore.S new file mode 100644 index 0000000..c1b3e2b --- /dev/null +++ b/sys/boot/sparc64/loader/locore.S @@ -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 <machine/asi.h> +#include <machine/asm.h> +#include <machine/pstate.h> +#include <machine/smp.h> +#include <machine/upa.h> + +#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 + +/* + * %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 + + .comm stack, STACK_SIZE, 32 + .comm smp_stack, STACK_SIZE, 32 diff --git a/sys/boot/sparc64/loader/main.c b/sys/boot/sparc64/loader/main.c new file mode 100644 index 0000000..ddf804a --- /dev/null +++ b/sys/boot/sparc64/loader/main.c @@ -0,0 +1,513 @@ +/* + * 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$ + */ +/* + * 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 <stand.h> +#include <sys/exec.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/linker.h> + +#include <machine/asi.h> +#include <machine/atomic.h> +#include <machine/cpufunc.h> +#include <machine/elf.h> +#include <machine/lsu.h> +#include <machine/metadata.h> +#include <machine/tte.h> +#include <machine/upa.h> + +#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; +}; + +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(vm_offset_t, vm_size_t); + +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_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_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(vm_offset_t va, vm_size_t len) +{ + vm_offset_t pa, mva; + u_long data; + + 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); + 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(void) +{ + 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"); +} + +int +main(int (*openfirm)(void *)) +{ + char bootpath[64]; + struct devsw **dp; + phandle_t chosenh; + + /* + * Tell the OpenFirmware 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(); + + 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 diff --git a/sys/boot/sparc64/loader/metadata.c b/sys/boot/sparc64/loader/metadata.c new file mode 100644 index 0000000..9bb8af0 --- /dev/null +++ b/sys/boot/sparc64/loader/metadata.c @@ -0,0 +1,326 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 + * $FreeBSD$ + */ + +#include <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> + +#include <machine/metadata.h> + +#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; + +/* + * 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_userconfig", RB_CONFIG}, + {"boot_ddb", RB_KDB}, + {"boot_gdb", RB_GDB}, + {"boot_single", RB_SINGLE}, + {"boot_verbose", RB_VERBOSE}, + {"boot_multicons", RB_MULTIPLE}, + {"boot_serial", RB_SERIAL}, + {NULL, 0} +}; + +int +md_getboothowto(char *kargs) +{ + char buf[32]; + phandle_t options; + 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_CONFIG; + 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 '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; + options = OF_finddevice("/options"); + OF_getprop(options, "output-device", buf, sizeof(buf)); + if (strcmp(buf, "ttya") == 0 || strcmp(buf, "ttyb") == 0) + howto |= RB_SERIAL; + return(howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as <name>=<value>, 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); +} diff --git a/sys/boot/sparc64/loader/version b/sys/boot/sparc64/loader/version new file mode 100644 index 0000000..bef4091 --- /dev/null +++ b/sys/boot/sparc64/loader/version @@ -0,0 +1,6 @@ +$FreeBSD$ + +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. |