diff options
Diffstat (limited to 'usr/src/psm/stand')
205 files changed, 40246 insertions, 0 deletions
diff --git a/usr/src/psm/stand/Makefile b/usr/src/psm/stand/Makefile new file mode 100644 index 0000000000..cbc6f7bc13 --- /dev/null +++ b/usr/src/psm/stand/Makefile @@ -0,0 +1,57 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../../Makefile.master + +# note: the x86 needs the "bootblks" target for installboot +SUBDIRS= lib bootblks boot cpr + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +clean.lint := TARGET= clean.lint + +.KEEP_STATE: + +all install clean lint clean.lint clobber: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +# +# Cross-reference customization: include all of the PROM and standalone +# goo in the cross-reference, except for the crufty "old" directory. +# +STANDDIR= ../../stand +PROMDIRS= ../promif ../../uts/intel/ia32/promif ../../uts/intel/promif +XRDIRS += $(STANDDIR)/lib $(STANDDIR)/sys $(PROMDIRS) +XRPRUNE = old diff --git a/usr/src/psm/stand/README b/usr/src/psm/stand/README new file mode 100644 index 0000000000..56c880ac4d --- /dev/null +++ b/usr/src/psm/stand/README @@ -0,0 +1,61 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 1996 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +README file for the usr/src/stand directory: (tpl 8/1/94) + please update this as required + +This tree has source code for both sparc and x86 platforms. +1). The lint target is implemented, but the source tree is not lint-free yet. +2). It is too much of a change to "clean-up" this directory at the time + of stand and stand.i386 merge. So, let's use the following rule for + the benefit of all. + Each time you check in a new version of a file, please try to + a). lint that file individually + b). cstyle that file +3). Please avoid using the following fragments in the common/ directory + #ifdef i386 + #ifdef sparc +4). The following fragment is non-ideal for the merge (promif) source base + #ifdef I386BOOT + It should be removed, re-org'ed after a good understanding of the + pieces involved and with suitable testing. +5). If you change "common" source files including Makefiles, you have + to build [ and test ] for all platforms. +6). The following list should be addressed and eliminated as we continue + to separate the PSM code out of shared common (PIM) code + a). nfs_readsize for sun4 and i386. + b). lib/fs/nfs_inet/netaddr.h: MAX_PKT_SIZE different between i386 and sparc + c). lib/fs/nfs_inet/nfsops.c: boot_nfs_read() uses local buffer for i386 case + d). all #ifdef sparc caused by prom_getversion() calls + +Commonly asked questions and brief answers: + +Q: Why is inetboot packaged differently? +A: inetboot is loaded by PROM code, especially old PROMs. They load + to certain specific address and can only recognize a.out header. + Thus, inetboot has to be packaged accordingly. Note that the bootblk + for sparc has the same constraints. These historical reasons do + not apply for i386 architecture. diff --git a/usr/src/psm/stand/boot/Makefile b/usr/src/psm/stand/boot/Makefile new file mode 100644 index 0000000000..cf248df166 --- /dev/null +++ b/usr/src/psm/stand/boot/Makefile @@ -0,0 +1,99 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../../../Makefile.master + +sparcv9_ARCHITECTURES = sparcv9 +sparc_ARCHITECTURES = $(sparcv9_ARCHITECTURES) +i386_ARCHITECTURES = i386 + +SUBDIRS = $($(MACH)_ARCHITECTURES) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all install lint clean: $(SUBDIRS) + +clobber: $(SUBDIRS) + $(RM) make.out lint.out + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +# +# Cross-reference customization: include all boot-related source files. +# +UTSDIR = ../../../uts +STANDLIBDIR = ../../../stand/lib +STANDSYSDIRS = ../../../stand/sys ../../../stand/i386/sys +PROMDIRS = ../../promif $(UTSDIR)/intel/promif +NAMESDIRS = ../lib/names +XRDIRS += $(STANDLIBDIR) $(STANDSYSDIRS) $(PROMDIRS) $(NAMESDIRS) +XRINCDIRS = $(UTSDIR)/sun4u $(UTSDIR)/sfmmu $(UTSDIR)/sparc/v7 \ + $(UTSDIR)/sparc/v9 $(UTSDIR)/sparc $(UTSDIR)/sun \ + $(UTSDIR)/common $(UTSDIR)/intel $(UTSDIR)/i86pc + +cscope.out tags: FRC + $(XREF) -x $@ + +FRC: + +# EXPORT DELETE START +EXPORT_SRC: + $(RM) sparc/common/wanboot.c+ + sed -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \ + < sparc/common/wanboot.c > sparc/common/wanboot.c+ + $(MV) sparc/common/wanboot.c+ sparc/common/wanboot.c + $(CHMOD) 444 sparc/common/wanboot.c + $(RM) sparc/common/wbcli.c+ + sed -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \ + < sparc/common/wbcli.c > sparc/common/wbcli.c+ + $(MV) sparc/common/wbcli.c+ sparc/common/wbcli.c + $(CHMOD) 444 sparc/common/wbcli.c + $(RM) sparc/common/ramdisk.c+ + sed -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \ + < sparc/common/ramdisk.c > sparc/common/ramdisk.c+ + $(MV) sparc/common/ramdisk.c+ sparc/common/ramdisk.c + $(CHMOD) 444 sparc/common/ramdisk.c + $(RM) sparcv9/Makefile.com+ + sed -e "/^# EXPORT DELETE START/,/^# EXPORT DELETE END/d" \ + < sparcv9/Makefile.com > sparcv9/Makefile.com+ + $(MV) sparcv9/Makefile.com+ sparcv9/Makefile.com + $(CHMOD) 444 sparcv9/Makefile.com + $(RM) Makefile+ + sed -e "/^# EXPORT DELETE START/,/^# EXPORT DELETE END/d" \ + < Makefile > Makefile+ + $(RM) Makefile + $(MV) Makefile+ Makefile + $(CHMOD) 444 Makefile +# EXPORT DELETE END diff --git a/usr/src/psm/stand/boot/Makefile.boot b/usr/src/psm/stand/boot/Makefile.boot new file mode 100644 index 0000000000..b5d0f7c8ca --- /dev/null +++ b/usr/src/psm/stand/boot/Makefile.boot @@ -0,0 +1,93 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/boot/Makefile.boot + +# +# Hack until stand makefiles are fixed +# +CLASS = 32 + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/Makefile.psm + +STANDDIR = $(TOPDIR)/stand +PSMSTANDDIR = $(TOPDIR)/psm/stand + +SYSHDRDIR = $(STANDDIR) +SYSLIBDIR = $(ROOT)/stand/lib + +PSMSYSHDRDIR = $(PSMSTANDDIR) +PSMNAMELIBDIR = $(PSMSTANDDIR)/lib/names/$(MACH) +PSMNAMELIBDIR64 = $(PSMSTANDDIR)/lib/names/$(MACH64) +PSMPROMLIBDIR = $(PSMSTANDDIR)/lib/promif/$(MACH) +PSMPROMLIBDIR64 = $(PSMSTANDDIR)/lib/promif/$(MACH64) + +# +# XXX one day we should just be able to set PROG to 'cfsboot'.. +# and everything will become a lot easier. +# +# XXX note that we build but -don't- install the HSFS boot +# program - it's unused and untested, and until it is we +# shouldn't ship it! +# +UNIBOOT = multiboot +UFSBOOT = ufsboot +WANBOOT = wanboot +NFSBOOT = inetboot +HSFSBOOT = hsfsboot + +# +# Common install modes and owners +# +FILEMODE = 644 +DIRMODE = 755 +OWNER = root +GROUP = sys + +# +# Install locations +# +ROOT_PSM_UNIBOOT= $(ROOT_PSM_DIR)/$(UNIBOOT) +ROOT_PSM_UFSBOOT= $(ROOT_PSM_DIR)/$(UFSBOOT) +ROOT_PSM_WANBOOT= $(ROOT_PSM_DIR)/$(WANBOOT) +USR_PSM_NFSBOOT = $(USR_PSM_LIB_NFS_DIR)/$(NFSBOOT) +USR_PSM_HSFSBOOT= $(USR_PSM_LIB_HSFS_DIR)/$(HSFSBOOT) + +# +# While things are pretty much 32-bit lint-clean, there are a ton of +# suspect pointer casts. Since these may be serious problems (especially +# on SPARC), this really needs to be investigated thoroughly one day. +# However, we shouldn't feel too bad: the whole kernel is linted with this +# turned off as well (along with a dozen other disabled warnings). +# +# The other two -erroff's are needed only because lint's -u flag is lame +# and also turns off "name used but not defined" checks (so we instead +# just enumerate the errors that -u turns off that we want turned off). +# +LINTFLAGS = -nmsF -erroff=E_BAD_PTR_CAST_ALIGN \ + -erroff=E_NAME_DECL_NOT_USED_DEF2 -erroff=E_NAME_DEF_NOT_USED2 diff --git a/usr/src/psm/stand/boot/Makefile.rules b/usr/src/psm/stand/boot/Makefile.rules new file mode 100644 index 0000000000..5999c83c6a --- /dev/null +++ b/usr/src/psm/stand/boot/Makefile.rules @@ -0,0 +1,124 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/boot/Makefile.rules + +#CPPFLAGS += -DDEBUG=1 + +# +# Pattern matching rules to compile the source in the current directory +# +%.o: $(TOP_CMN_DIR)/util/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(TOP_CMN_DIR)/fs/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(PROM_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(CMN_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(PIM_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(PAMD64_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(PAMD64_DIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(MACH_DIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(MACH_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: %.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(PLAT_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +# +# Pattern matching rules to lint the source in the current directory +# +%.ln: $(TOP_CMN_DIR)/util/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(TOP_CMN_DIR)/fs/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(PROM_DIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(CMN_DIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(PIM_DIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(PAMD64_DIR)/%.s + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(PAMD64_DIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(MACH_DIR)/%.s + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(MACH_DIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: %.s + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +%.ln: $(PLAT_DIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + +# +# Rules to compile libraries needed to build and lint the boot loaders. +# +$(LIBPROM_DIR)/libprom.a $(LIBPLAT_DEP) $(LIBNAME_DIR)/libnames.a: FRC + @cd $(@D); pwd; $(MAKE) $(@F) + +$(LIBPROM_DIR)/llib-lprom.ln $(LIBPLAT_DEP_L) $(LIBNAME_DIR)/llib-lnames.ln: FRC + @cd $(@D); pwd; $(MAKE) $(@F) + +FRC: diff --git a/usr/src/psm/stand/boot/Makefile.targ b/usr/src/psm/stand/boot/Makefile.targ new file mode 100644 index 0000000000..4d58601c91 --- /dev/null +++ b/usr/src/psm/stand/boot/Makefile.targ @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994 by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/boot/Makefile.files + +# +# Targets common to all versions +# +install: all $(ROOT_PSM_UFSBOOT) $(USR_PSM_NFSBOOT) + +# +# Install rules +# +include $(TOPDIR)/Makefile.psm.targ diff --git a/usr/src/psm/stand/boot/amd64/alloc.c b/usr/src/psm/stand/boot/amd64/alloc.c new file mode 100644 index 0000000000..0b1181477d --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/alloc.c @@ -0,0 +1,58 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <amd64/boothooks.h> +#include <amd64/alloc.h> +#include <amd64/amd64_page.h> +#include <amd64/cpu.h> +#include <amd64/print.h> + +void * +amd64_alloc_identity(size_t size) +{ + void *addr; + + if (addr = (void *)idmap_mem((uint32_t)0, size, AMD64_PAGESIZE)) + return (addr); + + amd64_panic("amd64_alloc_identity: boot failed to identity map 0x%lx " + "bytes\n", size); + + /*NOTREACHED*/ +} + +void * +amd64_zalloc_identity(size_t size) +{ + void *p; + + if (p = amd64_alloc_identity(size)) + bzero(p, size); + + return (p); +} diff --git a/usr/src/psm/stand/boot/amd64/amd64/alloc.h b/usr/src/psm/stand/boot/amd64/amd64/alloc.h new file mode 100644 index 0000000000..ba6a8c8da5 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/alloc.h @@ -0,0 +1,45 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_ALLOC_H +#define _AMD64_ALLOC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +extern void *amd64_alloc_identity(size_t); +extern void *amd64_zalloc_identity(size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_ALLOC_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/amd64.h b/usr/src/psm/stand/boot/amd64/amd64/amd64.h new file mode 100644 index 0000000000..f67a17d485 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/amd64.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_AMD64_H +#define _AMD64_AMD64_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/link.h> + +#include <amd64/types.h> +#include <amd64/boothooks.h> + +struct amd64_machregs; + +extern void amd64_system_reset(void); + +extern const char *amd64_getmmulist(void); +extern int amd64_config_cpu(void); + +extern struct bootops64 *init_bootops64(struct bootops *); +extern struct boot_syscalls64 *init_boot_syscalls64(struct boot_syscalls *); + +/* + * These routines probably belong in machregs.h + * Or we need to type the arguments as void * .. + */ +struct amd64_machregs; + +extern void amd64_vtrap(struct amd64_machregs *); +extern void amd64_dump_amd64_machregs(struct amd64_machregs *); +extern void amd64_dump_memlist(const char *); + +struct i386_machregs; +extern void amd64_dump_i386_machregs(struct i386_machregs *); + +extern struct amd64_machregs *amd64_makectx64(uint64_t); + +extern void amd64_exitto(struct amd64_machregs *); +extern void amd64_i386_clrtss(struct i386_machregs *); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_AMD64_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/amd64_page.h b/usr/src/psm/stand/boot/amd64/amd64/amd64_page.h new file mode 100644 index 0000000000..c2e7115205 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/amd64_page.h @@ -0,0 +1,161 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_AMD64_PAGE_H +#define _AMD64_AMD64_PAGE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AMD64_PAGESIZE 4096 +#define AMD64_PAGESIZE2M (2*1024*1024) +#define AMD64_PAGESIZE4M (4*1024*1024) + +#define AMD64_PAGEOFFSET(pagesize) ((uint64_t)((pagesize) - 1)) +#define AMD64_PAGEMASK(pagesize) (~(AMD64_PAGEOFFSET(pagesize))) + +#define AMD64_PAGEALIGNED(va, pagesize) \ + (!((uint64_t)(va) & AMD64_PAGEOFFSET(pagesize))) + +#define AMD64_PAGESIZE_OFFSET_NBITS 11 + +#define BIT_GLOBAL 8 +#define BIT_PS 7 /* PDE only */ +#define BIT_US 2 +#define BIT_RW 1 +#define BIT_VALID 0 + +#define TBL_GLOBAL (1 << BIT_GLOBAL) +#define TBL_US (1 << BIT_US) +#define TBL_RW (1 << BIT_RW) +#define TBL_VALID (1 << BIT_VALID) + +#define PDE_PS (1 << BIT_PS) + +#define IS_PDE(level, amd64_mmu_mode) \ + ((level) == (mmus[(amd64_mmu_mode)].map_level - 1)) + +#define IS_PTE(level, amd64_mmu_mode) \ + ((level) == mmus[(amd64_mmu_mode)].map_level) + +#define IS_LARGEMAP(entry) ((entry) & PDE_PS) +#define ENTRY_VALID(entry) ((entry) & TBL_VALID) + +#define PA_MODBITS_MASK 0x1eULL +#define PA_MODBITS(entry) (((uint64_t)(entry)) & PA_MODBITS_MASK) + +#define AMD64_MODE_LEGACY 0 +#define AMD64_MODE_LONG64 1 + +typedef struct amd64_mmumode { + uint8_t shift_base; /* shift to start of page tables */ + uint8_t level_shift; /* shift between page table levels */ + uint8_t map_level; /* mapping level for AMD64_PAGESIZE pages */ + uint16_t tbl_entries; /* number of entries per table level */ +} amd64_mmumode_t; + +/* + * This macro is needed because of a difference of opinion between compilers + * that can result in inadvertent sign extension when converting from 32-bit + * to 64-bit values. + * + * For example, given the code: + * + * long *i = (long *)0xf0000000; + * unsigned long long l; + * + * l = (unsigned long long)i; + * + * GCC will currently sign extend "i" before converting it to unsigned long + * long, resulting in the value 0xfffffffff0000000 being stored in l. + * + * On the other hand, Forte compilers will not do the extension, resulting in + * l receiving the value 0xf0000000. + * + * The only way to assure sane results regardless of compiler is to use this + * macro whenever converting any value to an unsigned 64-bit value. + */ +#define UINT64_FROMPTR32(val32) ((uint64_t)(uintptr_t)(val32)) + +#define TBL_ENTRY_DEFAULT(pa) (UINT64_FROMPTR32(pa) | TBL_RW | TBL_VALID) +#define TBL_PTR(table) ((uint64_t *)(&table)) + +#define TBL_INDEX(va, shift, mask) (((va) >> (shift)) & mask) + +#define TBL_ENTRY32(amd64_mmu_mode, tbl_base, va, shift, mask) \ + (((amd64_mmu_mode) == AMD64_MODE_LEGACY) ? \ + (*(((uint32_t *)(tbl_base)) + \ + TBL_INDEX((va), (shift), (mask)))) : \ + ((uint32_t)*(((uint64_t *)(tbl_base)) + \ + TBL_INDEX((va), (shift), (mask))))) + +#define TBL_ENTRY64(amd64_mmu_mode, tbl_base, va, shift, mask) \ + (((amd64_mmu_mode) == AMD64_MODE_LEGACY) ? \ + ((uint64_t)(*(((uint32_t *)(tbl_base)) + \ + TBL_INDEX((va), (shift), (mask))))) : \ + (*(((uint64_t *)(tbl_base)) + TBL_INDEX((va), (shift), (mask))))) + +#define SET_TABLEVAL(amd64_mmu_mode, tbl_base, va, shift, mask, val) \ + (((amd64_mmu_mode) == AMD64_MODE_LEGACY) ? \ + (*(((uint32_t *)(tbl_base)) + \ + TBL_INDEX((va), (shift), (mask))) = (uint32_t)val) : \ + (*(((uint64_t *)(tbl_base)) + TBL_INDEX((va), (shift), \ + (mask))) = val)) + +#define VA64_OFFSET (0xffffffff00000000ULL) + +#define ADDR_TRUNC(a) ((void *)((uintptr_t)(a))) +#define ADDR_XTND(a) (((uintptr_t)(a)) == 0 ? 0ULL : \ + ((UINT64_FROMPTR32(a)) | VA64_OFFSET)) + +extern void amd64_map_mem(uint64_t, uint64_t, uint32_t, uint8_t, uint32_t, + uint16_t); + +extern uint16_t amd64_modbits(uint64_t); + +extern uint64_t amd64_legacy_physaddr(uint32_t); +extern uint64_t amd64_long_physaddr(uint64_t); +extern uint64_t amd64_physaddr(uint64_t, uint8_t); + +extern uint64_t amd64_long_lookup(uint64_t, uint32_t *, uint32_t); +extern uint32_t amd64_legacy_lookup(uint64_t, uint32_t *, uint32_t); +extern uint64_t amd64_legacy_lookup_physaddr(uint64_t, uint32_t); + +extern uint64_t amd64_init_longpt(uint32_t); + +extern void amd64_xlate_legacy_va(uint32_t, uint32_t, uint32_t, uint32_t); +extern void amd64_xlate_long_va(uint64_t, uint32_t, uint32_t, uint32_t); + +extern void amd64_xlate_boot_tables(uint32_t, uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_AMD64_PAGE_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/auxv64.h b/usr/src/psm/stand/boot/amd64/amd64/auxv64.h new file mode 100644 index 0000000000..42e897e7ce --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/auxv64.h @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_AUXV64_H +#define _AMD64_AUXV64_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/auxv.h> + +typedef struct { + int a_type; + int a_pad; /* XX64 */ + union { + int64_t a_val; + uint64_t a_ptr; + } a_un; +} auxv64_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_AUXV64_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/boothooks.h b/usr/src/psm/stand/boot/amd64/amd64/boothooks.h new file mode 100644 index 0000000000..becc1ef9b9 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/boothooks.h @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_BOOTHOOKS_H +#define _AMD64_BOOTHOOKS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/bootconf.h> +#include <sys/bootsvcs.h> + +/* + * Grrr... conflicting #defines in sys/bootsvcs.h and sys/saio.h... + */ +#undef printf +#undef getchar +#undef putchar +#undef ischar + +#include <sys/saio.h> +#include <strings.h> + +extern caddr_t idmap_mem(uint32_t, size_t, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_BOOTHOOKS_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/bootops64.h b/usr/src/psm/stand/boot/amd64/amd64/bootops64.h new file mode 100644 index 0000000000..1281ccef3f --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/bootops64.h @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_BOOTOPS64_H +#define _AMD64_BOOTOPS64_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/inttypes.h> + +#include <amd64/types.h> + +struct bsys_mem64 { + caddr64_t physinstalled; /* struct memlist64 pointer */ + caddr64_t physavail; /* struct memlist64 pointer */ + caddr64_t pcimem; /* struct memlist64 pointer */ +}; + +/* + * We need bootops-extensions >= 1 to make S10 work. + * bsys_version is BO_VERSION == 5. + */ +struct bootops64 { + uint32_t bsys_version; + uint32_t __bsys_pad0; + caddr64_t boot_mem; /* struct bsys_mem64 pointer */ + fnaddr64_t bsys_alloc; + fnaddr64_t bsys_free; + fnaddr64_t bsys_getproplen; + fnaddr64_t bsys_getprop; + fnaddr64_t bsys_nextprop; + fnaddr64_t bsys_printf; + fnaddr64_t bsys_doint; + fnaddr64_t bsys_ealloc; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_BOOTOPS64_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/bootsvcs64.h b/usr/src/psm/stand/boot/amd64/amd64/bootsvcs64.h new file mode 100644 index 0000000000..4fd533e2df --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/bootsvcs64.h @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_BOOTSVCS64_H +#define _AMD64_BOOTSVCS64_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * We have to do this uglyness because of <bootsvcs.h>, sigh... + */ + +#ifndef _KERNEL +#define _KERNEL 1 +#define __XX64_KERNEL 1 +#endif /* _KERNEL */ + +#undef getchar +#undef putchar +#undef ischar + +#include <amd64/types.h> + +struct boot_syscalls64 { + fnaddr64_t getchar; /* 7 - getchar */ + fnaddr64_t putchar; /* 8 - putchar */ + fnaddr64_t ischar; /* 9 - ischar */ +}; + +#ifdef __XX64_KERNEL +#undef _KERNEL +#undef __XX64_KERNEL +#endif /* __XX64_KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_BOOTSVCS64_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/cpu.h b/usr/src/psm/stand/boot/amd64/amd64/cpu.h new file mode 100644 index 0000000000..d92faaeff0 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/cpu.h @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_CPU +#define _AMD64_CPU + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +extern void amd64_flush_tlb(void); +extern void amd64_flush_tlbentry(caddr_t); + +extern ulong_t amd64_get_cr2(void); +extern ulong_t amd64_get_cr0(void); +extern ulong_t amd64_get_cr3(void); +extern ulong_t amd64_get_cr4(void); + +extern ulong_t amd64_get_eflags(void); + +struct amd64_cpuid_regs { + uint32_t r_eax; + uint32_t r_ebx; + uint32_t r_ecx; + uint32_t r_edx; +}; + +#define AMD64_Auth 0x68747541 +#define AMD64_enti 0x69746e65 +#define AMD64_cAMD 0x444d4163 + +extern uint32_t amd64_cpuid_supported(void); +extern void amd64_cpuid_insn(uint32_t, struct amd64_cpuid_regs *); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_CPU */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/debug.h b/usr/src/psm/stand/boot/amd64/amd64/debug.h new file mode 100644 index 0000000000..d62d24c927 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/debug.h @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_DEBUG_H +#define _AMD64_DEBUG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/varargs.h> +#include <sys/promif.h> +#include <sys/debug.h> + +extern int amd64_debug; +extern int amd64_pt_debug; +extern uint_t bop_trace; + +#define dprintf if (amd64_debug) printf + +#define AMD64_TRACE_BOP_IO 1 +#define AMD64_TRACE_BOP_VM 2 +#define AMD64_TRACE_BOP_PROP 4 +#define AMD64_TRACE_BOP_1275 8 +#define AMD64_TRACE_BOP_BIOS 16 + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_DEBUG_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/machregs.h b/usr/src/psm/stand/boot/amd64/amd64/machregs.h new file mode 100644 index 0000000000..6784059966 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/machregs.h @@ -0,0 +1,198 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_MACHREGS_H +#define _AMD64_MACHREGS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_ASM) + +/* + * AMD64 is somewhat unique in that it involves switching the state + * of the machine back and forth between being a complete implementation + * of an i386 processor, and a complete implementation of an amd64 + * processor. As a result, it has to "know" about the state of both + * physical machines. + */ + +#include <sys/types.h> +#include <amd64/tss.h> +#include <amd64/segments.h> + +struct i386_machregs { + + /* + * This is the privileged machine (register) state + */ + + uint32_t r_cr0; + uint32_t r_cr2; + uint32_t r_cr3; + uint32_t r_cr4; + + union { + desctbr_t un_gdt; + uint64_t __pad0; + } r_gdt_un; +#define r_gdt r_gdt_un.un_gdt + + union { + desctbr_t un_idt; + uint64_t __pad0; + } r_idt_un; +#define r_idt r_idt_un.un_idt + + uint32_t r_ldt; + uint32_t r_tr; + + /* + * The rest of this structure is an i386 'struct regs' + */ + + int32_t r_gs; + int32_t r_fs; + int32_t r_es; + int32_t r_ds; + int32_t r_edi; + int32_t r_esi; + int32_t r_ebp; + int32_t r_esp; + int32_t r_ebx; + int32_t r_edx; + int32_t r_ecx; + int32_t r_eax; + int32_t r_trapno; + int32_t r_err; + int32_t r_eip; + int32_t r_cs; + int32_t r_efl; + int32_t r_uesp; + int32_t r_ss; +}; + +/* + * XX64 need assertions to validate structure offsets are really + * what they need to be! + */ + +struct amd64_machregs { + /* + * This is the privileged machine (register) state + * (Does NOT include amd64-specific MSRs, because boot doesn't + * touch them) + * + * XX64 An open question, however, is if the switch between amd64 + * and i386 modes damages any of them -- we may need to save more + * than present below. + */ + + uint64_t r_kgsbase; + uint64_t r_gsbase; + uint64_t r_fsbase; + + uint64_t r_cr0; + uint64_t r_cr2; + uint64_t r_cr3; + uint64_t r_cr4; + uint64_t r_cr8; + + union { + desctbr64_t un_gdt; + upad128_t __pad0; + } r_gdt_un; + + union { + desctbr64_t un_idt; + upad128_t __pad0; + } r_idt_un; + + uint64_t r_ldt; + uint64_t r_tr; + + /* + * The rest of this structure is an amd64 'struct regs' + * + * It is intended to match the 'struct regs' definition + * in amd64/sys/privregs.h + * + * XX64 Need to ensure that it does! + */ + + int64_t r_rdi; + int64_t r_rsi; + int64_t r_rdx; + int64_t r_rcx; + int64_t r_r8; + int64_t r_r9; + int64_t r_rax; + int64_t r_rbx; + int64_t r_rbp; + int64_t r_r10; + int64_t r_r11; + int64_t r_r12; + int64_t r_r13; + int64_t r_r14; + int64_t r_r15; + int64_t r_gs; + int64_t r_fs; + int64_t r_ds; + int64_t r_es; + int64_t r_trapno; + int64_t r_err; + int64_t r_rip; + int64_t r_cs; + int64_t r_rfl; + int64_t r_rsp; + int64_t r_ss; +}; + +/* + * C-calling convention argument order: + * + * %rdi, %rsi, %rdx, %rcx, %r8, %r9 + * + * and how to get them out of an amd64_machregs structure: + */ + +#define _ARG1(rp) ((rp)->r_rdi) +#define _ARG2(rp) ((rp)->r_rsi) +#define _ARG3(rp) ((rp)->r_rdx) +#define _ARG4(rp) ((rp)->r_rcx) +#define _ARG5(rp) ((rp)->r_r8) +#define _ARG6(rp) ((rp)->r_r9) + +#endif /* !_ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_MACHREGS_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/memlist64.h b/usr/src/psm/stand/boot/amd64/amd64/memlist64.h new file mode 100644 index 0000000000..ce3978e1e8 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/memlist64.h @@ -0,0 +1,49 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_MEMLIST64_H +#define _AMD64_MEMLIST64_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <amd64/types.h> + +struct memlist64 { + uint64_t address; /* starting address of memory segment */ + uint64_t size; /* size of same */ + caddr64_t next; /* struct memlist64 pointer */ + caddr64_t prev; /* struct memlist64 pointer */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_MEMLIST64_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/msr.h b/usr/src/psm/stand/boot/amd64/amd64/msr.h new file mode 100644 index 0000000000..4bbba75b9b --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/msr.h @@ -0,0 +1,46 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_MSR_H +#define _AMD64_MSR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/controlregs.h> + +extern void amd64_rdmsr(uint32_t, uint64_t *); +extern void amd64_wrmsr(uint32_t, const uint64_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_MSR_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/print.h b/usr/src/psm/stand/boot/amd64/amd64/print.h new file mode 100644 index 0000000000..80b3edff33 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/print.h @@ -0,0 +1,61 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_PRINT_H +#define _AMD64_PRINT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/varargs.h> + +#undef printf /* unbelievably broken bootsvcs.h */ + +extern int amd64_vsnprintf(char *, size_t, const char *, va_list) + __VPRINTFLIKE(3); +extern int amd64_vsnprintf64(char *, size_t, const char *, va_list) + __VPRINTFLIKE(3); +extern int amd64_snprintf(char *, size_t, const char *, ...) + __PRINTFLIKE(3); +extern int amd64_snprintf64(char *, size_t, const char *, ...) + __PRINTFLIKE(3); +extern void amd64_vpanic(const char *, va_list) + __VPRINTFLIKE(1); +extern void amd64_panic(const char *, ...) + __PRINTFLIKE(1); +extern void amd64_warning(const char *, ...) + __PRINTFLIKE(1); +extern int amd64_assfail(const char *, const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_PRINT_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/segments.h b/usr/src/psm/stand/boot/amd64/amd64/segments.h new file mode 100644 index 0000000000..478fc99790 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/segments.h @@ -0,0 +1,386 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_SEGMENTS_H +#define _AMD64_SEGMENTS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Copyright (c) 1989, 1990 William F. Jolitz + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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: @(#)segments.h 7.1 (Berkeley) 5/9/91 + * $FreeBSD: src/sys/i386/include/segments.h,v 1.34 2003/09/10 01:07:04 + * jhb Exp $ + * + * 386 Segmentation Data Structures and definitions + * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989 + */ + +/* + * Selector register format + * CS, DS, ES, FS, GS, SS + * + * 15 3 2 1 0 + * +---------------------+---+----+ + * | SI |TI |RPL | + * +---------------------+---+----+ + * + * SI = selector index + * TI = table indicator (0 = GDT, 1 = LDT) + * RPL = requestor privilege level + */ +#define SELTOIDX(s) ((s) >> 3) /* selector to index */ +#define IDXTOSEL(s) ((s) << 3) /* index to selector */ +#define SEL_KPL 0 /* kernel priority level */ +#define SEL_UPL 3 /* user priority level */ +#define SEL_TI_LDT 4 /* local descriptor table */ +#define SEL_LDT(s) (IDXTOSEL(s) | SEL_TI_LDT | SEL_UPL) /* local sel */ +#define SEL_GDT(s, r) (IDXTOSEL(s) | r) /* global sel */ +#define SELISLDT(s) (((s) & SEL_TI_LDT) == SEL_TI_LDT) +#define CPL_MASK 3 /* RPL mask for selector */ + +#ifndef _ASM + +typedef uint16_t selector_t; /* selector reigster */ + +/* + * Hardware descriptor table register format for GDT and IDT. + */ +#pragma pack(2) +typedef struct descriptor_table_register64 { + uint16_t dtr_limit; /* table limit */ + uint64_t dtr_base; /* table base address */ +} desctbr64_t; +#pragma pack() + +#pragma pack(2) +typedef struct descriptor_table_register { + uint16_t dtr_limit; /* table limit */ + uint32_t dtr_base; /* table base address */ +} desctbr_t; +#pragma pack() + + +/* + * Functions for loading and storing descriptor table + * registers. + */ +extern void rd_idtr(desctbr_t *); +extern void wr_idtr(desctbr_t *); +extern void rd_gdtr(desctbr_t *); +extern void wr_gdtr(desctbr_t *); +extern void wr_ldtr(selector_t); +extern void wr_tsr(selector_t); + +/* + * User segment descirptors (code and data). + * Legacy mode 64-bits wide. + */ +typedef struct user_segment_descriptor { + uint32_t usd_lolimit:16; /* segment limit 15:0 */ + uint32_t usd_lobase:16; /* segment base 15:0 */ + uint32_t usd_midbase:8; /* segment base 23:16 */ + uint32_t usd_type:5; /* segment type, includes S bit */ + uint32_t usd_dpl:2; /* segment descriptor priority level */ + uint32_t usd_p:1; /* segment descriptor present */ + uint32_t usd_hilimit:4; /* segment limit 19:16 */ + uint32_t usd_avl:1; /* available to sw, but not used */ + uint32_t usd_reserved:1; /* unsued, ignored */ + uint32_t usd_def32:1; /* default 32 vs 16 bit operand */ + uint32_t usd_gran:1; /* limit unit (bytes vs pages) */ + uint32_t usd_hibase:8; /* segment base 31:24 */ +} user_desc_t; + +/* + * User segment descriptors. + * Long mode 64-bits wide. + * + * In 32-bit compatibility mode (%cs:usd_long=0) all fields are interpreted + * as in legacy mode for both code and data. + * + * In 64-bit mode (%cs:usd_long=1) code segments only have the conforming + * bit in usd_type, usd_dpl, usd_p, usd_long and usd_def32=0. usd_def32 + * must be zero in 64-bit mode. Setting it to 1 is reserved for future use. + * All other fields are loaded but ignored by hardware. + * + * 64-bit data segments only have usd_p. All other fields are loaded but + * ignored by hardware when in 64-bit mode. + */ +typedef struct user_segment_descriptor64 { + uint32_t usd_lolimit:16; /* segment limit 15:0 */ + uint32_t usd_lobase:16; /* segment base 15:0 */ + uint32_t usd_midbase:8; /* segment base 23:16 */ + uint32_t usd_type:5; /* segment type, includes S bit */ + uint32_t usd_dpl:2; /* segment descriptor priority level */ + uint32_t usd_p:1; /* segment descriptor present */ + uint32_t usd_hilimit:4; /* segment limit 19:16 */ + uint32_t usd_avl:1; /* available to sw, but not used */ + uint32_t usd_long:1; /* long mode (%cs only) */ + uint32_t usd_def32:1; /* default 32 vs 16 bit operand */ + uint32_t usd_gran:1; /* limit gran (byte/page units) */ + uint32_t usd_hibase:8; /* segment base 31:24 */ +} user_desc64_t; + +/* + * System segment descriptors for LDT and TSS segments. + * Legacy mode 64-bits wide. + */ +typedef struct system_segment_descriptor { + uint32_t ssd_lolimit:16; /* segment limit 15:0 */ + uint32_t ssd_lobase:16; /* segment base 15:0 */ + uint32_t ssd_midbase:8; /* segment base 23:16 */ + uint32_t ssd_type:4; /* segment type */ + uint32_t ssd_zero:1; /* must be zero */ + uint32_t ssd_dpl:2; /* segment descriptor priority level */ + uint32_t ssd_p:1; /* segment descriptor present */ + uint32_t ssd_hilimit:4; /* segment limit 19:16 */ + uint32_t ssd_avl:1; /* available to sw, but not used */ + uint32_t ssd_reserved:2; /* unused, ignored */ + uint32_t ssd_gran:1; /* limit unit (bytes vs pages) */ + uint32_t ssd_hibase:8; /* segment base 31:24 */ +} system_desc_t; + +/* + * System segment descriptors for LDT and TSS segments. + * Long mode 128-bits wide. + * + * 32-bit LDT and TSS descriptor types are redefined to 64-bit equivalents. + * All other legacy types are reserved and illegal. + */ +typedef struct system_segment_descriptor64 { + uint32_t ssd_lolimit:16; /* segment limit 15:0 */ + uint32_t ssd_lobase:16; /* segment base 15:0 */ + uint32_t ssd_midbase:8; /* segment base 23:16 */ + uint32_t ssd_type:4; /* segment type */ + uint32_t ssd_zero1:1; /* must be zero */ + uint32_t ssd_dpl:2; /* segment descriptor priority level */ + uint32_t ssd_p:1; /* segment descriptor present */ + uint32_t ssd_hilimit:4; /* segment limit 19:16 */ + uint32_t ssd_avl:1; /* available to sw, but not used */ + uint32_t ssd_resv1:2; /* unused, ignored */ + uint32_t ssd_gran:1; /* limit unit (bytes vs pages) */ + uint32_t ssd_hibase:8; /* segment base 31:24 */ + uint32_t ssd_hi64base:32; /* segment base 63:32 */ + uint32_t ssd_resv2:8; /* unused, ignored */ + uint32_t ssd_zero2:5; /* must be zero */ + uint32_t ssd_resv3:19; /* unused, ignored */ +} system_desc64_t; + +/* + * System gate segment descriptors for interrupt, trap, call and task gates. + * Legacy mode 64-bits wide. + */ +typedef struct gate_segment_descriptor { + uint32_t sgd_looffset:16; /* segment code offset 15:0 */ + uint32_t sgd_selector:16; /* target code or task selector */ + uint32_t sgd_stkcpy:5; /* number of stack wds to cpy */ + uint32_t sgd_resv:3; /* unused, ignored */ + uint32_t sgd_type:5; /* segment type, includes S bit */ + uint32_t sgd_dpl:2; /* segment descriptor priority level */ + uint32_t sgd_p:1; /* segment descriptor present */ + uint32_t sgd_hioffset:16; /* code seg off 31:16 */ +} gate_desc_t; + +/* + * System segment descriptors for interrupt, trap and call gates. + * Long mode 128-bits wide. + * + * 32-bit interrupt, trap and call gate types are redefined to 64-bit + * equivalents. Task gates along with all other legacy types are reserved + * and illegal. + */ +typedef struct gate_segment_descriptor64 { + uint32_t sgd_looffset:16; /* segment code offset 15:0 */ + uint32_t sgd_selector:16; /* target code or task selector */ + uint32_t sgd_ist:3; /* IST table index */ + uint32_t sgd_resv1:5; /* unused, ignored */ + uint32_t sgd_type:5; /* segment type, includes S bit */ + uint32_t sgd_dpl:2; /* segment descriptor priority level */ + uint32_t sgd_p:1; /* segment descriptor present */ + uint32_t sgd_hioffset:16; /* segment code offset 31:16 */ + uint32_t sgd_hi64offset:32; /* segment code offset 63:32 */ + uint32_t sgd_resv2:8; /* unused, ignored */ + uint32_t sgd_zero:5; /* call gate only: must be zero */ + uint32_t sgd_resv3:19; /* unused, ignored */ +} gate_desc64_t; + +#undef BYTES +#define BYTES 0 + +#undef PAGES +#define PAGES 1 + +#undef OP32 +#define OP32 1 + +#undef LONG +#define LONG 1 + +#undef SHORT +#define SHORT 0 + +/* + * functions for initializing and updating segment descriptors. + */ +extern void set_usegd64(user_desc64_t *, uint_t, void *, size_t, uint_t, uint_t, + uint_t, uint_t); +extern void set_gatesegd64(gate_desc64_t *, void (*)(void), selector_t, uint_t, + uint_t, uint_t); +void set_syssegd64(system_desc64_t *, void *, size_t, uint_t, uint_t); + +extern void set_usegd(user_desc_t *, void *, size_t, uint_t, uint_t, + uint_t, uint_t); +extern void set_gatesegd(gate_desc_t *, void (*)(void), selector_t, + uint_t, uint_t, uint_t); +void set_syssegd(system_desc_t *, void *, size_t, uint_t, uint_t); + +#endif /* _ASM */ + +/* + * System segments and gate types. + * + * In long mode i386 32-bit ldt, tss, call, interrupt and trap gate + * types are redefined into 64-bit equivalents. + */ +#define SDT_SYSNULL 0 /* system null */ +#define SDT_SYS286TSS 1 /* system 286 TSS available */ +#define SDT_SYSLDT 2 /* system local descriptor table */ +#define SDT_SYS286BSY 3 /* system 286 TSS busy */ +#define SDT_SYS286CGT 4 /* system 286 call gate */ +#define SDT_SYSTASKGT 5 /* system task gate */ +#define SDT_SYS286IGT 6 /* system 286 interrupt gate */ +#define SDT_SYS286TGT 7 /* system 286 trap gate */ +#define SDT_SYSNULL2 8 /* system null again */ +#define SDT_SYSTSS 9 /* system TSS available */ +#define SDT_SYSNULL3 10 /* system null again */ +#define SDT_SYSTSSBSY 11 /* system TSS busy */ +#define SDT_SYSCGT 12 /* system call gate */ +#define SDT_SYSNULL4 13 /* system null again */ +#define SDT_SYSIGT 14 /* system interrupt gate */ +#define SDT_SYSTGT 15 /* system trap gate */ + +/* + * Memory segment types. + * + * While in long mode expand-down, writable and accessed type field + * attributes are ignored. Only the conforming bit is loaded by hardware + * for long mode code segment descriptors. + */ +#define SDT_MEMRO 16 /* read only */ +#define SDT_MEMROA 17 /* read only accessed */ +#define SDT_MEMRW 18 /* read write */ +#define SDT_MEMRWA 19 /* read write accessed */ +#define SDT_MEMROD 20 /* read only expand dwn limit */ +#define SDT_MEMRODA 21 /* read only expand dwn limit accessed */ +#define SDT_MEMRWD 22 /* read write expand dwn limit */ +#define SDT_MEMRWDA 23 /* read write expand dwn limit accessed */ +#define SDT_MEME 24 /* execute only */ +#define SDT_MEMEA 25 /* execute only accessed */ +#define SDT_MEMER 26 /* execute read */ +#define SDT_MEMERA 27 /* execute read accessed */ +#define SDT_MEMEC 28 /* execute only conforming */ +#define SDT_MEMEAC 29 /* execute only accessed conforming */ +#define SDT_MEMERC 30 /* execute read conforming */ +#define SDT_MEMERAC 31 /* execute read accessed conforming */ + + +/* + * Entries in the Interrupt Descriptor Table (IDT) + */ +#define IDT_DE 0 /* #DE: Divide Error */ +#define IDT_DB 1 /* #DB: Debug */ +#define IDT_NMI 2 /* Nonmaskable External Interrupt */ +#define IDT_BP 3 /* #BP: Breakpoint */ +#define IDT_OF 4 /* #OF: Overflow */ +#define IDT_BR 5 /* #BR: Bound Range Exceeded */ +#define IDT_UD 6 /* #UD: Undefined/Invalid Opcode */ +#define IDT_NM 7 /* #NM: No Math Coprocessor */ +#define IDT_DF 8 /* #DF: Double Fault */ +#define IDT_FPUGP 9 /* Coprocessor Segment Overrun */ +#define IDT_TS 10 /* #TS: Invalid TSS */ +#define IDT_NP 11 /* #NP: Segment Not Present */ +#define IDT_SS 12 /* #SS: Stack Segment Fault */ +#define IDT_GP 13 /* #GP: General Protection Fault */ +#define IDT_PF 14 /* #PF: Page Fault */ +#define IDT_MF 16 /* #MF: FPU Floating-Point Error */ +#define IDT_AC 17 /* #AC: Alignment Check */ +#define IDT_MC 18 /* #MC: Machine Check */ +#define IDT_XF 19 /* #XF: SIMD Floating-Point Exception */ +#define IDT_SYSCALL 0x80 /* System Call Interrupt Vector */ +#define NIDT 256 /* size in entries of IDT */ + +/* + * Entries in the Global Descriptor Table (GDT) for VMX (stretch) + * + * We make sure to space the system descriptors (LDT's, TSS') + * such that they are double gdt slot aligned. This is because + * in long mode system segment decriptors expand to 128 bits. + */ +#define GDT_NULL 0 /* null */ +#define GDT_DATA32 1 /* 32-bit data */ +#define GDT_CODE32 2 /* 32-bit code */ +#define GDT_DATA64 3 /* 64-bit data */ +#define GDT_CODE64 4 /* 64-bit code */ +#define GDT_NULL1 5 /* null */ +#define GDT_TSS64 6 /* 64-bit tss */ +#define GDT_NULL2 7 /* null */ + +#define NGDT 8 + +#ifndef _ASM + +extern void amd64_div0trap(), amd64_dbgtrap(), amd64_nmiint(), amd64_brktrap(); +extern void amd64_ovflotrap(), amd64_boundstrap(), amd64_invoptrap(); +extern void amd64_ndptrap(), amd64_doublefault(); +extern void amd64_invaltrap(), amd64_invtsstrap(), amd64_segnptrap(); +extern void amd64_stktrap(), amd64_gptrap(), amd64_pftrap(), amd64_ndperr(); +extern void amd64_overrun(), amd64_resvtrap(), amd64_achktrap(); +extern void amd64_mcetrap(), amd64_xmtrap(); + +#endif /* _ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_SEGMENTS_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/tss.h b/usr/src/psm/stand/boot/amd64/amd64/tss.h new file mode 100644 index 0000000000..1aff429e8d --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/tss.h @@ -0,0 +1,120 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ +/* All Rights Reserved */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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: @(#)tss.h 5.4 (Berkeley) 1/18/91 + * $FreeBSD: src/sys/i386/include/tss.h,v 1.13 2002/09/23 05:04:05 peter Exp $ + */ + +#ifndef _AMD64_TSS_H +#define _AMD64_TSS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASM +/* + * amd64 long mode TSS definition + */ +#pragma pack(2) +typedef struct amd64tss { + uint32_t tss_rsvd0; /* reserved, ignored */ + uint64_t tss_rsp0; /* stack pointer CPL = 0 */ + uint64_t tss_rsp1; /* stack pointer CPL = 1 */ + uint64_t tss_rsp2; /* stack pointer CPL = 2 */ + uint64_t tss_rsvd1; /* reserved, ignored */ + uint64_t tss_ist1; /* Interrupt stack table 1 */ + uint64_t tss_ist2; /* Interrupt stack table 2 */ + uint64_t tss_ist3; /* Interrupt stack table 3 */ + uint64_t tss_ist4; /* Interrupt stack table 4 */ + uint64_t tss_ist5; /* Interrupt stack table 5 */ + uint64_t tss_ist6; /* Interrupt stack table 6 */ + uint64_t tss_ist7; /* Interrupt stack table 7 */ + uint64_t tss_rsvd2; /* reserved, ignored */ + uint16_t tss_rsvd3; /* reserved, ignored */ + uint16_t tss_iobase; /* io bitmap offset */ +} amd64tss_t; +#pragma pack() + +/* + * Legacy 386 TSS definition + */ +typedef struct i386tss { + uint32_t tss_link; /* 16-bit prior TSS selector */ + uint32_t tss_esp0; + uint32_t tss_ss0; + uint32_t tss_esp1; + uint32_t tss_ss1; + uint32_t tss_esp2; + uint32_t tss_ss2; + uint32_t tss_cr3; + uint32_t tss_eip; + uint32_t tss_eflags; + uint32_t tss_eax; + uint32_t tss_ecx; + uint32_t tss_edx; + uint32_t tss_ebx; + uint32_t tss_esp; + uint32_t tss_ebp; + uint32_t tss_esi; + uint32_t tss_edi; + uint32_t tss_es; + uint32_t tss_cs; + uint32_t tss_ss; + uint32_t tss_ds; + uint32_t tss_fs; + uint32_t tss_gs; + uint32_t tss_ldt; + uint32_t tss_bitmapbase; +} i386tss_t; + +#endif /* !_ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_TSS_H */ diff --git a/usr/src/psm/stand/boot/amd64/amd64/types.h b/usr/src/psm/stand/boot/amd64/amd64/types.h new file mode 100644 index 0000000000..127effff25 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/amd64/types.h @@ -0,0 +1,49 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AMD64_TYPES_H +#define _AMD64_TYPES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/inttypes.h> + +typedef uint64_t caddr64_t; +typedef uint64_t fnaddr64_t; +typedef uint64_t size64_t; + +#define BITX(u, h, l) (((u) >> (l)) & ((1lu << ((h) - (l) + 1lu)) - 1lu)) + +#ifdef __cplusplus +} +#endif + +#endif /* _AMD64_TYPES_H */ diff --git a/usr/src/psm/stand/boot/amd64/context.c b/usr/src/psm/stand/boot/amd64/context.c new file mode 100644 index 0000000000..7fb2d61c7f --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/context.c @@ -0,0 +1,322 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/trap.h> +#include <sys/controlregs.h> +#include <sys/sysmacros.h> +#include <sys/link.h> + +#include <amd64/types.h> +#include <amd64/amd64.h> +#include <amd64/cpu.h> +#include <amd64/machregs.h> +#include <amd64/tss.h> +#include <amd64/segments.h> +#include <amd64/debug.h> +#include <amd64/bootops64.h> +#include <amd64/bootsvcs64.h> +#include <amd64/amd64_page.h> + +/* + * This save area is initialized by amd64_exitto(), and used to + * restore the state of the machine before invoking various + * bootops. + * + * However, it needs to be mapped 1:1 so that we can reference it + * while paging is disabled. This is achieved via mapfile trickery; + * we glom the entire program into one contiguous segment. + */ +struct i386_machregs exitto_i386_machregs; + +/*CSTYLED*/ +#pragma align 16 (amd64_stack) +static uint8_t amd64_stack[1024*16]; + +/*CSTYLED*/ +#pragma align 16 (amd64_dblfault_stack) +static uint8_t amd64_dblfault_stack[1024*16]; + +/*CSTYLED*/ +#pragma align 16 (amd64_exception_stack) +static uint8_t amd64_exception_stack[1024*16]; + +static const selector_t cs64sel = SEL_GDT(GDT_CODE64, SEL_KPL); +static const selector_t ds64sel = SEL_GDT(GDT_DATA64, SEL_KPL); + +static user_desc64_t gdt64[NGDT]; /* long mode gdt */ +static amd64tss_t tss64; /* long mode tss */ + +static void +make_gdt(desctbr64_t *rgdt) +{ + /* + * TSS + */ + bzero(&tss64, sizeof (tss64)); + + /* + * All exceptions but #DF will run on the exception stack. + */ + tss64.tss_ist1 = (uint64_t)(uintptr_t) + &amd64_exception_stack[sizeof (amd64_exception_stack)]; + + /* + * #DF (double fault) gets its own private stack. + */ + tss64.tss_ist2 = (uint64_t)(uintptr_t) + &amd64_dblfault_stack[sizeof (amd64_dblfault_stack)]; + + /* + * GDT + */ + bzero(gdt64, sizeof (gdt64)); + + /* + * 32-bit legacy or compatibility mode for data. + * Maps entire 4G address space. + */ + set_usegd64(&gdt64[GDT_DATA32], SHORT, NULL, 0xfffff, SDT_MEMRW, + SEL_KPL, PAGES, OP32); + + /* + * 32-bit legacy or compatibility mode for code. + * Maps entire 4G address space. + */ + set_usegd64(&gdt64[GDT_CODE32], SHORT, NULL, 0xfffff, SDT_MEMERC, + SEL_KPL, PAGES, OP32); + + /* + * 64-bit long mode for data. XXX don't really need this. + * Maps entire 64-bit address space by definition. + */ + set_usegd64(&gdt64[GDT_DATA64], LONG, NULL, 0, SDT_MEMRW, + SEL_KPL, PAGES, OP32); + + /* + * 64-bit long mode for code. + * Maps entire 64-bit address space by definition. + */ + set_usegd64(&gdt64[GDT_CODE64], LONG, NULL, 0, SDT_MEMERC, + SEL_KPL, PAGES, OP32); + + /* + * 64-bit long mode TSS. + */ + set_syssegd64((system_desc64_t *)&gdt64[GDT_TSS64], &tss64, + sizeof (tss64), SDT_SYSTSS, SEL_KPL); + + rgdt->dtr_limit = sizeof (gdt64) - 1; + rgdt->dtr_base = (uint64_t)(uintptr_t)gdt64; +} + +static gate_desc64_t idt64[NIDT]; /* long mode idt */ + +static void +make_idt(desctbr64_t *ridt) +{ + int i; + + /* + * IDT + * + * First initialize all entries to reserve trap then overwrite + * the important ones with specific handlers. + * + * XXX how big does this idt really need to be ? I suspect + * only large enough to hold kmdb's soft int? + * + * XX64 fbsd only uses interrupt gates for all. Perhaps + * This is good for amd64 since we want to block maskable + * interrupts once we take an exception? + */ + bzero(idt64, sizeof (idt64)); /* FIXME */ + + for (i = 0; i < NIDT; i++) + set_gatesegd64(&idt64[i], &amd64_resvtrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + + set_gatesegd64(&idt64[T_ZERODIV], &amd64_div0trap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_SGLSTP], &amd64_dbgtrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_NMIFLT], &amd64_nmiint, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_BPTFLT], &amd64_brktrap, cs64sel, 1, + SDT_SYSIGT, SEL_UPL); + set_gatesegd64(&idt64[T_OVFLW], &amd64_ovflotrap, cs64sel, 1, + SDT_SYSIGT, SEL_UPL); + set_gatesegd64(&idt64[T_BOUNDFLT], &amd64_boundstrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_ILLINST], &amd64_invoptrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_NOEXTFLT], &amd64_ndptrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + + /* + * double fault handler gets its own private stack (tss.ist2). + */ + set_gatesegd64(&idt64[T_DBLFLT], &amd64_doublefault, cs64sel, 2, + SDT_SYSIGT, SEL_KPL); + + /* + * T_EXTOVRFLT coprocessor-segment-overrun not supported. + */ + + set_gatesegd64(&idt64[T_TSSFLT], &amd64_invtsstrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_SEGFLT], &amd64_segnptrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_STKFLT], &amd64_stktrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_GPFLT], &amd64_gptrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_PGFLT], &amd64_pftrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + + /* + * 15 reserved. + */ + set_gatesegd64(&idt64[15], &amd64_resvtrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + + set_gatesegd64(&idt64[T_EXTERRFLT], &amd64_ndperr, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_ALIGNMENT], &amd64_achktrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_MCE], &amd64_mcetrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + set_gatesegd64(&idt64[T_SIMDFPE], &amd64_xmtrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + + /* + * 20-31 reserved + */ + for (i = 20; i < 32; i++) + set_gatesegd64(&idt64[i], &amd64_invaltrap, cs64sel, 1, + SDT_SYSIGT, SEL_KPL); + + /* + * XX64 -- why not resvtrap in initial programming?? + * either way, move this to the top so that the defaults + * are set together. + */ + ridt->dtr_limit = sizeof (idt64) - 1; + ridt->dtr_base = (uint64_t)(uintptr_t)idt64; +} + +/* + * Note that when rsp is being pushed, like the processor, we must + * ensure that the value of the stack pointer at the beginning of the + * instruction is the one that is pushed, NOT the value after. + */ +#define PUSHQ(rsp, value) \ + rsp[-1] = ((uint64_t)(value)); rsp-- + +#define SUBQ(rsp, value) \ + rsp -= ((value) / sizeof (*rsp)) + +struct amd64_machregs * +amd64_makectx64(uint64_t entry) +{ + extern struct bootops *bop; + extern struct boot_syscalls *sysp; + extern Elf64_Boot *elfbootvecELF64; + + struct boot_syscalls64 *sysp64; + struct bootops64 *bop64; + uint64_t *rsp; + + bzero(amd64_stack, sizeof (amd64_stack)); + + rsp = (void *)&amd64_stack[sizeof (amd64_stack)]; + + PUSHQ(rsp, entry); + + /* + * terminate stack walks with a null RBP value. + */ + PUSHQ(rsp, 0); + + /* + * push in amd64_machregs order. + */ + PUSHQ(rsp, ds64sel); /* ss */ + PUSHQ(rsp, (uintptr_t)rsp); /* rsp */ + PUSHQ(rsp, amd64_get_eflags()); /* rfl */ + PUSHQ(rsp, cs64sel); /* cs */ + PUSHQ(rsp, 0); /* %rip - because we didn't go thru a stub */ + PUSHQ(rsp, 0); /* err */ + PUSHQ(rsp, 0); /* trapno */ + PUSHQ(rsp, ds64sel); /* es */ + PUSHQ(rsp, ds64sel); /* ds */ + PUSHQ(rsp, 0); /* fs */ + PUSHQ(rsp, 0); /* gs */ + + SUBQ(rsp, 11 * 8); /* r8 thru r15 are zero */ + + bop64 = init_bootops64(bop); + sysp64 = init_boot_syscalls64(sysp); + + PUSHQ(rsp, (uintptr_t)elfbootvecELF64); /* rcx */ + PUSHQ(rsp, (uintptr_t)bop64); /* rdx */ + PUSHQ(rsp, 0); /* rsi - null dvec */ + PUSHQ(rsp, (uintptr_t)sysp64); /* rdi */ + + PUSHQ(rsp, SEL_GDT(GDT_TSS64, SEL_KPL)); /* tr */ + + SUBQ(rsp, 1 * 8); /* null ldt */ + + PUSHQ(rsp, 0); /* idt */ + PUSHQ(rsp, 0); + make_idt((desctbr64_t *)rsp); + + PUSHQ(rsp, 0); /* gdt */ + PUSHQ(rsp, 0); + make_gdt((desctbr64_t *)rsp); + + PUSHQ(rsp, 0); /* cr8 */ + + /* + * XX64: Note that boot enables CR4_PGE (global pages) + * and Joe has discovered errata that warns against + * mixing this. Need to investigate. + */ + PUSHQ(rsp, CR4_PGE | CR4_PAE | amd64_get_cr4()); /* cr4 */ + PUSHQ(rsp, amd64_init_longpt(amd64_get_cr3())); /* cr3 */ + PUSHQ(rsp, amd64_get_cr2()); /* cr2 */ + + /* + * XX64 - CR0_PG already set? + */ + PUSHQ(rsp, CR0_PG | amd64_get_cr0()); /* cr0 */ + + SUBQ(rsp, 3 * 8); /* kgsbase, gsbase, fsbase */ + + return ((struct amd64_machregs *)rsp); +} diff --git a/usr/src/psm/stand/boot/amd64/cpu.c b/usr/src/psm/stand/boot/amd64/cpu.c new file mode 100644 index 0000000000..61cbc19942 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/cpu.c @@ -0,0 +1,307 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/psw.h> + +#include <amd64/print.h> +#include <amd64/debug.h> +#include <amd64/cpu.h> +#include <amd64/amd64.h> +#include <amd64/msr.h> +#include "../i386/common/biosint.h" + +#ifdef DEBUG +static void +amd64_dump_cpuid(uint32_t eaxmin, uint32_t eaxmax) +{ + uint32_t eax; + struct amd64_cpuid_regs __vcr, *vcr = &__vcr; + + printf("\t%8s | %8s %8s %8s %8s\n", + "eax in", "eax", "ebx", "ecx", "edx"); + for (eax = eaxmin; eax <= eaxmax; eax++) { + amd64_cpuid_insn(eax, vcr); + printf("\t%8x | %8x %8x %8x %8x\n", eax, + vcr->r_eax, vcr->r_ebx, vcr->r_ecx, vcr->r_edx); + } +} + +#define cmprintf printf + +#else /* !DEBUG */ + +#ifdef lint +#define cmprintf printf +#else +#define cmprintf +#endif /* lint */ + +#endif /* DEBUG */ + +static int detect_target_operating_mode(); + +int is_amd64; + +/*ARGSUSED*/ +int +amd64_config_cpu(void) +{ + struct amd64_cpuid_regs __vcr, *vcr = &__vcr; + uint32_t maxeax; + uint32_t max_maxeax = 0x100; + char vendor[13]; + int isamd64 = 0; + uint32_t stdfeatures = 0, xtdfeatures = 0; + uint64_t efer; + + /* + * This check may seem silly, but if the C preprocesor symbol __amd64 + * is #defined during compilation, something that may outwardly seem + * like a good idea, uts/common/sys/isa_defs.h will #define _LP64, + * which will cause uts/common/sys/int_types.h to typedef uint64_t as + * an unsigned long - which is only 4 bytes in size when using a 32-bit + * compiler. + * + * If that happens, all the page table translation routines will fail + * horribly, so check the size of uint64_t just to insure some degree + * of sanity in future operations. + */ + /*LINTED [sizeof result is invarient]*/ + if (sizeof (uint64_t) != 8) + prom_panic("multiboot compiled improperly, unable to boot " + "64-bit AMD64 executables"); + + /* + * If the CPU doesn't support the CPUID instruction, it's definitely + * not an AMD64. + */ + if (amd64_cpuid_supported() == 0) + return (0); + + amd64_cpuid_insn(0, vcr); + + maxeax = vcr->r_eax; + { + /*LINTED [vendor string from cpuid data]*/ + uint32_t *iptr = (uint32_t *)vendor; + + *iptr++ = vcr->r_ebx; + *iptr++ = vcr->r_edx; + *iptr++ = vcr->r_ecx; + + vendor[12] = '\0'; + } + + if (maxeax > max_maxeax) { + cmprintf("cpu: warning, maxeax was 0x%x -> 0x%x\n", + maxeax, max_maxeax); + maxeax = max_maxeax; + } + + if (maxeax < 1) + return (0); /* no additional functions, not an AMD64 */ + else { + uint_t family, model, step; + + amd64_cpuid_insn(1, vcr); + + /* + * All AMD64/IA32e processors technically SHOULD report + * themselves as being in family 0xf, but for some reason + * Simics doesn't, and this may change in the future, so + * don't error out if it's not true. + */ + if ((family = BITX(vcr->r_eax, 11, 8)) == 0xf) + family += BITX(vcr->r_eax, 27, 20); + + if ((model = BITX(vcr->r_eax, 7, 4)) == 0xf) + model += BITX(vcr->r_eax, 19, 16) << 4; + step = BITX(vcr->r_eax, 3, 0); + + cmprintf("cpu: '%s' family %d model %d step %d\n", + vendor, family, model, step); + stdfeatures = vcr->r_edx; + } + +#ifdef DEBUG + if (amd64_debug) { + cmprintf("cpu: standard cpuid data:\n"); + amd64_dump_cpuid(0, maxeax); + } +#endif /* DEBUG */ + + amd64_cpuid_insn(0x80000000, vcr); + + if (vcr->r_eax & 0x80000000) { + uint32_t xmaxeax = vcr->r_eax; + const uint32_t max_xmaxeax = 0x80000100; + + if (xmaxeax > max_xmaxeax) { + cmprintf("amd64: warning, xmaxeax was 0x%x -> 0x%x\n", + xmaxeax, max_xmaxeax); + xmaxeax = max_xmaxeax; + } + +#ifdef DEBUG + if (amd64_debug) { + cmprintf("amd64: extended cpuid data:\n"); + amd64_dump_cpuid(0x80000000, xmaxeax); + } +#endif /* DEBUG */ + + if (xmaxeax >= 0x80000001) { + amd64_cpuid_insn(0x80000001, vcr); + xtdfeatures = vcr->r_edx; + } + } + + if (BITX(xtdfeatures, 29, 29)) /* long mode */ + isamd64++; + else + cmprintf("amd64: CPU does NOT support long mode\n"); + + if (!BITX(stdfeatures, 0, 0)) { + cmprintf("amd64: CPU does NOT support FPU\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 3, 3)) { + cmprintf("amd64: CPU does NOT support PSE\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 4, 4)) { + cmprintf("amd64: CPU does NOT support TSC\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 5, 5)) { + cmprintf("amd64: CPU does NOT support MSRs\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 6, 6)) { + cmprintf("amd64: CPU does NOT support PAE\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 8, 8)) { + cmprintf("amd64: CPU does NOT support CX8\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 13, 13)) { + cmprintf("amd64: CPU does NOT support PGE\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 17, 17)) { + cmprintf("amd64: CPU does NOT support PSE\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 19, 19)) { + cmprintf("amd64: CPU does NOT support CLFSH\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 23, 23)) { + cmprintf("amd64: CPU does NOT support MMX\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 24, 24)) { + cmprintf("amd64: CPU does NOT support FXSR\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 25, 25)) { + cmprintf("amd64: CPU does NOT support SSE\n"); + isamd64--; + } + + if (!BITX(stdfeatures, 26, 26)) { + cmprintf("amd64: CPU does NOT support SSE2\n"); + isamd64--; + } + + if (isamd64 < 1) { + cmprintf("amd64: CPU does not support amd64 executables.\n"); + return (0); + } + + amd64_rdmsr(MSR_AMD_EFER, &efer); + if (efer & AMD_EFER_SCE) + cmprintf("amd64: EFER_SCE (syscall/sysret) already enabled\n"); + if (efer & AMD_EFER_NXE) + cmprintf("amd64: EFER_NXE (no-exec prot) already enabled\n"); + if (efer & AMD_EFER_LME) + cmprintf("amd64: EFER_LME (long mode) already enabled\n"); + + return (detect_target_operating_mode()); +} + +/* + * Issue 'Detect Target Operating Mode' callback to the BIOS + */ +static int +detect_target_operating_mode() +{ + struct int_pb ic = {0}; + int ret, ah; + + ic.ax = 0xec00; /* Detect Target Operating Mode */ + ic.bx = 0x03; /* mixed mode target */ + + ret = bios_doint(0x15, &ic); + + ah = ic.ax >> 8; + if (ah == 0x86 && (ret & PS_C) != 0) { + dprintf("[BIOS 'Detect Target Operating Mode' " + "callback unsupported on this platform]\n"); + return (1); /* unsupported, ignore */ + } + + if (ah == 0x0 && (ret & PS_C) == 0) { + dprintf("[BIOS accepted mixed-mode target setting!]\n"); + return (1); /* told the bios what we're up to */ + } + + if (ah == 0 && ret & PS_C) { + printf("fatal: BIOS reports this machine CANNOT run in mixed " + "32/64-bit mode!\n"); + return (0); + } + + dprintf("warning: BIOS Detect Target Operating Mode callback " + "confused.\n %%ax = 0x%x, carry = %d\n", ic.ax, + ret & PS_C ? 1 : 0); + + return (1); +} diff --git a/usr/src/psm/stand/boot/amd64/exception.s b/usr/src/psm/stand/boot/amd64/exception.s new file mode 100644 index 0000000000..0d696a6120 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/exception.s @@ -0,0 +1,268 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. + * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T + * All Rights Reserved + */ +#if defined(__lint) + +#include <sys/link.h> + +#include <amd64/amd64.h> + +#endif /* __lint */ + +#include <sys/asm_linkage.h> +#include <sys/controlregs.h> +#include <sys/trap.h> + +#include <amd64/machregs.h> + +#include <assym.h> + +#ifdef lint +void +amd64_div0trap(void) +{} + +void +amd64_dbgtrap(void) +{} + +void +amd64_nmiint(void) +{} + +void +amd64_brktrap(void) +{} + +void +amd64_ovflotrap(void) +{} + +void +amd64_boundstrap(void) +{} + +void +amd64_invoptrap(void) +{} + +void +amd64_ndptrap(void) +{} + +void +amd64_doublefault(void) +{} + +void +amd64_overrun(void) +{} + +void +amd64_invtsstrap(void) +{} + +void +amd64_segnptrap(void) +{} + +void +amd64_stktrap(void) +{} + +void +amd64_gptrap(void) +{} + +void +amd64_pftrap(void) +{} + +void +amd64_resvtrap(void) +{} + +void +amd64_ndperr(void) +{} + +void +amd64_achktrap(void) +{} + +void +amd64_mcetrap(void) +{} + +void +amd64_xmtrap(void) +{} + +void +amd64_invaltrap(void) +{} + +#else + +/* + * never returns. + */ +#define TRAP(trapno) \ + push $trapno; \ + jmp __amd64_exception; + + .text + .code64 + + ENTRY_NP(amd64_div0trap) + push $0 + TRAP(T_ZERODIV) / $0 + hlt + SET_SIZE(amd64_div0trap) + + ENTRY_NP(amd64_dbgtrap) + push $0 + TRAP(T_SGLSTP) / $1 + hlt + SET_SIZE(amd64_dbgtrap) + + ENTRY_NP(amd64_nmiint) + push $0 + TRAP(T_NMIFLT) / $2 + hlt + SET_SIZE(amd64_nmiint) + + ENTRY_NP(amd64_brktrap) + push $0 + TRAP(T_BPTFLT) / $3 + hlt + SET_SIZE(amd64_brktrap) + + ENTRY_NP(amd64_ovflotrap) + push $0 + TRAP(T_OVFLW) / $4 + hlt + SET_SIZE(amd64_ovflotrap) + + ENTRY_NP(amd64_boundstrap) + push $0 + TRAP(T_BOUNDFLT) / $5 + hlt + SET_SIZE(amd64_boundstrap) + + ENTRY_NP(amd64_invoptrap) + push $0 + TRAP(T_ILLINST) / $6 + hlt + SET_SIZE(amd64_invoptrap) + + ENTRY_NP(amd64_ndptrap) + push $0 + TRAP(T_NOEXTFLT) / $7 + hlt + SET_SIZE(amd64_ndptrap) + + ENTRY_NP(amd64_doublefault) + push $0 + TRAP(T_DBLFLT) / $8 + hlt + SET_SIZE(amd64_doublefault) + + ENTRY_NP(amd64_overrun) + push $0 + TRAP(T_EXTOVRFLT) / $9 i386 only - not generated + hlt + SET_SIZE(amd64_overrun) + + ENTRY_NP(amd64_invtsstrap) + TRAP(T_TSSFLT) / $10 already have error code on stack + hlt + SET_SIZE(amd64_invtsstrap) + + ENTRY_NP(amd64_segnptrap) + TRAP(T_SEGFLT) / $11 already have error code on stack + hlt + SET_SIZE(amd64_segnptrap) + + ENTRY_NP(amd64_stktrap) + TRAP(T_STKFLT) / $12 already have error code on stack + hlt + SET_SIZE(amd64_stktrap) + + ENTRY_NP(amd64_gptrap) + TRAP(T_GPFLT) / $13 already have error code on stack + hlt + SET_SIZE(amd64_gptrap) + + ENTRY_NP(amd64_pftrap) + TRAP(T_PGFLT) / $14 already have error code on stack + hlt + SET_SIZE(amd64_pftrap) + + ENTRY_NP(amd64_resvtrap) + TRAP(15) / (reserved) + hlt + SET_SIZE(amd64_resvtrap) + + ENTRY_NP(amd64_ndperr) + push $0 + TRAP(T_EXTERRFLT) / $16 + hlt + SET_SIZE(amd64_ndperr) + + ENTRY_NP(amd64_achktrap) + TRAP(T_ALIGNMENT) / $17 zero already on stack + hlt + SET_SIZE(amd64_achktrap) + + ENTRY_NP(amd64_mcetrap) + push $0 + TRAP(T_MCE) / $18 + hlt + SET_SIZE(amd64_mcetrap) + + ENTRY_NP(amd64_xmtrap) + push $0 + TRAP(T_SIMDFPE) / $19 + hlt + SET_SIZE(amd64_xmtrap) + + /* + * XX64 if amd64 had sprintf we could do better. + */ + ENTRY_NP(amd64_invaltrap) + push $0 + TRAP(-1) / invalid trap + hlt + SET_SIZE(amd64_invaltrap) +#endif /* !__lint */ diff --git a/usr/src/psm/stand/boot/amd64/genassym.c b/usr/src/psm/stand/boot/amd64/genassym.c new file mode 100644 index 0000000000..cba7592a16 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/genassym.c @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <stdio.h> +#include "amd64/segments.h" + +int +main(void) +{ + (void) printf("#define\tKCS64SEL\t0x%x\n", + SEL_GDT(GDT_CODE64, SEL_KPL)); + (void) printf("#define\tKDS64SEL\t0x%x\n", + SEL_GDT(GDT_DATA64, SEL_KPL)); + (void) printf("#define\tKCS32SEL\t0x%x\n", + SEL_GDT(GDT_CODE32, SEL_KPL)); + (void) printf("#define\tKDS32SEL\t0x%x\n", + SEL_GDT(GDT_DATA32, SEL_KPL)); + (void) printf("#define\tTSS64SEL\t0x%x\n", + SEL_GDT(GDT_TSS64, SEL_KPL)); + return (0); +} diff --git a/usr/src/psm/stand/boot/amd64/handoff.c b/usr/src/psm/stand/boot/amd64/handoff.c new file mode 100644 index 0000000000..dafc7ad751 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/handoff.c @@ -0,0 +1,91 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <amd64/amd64.h> +#include <amd64/print.h> +#include <amd64/amd64_page.h> +#include <amd64/cpu.h> +#include <amd64/debug.h> +#include <amd64/alloc.h> +#include <amd64/msr.h> +#include <amd64/auxv64.h> + +#ifdef DEBUG +int amd64_debug = 1; +#else +int amd64_debug = 0; +#endif + +/*ARGSUSED*/ +void +amd64_handoff(uint64_t entry) +{ + uint64_t va, pa; + void *rp; + + va = UINT64_FROMPTR32(amd64_handoff); + pa = amd64_legacy_lookup_physaddr(va, amd64_get_cr3()); + + if (va != pa) + amd64_panic("amd64 booter text not identity mapped (va 0x%llx " + "!= pa 0x%llx)\nCannot continue boot.\n", va, pa); + + rp = amd64_makectx64(entry); +#if defined(DEBUG) + amd64_dump_amd64_machregs(rp); +#endif + + /* + * XX64: Any other post-ELF load, pre-exitto() initialization required + * for AMD64 goes here. + */ + + amd64_exitto(rp); + /*NOTREACHED*/ +} + +/* + * The kernel is linked against a module whose + * name includes $MMU, thus krtld requires that + * boot supplies an mmu module list. + * + * For now, there's only one kind of mmu module for + * 64-bit systems + * + * XX64 So do we need this -- could we just link + * the kernel explicitly with mmu64? Are there + * any interesting MMU reworks in the future that + * might make this modularity more useful? + */ + +/*ARGSUSED*/ +const char * +amd64_getmmulist(void) +{ + return ("mmu64"); +} diff --git a/usr/src/psm/stand/boot/amd64/i386_subr.s b/usr/src/psm/stand/boot/amd64/i386_subr.s new file mode 100644 index 0000000000..b5f7c4fd79 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/i386_subr.s @@ -0,0 +1,224 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/asm_linkage.h> + +#if defined(__lint) +#include <amd64/amd64.h> +#include <amd64/cpu.h> +#else +#include <assym.h> +#endif + +#if defined(__lint) + +void +amd64_system_reset(void) +{} + +void +amd64_flush_tlb(void) +{} + +/*ARGSUSED*/ +void +amd64_flush_tlbentry(char *addr) +{} + +#else + + ENTRY_NP(amd64_system_reset) + movw $0x64, %dx + movb $0xfe, %al + outb (%dx) + hlt + SET_SIZE(amd64_system_reset); + + /* + * Note: does NOT flush global entries if PGE enabled... + */ + ENTRY_NP(amd64_flush_tlb) + movl %cr3, %eax + movl %eax, %cr3 + ret + SET_SIZE(amd64_flush_tlb) + + ENTRY_NP(amd64_flush_tlbentry) + movl 4(%esp), %eax + invlpg (%eax) + ret + SET_SIZE(amd64_flush_tlbentry) +#endif + +#if defined(__lint) + +ulong_t +amd64_get_cr0(void) +{ return (0ul); } + +ulong_t +amd64_get_cr2(void) +{ return (0ul); } + +ulong_t +amd64_get_cr3(void) +{ return (0ul); } + +ulong_t +amd64_get_cr4(void) +{ return (0ul); } + +#else + + ENTRY(amd64_get_cr0) + movl %cr0, %eax + ret + SET_SIZE(amd64_get_cr0) + + ENTRY(amd64_get_cr2) + movl %cr2, %eax + ret + SET_SIZE(amd64_get_cr2) + + ENTRY(amd64_get_cr3) + movl %cr3, %eax + ret + SET_SIZE(amd64_get_cr3) + + ENTRY(amd64_get_cr4) + movl %cr4, %eax + ret + SET_SIZE(amd64_get_cr4) + +#endif + +#if defined(__lint) + +/*ARGSUSED*/ +void +amd64_rdmsr(uint32_t msr, uint64_t *data) +{} + +/*ARGSUSED*/ +void +amd64_wrmsr(uint32_t msr, const uint64_t *data) +{} + +#else + + ENTRY(amd64_rdmsr) + movl 4(%esp), %ecx + rdmsr + movl 8(%esp), %ecx + movl %eax, (%ecx) + movl %edx, 4(%ecx) + ret + SET_SIZE(amd64_rdmsr) + + ENTRY(amd64_wrmsr) + movl 8(%esp), %ecx + movl (%ecx), %eax + movl 4(%ecx), %edx + movl 4(%esp), %ecx + wrmsr + ret + SET_SIZE(amd64_wrmsr) + +#endif /* __lint */ + +#if defined(__lint) + +ulong_t +amd64_get_eflags(void) +{ return (0); } + +#else /* __lint */ + + ENTRY(amd64_get_eflags) + pushfl + pop %eax + ret + SET_SIZE(amd64_get_eflags) + +#endif /* __lint */ + +#if defined(__lint) + +/*ARGSUSED*/ +void +amd64_cpuid_insn(uint32_t eax, struct amd64_cpuid_regs *vcr) +{} + +#else /* __lint */ + + ENTRY(amd64_cpuid_insn) + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %esi + movl 0x8(%ebp), %eax + movl 0xc(%ebp), %esi + cpuid + movl %eax, AMD64_CPUID_REG_EAX(%esi) + movl %ebx, AMD64_CPUID_REG_EBX(%esi) + movl %ecx, AMD64_CPUID_REG_ECX(%esi) + movl %edx, AMD64_CPUID_REG_EDX(%esi) + popl %esi + popl %ebx + popl %ebp + ret + SET_SIZE(amd64_cpuid_insn) + +#endif /* __lint */ + +#if defined(__lint) + +unsigned +amd64_cpuid_supported(void) { return (1); } + +#else + /* + * Based on code from AMD64 Volume 3 + */ + ENTRY(amd64_cpuid_supported) + pushf + popl %eax + mov %eax, %edx /* save %eax for later */ + xorl %eax, 0x200000 /* toggle bit 21 */ + pushl %eax + popf /* save new %eax to EFLAGS */ + pushf /* save new EFLAGS */ + popl %ecx /* copy EFLAGS to %eax */ + xorl %eax, %eax + cmpl %ecx, %edx /* see if bit 21 has changes */ + jne 1f + incl %eax +1: + ret + SET_SIZE(amd64_cpuid_supported) +#endif /* __lint */ diff --git a/usr/src/psm/stand/boot/amd64/locore.s b/usr/src/psm/stand/boot/amd64/locore.s new file mode 100644 index 0000000000..a127e02f05 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/locore.s @@ -0,0 +1,577 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#if defined(__lint) + +#include <sys/link.h> + +#include <amd64/amd64.h> + +#endif /* __lint */ + +#include <sys/asm_linkage.h> +#include <sys/controlregs.h> + +#include <amd64/machregs.h> + +#include <assym.h> + +#if defined(__lint) + +/*ARGSUSED*/ +void +amd64_exitto(struct amd64_machregs *rp) +{} + +#else /* __lint */ + + .data + .globl need_init_cr8 +need_init_cr8: + .long 1 + + ENTRY_NP(amd64_exitto) + pushl %ebp + movl %esp, %ebp + /* + * stash current i386 state in i386_machregs + */ + lea exitto_i386_machregs, %eax + movw %ss, %dx + movzx %dx, %edx + mov %edx, i386_REG_SS(%eax) + pushfl + pop %edx + mov %edx, i386_REG_EFL(%eax) + movw %cs, %dx + movzx %dx, %edx + mov %edx, i386_REG_CS(%eax) + mov %ebx, i386_REG_EBX(%eax) + mov %esp, i386_REG_ESP(%eax) + mov %ebp, i386_REG_EBP(%eax) + mov %esi, i386_REG_ESI(%eax) + mov %edi, i386_REG_EDI(%eax) + movw %ds, %dx + movzx %dx, %edx + mov %edx, i386_REG_DS(%eax) + movw %es, %dx + movzx %dx, %edx + mov %edx, i386_REG_ES(%eax) + movw %fs, %dx + movzx %dx, %edx + mov %edx, i386_REG_FS(%eax) + movw %gs, %dx + movzx %dx, %edx + mov %edx, i386_REG_GS(%eax) + str i386_REG_TR(%eax) + sldt i386_REG_LDT(%eax) + sidt i386_REG_IDT(%eax) + sgdt i386_REG_GDT(%eax) + mov %cr4, %edx + mov %edx, i386_REG_CR4(%eax) + mov %cr3, %edx + mov %edx, i386_REG_CR3(%eax) + mov %cr2, %edx + mov %edx, i386_REG_CR2(%eax) + mov %cr0, %edx + mov %edx, i386_REG_CR0(%eax) + movl $1, need_init_cr8 /* set flag to cause %cr8 init */ +#ifdef DEBUG + push %eax + call amd64_dump_i386_machregs + addl $4, %esp +#endif /* DEBUG */ + /* + * Fetch the argument, and switch to it as a stack; + * the new stack contains an amd64_machregs on it, + * just sitting there waiting for us to restore it. + */ + mov 8(%ebp), %esp + jmp __return_to_long_mode + /*NOTREACHED*/ + SET_SIZE(amd64_exitto) + +#endif /* __lint */ + +#if defined(__lint) + +#define VTRAP_STUB_BEGIN(opname) \ + uintptr_t opname; + +#define VTRAP_STUB_END(opname) \ + uintptr_t opname; + +#define VTRAP_STUB(symname) \ + uintptr_t symname; + +#else + +#define VTRAP_STUB_BEGIN(symname) \ + .global symname; \ +symname: \ + .code64 + +#define VTRAP_STUB_END(symname) \ + .code32; \ + .global symname; \ +symname: + +/* + * callbacks from the amd64 kernel to the i386 world are handled + * as calls into a virtual amd64 boot program as if they were + * virtual traps i.e. we save the machine state, switch to i386 mode, + * then decode and interpret the request in C code (amd64_vtrap) + */ + +#define VTRAP_STUB(opname) \ + ENTRY_NP(opname); \ + pushq %rbp; \ + movq %rsp, %rbp; \ + call 1f; \ +1: pop %r11; \ + sub $_CONST(1b - opname), %r11; \ + jmp __vtrap_common; \ + SET_SIZE(opname) + + ENTRY_NP(__vtrap_common) + .code64 + /* + * put the state of the amd64 machine onto the stack + */ + movq %rsp, %r10 + addq $0x10, %r10 /* (%rsp immediately before the call) */ + push $0 /* %ss */ + push %r10 /* %rsp */ + pushf /* rflags */ + push $0 /* %cs */ + push %r11 /* %rip (the pc we came in on) */ + push $0 /* err */ + push $-1 /* trapno (virt trap# larger than idt itself) */ + cli + + ALTENTRY(__amd64_exception) /* vectored from amd64_idt */ + push $0 /* %es */ + push $0 /* %ds */ + push %fs + push %gs + push %r15 + push %r14 + push %r13 + push %r12 + push %r11 + push %r10 + push %rbp + push %rbx + push %rax + push %r9 + push %r8 + push %rcx + push %rdx + push %rsi + push %rdi + + /* + * (that was the 'struct regs' part, now for the somewhat trickier + * parts of the machine (with all the implicit state that goes + * along with those registers (?))) + */ + + str %rax + push %rax + sldt %rax + push %rax + + /* XX64 need to do some compile-time assert here to check this! */ + + push $0 + push $0 + sidt (%rsp) + + push $0 + push $0 + sgdt (%rsp) + +#define PUSH_CREG(creg) \ + mov creg, %rax; \ + push %rax + + PUSH_CREG(%cr8) + PUSH_CREG(%cr4) + PUSH_CREG(%cr3) + PUSH_CREG(%cr2) + PUSH_CREG(%cr0) + +#define PUSH_SEG_BASE(msr) \ + mov $msr, %ecx; \ + rdmsr; \ + salq $32, %rdx; \ + mov %eax, %eax; \ + or %rdx, %rax; \ + push %rax + + PUSH_SEG_BASE(MSR_AMD_FSBASE) + PUSH_SEG_BASE(MSR_AMD_GSBASE) + PUSH_SEG_BASE(MSR_AMD_KGSBASE) + + /* + * save the sodding segment registers (because push doesn't work!) + */ + mov %cs, %ax + movzx %ax, %rax + mov %rax, amd64_REG_CS(%rsp) + + mov %ds, %ax + movzx %ax, %rax + mov %rax, amd64_REG_DS(%rsp) + + mov %es, %ax + movzx %ax, %rax + mov %rax, amd64_REG_ES(%rsp) + + mov %ss, %ax + movzx %ax, %rax + mov %rax, amd64_REG_SS(%rsp) + + /* + * Back to i386 mode + */ + + /* + * reload %ds here so we can refer to i386_machregs below + */ + mov $KDS32SEL, %rax + movw %ax, %ds + + /* + * 1. Switch to compatibility mode at CPL=0 + * + * We seem forced to do this -- which is a complicated + * way to do: + * + * ljmp $KCS32SEL, $__amd64_compat_mode + * __amd64_compat_mode: + * + * which unfortunately isn't legal in long mode. + * + * You'd think this would work, but it doesn't. + * + * push $KCS32SEL + * push %rax + * lret + * + * Perhaps there's a better way? + */ + call 9f +9: pop %rax + add $_CONST(__amd64_compat_mode - 9b), %rax + mov %rsp, %rdx + push $KDS32SEL + push %rdx + pushf + push $KCS32SEL + push %rax + iretq + +__amd64_compat_mode: + .code32 + /* + * 2. Deactivate long mode by clearing CR0.PG + */ + mov %cr0, %eax + and $_BITNOT(CR0_PG), %eax + mov %eax, %cr0 + /* + * 2a. Disable PAE + */ + mov %cr4, %eax + and $_BITNOT(CR4_PAE), %eax + mov %eax, %cr4 + /* + * 3. Load CR3 with physical base address of page tables + * + * (Note we loaded %ds above) + */ + lea exitto_i386_machregs, %eax + mov i386_REG_CR3(%eax), %edx + mov %edx, %cr3 + /* + * 4. Disable long mode by clearing EFER.LME to 0 + */ + mov $MSR_AMD_EFER, %ecx + rdmsr + and $_BITNOT(AMD_EFER_LME), %eax + wrmsr + /* + * 5. Enable legacy page-translation + */ + mov %cr0, %eax + or $CR0_PG, %eax + mov %eax, %cr0 + jmp __i386_mode +__i386_mode: + /* + * Reconstruct our life as an i386 processor from the + * exitto save area. + */ + lea exitto_i386_machregs, %eax + mov i386_REG_CR0(%eax), %edx + mov %edx, %cr0 + /* + * %cr2 is the page fault address; we have no need to restore it + */ + mov i386_REG_CR3(%eax), %edx + mov %edx, %cr3 + mov i386_REG_CR4(%eax), %edx + mov %edx, %cr4 + lgdt i386_REG_GDT(%eax) + lidt i386_REG_IDT(%eax) + + /* + * Need to clear busy bit in our tss descriptor + */ +/ clrtss: +/ push %eax +/ call amd64_i386_clrtss +/ pop %eax +/ +/ ltr i386_REG_TR(%eax) + + mov i386_REG_GS(%eax), %edx + movw %dx, %gs + mov i386_REG_FS(%eax), %edx + movw %dx, %fs + mov i386_REG_ES(%eax), %edx + movw %dx, %es + mov i386_REG_DS(%eax), %edx + movw %dx, %ds + mov i386_REG_SS(%eax), %edx + movw %dx, %ss + + pushl i386_REG_EFL(%eax) + popf + + /* + * As long as the transition from long mode to i386 mode + * simply truncated %rsp -> %esp, we now have a struct amd64_machregs + * sitting on the top of the stack. + */ + pushl %esp + call amd64_vtrap + addl $4, %esp + + /* + * let's go long .. + */ +__return_to_long_mode: + mov amd64_REG_CR3(%esp), %edx + + /* + * Disable paging + */ + mov %cr0, %eax + and $_BITNOT(CR0_PG), %eax + mov %eax, %cr0 + /* + * 2a. enable PAE + */ + mov %cr4, %eax + or $CR4_PAE, %eax + mov %eax, %cr4 + /* + * 2b. load CR3 with PML4 base address + */ + mov %edx, %cr3 + /* + * 2c. enable long mode + */ + mov $MSR_AMD_EFER, %ecx + rdmsr + or $AMD_EFER_LME, %eax + wrmsr + /* + * 2d. enable paging + */ + mov %cr0, %eax + or $CR0_PG, %eax + mov %eax, %cr0 + jmp __enable_long_mode +__enable_long_mode: + + /* + * we are now in compatibility mode + * move to the 64 bit descriptor tables so that + * we find ourselves in a sane place when we lret + * and switch to 64 bit mode .. + */ + lgdt amd64_REG_GDT(%esp) + + /* + * switch to 64-bit mode + */ + call 1f +1: pop %eax + add $_CONST(__amd64_64bit_mode - 1b), %eax + mov amd64_REG_CS(%esp), %edx + push %edx + push %eax + lret +__amd64_64bit_mode: + .code64 + + /* + * the following descriptor table loads fetch the full + * 64-bit values expected by the client. + */ + lgdt amd64_REG_GDT(%rsp) + lidt amd64_REG_IDT(%rsp) + lldt amd64_REG_LDT(%rsp) + ltr amd64_REG_TR(%rsp) + + /* + * fix up the selectors for long mode + */ + mov amd64_REG_DS(%rsp), %rax + movw %ax, %ds + mov amd64_REG_ES(%rsp), %rax + movw %ax, %es + mov amd64_REG_FS(%rsp), %rax + movw %ax, %fs + mov amd64_REG_GS(%rsp), %rax + movw %ax, %gs + mov amd64_REG_SS(%rsp), %rax + movw %ax, %ss + +#define RESTORE_SEG_BASE(seg) \ + movq amd64_REG_/**/seg(%rsp), %rax; \ + movq %rax, %rdx; \ + movl %eax, %eax; \ + shrq $32, %rdx; \ + movl $MSR_AMD_/**/seg, %ecx; \ + wrmsr + + RESTORE_SEG_BASE(KGSBASE) + RESTORE_SEG_BASE(GSBASE) + RESTORE_SEG_BASE(FSBASE) + +#define RESTORE_CR(num) \ + movq amd64_REG_CR/**/num(%rsp), %rax; \ + movq %rax, %cr/**/num + + RESTORE_CR(0) + + /* don't restore %cr2 */ + + RESTORE_CR(3) + RESTORE_CR(4) + + /* + * Only restore %cr8 if it's nonzero or if we have not yet initialized + * it (if it's zero, that means it's not safe to restore it -- we're + * either using the local APIC TPR or no TPR at all). We only test the + * non-reserved bits. The %cr8 initialization is done only on the first + * transfer from the booter to the loaded image. + */ + cmpl $0, need_init_cr8(%rip) /* Did we initialize cr8 yet? */ + jnz 1f /* No? Then go and zero it. */ + + testq $0xF, amd64_REG_CR8(%rsp) /* Is the saved cr8 zero? */ + jz 2f /* Yes, -- skip the restore */ +1: + movl $0, need_init_cr8(%rip) /* Mark cr8 as initialized */ + RESTORE_CR(8) +2: + /* + * gdt/idt/ldt/tr have already been restored, as have %gs, %fs, %ds + * and %es. + * + * Meanwhile %rbp, %r11, err and trapno don't get restored at all. + */ + movq amd64_REG_RDI(%rsp), %rdi + movq amd64_REG_RSI(%rsp), %rsi + movq amd64_REG_RAX(%rsp), %rax + movq amd64_REG_RCX(%rsp), %rcx + movq amd64_REG_RDX(%rsp), %rdx + movq amd64_REG_R8(%rsp), %r8 + movq amd64_REG_R9(%rsp), %r9 + movq amd64_REG_RBX(%rsp), %rbx + movq amd64_REG_R10(%rsp), %r10 + movq amd64_REG_R12(%rsp), %r12 + movq amd64_REG_R13(%rsp), %r13 + movq amd64_REG_R14(%rsp), %r14 + movq amd64_REG_R15(%rsp), %r15 + + /* + * The bottom five arguments in the struct amd64_machregs on the + * stack (starting with r_rip) are positioned such that they can be + * used as-is by iretq to return to the caller, switch interrupts + * back on if needed, and restore the proper %rsp. + * + * HOWEVER, we need the %rbp and %rip sitting in the return frame + * on the stack, so grab them from beyond the end of the amd64_machregs + * structure on the stack so that everything will be restored properly + * by the iretq. + * + * The stack after the addq below will be: + * + * 0 amd64_machregs %rip + * +8 amd64_machregs %cs + * +0x10 amd64_machflags rflags + * +0x18 amd64_machflags %rsp + * +0x20 amd64_machflags %ss + * +0x28 return %rbp from bootops 'call' insn + * +0x30 return %rip from bootops 'call' insn + */ + addq $amd64_REG_RIP, %rsp + movq 0x28(%rsp), %rbp /* load the return %rbp to %rbp */ + movq 0x30(%rsp), %r11 /* copy the return %rip to %r11 */ + movq %r11, (%rsp) /* save it as amd64_machregs' r_rip */ + iretq + SET_SIZE(__vtrap_common) + +#endif /* __lint */ + + VTRAP_STUB_BEGIN(bop64_first) + + VTRAP_STUB(bop64_alloc) + VTRAP_STUB(bop64_free) + VTRAP_STUB(bop64_getproplen) + VTRAP_STUB(bop64_getprop) + VTRAP_STUB(bop64_nextprop) + VTRAP_STUB(bop64_printf) + VTRAP_STUB(bop64_doint) + VTRAP_STUB(bop64_ealloc) + + VTRAP_STUB_END(bop64_last) + + VTRAP_STUB_BEGIN(bsys64_first) + + VTRAP_STUB(bsys64_getchar) + VTRAP_STUB(bsys64_putchar) + VTRAP_STUB(bsys64_ischar) + + VTRAP_STUB_END(bsys64_last) diff --git a/usr/src/psm/stand/boot/amd64/memlist.c b/usr/src/psm/stand/boot/amd64/memlist.c new file mode 100644 index 0000000000..023fd240ef --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/memlist.c @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <amd64/boothooks.h> +#include <amd64/print.h> +#include <amd64/types.h> +#include <amd64/bootops64.h> +#include <amd64/memlist64.h> +#include <amd64/amd64_page.h> + +struct memlist64 * +amd64_convert_memlist(struct memlist *ml, struct memlist64 *ml64) +{ + extern struct memlist64 *amd64_memlistpage; + + ml64->prev = (caddr64_t)0; + + while (ml) { + ml64->address = ml->address; + ml64->size = ml->size; + ml = ml->next; + + if (ml) { + struct memlist64 *next_ml = ml64 + 1; + + ml64->next = (caddr64_t)(uintptr_t)next_ml; + next_ml->prev = (caddr64_t)(uintptr_t)ml64; + ml64++; + + /* + * This may end up being shortsighted, but currently + * boot will panic if the memlists don't all fit on + * one page so we may as well make the same assumption. + */ + if ((uint64_t)ml64 > ((uint64_t)amd64_memlistpage + + AMD64_PAGESIZE)) + amd64_panic("Memory space for 64-bit memlists " + "exhausted when converting memlist @ 0x%x.", + (uint32_t)ml->prev); + } + } + + ml64->next = (caddr64_t)0; + return (ml64 + 1); +} diff --git a/usr/src/psm/stand/boot/amd64/offsets.in b/usr/src/psm/stand/boot/amd64/offsets.in new file mode 100644 index 0000000000..b07ea48e76 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/offsets.in @@ -0,0 +1,111 @@ +\ +\ Copyright 2005 Sun Microsystems, Inc. All rights reserved. +\ Use is subject to license terms. +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License, Version 1.0 only +\ (the "License"). You may not use this file except in compliance +\ with the License. +\ +\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ or http://www.opensolaris.org/os/licensing. +\ See the License for the specific language governing permissions +\ and limitations under the License. +\ +\ When distributing Covered Code, include this CDDL HEADER in each +\ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ If applicable, add the following below this CDDL HEADER, with the +\ fields enclosed by brackets "[]" replaced with your own identifying +\ information: Portions Copyright [yyyy] [name of copyright owner] +\ +\ CDDL HEADER END +\ + +#pragma ident "%Z%%M% %I% %E% SMI" + +\ +\ offsets.in: input file to produce assym.h using the ctfstabs program +\ + +#include <sys/types.h> +#include <amd64/cpu.h> +#include <amd64/machregs.h> +#include <amd64/tss.h> +#include <amd64/segments.h> + +amd64_cpuid_regs + r_eax AMD64_CPUID_REG_EAX + r_ebx AMD64_CPUID_REG_EBX + r_ecx AMD64_CPUID_REG_ECX + r_edx AMD64_CPUID_REG_EDX + +amd64_machregs SIZEOF_amd64_machregs + r_kgsbase amd64_REG_KGSBASE + r_gsbase amd64_REG_GSBASE + r_fsbase amd64_REG_FSBASE + r_cr0 amd64_REG_CR0 + r_cr2 amd64_REG_CR2 + r_cr3 amd64_REG_CR3 + r_cr4 amd64_REG_CR4 + r_cr8 amd64_REG_CR8 + r_gdt_un.un_gdt amd64_REG_GDT + r_idt_un.un_idt amd64_REG_IDT + r_ldt amd64_REG_LDT + r_tr amd64_REG_TR + r_rdi amd64_REG_RDI + r_rsi amd64_REG_RSI + r_rdx amd64_REG_RDX + r_rcx amd64_REG_RCX + r_r8 amd64_REG_R8 + r_r9 amd64_REG_R9 + r_rax amd64_REG_RAX + r_rbx amd64_REG_RBX + r_rbp amd64_REG_RBP + r_r10 amd64_REG_R10 + r_r11 amd64_REG_R11 + r_r12 amd64_REG_R12 + r_r13 amd64_REG_R13 + r_r14 amd64_REG_R14 + r_r15 amd64_REG_R15 + r_gs amd64_REG_GS + r_fs amd64_REG_FS + r_ds amd64_REG_DS + r_es amd64_REG_ES + r_trapno amd64_REG_TRAPNO + r_err amd64_REG_ERR + r_rip amd64_REG_RIP + r_cs amd64_REG_CS + r_rfl amd64_REG_FLAGS + r_rsp amd64_REG_RSP + r_ss amd64_REG_SS + +i386_machregs SIZEOF_i386_machregs + r_ss i386_REG_SS + r_uesp i386_REG_UESP + r_efl i386_REG_EFL + r_cs i386_REG_CS + r_eip i386_REG_EIP + r_err i386_REG_ERR + r_trapno i386_REG_TRAPNO + r_eax i386_REG_EAX + r_ecx i386_REG_ECX + r_edx i386_REG_EDX + r_ebx i386_REG_EBX + r_esp i386_REG_ESP + r_ebp i386_REG_EBP + r_esi i386_REG_ESI + r_edi i386_REG_EDI + r_ds i386_REG_DS + r_es i386_REG_ES + r_fs i386_REG_FS + r_gs i386_REG_GS + r_tr i386_REG_TR + r_ldt i386_REG_LDT + r_idt_un.un_idt i386_REG_IDT + r_gdt_un.un_gdt i386_REG_GDT + r_cr4 i386_REG_CR4 + r_cr3 i386_REG_CR3 + r_cr2 i386_REG_CR2 + r_cr0 i386_REG_CR0 diff --git a/usr/src/psm/stand/boot/amd64/print.c b/usr/src/psm/stand/boot/amd64/print.c new file mode 100644 index 0000000000..7f2f7f3aef --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/print.c @@ -0,0 +1,278 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/inttypes.h> +#include <sys/varargs.h> +#include <sys/promif.h> + +#include <amd64/print.h> +#include <amd64/amd64.h> + +/* + * Printn prints a number n in base b. + * We don't use recursion to avoid deep stacks. + */ +static void +__amd64_printn(uint64_t n, int b, int width, int pad, + void (*put)(void *, int), void *arg) +{ + char prbuf[65]; + char *cp; + + cp = prbuf; + do { + *cp++ = "0123456789abcdef"[n%b]; + n /= b; + width--; + } while (n); + while (width-- > 0) + *cp++ = (char)pad; + do { + (*put)(arg, *--cp); + } while (cp > prbuf); +} + +/* + * This routine is highly specific to amd64, and is essentially a + * complete kludge which allows amd64 to print using the 64-bit regs + * from an LP64 kernel. + * + * The worst part about it is the assumptions around decoding string + * pointers -- we assume that the top bits of the string pointer can + * be discarded yet still remain as a valid address. + * + * cell size == sizeof (long long) + */ +static void +__amd64_doprnt64( + const char *fmt, + va_list adx, + void (*put)(void *, int), + void *arg) +{ + int b, c, i, pad, width, ells; + char *s; + int64_t l; + uint64_t ul; + +loop: + while ((c = *fmt++) != '%') { + if (c == '\0') + goto out; + (*put)(arg, c); + } + + c = *fmt++; + for (pad = ' '; c == '0'; c = *fmt++) + pad = '0'; + + for (width = 0; c >= '0' && c <= '9'; c = *fmt++) + width = width * 10 + c - '0'; + + for (ells = 0; c == 'l'; c = *fmt++) + ells++; + + switch (c) { + case 'd': + case 'D': + b = 10; + if (ells == 0) + l = (int64_t)(int)va_arg(adx, int64_t); + else if (ells == 1) + l = (int64_t)va_arg(adx, int64_t); + else + l = (int64_t)va_arg(adx, int64_t); + if (l < 0) { + (*put)(arg, '-'); + width--; + ul = -l; + } else + ul = l; + goto number; + + case 'p': + ells = 1; + /*FALLTHROUGH*/ + case 'x': + case 'X': + b = 16; + goto u_number; + + case 'u': + b = 10; + goto u_number; + + case 'o': + case 'O': + b = 8; +u_number: + if (ells == 0) + ul = (uint64_t)(uint_t)va_arg(adx, uint64_t); + else if (ells == 1) + ul = (uint64_t)va_arg(adx, uint64_t); + else + ul = (uint64_t)va_arg(adx, uint64_t); +number: + __amd64_printn(ul, b, width, pad, put, arg); + break; + + case 'c': + b = (int)va_arg(adx, uint64_t); + for (i = 24; i >= 0; i -= 8) + if ((c = ((b >> i) & 0x7f)) != 0) + (*put)(arg, (char)c); + break; + + /* + * Yuck. We're encoding the assumption that a valid 32-bit pointer + * can be obtained by simply truncating the 64-bit pointer. + */ + case 's': + s = (char *)(uintptr_t)va_arg(adx, uint64_t); + for (width -= strlen(s); width > 0; width--) + (*put)(arg, pad); + while ((c = *s++) != 0) + (*put)(arg, c); + break; + + case '%': + (*put)(arg, (char)c); + break; + + default: + break; + } + goto loop; +out: + ; +} + +struct strbuf { + char *sb_base; + char *sb_ptr; + size_t sb_maxsize; +}; + +static void +sput(void *arg, int c) +{ + struct strbuf *sb = arg; + + if (c == '\n') + sput(arg, '\r'); + + if ((sb->sb_ptr - sb->sb_base) >= sb->sb_maxsize) + sb->sb_ptr++; + else + *sb->sb_ptr++ = (char)c; +} + +static int +amd64_vsnprintf_helper(char *s, size_t n, const char *fmt, va_list ap, + void (*doprnt)(const char *, va_list, void (*)(void *, int), void *)) +{ + struct strbuf sbuf, *sb = &sbuf; + int count; + + sb->sb_base = sb->sb_ptr = s; + sb->sb_maxsize = n; + + (*doprnt)(fmt, ap, sput, sb); + + /* + * Ensure there's a trailing NULL to terminate the string + */ + if (sb->sb_maxsize == 0) + return ((int)(sb->sb_ptr - sb->sb_base)); + if ((count = sb->sb_ptr - sb->sb_base) >= sb->sb_maxsize) + sb->sb_ptr = sb->sb_base + sb->sb_maxsize - 1; + if (sb->sb_ptr) + *sb->sb_ptr = '\0'; + return (count); +} + +/* + * Specialized vsnprintf() that is used to print arguments from + * an environment where the native argument size is 64-bit + */ +int +amd64_vsnprintf64(char *s, size_t n, const char *fmt, va_list ap) +{ + return (amd64_vsnprintf_helper(s, n, fmt, ap, __amd64_doprnt64)); +} + +int +amd64_snprintf64(char *s, size_t n, const char *fmt, ...) +{ + int r; + va_list ap; + + va_start(ap, fmt); + r = amd64_vsnprintf64(s, n, fmt, ap); + va_end(ap); + return (r); +} + +struct amd64buf { + char *vb_base; + char *vb_ptr; + size_t vb_maxsize; + struct bootops *vb_bop; +}; + +void +amd64_vpanic(const char *fmt, va_list ap) +{ + printf("amd64_panic: "); + prom_vprintf(fmt, ap); + printf("\n"); + amd64_system_reset(); +} + +void +amd64_panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + amd64_vpanic(fmt, ap); + va_end(ap); +} + +void +amd64_warning(const char *fmt, ...) +{ + va_list ap; + + printf("amd64 warning: "); + va_start(ap, fmt); + prom_vprintf(fmt, ap); + va_end(ap); + printf("\n"); +} diff --git a/usr/src/psm/stand/boot/amd64/ptops.c b/usr/src/psm/stand/boot/amd64/ptops.c new file mode 100644 index 0000000000..3b6244efe9 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/ptops.c @@ -0,0 +1,372 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> + +#include <amd64/amd64.h> +#include <amd64/print.h> +#include <amd64/debug.h> +#include <amd64/alloc.h> +#include <amd64/cpu.h> +#include <amd64/amd64_page.h> + +static amd64_mmumode_t mmus[] = { + { 22, 10, 2, 1024 }, /* legacy 32-bit mode */ + { 39, 9, 4, 512 } /* long 64-bit mode */ +}; + +uint16_t +amd64_modbits(uint64_t entry) +{ + return ((uint16_t)PA_MODBITS(entry)); +} + +uint64_t +amd64_legacy_physaddr(uint32_t entry) +{ + return (IS_LARGEMAP(entry) ? + ((uint64_t)(entry) & ~0x3fffffULL | + (((uint64_t)(entry) >> 13) & 0xffULL) << 32) + : ((uint64_t)(entry) & ~0xfffULL)); +} + +uint64_t +amd64_long_physaddr(uint64_t entry) +{ + return (IS_LARGEMAP(entry) ? (entry & ~0x1fffffULL) : + (entry & ~0xfffULL)); +} + +uint64_t +amd64_physaddr(uint64_t entry, uint8_t amd64_mmu_mode) +{ + return (amd64_mmu_mode == AMD64_MODE_LONG64) ? + amd64_long_physaddr(entry) : amd64_legacy_physaddr((uint32_t)entry); +} + +static uint64_t +amd64_tbl_lookup(uint8_t amd64_mmu_mode, uint64_t va, uint32_t tbl_base, + uint32_t *addr_inc) +{ + uint8_t level; + uint8_t level_shift = mmus[amd64_mmu_mode].level_shift; + uint8_t pde_level = mmus[amd64_mmu_mode].map_level - 1; + uint8_t shift = mmus[amd64_mmu_mode].shift_base; + uint64_t mask = (1ULL << level_shift) - 1; + uint64_t entry; + + ASSERT(tbl_base); + + for (level = 1; shift > AMD64_PAGESIZE_OFFSET_NBITS; + shift -= level_shift, level++) { + entry = TBL_ENTRY64(amd64_mmu_mode, tbl_base, va, shift, + mask); + + if (!(ENTRY_VALID(entry))) { + /* + * If a page level is empty, set addr_inc to the shift + * value because in a sequential search we know the next + * (1 << level_shift) bytes are unmapped. + */ + while (shift >= 32) + shift -= level_shift; /* XXX */ + + if (addr_inc) + *addr_inc = (1 << shift); + + return (0); + } + + if (((level == pde_level) && (IS_LARGEMAP(entry))) || + IS_PTE(level, amd64_mmu_mode)) { + /* Set addr_inc to pagesize found and return entry. */ + + while (shift >= 32) + shift -= level_shift; /* XXX */ + + if (addr_inc) + *addr_inc = (1 << shift); + + return (entry); + } + + tbl_base = (uint32_t)amd64_physaddr(entry, amd64_mmu_mode); + } + + if (addr_inc) + *addr_inc = (uint32_t)AMD64_PAGESIZE; + + return (0); +} + +uint64_t +amd64_long_lookup(uint64_t va, uint32_t *addr_inc, uint32_t tbl_base) +{ + return (amd64_tbl_lookup(AMD64_MODE_LONG64, va, tbl_base, addr_inc)); +} + +uint32_t +amd64_legacy_lookup(uint64_t va, uint32_t *addr_inc, uint32_t tbl_base) +{ + return ((uint32_t)amd64_tbl_lookup(AMD64_MODE_LEGACY, va, tbl_base, + addr_inc)); +} + +uint64_t +amd64_legacy_lookup_physaddr(uint64_t va, uint32_t tbl_base) +{ + uint32_t entry, pagesize; + uint64_t offset; + + if (!(entry = amd64_legacy_lookup(va, &pagesize, tbl_base))) + amd64_panic("legacy lookup failed for va 0x%llx\n!", va); + + offset = va & AMD64_PAGEOFFSET(pagesize); + return (amd64_legacy_physaddr(entry) + offset); +} + +uint64_t +amd64_long_lookup_physaddr(uint64_t va, uint32_t tbl_base) +{ + uint32_t pagesize; + uint64_t entry, offset; + + if (!(entry = amd64_long_lookup(va, &pagesize, tbl_base))) + amd64_panic("long lookup failed for va 0x%llx\n!", va); + + offset = va & AMD64_PAGEOFFSET(pagesize); + return (amd64_long_physaddr(entry) + offset); +} + +void +amd64_map_mem(uint64_t va, uint64_t pa, uint32_t len, uint8_t amd64_mmu_mode, + uint32_t tbl_base, uint16_t page_modbits) +{ + uint64_t parentlvl_entry; + uint64_t entry; + uint64_t local_pagebits; + + uint32_t pagesize; + uint32_t parent_base; + uint32_t tbl_root = tbl_base; + + uint8_t level_shift = mmus[amd64_mmu_mode].level_shift; + uint64_t idx_mask = (1ULL << level_shift) - 1; + + uint8_t level, map_level; + uint8_t shift; + + ASSERT(tbl_base); + ASSERT(AMD64_PAGEALIGNED(va, AMD64_PAGESIZE)); + ASSERT(AMD64_PAGEALIGNED(pa, AMD64_PAGESIZE)); + ASSERT(AMD64_PAGEALIGNED(len, AMD64_PAGESIZE)); + + if ((amd64_mmu_mode == AMD64_MODE_LONG64) && ((va >> 47) & 1) && + ((va >> 48) != 0xffffULL)) + amd64_panic("amd64_map_mem: map attempted into 64-bit VA " + "hole (va 0x%llx)\n", va); + + while (len != 0) { + map_level = mmus[amd64_mmu_mode].map_level; + + /* + * Check to see if we're mapping a range that could be + * mapped by a large page one page table level up. If so, + * use the larger page for efficiency: + * + * Long 64-bit mode: 2M PAGE = (AMD64_PAGESIZE << LEVEL_SHIFT) + * Legacy 32-bit mode: 4M PAGE = (AMD64_PAGESIZE << LEVEL_SHIFT) + */ + pagesize = AMD64_PAGESIZE << level_shift; + + if (AMD64_PAGEALIGNED(va, pagesize) && AMD64_PAGEALIGNED(pa, + pagesize) && (len >= pagesize)) { + map_level--; + local_pagebits = PDE_PS; + } else { + pagesize = AMD64_PAGESIZE; + local_pagebits = 0; + } + + level = 1; + shift = mmus[amd64_mmu_mode].shift_base; + + while ((level <= map_level) && (len >= pagesize)) { + entry = TBL_ENTRY64(amd64_mmu_mode, tbl_base, va, shift, + idx_mask); + + if (level < map_level) { + if (!(ENTRY_VALID(entry))) { + uint32_t page; + + /* + * Grab an identity-mapped page at this + * level for an array of entries. + */ + page = (uint32_t)amd64_zalloc_identity( + AMD64_PAGESIZE); + + /* + * Setup entry pointing to the new array + */ + entry = TBL_ENTRY_DEFAULT(page); + + /* + * Insert new entry into table + */ + SET_TABLEVAL(amd64_mmu_mode, tbl_base, + va, shift, idx_mask, entry); + + /* + * If we're mapping in 64-bit long mode, + * make sure to identity map the + * allocation above into the 64-bit + * page tables to make sure the kernel + * can walk the 64-bit page tables. + */ + if (amd64_mmu_mode == + AMD64_MODE_LONG64) + amd64_map_mem( + (uint64_t)page, + (uint64_t)page, + AMD64_PAGESIZE, + amd64_mmu_mode, tbl_root, + page_modbits); + } + + /* + * Continue down another level. + */ + if ((level + 1) == map_level) { + parent_base = tbl_base; + parentlvl_entry = entry; + } + + tbl_base = (uint32_t)amd64_physaddr(entry, + amd64_mmu_mode); + shift -= level_shift; + level++; + continue; + } + + do { + /* + * Create mapping entry at this level. + */ + entry = TBL_ENTRY_DEFAULT(pa) | page_modbits | + local_pagebits; + + /* + * Install mapping entry + */ + SET_TABLEVAL(amd64_mmu_mode, tbl_base, va, + shift, idx_mask, entry); + + va += pagesize; + pa += pagesize; + len -= pagesize; + } while ((TBL_ENTRY64(amd64_mmu_mode, parent_base, va, + shift + level_shift, + idx_mask) == parentlvl_entry) && (len >= pagesize)); + + if (len != 0) { + /* + * We went over a parent's table entry mapping + * border, so we need to recalculate where we + * should be adding page tables. + * + * For example, if we are mapping 4K page + * tables in long mode, this means we crossed a + * 2M boundary. (It would be a 4M boundary for + * 32-bit legacy mode.) + */ + level = 1; + tbl_base = tbl_root; + shift = mmus[amd64_mmu_mode].shift_base; + } + } + } +} + +/* + * Save top of boot's 64-bit page tables for future use. + */ +uint64_t amd64_boot_pml4; + +/* + * Initialize long page tables + */ +uint64_t +amd64_init_longpt(uint32_t cr3) +{ + extern int magic_phys; + int i; + uint64_t *pml4, *pdpt, *pdpt_hi, *pdt, *pte_zero; + + pml4 = amd64_zalloc_identity(AMD64_PAGESIZE); + pdpt = amd64_zalloc_identity(AMD64_PAGESIZE); + pdpt_hi = amd64_zalloc_identity(AMD64_PAGESIZE); + pdt = amd64_zalloc_identity(AMD64_PAGESIZE * 4); + pte_zero = amd64_zalloc_identity(AMD64_PAGESIZE); + + /* + * Initialize long mode page tables. + * + * The only initial mappings are those for the identity mapped boot 4M + * (0x01000:0x400000) and those boot has already allocated. + */ + *pml4 = TBL_ENTRY_DEFAULT(pdpt); + + /* + * Preallocate enough level two and three entries to map the lower 4G + * of VA space, which will be reflected to the top 4G of VM space + * directly at the level two page tables. + */ + *(pml4 + 511) = TBL_ENTRY_DEFAULT(pdpt_hi); + + *pdpt = *(pdpt_hi + 508) = TBL_ENTRY_DEFAULT(pdt); + *(pdpt + 1) = *(pdpt_hi + 509) = TBL_ENTRY_DEFAULT(pdt + 512); + *(pdpt + 2) = *(pdpt_hi + 510) = TBL_ENTRY_DEFAULT(pdt + 1024); + *(pdpt + 3) = *(pdpt_hi + 511) = TBL_ENTRY_DEFAULT(pdt + 1536); + + *pdt = TBL_ENTRY_DEFAULT(pte_zero); /* leave page zero unmapped */ + + /* Identity map VA 0x200000:magic_phys at the PDE level via 2M pages */ + for (i = 1; (i + 1) * 0x200000 < magic_phys; i++) + *(pdt + i) = TBL_ENTRY_DEFAULT(i * 0x200000) | PDE_PS; + + /* + * Copy the balance of boot's initial mappings - this will fill in + * mapped entries in the page tables other than the 2M identity mapped + * page mentioned above. + */ + amd64_xlate_boot_tables(cr3, (uint32_t)pml4); + amd64_boot_pml4 = UINT64_FROMPTR32(pml4); + + return (amd64_boot_pml4); +} diff --git a/usr/src/psm/stand/boot/amd64/ptxlate.c b/usr/src/psm/stand/boot/amd64/ptxlate.c new file mode 100644 index 0000000000..80e20f783a --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/ptxlate.c @@ -0,0 +1,359 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> + +#include <amd64/amd64.h> +#include <amd64/print.h> +#include <amd64/debug.h> +#include <amd64/amd64_page.h> + +/* + * NOTE: ALL these routines assume that page tables are identity mapped (1:1, + * VA == PA). If they cannot access a given physical address by + * dereferencing the equivalent virtual address, they will fail due to + * the inability of the x86 to easily access any given physical address + * without explicitly mapping a special page specifically to do so. + * + * Since boot already maps the 32-bit page tables this way and we control + * creation of the 64-bit page tables, we can assure that this remains + * the case unless a callback is made from 64-bit mode that references a + * kernel-mapped page; doing THAT will likely cause a crash as the + * routines try to dereference an unmapped or wrong address. + */ + +/* + * Routines to manage legacy 32-bit and long mode 64-bit page mappings + */ + +void +amd64_xlate_legacy_va(uint32_t va, uint32_t len, uint32_t legacy_ptbase, + uint32_t long_ptbase) +{ + uint64_t map_pa, map_va, entry, offset; + uint32_t pagesize, map_pagesize; + + uint64_t maplen = 0; + + /* + * If passed VA is not page aligned, make it so + * and add the offset to the length we need to map, + * so a map of va 0x3100, len 0x1000 becomes a map + * of va 0x3000, len 0x1100. + */ + if (!(AMD64_PAGEALIGNED(va, AMD64_PAGESIZE))) { + len += va & AMD64_PAGEOFFSET(AMD64_PAGESIZE); + va &= AMD64_PAGEMASK(AMD64_PAGESIZE); + } + + while (len) { + uint64_t check_pa, entry_64; + + entry = amd64_legacy_lookup((uint64_t)(va), &map_pagesize, + legacy_ptbase); + + if (entry_64 = amd64_long_lookup((uint64_t)(va), &pagesize, + long_ptbase)) { + /* + * We can skip the next map_pagesize bytes since + * they've already been mapped. + */ + +#ifdef DEBUG + if ((amd64_physaddr(entry_64, AMD64_MODE_LONG64)) != + (amd64_physaddr((uint64_t)entry, + AMD64_MODE_LEGACY))) { + printf("WARNING: 64-bit va 0x%llx already " + "mapped, pa 0x%llx, len 0x%x!\n", + (uint64_t)va, amd64_physaddr(entry_64, + AMD64_MODE_LONG64), + pagesize); + printf(" Will not remap address to pa " + "0x%llx as requested.\n", + amd64_physaddr((uint64_t)entry, + AMD64_MODE_LEGACY)); + } +#endif /* DEBUG */ +#ifdef lint + entry_64 = entry_64; +#endif /* lint */ + map_pagesize = pagesize; + entry = 0; + } + + pagesize = (map_pagesize > len) ? AMD64_PAGESIZE : map_pagesize; + + if (entry) { + /* + * Valid page mapping for va found, so either add + * it to the current page range or map what we have + * and start a new range. + */ + check_pa = amd64_legacy_physaddr(entry); + + if ((map_pagesize == AMD64_PAGESIZE4M) && + (!(AMD64_PAGEALIGNED(va, map_pagesize)))) { + offset = va & AMD64_PAGEMASK(map_pagesize); + check_pa += offset; + pagesize = AMD64_PAGESIZE; + } + + if (!maplen) { + map_va = (uint64_t)(va); + + map_pa = check_pa; + maplen = pagesize; + + if (!(AMD64_PAGEALIGNED(va, pagesize))) { + offset = va & + AMD64_PAGEOFFSET(pagesize); + map_pa += offset; + maplen -= offset; + } + } else { + if (check_pa != (map_pa + maplen)) { + /* + * Range of mapped entries ends, + * so map what we've got and start + * a new range. + */ + amd64_map_mem(map_va, map_pa, + maplen, AMD64_MODE_LONG64, + long_ptbase, + amd64_modbits((uint64_t)entry)); + + /* + * Use current mapping as start of + * new range. + */ + map_va = (uint64_t)(va); + map_pa = check_pa; + maplen = pagesize; + + if (!(AMD64_PAGEALIGNED(va, + pagesize))) { + offset = va & + AMD64_PAGEOFFSET(pagesize); + map_pa += offset; + maplen -= offset; + } + } else { + /* + * Just increment mapping range + * by mapped pagesize. + */ + maplen += pagesize; + } + } + } else if (maplen) { + /* + * Found a bad map entry, so end the mapping range and + * translate the address range we have. + */ + amd64_map_mem(map_va, map_pa, maplen, AMD64_MODE_LONG64, + long_ptbase, amd64_modbits((uint64_t)entry)); + + maplen = 0; + } + + va += pagesize; + len -= (pagesize > len) ? len : pagesize; + } + + /* + * If we ended with an outstanding range left to map, be sure to map it + * now. + */ + if (maplen) + amd64_map_mem(map_va, map_pa, maplen, AMD64_MODE_LONG64, + long_ptbase, amd64_modbits((uint64_t)entry)); +} + +void +amd64_xlate_long_va(uint64_t va, uint32_t len, uint32_t long_ptbase, + uint32_t legacy_ptbase) +{ + uint32_t map_pagesize, pagesize; + uint64_t map_pa, map_va, entry, offset; + uint64_t maplen = 0; + + /* + * If passed VA is not page aligned, make it so + * and add the offset to the length we need to map, + * so a map of va 0x3100, len 0x1000 becomes a map + * of va 0x3000, len 0x1100. + */ + if (!(AMD64_PAGEALIGNED(va, AMD64_PAGESIZE))) { + len += va & AMD64_PAGEOFFSET(AMD64_PAGESIZE); + va &= AMD64_PAGEMASK(AMD64_PAGESIZE); + } + + while (len) { + uint64_t check_pa; + uint32_t entry_32; + + entry = amd64_long_lookup(va, &map_pagesize, long_ptbase); + + if (entry_32 = amd64_legacy_lookup((uint32_t)ADDR_TRUNC(va), + &pagesize, legacy_ptbase)) { + /* + * We can skip the next map_pagesize bytes since + * they've already been mapped. + */ +#ifdef DEBUG + if ((amd64_physaddr((uint64_t)entry_32, + AMD64_MODE_LEGACY)) != (amd64_physaddr(entry, + AMD64_MODE_LONG64))) { + printf("WARNING: 32-bit va 0x%llx already " + "mapped, pa 0x%llx, len 0x%x!\n", + (uint64_t)va, amd64_physaddr(entry_32, + AMD64_MODE_LEGACY), pagesize); + printf(" Will not remap address to " + "pa 0x%llx as requested.\n", + amd64_physaddr(entry, AMD64_MODE_LONG64)); + } + +#endif /* DEBUG */ +#ifdef lint + entry_32 = entry_32; +#endif /* lint */ + map_pagesize = pagesize; + entry = 0; + } + + pagesize = (map_pagesize > len) ? AMD64_PAGESIZE + : map_pagesize; + + if (entry) { + /* + * Valid page mapping for va found, so either add + * it to the current page range or map what we have + * and start a new range. + */ + check_pa = amd64_long_physaddr(entry); + + if ((map_pagesize == AMD64_PAGESIZE2M) && + (!(AMD64_PAGEALIGNED(va, map_pagesize)))) { + offset = va & AMD64_PAGEMASK(map_pagesize); + check_pa += offset; + pagesize = AMD64_PAGESIZE; + } + + if (!maplen) { + map_va = va; + map_pa = check_pa; + maplen = pagesize; + + if (!(AMD64_PAGEALIGNED(va, pagesize))) { + offset = va & + AMD64_PAGEOFFSET(pagesize); + + map_pa += offset; + maplen -= offset; + } + } else { + if (check_pa != (map_pa + maplen)) { + /* + * Range of mapped entries ends, + * so map what we've got and start + * a new range. + */ + amd64_map_mem(map_va, map_pa, maplen, + AMD64_MODE_LEGACY, legacy_ptbase, + amd64_modbits(entry)); + + /* + * Use current mapping as start of + * new range. + */ + map_va = va; + map_pa = check_pa; + maplen = pagesize; + + if (!(AMD64_PAGEALIGNED(va, + pagesize))) { + offset = va & + AMD64_PAGEOFFSET(pagesize); + map_pa += offset; + maplen -= offset; + } + } else { + /* + * Just increment mapping range + * by mapped pagesize. + */ + maplen += pagesize; + } + } + } else if (maplen) { + /* + * Found a bad map entry, so end the mapping range and + * translate the address range we have. + */ + amd64_map_mem(map_va, map_pa, maplen, AMD64_MODE_LEGACY, + legacy_ptbase, amd64_modbits(entry)); + maplen = 0; + } + + va += pagesize; + len -= (pagesize > len) ? len : pagesize; + } + + /* + * If we ended with an outstanding range left to map, be sure to map it + * now. + */ + if (maplen) + amd64_map_mem(map_va, map_pa, maplen, AMD64_MODE_LEGACY, + legacy_ptbase, amd64_modbits(entry)); +} + +void +amd64_xlate_boot_tables(uint32_t boot_ptbase, uint32_t long_ptbase) +{ + extern uint_t magic_phys; + + /* + * The initial 64-bit page tables are setup with 0x200000:0x600000 + * already identity mapped, so we can skip that range. + */ + + /* + * Copy first 2M of boot's pages but SKIP PAGE ZERO. + */ + amd64_xlate_legacy_va(0x1000ULL, 0x1ff000, boot_ptbase, long_ptbase); + + /* + * Now copy balance of boot's pages. + * + * The initial 64-bit page tables are setup with 0x200000:0x400000 + * already identity mapped, so we can skip that range... + */ + amd64_xlate_legacy_va((magic_phys / 0x200000) * 0x200000, + 0xffc00000, boot_ptbase, long_ptbase); +} diff --git a/usr/src/psm/stand/boot/amd64/segments.c b/usr/src/psm/stand/boot/amd64/segments.c new file mode 100644 index 0000000000..f384110045 --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/segments.c @@ -0,0 +1,217 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Copyright (c) 1992 Terrence R. Lambert. + * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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: @(#)machdep.c 7.4 (Berkeley) 6/3/91 + */ + +#include <sys/types.h> + +#include <amd64/boothooks.h> +#include <amd64/types.h> +#include <amd64/debug.h> +#include <amd64/tss.h> +#include <amd64/segments.h> + +/* + * Routines for loading segment descriptors in a format the hardware + * understands. + */ + +/* + * Install user segment descriptor for code and data. + */ +void +set_usegd(user_desc_t *dp, void *base, size_t size, uint_t type, + uint_t dpl, uint_t gran, uint_t defopsz) +{ + bzero(dp, sizeof (*dp)); + + dp->usd_lolimit = size; + dp->usd_hilimit = (uintptr_t)size >> 16; + + dp->usd_lobase = (uintptr_t)base; + dp->usd_midbase = (uintptr_t)base >> 16; + dp->usd_hibase = (uintptr_t)base >> (16 + 8); + + dp->usd_type = type; + dp->usd_dpl = dpl; + dp->usd_p = 1; + dp->usd_def32 = defopsz; /* 0 = 16, 1 = 32 bit operands */ + dp->usd_gran = gran; /* 0 = bytes, 1 = pages */ +} + +/* + * In long mode we have the new L or long mode attribute bit + * for code segments. Only the conforming bit in type is used along + * with descriptor priority and present bits. Default operand size must + * be zero when in long mode. In 32-bit compatibility mode all fields + * are treated as in legacy mode. For data segments while in long mode + * only the present bit is loaded. + */ +void +set_usegd64(user_desc64_t *dp, uint_t lmode, void *base, size_t size, + uint_t type, uint_t dpl, uint_t gran, uint_t defopsz) +{ + bzero(dp, sizeof (*dp)); + + ASSERT(lmode == 0 || lmode == 1); + + /* + * 64-bit long mode. + */ + if (lmode == LONG) { + dp->usd_type = type; + dp->usd_dpl = dpl; + dp->usd_p = 1; + dp->usd_long = 1; /* 64-bit mode */ + dp->usd_def32 = 0; /* must be zero for 32-bit operands */ + dp->usd_gran = gran; /* 0 = bytes, 1 = pages */ + } else { + + /* + * 32-bit compatibility mode. + */ + dp->usd_lolimit = size; + dp->usd_hilimit = (uintptr_t)size >> 16; + + dp->usd_lobase = (uintptr_t)base; + dp->usd_midbase = (uintptr_t)base >> 16; + dp->usd_hibase = (uintptr_t)base >> (16 + 8); + + dp->usd_type = type; + dp->usd_dpl = dpl; + dp->usd_p = 1; + dp->usd_long = 0; /* 32-bit mode */ + dp->usd_def32 = defopsz; /* 0 = 16, 1 = 32-bit ops */ + dp->usd_gran = gran; /* 0 = bytes, 1 = pages */ + } +} + +/* + * Install system segment descriptor for LDT and TSS segments. + */ +void +set_syssegd(system_desc_t *dp, void *base, size_t size, uint_t type, + uint_t dpl) +{ + bzero(dp, sizeof (*dp)); + + dp->ssd_lolimit = size; + dp->ssd_hilimit = (uintptr_t)size >> 16; + + dp->ssd_lobase = (uintptr_t)base; + dp->ssd_midbase = (uintptr_t)base >> 16; + dp->ssd_hibase = (uintptr_t)base >> (16 + 8); + + dp->ssd_type = type; + dp->ssd_zero = 0; /* must be zero */ + dp->ssd_dpl = dpl; + dp->ssd_p = 1; + + /* + * XXX why would anyone care to use page units for + * ldt or tss sizes? Force it to be bytes. + */ + dp->ssd_gran = 0; +} + +void +set_syssegd64(system_desc64_t *dp, void *base, size_t size, uint_t type, + uint_t dpl) +{ + bzero(dp, sizeof (*dp)); + + dp->ssd_lolimit = size; + dp->ssd_hilimit = (uintptr_t)size >> 16; + + dp->ssd_lobase = (uint32_t)base; + dp->ssd_midbase = (uint64_t)(uint32_t)base >> 16; + dp->ssd_hibase = (uint64_t)(uint32_t)base >> (16 + 8); + dp->ssd_hi64base = (uint64_t)(uint32_t)base >> (16 + 8 + 8); + + dp->ssd_type = type; + dp->ssd_zero1 = 0; /* must be zero */ + dp->ssd_zero2 = 0; + dp->ssd_dpl = dpl; + dp->ssd_p = 1; + dp->ssd_gran = 0; /* force byte units */ +} + +/* + * Install gate segment descriptor for interrupt, trap, call and task gates. + */ +void +set_gatesegd(gate_desc_t *dp, void (*func)(void), selector_t sel, + uint_t wcount, uint_t type, uint_t dpl) +{ + bzero(dp, sizeof (*dp)); + + dp->sgd_looffset = (uintptr_t)func; + dp->sgd_hioffset = (uintptr_t)func >> 16; + + dp->sgd_selector = (uint16_t)sel; + dp->sgd_stkcpy = wcount; + dp->sgd_type = type; + dp->sgd_dpl = dpl; + dp->sgd_p = 1; +} + +/* + * Note stkcpy is replaced with ist. Read the PRM for details on this. + */ +void +set_gatesegd64(gate_desc64_t *dp, void (*func)(void), selector_t sel, + uint_t ist, uint_t type, uint_t dpl) +{ + bzero(dp, sizeof (*dp)); + + dp->sgd_looffset = (uint64_t)(uint32_t)func; + dp->sgd_hioffset = (uint64_t)(uint32_t)func >> 16; + dp->sgd_hi64offset = (uint64_t)(uint32_t)func >> (16 + 16); + + dp->sgd_selector = (uint16_t)sel; + dp->sgd_ist = ist; + dp->sgd_type = type; + dp->sgd_dpl = dpl; + dp->sgd_p = 1; +} diff --git a/usr/src/psm/stand/boot/amd64/vtrap.c b/usr/src/psm/stand/boot/amd64/vtrap.c new file mode 100644 index 0000000000..cfd0df618d --- /dev/null +++ b/usr/src/psm/stand/boot/amd64/vtrap.c @@ -0,0 +1,1148 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Contains the set of routines that implement the bootops and bsyscall + * vectors for a 64-bit client program. + */ + +#include <sys/types.h> +#include <sys/controlregs.h> +#include <sys/trap.h> +#include <sys/bootsvcs.h> + +#include <amd64/print.h> +#include <amd64/bootops64.h> +#include <amd64/bootsvcs64.h> +#include <amd64/machregs.h> +#include <amd64/alloc.h> +#include <amd64/amd64_page.h> +#include <amd64/cpu.h> +#include <amd64/debug.h> +#include <amd64/amd64.h> + +uint_t bop64_trace = +#if defined(DEBUG) + /* AMD64_TRACE_BOP_VM | XX64 - also too chatty */ + /* AMD64_TRACE_BOP_PROP | XX64 - also too chatty */ + /* AMD64_TRACE_BOP_BIOS | XX64 - final vestiges of chattyness */ +#endif + 0; + +static struct bsys_mem64 *amd64_update_ml64(struct bootops *); + +/* + * Memory page set aside for translation of boot's memory lists into + * "struct memlist64" format + */ +struct memlist64 *amd64_memlistpage; + +static void +return_int(struct amd64_machregs *rp, int rval) +{ + rp->r_rax = (int64_t)rval; +} + +static void +return_paddr(struct amd64_machregs *rp, void *rval) +{ + rp->r_rax = (caddr64_t)(uint32_t)rval; +} + +static void +return_addr(struct amd64_machregs *rp, void *rval) +{ + rp->r_rax = (caddr64_t)ADDR_XTND(rval); +} + +static const char * +trap_type_name(uint_t type) +{ + switch (type) { + case T_ZERODIV: return ("Divide error (#de)"); + case T_SGLSTP: return ("Debug (#db)"); + case T_NMIFLT: return ("NMI interrupt"); + case T_BPTFLT: return ("Breakpoint (#bp)"); + case T_OVFLW: return ("Overflow (#of)"); + case T_BOUNDFLT: return ("BOUND range exceeded (#br)"); + case T_ILLINST: return ("Invalid opcode (#ud)"); + case T_NOEXTFLT: return ("Device not available (#nm)"); + case T_DBLFLT: return ("Double fault (#df)"); + case T_EXTOVRFLT: return ("(i386 only reserved trap (9))"); + case T_TSSFLT: return ("Invalid TSS (#ts)"); + case T_SEGFLT: return ("Segment not present (#np)"); + case T_STKFLT: return ("Stack segment fault (#ss)"); + case T_GPFLT: return ("General protection (#gp)"); + case T_PGFLT: return ("Page fault (#pf)"); + case 15: return ("Intel reserved trap (15)"); + case T_EXTERRFLT: return ("x87 floating point error (#mf)"); + case T_ALIGNMENT: return ("Alignment check (#ac)"); + case T_MCE: return ("Machine check (#mc)"); + case T_SIMDFPE: return ("SIMD floating point exception (#xf)"); + default: + /* + * see r_trapno for type. Sorry but amd64 + * does not support sprtintf(). + */ + return ("reserved, external or soft int"); + } +} + +/* + * (When we need to get more ambitious with this, we + * can climb the long-mode stack to see how we got here..) + */ +/*PRINTFLIKE2*/ +static void +traceback64(struct amd64_machregs *rp, const char *fmt, ...) +{ + va_list ap; + + printf("%%rip: entry 0x%16" PRIx64 " return 0x%16" PRIx64 "\n", + rp->r_trapno, rp->r_rip); + printf("%%rsp: 0x%16" PRIx64 "\n", rp->r_rsp); + + va_start(ap, fmt); + amd64_vpanic(fmt, ap); + va_end(ap); +} + +/* + * We took a real exception thru amd64's IDT. + * Dump state and reset machine. + */ +static void +idt_exception(struct amd64_machregs *rp) +{ + printf("AMD64_BAD_TRAP: %s error=0x%llx\n\n", + trap_type_name(rp->r_trapno), rp->r_err); + + amd64_dump_amd64_machregs(rp); + printf("resetting ..."); + amd64_system_reset(); + /*NOTREACHED*/ +} + +extern uintptr_t bsys64_first, bsys64_last, bop64_first, bop64_last; +extern struct boot_syscalls *entry_boot_syscalls; + +#ifdef DEBUG +static void +amd64_assert_addr(caddr_t addr, int64_t arg_64, char *caller_name, char *type) +{ + if ((int64_t)ADDR_XTND(addr) != arg_64) + amd64_panic("%s(): unexpected address for %s\n" + " (expected 0x%llx, passed 0x%llx)\n", caller_name, + type, (int64_t)ADDR_XTND(addr), arg_64); +} + +static int +amd64_check_mapped_32(uint64_t addr, char *caller_name, char *type) +{ + if (!(amd64_legacy_lookup((uint64_t)(uintptr_t)addr, (uint32_t *)0, + amd64_get_cr3()))) { + printf("ERROR: %s(): called with unmapped 32-bit %s @ " + "0x%llx\n failing operation...\n", caller_name, type, + addr); + return (0); + } + + return (1); +} + +static int +amd64_check_arg(caddr_t addr, int64_t arg_64, char *caller_name, char *type) +{ + amd64_assert_addr(addr, arg_64, caller_name, type); + return (amd64_check_mapped_32((uint64_t)(uintptr_t)addr, caller_name, + type)); +} +#endif /* DEBUG */ + +static void +amd64_invoke_bootop( + struct amd64_machregs *rp, + struct bootops64 *bop64, + struct bootops *bop) +{ + extern uint64_t amd64_boot_pml4; + static int amd64_io_quiesced = 0; + + fnaddr64_t this = (fnaddr64_t)rp->r_rip; + enum tracetype { + TRACE_NONE_RETURN, + TRACE_INT_RETURN, + TRACE_ADDR_RETURN, + TRACE_VOID_RETURN + } trace = TRACE_NONE_RETURN; + + if (this == bop64->bsys_alloc) { + + caddr_t vahint = ADDR_TRUNC(_ARG2(rp)); + size_t size = (size_t)_ARG3(rp); + int align = (int)_ARG4(rp); + void *retval; + + if (rp->r_cr3 != amd64_boot_pml4) + amd64_panic("bop64_alloc() called with wrong 64-bit " + "page table start address\n (caller's cr3: " + "0x%llx, should be: 0x%llx)\n", rp->r_cr3, + amd64_boot_pml4); + + if (bop64_trace & AMD64_TRACE_BOP_VM) { + printf("+alloc(vahint 0x%p/0x%" PRIx64 + " size %lu/%" PRIu64 " align %d) ", + (void *)vahint, _ARG2(rp), + size, _ARG3(rp), align); + trace = TRACE_ADDR_RETURN; + } + +#ifdef DEBUG + amd64_assert_addr(vahint, _ARG2(rp), "BOP_ALLOC", "vahint"); +#endif /* DEBUG */ + + retval = BOP_ALLOC(bop, vahint, size, align); + + if (retval != 0) + amd64_xlate_legacy_va((uint32_t)retval, size, + amd64_get_cr3(), amd64_boot_pml4); + + return_addr(rp, retval); + + } else if (this == bop64->bsys_free) { + + caddr_t va = ADDR_TRUNC(_ARG2(rp)); + size_t size = (size_t)_ARG3(rp); + + if (rp->r_cr3 != amd64_boot_pml4) + amd64_panic("bop64_free() called with wrong 64-bit " + "page table start address\n (caller's cr3: " + "0x%llx, should be: 0x%llx)\n", rp->r_cr3, + amd64_boot_pml4); + + if (bop64_trace & AMD64_TRACE_BOP_VM) { + printf("+free(va 0x%p/0x%" PRIx64 + " size %lu/%" PRIu64 ") ", + (void *)va, _ARG2(rp), size, _ARG3(rp)); + trace = TRACE_VOID_RETURN; + } + +#ifdef DEBUG + amd64_assert_addr(va, _ARG2(rp), "BOP_FREE", "va"); +#endif /* DEBUG */ + + BOP_FREE(bop, va, size); + + } else if (this == bop64->bsys_getproplen) { + + /* + * The property routines are mostly pass-through, but + * we take steps to hide our existence, so that the + * 64-bit kernel really does think it's talking to + * a native booter + * + * XX64 The "real" version of 'whoami' handling should be + * done in boot -- if that booter is asked to boot an + * EM_AMD64 file, it should know to put stretch into + * memory, then tell stretch and the kernel to boot + * that program, then we wouldn't need to fib here, + * because boot would be fibbing for us. + */ + + char *name = ADDR_TRUNC(_ARG2(rp)); + + if (bop64_trace & AMD64_TRACE_BOP_PROP) { + printf("+getproplen(name 0x%p/0x%" PRIx64 + " '%s') ", (void *)name, _ARG2(rp), name); + trace = TRACE_INT_RETURN; + } + +#ifdef DEBUG + if (!amd64_check_arg((caddr_t)name, _ARG2(rp), "BOP_GETPROPLEN", + "property name")) { + return_int(rp, 0); + return; + } +#endif /* DEBUG */ + + if (strcmp(name, "mmu-modlist") == 0) { + return_int(rp, strlen(amd64_getmmulist()) + 1); + } else + return_int(rp, BOP_GETPROPLEN(bop, name)); + + } else if (this == bop64->bsys_getprop) { + + char *name = ADDR_TRUNC(_ARG2(rp)); + caddr_t value = ADDR_TRUNC(_ARG3(rp)); + + if (bop64_trace & AMD64_TRACE_BOP_PROP) { + printf("+getprop(name 0x%p/0x%" PRIx64 + " '%s' value 0x%p/0x%" PRIx64 " ", + (void *)name, _ARG2(rp), name, (void *)value, + _ARG3(rp)); + } + +#ifdef DEBUG + if (!amd64_check_arg((caddr_t)name, _ARG2(rp), "BOP_GETPROP", + "property name")) { + return_int(rp, -1); + return; + } + + /* + * amd64_check_arg() can't be used here because krtld + * does a bop_getprop("whoami") with a buffer that is in stack + * space allocated just above AMD64 in memory, typically on the + * page mapped at 0x100f000), so just check to make sure the + * destination buffer is mapped in a way we can access. + */ + if (!amd64_check_mapped_32((uint64_t)(uintptr_t)value, + "BOP_GETPROP", "property value buffer")) { + return_int(rp, -1); + return; + } +#endif /* DEBUG */ + + if (strcmp(name, "memory-update") == 0) { + int retval; + + retval = BOP_GETPROP(bop, name, value); + (void) amd64_update_ml64(bop); + return_int(rp, retval); + } else if (strcmp(name, "mmu-modlist") == 0) { + (void) strcpy(value, amd64_getmmulist()); + return_int(rp, 0); + } else + return_int(rp, BOP_GETPROP(bop, name, value)); + + if (bop64_trace & AMD64_TRACE_BOP_PROP) { + static const char *string_props[] = { + "backfs-fstype", + "backfs-path", + "bootargs", + "bootpath", + "boot-path", + "boot-message", + "default-name", + "extent", + "frontfs-fstype", + "frontfs-path", + "fstype", + "impl-arch-name", + "mfg-name", + "whoami", + 0 + }; + const char * const *sp; + + printf(" = %" PRId64, rp->r_rax); + + /* + * (Sigh. This is a rather tawdry hack so that + * we can print out various "well-known" string + * properties as strings.) + */ + for (sp = string_props; *sp; sp++) + if (strcmp(*sp, name) == 0) { + printf(" [= '%s']", value); + break; + } + + printf("\n"); + } + + } else if (this == bop64->bsys_nextprop) { + + char *prevprop = ADDR_TRUNC(_ARG2(rp)); + + if (bop64_trace & AMD64_TRACE_BOP_PROP) { + printf("+nextprop(prevprop 0x%p/0x%" PRIx64 + "/'%s') ", (void *)prevprop, _ARG2(rp), prevprop); + trace = TRACE_ADDR_RETURN; + } + +#ifdef DEBUG + if (!amd64_check_arg((caddr_t)prevprop, _ARG2(rp), + "BOP_NEXTPROP", "previous property")) { + return_addr(rp, 0); + return; + } +#endif /* DEBUG */ + + return_addr(rp, BOP_NEXTPROP(bop, prevprop)); + + } else if (this == bop64->bsys_printf) { + + char lnbuf[128]; + char *fmt = ADDR_TRUNC(_ARG2(rp)); + int lnlen; + +#if 0 /* correct code */ + ASSERT((uint16_t)rp->r_rax <= 8); /* no SSE regs! */ +#else /* XX64 */ + /* + * Technically an ABI violation, gcc 3.2.3 currently + * only does a "mov $0, al" before calling printf, with + * the result that we tripped over this assert due to garbage + * in the upper 8 bytes of what would be ax. + */ + ASSERT((uint8_t)rp->r_rax <= 8); /* no SSE regs! */ +#endif + +#ifdef DEBUG + if (!amd64_check_mapped_32((uint64_t)(uintptr_t)fmt, + "BOP_PRINTF", "fmt string")) + return; +#endif /* DEBUG */ + + lnlen = amd64_snprintf64(lnbuf, sizeof (lnbuf), fmt, + _ARG3(rp), _ARG4(rp), _ARG5(rp), _ARG6(rp)); + + printf("%s%s", lnbuf, + (lnlen > sizeof (lnbuf)) ? " [truncated]\n" : ""); + + } else if (this == bop64->bsys_doint) { + + int intnum = (int)_ARG2(rp); + struct bop_regs *regs = ADDR_TRUNC(_ARG3(rp)); + + /* + * (Looks like the -kernel- only does this for pci_check() + */ + + if (bop64_trace & AMD64_TRACE_BOP_BIOS) { + printf("+doint(intnum %d " + "regs 0x%p/0x%" PRIx64 ") ", + intnum, (void *)regs, _ARG3(rp)); + trace = TRACE_VOID_RETURN; + } + +#ifdef DEBUG + if (!amd64_check_arg((caddr_t)regs, _ARG3(rp), "BOP_DOINT", + "regs")) + return; +#endif /* DEBUG */ + + BOP_DOINT(bop, intnum, regs); + + } else if (this == bop64->bsys_ealloc) { + + caddr_t vahint = ADDR_TRUNC(_ARG2(rp)); + size_t size = (size_t)_ARG3(rp); + int align = (int)_ARG4(rp); + int flags = (int)_ARG5(rp); + void *retval; + + if (rp->r_cr3 != amd64_boot_pml4) + amd64_panic("bop64_ealloc() called with wrong 64-bit " + "page table start address\n (caller's cr3: " + "0x%llx, should be: 0x%llx)\n", rp->r_cr3, + amd64_boot_pml4); + + if (bop64_trace & AMD64_TRACE_BOP_VM) { + printf("+ealloc(vahint 0x%p/0x%" PRIx64 + " size %lu/%" PRIu64 " align %d flags 0x%x) ", + (void *)vahint, _ARG2(rp), size, _ARG3(rp), align, + flags); + trace = TRACE_ADDR_RETURN; + } + +#ifdef DEBUG + if (vahint) + amd64_assert_addr(vahint, _ARG2(rp), "BOP_EALLOC", + "vahint"); +#endif /* DEBUG */ + + retval = BOP_EALLOC(bop, vahint, size, align, flags); + + /* + * Don't attempt to create 64-bit mappings for purely physical + * memory reservations or for failed allocations, + */ + if (flags & BOPF_X86_ALLOC_PHYS) + return_paddr(rp, retval); + else { + if (retval != 0) + amd64_xlate_legacy_va((uint32_t)retval, size, + amd64_get_cr3(), amd64_boot_pml4); + + return_addr(rp, retval); + } + } else + traceback64(rp, "BOP_xxx (@ 0x%" PRIx64 ") unimp", this); + + switch (trace) { + case TRACE_NONE_RETURN: + break; + case TRACE_INT_RETURN: + printf(" = %" PRId64 "\n", rp->r_rax); + break; + case TRACE_ADDR_RETURN: + printf(" = 0x%p/0x%" PRIx64 "\n", + ADDR_TRUNC(rp->r_rax), rp->r_rax); + break; + case TRACE_VOID_RETURN: + printf(" = (void)\n"); + break; + } +} + +static struct bsys_mem64 * +amd64_update_ml64(struct bootops *bop) +{ + extern struct memlist64 *amd64_convert_memlist(struct memlist *, + struct memlist64 *); + + static struct bsys_mem64 __memlist64, *bop_ml64 = &__memlist64; + + struct memlist64 *ml64 = amd64_memlistpage; + + /* + * amd64_convert_memlist() returns a pointer to the entry one past the + * previous translated list, suitable for the start of the next new + * memlist64, so the assignments below may seem a bit non-intuitive + * at first... + */ + bop_ml64->physinstalled = UINT64_FROMPTR32(ml64); + ml64 = amd64_convert_memlist(bop->boot_mem->physinstalled, ml64); + + bop_ml64->physavail = UINT64_FROMPTR32(ml64); + ml64 = amd64_convert_memlist(bop->boot_mem->physavail, ml64); + + bop_ml64->pcimem = UINT64_FROMPTR32(ml64); + ml64 = amd64_convert_memlist(bop->boot_mem->pcimem, ml64); + return (bop_ml64); +} + +static struct bootops *saved_bootops; + +/* + * This is the 64-bit bootops vector that we hand to the 64-bit standalone + */ +struct bootops64 * +init_bootops64(struct bootops *bop) +{ + static struct bootops64 __bootops64, *bop64 = &__bootops64; + +#define SET_BOP64(bop, opname) \ + { \ + extern uintptr_t bop64_##opname; \ + (bop)->bsys_##opname = \ + (fnaddr64_t)(uintptr_t)&bop64_##opname; \ + } + + /* move to main.c or to startup */ + + ASSERT(bop->bsys_version >= BO_VERSION); + + amd64_memlistpage = (struct memlist64 *) + amd64_zalloc_identity(2 * AMD64_PAGESIZE); + + saved_bootops = bop; + bop64->bsys_version = BO_VERSION; + bop64->boot_mem = (caddr64_t)(uintptr_t)amd64_update_ml64(bop); + + SET_BOP64(bop64, alloc) + SET_BOP64(bop64, free) + SET_BOP64(bop64, getproplen) + SET_BOP64(bop64, getprop) + SET_BOP64(bop64, nextprop) + SET_BOP64(bop64, printf) + SET_BOP64(bop64, doint) + SET_BOP64(bop64, ealloc) + +#undef SET_BOP64 + + return (bop64); +} + +static void +amd64_invoke_boot_syscall( + struct amd64_machregs *rp, + struct boot_syscalls *bsys, + struct boot_syscalls64 *bsys64) +{ + fnaddr64_t this = (fnaddr64_t)rp->r_rip; + + if (this == bsys64->getchar) { + rp->r_rax = BSVC_GETCHAR(bsys); + } else if (this == bsys64->putchar) { + BSVC_PUTCHAR(bsys, (uchar_t)rp->r_rdi); + } else if (this == bsys64->ischar) { + rp->r_rax = BSVC_ISCHAR(bsys); + } else + traceback64(rp, "bsys_xxx (type 0x%" PRIx64 ") unimp", this); +} + +static struct boot_syscalls64 __boot_syscalls64; /* XXX - global scope */ +static struct boot_syscalls *saved_boot_syscallp; + +/* + * Return the 64-bit bsyscall vector that we hand to the 64-bit standalone + */ +struct boot_syscalls64 * +init_boot_syscalls64(struct boot_syscalls *bsys) +{ + struct boot_syscalls64 *bsys64 = &__boot_syscalls64; + + /* + * This variable is awful; the 'bsys' pointer should be + * the first argument to every bsys handler .. but in the + * meantime, this'll do. + */ + saved_boot_syscallp = bsys; + + bzero(bsys64, sizeof (*bsys64)); + +#define SET_BSYS64(bsys, opname) \ + { \ + extern uintptr_t bsys64_##opname; \ + (bsys)->opname = \ + (fnaddr64_t)(uintptr_t)&bsys64_##opname; \ + } + + SET_BSYS64(bsys64, getchar) + SET_BSYS64(bsys64, putchar) + SET_BSYS64(bsys64, ischar) + +#undef SET_BSYS64 + + return (bsys64); +} + +static void dump_desctbr(const char *, desctbr_t *); +static void dump_desctbr64(const char *, desctbr64_t *); + +/* + * After stashing machine state we must convert the tss gdt entry from + * busy to available type. + */ +void +amd64_i386_clrtss(struct i386_machregs *rp) +{ +#if 0 + system_desc_t *ssd; + + if (rp->r_tr != 0) { + ASSERT(SELTOIDX(rp->r_tr) < SELTOIDX(rp->r_gdt.dtr_limit)); + ASSERT((rp->r_tr & CPL_MASK) == 0); + ssd = (system_desc_t *)(rp->r_gdt.dtr_base + rp->r_tr); + + ASSERT(ssd->ssd_type == SDT_SYSTSSBSY); + ssd->ssd_type = SDT_SYSTSS; + ASSERT(rp->r_gdt.dtr_limit != 0); + } +#endif +} + +static void +amd64_clrtss(struct amd64_machregs *rp) +{ + system_desc64_t *ssd; + + if (rp->r_tr != 0) { + + ASSERT(SELTOIDX(rp->r_tr) < SELTOIDX(rp->r_gdt.dtr_limit)); + ASSERT((rp->r_tr & CPL_MASK) == 0); + ssd = (system_desc64_t *)(uintptr_t) + (rp->r_gdt.dtr_base + rp->r_tr); + + ssd->ssd_type = SDT_SYSTSS; + ASSERT(rp->r_gdt.dtr_limit != 0); + } +} + +void +amd64_vtrap(struct amd64_machregs *rp) +{ + uintptr_t addr = (uintptr_t)rp->r_rip; + + /* + * __vtrap_common always sets r_trapno to -1 + */ + if (rp->r_trapno == -1) { + if ((addr - (uintptr_t)&bsys64_first) <= + ((uintptr_t)&bsys64_last - (uintptr_t)&bsys64_first)) { + amd64_invoke_boot_syscall(rp, + saved_boot_syscallp, &__boot_syscalls64); + } else if ((addr - (uintptr_t)&bop64_first) <= + ((uintptr_t)&bop64_last - (uintptr_t)&bop64_first)) { + struct bootops64 *bop64 = ADDR_TRUNC(_ARG1(rp)); + amd64_invoke_bootop(rp, bop64, saved_bootops); + } + } else { + /* + * we took a real exception. + */ + idt_exception(rp); + } + + amd64_clrtss(rp); +} + +static const char * +desc_type_name(uint_t type) +{ + switch (type) { + case SDT_SYSNULL: + case SDT_SYSNULL2: + case SDT_SYSNULL3: + case SDT_SYSNULL4: return ("illegal"); + case SDT_SYS286TSS: return ("16-bit tss"); + case SDT_SYSLDT: return ("ldt"); + case SDT_SYS286BSY: return ("16-bit tss busy"); + case SDT_SYS286CGT: return ("16-bit call gate"); + case SDT_SYSTASKGT: return ("task gate"); + case SDT_SYS286IGT: return ("16-bit intr gate"); + case SDT_SYS286TGT: return ("16-bit trap gate"); + case SDT_SYSTSS: return ("32-bit tss"); + case SDT_SYSTSSBSY: return ("32-bit tss busy"); + case SDT_SYSCGT: return ("32-bit call gate"); + case SDT_SYSIGT: return ("32-bit intr gate"); + case SDT_SYSTGT: return ("32-bit trap gate"); + + case SDT_MEMRO: return ("r-- --"); + case SDT_MEMROA: return ("r-- -a"); + case SDT_MEMRW: return ("rw- --"); + case SDT_MEMRWA: return ("rw- -a"); + case SDT_MEMROD: return ("r-- d-"); + case SDT_MEMRODA: return ("r-- da"); + case SDT_MEMRWD: return ("rw- d-"); + case SDT_MEMRWDA: return ("rw- da"); + case SDT_MEME: return ("--x --"); + case SDT_MEMEA: return ("--x -a"); + case SDT_MEMER: return ("r-x --"); + case SDT_MEMERA: return ("r-x -a"); + case SDT_MEMEC: return ("--x c-"); + case SDT_MEMEAC: return ("--x ca"); + case SDT_MEMERC: return ("r-x c-"); + case SDT_MEMERAC: return ("r-x ca"); + default: return ("(unknown)"); + } +} + +static size_t +dump_ssd(void *desc) +{ + uint_t type = ((struct user_segment_descriptor *)desc)->usd_type; + + printf("type %2d (%s) ", type, desc_type_name(type)); + + switch (type) { + + case SDT_SYSTASKGT: { + struct gate_segment_descriptor *sgd = desc; + + printf("tss sel 0x%x dpl %d %spresent\n", + sgd->sgd_selector, sgd->sgd_dpl, + sgd->sgd_p ? "" : "NOT "); + return (sizeof (*sgd)); + } + + case SDT_SYSLDT: + case SDT_SYSTSS: + case SDT_SYSTSSBSY: { + struct system_segment_descriptor *ssd = desc; + uint32_t base = ssd->ssd_lobase | + (ssd->ssd_midbase << 16) | (ssd->ssd_hibase << 24); + uint32_t lim = ssd->ssd_lolimit | + (ssd->ssd_hilimit << 16); + + printf("base 0x%x lim 0x%x dpl %d %spresent\n", + base, ssd->ssd_gran ? lim * 4096 : lim, + ssd->ssd_dpl, ssd->ssd_p ? "" : "NOT "); + return (sizeof (*ssd)); + } + + case SDT_SYSCGT: + case SDT_SYSIGT: + case SDT_SYSTGT: { + struct gate_segment_descriptor *sgd = desc; + + printf("target 0x%x:0x%x dpl %d %spresent", + sgd->sgd_selector, sgd->sgd_looffset | + (sgd->sgd_hioffset << 16), + sgd->sgd_dpl, sgd->sgd_p ? "" : "NOT "); + if (type == SDT_SYSCGT) + printf(" %d parms", sgd->sgd_stkcpy); + printf("\n"); + return (sizeof (*sgd)); + } + + case SDT_MEMRO: + case SDT_MEMROA: + case SDT_MEMRW: + case SDT_MEMRWA: + case SDT_MEMROD: + case SDT_MEMRODA: + case SDT_MEMRWD: + case SDT_MEMRWDA: + case SDT_MEME: + case SDT_MEMEA: + case SDT_MEMER: + case SDT_MEMERA: + case SDT_MEMEC: + case SDT_MEMEAC: + case SDT_MEMERC: + case SDT_MEMERAC: { + struct user_segment_descriptor *usd = desc; + uint32_t base = usd->usd_lobase | + (usd->usd_midbase << 16) | (usd->usd_hibase << 24); + uint32_t lim = usd->usd_lolimit | + (usd->usd_hilimit << 16); + + printf("base 0x%x lim 0x%x dpl %d %spresent\n", + base, usd->usd_gran ? lim * 4096 : lim, + usd->usd_dpl, usd->usd_p ? "" : "NOT "); + return (sizeof (*usd)); + } + + default: { + uint16_t *u16 = desc; + struct system_segment_descriptor *ssd = desc; + + printf("0x%x.%x.%x.%x dpl %d %spresent\n", + u16[0], u16[1], u16[2], u16[3], + ssd->ssd_dpl, ssd->ssd_p ? "" : "NOT "); + return (sizeof (*ssd)); + } + + } +} + +static void +dump_desctbr(const char *name, desctbr_t *dtr) +{ + uintptr_t entry, theend; + + printf(" %s [limit %x base %x]\n", + name, dtr->dtr_limit, dtr->dtr_base); + + theend = (uintptr_t)(dtr->dtr_base + dtr->dtr_limit); + + for (entry = dtr->dtr_base; entry < theend; ) { + printf(" %6lu: ", entry - (uintptr_t)dtr->dtr_base); + entry += dump_ssd((void *)entry); + /* + * Hack to print only the hardware entries in the idt + */ + if (entry - (uintptr_t)dtr->dtr_base > 19 && + strcmp(name, "idt") == 0) + return; + } +} + +static void +dump_user_descriptor(desctbr_t *gdt, const char *name, uint16_t sel) +{ + uint_t index; + static const char fmt1[] = " %8s %16x\n "; + + printf(fmt1, name, sel); + + if ((index = SELTOIDX(sel)) == 0) + printf("<null selector>\n"); + else if (index > gdt->dtr_limit) + printf("<selector out of range?>\n"); + else { + uintptr_t entry = + (uintptr_t)gdt->dtr_base + IDXTOSEL(index); + + (void) dump_ssd((void *)entry); + } +} + +void +amd64_dump_i386_machregs(struct i386_machregs *rp) +{ + static const char fmt1[] = " %8s %16x\n"; + static const char fmt2[] = " %8s %16x %8s %16x\n"; + static const char fmtb[] = " %8s %16b\n"; + + printf("struct i386_machregs @0x%p = {\n", (void *)rp); + +#if defined(__GNUC__) + printf(fmt1, "cr0", rp->r_cr0); + printf(fmt1, "cr2", rp->r_cr2); + printf(fmt1, "cr3", rp->r_cr3); + printf(fmt1, "cr4", rp->r_cr4); +#else + printf(fmtb, "cr0", rp->r_cr0, FMT_CR0); + printf(fmt1, "cr2", rp->r_cr2); + printf(fmtb, "cr3", rp->r_cr3, FMT_CR3); + printf(fmtb, "cr4", rp->r_cr4, FMT_CR4); +#endif + dump_desctbr("gdt", &rp->r_gdt); + dump_desctbr("idt", &rp->r_idt); + + dump_user_descriptor(&rp->r_gdt, "ldt", rp->r_ldt); + dump_user_descriptor(&rp->r_gdt, "tr", rp->r_tr); + + printf(fmt2, "edi", rp->r_edi, "esi", rp->r_esi); + printf(fmt2, "ebp", rp->r_ebp, "esp", rp->r_esp); + printf(fmt2, "ebx", rp->r_ebx, "ecx", rp->r_ecx); + + printf(fmt2, "eip", rp->r_eip, "efl", rp->r_efl); + printf(fmt1, "uesp", rp->r_uesp); + + dump_user_descriptor(&rp->r_gdt, "cs", (uint16_t)rp->r_cs); + dump_user_descriptor(&rp->r_gdt, "ds", (uint16_t)rp->r_ds); + dump_user_descriptor(&rp->r_gdt, "es", (uint16_t)rp->r_es); + dump_user_descriptor(&rp->r_gdt, "fs", (uint16_t)rp->r_fs); + dump_user_descriptor(&rp->r_gdt, "gs", (uint16_t)rp->r_gs); + dump_user_descriptor(&rp->r_gdt, "ss", (uint16_t)rp->r_ss); + + printf(fmt2, "trapno", rp->r_trapno, "err", rp->r_err); + + printf("}\n"); +} + +static const char * +desc64_type_name(uint_t type) +{ + switch (type) { + case SDT_SYSNULL: + case SDT_SYS286TSS: + case SDT_SYS286BSY: + case SDT_SYS286CGT: + case SDT_SYSTASKGT: + case SDT_SYS286IGT: + case SDT_SYS286TGT: + case SDT_SYSNULL2: + case SDT_SYSNULL3: + case SDT_SYSNULL4: return ("illegal"); + + case SDT_SYSLDT: return ("64-bit ldt"); + case SDT_SYSTSS: return ("64-bit tss"); + case SDT_SYSTSSBSY: return ("64-bit tss busy"); + case SDT_SYSCGT: return ("64-bit call gate"); + case SDT_SYSIGT: return ("64-bit intr gate"); + case SDT_SYSTGT: return ("64-bit trap gate"); + + case SDT_MEMRO: return ("r-- --"); + case SDT_MEMROA: return ("r-- -a"); + case SDT_MEMRW: return ("rw- --"); + case SDT_MEMRWA: return ("rw- -a"); + case SDT_MEMROD: return ("r-- d-"); + case SDT_MEMRODA: return ("r-- da"); + case SDT_MEMRWD: return ("rw- d-"); + case SDT_MEMRWDA: return ("rw- da"); + case SDT_MEME: return ("--x --"); + case SDT_MEMEA: return ("--x -a"); + case SDT_MEMER: return ("r-x --"); + case SDT_MEMERA: return ("r-x -a"); + case SDT_MEMEC: return ("--x c-"); + case SDT_MEMEAC: return ("--x ca"); + case SDT_MEMERC: return ("r-x c-"); + case SDT_MEMERAC: return ("r-x ca"); + default: return ("(unknown)"); + } +} + +static size_t +dump_ssd64(void *desc) +{ + uint_t type = ((struct user_segment_descriptor64 *)desc)->usd_type; + + printf("type %d (%s) ", type, desc64_type_name(type)); + + switch (type) { + case SDT_SYSLDT: + case SDT_SYSTSS: + case SDT_SYSTSSBSY: { + struct system_segment_descriptor64 *ssd = desc; + uint64_t base = (uint64_t)ssd->ssd_lobase | + ((uint64_t)ssd->ssd_midbase << 16) | + ((uint64_t)ssd->ssd_hibase << 24) | + ((uint64_t)ssd->ssd_hi64base << 32); + uint32_t lim = ssd->ssd_lolimit | + (ssd->ssd_hilimit << 16); + + printf("base 0x%" PRIx64 + " lim 0x%x dpl %d %spresent\n", + base, ssd->ssd_gran ? lim * 4096 : lim, + ssd->ssd_dpl, ssd->ssd_p ? "" : "NOT "); + + if (ssd->ssd_zero1 != 0 || ssd->ssd_zero2) + amd64_warning("zero1 field 0x%x zero2 field " + "0x%x", ssd->ssd_zero1, ssd->ssd_zero2); + return (sizeof (*ssd)); + } + + case SDT_SYSCGT: + case SDT_SYSIGT: + case SDT_SYSTGT: { + struct gate_segment_descriptor64 *sgd = desc; + + printf("target 0x%x:0x%" PRIx64 " dpl %d " + "%spresent\n", sgd->sgd_selector, + (uint64_t)sgd->sgd_looffset | + ((uint64_t)sgd->sgd_hioffset) << 16 | + ((uint64_t)sgd->sgd_hi64offset), + sgd->sgd_dpl, sgd->sgd_p ? "" : "NOT "); + + if (type == SDT_SYSCGT && sgd->sgd_zero != 0) + amd64_warning("zero field 0x%x\n", + sgd->sgd_zero); + return (sizeof (*sgd)); + } + + case SDT_MEMRO: + case SDT_MEMROA: + case SDT_MEMRW: + case SDT_MEMRWA: + case SDT_MEMROD: + case SDT_MEMRODA: + case SDT_MEMRWD: + case SDT_MEMRWDA: { + struct user_segment_descriptor64 *usd = desc; + + printf("%spresent\n", usd->usd_p ? "" : "NOT "); + return (sizeof (*usd)); + } + + case SDT_MEME: + case SDT_MEMEA: + case SDT_MEMER: + case SDT_MEMERA: + case SDT_MEMEC: + case SDT_MEMEAC: + case SDT_MEMERC: + case SDT_MEMERAC: { + struct user_segment_descriptor64 *usd = desc; + + printf("%sconforming, dpl %d, %spresent, " + "long %d, defopsz %d\n", + BITX(usd->usd_type, 2, 2) ? "" : "non-", + usd->usd_dpl, + usd->usd_p ? "" : "NOT ", + usd->usd_long, usd->usd_def32); + if (usd->usd_long && usd->usd_def32) + amd64_warning("both the L and D bit are " + "set!\n"); + return (sizeof (*usd)); + } + + default: + printf("\n"); + return (sizeof (struct user_segment_descriptor64)); + } +} + +static void +dump_desctbr64(const char *name, desctbr64_t *dtr) +{ + uintptr_t entry, theend; + + printf(" %s [limit 0x%x base 0x%" PRIx64 "]\n", + name, dtr->dtr_limit, dtr->dtr_base); + + theend = (uintptr_t)(dtr->dtr_base + dtr->dtr_limit); + + for (entry = (uintptr_t)dtr->dtr_base; entry < theend; ) { + printf(" %6lu: ", entry - (uintptr_t)dtr->dtr_base); + entry += dump_ssd64((void *)entry); + + /* + * Hack to print only the hardware entries in the idt + */ + if (entry - (uintptr_t)dtr->dtr_base > 19 && + strcmp(name, "idt") == 0) + return; + } +} + +static void +dump_user_descriptor64(desctbr64_t *gdt, const char *name, uint16_t sel) +{ + uint_t index; + static const char fmt1[] = " %8s %16x\n "; + + printf(fmt1, name, sel); + + if ((index = SELTOIDX(sel)) == 0) + printf("<null selector>\n"); + else if (index > gdt->dtr_limit) + printf("<selector out of range?>\n"); + else { + uintptr_t entry = + (uintptr_t)gdt->dtr_base + IDXTOSEL(index); + + (void) dump_ssd((void *)entry); + } +} + +void +amd64_dump_amd64_machregs(struct amd64_machregs *rp) +{ + static const char fmt1[] = " %8s %16" PRIx64 "\n"; + static const char fmt2[] = " %8s %16" PRIx64 " %8s %16" PRIx64 "\n"; + static const char fmtb[] = " %8s %16b\n"; + + printf("struct amd64_machregs @0x%p = {\n", (void *)rp); + + printf(fmt1, "kgsbase", rp->r_kgsbase); + printf(fmt2, "gsbase", rp->r_gsbase, "fsbase", rp->r_fsbase); + + printf(fmt2, "cr0", rp->r_cr0, "cr2", rp->r_cr2); + printf(fmt2, "cr3", rp->r_cr3, "cr4", rp->r_cr4); + printf(fmt1, "cr8", rp->r_cr8); + +#if !defined(__GNUC__) + printf(fmtb, "cr0", (uint_t)rp->r_cr0, FMT_CR0); + printf(fmtb, "cr3", (uint_t)rp->r_cr3, FMT_CR3); + printf(fmtb, "cr4", (uint_t)rp->r_cr4, FMT_CR4); +#endif + + dump_desctbr64("gdt", &rp->r_gdt); + dump_desctbr64("idt", &rp->r_idt); + + dump_user_descriptor64(&rp->r_gdt, "ldt", (uint16_t)rp->r_ldt); + dump_user_descriptor64(&rp->r_gdt, "tr", (uint16_t)rp->r_tr); + + printf(fmt2, "rdi", rp->r_rdi, "rsi", rp->r_rsi); + printf(fmt2, "rdx", rp->r_rdx, "rcx", rp->r_rcx); + printf(fmt2, "r8", rp->r_r8, "r9", rp->r_r9); + printf(fmt2, "rax", rp->r_rax, "rbx", rp->r_rbx); + printf(fmt2, "rbp", rp->r_rbp, "r10", rp->r_r10); + printf(fmt2, "r11", rp->r_r11, "r12", rp->r_r12); + printf(fmt2, "r13", rp->r_r13, "r14", rp->r_r14); + printf(fmt2, "r15", rp->r_r15, "rsp", rp->r_rsp); + printf(fmt2, "rip", rp->r_rip, "rfl", rp->r_rfl); + + dump_user_descriptor64(&rp->r_gdt, "cs", (uint16_t)rp->r_cs); + dump_user_descriptor64(&rp->r_gdt, "ds", (uint16_t)rp->r_ds); + dump_user_descriptor64(&rp->r_gdt, "es", (uint16_t)rp->r_es); + dump_user_descriptor64(&rp->r_gdt, "fs", (uint16_t)rp->r_fs); + dump_user_descriptor64(&rp->r_gdt, "gs", (uint16_t)rp->r_gs); + dump_user_descriptor64(&rp->r_gdt, "ss", (uint16_t)rp->r_ss); + + printf(fmt2, "trapno", rp->r_trapno, "err", rp->r_err); + + printf("}\n"); +} diff --git a/usr/src/psm/stand/boot/common/heap_kmem.c b/usr/src/psm/stand/boot/common/heap_kmem.c new file mode 100644 index 0000000000..344325ca99 --- /dev/null +++ b/usr/src/psm/stand/boot/common/heap_kmem.c @@ -0,0 +1,882 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#if 1 +#undef DEBUG +#endif + +/* #define DEBUG ON */ + +/* + * Conditions on use: + * kmem_alloc and kmem_free must not be called from interrupt level, + * except from software interrupt level. This is because they are + * not reentrant, and only block out software interrupts. They take + * too long to block any real devices. There is a routine + * kmem_free_intr that can be used to free blocks at interrupt level, + * but only up to splimp, not higher. This is because kmem_free_intr + * only spl's to splimp. + * + * Also, these routines are not that fast, so they should not be used + * in very frequent operations (e.g. operations that happen more often + * than, say, once every few seconds). + */ + +/* + * description: + * Yet another memory allocator, this one based on a method + * described in C.J. Stephenson, "Fast Fits", IBM Sys. Journal + * + * The basic data structure is a "Cartesian" binary tree, in which + * nodes are ordered by ascending addresses (thus minimizing free + * list insertion time) and block sizes decrease with depth in the + * tree (thus minimizing search time for a block of a given size). + * + * In other words, for any node s, letting D(s) denote + * the set of descendents of s, we have: + * + * a. addr(D(left(s))) < addr(s) < addr(D(right(s))) + * b. len(D(left(s))) <= len(s) >= len(D(right(s))) + */ + +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/salib.h> +#include <sys/saio.h> +#include <sys/promif.h> + +/* + * The node header structure. + * + * To reduce storage consumption, a header block is associated with + * free blocks only, not allocated blocks. + * When a free block is allocated, its header block is put on + * a free header block list. + * + * This creates a header space and a free block space. + * The left pointer of a header blocks is used to chain free header + * blocks together. + */ + +typedef enum {false, true} bool; +typedef struct freehdr *Freehdr; +typedef struct dblk *Dblk; + +/* + * Description of a header for a free block + * Only free blocks have such headers. + */ +struct freehdr { + Freehdr left; /* Left tree pointer */ + Freehdr right; /* Right tree pointer */ + Dblk block; /* Ptr to the data block */ + size_t size; /* Size of the data block */ +}; + +#define NIL ((Freehdr) 0) +#define WORDSIZE sizeof (int) +#define SMALLEST_BLK 1 /* Size of smallest block */ + +/* + * Description of a data block. + */ +struct dblk { + char data[1]; /* Addr returned to the caller */ +}; + +/* + * weight(x) is the size of a block, in bytes; or 0 if and only if x + * is a null pointer. It is the responsibility of kmem_alloc() and + * kmem_free() to keep zero-length blocks out of the arena. + */ + +#define weight(x) ((x) == NIL? 0: (x->size)) +#define nextblk(p, size) ((Dblk) ((char *)(p) + (size))) +#define max(a, b) ((a) < (b)? (b): (a)) + +void *kmem_alloc(size_t, int); +void kmem_free(void *ptr, size_t nbytes); +Freehdr getfreehdr(void); +static bool morecore(size_t); +void insert(Dblk p, size_t len, Freehdr *tree); +void freehdr(Freehdr p); +void delete(Freehdr *p); +static void check_need_to_free(void); +extern caddr_t resalloc(enum RESOURCES, size_t, caddr_t, int); +#ifdef __sparc +extern void resalloc_init(void); +#endif +extern int splnet(void); +extern int splimp(void); +extern void splx(int); + +/* + * Structure containing various info about allocated memory. + */ +#define NEED_TO_FREE_SIZE 5 +struct kmem_info { + Freehdr free_root; + Freehdr free_hdr_list; + struct map *map; + struct pte *pte; + caddr_t vaddr; + struct need_to_free { + caddr_t addr; + size_t nbytes; + } need_to_free_list, need_to_free[NEED_TO_FREE_SIZE]; +} kmem_info; + + +struct map *kernelmap; + +#ifdef DEBUG +static void prtree(Freehdr, char *); +#endif + +/* + * Initialize kernel memory allocator + */ + +void +kmem_init(void) +{ + int i; + struct need_to_free *ntf; + +#ifdef DEBUG +printf("kmem_init entered\n"); +#endif + +#ifdef __sparc + resalloc_init(); +#endif + + kmem_info.free_root = NIL; + kmem_info.free_hdr_list = NULL; + kmem_info.map = kernelmap; + kmem_info.need_to_free_list.addr = 0; + ntf = kmem_info.need_to_free; + for (i = 0; i < NEED_TO_FREE_SIZE; i++) { + ntf[i].addr = 0; + } +#ifdef DEBUG +printf("kmem_init returning\n"); +prtree(kmem_info.free_root, "kmem_init"); +#endif +} + +/* + * Insert a new node in a cartesian tree or subtree, placing it + * in the correct position with respect to the existing nodes. + * + * algorithm: + * Starting from the root, a binary search is made for the new + * node. If this search were allowed to continue, it would + * eventually fail (since there cannot already be a node at the + * given address); but in fact it stops when it reaches a node in + * the tree which has a length less than that of the new node (or + * when it reaches a null tree pointer). The new node is then + * inserted at the root of the subtree for which the shorter node + * forms the old root (or in place of the null pointer). + */ + + +void +insert(Dblk p, /* Ptr to the block to insert */ + size_t len, /* Length of new node */ + Freehdr *tree) /* Address of ptr to root */ +{ + Freehdr x; + Freehdr *left_hook; /* Temp for insertion */ + Freehdr *right_hook; /* Temp for insertion */ + Freehdr newhdr; + + x = *tree; + /* + * Search for the first node which has a weight less + * than that of the new node; this will be the + * point at which we insert the new node. + */ + + while (weight(x) >= len) { + if (p < x->block) + tree = &x->left; + else + tree = &x->right; + x = *tree; + } + + /* + * Perform root insertion. The variable x traces a path through + * the tree, and with the help of left_hook and right_hook, + * rewrites all links that cross the territory occupied + * by p. Note that this improves performance under + * paging. + */ + + newhdr = getfreehdr(); + *tree = newhdr; + left_hook = &newhdr->left; + right_hook = &newhdr->right; + + newhdr->left = NIL; + newhdr->right = NIL; + newhdr->block = p; + newhdr->size = len; + + while (x != NIL) { + /* + * Remark: + * The name 'left_hook' is somewhat confusing, since + * it is always set to the address of a .right link + * field. However, its value is always an address + * below (i.e., to the left of) p. Similarly + * for right_hook. The values of left_hook and + * right_hook converge toward the value of p, + * as in a classical binary search. + */ + if (x->block < p) { + /* + * rewrite link crossing from the left + */ + *left_hook = x; + left_hook = &x->right; + x = x->right; + } else { + /* + * rewrite link crossing from the right + */ + *right_hook = x; + right_hook = &x->left; + x = x->left; + } /* else */ + } /* while */ + + *left_hook = *right_hook = NIL; /* clear remaining hooks */ + +} /* insert */ + + +/* + * Delete a node from a cartesian tree. p is the address of + * a pointer to the node which is to be deleted. + * + * algorithm: + * The left and right sons of the node to be deleted define two + * subtrees which are to be merged and attached in place of the + * deleted node. Each node on the inside edges of these two + * subtrees is examined and longer nodes are placed above the + * shorter ones. + * + * On entry: + * *p is assumed to be non-null. + */ + +void +delete(Freehdr *p) +{ + Freehdr x; + Freehdr left_branch; /* left subtree of deleted node */ + Freehdr right_branch; /* right subtree of deleted node */ + + x = *p; + left_branch = x->left; + right_branch = x->right; + + while (left_branch != right_branch) { + /* + * iterate until left branch and right branch are + * both NIL. + */ + if (weight(left_branch) >= weight(right_branch)) { + /* + * promote the left branch + */ + *p = left_branch; + p = &left_branch->right; + left_branch = left_branch->right; + } else { + /* + * promote the right branch + */ + *p = right_branch; + p = &right_branch->left; + right_branch = right_branch->left; + } /* else */ + } /* while */ + *p = NIL; + freehdr(x); +} /* delete */ + + +/* + * Demote a node in a cartesian tree, if necessary, to establish + * the required vertical ordering. + * + * algorithm: + * The left and right subtrees of the node to be demoted are to + * be partially merged and attached in place of the demoted node. + * The nodes on the inside edges of these two subtrees are + * examined and the longer nodes are placed above the shorter + * ones, until a node is reached which has a length no greater + * than that of the node being demoted (or until a null pointer + * is reached). The node is then attached at this point, and + * the remaining subtrees (if any) become its descendants. + * + * on entry: + * a. All the nodes in the tree, including the one to be demoted, + * must be correctly ordered horizontally; + * b. All the nodes except the one to be demoted must also be + * correctly positioned vertically. The node to be demoted + * may be already correctly positioned vertically, or it may + * have a length which is less than that of one or both of + * its progeny. + * c. *p is non-null + */ + + +static void +demote(Freehdr *p) +{ + Freehdr x; /* addr of node to be demoted */ + Freehdr left_branch; + Freehdr right_branch; + size_t wx; + + x = *p; + left_branch = x->left; + right_branch = x->right; + wx = weight(x); + + while (weight(left_branch) > wx || weight(right_branch) > wx) { + /* + * select a descendant branch for promotion + */ + if (weight(left_branch) >= weight(right_branch)) { + /* + * promote the left branch + */ + *p = left_branch; + p = &left_branch->right; + left_branch = *p; + } else { + /* + * promote the right branch + */ + *p = right_branch; + p = &right_branch->left; + right_branch = *p; + } /* else */ + } /* while */ + + *p = x; /* attach demoted node here */ + x->left = left_branch; + x->right = right_branch; +} /* demote */ + +/* + * Allocate a block of storage + * + * algorithm: + * The freelist is searched by descending the tree from the root + * so that at each decision point the "better fitting" child node + * is chosen (i.e., the shorter one, if it is long enough, or + * the longer one, otherwise). The descent stops when both + * child nodes are too short. + * + * function result: + * kmem_alloc returns a pointer to the allocated block; a null + * pointer indicates storage could not be allocated. + */ +/* + * We need to return blocks that are on word boundaries so that callers + * that are putting int's into the area will work. Since we allow + * arbitrary free'ing, we need a weight function that considers + * free blocks starting on an odd boundary special. Allocation is + * aligned to 8 byte boundaries (ALIGN). + */ +#define ALIGN 8 /* doubleword aligned .. */ +#define ALIGNMASK (ALIGN-1) +#define ALIGNMORE(addr) (ALIGN - ((uintptr_t)(addr) & ALIGNMASK)) + +/* + * If it is empty then weight == 0 + * If it is aligned then weight == size + * If it is unaligned + * if not enough room to align then weight == 0 + * else weight == aligned size + */ +#define mweight(x) ((x) == NIL ? 0 : \ + ((((uintptr_t)(x)->block) & ALIGNMASK) == 0 ? (x)->size : \ + (((x)->size <= ALIGNMORE((x)->block)) ? 0 : \ + (x)->size - ALIGNMORE((x)->block)))) + +/*ARGSUSED1*/ +void * +kmem_alloc(size_t nbytes, int kmflag) +{ + Freehdr a; /* ptr to node to be allocated */ + Freehdr *p; /* address of ptr to node */ + size_t left_weight; + size_t right_weight; + Freehdr left_son; + Freehdr right_son; + char *retblock; /* Address returned to the user */ + int s; +#ifdef DEBUG + printf("kmem_alloc(nbytes 0x%lx)\n", nbytes); +#endif /* DEBUG */ + + if (nbytes == 0) { + return (NULL); + } + s = splnet(); + + if (nbytes < SMALLEST_BLK) { + printf("illegal kmem_alloc call for %lx bytes\n", nbytes); + prom_panic("kmem_alloc"); + } + check_need_to_free(); + + /* + * ensure that at least one block is big enough to satisfy + * the request. + */ + + if (mweight(kmem_info.free_root) <= nbytes) { + /* + * the largest block is not enough. + */ + if (!morecore(nbytes)) { + printf("kmem_alloc failed, nbytes %lx\n", nbytes); + prom_panic("kmem_alloc"); + } + } + + /* + * search down through the tree until a suitable block is + * found. At each decision point, select the better + * fitting node. + */ + + p = (Freehdr *) &kmem_info.free_root; + a = *p; + left_son = a->left; + right_son = a->right; + left_weight = mweight(left_son); + right_weight = mweight(right_son); + + while (left_weight >= nbytes || right_weight >= nbytes) { + if (left_weight <= right_weight) { + if (left_weight >= nbytes) { + p = &a->left; + a = left_son; + } else { + p = &a->right; + a = right_son; + } + } else { + if (right_weight >= nbytes) { + p = &a->right; + a = right_son; + } else { + p = &a->left; + a = left_son; + } + } + left_son = a->left; + right_son = a->right; + left_weight = mweight(left_son); + right_weight = mweight(right_son); + } /* while */ + + /* + * allocate storage from the selected node. + */ + + if (a->size - nbytes < SMALLEST_BLK) { + /* + * not big enough to split; must leave at least + * a dblk's worth of space. + */ + retblock = a->block->data; + delete(p); + } else { + + /* + * split the node, allocating nbytes from the top. + * Remember we've already accounted for the + * allocated node's header space. + */ + Freehdr x; + x = getfreehdr(); + if ((uintptr_t)a->block->data & ALIGNMASK) { + size_t size; + if (a->size <= ALIGNMORE(a->block->data)) + prom_panic("kmem_alloc: short block allocated"); + size = nbytes + ALIGNMORE(a->block->data); + x->block = a->block; + x->size = ALIGNMORE(a->block->data); + x->left = a->left; + x->right = a->right; + /* + * the node pointed to by *p has become smaller; + * move it down to its appropriate place in + * the tree. + */ + *p = x; + demote(p); + retblock = a->block->data + ALIGNMORE(a->block->data); + if (a->size > size) { + kmem_free((caddr_t)nextblk(a->block, size), + (size_t)(a->size - size)); + } + freehdr(a); + } else { + x->block = nextblk(a->block, nbytes); + x->size = a->size - nbytes; + x->left = a->left; + x->right = a->right; + /* + * the node pointed to by *p has become smaller; + * move it down to its appropriate place in + * the tree. + */ + *p = x; + demote(p); + retblock = a->block->data; + freehdr(a); + } + } +#ifdef DEBUG + prtree(kmem_info.free_root, "kmem_alloc"); +#endif + + splx(s); + bzero(retblock, nbytes); +#ifdef DEBUG + printf("kmem_alloc bzero complete - returning %p\n", retblock); +#endif + return (retblock); + +} /* kmem_alloc */ + +/* + * Return a block to the free space tree. + * + * algorithm: + * Starting at the root, search for and coalesce free blocks + * adjacent to one given. When the appropriate place in the + * tree is found, insert the given block. + * + * Do some sanity checks to avoid total confusion in the tree. + * If the block has already been freed, prom_panic. + * If the ptr is not from the arena, prom_panic. + */ +void +kmem_free(void *ptr, size_t nbytes) +{ + Freehdr *np; /* For deletion from free list */ + Freehdr neighbor; /* Node to be coalesced */ + char *neigh_block; /* Ptr to potential neighbor */ + size_t neigh_size; /* Size of potential neighbor */ + int s; + +#ifdef DEBUG +printf("kmem_free (ptr %p nbytes %lx)\n", ptr, nbytes); +prtree(kmem_info.free_root, "kmem_free"); +#endif + +#ifdef lint + neigh_block = bkmem_zalloc(nbytes); + neigh_block = neigh_block; +#endif + if (nbytes == 0) { + return; + } + + if (ptr == 0) { + prom_panic("kmem_free of 0"); + } + s = splnet(); + + /* + * Search the tree for the correct insertion point for this + * node, coalescing adjacent free blocks along the way. + */ + np = &kmem_info.free_root; + neighbor = *np; + while (neighbor != NIL) { + neigh_block = (char *)neighbor->block; + neigh_size = neighbor->size; + if ((char *)ptr < neigh_block) { + if ((char *)ptr + nbytes == neigh_block) { + /* + * Absorb and delete right neighbor + */ + nbytes += neigh_size; + delete(np); + } else if ((char *)ptr + nbytes > neigh_block) { + /* + * The block being freed overlaps + * another block in the tree. This + * is bad news. + */ + printf("kmem_free: free block overlap %p+%lx" + " over %p\n", (void *)ptr, nbytes, + (void *)neigh_block); + prom_panic("kmem_free: free block overlap"); + } else { + /* + * Search to the left + */ + np = &neighbor->left; + } + } else if ((char *)ptr > neigh_block) { + if (neigh_block + neigh_size == ptr) { + /* + * Absorb and delete left neighbor + */ + ptr = neigh_block; + nbytes += neigh_size; + delete(np); + } else if (neigh_block + neigh_size > (char *)ptr) { + /* + * This block has already been freed + */ + prom_panic("kmem_free block already free"); + } else { + /* + * search to the right + */ + np = &neighbor->right; + } + } else { + /* + * This block has already been freed + * as "ptr == neigh_block" + */ + prom_panic("kmem_free: block already free as neighbor"); + return; + } /* else */ + neighbor = *np; + } /* while */ + + /* + * Insert the new node into the free space tree + */ + insert((Dblk) ptr, nbytes, &kmem_info.free_root); +#ifdef DEBUG +printf("exiting kmem_free\n"); +prtree(kmem_info.free_root, "kmem_free"); +#endif + splx(s); +} /* kmem_free */ + +/* + * Sigh. We include a header file which the kernel + * uses to declare (one of its many) kmem_free prototypes. + * In order not to use the kernel's namespace, then, we must + * define another name here for use by boot. + */ +void * +bkmem_alloc(size_t size) +{ + return (kmem_alloc(size, 0)); +} + +/* + * Boot's kmem_alloc is really kmem_zalloc(). + */ +void * +bkmem_zalloc(size_t size) +{ + return (kmem_alloc(size, 0)); +} + +void +bkmem_free(void *p, size_t bytes) +{ + kmem_free(p, bytes); +} + +static void +check_need_to_free(void) +{ + int i; + struct need_to_free *ntf; + caddr_t addr; + size_t nbytes; + int s; + +again: + s = splimp(); + ntf = &kmem_info.need_to_free_list; + if (ntf->addr) { + addr = ntf->addr; + nbytes = ntf->nbytes; + *ntf = *(struct need_to_free *)ntf->addr; + splx(s); + kmem_free(addr, nbytes); + goto again; + } + ntf = kmem_info.need_to_free; + for (i = 0; i < NEED_TO_FREE_SIZE; i++) { + if (ntf[i].addr) { + addr = ntf[i].addr; + nbytes = ntf[i].nbytes; + ntf[i].addr = 0; + splx(s); + kmem_free(addr, nbytes); + goto again; + } + } + splx(s); +} + +/* + * Add a block of at least nbytes to the free space tree. + * + * return value: + * true if at least nbytes can be allocated + * false otherwise + * + * remark: + * free space (delimited by the static variable ubound) is + * extended by an amount determined by rounding nbytes up to + * a multiple of the system page size. + */ + +static bool +morecore(size_t nbytes) +{ +#ifdef __sparc + enum RESOURCES type = RES_BOOTSCRATCH_NOFAIL; +#else + enum RESOURCES type = RES_BOOTSCRATCH; +#endif + Dblk p; +#ifdef DEBUG + printf("morecore(nbytes 0x%lx)\n", nbytes); +#endif /* DEBUG */ + + + nbytes = roundup(nbytes, PAGESIZE); + p = (Dblk) resalloc(type, nbytes, (caddr_t)0, 0); + if (p == 0) { + return (false); + } + kmem_free((caddr_t)p, nbytes); +#ifdef DEBUG + printf("morecore() returing, p = %p\n", p); +#endif + return (true); + +} /* morecore */ + +/* + * Get a free block header + * There is a list of available free block headers. + * When the list is empty, allocate another pagefull. + */ +Freehdr +getfreehdr(void) +{ + Freehdr r; + int n = 0; +#ifdef DEBUG + printf("getfreehdr()\n"); +#endif /* DEBUG */ + + if (kmem_info.free_hdr_list != NIL) { + r = kmem_info.free_hdr_list; + kmem_info.free_hdr_list = kmem_info.free_hdr_list->left; + } else { + r = (Freehdr)resalloc(RES_BOOTSCRATCH, PAGESIZE, (caddr_t)0, 0); + if (r == 0) { + prom_panic("getfreehdr"); + } + for (n = 1; n < PAGESIZE / sizeof (*r); n++) { + freehdr(&r[n]); + } + } +#ifdef DEBUG + printf("getfreehdr: freed %x headers\n", n); + printf("getfreehdr: returning %p\n", r); +#endif /* DEBUG */ + return (r); +} + +/* + * Free a free block header + * Add it to the list of available headers. + */ + +void +freehdr(Freehdr p) +{ +#ifdef DEBUG + printf("freehdr(%p)\n", p); +#endif /* DEBUG */ + p->left = kmem_info.free_hdr_list; + p->right = NIL; + p->block = NULL; + kmem_info.free_hdr_list = p; +} + +#ifdef DEBUG +/* + * Diagnostic routines + */ +static int depth = 0; + +static void +prtree(Freehdr p, char *cp) +{ + int n; + if (depth == 0) { + printf("prtree(p %p cp %s)\n", p, cp); + } + if (p != NIL) { + depth++; + prtree(p->left, (char *)NULL); + depth--; + + for (n = 0; n < depth; n++) { + printf(" "); + } + printf( + "(%p): (left = %p, right = %p, block = %p, size = %lx)\n", + p, p->left, p->right, p->block, p->size); + + depth++; + prtree(p->right, (char *)NULL); + depth--; + } +} +#endif /* DEBUG */ diff --git a/usr/src/psm/stand/boot/common/readfile.c b/usr/src/psm/stand/boot/common/readfile.c new file mode 100644 index 0000000000..3cd0f8279f --- /dev/null +++ b/usr/src/psm/stand/boot/common/readfile.c @@ -0,0 +1,1571 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/sysmacros.h> +#include <sys/types.h> +#include <sys/exechdr.h> +#include <sys/elf.h> +#include <sys/elf_notes.h> +#include <sys/bootconf.h> +#include <sys/reboot.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/modctl.h> +#include <sys/link.h> +#include <sys/auxv.h> +#include <sys/salib.h> +#include <sys/bootvfs.h> +#include <sys/platnames.h> + +#ifdef BOOTAMD64 +#include <amd64/amd64_page.h> +#endif /* BOOTAMD64 */ + +union { + struct exec X; + Elf32_Ehdr Elfhdr; + Elf64_Ehdr Elfhdr64; +} ex; + +#define x ex.X +#define elfhdr ex.Elfhdr +#define elfhdr64 ex.Elfhdr64 + +typedef int (*func_t)(); + +#define FAIL ((func_t)-1) +#define ALIGN(x, a) \ + ((a) == 0 ? (uintptr_t)(x) : (((uintptr_t)(x) + (a) - 1) & ~((a) - 1))) + +#define __BOOT_NAUXV_IMPL 22 + +int use_align = 0; +int npagesize = 0; +uint_t icache_flush = 0; +char *cpulist = NULL; +char *mmulist = NULL; +char *module_path; /* path for kernel modules */ + +/* + * This file gets compiled in LP64 (for sun4u) and ILP32 models. + * For LP64 compilation, the "client" file we load and run may be LP64 or ILP32, + * and during bringup, the LP64 clients may have ELF32 headers. + */ +#ifdef _ELF64_SUPPORT +#ifndef BOOTAMD64 +/* + * Bootstrap vector for ELF32 LP64 client - neither supported nor needed for + * AMD64 + */ +Elf32_Boot *elfbootvecELF32_64; +#endif /* !BOOTAMD64 */ + +Elf64_Boot *elfbootvecELF64; /* ELF bootstrap vector for Elf64 LP64 */ + +#define OK ((func_t)0) + +#define FAIL_READELF64 ((uint64_t)0) +#define FAIL_ILOAD64 ((Elf64_Addr)-1) +#endif /* _ELF64_SUPPORT */ + +/* + * And by an ILP32 client. The non-sun4u/LP64 booters use these. + * Also, the sun4u booter must create this for ILP32 clients. + */ +Elf32_Boot *elfbootvec; /* ELF bootstrap vector normal ILP32 */ + +/* + * Read in a Unix executable file and return its entry point. + * Handle the various a.out formats correctly. + * "fd" is the standalone file descriptor to read from. + * Print informative little messages if "print" is on. + * Returns -1 for errors. + */ + +#ifdef DEBUG +static int debug = 1; +#else /* DEBUG */ +static int debug = 0; +#endif /* DEBUG */ + +#define dprintf if (debug) printf + +#ifdef _ELF64_SUPPORT +typedef struct { + uint_t a_type; +#ifdef BOOTAMD64 + uint_t a_pad; /* needed to 8-byte align uint64_ts below for AMD64 */ +#endif /* BOOTAMD64 */ + union { + uint64_t a_val; + uint64_t a_ptr; +#ifndef BOOTAMD64 + void (*a_fcn)(); /* XXX - UNUSED? */ +#endif /* !BOOTAMD64 */ + } a_un; +} auxv64_t; + +#if defined(__sparcv9) || defined(__ia64) +extern int client_isLP64; +#endif /* __sparcv9 || __ia64 */ + +static uint64_t read_elf64(int, int, Elf64_Ehdr *); +static Elf64_Addr iload64(char *, Elf64_Phdr *, Elf64_Phdr *, auxv64_t **); +#endif /* _ELF64_SUPPORT */ + +#if defined(i386) && !defined(_SYSCALL32) +typedef auxv_t auxv32_t; +#endif + +static func_t read_elf32(int, int, Elf32_Ehdr *); +static func_t iload32(char *, Elf32_Phdr *, Elf32_Phdr *, auxv32_t **); +static caddr_t segbrk(caddr_t *, size_t, size_t); +static int openpath(char *, char *, int); +static char *getmodpath(char *); +extern void setup_aux(void); + +extern void *kmem_alloc(size_t, int); +extern void kmem_free(void *, size_t); +extern int cons_gets(char *, int); + +#ifdef BOOTAMD64 +extern const char *amd64_getmmulist(void); + +extern int amd64_elf64; +extern int is_amd64; +#endif /* BOOTAMD64 */ + +#ifdef lint +/* + * This function is currently inlined + */ +/*ARGSUSED*/ +void +sync_instruction_memory(caddr_t v, size_t len) +{} +#else /* lint */ +extern void sync_instruction_memory(caddr_t v, size_t len); +#endif /* lint */ + + +extern int verbosemode; +extern int boothowto; +extern int pagesize; +extern char filename[]; + +#ifdef MPSAS +extern void sas_symtab(int start, int end); +#endif + +/* + * repeat reads (forever) until size of request is satisfied + * (Thus, you don't want to use this cases where short reads are ok) + */ +static ssize_t +xread(int fd, char *p, size_t nbytes) +{ + size_t bytesread = 0; + int errorcount = 0; + ssize_t i; + + while (bytesread < nbytes) { + i = read(fd, p, nbytes - bytesread); + if (i < 0) { + ++errorcount; + if (verbosemode) + printf("read error (0x%x times)\n", errorcount); + continue; + } + bytesread += i; + p += i; + } + return (bytesread); +} + +func_t +readfile(int fd, int print) +{ +#ifdef _ELF64_SUPPORT +#ifdef BOOTAMD64 + extern int bsetprop(struct bootops *, char *, caddr_t, int, phandle_t); + extern struct bootops *bop; + extern uint64_t elf64_go2; +#else /* !BOOTAMD64 */ + uint64_t elf64_go2; +#endif /* BOOTAMD64 */ +#endif /* _ELF64_SUPPORT */ + + ssize_t i; + int shared = 0; + + if (verbosemode) { + dprintf("fd = %x\n", fd); + } + + i = xread(fd, (char *)&elfhdr, sizeof (Elf64_Ehdr)); + if (x.a_magic == ZMAGIC || x.a_magic == NMAGIC) + shared = 1; + if (i != sizeof (Elf64_Ehdr)) { + printf("Error reading ELF header.\n"); + return (FAIL); + } + if (!shared && x.a_magic != OMAGIC) { + if (*(int *)&elfhdr.e_ident == *(int *)(ELFMAG)) { + if (verbosemode) { + int is64 = (elfhdr.e_ident[EI_CLASS] == + ELFCLASS64); + + dprintf("calling readelf, elfheader is:\n"); + dprintf("e_ident\t0x%x, 0x%x, 0x%x, 0x%x\n", + *(int *)&elfhdr.e_ident[0], + *(int *)&elfhdr.e_ident[4], + *(int *)&elfhdr.e_ident[8], + *(int *)&elfhdr.e_ident[12]); + dprintf("e_machine\t0x%x\n", elfhdr.e_machine); + + dprintf("e_entry\t\t0x%llx\n", (is64 ? + elfhdr64.e_entry : + (u_longlong_t)elfhdr.e_entry)); + dprintf("e_shoff\t\t0x%llx\n", (is64 ? + elfhdr64.e_shoff : + (u_longlong_t)elfhdr.e_shoff)); + dprintf("e_shnentsize\t%d\n", (is64 ? + elfhdr64.e_shentsize : elfhdr.e_shentsize)); + dprintf("e_shnum\t\t%d\n", (is64 ? + elfhdr64.e_shnum : elfhdr.e_shnum)); + dprintf("e_shstrndx\t%d\n", (is64 ? + elfhdr64.e_shstrndx : elfhdr.e_shstrndx)); + } + + +#ifdef _ELF64_SUPPORT + dprintf("ELF file CLASS 0x%x 32 is %x 64 is %x\n", + elfhdr.e_ident[EI_CLASS], ELFCLASS32, ELFCLASS64); + + if (elfhdr.e_ident[EI_CLASS] == ELFCLASS64) { +#ifdef BOOTAMD64 + if (elfhdr.e_machine != EM_AMD64) { + printf("FATAL: 64-bit ELF executable " + "not for AMD64\n (e_machine " + "= %d).\n", elfhdr.e_machine); + return (FAIL); + } + + /* + * OK, we know the executable is for an AMD64 + * CPU. Make sure we ARE an AMD64 CPU before + * proceeding. + */ + if (is_amd64 == 0) { + printf("FATAL: AMD64 executables not " + " supported on this CPU.\n"); + return (FAIL); + } + + amd64_elf64 = (elfhdr.e_ident[EI_CLASS] == + ELFCLASS64); +#endif /* BOOTAMD64 */ + + elf64_go2 = read_elf64(fd, print, + (Elf64_Ehdr *)&elfhdr); + +#ifdef BOOTAMD64 + if (elf64_go2 != FAIL_READELF64) + (void) bsetprop(bop, "mmu-modlist", + "mmu64", 0, 0); + + return ((elf64_go2 == FAIL_READELF64) ? FAIL : + OK); +#else /* !BOOTAMD64 */ + return ((elf64_go2 == FAIL_READELF64) ? FAIL : + (func_t)elf64_go2); +#endif /* BOOTAMD64 */ + + } else +#endif /* _ELF64_SUPPORT */ + return (read_elf32(fd, print, &elfhdr)); + } else { + printf("File not executable.\n"); + return (FAIL); + } + } + return (FAIL); +} + +/* + * Macros to add attribute/values + * to the ELF bootstrap vector + * and the aux vector. + */ +#define AUX(p, a, v) { (p)->a_type = (a); \ + ((p)++)->a_un.a_val = (int32_t)(v); } + +#define EBV(p, a, v) { (p)->eb_tag = (a); \ + ((p)++)->eb_un.eb_val = (Elf32_Word)(v); } + +static func_t +read_elf32(int fd, int print, Elf32_Ehdr *elfhdrp) +{ + Elf32_Phdr *phdr; /* program header */ + Elf32_Nhdr *nhdr; /* note header */ + int nphdrs, phdrsize; + caddr_t allphdrs; + caddr_t namep, descp; + Elf32_Addr loadaddr, base; + size_t offset = 0; + size_t size; + uintptr_t off; + int i; + int bss_seen = 0; + int interp = 0; /* interpreter required */ + static char dlname[MAXPATHLEN]; /* name of interpeter */ + uint_t dynamic; /* dynamic tags array */ + Elf32_Phdr *thdr; /* "text" program header */ + Elf32_Phdr *dhdr; /* "data" program header */ + func_t entrypt; /* entry point of standalone */ + + /* Initialize pointers so we won't free bogus ones on elferror */ + allphdrs = NULL; + nhdr = NULL; + +#ifdef _ELF64_SUPPORT + if (verbosemode) + printf("Elf32 client\n"); +#endif /* _ELF64_SUPPORT */ + + if (elfhdrp->e_phnum == 0 || elfhdrp->e_phoff == 0) + goto elferror; + + entrypt = (func_t)elfhdrp->e_entry; + if (verbosemode) + dprintf("Entry point: %p\n", (void *)entrypt); + + /* + * Allocate and read in all the program headers. + */ + nphdrs = elfhdrp->e_phnum; + phdrsize = nphdrs * elfhdrp->e_phentsize; + allphdrs = (caddr_t)kmem_alloc(phdrsize, 0); + if (allphdrs == NULL) + goto elferror; + if (verbosemode) + dprintf("lseek: args = %x %x %x\n", fd, elfhdrp->e_phoff, 0); + if (lseek(fd, elfhdrp->e_phoff, 0) == -1) + goto elferror; + if (xread(fd, allphdrs, phdrsize) != phdrsize) + goto elferror; + + /* + * First look for PT_NOTE headers that tell us what pagesize to + * use in allocating program memory. + */ + npagesize = 0; + for (i = 0; i < nphdrs; i++) { + void *note_buf; + + phdr = (Elf32_Phdr *)(allphdrs + elfhdrp->e_phentsize * i); + if (phdr->p_type != PT_NOTE) + continue; + if (verbosemode) { + dprintf("allocating 0x%x bytes for note hdr\n", + phdr->p_filesz); + } + if ((note_buf = kmem_alloc(phdr->p_filesz, 0)) == NULL) + goto elferror; + if (verbosemode) + dprintf("seeking to 0x%x\n", phdr->p_offset); + if (lseek(fd, phdr->p_offset, 0) == -1) + goto elferror; + if (verbosemode) { + dprintf("reading 0x%x bytes into %p\n", + phdr->p_filesz, (void *)nhdr); + } + nhdr = (Elf32_Nhdr *)note_buf; + if (xread(fd, (caddr_t)nhdr, phdr->p_filesz) != phdr->p_filesz) + goto elferror; + if (verbosemode) { + dprintf("p_note namesz %x descsz %x type %x\n", + nhdr->n_namesz, nhdr->n_descsz, nhdr->n_type); + } + + /* + * Iterate through all ELF PT_NOTE elements looking for + * ELF_NOTE_SOLARIS which, if present, will specify the + * executable's preferred pagesize. + */ + do { + namep = (caddr_t)(nhdr + 1); + + if (nhdr->n_namesz == strlen(ELF_NOTE_SOLARIS) + 1 && + strcmp(namep, ELF_NOTE_SOLARIS) == 0 && + nhdr->n_type == ELF_NOTE_PAGESIZE_HINT) { + descp = namep + roundup(nhdr->n_namesz, 4); + npagesize = *(int *)descp; + if (verbosemode) + dprintf("pagesize is %x\n", npagesize); + } + + offset += sizeof (Elf32_Nhdr) + roundup(nhdr->n_namesz, + 4) + roundup(nhdr->n_descsz, 4); + + nhdr = (Elf32_Nhdr *)((char *)note_buf + offset); + } while (offset < phdr->p_filesz); + + kmem_free(note_buf, phdr->p_filesz); + nhdr = NULL; + } + + /* + * Next look for PT_LOAD headers to read in. + */ + if (print) + printf("Size: "); + for (i = 0; i < nphdrs; i++) { + phdr = (Elf32_Phdr *)(allphdrs + elfhdrp->e_phentsize * i); + if (verbosemode) { + dprintf("Doing header 0x%x\n", i); + dprintf("phdr\n"); + dprintf("\tp_offset = %x, p_vaddr = %x\n", + phdr->p_offset, phdr->p_vaddr); + dprintf("\tp_memsz = %x, p_filesz = %x\n", + phdr->p_memsz, phdr->p_filesz); + } + if (phdr->p_type == PT_LOAD) { + if (verbosemode) + dprintf("seeking to 0x%x\n", phdr->p_offset); + if (lseek(fd, phdr->p_offset, 0) == -1) + goto elferror; + + if (phdr->p_flags == (PF_R | PF_W) && + phdr->p_vaddr == 0) { + /* + * It's a PT_LOAD segment that is RW but + * not executable and has a vaddr + * of zero. This is relocation info that + * doesn't need to stick around after + * krtld is done with it. We allocate boot + * memory for this segment, since we don't want + * it mapped in permanently as part of + * the kernel image. + */ + if ((loadaddr = (uintptr_t) + kmem_alloc(phdr->p_memsz, 0)) == NULL) + goto elferror; + /* + * Save this to pass on + * to the interpreter. + */ + phdr->p_vaddr = (Elf32_Addr)loadaddr; + } else { + if (print) + printf("0x%x+", phdr->p_filesz); + /* + * If we found a new pagesize above, use it + * to adjust the memory allocation. + */ + loadaddr = phdr->p_vaddr; + if (use_align && npagesize != 0) { + off = loadaddr & (npagesize - 1); + size = roundup(phdr->p_memsz + off, + npagesize); + base = loadaddr - off; + } else { + npagesize = 0; + size = phdr->p_memsz; + base = loadaddr; + } + /* + * Check if it's text or data. + */ + if (phdr->p_flags & PF_W) + dhdr = phdr; + else + thdr = phdr; + + /* + * If memory size is zero just ignore this + * header. + */ + if (size == 0) + continue; + + if (verbosemode) + dprintf("allocating memory: %x %lx " + "%x\n", base, size, npagesize); + /* + * We're all set up to read. + * Now let's allocate some memory. + */ + +#ifdef i386 + /* + * If vaddr == paddr and npagesize is 0, that + * means the executable needs to be identity + * mapped in memory (va == pa, mapped 1:1) + * + * Otherwise load as usual. + */ + if ((phdr->p_vaddr == phdr->p_paddr) && + (npagesize == 0)) { + extern caddr_t idmap_mem(uint32_t, + size_t, int); + + uint_t n; + + n = (uint_t)base & (pagesize - 1); + if (n) { + base -= n; + size += n; + } + + if (!idmap_mem((uint32_t)base, + (size_t)size, pagesize)) + goto elferror; + } else +#endif /* i386 */ + if (get_progmemory((caddr_t)base, size, + npagesize)) + goto elferror; + } + + if (verbosemode) { + dprintf("reading 0x%x bytes into 0x%x\n", + phdr->p_filesz, loadaddr); + } + if (xread(fd, (caddr_t)loadaddr, phdr->p_filesz) != + phdr->p_filesz) + goto elferror; + + /* zero out BSS */ + if (phdr->p_memsz > phdr->p_filesz) { + loadaddr += phdr->p_filesz; + if (verbosemode) { + dprintf("bss from 0x%x size 0x%x\n", + loadaddr, + phdr->p_memsz - phdr->p_filesz); + } + + bzero((void *)loadaddr, + phdr->p_memsz - phdr->p_filesz); + bss_seen++; + if (print) + printf("0x%x Bytes\n", + phdr->p_memsz - phdr->p_filesz); + } + + /* force instructions to be visible to icache */ + if (phdr->p_flags & PF_X) + sync_instruction_memory((caddr_t)phdr->p_vaddr, + phdr->p_memsz); + +#ifdef MPSAS + sas_symtab(phdr->p_vaddr, + phdr->p_vaddr + phdr->p_memsz); +#endif + } else if (phdr->p_type == PT_INTERP) { + /* + * Dynamically-linked executable. + */ + interp = 1; + if (lseek(fd, phdr->p_offset, 0) == -1) { + goto elferror; + } + /* + * Get the name of the interpreter. + */ + if (xread(fd, dlname, phdr->p_filesz) != + phdr->p_filesz || + dlname[phdr->p_filesz - 1] != '\0') + goto elferror; + } else if (phdr->p_type == PT_DYNAMIC) { + dynamic = phdr->p_vaddr; + } + } + + if (!bss_seen && print) + printf("0 Bytes\n"); + + /* + * Load the interpreter + * if there is one. + */ + if (interp) { + Elf32_Boot bootv[EB_MAX]; /* Bootstrap vector */ + auxv32_t auxv[__BOOT_NAUXV_IMPL]; /* Aux vector */ + Elf32_Boot *bv = bootv; + auxv32_t *av = auxv; + size_t vsize; + + /* + * Load it. + */ + if ((entrypt = iload32(dlname, thdr, dhdr, &av)) == FAIL) + goto elferror; + /* + * Build bootstrap and aux vectors. + */ + setup_aux(); + EBV(bv, EB_AUXV, 0); /* fill in later */ + EBV(bv, EB_PAGESIZE, pagesize); + EBV(bv, EB_DYNAMIC, dynamic); + EBV(bv, EB_NULL, 0); + + AUX(av, AT_BASE, entrypt); + AUX(av, AT_ENTRY, elfhdrp->e_entry); + AUX(av, AT_PAGESZ, pagesize); + AUX(av, AT_PHDR, allphdrs); + AUX(av, AT_PHNUM, elfhdrp->e_phnum); + AUX(av, AT_PHENT, elfhdrp->e_phentsize); + if (use_align) + AUX(av, AT_SUN_LPAGESZ, npagesize); + AUX(av, AT_SUN_IFLUSH, icache_flush); + if (cpulist != NULL) + AUX(av, AT_SUN_CPU, cpulist); + if (mmulist != NULL) + AUX(av, AT_SUN_MMU, mmulist); + AUX(av, AT_NULL, 0); + /* + * Realloc vectors and copy them. + */ + vsize = (caddr_t)bv - (caddr_t)bootv; + if ((elfbootvec = (Elf32_Boot *)kmem_alloc(vsize, 0)) == NULL) + goto elferror; + bcopy((char *)bootv, (char *)elfbootvec, vsize); + + size = (caddr_t)av - (caddr_t)auxv; + if (size > sizeof (auxv)) { + printf("readelf: overrun of available aux vectors\n"); + kmem_free(elfbootvec, vsize); + goto elferror; + } + if ((elfbootvec->eb_un.eb_ptr = + (Elf32_Addr)kmem_alloc(size, 0)) == NULL) { + kmem_free(elfbootvec, vsize); + goto elferror; + } + bcopy(auxv, (void *)(elfbootvec->eb_un.eb_ptr), size); + +#if defined(_ELF64_SUPPORT) && !defined(BOOTAMD64) + /* + * Make an LP64 copy of the vector for use by 64-bit standalones + * even if they have ELF32. + */ + if ((elfbootvecELF32_64 = (Elf32_Boot *)kmem_alloc(vsize, 0)) + == NULL) + goto elferror; + bcopy(bootv, elfbootvecELF32_64, vsize); + + size = (av - auxv) * sizeof (auxv64_t); + if ((elfbootvecELF32_64->eb_un.eb_ptr = + (Elf32_Addr)kmem_alloc(size, 0)) == NULL) { + kmem_free(elfbootvecELF32_64, vsize); + goto elferror; + } else { + auxv64_t *a64 = + (auxv64_t *)elfbootvecELF32_64->eb_un.eb_ptr; + auxv32_t *a = auxv; + + for (a = auxv; a < av; a++) { + a64->a_type = a->a_type; + a64->a_un.a_val = a->a_un.a_val; + a64++; + } + } +#endif /* _ELF64_SUPPORT && !BOOTAMD64 */ + } else { + kmem_free(allphdrs, phdrsize); + } + return (entrypt); + +elferror: + if (allphdrs != NULL) + kmem_free(allphdrs, phdrsize); + if (nhdr != NULL) + kmem_free(nhdr, phdr->p_filesz); + printf("Elf32 read error.\n"); + return (FAIL); +} + +#ifdef _ELF64_SUPPORT +/* + * Macros to add attribute/values to the ELF bootstrap vector + * and the aux vector. + */ +#define AUX64(p, a, v) { (p)->a_type = (a); \ + ((p)++)->a_un.a_val = (uint64_t)(v); } + +#define EBV64(p, a, v) { (p)->eb_tag = (a); \ + ((p)++)->eb_un.eb_val = (Elf64_Xword)(v); } + +static uint64_t +read_elf64(int fd, int print, Elf64_Ehdr *elfhdrp) +{ + Elf64_Phdr *phdr; /* program header */ + Elf64_Nhdr *nhdr; /* note header */ + int nphdrs, phdrsize; + caddr_t allphdrs; + caddr_t namep, descp; + Elf64_Addr loadaddr, base; + size_t offset = 0; + size_t size; + int i; + uintptr_t off; + int bss_seen = 0; + int interp = 0; /* interpreter required */ + static char dlname[MAXPATHLEN]; /* name of interpeter */ + uintptr_t dynamic; /* dynamic tags array */ + Elf64_Phdr *thdr; /* "text" program header */ + Elf64_Phdr *dhdr; /* "data" program header */ + Elf64_Addr entrypt; /* entry point of standalone */ + + /* Initialize pointers so we won't free bogus ones on elf64error */ + allphdrs = NULL; + nhdr = NULL; +#if defined(__sparcv9) || defined(__ia64) + client_isLP64 = 1; +#endif /* __sparcv9 || __ia64 */ + + if (verbosemode) + printf("Elf64 client\n"); + + if (elfhdrp->e_phnum == 0 || elfhdrp->e_phoff == 0) + goto elf64error; + + entrypt = elfhdrp->e_entry; + if (verbosemode) + dprintf("Entry point: 0x%llx\n", (u_longlong_t)entrypt); + + /* + * Allocate and read in all the program headers. + */ + nphdrs = elfhdrp->e_phnum; + phdrsize = nphdrs * elfhdrp->e_phentsize; + allphdrs = (caddr_t)kmem_alloc(phdrsize, 0); + if (allphdrs == NULL) + goto elf64error; + if (verbosemode) + dprintf("lseek: args = %x %llx %x\n", fd, + (u_longlong_t)elfhdrp->e_phoff, 0); + if (lseek(fd, elfhdrp->e_phoff, 0) == -1) + goto elf64error; + if (xread(fd, allphdrs, phdrsize) != phdrsize) + goto elf64error; + + /* + * First look for PT_NOTE headers that tell us what pagesize to + * use in allocating program memory. + */ + npagesize = 0; + for (i = 0; i < nphdrs; i++) { + void *note_buf; + + phdr = (Elf64_Phdr *)(allphdrs + elfhdrp->e_phentsize * i); + if (phdr->p_type != PT_NOTE) + continue; + if (verbosemode) { + dprintf("allocating 0x%llx bytes for note hdr\n", + (u_longlong_t)phdr->p_filesz); + } + if ((note_buf = kmem_alloc(phdr->p_filesz, 0)) == NULL) + goto elf64error; + if (verbosemode) + dprintf("seeking to 0x%llx\n", + (u_longlong_t)phdr->p_offset); + if (lseek(fd, phdr->p_offset, 0) == -1) + goto elf64error; + if (verbosemode) { + dprintf("reading 0x%llx bytes into 0x%p\n", + (u_longlong_t)phdr->p_filesz, (void *)nhdr); + } + nhdr = (Elf64_Nhdr *)note_buf; + if (xread(fd, (caddr_t)nhdr, phdr->p_filesz) != phdr->p_filesz) + goto elf64error; + if (verbosemode) { + dprintf("p_note namesz %x descsz %x type %x\n", + nhdr->n_namesz, nhdr->n_descsz, nhdr->n_type); + } + + /* + * Iterate through all ELF PT_NOTE elements looking for + * ELF_NOTE_SOLARIS which, if present, will specify the + * executable's preferred pagesize. + */ + do { + namep = (caddr_t)(nhdr + 1); + + if (nhdr->n_namesz == strlen(ELF_NOTE_SOLARIS) + 1 && + strcmp(namep, ELF_NOTE_SOLARIS) == 0 && + nhdr->n_type == ELF_NOTE_PAGESIZE_HINT) { + descp = namep + roundup(nhdr->n_namesz, 4); + npagesize = *(int *)descp; + if (verbosemode) + dprintf("pagesize is %x\n", npagesize); + } + + offset += sizeof (Elf64_Nhdr) + roundup(nhdr->n_namesz, + 4) + roundup(nhdr->n_descsz, 4); + + nhdr = (Elf64_Nhdr *)((char *)note_buf + offset); + } while (offset < phdr->p_filesz); + + kmem_free(note_buf, phdr->p_filesz); + nhdr = NULL; + } + + /* + * Next look for PT_LOAD headers to read in. + */ + if (print) + printf("Size: "); + for (i = 0; i < nphdrs; i++) { + phdr = (Elf64_Phdr *)(allphdrs + elfhdrp->e_phentsize * i); + if (verbosemode) { + dprintf("Doing header 0x%x\n", i); + dprintf("phdr\n"); + dprintf("\tp_offset = %llx, p_vaddr = %llx\n", + (u_longlong_t)phdr->p_offset, + (u_longlong_t)phdr->p_vaddr); + dprintf("\tp_memsz = %llx, p_filesz = %llx\n", + (u_longlong_t)phdr->p_memsz, + (u_longlong_t)phdr->p_filesz); + dprintf("\tp_type = %x, p_flags = %x\n", + phdr->p_type, phdr->p_flags); + } + if (phdr->p_type == PT_LOAD) { + if (verbosemode) + dprintf("seeking to 0x%llx\n", + (u_longlong_t)phdr->p_offset); + if (lseek(fd, phdr->p_offset, 0) == -1) + goto elf64error; + + if (phdr->p_flags == (PF_R | PF_W) && + phdr->p_vaddr == 0) { + /* + * It's a PT_LOAD segment that is RW but + * not executable and has a vaddr + * of zero. This is relocation info that + * doesn't need to stick around after + * krtld is done with it. We allocate boot + * memory for this segment, since we don't want + * it mapped in permanently as part of + * the kernel image. + */ +#ifdef BOOTAMD64 + if ((loadaddr = (Elf64_Addr) + (ADDR_XTND(kmem_alloc(phdr->p_memsz, 0)))) + == NULL) +#else /* !BOOTAMD64 */ + if ((loadaddr = (Elf64_Addr)(uintptr_t) + kmem_alloc(phdr->p_memsz, 0)) == NULL) +#endif /* BOOTAMD64 */ + goto elf64error; + + /* + * Save this to pass on + * to the interpreter. + */ + phdr->p_vaddr = loadaddr; + } else { + if (print) + printf("0x%llx+", + (u_longlong_t)phdr->p_filesz); + /* + * If we found a new pagesize above, use it + * to adjust the memory allocation. + */ + loadaddr = phdr->p_vaddr; + if (use_align && npagesize != 0) { + off = loadaddr & (npagesize - 1); + size = roundup(phdr->p_memsz + off, + npagesize); + base = loadaddr - off; + } else { + npagesize = 0; + size = phdr->p_memsz; + base = loadaddr; + } + /* + * Check if it's text or data. + */ + if (phdr->p_flags & PF_W) + dhdr = phdr; + else + thdr = phdr; + + if (verbosemode) + dprintf( + "allocating memory: %llx %lx %x\n", + (u_longlong_t)base, + size, npagesize); + + /* + * If memory size is zero just ignore this + * header. + */ + if (size == 0) + continue; + + /* + * We're all set up to read. + * Now let's allocate some memory. + */ + if (get_progmemory((caddr_t)base, size, + npagesize)) + goto elf64error; + } + + if (verbosemode) { + dprintf("reading 0x%llx bytes into 0x%llx\n", + (u_longlong_t)phdr->p_filesz, + (u_longlong_t)loadaddr); + } + if (xread(fd, (caddr_t)loadaddr, phdr->p_filesz) != + phdr->p_filesz) + goto elf64error; + + /* zero out BSS */ + if (phdr->p_memsz > phdr->p_filesz) { + loadaddr += phdr->p_filesz; + if (verbosemode) { + dprintf("bss from 0x%llx size 0x%llx\n", + (u_longlong_t)loadaddr, + (u_longlong_t)(phdr->p_memsz - + phdr->p_filesz)); + } + + bzero((caddr_t)loadaddr, + phdr->p_memsz - phdr->p_filesz); + bss_seen++; + if (print) + printf("0x%llx Bytes\n", + (u_longlong_t)(phdr->p_memsz - + phdr->p_filesz)); + } + + /* force instructions to be visible to icache */ + if (phdr->p_flags & PF_X) + sync_instruction_memory((caddr_t)phdr->p_vaddr, + phdr->p_memsz); + +#ifdef MPSAS + sas_symtab(phdr->p_vaddr, + phdr->p_vaddr + phdr->p_memsz); +#endif + } else if (phdr->p_type == PT_INTERP) { + /* + * Dynamically-linked executable. + */ + interp = 1; + if (lseek(fd, phdr->p_offset, 0) == -1) { + goto elf64error; + } + /* + * Get the name of the interpreter. + */ + if (xread(fd, dlname, phdr->p_filesz) != + phdr->p_filesz || + dlname[phdr->p_filesz - 1] != '\0') + goto elf64error; + } else if (phdr->p_type == PT_DYNAMIC) { + dynamic = phdr->p_vaddr; + } + } + + if (!bss_seen && print) + printf("0 Bytes\n"); + + /* + * Load the interpreter + * if there is one. + */ + if (interp) { + Elf64_Boot bootv[EB_MAX]; /* Bootstrap vector */ + auxv64_t auxv[__BOOT_NAUXV_IMPL]; /* Aux vector */ + Elf64_Boot *bv = bootv; + auxv64_t *av = auxv; + size_t vsize; + + /* + * Load it. + */ + if ((entrypt = iload64(dlname, thdr, dhdr, &av)) == + FAIL_ILOAD64) + goto elf64error; + /* + * Build bootstrap and aux vectors. + */ + setup_aux(); + EBV64(bv, EB_AUXV, 0); /* fill in later */ + EBV64(bv, EB_PAGESIZE, pagesize); + EBV64(bv, EB_DYNAMIC, dynamic); + EBV64(bv, EB_NULL, 0); + + AUX64(av, AT_BASE, entrypt); + AUX64(av, AT_ENTRY, elfhdrp->e_entry); + AUX64(av, AT_PAGESZ, pagesize); + AUX64(av, AT_PHDR, allphdrs); + AUX64(av, AT_PHNUM, elfhdrp->e_phnum); + AUX64(av, AT_PHENT, elfhdrp->e_phentsize); + if (npagesize) + AUX64(av, AT_SUN_LPAGESZ, npagesize); + +#ifdef BOOTAMD64 + vsize = strlen(amd64_getmmulist()) + 1; + if ((mmulist = kmem_alloc(vsize, 0)) == NULL) + goto elf64error; + + bcopy(amd64_getmmulist(), mmulist, vsize); + AUX64(av, AT_SUN_MMU, (uintptr_t)mmulist); +#endif /* BOOTAMD64 */ + + AUX64(av, AT_SUN_IFLUSH, icache_flush); + if (cpulist != NULL) + AUX64(av, AT_SUN_CPU, cpulist); + AUX64(av, AT_NULL, 0); + /* + * Realloc vectors and copy them. + */ + vsize = (caddr_t)bv - (caddr_t)bootv; + if ((elfbootvecELF64 = + (Elf64_Boot *)kmem_alloc(vsize, 0)) == NULL) + goto elf64error; + bcopy((char *)bootv, (char *)elfbootvecELF64, vsize); + + size = (caddr_t)av - (caddr_t)auxv; + if (size > sizeof (auxv)) { + printf("readelf: overrun of available aux vectors\n"); + kmem_free(elfbootvecELF64, vsize); + goto elf64error; + } + +#ifdef BOOTAMD64 + if ((elfbootvecELF64->eb_un.eb_ptr = + ADDR_XTND(kmem_alloc(size, 0))) == NULL) { + kmem_free(elfbootvecELF64, vsize); + goto elf64error; + } + + bcopy((char *)auxv, + (char *)ADDR_TRUNC((elfbootvecELF64->eb_un.eb_ptr)), size); +#else /* !BOOTAMD64 */ + if ((elfbootvecELF64->eb_un.eb_ptr = + (Elf64_Addr)kmem_alloc(size, 0)) == NULL) { + kmem_free(elfbootvecELF64, vsize); + goto elf64error; + } + + bcopy((char *)auxv, (char *)(elfbootvecELF64->eb_un.eb_ptr), + size); +#endif /* BOOTAMD64 */ + } else { + kmem_free(allphdrs, phdrsize); + } + return ((uint64_t)entrypt); + +elf64error: + if (allphdrs != NULL) + kmem_free(allphdrs, phdrsize); + if (nhdr != NULL) + kmem_free(nhdr, phdr->p_filesz); + printf("Elf64 read error.\n"); + return (FAIL_READELF64); +} +#endif /* _ELF64_SUPPORT */ + +/* + * Load the interpreter. It expects a + * relocatable .o capable of bootstrapping + * itself. + */ +static func_t +iload32(char *rtld, Elf32_Phdr *thdr, Elf32_Phdr *dhdr, auxv32_t **avp) +{ + Elf32_Ehdr *ehdr = NULL; + uintptr_t dl_entry = 0; + uint_t i; + int fd; + int size; + caddr_t shdrs = NULL; + caddr_t etext, edata; + + etext = (caddr_t)thdr->p_vaddr + thdr->p_memsz; + edata = (caddr_t)dhdr->p_vaddr + dhdr->p_memsz; + + /* + * Get the module path. + */ + module_path = getmodpath(filename); + + if ((fd = openpath(module_path, rtld, O_RDONLY)) < 0) { + printf("boot: cannot find %s\n", rtld); + goto errorx; + } + dprintf("Opened %s OK\n", rtld); + AUX(*avp, AT_SUN_LDNAME, rtld); + /* + * Allocate and read the ELF header. + */ + if ((ehdr = (Elf32_Ehdr *)kmem_alloc(sizeof (Elf32_Ehdr), 0)) == NULL) { + printf("boot: alloc error reading ELF header (%s).\n", rtld); + goto error; + } + + if (xread(fd, (char *)ehdr, sizeof (*ehdr)) != sizeof (*ehdr)) { + printf("boot: error reading ELF header (%s).\n", rtld); + goto error; + } + + size = ehdr->e_shentsize * ehdr->e_shnum; + if ((shdrs = (caddr_t)kmem_alloc(size, 0)) == NULL) { + printf("boot: alloc error reading ELF header (%s).\n", rtld); + goto error; + } + /* + * Read the section headers. + */ + if (lseek(fd, ehdr->e_shoff, 0) == -1 || + xread(fd, shdrs, size) != size) { + printf("boot: error reading section headers\n"); + goto error; + } + AUX(*avp, AT_SUN_LDELF, ehdr); + AUX(*avp, AT_SUN_LDSHDR, shdrs); + /* + * Load sections into the appropriate dynamic segment. + */ + for (i = 1; i < ehdr->e_shnum; i++) { + Elf32_Shdr *sp; + caddr_t *spp; + caddr_t load; + + sp = (Elf32_Shdr *)(shdrs + (i*ehdr->e_shentsize)); + /* + * If it's not allocated and not required + * to do relocation, skip it. + */ + if (!(sp->sh_flags & SHF_ALLOC) && + sp->sh_type != SHT_SYMTAB && + sp->sh_type != SHT_STRTAB && +#ifdef i386 + sp->sh_type != SHT_REL) +#else + sp->sh_type != SHT_RELA) +#endif + continue; + /* + * If the section is read-only, + * it goes in as text. + */ + spp = (sp->sh_flags & SHF_WRITE)? &edata: &etext; + /* + * Make some room for it. + */ + load = segbrk(spp, sp->sh_size, sp->sh_addralign); + if (load == NULL) { + printf("boot: allocating memory for sections failed\n"); + goto error; + } + /* + * Compute the entry point of the linker. + */ + if (dl_entry == 0 && + !(sp->sh_flags & SHF_WRITE) && + (sp->sh_flags & SHF_EXECINSTR)) { + dl_entry = (uintptr_t)load + ehdr->e_entry; + } + /* + * If it's bss, just zero it out. + */ + if (sp->sh_type == SHT_NOBITS) { + bzero(load, sp->sh_size); + } else { + /* + * Read the section contents. + */ + if (lseek(fd, sp->sh_offset, 0) == -1 || + xread(fd, load, sp->sh_size) != sp->sh_size) { + printf("boot: error reading sections\n"); + goto error; + } + } + /* + * Assign the section's virtual addr. + */ + sp->sh_addr = (Elf32_Off)load; + /* force instructions to be visible to icache */ + if (sp->sh_flags & SHF_EXECINSTR) + sync_instruction_memory((caddr_t)sp->sh_addr, + sp->sh_size); + } + /* + * Update sizes of segments. + */ + thdr->p_memsz = (Elf32_Word)((uintptr_t)etext - thdr->p_vaddr); + dhdr->p_memsz = (Elf32_Word)((uintptr_t)edata - dhdr->p_vaddr); + + /* load and relocate symbol tables in SAS */ + (void) close(fd); + return ((func_t)dl_entry); + +error: + (void) close(fd); +errorx: + if (ehdr) + kmem_free(ehdr, sizeof (Elf32_Ehdr)); + if (shdrs) + kmem_free(shdrs, size); + printf("boot: error loading interpreter (%s)\n", rtld); + return (FAIL); +} + +#ifdef _ELF64_SUPPORT +/* + * Load the interpreter. It expects a + * relocatable .o capable of bootstrapping + * itself. + */ +static Elf64_Addr +iload64(char *rtld, Elf64_Phdr *thdr, Elf64_Phdr *dhdr, auxv64_t **avp) +{ + Elf64_Ehdr *ehdr = NULL; + Elf64_Addr dl_entry = (Elf64_Addr)0; + Elf64_Addr etext, edata; + uint_t i; + int fd; + int size; + caddr_t shdrs = NULL; + + etext = thdr->p_vaddr + thdr->p_memsz; + edata = dhdr->p_vaddr + dhdr->p_memsz; + + /* + * Get the module path. + */ + module_path = getmodpath(filename); + + if ((fd = openpath(module_path, rtld, O_RDONLY)) < 0) { + printf("boot: cannot find %s\n", rtld); + goto errorx; + } + dprintf("Opened %s OK\n", rtld); + AUX64(*avp, AT_SUN_LDNAME, rtld); + /* + * Allocate and read the ELF header. + */ +#ifdef BOOTAMD64 + if ((ehdr = (Elf64_Ehdr *)(uintptr_t)kmem_alloc(sizeof (Elf64_Ehdr), + 0)) == NULL) { +#else /* !BOOTAMD64 */ + if ((ehdr = (Elf64_Ehdr *)kmem_alloc(sizeof (Elf64_Ehdr), 0)) == NULL) { +#endif /* BOOTAMD64 */ + printf("boot: alloc error reading ELF header (%s).\n", rtld); + goto error; + } + + if (xread(fd, (char *)ehdr, sizeof (*ehdr)) != sizeof (*ehdr)) { + printf("boot: error reading ELF header (%s).\n", rtld); + goto error; + } + + size = ehdr->e_shentsize * ehdr->e_shnum; + if ((shdrs = (caddr_t)kmem_alloc(size, 0)) == NULL) { + printf("boot: alloc error reading ELF header (%s).\n", rtld); + goto error; + } + /* + * Read the section headers. + */ + if (lseek(fd, ehdr->e_shoff, 0) == -1 || + xread(fd, shdrs, size) != size) { + printf("boot: error reading section headers\n"); + goto error; + } + +#ifdef BOOTAMD64 + AUX64(*avp, AT_SUN_LDELF, (uintptr_t)ehdr); + AUX64(*avp, AT_SUN_LDSHDR, (uintptr_t)shdrs); +#else /* !BOOTAMD64 */ + AUX64(*avp, AT_SUN_LDELF, ehdr); + AUX64(*avp, AT_SUN_LDSHDR, shdrs); +#endif /* BOOTAMD64 */ + + /* + * Load sections into the appropriate dynamic segment. + */ + for (i = 1; i < ehdr->e_shnum; i++) { + Elf64_Shdr *sp; + Elf64_Addr *spp, load; + + sp = (Elf64_Shdr *)(shdrs + (i*ehdr->e_shentsize)); + /* + * If it's not allocated and not required + * to do relocation, skip it. + */ + if (!(sp->sh_flags & SHF_ALLOC) && + sp->sh_type != SHT_SYMTAB && + sp->sh_type != SHT_STRTAB && + sp->sh_type != SHT_RELA) + continue; + /* + * If the section is read-only, + * it goes in as text. + */ + spp = (sp->sh_flags & SHF_WRITE)? &edata: &etext; + + /* + * Make some room for it. + */ +#ifdef BOOTAMD64 + load = ADDR_XTND(segbrk((caddr_t *)spp, + sp->sh_size, sp->sh_addralign)); +#else /* !BOOTAMD64 */ + load = (Elf64_Addr)segbrk((caddr_t *)spp, sp->sh_size, + sp->sh_addralign); +#endif /* BOOTAMD64 */ + + if (load == NULL) { + printf("boot: allocating memory for section %d " + "failed\n", i); + goto error; + } + + /* + * Compute the entry point of the linker. + */ + if (dl_entry == 0 && + !(sp->sh_flags & SHF_WRITE) && + (sp->sh_flags & SHF_EXECINSTR)) { + dl_entry = load + ehdr->e_entry; + if (verbosemode) + dprintf("boot: loading linker @ 0x%llx\n", + (u_longlong_t)dl_entry); + } + + /* + * If it's bss, just zero it out. + */ + if (sp->sh_type == SHT_NOBITS) { + bzero((caddr_t)load, sp->sh_size); + } else { + /* + * Read the section contents. + */ + if (lseek(fd, sp->sh_offset, 0) == -1 || + xread(fd, (caddr_t)load, sp->sh_size) != + sp->sh_size) { + printf("boot: error reading section %d\n", + i); + goto error; + } + } + /* + * Assign the section's virtual addr. + */ + + sp->sh_addr = load; + + if (verbosemode) + dprintf("boot: section %d, type %d, loaded @ 0x%llx, " + "size 0x%llx\n", i, sp->sh_type, (u_longlong_t)load, + (u_longlong_t)sp->sh_size); + + /* force instructions to be visible to icache */ + if (sp->sh_flags & SHF_EXECINSTR) + sync_instruction_memory((caddr_t)sp->sh_addr, + sp->sh_size); + } + /* + * Update sizes of segments. + */ + thdr->p_memsz = etext - thdr->p_vaddr; + dhdr->p_memsz = edata - dhdr->p_vaddr; + + /* load and relocate symbol tables in SAS */ + (void) close(fd); + return (dl_entry); + +error: + (void) close(fd); +errorx: + if (ehdr) + kmem_free((caddr_t)ehdr, sizeof (Elf64_Ehdr)); + if (shdrs) + kmem_free(shdrs, size); + printf("boot: error loading interpreter (%s)\n", rtld); + return (FAIL_ILOAD64); +} +#endif /* _ELF64_SUPPORT */ + +/* + * Extend the segment's "break" value by bytes. + */ +static caddr_t +segbrk(caddr_t *spp, size_t bytes, size_t align) +{ + caddr_t va, pva; + size_t size = 0; + unsigned int alloc_pagesize = pagesize; + unsigned int alloc_align = 0; + + if (npagesize) { + alloc_align = npagesize; + alloc_pagesize = npagesize; + } + + va = (caddr_t)ALIGN(*spp, align); + pva = (caddr_t)roundup((uintptr_t)*spp, alloc_pagesize); + /* + * Need more pages? + */ + if (va + bytes > pva) { + size = roundup((bytes - (pva - va)), alloc_pagesize); + + if (get_progmemory(pva, size, alloc_align)) { + printf("boot: segbrk allocation failed, " + "0x%lx bytes @ %p\n", bytes, (void *)pva); + return (NULL); + } + } + *spp = va + bytes; + + return (va); +} + +/* + * Open the file using a search path and + * return the file descriptor (or -1 on failure). + */ +static int +openpath(path, fname, flags) +char *path; +char *fname; +int flags; +{ + register char *p, *q; + char buf[MAXPATHLEN]; + int fd; + + /* + * If the file name is absolute, + * don't use the module search path. + */ + if (fname[0] == '/') + return (open(fname, flags)); + + q = NULL; + for (p = path; /* forever */; p = q) { + + while (*p == ' ' || *p == '\t' || *p == ':') + p++; + if (*p == '\0') + break; + q = p; + while (*q && *q != ' ' && *q != '\t' && *q != ':') + q++; + (void) strncpy(buf, p, q - p); + if (q[-1] != '/') { + buf[q - p] = '/'; + (void) strcpy(&buf[q - p + 1], fname); + } else { + /* + * This checks for paths that end in '/' + */ + (void) strcpy(&buf[q - p], fname); + } + + if ((fd = open(buf, flags)) > 0) + return (fd); + } + return (-1); +} + +/* + * Get the module search path. + */ +static char * +getmodpath(fname) +char *fname; +{ + register char *p = strrchr(fname, '/'); + static char mod_path[MOD_MAXPATH]; + size_t len; + extern char *impl_arch_name; +#if defined(__sparcv9) || defined(__ia64) || defined(BOOTAMD64) +#ifdef __sparcv9 + char *isastr = "/sparcv9"; +#endif /* __sparcv9 */ +#ifdef __ia64 + char *isastr = "/ia64"; +#endif /* __ia64 */ +#ifdef BOOTAMD64 + char *isastr = "/amd64"; +#endif /* BOOTAMD64 */ + size_t isalen = strlen(isastr); +#endif /* __sparcv9 || __ia64 || BOOTAMD64 */ + + if (p == NULL) { + /* strchr could not find a "/" */ + printf("%s is not a legal kernel pathname", fname); + return (NULL); + } + while (p > fname && *(p - 1) == '/') + p--; /* remove trailing "/"s */ + if (p == fname) + p++; /* "/" is the modpath in this case */ + + len = p - fname; + (void) strncpy(mod_path, fname, len); + mod_path[len] = 0; + +#if defined(__sparcv9) || defined(__ia64) || defined(BOOTAMD64) + len = strlen(mod_path); + if ((len > isalen) && (strcmp(&mod_path[len - isalen], isastr) == 0)) { + mod_path[len - isalen] = '\0'; +#if defined(__sparcv9) || defined(__ia64) + if ((client_isLP64 == 0) && verbosemode) + printf("Assuming LP64 %s client.\n", isastr); + client_isLP64 = 1; +#endif /* __sparcv9 || __ia64 */ + } +#endif /* __sparcv9 || __ia64 || BOOTAMD64 */ + mod_path_uname_m(mod_path, impl_arch_name); + (void) strcat(mod_path, " "); + (void) strcat(mod_path, MOD_DEFPATH); + + if (boothowto & RB_ASKNAME) { + char buf[MOD_MAXPATH]; + + printf("Enter default directory for modules [%s]: ", mod_path); + (void) cons_gets(buf, sizeof (buf)); + if (buf[0] != '\0') + (void) strcpy(mod_path, buf); + } + if (verbosemode) + printf("modpath: %s\n", mod_path); + return (mod_path); +} diff --git a/usr/src/psm/stand/boot/common/stripalign.c b/usr/src/psm/stand/boot/common/stripalign.c new file mode 100644 index 0000000000..17a2f428c4 --- /dev/null +++ b/usr/src/psm/stand/boot/common/stripalign.c @@ -0,0 +1,162 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1992-2003 Sun Microsystems, Inc. + * All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/exechdr.h> +#include <sys/elf.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <strings.h> + +static Elf32_Ehdr elfhdr; +static Elf32_Phdr phdr, dphdr; +static char machine[] = {0, 0, 3, 0, 2}; +static int fd; +static char buf[4096]; +static long lalignbuf[2]; + +int +main(int argc, char **argv) +{ + int ifd; + struct exec exec; + int count; + int tot_write = 0; + long lalign; + int lbytes; + int text_written = 0; + int data_written = 0; + char *prog = *argv; + + if (argc < 3) { + (void) printf("usage: stripalign elf_file a.outfile \n"); + exit(1); + } + if ((ifd = open(argv[1], O_RDONLY)) == -1) { + perror("open input"); + exit(1); + } + if (read(ifd, &elfhdr, sizeof (elfhdr)) < sizeof (elfhdr)) { + perror("read elfhdr"); + exit(1); + } + if ((fd = open(argv[2], O_RDWR | O_TRUNC | O_CREAT, 0777)) == -1) { + perror("open aout"); + exit(1); + } + + if (*(int *)(elfhdr.e_ident) != *(int *)(ELFMAG)) { + perror("elfmag"); + exit(1); + } + if (lseek(ifd, elfhdr.e_phoff, 0) == -1) { + perror("lseek"); + exit(1); + } + if (read(ifd, &phdr, sizeof (phdr)) < sizeof (phdr)) { + perror("read phdr"); + exit(1); + } + if (read(ifd, &dphdr, sizeof (dphdr)) < sizeof (dphdr)) { + perror("read dphdr"); + exit(1); + } + + bzero(&exec, sizeof (exec)); + exec.a_dynamic = 0; + exec.a_toolversion = 1; + exec.a_machtype = machine[elfhdr.e_machine]; + exec.a_magic = OMAGIC; + exec.a_text = dphdr.p_vaddr - phdr.p_vaddr; + exec.a_data = dphdr.p_filesz; + exec.a_bss = dphdr.p_memsz - dphdr.p_filesz; + exec.a_entry = elfhdr.e_entry; + + if (write(fd, &exec, sizeof (exec)) != sizeof (exec)) { + perror("write exec"); + exit(1); + } + tot_write += sizeof (exec); + + if (lseek(ifd, phdr.p_offset, 0) == -1) { + perror("lseek text"); + exit(1); + } + /* do text section first */ + while (text_written < exec.a_text && + (count = read(ifd, buf, sizeof (buf))) > 0) { + if (count > exec.a_text - text_written) + count = (exec.a_text - text_written); + if (write(fd, buf, count) < count) { + perror("write text file"); + exit(1); + } + text_written += count; + } + tot_write += text_written; + if (lseek(ifd, dphdr.p_offset, 0) == -1) { + perror("lseek data"); + exit(1); + } + while (data_written < exec.a_data && + (count = read(ifd, buf, sizeof (buf))) > 0) { + if (count > exec.a_data - data_written) + count = (exec.a_data - data_written); + if (write(fd, buf, count) < count) { + perror("write data file"); + exit(1); + } + data_written += count; + } + tot_write += data_written; + + /* + * Round file size out to long word boundary. + * If the longword boundary is a multiple of 512 bytes, + * add another longword. + */ + lbytes = 0; + if ((lalign = tot_write % sizeof (long)) != 0) + lbytes = sizeof (long) - lalign; + if (((lbytes + tot_write) % 512) == 0) + lbytes += sizeof (long); + + if (lbytes != 0) { + (void) printf("%s: (Align) 0x%x + 0x%x = 0x%x bytes\n", prog, + tot_write, lbytes, (tot_write + lbytes)); + if (write(fd, (char *)lalignbuf, lbytes) < lbytes) { + perror("write (alignment) data file"); + exit(1); + } + } + (void) close(fd); + (void) close(ifd); + return (0); +} diff --git a/usr/src/psm/stand/boot/i386/Makefile b/usr/src/psm/stand/boot/i386/Makefile new file mode 100644 index 0000000000..3c2e60a3cb --- /dev/null +++ b/usr/src/psm/stand/boot/i386/Makefile @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../../../../Makefile.master + +# firmware libraries, platform-group, and platform-specific +# subdirectories to visit. + +SUBDIRS = i86pc + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +all install clean clobber lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +# +# Cross-reference customization: include all boot-related source files. +# +UTSDIR= ../../../../uts +XRDIRS += ../amd64 ../intel ../common + +cscope.out tags: FRC + $(XREF) -x $@ + +FRC: diff --git a/usr/src/psm/stand/boot/i386/Makefile.com b/usr/src/psm/stand/boot/i386/Makefile.com new file mode 100644 index 0000000000..7e364c12de --- /dev/null +++ b/usr/src/psm/stand/boot/i386/Makefile.com @@ -0,0 +1,207 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/boot/i386/Makefile.com + +include $(TOPDIR)/psm/stand/boot/Makefile.boot + +BOOTSRCDIR = ../.. + +TOP_CMN_DIR = $(SRC)/common +PROM_DIR = $(SRC)/uts/intel/promif +CMN_DIR = $(BOOTSRCDIR)/common +MACH_DIR = ../common +PLAT_DIR = . +PAMD64_DIR = $(BOOTSRCDIR)/amd64 + +TOP_CMN_C_SRC = getoptstr.c string.c ufsops.c hsfs.c +TOP_CMN_C_SRC += memcpy.c memmove.c memset.c bcopy.c bzero.c +PROM_C_SRC = prom_printf.c prom_putchar.c prom_env.c +CMN_C_SRC = heap_kmem.c readfile.c + +PAMD64_C_SRC = alloc.c context.c cpu.c handoff.c memlist.c print.c +PAMD64_C_SRC += ptops.c ptxlate.c segments.c vtrap.c +PAMD64_S_SRC = i386_subr.s +PAMD64_SL_SRC = locore.s exception.s + +ASSYM_H = assym.h +GENASSYM = genassym +GENASSYM_FILES = $(ASSYM_H) $(GENASSYM) + +$(PAMD64_SL_SRC:%.s=%.o) := AS = $(amd64_AS) +$(PAMD64_SL_SRC:%.s=%.o) := ASFLAGS = -P $(CPPDEFS) -D_ASM $(CPPINCS) + +MACH_C_SRC = bios.c bootflags.c bootops.c bootprop.c +MACH_C_SRC += boot_plat.c boot_ramdisk.c console.c +MACH_C_SRC += keyboard.c keyboard_table.c memory.c +MACH_C_SRC += multiboot.c standalloc.c vga.c graphics.c +MACH_C_SRC += bootenv.c vgaprobe.c check_iopath.c + +BIOS_C_SRC = biosutil.c + +C_SRC = $(TOP_CMN_C_SRC) $(CMN_C_SRC) $(MACH_C_SRC) $(ARCH_C_SRC) +C_SRC += $(PAMD64_C_SRC) $(PROM_C_SRC) +S_SRC = $(ARCH_S_SRC) $(PAMD64_S_SRC) $(PAMD64_SL_SRC) + +START_OBJS = $(START_S_SRC:%.s=%.o) +OBJS = $(C_SRC:%.c=%.o) $(S_SRC:%.s=%.o) +L_OBJS = $(OBJS:%.o=%.ln) + +# Note: the BIOS_S_SRC (biosint.s) must come first +BIOS_OBJS = $(BIOS_S_SRC:%.s=%.o) $(BIOS_C_SRC:%.c=%.o) + +ELFCONV = mkbin +BIOSINT = biosint +UNIBOOT = multiboot + +ROOT_PSM_BIOSINT = $(ROOT_PSM_DIR)/$(BIOSINT) +ROOT_PSM_UNIBOOT = $(ROOT_PSM_DIR)/$(UNIBOOT) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(START_OBJS) $(L_OBJS) + +all: $(ELFCONV) $(UNIBOOT) $(BIOSINT) + +SYSDIR = $(TOPDIR)/uts + +CPPDEFS = $(ARCHOPTS) -D$(PLATFORM) -D_BOOT -D_KERNEL -D_MACHDEP +CPPINCS += -I$(TOP_CMN_DIR) +CPPINCS += -I. -I$(PAMD64_DIR) +CPPINCS += -I$(PSMSYSHDRDIR) +CPPINCS += -I$(ROOT)/usr/platform/$(PLATFORM)/include +CPPINCS += -I$(TOPDIR)/uts/intel -I$(TOPDIR)/uts/i86pc +CPPINCS += -I$(TOPDIR)/uts/common +CPPINCS += -I$(STANDDIR)/lib/sa +CPPINCS += -I$(STANDDIR) + +CPPFLAGS = $(CPPDEFS) $(CPPINCS) +CPPFLAGS += $(CCYFLAG)$(SYSDIR)/common +ASFLAGS = $(CPPDEFS) -P -D__STDC__ -D_BOOT -D_ASM $(CPPINCS) + +CFLAGS = ../common/i86.il $(COPTFLAG) +# +# Force 16-bit alignment in multiboot +# +CFLAGS += -xcache=0/16/0:0/16/0 +# +# This should be globally enabled! +# +CFLAGS += $(CCVERBOSE) + +YFLAGS = -d + +# +# Loader flags used to build biosint +# +BIOS_LOADMAP = bios_loadmap +BIOS_MAPFILE = $(MACH_DIR)/biosint.map +BIOS_LDFLAGS = -dn -m -M $(BIOS_MAPFILE) + +$(ELFCONV): $(MACH_DIR)/$$(@).c + $(NATIVECC) -O -o $@ $(MACH_DIR)/$@.c + +$(BIOSINT): $(ELFCONV) $(BIOS_MAPFILE) $(BIOS_OBJS) + $(LD) $(BIOS_OBJS) $(BIOS_LDFLAGS) -o $@.elf > $(BIOS_LOADMAP) + cp $@.elf $@.strip + $(STRIP) $@.strip + $(RM) $@; ./$(ELFCONV) $@.strip $@ + +# +# Loader flags used to build unified boot +# +UNI_LOADMAP = loadmap +UNI_MAPFILE = $(MACH_DIR)/mapfile +UNI_LDFLAGS = -dn -m -M $(UNI_MAPFILE) + +# +# Object files used to build unified boot +# Note: START_OBJS must come within first 8K to comply with Multiboot Spec +# +UNI_OBJS = $(START_OBJS) $(OBJS) +UNI_L_OBJS = $(UNI_OBJS:%.o=%.ln) + +$(UNIBOOT): $(UNI_MAPFILE) $(UNI_OBJS) + $(LD) $(UNI_LDFLAGS) -o $@ $(UNI_OBJS) > $(UNI_LOADMAP) + $(POST_PROCESS) + +$(UNIBOOT)_lint: $(UNI_L_OBJS) + $(LINT.c) $(UNI_L_OBJS) + +ROOT_BOOT_DIR = $(ROOT)/boot +ROOT_BOOT_SOL_DIR = $(ROOT_BOOT_DIR)/solaris + +$(ROOT_BOOT_DIR): $(ROOT) + -$(INS.dir.root.sys) + +$(ROOT_BOOT_SOL_DIR): $(ROOT_BOOT_DIR) + -$(INS.dir.root.sys) + +$(ROOT_BOOT_SOL_DIR)/%: % $(ROOT_BOOT_SOL_DIR) + $(INS.file) + +# +# AMD64 genassym fun +# +$(PAMD64_S_SRC:%.s=%.o) : $(GENASSYM_FILES) +$(PAMD64_SL_SRC:%.s=%.o) : $(GENASSYM_FILES) + +GENASSYM_SRC = $(PAMD64_DIR)/$(GENASSYM:%=%.c) +$(GENASSYM) := CFLAGS = -D__sun $(ENVCPPFLAGS1) $(ENVCPPFLAGS2) \ + $(ENVCPPFLAGS3) $(ENVCPPFLAGS4) + +$(GENASSYM): $(GENASSYM_SRC) + $(NATIVECC) $(CFLAGS) -o $@ $(GENASSYM_SRC) + +OFFSETS = $(PAMD64_DIR)/offsets.in +$(ASSYM_H) := CC = $(amd64_CC) +$(ASSYM_H) := CFLAGS = -g -xarch=amd64 -xc99=%none \ + -D__sun $(CPPFLAGS) +$(ASSYM_H) := CCYFLAG = -g -YI, + +$(ASSYM_H): $(OFFSETS) $(GENASSYM) + $(GENOFFSETS) -s $(CTFSTABS) -r $(CTFCONVERT) \ + $(CC) $(CFLAGS) $(GOFLAGS) <$(OFFSETS) >$@ + ./$(GENASSYM) >>$@ + +include $(BOOTSRCDIR)/Makefile.rules + +clean: + $(RM) $(OBJS) $(BIOS_OBJS) + $(RM) $(L_OBJS) $(GENASSYM_FILES) + $(RM) $(BIOSINT).elf a.out core + +clobber: clean + $(RM) $(ELFCONV) $(UNIBOOT) $(UNI_LOADMAP) $(BIOSINT) $(BIOS_LOADMAP) + $(RM) $(UFSBOOT) $(NFSBOOT) + +include $(TOPDIR)/Makefile.psm.targ + +install: $(ROOT_PSM_UNIBOOT) $(ROOT_PSM_BIOSINT) + +lint: all $(UNIBOOT)_lint + +FRC: diff --git a/usr/src/psm/stand/boot/i386/common/bios.c b/usr/src/psm/stand/boot/i386/common/bios.c new file mode 100644 index 0000000000..f6c0ee5013 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/bios.c @@ -0,0 +1,90 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/controlregs.h> +#include <sys/bootconf.h> +#include <sys/bootvfs.h> +#include <sys/psw.h> +#include "biosint.h" +#include "machine.h" +#include "standalloc.h" +#include "console.h" +#include "util.h" +#include "debug.h" + +#define PCI_FUNCTION_ID 0xB1 +#define PCI_BIOS_PRESENT 0x1 +#define dprintf if (debug & D_BIOS) printf + +extern int openfile(char *, int); +int (*bios_doint)(int, struct int_pb *); + +static void +pci_check_bios(void) +{ + int ret; + struct int_pb ic = {0}; + + ic.ax = (PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT; + ret = bios_doint(0x1a, &ic); + if (ret & PS_C) + printf("bios_doint failed: %d\r\n", ret); + dprintf("bios_doint returned: %d\r\n", ret); + dprintf("ic.ax = 0x%x\r\n", (int)ic.ax); + dprintf("ic.dx = 0x%x\r\n", (int)ic.dx); +} + +void +init_biosprog() +{ + int fd; + char *buf = (char *)0x2000; + ssize_t count; + + /* read biosint program to pfn 2 */ + fd = openfile("biosint", 0); + if (fd == -1) { + printf("cannot open biosint\n"); + return; + } + + count = read(fd, buf, PAGESIZE); + if (count <= 0) { + printf("cannot read biosint\n"); + return; + } + + bios_doint = (int (*)(int, struct int_pb *))(buf); + dprintf("biosint loaded at 0x%x: %d bytes\r\n", buf, count); + if (debug & D_BIOS) /* run a check if debug */ + pci_check_bios(); + if (verbosemode) + printf("bios service program installed\n"); +} diff --git a/usr/src/psm/stand/boot/i386/common/biosint.h b/usr/src/psm/stand/boot/i386/common/biosint.h new file mode 100644 index 0000000000..0372ed078a --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/biosint.h @@ -0,0 +1,46 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_BIOSINT_H +#define _SYS_BIOSINT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +struct int_pb { + unsigned short ax, bx, cx, dx, bp, si, di, ds, es; +}; + +extern int (*bios_doint)(int, struct int_pb *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_BIOSINT_H */ diff --git a/usr/src/psm/stand/boot/i386/common/biosint.map b/usr/src/psm/stand/boot/i386/common/biosint.map new file mode 100644 index 0000000000..8780bf99b3 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/biosint.map @@ -0,0 +1,28 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" + +text = LOAD V0x2000; +data = A0x1; diff --git a/usr/src/psm/stand/boot/i386/common/biosutil.c b/usr/src/psm/stand/boot/i386/common/biosutil.c new file mode 100644 index 0000000000..8a309f5756 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/biosutil.c @@ -0,0 +1,335 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * helper functions for switching to realmode and make a bios call. + * The only interesting functions are copyin_args and copyout_args. + * The rest are for debugging via a serial line. + */ + +#include <sys/types.h> +#include <sys/varargs.h> +#include "../common/biosint.h" +#include "../common/chario.h" +#include "../common/serial.h" + +extern uchar_t inb(int); +extern void outb(int, uchar_t); + +/* Forward declarations. */ +static void putchar(int c); +static void itoa(char *buf, int base, int d); + +void +copyin_args(int intnum, struct int_pb *ic) +{ + extern int ic_int; + extern uint16_t ic_ax, ic_bx, ic_cx, ic_dx; + extern uint16_t ic_bp, ic_si, ic_di, ic_ds, ic_es; + + ic_int = intnum; + ic_ax = ic->ax; + ic_bx = ic->bx; + ic_cx = ic->cx; + ic_dx = ic->dx; + ic_bp = ic->bp; + ic_si = ic->si; + ic_di = ic->di; + ic_ds = ic->ds; + ic_es = ic->es; +} + +void +copyout_args(struct int_pb *ic) +{ + extern uint16_t ic_ax, ic_bx, ic_cx, ic_dx; + extern uint16_t ic_bp, ic_si, ic_di, ic_ds, ic_es; + + ic->ax = ic_ax; + ic->bx = ic_bx; + ic->cx = ic_cx; + ic->dx = ic_dx; + ic->bp = ic_bp; + ic->si = ic_si; + ic->di = ic_di; + ic->ds = ic_ds; + ic->es = ic_es; +} + +/* + * Convert the integer D to a string and save the string in BUF. If + * BASE is equal to 'd', interpret that D is decimal, and if BASE is + * equal to 'x', interpret that D is hexadecimal. + */ +static void +itoa(char *buf, int base, int d) +{ + char *p = buf; + char *p1, *p2; + unsigned long ud = d; + int divisor = 10; + + /* If %d is specified and D is minus, put `-' in the head. */ + if (base == 'd' && d < 0) { + *p++ = '-'; + buf++; + ud = -d; + } else if (base == 'x') { + divisor = 16; + } + + /* Divide UD by DIVISOR until UD == 0. */ + do { + int remainder = ud % divisor; + + *p++ = (remainder < 10) ? + remainder + '0' : remainder + 'a' - 10; + } + + while (ud /= divisor) + ; + + /* Terminate BUF. */ + *p = 0; + + /* Reverse BUF. */ + p1 = buf; + p2 = p - 1; + while (p1 < p2) { + char tmp = *p1; + *p1 = *p2; + *p2 = tmp; + p1++; + p2--; + } +} + +/* + * Printn prints a number n in base b. + * We don't use recursion to avoid deep kernel stacks. + */ +/* XXX need to support 64-bit numbers */ +static void +_printn(uint_t n, int b, int width, int pad) +{ + char prbuf[40]; + char *cp; + + cp = prbuf; + do { + *cp++ = "0123456789abcdef"[n%b]; + n /= b; + width--; + } while (n); + while (width-- > 0) + *cp++ = (char)pad; + do { + putchar(*--cp); + } while (cp > prbuf); +} + +/* + * Format a string and print it on the screen, just like the libc + * function printf. + */ +void +vprintf(const char *fmt, va_list adx) +{ + int b, c, i, pad, width, ells; + char *s; + int64_t l; + uint64_t ul; + +loop: + width = 0; + while ((c = *fmt++) != '%') { + if (c == '\0') + return; + putchar(c); + } + + c = *fmt++; + + for (pad = ' '; c == '0'; c = *fmt++) + pad = '0'; + + for (width = 0; c >= '0' && c <= '9'; c = *fmt++) + width = (width * 10) + (c - '0'); + + for (ells = 0; c == 'l'; c = *fmt++) + ells++; + + switch (c) { + + case 'd': + case 'D': + b = 10; + if (ells == 0) + l = (int64_t)va_arg(adx, int); + else if (ells == 1) + l = (int64_t)va_arg(adx, long); + else + l = (int64_t)va_arg(adx, int64_t); + if (l < 0) { + putchar('-'); + width--; + putchar('-'); + width--; + ul = -l; + } else + ul = l; + goto number; + + case 'p': + ells = 1; + /* FALLTHROUGH */ + case 'x': + case 'X': + b = 16; + goto u_number; + + case 'u': + b = 10; + goto u_number; + + case 'o': + case 'O': + b = 8; +u_number: + if (ells == 0) + ul = (uint64_t)va_arg(adx, uint_t); + else if (ells == 1) + ul = (uint64_t)va_arg(adx, ulong_t); + else + ul = (uint64_t)va_arg(adx, uint64_t); +number: + _printn((uint_t)ul, b, width, pad); + break; + + case 'c': + b = va_arg(adx, int); + for (i = 24; i >= 0; i -= 8) + if ((c = ((b >> i) & 0x7f)) != 0) { + putchar(c); + } + break; + case 's': + s = va_arg(adx, char *); + while ((c = *s++) != 0) { + putchar(c); + } + break; + + case '%': + putchar('%'); + break; + } + goto loop; + +} + +/* + * Format a string and print it on the screen, just like the libc + * function printf. + */ +void +printf(const char *fmt, ...) +{ + va_list adx; + + va_start(adx, fmt); + vprintf(fmt, adx); + va_end(adx); +} + +/* serial port stuff */ +static int port = 0x3f8; + +static void +serial_putchar(int c) +{ + int checks = 10000; + + while (((inb(port + LSR) & XHRE) == 0) && checks--) + ; + outb(port + DAT, (char)c); +} + +static void +_doputchar(int c) +{ + serial_putchar(c); +} + +void +putchar(int c) +{ + static int bhcharpos = 0; + + if (c == '\t') { + do { + _doputchar(' '); + } while (++bhcharpos % 8); + return; + } else if (c == '\n') { + bhcharpos = 0; + _doputchar('\r'); + _doputchar(c); + return; + } else if (c == '\b') { + if (bhcharpos) + bhcharpos--; + _doputchar(c); + return; + } + + bhcharpos++; + _doputchar(c); +} + +void +print_long(int reg) +{ + printf("long = 0x%x\n", reg); +} + +void +print_word(ushort_t reg) +{ + printf("word = 0x%x\n", reg); +} + +void +print_regs() +{ + extern int call_esp, ic_int; + extern uint16_t call_cs, call_ss; + + printf("call_cs = %x, call_ss = %x\r\n", call_cs, call_ss); + printf("intnum = %x, esp = %x\r\n", ic_int, call_esp); +} diff --git a/usr/src/psm/stand/boot/i386/common/boot_plat.c b/usr/src/psm/stand/boot/i386/common/boot_plat.c new file mode 100644 index 0000000000..14dea10f6f --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/boot_plat.c @@ -0,0 +1,267 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/bootvfs.h> +#include <sys/varargs.h> +#include "console.h" +#include "util.h" +#include "bootprop.h" +#include "biosint.h" +#include "debug.h" + +char filename[MAXPATHLEN]; +char *impl_arch_name = "i86pc"; +int pagesize = 0x1000; + +extern void *memset(void *, int, size_t); + + +/* + * Open the given filename, expanding to its + * platform-dependent location if necessary. + */ +int +openfile(char *fname, char *kern) +{ + int fd; + + /* + * If the caller -specifies- an absolute pathname, then we just try to + * open it. + */ + if (*fname == '/') { + (void) strcpy(filename, fname); + return (open(fname, 0)); + } + + (void) strcpy(filename, "/platform/i86pc/"); + if (kern) + (void) strcat(filename, kern); + (void) strcat(filename, fname); + if ((fd = open(filename, 0)) != -1) + return (fd); + + /* try / */ + (void) strcpy(filename, "/"); + if (kern) + (void) strcat(filename, kern); + (void) strcat(filename, fname); + return (open(filename, 0)); +} + +/* + * Is path "/platform/"dir"/" ? + */ +static int +platcmp(char *path, char *dir) +{ + static char prefix[] = "/platform/"; + static char suffix[] = "/kernel"; + int len; + + if (strncmp(path, prefix, sizeof (prefix) - 1) != 0) + return (0); + len = strlen(dir); + path += sizeof (prefix) - 1; + if (strncmp(path, dir, len) != 0) + return (0); + path += len; + if (strcmp(path, suffix) != 0) + return (0); + return (1); +} + +void +mod_path_uname_m(char *mod_path, char *ia_name) +{ + /* + * If we found the kernel in the default "i86pc" dir, prepend the + * ia_name directory (e.g. /platform/SUNW,foo/kernel) to the mod_path + * unless ia_name is the same as the default dir. + * + * If we found the kernel in the ia_name dir, append the default + * directory to the modpath. + * + * If neither of the above are true, we were given a specific kernel + * to boot, so we leave things well enough alone. + */ + if (platcmp(mod_path, "i86pc")) { + if (strcmp(ia_name, "i86pc") != 0) { + char tmp[MAXPATHLEN]; + + (void) strcpy(tmp, mod_path); + (void) strcpy(tmp, mod_path); + (void) strcpy(mod_path, "/platform/"); + (void) strcat(mod_path, ia_name); + (void) strcat(mod_path, "/kernel "); + (void) strcat(mod_path, tmp); + } + } else if (platcmp(mod_path, ia_name)) + (void) strcat(mod_path, " /platform/i86pc/kernel"); +} + +void +setup_aux(void) +{ + extern char *mmulist; + static char mmubuf[16]; + int plen; + + if (((plen = bgetproplen(NULL, "mmu-modlist")) > 0) && (plen < 20)) + (void) bgetprop(NULL, "mmu-modlist", mmubuf); + else + (void) strcpy(mmubuf, "mmu32"); /* default to mmu32 */ + mmulist = mmubuf; +} + +/* Print panic string, then blow up! */ +/*PRINTFLIKE1*/ +void +panic(const char *fmt, ...) +{ + va_list adx; + + /* turn on output */ + verbosemode = 1; + printf("panic: "); + va_start(adx, fmt); + prom_vprintf(fmt, adx); + va_end(adx); + printf("Press any key to reboot\n"); + (void) getchar(); + printf("rebooting...\n"); + reset(); +} + +void +prom_panic(char *str) +{ + panic(str); +} + +/* + * stubs for heap_kmem (assuming they're actually even needed there) + */ + +int +splimp() +{ + return (0); +} + +/*ARGSUSED*/ +void +splx(int rs) +{ +} + +int +splnet() +{ + return (0); +} + +static uint_t +gettime(void) +{ + /* + * Read system timer: + * + * Return milliseconds since last time counter was reset. + * The timer ticks 18.2 times per second or approximately + * 55 milliseconds per tick. + * + * The counter will be reset to zero by the bios after 24 hours + * or 1,573,040 ticks. The first read after a counter + * reset will flag this condition in the %al register. + * Unfortunately, it is hard to take advantage of this + * fact because some broken bioses will return bogus + * counter values if the counter is in the process of + * updating. We protect against this race by reading the + * counter until we get consecutive identical readings. + * By doing so, we lose the counter reset bit. To make this + * highly unlikely, we reset the counter to zero on the + * first call and assume 24 hours is enough time to get this + * machine booted. + * + * An attempt is made to provide a unique number on each + * call by adding 1 millisecond if the 55 millisecond counter + * hasn't changed. If this happens more than 54 times, we + * return the same value until the next real tick. + */ + static uint_t lasttime = 0; + static ushort_t fudge = 0; + uint_t ticks, mills, first, tries; + struct int_pb ic; + + if (lasttime == 0) { + /* + * initialize counter to zero so we don't have to + * worry about 24 hour wrap. + */ + (void) memset(&ic, 0, sizeof (ic)); + ic.ax = 0x0100; + (void) bios_doint(0x1a, &ic); + } + tries = 0; + do { + /* + * Loop until we trust the counter value. + */ + (void) memset(&ic, 0, sizeof (ic)); + (void) bios_doint(0x1a, &ic); + first = (ic.cx << 16) + (ic.dx & 0xFFFF); + (void) memset(&ic, 0, sizeof (ic)); + (void) bios_doint(0x1a, &ic); + ticks = (ic.cx << 16) + (ic.dx & 0xFFFF); + } while (first != ticks && ++tries < 10); + if (tries == 10) + printf("gettime: BAD BIOS TIMER\n"); + + mills = ticks*55; + if (mills > lasttime) { + fudge = 0; + } else { + fudge += (fudge < 54) ? 1 : 0; + } + mills += fudge; + lasttime = mills; + return (mills); +} + +void +mdelay(uint_t msec) +{ + uint_t time_now = gettime(); + uint_t time_end = time_now + msec; + + /* spin, we can't do anything else */ + while (gettime() < time_end) + ; +} diff --git a/usr/src/psm/stand/boot/i386/common/boot_ramdisk.c b/usr/src/psm/stand/boot/i386/common/boot_ramdisk.c new file mode 100644 index 0000000000..c9bf684ecd --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/boot_ramdisk.c @@ -0,0 +1,119 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/bootconf.h> +#include <sys/bootvfs.h> +#include <sys/filep.h> +#include "util.h" +#include "debug.h" + +extern struct boot_fs_ops bufs_ops, bhsfs_ops; + +extern uint64_t ramdisk_start, ramdisk_end; +struct boot_fs_ops *bfs_ops; +struct boot_fs_ops *bfs_tab[] = {&bufs_ops, &bhsfs_ops, NULL}; + +/* + * This one reads the ramdisk. If fi_memp is set, we copy the + * ramdisk content to the designated buffer. Otherwise, we + * do a "cached" read (set fi_memp to the actual ramdisk buffer). + */ +int +diskread(fileid_t *filep) +{ + uint_t blocknum; + caddr_t diskloc; + + /* add in offset of root slice */ + blocknum = filep->fi_blocknum; + + diskloc = (caddr_t)(ramdisk_start + blocknum * DEV_BSIZE); + if (diskloc + filep->fi_count > (caddr_t)ramdisk_end) { + printf("diskread: reading beyond end of ramdisk\n"); + printf("\tstart = 0x%p, size = 0x%x\n", + diskloc, filep->fi_count); + return (-1); + } + + if (filep->fi_memp) { + bcopy(diskloc, filep->fi_memp, filep->fi_count); + } else { + /* "cached" read */ + filep->fi_memp = diskloc; + } + + return (0); +} + +int +mountroot(char *name) +{ + int i; + + if (verbosemode) + printf("mountroot on ramdisk: 0x%llx-%llx\n", + ramdisk_start, ramdisk_end); + /* try ops in bfs_tab and return the first successful one */ + for (i = 0; bfs_tab[i] != NULL; i++) { + bfs_ops = bfs_tab[i]; + if (BRD_MOUNTROOT(bfs_ops, name) == 0) + return (0); + } + return (-1); +} + +int +unmountroot() +{ + return (BRD_UNMOUNTROOT(bfs_ops)); +} + +int +open(const char *filename, int flags) +{ + return (BRD_OPEN(bfs_ops, (char *)filename, flags)); +} + +int +close(int fd) +{ + return (BRD_CLOSE(bfs_ops, fd)); +} + +ssize_t +read(int fd, void *buf, size_t size) +{ + return (BRD_READ(bfs_ops, fd, buf, size)); +} + +off_t +lseek(int fd, off_t addr, int whence) +{ + return (BRD_SEEK(bfs_ops, fd, addr, whence)); +} diff --git a/usr/src/psm/stand/boot/i386/common/bootenv.c b/usr/src/psm/stand/boot/i386/common/bootenv.c new file mode 100644 index 0000000000..50eb192244 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/bootenv.c @@ -0,0 +1,205 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/bootconf.h> +#include <sys/salib.h> +#include "debug.h" +#include "multiboot.h" +#include "bootprop.h" + +extern void prom_init(char *, void *); +extern void prom_panic(char *); +extern int openfile(char *, char *); +extern int close(int); + + +#define BOOTENV_BUFSIZE 4096 +#define BOOTENV_LINESIZE 256 + +/* + * Note this path name must be consistent with that used + * in the ramdisk construction. + */ +static char *f_bootenv = "/boot/solaris/bootenv.rc"; + + +static void +get_bootenv_prop(char *line, int lineno) +{ + char *p; + int inq; + char *name; + char *val; + char **propp; + + /* + * Trim comments, respecting single quotes, then + * skip any blank lines and leading white space. + */ + inq = 0; + for (p = line; *p; p++) { + if (*p == '\'' || *p == '"') { + inq ^= 1; + } else if ((inq == 0 && *p == '#') || + *p == '\r' || *p == '\n') { + *p = 0; + break; + } + } + + while (*line == ' ' || *line == '\t') + line++; + if (strlen(line) == 0) + return; + + /* + * Anything remaining must be in a fixed format + */ + if ((name = strchr(line, ' ')) == NULL) + goto err; + *name++ = 0; + if (strcmp(line, "setprop") != 0) + goto err; + if ((val = strchr(name, ' ')) == NULL) + goto err; + *val++ = 0; + + p = val + strlen(val) - 1; + if (((*val == '\'' && *p == '\'') || + (*val == '"' && *p == '"')) && val != p) { + *p = 0; + val++; + } + + /* + * An empty name indicates a syntax error but + * an empty value should just be ignored. + */ + if (strlen(name) == 0) + goto err; + if (strlen(val) == 0) + return; + + if (debug & D_BPROP) + printf("%s(%d): %s %s\n", f_bootenv, lineno, name, val); + + (void) bsetprop(NULL, name, val, strlen(val) + 1); + + /* + * We respect certain eeprom(1M) properties internally + * if not overridden on the grub kernel cmdline. + * There should never be multiple definitions, but + * should that occur, the last one is the one that sticks. + */ + propp = NULL; + if (strcmp(name, "boot-file") == 0) + propp = &bootfile_prop; + else if (strcmp(name, "console") == 0) + propp = &console_prop; + else if (strcmp(name, "input-device") == 0) + propp = &inputdevice_prop; + else if (strcmp(name, "output-device") == 0) + propp = &outputdevice_prop; + + if (propp) { + if (*propp) + bkmem_free(*propp, strlen(*propp) + 1); + *propp = bkmem_zalloc(strlen(val)+1); + strcpy(*propp, val); + } + + return; + +err: + printf("%s: syntax error on line %d\n", f_bootenv, lineno); +} + +int +get_bootenv_props() +{ + int fd; + char *line; + char *buf; + int n, bufcnt; + int c, linecnt; + char *bp, *lp; + int lineno = 1; + int err; + + fd = openfile(f_bootenv, 0); + if (fd == -1) { + printf("error opening %s\n", f_bootenv); + return (0); + } + + buf = bkmem_zalloc(BOOTENV_BUFSIZE); + line = bkmem_zalloc(BOOTENV_LINESIZE); + + lp = line; + *lp = 0; + bufcnt = 0; + linecnt = 0; + err = 0; + + for (;;) { + if (bufcnt == 0) { + n = read(fd, buf, BOOTENV_BUFSIZE); + if (n <= 0) + goto exit; + bufcnt = n; + bp = buf; + } + while (bufcnt > 0) { + if ((c = *bp++) == '\n') { + get_bootenv_prop(line, lineno++); + linecnt = 0; + lp = line; + err = 0; + } else if (linecnt < BOOTENV_LINESIZE-1) { + *lp++ = c; + linecnt++; + } else if (err == 0) { + printf("%s: line %d exceeds maximum (%d)\n", + f_bootenv, lineno, BOOTENV_LINESIZE); + err = 1; + } + bufcnt--; + *lp = 0; + } + } + +exit: + + bkmem_free(buf, BOOTENV_BUFSIZE); + bkmem_free(line, BOOTENV_LINESIZE); + + close(fd); + + return (0); +} diff --git a/usr/src/psm/stand/boot/i386/common/bootflags.c b/usr/src/psm/stand/boot/i386/common/bootflags.c new file mode 100644 index 0000000000..95a1c706e5 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/bootflags.c @@ -0,0 +1,279 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Parse the boot arguments. + */ + +#include <sys/reboot.h> +#include <sys/promif.h> +#include <sys/boot.h> +#include <sys/salib.h> +#include <sys/param.h> +#include <util/getoptstr.h> +#include "bootprop.h" +#include "debug.h" + +int boothowto; +int verbosemode; +char *bootprog; +char *bootfile; +char bootargs[MAXNAMELEN]; +char bootprop[MAXPATHLEN]; +static char bootfile_buf[MAXNAMELEN]; +static char bootprog_buf[MAXNAMELEN]; +static int grub_line_present; + + +/* + * Parse the boot arguments and place results in bootprog, bootfile, + * bootargs, and bootprops. Note that anything unknown is treated as + * [kern-args] and is passed to kernel as is. + * + * The format for the GRUB args is: + * /boot/multiboot [bootfile [-D path]] [-Vadvk] + * [-B prop=value[,prop=value...]] [kern-args] + * + * The format for the eeprom boot-file is: + * [bootfile [-D path]] [-Vadvk] [kern-args] + * + * The grub line takes precedence + */ +static void +get_bootargs(char *args, int grub) +{ + struct gos_params params; + const char *cp, *SPC = " \t"; + char *np; + size_t npres; + int c; + + /* parse grub bootprog (multiboot) and -B */ + if (grub) { + char *dash_B = strstr(args, " -B"); + if (dash_B) { + /* copy -B arg to bootprop */ + cp = strtok(dash_B + 3, SPC); + (void) strncpy(bootprop, cp, MAXPATHLEN - 1); + bootprop[MAXPATHLEN - 1] = 0; + + /* move the end string forward */ + cp = strtok(NULL, ""); + if (cp) { + *dash_B++ = ' '; + while (*dash_B++ = *cp++) + ; + } else { + *dash_B = 0; + } + } + + /* get the multiboot prog (must be present) */ + bootprog = strtok(args, SPC); + strcpy(bootprog_buf, bootprog); + bootprog = bootprog_buf; + bootfile = strtok(NULL, SPC); + grub_line_present = (bootfile != NULL); + } else { + /* don't process bootfile_prop if grub line is present */ + if (grub_line_present) { + if (args && verbosemode) + printf("grub line specified, ignoring " + "boot-file setting %s in bootenv.rc\n", + args); + return; + } + bootfile = strtok(args, SPC); + } + + /* check for leading kmdb/kadb for compatibility */ + if (bootfile == NULL) + return; + + if (*bootfile == '-') { + args = bootfile; + /* XXX undo strtok, if have additional tokens */ + if (strtok(NULL, "")) + args[strlen(bootfile)] = ' '; + bootfile = NULL; + } else { + if (strcmp(bootfile, "kmdb") == 0 || + strcmp(bootfile, "kadb") == 0) { + bootfile = NULL; + boothowto |= RB_KMDB; + } else { + /* copy to buf to avoid being overwritten */ + strcpy(bootfile_buf, bootfile); + bootfile = bootfile_buf; + } + /* get the remainder of string */ + args = strtok(NULL, ""); + if (args == NULL) + args = ""; + } + + params.gos_opts = "CD:Vadvk"; + params.gos_strp = args; + getoptstr_init(¶ms); + while ((c = getoptstr(¶ms)) != -1) { + extern void check_iopath(void); + + switch (c) { + case 'V': /* Undocumented. */ + verbosemode = 1; + break; + case 'C': /* Undocumented for checking IO path */ + check_iopath(); + /* never returns here */ + break; + case 'D': + if (bootfile || (boothowto & RB_KMDB) == 0) { + printf("boot: -D invalid without kadb/kmdb. " + "Ignoring.\n"); + break; + } + if (params.gos_optarglen >= sizeof (bootfile_buf)) { + printf("boot: -D argument too long. " + "Ignoring.\n"); + break; + } + (void) strncpy(bootfile_buf, params.gos_optargp, + params.gos_optarglen); + bootfile_buf[params.gos_optarglen] = '\0'; + bootfile = bootfile_buf; + break; + + /* Consumed by the kernel */ + case 'a': /* Undocumented. */ + boothowto |= RB_ASKNAME; + break; + case 'd': + boothowto |= RB_DEBUGENTER; + break; + case 'v': + boothowto |= RB_VERBOSE; + break; + case 'k': + boothowto |= RB_KMDB; + break; + + case '?': + /* + * Error. Either an unrecognized option, or an option + * without an argument. Check for the latter. + */ + switch (params.gos_last_opt) { + case 'D': + case 'O': + printf("boot: -%c flag missing required " + "argument. Ignoring.\n", + params.gos_last_opt); + break; + default: + /* Unrecognized flag: stop. */ + goto done; + } + break; + + default: + printf("boot: Ignoring unimplemented option -%c.", c); + } + } +done: + + /* + * Construct the arguments for the standalone. + */ + *bootargs = '\0'; + np = bootargs; + + /* + * Start with '-' if we encountered an unrecognized option or if we + * need to pass flags to the standalone. + */ + if (c == '?' || (boothowto & + /* These flags are to be passed to the kernel. */ + (RB_ASKNAME | RB_DEBUGENTER | RB_VERBOSE | + RB_KMDB))) { + *np++ = '-'; + if (boothowto & RB_ASKNAME) + *np++ = 'a'; + if (boothowto & RB_DEBUGENTER) + *np++ = 'd'; + if (boothowto & RB_VERBOSE) + *np++ = 'v'; + if (boothowto & RB_KMDB) + *np++ = 'k'; + + /* + * If we didn't encounter an unrecognized flag and there's + * more to copy, add a space to separate these flags. + * (Otherwise, unrecognized flags can be appended since we + * started this word with a dash.) + */ + if (c == -1 && params.gos_strp[0] != '\0') + *np++ = ' '; + } + + npres = sizeof (bootargs) - (size_t)(np - bootargs); + + /* + * Unrecognized flag. gos_errp contains the remaining bootargs + */ + + if (c == '?') + cp = params.gos_errp; + else + cp = params.gos_strp; + + while (npres > 0 && (*np++ = *cp++) != '\0') + npres--; + *np = 0; + + if (verbosemode) { + printf("bootprog = %s\n", bootprog); + if (bootfile) + printf("bootfile = %s\n", bootfile); + printf("boot-args = %s\n", bootargs); + printf("bootprop = %s\n", bootprop); + } +} + +void +get_grub_bootargs(char *args) +{ + /* grub args is always present */ + get_bootargs(args, 1); +} + +void +get_eeprom_bootargs(char *args) +{ + if (args) /* boot-file prop may not be present */ + get_bootargs(args, 0); +} diff --git a/usr/src/psm/stand/boot/i386/common/bootops.c b/usr/src/psm/stand/boot/i386/common/bootops.c new file mode 100644 index 0000000000..60b320e0fd --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/bootops.c @@ -0,0 +1,193 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/promif.h> +#include <sys/bootconf.h> +#include <sys/bootvfs.h> +#include <sys/varargs.h> +#include "standalloc.h" +#include "bootprop.h" +#include "util.h" +#include "biosint.h" +#include "debug.h" + +#define dprintf if (debug & D_BOP) printf + +extern struct memlist *pinstalledp, *pfreelistp, *vfreelistp, *pbooterp; +extern struct memlist *ppcimemp, *pramdiskp; +extern struct bootops *bop; + +/* Misc memlist stuff */ +extern void update_memlist(char *, char *, struct memlist **); + +/*ARGSUSED*/ +static caddr_t +bkern_alloc(struct bootops *bop, caddr_t virt, size_t size, int align) +{ + if (size < PAGESIZE) + return (bkmem_alloc(size)); + + return (resalloc(((virt == 0) ? RES_BOOTSCRATCH : RES_CHILDVIRT), + size, virt, align)); +} + +/*ARGSUSED*/ +static caddr_t +bkern_ealloc(struct bootops *bop, caddr_t virt, size_t size, int align, + int flags) +{ + uint_t delta; + + /* sanity check */ + if (size == 0) + return ((caddr_t)0); + + if (flags == BOPF_X86_ALLOC_IDMAP || + flags == BOPF_X86_ALLOC_PHYS) { + + /* align to PAGESIZE */ + delta = (uint_t)virt & (PAGESIZE - 1); + size += delta; + size = roundup(size, PAGESIZE); + + switch (flags) { + case BOPF_X86_ALLOC_IDMAP: + return ((caddr_t)idmap_mem( + (uint32_t)virt, size, align)); + /*NOTREACHED*/ + case BOPF_X86_ALLOC_PHYS: + return ((caddr_t)phys_alloc_mem(size, align)); + /*NOTREACHED*/ + } + } + + return (resalloc(((virt == 0) ? RES_BOOTSCRATCH : RES_CHILDVIRT), + size, virt, align)); +} + +/*ARGSUSED*/ +static void +bkern_free(struct bootops *bop, caddr_t virt, size_t size) +{ + resfree(virt, size); +} + +void +install_memlistptrs(void) +{ + /* allocate boot_mem structure */ + bop->boot_mem->physinstalled = pinstalledp; + bop->boot_mem->physavail = pfreelistp; + bop->boot_mem->pcimem = ppcimemp; + + dprintf("physinstalledp = 0x%p\n", + (void *)bop->boot_mem->physinstalled); + dprintf("pfreelistp = 0x%p\n", + (void *)bop->boot_mem->physavail); + dprintf("ppcimemp = 0x%p\n", + (void *)bop->boot_mem->pcimem); +} + +/*ARGSUSED*/ +static void +bkern_printf(struct bootops *bop, char *fmt, ...) +{ + va_list adx; + + va_start(adx, fmt); + prom_vprintf(fmt, adx); + va_end(adx); +} + +/* + * Translate register structure fit what /platform/i86pc/biosint expects. + */ +static void +bkern_doint(struct bootops *bop, int intnum, struct bop_regs *rp) +{ + struct int_pb ic; + + ic.ax = rp->eax.word.ax; + ic.bx = rp->ebx.word.bx; + ic.cx = rp->ecx.word.cx; + ic.dx = rp->edx.word.dx; + ic.bp = rp->ebp.word.bp; + ic.si = rp->esi.word.si; + ic.di = rp->edi.word.di; + ic.ds = rp->ds; + ic.es = rp->es; + + if (debug & D_BIOS) + printf("bkern_doint: int = 0x%x, ax 0x%x, dx 0x%x\n", + intnum, ic.ax, ic.dx); + rp->eflags = bios_doint(intnum, &ic); + if (debug & D_BIOS) + printf("bios_doint ret = %d, ax 0x%x, dx 0x%x\n", + rp->eflags, ic.ax, ic.dx); + + rp->eax.word.ax = ic.ax; + rp->ebx.word.bx = ic.bx; + rp->ecx.word.cx = ic.cx; + rp->edx.word.dx = ic.dx; + rp->ebp.word.bp = ic.bp; + rp->esi.word.si = ic.si; + rp->edi.word.di = ic.di; + rp->ds = ic.ds; + rp->es = ic.es; +} + +bootops_t bootops = +{ + /* reduced bootops BO_VERSION == 11 ... */ + + BO_VERSION, /* "major" version number */ + 0, /* memlist pointers */ + bkern_alloc, /* G.P. memory allocator */ + bkern_free, /* G.P. memory release */ + bgetproplen, /* proplen */ + bgetprop, /* getprop */ + bnextprop, /* nextprop */ + bkern_printf, /* limited printf for kobj */ + bkern_doint, /* biosint */ + bkern_ealloc +}; + +void +setup_bootops(void) +{ + /* + * Initialize the bootops struct and establish a pointer to it ("bop") + * for use by standalone clients. + */ + bop = &bootops; + bop->boot_mem = bkmem_zalloc(sizeof (struct bsys_mem)); + install_memlistptrs(); + if (verbosemode) + printf("setup bootops\n"); +} diff --git a/usr/src/psm/stand/boot/i386/common/bootprop.c b/usr/src/psm/stand/boot/i386/common/bootprop.c new file mode 100644 index 0000000000..5641f6b1f1 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/bootprop.c @@ -0,0 +1,331 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/bootconf.h> +#include <sys/bootprops.h> +#include <sys/salib.h> +#include "debug.h" +#include "multiboot.h" + +extern void install_memlistptrs(); +#define dprintf if (debug & D_BPROP) printf + +struct pseudoprop { + char *pp_name; + void (*pp_func)(); +} pp_list[] = { + { "memory_update", install_memlistptrs }, + { NULL, NULL} +}; + +struct bootprop { + struct bootprop *bp_next; + char *bp_name; + void *bp_val; + int bp_len; +}; + +static struct bootprop *bp_list; + +static int find_pseudo(char *); +static struct bootprop *find_prop(char *); +static struct bootprop *alloc_prop(char *); +static void set_propval(struct bootprop *, void *, int); +static void setup_rarp_props(struct sol_netinfo *); + +/* + * Return the length of the "name"d property's value. + */ +/*ARGSUSED*/ +int +bgetproplen(struct bootops *bop, char *name) +{ + struct bootprop *bp; + + dprintf("bgetproplen: name = %s\n", name); + bp = find_prop(name); + return (bp ? bp->bp_len : BOOT_FAILURE); +} + +/*ARGSUSED*/ +int +bgetprop(struct bootops *bop, char *name, void *value) +{ + struct bootprop *bp; + + dprintf("bgetprop: name = %s\n", name); + if (find_pseudo(name) == BOOT_SUCCESS) + return (BOOT_SUCCESS); + + bp = find_prop(name); + if (!bp) + return (BOOT_FAILURE); + + /* Found the property in question; return its value */ + (void) bcopy(bp->bp_val, value, bp->bp_len); + return (BOOT_SUCCESS); +} + +/*ARGSUSED*/ +char * +bnextprop(struct bootops *bop, char *prev) +{ + struct bootprop *bp = find_prop(prev); + + if (bp == NULL || bp->bp_next == NULL) + return (NULL); + return (bp->bp_next->bp_name); +} + +/*ARGSUSED*/ +int +bsetprop(struct bootops *bop, char *name, char *value, int len) +{ + struct bootprop *bp; + + dprintf("bsetprop: name = %s, len = %d", name, len); + bp = find_prop(name); + if (bp == NULL) + bp = alloc_prop(name); + + set_propval(bp, value, len); + return (BOOT_SUCCESS); +} + +int +find_pseudo(char *name) +{ + struct pseudoprop *pp = pp_list; + + while (pp->pp_name) { + if (strcmp(name, pp->pp_name) == 0) { + (*pp->pp_func)(); + dprintf("find_pseudo: prop = %s\n", name); + return (BOOT_SUCCESS); + } + pp++; + } + return (BOOT_FAILURE); +} + +struct bootprop * +find_prop(char *name) +{ + struct bootprop *bp = bp_list; + + if (name == NULL || *name == '\0') + return (bp); + + while (bp) { + if (strcmp(name, bp->bp_name) == 0) + break; + bp = bp->bp_next; + } + return (bp); +} + +static struct bootprop * +alloc_prop(char *name) +{ + struct bootprop *bp = bkmem_zalloc(sizeof (*bp)); + + dprintf("alloc_prop: name = %s\n", name); + bp->bp_name = bkmem_alloc(strlen(name) + 1); + (void) strcpy(bp->bp_name, name); + bp->bp_next = bp_list; + bp_list = bp; + + return (bp); +} + +static void +set_propval(struct bootprop *bp, void *value, int len) +{ + dprintf("set_propval: name = %s\n", bp->bp_name); + + if (bp->bp_val) + bkmem_free(bp->bp_val, bp->bp_len); + bp->bp_len = len; + bp->bp_val = bkmem_alloc(len); + bcopy(value, bp->bp_val, len); +} + +void +setup_bootprop(void) +{ + extern char bootprop[], bootargs[]; + extern char *bootprog; + extern uint64_t ramdisk_start, ramdisk_end; + extern multiboot_info_t *mbi; + char *name, *val, *cp; + int netboot = 0; + int stdout_val = 0; /* for a dummy property */ + + if (verbosemode) + printf("setup boot properties.\n"); + + dprintf("process command line bootargs: %s\n", bootprop); + cp = bootprop; + while (cp && *cp) { + name = strtok(cp, "="); + val = strtok(NULL, ""); + if (val == NULL) { + val = "true"; + cp = NULL; /* terminate loop */ + } else if (*val != '\'' && *val != '\"') { + cp = strtok(val, ","); + cp = strtok(NULL, ""); + } else { + /* look for closing single or double quote */ + cp = val + 1; + while (cp && *cp != *val) + ++cp; + if (cp == NULL) { + printf("missing %c in property %s.\n", + *val, name); + } else { + *cp++ = '\0'; + if (*cp == ',') + cp++; + else if (*cp != '\0') { + printf("syntax error in GRUB -B option:" + " ignore %s\n", cp); + cp = NULL; /* terminate */ + } + } + val++; + } + + (void) bsetprop(NULL, name, val, strlen(val) + 1); + } + + (void) bsetprop(NULL, "bootprog", bootprog, strlen(bootprog) + 1); + (void) bsetprop(NULL, "boot-args", bootargs, strlen(bootargs) + 1); + (void) bsetprop(NULL, "ramdisk_start", (char *)&ramdisk_start, + sizeof (ramdisk_start)); + (void) bsetprop(NULL, "ramdisk_end", (char *)&ramdisk_end, + sizeof (ramdisk_end)); + + /* a bunch of fixed properties */ + (void) bsetprop(NULL, "mfg-name", "i86pc", sizeof ("i86pc")); + (void) bsetprop(NULL, "impl-arch-name", "i86pc", sizeof ("i86pc")); + + /* figure out the boot device */ + if (MB_CHECK_FLAG(mbi->flags, 2)) { + char str[3]; + uint_t boot_device = (mbi->boot_device >> 24) & 0xff; + if (boot_device == MB_NETWORK_DRIVE) + netboot++; + (void) snprintf(str, 3, "%x", boot_device); + bsetprop(NULL, "bios-boot-device", str, 3); + } else { /* assume netboot? */ + netboot++; + } + + /* + * In the netboot case, drives_info is overloaded with + * the dhcp ack. This is not multiboot compliant and + * requires special pxegrub! + */ + if (netboot) { + if (verbosemode) + printf("booting from network\n"); + + if (mbi->drives_length == 0) { + if (verbosemode) { + printf("no network info, " + "need a GRUB with Solaris enhancements\n"); + } + } else { + struct sol_netinfo *sip = + (struct sol_netinfo *)mbi->drives_addr; + switch (sip->sn_infotype) { + case SN_TYPE_BOOTP: + bsetprop(NULL, BP_BOOTP_RESPONSE, + (void *)mbi->drives_addr, + mbi->drives_length); + break; + case SN_TYPE_RARP: + setup_rarp_props(sip); + break; + default: + printf("invalid network info: type %d\n", + sip->sn_infotype); + break; + }; + } + } + + /* dummy properties needed by Install miniroot */ + bsetprop(NULL, "stdout", (char *)&stdout_val, sizeof (stdout_val)); +} + +#define BUFLEN 64 + +static void +setup_rarp_props(struct sol_netinfo *sip) +{ + char *buf = bkmem_alloc(BUFLEN); /* to hold ip/mac addrs */ + uint8_t *val; + + val = (uint8_t *)&sip->sn_ciaddr; + (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", + val[0], val[1], val[2], val[3]); + bsetprop(NULL, BP_HOST_IP, buf, strlen(buf) + 1); + + val = (uint8_t *)&sip->sn_siaddr; + (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", + val[0], val[1], val[2], val[3]); + bsetprop(NULL, BP_SERVER_IP, buf, strlen(buf) + 1); + + if (sip->sn_giaddr != 0) { + val = (uint8_t *)&sip->sn_giaddr; + (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", + val[0], val[1], val[2], val[3]); + bsetprop(NULL, BP_ROUTER_IP, buf, strlen(buf) + 1); + } + + if (sip->sn_netmask != 0) { + val = (uint8_t *)&sip->sn_netmask; + (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", + val[0], val[1], val[2], val[3]); + bsetprop(NULL, BP_SUBNET_MASK, buf, strlen(buf) + 1); + } + + if (sip->sn_mactype != 4 || sip->sn_maclen != 6) { + printf("unsupported mac type %d, mac len %d\n", + sip->sn_mactype, sip->sn_maclen); + return; + } + + val = sip->sn_macaddr; + (void) snprintf(buf, BUFLEN, "%x:%x:%x:%x:%x:%x", + val[0], val[1], val[2], val[3], val[4], val[5]); + bsetprop(NULL, BP_BOOT_MAC, buf, strlen(buf) + 1); +} diff --git a/usr/src/psm/stand/boot/i386/common/bootprop.h b/usr/src/psm/stand/boot/i386/common/bootprop.h new file mode 100644 index 0000000000..004c8049d0 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/bootprop.h @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _BOOTPROP_H +#define _BOOTPROP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Global variables which will be exported as boot properties in + * i386_bootprop.c. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/bootconf.h> +#include <sys/obpdefs.h> +#include <sys/param.h> + +extern char *impl_arch_name; +extern char *module_path; + +/* + * bootenv.rc properties + */ +extern char *bootfile_prop; +extern char *inputdevice_prop; +extern char *outputdevice_prop; +extern char *console_prop; + +/* These are actually in intel/bootprop.c. */ +extern int bgetproplen(struct bootops *, char *); +extern int bgetprop(struct bootops *, char *, void *); +extern int bsetprop(struct bootops *, char *, void *, int); +extern char *bnextprop(struct bootops *, char *); + +extern void setup_bootprop(void); +extern void get_grub_bootargs(char *); +extern void get_eeprom_bootargs(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _BOOTPROP_H */ diff --git a/usr/src/psm/stand/boot/i386/common/chario.h b/usr/src/psm/stand/boot/i386/common/chario.h new file mode 100644 index 0000000000..7023c17134 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/chario.h @@ -0,0 +1,145 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1995-1998, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _CHARIO_H +#define _CHARIO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains all character i/o related structures + * and defines. + * + * Project: Devconf + * Author : Rick McNeal + * Date : 2-Nov-1994 + */ +struct _char_io_ { + struct _char_io_ *next; /* next i/o member */ + char *name; /* Name for stats */ + int in, out, errs; /* Simple stats */ + int flags; /* control bits */ + int vals; /* state bits */ + int addr; /* physical address */ + char *cookie; /* for driver use */ + char (*getc)(struct _char_io_ *); /* returns character */ + void (*putc)(struct _char_io_ *, char); /* outputs one character */ + int (*avail)(struct _char_io_ *); /* returns 1 if char avail */ + void (*clear)(struct _char_io_ *); /* clear screen */ + void (*set)(struct _char_io_ *, int, int); /* set cursor pos. */ +}; +typedef struct _char_io_ _char_io_t, *_char_io_p; + +int serial_port_enabled(int port); + +#define CHARIO_IGNORE_ALL 0x0001 /* don't output to this dev */ +#define CHARIO_DISABLED 0x0002 /* error occured and ports not used */ +#define CHARIO_OUT_ENABLE 0x0004 /* Device does output */ +#define CHARIO_IN_ENABLE 0x0008 /* Device does input */ +#define CHARIO_IGNORE_CD 0x0010 /* Device shouldn't wait for CD */ +#define CHARIO_RTS_DTR_OFF 0x0020 /* Device shouldn't set rts/dtr */ +#define CHARIO_INIT 0x0040 /* Device should be (re)initialized */ + +/* + * Use this macro when debugging the output side of your driver. This + * will prevent any printf's from your driver causing an infinite loop + */ +#define PRINT(p, x) \ +{ p->flags |= CHARIO_IGNORE_ALL; printf x; p->flags &= ~CHARIO_IGNORE_ALL; } + +/* + * Defines for the serial port + */ + +#define SERIAL_FIFO_FLUSH 16 /* maximum number of chars to flush */ + +/* ---- Bit 11 defines direct serial port ---- */ +#define SDIRECT 0x1000 + +/* ---- Bits 9-10 define flow control ---- */ +#define SSOFT 0x800 +#define SHARD 0x400 + +/* ---- Bits 5-8 define baud rate ---- */ +#define S110 0x00 +#define S150 0x20 +#define S300 0x40 +#define S600 0x60 +#define S1200 0x80 +#define S2400 0xa0 +#define S4800 0xc0 +#define S9600 0xe0 +#define S19200 0x100 +#define S38400 0x120 +#define S57600 0x140 +#define S76800 0x160 +#define S115200 0x180 +#define S153600 0x1a0 +#define S230400 0x1c0 +#define S307200 0x1e0 +#define S460800 0x200 + +/* ---- Bits 3 & 4 are parity ---- */ +#define PARITY_NONE 0x10 +#define PARITY_ODD 0x08 +#define PARITY_EVEN 0x18 + +/* ---- Bit 2 is stop bit ---- */ +#define STOP_1 0x00 +#define STOP_2 0x04 + +/* ---- Bits 0 & 1 are data bits ---- */ +#define DATA_8 0x03 +#define DATA_7 0x02 +#define DATA_6 0x01 +#define DATA_5 0x00 + +/* ---- Line Status ---- */ +#define SERIAL_TIMEOUT 0x80 +#define SERIAL_XMITSHFT 0x40 +#define SERIAL_XMITHOLD 0x20 +#define SERIAL_BREAK 0x10 +#define SERIAL_FRAME 0x08 +#define SERIAL_PARITY 0x04 +#define SERIAL_OVERRUN 0x02 +#define SERIAL_DATA 0x01 + +/* + * Bit style flag operations for 32bit ints only + */ +#define BCLR(x) x &= ~(1 << y) +#define BSET(x, y) x |= (1 << y) +#define BISSET(x, y) x & (1 << y) + +#ifdef __cplusplus +} +#endif + +#endif /* _CHARIO_H */ diff --git a/usr/src/psm/stand/boot/i386/common/check_iopath.c b/usr/src/psm/stand/boot/i386/common/check_iopath.c new file mode 100644 index 0000000000..749d89a2cc --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/check_iopath.c @@ -0,0 +1,96 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/promif.h> +#include "multiboot.h" +#include "util.h" +#include "debug.h" + +extern multiboot_info_t *mbi; + +/* return the number of bits set to 1 */ +static uint_t +count_bits(int val) +{ + int nbits = 0; + + while (val = (val ^ (val - 1))) + nbits++; + + return (nbits); +} + +/* + * GRUB has loaded two identical modules, we compare the content + * to check for potential problems in the BIOS I/O code path. + * Andromeda appears to have problems with USB DVD drive, but IDE + * drive works fine. This is a simple way to check it. + */ +void +check_iopath(void) +{ + mb_module_t *mod; + char errbits = 0; + uchar_t *cp1, *cp2; + uint_t i, size1, size2; + + /* check # modules */ + if (mbi->mods_count != 2) { + printf("The number of modules is not 2.\n"); + panic("reboot with modified GRUB menu"); + } + + /* check module sizes */ + mod = (mb_module_t *)mbi->mods_addr; + cp1 = (uchar_t *)mod[0].mod_start; + cp2 = (uchar_t *)mod[1].mod_start; + size1 = mod[0].mod_end - mod[0].mod_start; + size2 = mod[1].mod_end - mod[1].mod_start; + printf("module 1: start = 0x%x, size = 0x%x (%s)\n", + cp1, size1, mod[0].string); + printf("module 2: start = 0x%x, size = 0x%x (%s)\n", + cp2, size2, mod[1].string); + + if (size1 != size2) { + printf("Module sizes are different!\n"); + panic("Check FAILED"); + } + + for (i = 0; i < size1; i++) { + if (cp1[i] != cp2[i]) { + printf("byte 0x%x differ: %2x, %2x\n", + i, cp1[i], cp2[i]); + errbits += count_bits(cp1[i] ^ cp2[i]); + } + } + if (errbits) + panic("Check FAILED: err bit rate %d in %d bytes\n", + errbits, size1); + else + panic("Check PASSED: no bit error\n"); +} diff --git a/usr/src/psm/stand/boot/i386/common/console.c b/usr/src/psm/stand/boot/i386/common/console.c new file mode 100644 index 0000000000..fd7c4a4b9f --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/console.c @@ -0,0 +1,592 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/bootsvcs.h> +#include <sys/varargs.h> +#include <sys/promif.h> +#include <sys/salib.h> +#include "serial.h" +#include "chario.h" +#include "vga.h" +#include "console.h" +#include "debug.h" +#include "graphics.h" +#include "bootprop.h" + +static int cons_color = CONS_COLOR; +int console = CONS_SCREEN_TEXT; +/* or CONS_SCREEN_GRAPHICS, CONS_TTYA, CONS_TTYB */ +static int serial_ischar(void); +static int serial_getchar(void); +static void serial_putchar(int); +static void serial_adjust_prop(void); +static int console_state = 0; + +/* Clear the screen and initialize VIDEO, XPOS and YPOS. */ +static void +clear_screen(void) +{ + /* + * XXX should set vga mode so we don't depend on the + * state left by the boot loader + */ + vga_clear(cons_color); + vga_setpos(0, 0); +} + +void +text_init(void) +{ + set_videomode(0x3); + clear_screen(); +} + +/* Put the character C on the screen. */ +static void +screen_putchar(int c) +{ + int row, col; + + vga_getpos(&row, &col); + switch (c) { + case '\r': + vga_setpos(row, 0); + break; + + case '\b': + if (col > 0) + vga_setpos(row, col - 1); + break; + + case '\n': + if (row < VGA_TEXT_ROWS - 1) + vga_setpos(row + 1, col); + else + vga_scroll(cons_color); + break; + + default: + vga_drawc(c, cons_color); + if (col < VGA_TEXT_COLS -1) + vga_setpos(row, col + 1); + else if (row < VGA_TEXT_ROWS - 1) + vga_setpos(row + 1, 0); + else { + vga_setpos(row, 0); + vga_scroll(cons_color); + } + break; + } +} + +/* serial port stuff */ +static int port; + +static void +serial_init(void) +{ + extern void mdelay(); + + /* initialize only once */ + if (port != 0) + return; + + /* + * wait 2 seconds for serial console redirection to settle + * NOTE we only need to wait if BIOS console redirection + * is enabled, but we can't really tell without working + * through a scary Microsoft license. + */ + mdelay(2000); + + switch (console) { + case CONS_TTYA: + port = 0x3f8; + break; + case CONS_TTYB: + port = 0x2f8; + break; + } + + outb(port + ISR, 0x20); + if (inb(port + ISR) & 0x20) { + /* + * 82510 chip is present + */ + outb(port + DAT+7, 0x04); /* clear status */ + outb(port + ISR, 0x40); /* set to bank 2 */ + outb(port + MCR, 0x08); /* IMD */ + outb(port + DAT, 0x21); /* FMD */ + outb(port + ISR, 0x00); /* set to bank 0 */ + } else { + /* + * set the UART in FIFO mode if it has FIFO buffers. + * use 16550 fifo reset sequence specified in NS + * application note. disable fifos until chip is + * initialized. + */ + outb(port + FIFOR, 0x00); /* clear */ + outb(port + FIFOR, FIFO_ON); /* enable */ + outb(port + FIFOR, FIFO_ON|FIFORXFLSH); /* reset */ + outb(port + FIFOR, + FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80); + if ((inb(port + ISR) & 0xc0) != 0xc0) { + /* + * no fifo buffers so disable fifos. + * this is true for 8250's + */ + outb(port + FIFOR, 0x00); + } + } + + /* disable interrupts */ + outb(port + ICR, 0); + + /* adjust setting based on tty properties */ + serial_adjust_prop(); + + /* + * Do a full reset to match console behavior. + * In verbose mode (-V), we only reset ansi attributes, + * leaving existing output on screen. + * 0x1B + c - reset everything + * 0x1B + + * [ - attribute change (blick, inverse, color, etc.) + * 0 - attribute value + * m - terminate escape sequence + * + */ + if (verbosemode) { + serial_putchar(0x1B); + serial_putchar('['); + serial_putchar('0'); + serial_putchar('m'); + } else { + serial_putchar(0x1B); + serial_putchar('c'); + } +} + +/* adjust serial port based on properties */ +static void +serial_adjust_prop(void) +{ + int plen; + char propname[20], propval[20]; + + (void) snprintf(propname, sizeof (propname), "tty%c-mode", + 'a' + console - CONS_TTYA); + plen = bgetproplen(NULL, propname); + if (plen > 0 && plen <= sizeof (propval)) { + char *p; + ulong_t baud; + uchar_t lcr = 0; + + /* property is of the form: "9600,8,n,1,-" */ + bgetprop(NULL, propname, propval); + p = strtok(propval, ","); + if (strcmp(p, "110") == 0) + baud = ASY110; + else if (strcmp(p, "150") == 0) + baud = ASY150; + else if (strcmp(p, "300") == 0) + baud = ASY300; + else if (strcmp(p, "600") == 0) + baud = ASY600; + else if (strcmp(p, "1200") == 0) + baud = ASY1200; + else if (strcmp(p, "2400") == 0) + baud = ASY2400; + else if (strcmp(p, "4800") == 0) + baud = ASY4800; + else if (strcmp(p, "19200") == 0) + baud = ASY19200; + else if (strcmp(p, "38400") == 0) + baud = ASY38400; + else if (strcmp(p, "57600") == 0) + baud = ASY57600; + else if (strcmp(p, "115200") == 0) + baud = ASY115200; + else + baud = ASY9600; + + /* set baud */ + outb(port + LCR, DLAB); + outb(port + DAT+DLL, baud & 0xff); + outb(port + DAT+DLH, (baud >> 8) & 0xff); + + p = strtok(NULL, ","); + if (p) { + switch (*p) { + case '5': + lcr |= BITS5; + break; + case '6': + lcr |= BITS6; + break; + case '7': + lcr |= BITS7; + break; + case '8': + default: + lcr |= BITS8; + break; + } + } + + p = strtok(NULL, ","); + if (p) { + switch (*p) { + case 'n': + lcr |= PARITY_NONE; + break; + case 'o': + lcr |= PARITY_ODD; + break; + case 'e': + default: + lcr |= PARITY_EVEN; + break; + } + } + + p = strtok(NULL, ","); + if (p) { + switch (*p) { + case '1': + /* STOP1 is 0 */ + break; + default: + lcr |= STOP2; + break; + } + } + + /* set parity bits */ + outb(port + LCR, lcr); + } + + (void) snprintf(propname, sizeof (propname), + "tty%c-rts-dtr-off", 'a' + console - CONS_TTYA); + plen = bgetproplen(NULL, propname); + if (plen > 0 && plen <= sizeof (propval)) { + char *p; + uchar_t mcr = DTR | RTS; + bgetprop(NULL, propname, propval); + if (propval[0] != 'f' && propval[0] != 'F') + mcr = 0; + /* set modem control bits */ + outb(port + MCR, mcr | OUT2); + } +} + +void +console_init(char *bootstr) +{ + char *cons; + + console = CONS_INVALID; + + cons = strstr(bootstr, "console="); + if (cons) { + cons += strlen("console="); + if (strncmp(cons, "ttya", 4) == 0) + console = CONS_TTYA; + else if (strncmp(cons, "ttyb", 4) == 0) + console = CONS_TTYB; + else if (strncmp(cons, "graphics", 9) == 0) + console = CONS_SCREEN_GRAPHICS; + else if (strncmp(cons, "text", 4) == 0) + console = CONS_SCREEN_TEXT; + } + + /* + * If no console device specified, default to text. + * Remember what was specified for second phase. + */ + console_state = console; + if (console == CONS_INVALID) + console = CONS_SCREEN_TEXT; + + switch (console) { + case CONS_TTYA: + case CONS_TTYB: + /* leave initialization till later, when we know tty mode */ + break; + case CONS_SCREEN_TEXT: + default: + clear_screen(); + kb_init(); + break; + /* + * if console is CONS_SCREEN_GRAPHICS, + * initialize it in console_init2() + */ + } +} + +/* + * Second phase of possible console redirection, + * based on input-device & output-device eeprom(1M) properties. + * Also support a unified "console" property. + */ +void +console_init2(char *inputdev, char *outputdev, char *consoledev) +{ + int cons = CONS_INVALID; + + if (console_state == CONS_INVALID) { + + if (consoledev) { + if (strcmp(consoledev, "ttya") == 0) + cons = CONS_TTYA; + else if (strcmp(consoledev, "ttyb") == 0) + cons = CONS_TTYB; + else if (strcmp(consoledev, "text") == 0) + cons = CONS_SCREEN_TEXT; + else if (strcmp(consoledev, "graphics") == 0) + cons = CONS_SCREEN_GRAPHICS; + } + + if (cons == CONS_INVALID) { + if (inputdev) { + if (strcmp(inputdev, "ttya") == 0) + cons = CONS_TTYA; + else if (strcmp(inputdev, "ttyb") == 0) + cons = CONS_TTYB; + } + if (outputdev) { + if (strcmp(outputdev, "ttya") == 0) + cons = CONS_TTYA; + else if (strcmp(outputdev, "ttyb") == 0) + cons = CONS_TTYB; + } + } + + if (cons == CONS_INVALID) + cons = CONS_SCREEN_TEXT; + console = cons; + + switch (console) { + case CONS_TTYA: + case CONS_TTYB: + if (console_state != CONS_TTYA && + console_state != CONS_TTYB) { + serial_init(); + } + break; + case CONS_SCREEN_TEXT: + if (console_state != CONS_SCREEN_TEXT) { + clear_screen(); + kb_init(); + } + break; + } + } + + /* special handling for graphics boot and serial console */ + switch (console) { + case CONS_TTYA: + case CONS_TTYB: + serial_init(); + break; + case CONS_SCREEN_GRAPHICS: + if (!graphics_init()) + printf("failed to initialize " + "console to graphics mode\n"); + break; + }; +} + +static void +serial_putchar(int c) +{ + int checks = 10000; + + while (((inb(port + LSR) & XHRE) == 0) && checks--) + ; + outb(port + DAT, (char)c); +} + +static int +serial_getchar(void) +{ + uchar_t lsr; + + while (serial_ischar() == 0) + ; + + lsr = inb(port + LSR); + if (lsr & (SERIAL_BREAK | SERIAL_FRAME | + SERIAL_PARITY | SERIAL_OVERRUN)) { + if (lsr & SERIAL_OVERRUN) { + printf("silo overflow\n"); + return (inb(port + DAT)); + } else { + /* Toss the garbage */ + (void) inb(port + DAT); + return (0); + } + } + return (inb(port + DAT)); +} + +static int +serial_ischar(void) +{ + return (inb(port + LSR) & RCA); +} + +static void +_doputchar(int c) +{ + switch (console) { + case CONS_TTYA: + case CONS_TTYB: + serial_putchar(c); + return; + case CONS_SCREEN_TEXT: + screen_putchar(c); + return; + case CONS_SCREEN_GRAPHICS: + if (verbosemode) + graphics_putchar(c); + } +} + +void +putchar(int c) +{ + static int bhcharpos = 0; + + if (c == '\t') { + do { + _doputchar(' '); + } while (++bhcharpos % 8); + return; + } else if (c == '\n' || c == '\r') { + bhcharpos = 0; + _doputchar('\r'); + _doputchar(c); + return; + } else if (c == '\b') { + if (bhcharpos) + bhcharpos--; + _doputchar(c); + return; + } + + bhcharpos++; + _doputchar(c); +} + + +int +getchar(void) +{ + switch (console) { + case CONS_TTYA: + case CONS_TTYB: + return (serial_getchar()); + default: + return (kb_getchar()); + } +} + +int +ischar(void) +{ + switch (console) { + case CONS_TTYA: + case CONS_TTYB: + return (serial_ischar()); + default: + return (kb_ischar()); + } +} + +/* + * Read from the console (using getchar) into string str, + * until a carriage return or until n-1 characters are read. + * Null terminate the string, and return. + * This all is made complicated by the fact that we must + * do our own echoing during input. + * N.B.: Returns the *number of characters in str*. + */ + +int +cons_gets(char *str, int n) +{ + int c; + int t; + char *p; + + p = str; + c = 0; + + while ((t = getchar()) != '\r') { + putchar(t); + if (t == '\b') { + if (c) { + printf(" \b"); + c--; p--; + } else + putchar(' '); + continue; + } + if (c < n - 1) { + *p++ = t; + c++; + } + } + putchar('\n'); + *p = '\0'; + + return (c); +} + +/*PRINTFLIKE1*/ +void +printf(const char *fmt, ...) +{ + va_list adx; + + va_start(adx, fmt); + prom_vprintf(fmt, adx); + va_end(adx); +} + +/* setup boot syscall fields needed by the kernel */ +static struct boot_syscalls sc = { + getchar, + putchar, + ischar +}; + +struct boot_syscalls *sysp = ≻ diff --git a/usr/src/psm/stand/boot/i386/common/console.h b/usr/src/psm/stand/boot/i386/common/console.h new file mode 100644 index 0000000000..4765780cc6 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/console.h @@ -0,0 +1,63 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CONS_INVALID -1 +#define CONS_SCREEN_TEXT 0 +#define CONS_SCREEN_GRAPHICS 1 +#define CONS_TTYA 2 +#define CONS_TTYB 3 + +#define CONS_COLOR 7 + +extern uchar_t inb(int); +extern void outb(int, uchar_t); +extern void kb_init(void); +extern int kb_getchar(void); +extern int kb_ischar(void); + +extern void console_init(char *); +extern void console_init2(char *, char *, char *); +extern void text_init(void); +extern void putchar(int); +extern int getchar(void); +extern int ischar(void); +extern int cons_gets(char *, int); +extern void reset(); + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSOLE_H */ diff --git a/usr/src/psm/stand/boot/i386/common/cpu_id.h b/usr/src/psm/stand/boot/i386/common/cpu_id.h new file mode 100644 index 0000000000..8948d8031b --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/cpu_id.h @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _CPU_ID_H +#define _CPU_ID_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GenuineIntel 0x1 +#define AuthenticAMD 0x2 + +#define Genu 0x756e6547 +#define ineI 0x49656e69 +#define ntel 0x6c65746e + +#define Auth 0x68747541 +#define enti 0x69746e65 +#define cAMD 0x444d4163 + +#ifndef _ASM + +extern int max_std_cpuid_level; +extern unsigned int cpu_vendor; + +extern int is486(void); +extern int enable_cpuid(void); +extern int largepage_supported(void); +extern int enable_large_pages(void); +extern int global_bit(void); +extern int enable_global_pages(void); +extern int pae_supported(void); + +#endif /* !_ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _CPU_ID_H */ diff --git a/usr/src/psm/stand/boot/i386/common/debug.h b/usr/src/psm/stand/boot/i386/common/debug.h new file mode 100644 index 0000000000..858cb21245 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/debug.h @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DEBUG_H +#define _DEBUG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int debug; +extern int verbosemode; + +/* Mask bits for debug */ +#define D_BPROP 0x01 +#define D_MBINFO 0x02 +#define D_KEYBOARD 0x04 +#define D_ALLOC 0x08 +#define D_BOP 0x10 +#define D_BIOS 0x20 +#define D_GRAPHICS 0x40 + +#ifdef __cplusplus +} +#endif + +#endif /* _DEBUG_H */ diff --git a/usr/src/psm/stand/boot/i386/common/graphics.c b/usr/src/psm/stand/boot/i386/common/graphics.c new file mode 100644 index 0000000000..d4e1cd9f11 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/graphics.c @@ -0,0 +1,743 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/psw.h> +#include <sys/memlist.h> +#include <sys/bootvfs.h> +#include "graphics.h" +#include "biosint.h" +#include "vga.h" +#include "util.h" +#include "multiboot.h" +#include "console.h" +#include "standalloc.h" +#include "debug.h" + +typedef int (*func_t)(); +extern int openfile(char *, char *); +extern int close(int); +extern int console; + +int saved_videomode; +unsigned char *font8x16; + +int graphics_inited = 0; +static char splashimage[64]; + +#define VSHADOW VSHADOW1 +unsigned char VSHADOW1[38400]; +unsigned char VSHADOW2[38400]; +unsigned char VSHADOW4[38400]; +unsigned char VSHADOW8[38400]; + +#define dprintf if (debug & D_GRAPHICS) printf + +/* + * constants to define the viewable area + */ +const int x0 = 0; +const int x1 = 80; +const int y0 = 0; +const int y1 = 30; + +/* + * text buffer has to be kept around so that we can write things as we + * scroll and the like + */ +unsigned short text[80 * 30]; + +/* + * why do these have to be kept here? + */ +int foreground = (63 << 16) | (63 << 8) | (63), background = 0, border = 0; + +/* + * current position + */ + +static int fontx = 0; +static int fonty = 10; + +/* + * global state so that we don't try to recursively scroll or cursor + */ +static int no_scroll = 0; + +/* + * color state + */ +static int graphics_standard_color = A_NORMAL; +static int graphics_normal_color = A_NORMAL; +static int graphics_highlight_color = A_REVERSE; +static int graphics_current_color = A_NORMAL; +static color_state graphics_color_state = COLOR_STATE_STANDARD; + + +/* + * graphics local functions + */ +static void graphics_setxy(int col, int row); +static void graphics_scroll(); +static void graphics_memcpy(void *dest, const void *src, int len); +static int graphics_memcmp(const char *s1, const char *s2, int n); +static int read_image(char *s); +static int hex(int v); + +extern uchar_t inb(int); +extern void outb(int, uchar_t); + +static void MapMask(int value) { + outb(0x3c4, 2); + outb(0x3c5, value); +} + +/* bit mask register */ +static void BitMask(int value) { + outb(0x3ce, 8); + outb(0x3cf, value); +} + +/* Set the splash image */ +int graphics_set_splash(char *splashfile) { + /* filename can only be 64 characters due to our buffer size */ + if (strlen(splashfile) > 63) + return (0); + strcpy(splashimage, splashfile); + return (1); +} + +/* Get the current splash image */ +char * +graphics_get_splash(void) +{ + return (splashimage); +} + +/* + * Initialize a vga16 graphics display with the palette based off of + * the image in splashimage. If the image doesn't exist, leave graphics + * mode. + */ +int +graphics_init() +{ + int fail_n = 0; + + if (!graphics_inited) { + saved_videomode = set_videomode(0x12); + if (saved_videomode == -1) { + fail_n = 1; + goto fail; + } + } + + if (!graphics_set_splash("boot/solaris.xpm")) { + fail_n = 2; + goto fail; + } + + if (!read_image(splashimage)) { + fail_n = 3; + goto fail; + } + + font8x16 = (unsigned char *)graphics_get_font(); + if (!font8x16) { + fail_n = 4; + goto fail; + } + + graphics_inited = 1; + + /* make sure that the highlight color is set correctly */ + graphics_highlight_color = ((graphics_normal_color >> 4) | + ((graphics_normal_color & 0xf) << 4)); + + graphics_cursor(0); + graphics_setxy(fontx, fonty); + graphics_cursor(1); + graphics_cls(); + + return (1); + +fail : + console = CONS_SCREEN_TEXT; + text_init(); + switch (fail_n) { + case 1: + printf("Failed to set graphics video mode\n"); + break; + case 2: + printf("Splash image file name is too long\n"); + break; + case 3: + printf("Failed to read splash image\n"); + break; + case 4: + printf("Failed to get font address\n"); + } + + return (0); +} + +/* + * int set_videomode(mode) + * BIOS call "INT 10H Function 0h" to set video mode + * Call with %ah = 0x0 + * %al = video mode + * Return correct : old videomode + * error : -1 + */ +int +set_videomode(int mode) +{ + int ret; + struct int_pb ic = {0}; + + ic.ax = 0x0f00; + ret = bios_doint(0x10, &ic); /* Get Current Video mode */ + if (ret & PS_C) { + dprintf("bios_doint returned: %d\r\n", ret); + return (-1); + } + ret = ic.ax & 0xFF; /* al is the current mode */ + + ic.ax = mode & 0xFF; /* ah = 0, al = mode */ + if (bios_doint(0x10, &ic) & PS_C) { + dprintf("bios_doint returned: %d\r\n", ret); + return (-1); + } /* Set Video mode */ + + return (ret); +} + +/* + * unsigned char * graphics_get_font() + * BIOS call "INT 10H Function 11h" to set font + * Call with %ah = 0x11 + * Return correct : font address + * error : 0 + */ +unsigned char * +graphics_get_font() +{ + int ret; + struct int_pb ic = {0}; + + ic.ax = 0x1130; + ic.bx = 0x0600; /* font 8x16 */ + ret = bios_doint(0x10, &ic); /* get font address */ + if (ret & PS_C) { + dprintf("bios_doint returned: %d\r\n", ret); + return (0); + } + + ret = (ic.es << 4) + ic.bp; + return ((unsigned char *) ret); +} + +/* + * int graphics_set_palette(unsigned index, unsigned red, + * unsigned green,unsigned blue) + * BIOS call "INT 10H Function 10h" to set individual dac register + * Call with %ah = 0x10 + * %bx = register number + * %ch = new value for green (0-63) + * %cl = new value for blue (0-63) + * %dh = new value for red (0-63) + * Return correct : 1 + * error : 0 + */ +int +graphics_set_palette(int index, int red, int green, int blue) +{ + int ret; + struct int_pb ic = {0}; + /* wait vertical active display */ + while (((inb(VGA_IO_IS) & 0x8)) == 0x8) {} + /* wait vertical retrace */ + while (((inb(VGA_IO_IS) & 0x8)) == 0x8) {} + + outb(VGA_IO_WMR, (index & 0xFF)); + outb(VGA_IO_DR, (red & 0xFF)); + outb(VGA_IO_DR, (green & 0xFF)); + outb(VGA_IO_DR, (blue & 0xFF)); + + ic.ax = 0x1000; + ic.bx = ((index & 0xFF) <<8) | (index & 0xFF); /* ?? */ + ic.cx = ((green & 0xFF) <<8) | (blue & 0xFF); + ic.dx = (red & 0xFF) <<8; + ret = bios_doint(0x10, &ic); /* set palette registert */ + if (ret & PS_C) { + dprintf("bios_doint returned: %d\r\n", ret); + return (0); + } else + return (1); +} + +/* Leave graphics mode */ +void +graphics_end(void) +{ + if (graphics_inited) { + set_videomode(saved_videomode); + graphics_inited = 0; + } +} + +/* Print ch on the screen. Handle any needed scrolling or the like */ +void +graphics_putchar(int ch) +{ + ch &= 0xff; + + graphics_cursor(0); + + if (ch == '\n') { + if (fonty + 1 < y1) + graphics_setxy(fontx, fonty + 1); + else + graphics_scroll(); + graphics_cursor(1); + return; + } else if (ch == '\r') { + graphics_setxy(x0, fonty); + graphics_cursor(1); + return; + } + + graphics_cursor(0); + + text[fonty * 80 + fontx] = ch; + text[fonty * 80 + fontx] &= 0x00ff; + if (graphics_current_color & 0xf0) + text[fonty * 80 + fontx] |= 0x100; + + graphics_cursor(0); + + if ((fontx + 1) >= x1) { + graphics_setxy(x0, fonty); + if (fonty + 1 < y1) + graphics_setxy(x0, fonty + 1); + else + graphics_scroll(); + } else { + graphics_setxy(fontx + 1, fonty); + } + + graphics_cursor(1); +} + +/* get the current location of the cursor */ +int +graphics_getxy(void) +{ + return ((fontx << 8) | fonty); +} + +void +graphics_gotoxy(int x, int y) +{ + graphics_cursor(0); + + graphics_setxy(x, y); + + graphics_cursor(1); +} + +void +graphics_cls(void) +{ + int i; + unsigned char *mem, *s1, *s2, *s4, *s8; + + graphics_cursor(0); + graphics_gotoxy(x0, y0); + + mem = (unsigned char *)VIDEOMEM; + s1 = (unsigned char *)VSHADOW1; + s2 = (unsigned char *)VSHADOW2; + s4 = (unsigned char *)VSHADOW4; + s8 = (unsigned char *)VSHADOW8; + + for (i = 0; i < 80 * 30; i++) + text[i] = ' '; + graphics_cursor(1); + + BitMask(0xff); + + /* plano 1 */ + MapMask(1); + graphics_memcpy(mem, s1, 38400); + + /* plano 2 */ + MapMask(2); + graphics_memcpy(mem, s2, 38400); + + /* plano 3 */ + MapMask(4); + graphics_memcpy(mem, s4, 38400); + + /* plano 4 */ + MapMask(8); + graphics_memcpy(mem, s8, 38400); + + MapMask(15); +} + +void +graphics_setcolorstate(color_state state) +{ + switch (state) { + case COLOR_STATE_STANDARD: + graphics_current_color = graphics_standard_color; + break; + case COLOR_STATE_NORMAL: + graphics_current_color = graphics_normal_color; + break; + case COLOR_STATE_HIGHLIGHT: + graphics_current_color = graphics_highlight_color; + break; + default: + graphics_current_color = graphics_standard_color; + break; + } + + graphics_color_state = state; +} + +void +graphics_setcolor(int normal_color, int highlight_color) +{ + graphics_normal_color = normal_color; + graphics_highlight_color = highlight_color; + + graphics_setcolorstate(graphics_color_state); +} + +void +graphics_setcursor(int on) +{ + /* FIXME: we don't have a cursor in graphics */ +} + +/* + * Read in the splashscreen image and set the palette up appropriately. + * Format of splashscreen is an xpm (can be gzipped) with 16 colors and + * 640x480. + */ +static int +read_image(char *s) +{ + char buf[32], pal[16]; + unsigned char c, base, mask, *s1, *s2, *s4, *s8; + unsigned i, len, idx, colors, x, y, width, height; + int fd; + ssize_t count; + + fd = openfile(s, 0); + if (fd == -1) { + dprintf("error opening %s\n", s); + return (0); + } + + /* read header */ + count = read(fd, (char *)&buf, 10); + if ((count < 10) || graphics_memcmp(buf, "/* XPM */\n", 10)) { + close(fd); + dprintf("read header error\n"); + return (0); + } + + /* parse info */ + while (read(fd, &c, 1)) { + if (c == '"') + break; + } + + while (read(fd, &c, 1) && (c == ' ' || c == '\t')) + ; + + i = 0; + width = c - '0'; + while (read(fd, &c, 1)) { + if (c >= '0' && c <= '9') + width = width * 10 + c - '0'; + else + break; + } + while (read(fd, &c, 1) && (c == ' ' || c == '\t')) + ; + + height = c - '0'; + while (read(fd, &c, 1)) { + if (c >= '0' && c <= '9') + height = height * 10 + c - '0'; + else + break; + } + while (read(fd, &c, 1) && (c == ' ' || c == '\t')) + ; + + colors = c - '0'; + while (read(fd, &c, 1)) { + if (c >= '0' && c <= '9') + colors = colors * 10 + c - '0'; + else + break; + } + + base = 0; + while (read(fd, &c, 1) && c != '"') + ; + /* palette */ + for (i = 0, idx = 1; i < colors; i++) { + len = 0; + + while (read(fd, &c, 1) && c != '"') + ; + read(fd, &c, 1); /* char */ + base = c; + read(fd, buf, 4); /* \t c # */ + + while (read(fd, &c, 1) && c != '"') { + if (len < sizeof (buf)) + buf[len++] = c; + } + + if (len == 6 && idx < 15) { + int r = ((hex(buf[0]) << 4) | hex(buf[1])) >> 2; + int g = ((hex(buf[2]) << 4) | hex(buf[3])) >> 2; + int b = ((hex(buf[4]) << 4) | hex(buf[5])) >> 2; + pal[idx] = base; + graphics_set_palette(idx, r, g, b); + ++idx; + } + } + + x = y = len = 0; + + s1 = (unsigned char *)VSHADOW1; + s2 = (unsigned char *)VSHADOW2; + s4 = (unsigned char *)VSHADOW4; + s8 = (unsigned char *)VSHADOW8; + + for (i = 0; i < 38400; i++) + s1[i] = s2[i] = s4[i] = s8[i] = 0; + + /* parse xpm data */ + while (y < height) { + while (1) { + if (!read(fd, &c, 1)) { + close(fd); + return (0); + } + if (c == '"') + break; + } + + while (read(fd, &c, 1) && c != '"') { + for (i = 1; i < 15; i++) + if (pal[i] == c) { + c = i; + break; + } + + mask = 0x80 >> (x & 7); + if (c & 1) + s1[len + (x >> 3)] |= mask; + if (c & 2) + s2[len + (x >> 3)] |= mask; + if (c & 4) + s4[len + (x >> 3)] |= mask; + if (c & 8) + s8[len + (x >> 3)] |= mask; + + if (++x >= 640) { + x = 0; + + if (y < 480) + len += 80; + ++y; + } + } + } + + close(fd); + + graphics_set_palette(0, (background >> 16), (background >> 8) & 63, + background & 63); + graphics_set_palette(15, (foreground >> 16), (foreground >> 8) & 63, + foreground & 63); + graphics_set_palette(0x11, (border >> 16), (border >> 8) & 63, + border & 63); + + return (1); +} + +/* Convert a character which is a hex digit to the appropriate integer */ +static int +hex(int v) +{ + if (v >= 'A' && v <= 'F') + return (v - 'A' + 10); + if (v >= 'a' && v <= 'f') + return (v - 'a' + 10); + return (v - '0'); +} + + +/* move the graphics cursor location to col, row */ +static void +graphics_setxy(int col, int row) +{ + if (col >= x0 && col < x1) { + fontx = col; + cursorX = col << 3; + } + if (row >= y0 && row < y1) { + fonty = row; + cursorY = row << 4; + } +} + +static void +graphics_memcpy(void *dest, const void *src, int len) +{ + int i; + register char *d = (char *)dest, *s = (char *)src; + + for (i = 0; i < len; i++) + d[i] = s[i]; +} + +static int +graphics_memcmp(const char *s1, const char *s2, int n) +{ + while (n) { + if (*s1 < *s2) + return (-1); + else if (*s1 > *s2) + return (1); + s1++; + s2++; + n--; + } + + return (0); +} + +/* scroll the screen */ +static void +graphics_scroll() +{ + int i, j; + + /* we don't want to scroll recursively... that would be bad */ + if (no_scroll) + return; + no_scroll = 1; + + /* move everything up a line */ + for (j = y0 + 1; j < y1; j++) { + graphics_gotoxy(x0, j - 1); + for (i = x0; i < x1; i++) { + graphics_putchar(text[j * 80 + i]); + } + } + + /* last line should be blank */ + graphics_gotoxy(x0, y1 - 1); + for (i = x0; i < x1; i++) + graphics_putchar(' '); + graphics_setxy(x0, y1 - 1); + + no_scroll = 0; +} + + +void graphics_cursor(int set) { + unsigned char *pat, *mem, *ptr, chr[16 << 2]; + int i, ch, invert, offset; + + if (set && no_scroll) + return; + + offset = cursorY * 80 + fontx; + ch = text[fonty * 80 + fontx] & 0xff; + invert = (text[fonty * 80 + fontx] & 0xff00) != 0; + pat = font8x16 + (ch << 4); + + mem = (unsigned char *)VIDEOMEM + offset; + + if (set) { + MapMask(15); + ptr = mem; + for (i = 0; i < 16; i++, ptr += 80) { + cursorBuf[i] = pat[i]; + *ptr = ~pat[i]; + } + return; + } + + for (i = 0; i < 16; i++) { + unsigned char mask = pat[i]; + + if (!invert) { + chr[i ] = ((unsigned char *)VSHADOW1)[offset]; + chr[16 + i] = ((unsigned char *)VSHADOW2)[offset]; + chr[32 + i] = ((unsigned char *)VSHADOW4)[offset]; + chr[48 + i] = ((unsigned char *)VSHADOW8)[offset]; + + chr[i ] |= mask; + chr[16 + i] |= mask; + chr[32 + i] |= mask; + chr[48 + i] |= mask; + + offset += 80; + } else { + chr[i ] = mask; + chr[16 + i] = mask; + chr[32 + i] = mask; + chr[48 + i] = mask; + } + } + + offset = 0; + for (i = 1; i < 16; i <<= 1, offset += 16) { + int j; + + MapMask(i); + ptr = mem; + for (j = 0; j < 16; j++, ptr += 80) + *ptr = chr[j + offset]; + } + + MapMask(15); +} diff --git a/usr/src/psm/stand/boot/i386/common/graphics.h b/usr/src/psm/stand/boot/i386/common/graphics.h new file mode 100644 index 0000000000..d589d8b38a --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/graphics.h @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _GRAPHICS_H +#define _GRAPHICS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* magic constant */ +#define VIDEOMEM 0xA0000 + +/* code for getchar */ +#define A_NORMAL 0x7 +#define A_REVERSE 0x70 + +/* These are used to represent the various color states we use */ +typedef enum +{ +/* + * represents the color used to display all text that does not use the user + * defined colors below + */ +COLOR_STATE_STANDARD, +/* represents the user defined colors for normal text */ +COLOR_STATE_NORMAL, +/* represents the user defined colors for highlighted text */ +COLOR_STATE_HIGHLIGHT +} color_state; + +void graphics_cursor(int set); +void graphics_putchar(int c); +int graphics_getxy(void); +void graphics_gotoxy(int x, int y); +void graphics_cls(void); +void graphics_setcolorstate(color_state state); +void graphics_setcolor(int normal_color, int highlight_color); +void graphics_setcursor(int on); +int set_videomode(int mode); +int graphics_init(void); +void graphics_end(void); +unsigned char *graphics_get_font(void); +int graphics_set_palette(int idx, int red, int green, int blue); +int graphics_set_splash(char *splashfile); + +short cursorX, cursorY; +char cursorBuf[16]; + +#ifdef __cplusplus +} +#endif + +#endif /* _GRAPHICS_H */ diff --git a/usr/src/psm/stand/boot/i386/common/i86.il b/usr/src/psm/stand/boot/i386/common/i86.il new file mode 100644 index 0000000000..180cb5135a --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/i86.il @@ -0,0 +1,122 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1992,2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/ +/ In-line functions for i86 calls. +/ + + +/ +/ in and out +/ + .inline inb,4 + movl (%esp), %edx + xorl %eax, %eax + inb (%dx) + .end + + .inline inw,4 + movl (%esp), %edx + xorl %eax, %eax + inw (%dx) + .end + + .inline inl,4 + movl (%esp), %edx + xorl %eax, %eax + inl (%dx) + .end + + .inline outb,8 + movl (%esp), %edx + movl 4(%esp), %eax + outb (%dx) + .end + + .inline outw,8 + movl (%esp), %edx + movl 4(%esp), %eax + outw (%dx) + .end + + .inline outl,8 + movl (%esp), %edx + movl 4(%esp), %eax + outl (%dx) + .end + +/ +/ Networking byte order functions (too bad, Intel has the wrong byte order) +/ + + .inline htonl,4 + movl (%esp), %eax + bswap %eax + .end + + .inline ntohl,4 + movl (%esp), %eax + bswap %eax + .end + + .inline htons,4 + movl (%esp), %eax + bswap %eax + shrl $16, %eax + .end + + .inline ntohs,4 + movl (%esp), %eax + bswap %eax + shrl $16, %eax + .end + +/ +/ disable interrupts and return value describing if interrupts were enabled +/ + .inline clear_int_flag,0 + pushfl + cli + popl %eax + .end + +/ +/ restore interrupt enable flag to value returned from 'clear_int_flag' above +/ + .inline restore_int_flag,4 + pushl (%esp) + popfl + .end + +/ +/ stub function. +/ i386 arch currently has a unified cache +/ + .inline sync_instruction_memory,8 + nop + .end diff --git a/usr/src/psm/stand/boot/i386/common/keyboard.c b/usr/src/psm/stand/boot/i386/common/keyboard.c new file mode 100644 index 0000000000..095a46b432 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/keyboard.c @@ -0,0 +1,554 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Miniature keyboard driver for bootstrap. This allows keyboard + * support to continue after we take over interrupts and disable + * BIOS keyboard support. + */ + +#include <sys/types.h> +#include "chario.h" +#include "keyboard_table.h" +#include "console.h" +#include "util.h" +#include "debug.h" + +/* + * Definitions for BIOS keyboard state. We use BIOS's variable to store + * state, ensuring that we stay in sync with it. + */ +#define BIOS_KB_FLAG 0x417 +#define BIOS_RIGHT_SHIFT 0x01 +#define BIOS_LEFT_SHIFT 0x02 +#define BIOS_EITHER_SHIFT (BIOS_LEFT_SHIFT | BIOS_RIGHT_SHIFT) +#define BIOS_CTL_SHIFT 0x04 +#define BIOS_ALT_SHIFT 0x08 +#define BIOS_SCROLL_STATE 0x10 +#define BIOS_NUM_STATE 0x20 +#define BIOS_CAPS_STATE 0x40 +#define BIOS_INS_STATE 0x80 + +#define BIOS_KB_FLAG_1 0x418 +#define BIOS_SYS_SHIFT 0x04 +#define BIOS_HOLD_STATE 0x08 +#define BIOS_SCROLL_SHIFT 0x10 +#define BIOS_NUM_SHIFT 0x20 +#define BIOS_CAPS_SHIFT 0x40 +#define BIOS_INS_SHIFT 0x80 + +#define kb_flag ((unsigned char *)BIOS_KB_FLAG) +#define kb_flag_1 ((unsigned char *)BIOS_KB_FLAG_1) + +/* + * Keyboard controller registers + */ +#define I8042_DATA 0x60 +#define I8042_STAT 0x64 +#define I8042_CMD 0x64 + +/* + * Keyboard controller status register bits + */ +#define I8042_STAT_OUTBF 0x01 +#define I8042_STAT_INBF 0x02 +#define I8042_STAT_AUXBF 0x20 + +/* + * Keyboard controller commands + */ +#define I8042_RCB 0x20 +#define I8042_WCB 0x60 + +/* + * Keyboard commands + */ +#define KB_SET_LED 0xED /* LED byte follows... */ +#define KB_LED_SCROLL_LOCK 0x01 /* Bits for LED byte */ +#define KB_LED_NUM_LOCK 0x02 +#define KB_LED_CAPS_LOCK 0x04 + +#ifndef ASSERT +#define ASSERT(x) +#endif + +#define peek8(p) (*(p)) +#define poke8(p, val) (*(p) = (val)) +#define peeks(p) (*(p)) +#define pokes(p, val) (*(p) = (val)) + +static struct { + boolean_t initialized; + enum { KB_LED_IDLE, KB_LED_COMMAND_SENT, KB_LED_VALUE_SENT } + led_state; + int led_commanded; + /* + * Possible values: + * + * -1 Nothing pending + * 0x000-0x0ff Pending byte + * 0x100-0x1ff Needs leading zero, then low byte next. + * + * Others undefined. + */ + int pending; +} kb = { + B_FALSE, /* initialized? */ + KB_LED_IDLE, /* LED command state */ + -1, /* commanded LEDs - force refresh */ + -1, /* pending */ +}; + +#define kb_debug (debug & D_KEYBOARD) + +static int kb_translate(unsigned char code); +static void kb_send(unsigned char cmd); +static void kb_update_leds(void); +static uchar_t kb_calculate_leds(void); + +int +kb_getchar(void) +{ + int ret; + + if (kb_debug) + printf(" getchar()"); + + while (!kb_ischar()) + /* LOOP */; + + /* + * kb_ischar() doesn't succeed without leaving kb.pending + * set. + */ + ASSERT(kb.pending >= 0); + + if (kb.pending & 0x100) { + ret = 0; + kb.pending &= 0xff; + } else { + ret = kb.pending; + kb.pending = -1; + } + + if (kb_debug) + printf("=0x%x ", ret); + + return (ret); +} + +int +kb_ischar(void) +{ + unsigned char buffer_stat; + unsigned char code; + unsigned char leds; + static int cnt = 0; + + if (!kb.initialized) { + kb_init(); + kb.initialized = B_TRUE; + } + + if (kb_debug) + printf("%c\b", "/-\\|"[cnt++ % 4]); + + if (kb.pending >= 0) + return (1); + + for (;;) { + buffer_stat = + inb(I8042_STAT) & (I8042_STAT_OUTBF | I8042_STAT_AUXBF); + + switch (buffer_stat) { + case 0: + case I8042_STAT_AUXBF: + return (0); + case (I8042_STAT_OUTBF | I8042_STAT_AUXBF): + /* + * Discard unwanted mouse data. + */ + (void) inb(I8042_DATA); + continue; + } + + code = inb(I8042_DATA); + + if (kb_debug) + printf("0x%x->", code); + + switch (code) { + /* + * case 0xAA: + * + * You might think that we should ignore 0xAA on the + * grounds that it is the BAT Complete response and will + * occur on keyboard detach/reattach. Unfortunately, + * it is ambiguous - this is also the code for a break + * of the left shift key. Since it will be harmless for + * us to "spuriously" process a break of Left Shift, + * we just let the normal code handle it. Perhaps we + * should take a hint and refresh the LEDs, but I + * refuse to get very worried about hot-plug issues + * in this mini-driver. + */ + case 0xFA: + if (kb_debug) + printf("ack "); + + switch (kb.led_state) { + case KB_LED_IDLE: + /* + * Spurious. Oh well, ignore it. + */ + break; + case KB_LED_COMMAND_SENT: + leds = kb_calculate_leds(); + kb_send(leds); + kb.led_commanded = leds; + kb.led_state = KB_LED_VALUE_SENT; + break; + case KB_LED_VALUE_SENT: + kb.led_state = KB_LED_IDLE; + /* + * Check for changes made while we were + * working on the last change. + */ + kb_update_leds(); + break; + } + continue; + + case 0xE0: + case 0xE1: + /* + * These are used to distinguish the keys added on + * the AT-101 keyboard from the original 84 keys. + * We don't care, and the codes are carefully arranged + * so that we don't have to. + */ + if (kb_debug) + printf("ignored "); + continue; + + default: + if (code & 0x80) { + if (kb_debug) + printf("release->"); + /* Release */ + code &= 0x7f; + switch (keyboard_translate[code].normal) { + case KBTYPE_SPEC_LSHIFT: + poke8(kb_flag, peek8(kb_flag) & + ~BIOS_LEFT_SHIFT); + if (kb_debug) + printf("lshift "); + break; + case KBTYPE_SPEC_RSHIFT: + poke8(kb_flag, peek8(kb_flag) & + ~BIOS_RIGHT_SHIFT); + if (kb_debug) + printf("rshift "); + break; + case KBTYPE_SPEC_CTRL: + poke8(kb_flag, peek8(kb_flag) & + ~BIOS_CTL_SHIFT); + if (kb_debug) + printf("ctrl "); + break; + case KBTYPE_SPEC_ALT: + poke8(kb_flag, peek8(kb_flag) & + ~BIOS_ALT_SHIFT); + if (kb_debug) + printf("alt "); + break; + case KBTYPE_SPEC_CAPS_LOCK: + poke8(kb_flag_1, peek8(kb_flag_1) & + ~BIOS_CAPS_SHIFT); + if (kb_debug) + printf("caps "); + break; + case KBTYPE_SPEC_NUM_LOCK: + poke8(kb_flag_1, peek8(kb_flag_1) & + ~BIOS_NUM_SHIFT); + if (kb_debug) + printf("num "); + break; + case KBTYPE_SPEC_SCROLL_LOCK: + poke8(kb_flag_1, peek8(kb_flag_1) & + ~BIOS_SCROLL_SHIFT); + if (kb_debug) + printf("scroll "); + break; + default: + /* + * Ignore all other releases. + */ + if (kb_debug) + printf("ignored "); + break; + } + } else { + /* Press */ + if (kb_debug) + printf("press->"); + + kb.pending = kb_translate(code); + if (kb.pending >= 0) { + if (kb_debug) + printf("0x%x ", kb.pending); + return (1); + } else { + if (kb_debug) + printf("ignored "); + } + } + } + } +} + +int +kb_translate(unsigned char code) +{ + struct keyboard_translate *k; + unsigned short action; + boolean_t shifted; + + k = keyboard_translate + code; + + shifted = (peek8(kb_flag) & BIOS_EITHER_SHIFT) != 0; + + switch (k->normal & 0xFF00) { + case KBTYPE_NUMPAD: + if (peek8(kb_flag) & BIOS_NUM_STATE) + shifted = !shifted; + break; + case KBTYPE_ALPHA: + if (peek8(kb_flag) & BIOS_CAPS_STATE) + shifted = !shifted; + break; + } + + if (peek8(kb_flag) & BIOS_ALT_SHIFT) + action = k->alted; + else if (peek8(kb_flag) & BIOS_CTL_SHIFT) + action = k->ctrled; + else if (shifted) + action = k->shifted; + else + action = k->normal; + + switch (action & 0xFF00) { + case KBTYPE_NORMAL: + case KBTYPE_ALPHA: + return (action & 0xFF); + + case KBTYPE_NUMPAD: + case KBTYPE_FUNC: + return ((action & 0xFF) | 0x100); + + case KBTYPE_SPEC: + break; + + default: + /* + * Bad entry. + */ + ASSERT(0); + return (-1); + } + + /* + * Handle special keys, mostly shifts. + */ + switch (action) { + case KBTYPE_SPEC_NOP: + case KBTYPE_SPEC_UNDEF: + break; + + case KBTYPE_SPEC_LSHIFT: + poke8(kb_flag, peek8(kb_flag) | BIOS_LEFT_SHIFT); + break; + + case KBTYPE_SPEC_RSHIFT: + poke8(kb_flag, peek8(kb_flag) | BIOS_RIGHT_SHIFT); + break; + + case KBTYPE_SPEC_CTRL: + poke8(kb_flag, peek8(kb_flag) | BIOS_CTL_SHIFT); + break; + + case KBTYPE_SPEC_ALT: + poke8(kb_flag, peek8(kb_flag) | BIOS_ALT_SHIFT); + break; + + case KBTYPE_SPEC_CAPS_LOCK: + if (!(peek8(kb_flag_1) & BIOS_CAPS_SHIFT)) { + poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_CAPS_SHIFT); + poke8(kb_flag, peek8(kb_flag) ^ BIOS_CAPS_STATE); + } + break; + + case KBTYPE_SPEC_NUM_LOCK: + if (!(peek8(kb_flag_1) & BIOS_NUM_SHIFT)) { + poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_NUM_SHIFT); + poke8(kb_flag, peek8(kb_flag) ^ BIOS_NUM_STATE); + } + break; + + case KBTYPE_SPEC_SCROLL_LOCK: + if (!(peek8(kb_flag_1) & BIOS_SCROLL_SHIFT)) { + poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_SCROLL_SHIFT); + poke8(kb_flag, peek8(kb_flag) ^ BIOS_SCROLL_STATE); + } + break; + + case KBTYPE_SPEC_MAYBE_REBOOT: + if ((peek8(kb_flag) & (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) == + (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) { + reset(); + /* NOTREACHED */ + } + break; + + default: + /* + * Bad entry + */ + ASSERT(0); + break; + } + + /* + * Consider updating the LEDs. This does nothing if nothing + * needs to be done. + */ + kb_update_leds(); + + return (-1); +} + +void +kb_send(unsigned char cmd) +{ + while (inb(I8042_STAT) & I8042_STAT_INBF) + /* LOOP */; + outb(I8042_DATA, cmd); +} + +void +kb_update_leds(void) +{ + if (kb.led_state != KB_LED_IDLE) { + /* + * The state machine will take care of any additional + * changes that are necessary. + */ + return; + } + + if (kb_calculate_leds() == kb.led_commanded) { + kb.led_state = KB_LED_IDLE; + } else { + kb_send(KB_SET_LED); + kb.led_state = KB_LED_COMMAND_SENT; + } +} + +#define MIMR_PORT 0x21 /* Mask register for master PIC */ +#define MIMR_KB 2 /* Keyboard mask bit in master PIC */ + +void +kb_init(void) +{ + unsigned char pic_mask; + + /* + * Write the command byte to turn off interrupts and + * disable the auxiliary port. + * + * 0x80: 0 = Reserved, must be zero. + * 0x40: 1 = Translate to XT codes. + * Solaris turns this off later, but we have a legacy + * of using XT codes. + * 0x20: 1 = Disable aux (mouse) port. + * 0x10: 0 = Enable main (keyboard) port. + * 0x08: 0 = Reserved, must be zero. + * 0x04: 1 = System flag, 1 means passed self-test. + * Caution: setting this bit to zero causes some + * systems (HP Kayak XA) to fail to reboot without + * a hard reset. + * 0x02: 0 = Disable aux interrupts. + * 0x01: 0 = Disable aux interrupts. + */ + + while (inb(I8042_STAT) & I8042_STAT_INBF) + /* LOOP */; + outb(I8042_CMD, I8042_WCB); + + while (inb(I8042_STAT) & I8042_STAT_INBF) + /* LOOP */; + outb(I8042_DATA, 0x64); + + /* + * If we're running on a system with an emulated 8042 (with + * USB and SMI emulation), the above command *might* not + * have turned off keyboard interrupts. If it didn't, + * we will lose keystrokes to the BIOS int handler every + * time someone hits a key while BIOS and STI are active.. + * that is, every time we're in bootconf.exe, for example. + * Turn off ints at the PIC to prevent this from happening. + * + * Yes, this is yet another workaround for buggy BIOS + * emulation. + */ + + pic_mask = inb(MIMR_PORT); + outb(MIMR_PORT, pic_mask | MIMR_KB); + + kb_update_leds(); +} + +unsigned char +kb_calculate_leds(void) +{ + int res; + + res = 0; + + if (peek8(kb_flag) & BIOS_CAPS_STATE) + res |= KB_LED_CAPS_LOCK; + + if (peek8(kb_flag) & BIOS_NUM_STATE) + res |= KB_LED_NUM_LOCK; + + if (peek8(kb_flag) & BIOS_SCROLL_STATE) + res |= KB_LED_SCROLL_LOCK; + + return (res); +} diff --git a/usr/src/psm/stand/boot/i386/common/keyboard_table.c b/usr/src/psm/stand/boot/i386/common/keyboard_table.c new file mode 100644 index 0000000000..64d57720df --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/keyboard_table.c @@ -0,0 +1,181 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Keyboard table for bootstrap's miniature keyboard driver. + */ + +#include "keyboard_table.h" + +#define A | KBTYPE_ALPHA +#define C & 0x1f +#define F | KBTYPE_FUNC +#define N | KBTYPE_NUMPAD + +#define ALT KBTYPE_SPEC_ALT +#define CTRL KBTYPE_SPEC_CTRL +#define LSHIFT KBTYPE_SPEC_LSHIFT +#define NOP KBTYPE_SPEC_NOP +#define NUMLK KBTYPE_SPEC_NUM_LOCK +#define SCRLLK KBTYPE_SPEC_SCROLL_LOCK +#define CAPSLK KBTYPE_SPEC_CAPS_LOCK +#define RSHIFT KBTYPE_SPEC_RSHIFT +#define REBOOT KBTYPE_SPEC_MAYBE_REBOOT +#define UNDEF KBTYPE_SPEC_UNDEF + +struct keyboard_translate keyboard_translate[128] = { + /* Normal Shifted Ctrled Alted */ + /* 00 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 01 */ '['C, '['C, NOP, NOP, + /* 02 */ '1', '!', NOP, 0x78 F, + /* 03 */ '2', '@', NOP, 0x79 F, + /* 04 */ '3', '#', NOP, 0x7a F, + /* 05 */ '4', '$', NOP, 0x7b F, + /* 06 */ '5', '%', NOP, 0x7c F, + /* 07 */ '6', '^', '^'C, 0x7d F, + /* 08 */ '7', '&', NOP, 0x7e F, + /* 09 */ '8', '*', NOP, 0x7f F, + /* 0a */ '9', '(', NOP, 0x80 F, + /* 0b */ '0', ')', NOP, 0x81 F, + /* 0c */ '-', '_', NOP, 0x82 F, + /* 0d */ '=', '+', NOP, 0x83 F, + /* 0e */ 'h'C, 0x0e F, 0x7f, NOP, + /* 0f */ 'i'C, 0x0f F, NOP, NOP, + /* 10 */ 'q'A, 'Q', 'q'C, 0x10 F, + /* 11 */ 'w'A, 'W', 'w'C, 0x11 F, + /* 12 */ 'e'A, 'E', 'e'C, 0x12 F, + /* 13 */ 'r'A, 'R', 'r'C, 0x13 F, + /* 14 */ 't'A, 'T', 't'C, 0x14 F, + /* 15 */ 'y'A, 'Y', 'y'C, 0x15 F, + /* 16 */ 'u'A, 'U', 'u'C, 0x16 F, + /* 17 */ 'i'A, 'I', 'i'C, 0x17 F, + /* 18 */ 'o'A, 'O', 'o'C, 0x18 F, + /* 19 */ 'p'A, 'P', 'p'C, 0x19 F, + /* 1a */ '[', '{', '['C, NOP, + /* 1b */ ']', '}', ']'C, NOP, + /* 1c */ 'm'C, 'm'C, NOP, NOP, + /* 1d */ CTRL, CTRL, CTRL, CTRL, + /* 1e */ 'a'A, 'A', 'a'C, 0x1e F, + /* 1f */ 's'A, 'S', 's'C, 0x1f F, + /* 20 */ 'd'A, 'D', 'd'C, 0x20 F, + /* 21 */ 'f'A, 'F', 'f'C, 0x21 F, + /* 22 */ 'g'A, 'G', 'g'C, 0x22 F, + /* 23 */ 'h'A, 'H', 'h'C, 0x23 F, + /* 24 */ 'j'A, 'J', 'j'C, 0x24 F, + /* 25 */ 'k'A, 'K', 'k'C, 0x25 F, + /* 26 */ 'l'A, 'L', 'l'C, 0x26 F, + /* 27 */ ';', ':', NOP, NOP, + /* 28 */ '\'', '"', NOP, NOP, + /* 29 */ '`', '~', NOP, NOP, + /* 2a */ LSHIFT, LSHIFT, LSHIFT, LSHIFT, + /* 2b */ '\\', '|', '\\'C, NOP, + /* 2c */ 'z'A, 'Z', 'z'C, 0x2c F, + /* 2d */ 'x'A, 'X', 'x'C, 0x2d F, + /* 2e */ 'c'A, 'C', 'c'C, 0x2e F, + /* 2f */ 'v'A, 'V', 'v'C, 0x2f F, + /* 30 */ 'b'A, 'B', 'b'C, 0x30 F, + /* 31 */ 'n'A, 'N', 'n'C, 0x31 F, + /* 32 */ 'm'A, 'M', 'm'C, 0x32 F, + /* 33 */ ',', '<', NOP, NOP, + /* 34 */ '.', '>', NOP, NOP, + /* 35 */ '/', '?', NOP, NOP, + /* 36 */ RSHIFT, RSHIFT, RSHIFT, RSHIFT, + /* 37 */ '*', NOP, NOP, NOP, /* * PrtSc */ + /* 38 */ ALT, ALT, ALT, ALT, + /* 39 */ ' ', ' ', NOP, NOP, + /* 3a */ CAPSLK, CAPSLK, CAPSLK, CAPSLK, + /* 3b */ 0x3b F, 0x54 F, 0x5e F, 0x68 F, + /* 3c */ 0x3c F, 0x55 F, 0x5f F, 0x69 F, + /* 3d */ 0x3d F, 0x56 F, 0x60 F, 0x6a F, + /* 3e */ 0x3e F, 0x57 F, 0x61 F, 0x6b F, + /* 3f */ 0x3f F, 0x58 F, 0x62 F, 0x6c F, + /* 40 */ 0x40 F, 0x59 F, 0x63 F, 0x6d F, + /* 41 */ 0x41 F, 0x5a F, 0x64 F, 0x6e F, + /* 42 */ 0x42 F, 0x5b F, 0x65 F, 0x6f F, + /* 43 */ 0x43 F, 0x5c F, 0x66 F, 0x70 F, + /* 44 */ 0x44 F, 0x5d F, 0x67 F, 0x71 F, + /* 45 */ NUMLK, NUMLK, NUMLK, NUMLK, + /* 46 */ SCRLLK, SCRLLK, SCRLLK, SCRLLK, + /* 47 */ 0x47 N, '7', NOP, NOP, + /* 48 */ 0x48 N, '8', NOP, NOP, + /* 49 */ 0x49 N, '9', NOP, NOP, + /* 4a */ '-', '-', NOP, NOP, + /* 4b */ 0x4b N, '4', NOP, NOP, + /* 4c */ NOP, '5', NOP, NOP, + /* 4d */ 0x4d N, '6', NOP, NOP, + /* 4e */ '+', '+', NOP, NOP, + /* 4f */ 0x4f N, '1', NOP, NOP, + /* 50 */ 0x50 N, '2', NOP, NOP, + /* 51 */ 0x51 N, '3', NOP, NOP, + /* 52 */ 0x52 N, '0', NOP, NOP, + /* 53 */ 0x53 N, '.', REBOOT, REBOOT, + /* 54 */ NOP, NOP, NOP, NOP, /* SysReq */ + /* 55 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 56 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 57 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 58 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 59 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 5a */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 5b */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 5c */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 5d */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 5e */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 5f */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 60 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 61 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 62 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 63 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 64 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 65 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 66 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 67 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 68 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 69 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 6a */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 6b */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 6c */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 6d */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 6e */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 6f */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 70 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 71 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 72 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 73 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 74 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 75 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 76 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 77 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 78 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 79 */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 7a */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 7b */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 7c */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 7d */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 7e */ UNDEF, UNDEF, UNDEF, UNDEF, + /* 7f */ UNDEF, UNDEF, UNDEF, UNDEF, +}; diff --git a/usr/src/psm/stand/boot/i386/common/keyboard_table.h b/usr/src/psm/stand/boot/i386/common/keyboard_table.h new file mode 100644 index 0000000000..2b72bdc0a3 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/keyboard_table.h @@ -0,0 +1,75 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _KEYBOARD_TABLE_H +#define _KEYBOARD_TABLE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Structure of the keyboard table for the bootstrap miniature + * keyboard driver. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define KBTYPE_NORMAL 0x000 /* Normal keys, process mindlessly. */ +#define KBTYPE_ALPHA 0x100 /* Alpha. If CapsLock is set, swap */ + /* shifted and unshifted meanings. */ + /* Set this on the unshifted character */ +#define KBTYPE_NUMPAD 0x200 /* Numeric/Arrow Pad. If NumLock is set, */ + /* swap shifted and unshifted meanings. */ + /* Set this on the unshifted character. */ +#define KBTYPE_FUNC 0x300 /* Extended Function. Send this code, */ + /* prefixed with zero. */ +#define KBTYPE_SPEC 0x400 /* One-of-a-kind codes. Self-explanatory. */ +#define KBTYPE_SPEC_NOP (KBTYPE_SPEC | 0x00) +#define KBTYPE_SPEC_UNDEF (KBTYPE_SPEC | 0x01) +#define KBTYPE_SPEC_LSHIFT (KBTYPE_SPEC | 0x02) +#define KBTYPE_SPEC_RSHIFT (KBTYPE_SPEC | 0x03) +#define KBTYPE_SPEC_CTRL (KBTYPE_SPEC | 0x04) +#define KBTYPE_SPEC_ALT (KBTYPE_SPEC | 0x05) +#define KBTYPE_SPEC_CAPS_LOCK (KBTYPE_SPEC | 0x06) +#define KBTYPE_SPEC_NUM_LOCK (KBTYPE_SPEC | 0x07) +#define KBTYPE_SPEC_SCROLL_LOCK (KBTYPE_SPEC | 0x08) +#define KBTYPE_SPEC_MAYBE_REBOOT (KBTYPE_SPEC | 0x09) + +struct keyboard_translate { + unsigned short normal; + unsigned short shifted; + unsigned short ctrled; + unsigned short alted; +}; + +extern struct keyboard_translate keyboard_translate[128]; + +#ifdef __cplusplus +} +#endif + +#endif /* _KEYBOARD_TABLE_H */ diff --git a/usr/src/psm/stand/boot/i386/common/machine.h b/usr/src/psm/stand/boot/i386/common/machine.h new file mode 100644 index 0000000000..d841cb8526 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/machine.h @@ -0,0 +1,128 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ +/* All Rights Reserved */ + +/* + * Copyrighted as an unpublished work. + * (c) Copyright INTERACTIVE Systems Corporation 1986, 1988, 1990 + * All rights reserved. + */ + +#ifndef _MACHINE_H +#define _MACHINE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +struct machconfig { + char *sigaddr; /* Machine signature location */ + unsigned char siglen; /* Signature length */ + unsigned char sigid[10]; /* Signature to match */ + unsigned char old_mt; /* OLD Machine type */ + unsigned char machine; /* Machine type */ + ulong_t m_flag; /* status flag */ + int (*m_entry)(); /* machine entry point */ +}; + +#define M_FLG_SRGE 1 /* sig scattered in a range of memory */ + +#define M_ID_AT386 0 +#define M_ID_MC386 1 +#define M_ID_EISA 2 + +#define SYS_MODEL() *(char *)0xFFFFE +#define MODEL_AT (uchar_t)0xFC +#define MODEL_MC (uchar_t)0xF8 +#define USER_START 0x100000 + +#define NPTEPERPT 1024 +typedef struct ptbl { + int page[NPTEPERPT]; +} ptbl_t; + +/* combine later with ../../../uts/i86/sys/pte.h */ +#define PG_P 0x1 /* page is present */ +#define PG_RW 0x2 /* page is read/write */ +#define PG_SIZE 0x80 /* page is 4MB */ +#define PG_GLOBAL 0x100 /* page is persistent */ + +/* + * keyboard controller I/O port addresses + */ + +#define KB_OUT 0x60 /* output buffer R/O */ +#define KB_IDAT 0x60 /* input buffer data write W/O */ +#define KB_STAT 0x64 /* keyboard controller status R/O */ +#define KB_ICMD 0x64 /* input buffer command write W/O */ + +/* + * keyboard controller commands and flags + */ +#define KB_INBF 0x02 /* input buffer full flag */ +#define KB_OUTBF 0x01 /* output buffer full flag */ +#define KB_GATE20 0x02 /* set this bit to allow addresses > 1Mb */ +#define KB_ROP 0xD0 /* read output port command */ +#define KB_WOP 0xD1 /* write output port command */ +#define KB_RCB 0x20 /* read command byte command */ +#define KB_WCB 0x60 /* write command byte command */ +#define KB_ENAB 0xae /* enable keyboard interface */ +#define KB_DISAB 0x10 /* disable keyboard */ +#define KB_EOBFI 0x01 /* enable interrupt on output buffer full */ +#define KB_ACK 0xFA /* Acknowledgement byte from keyboard */ +#define KB_RESETCPU 0xFE /* command to reset AT386 cpu */ +#define KB_READID 0xF2 /* command to read keyboard id */ +#define KB_RESEND 0xFE /* response from keyboard to resend data */ +#define KB_ERROR 0xFF /* response from keyboard to resend data */ +#define KB_RESET 0xFF /* command to reset keyboard */ +/* + * command to to enable keyboard + * this is different from KB_ENAB above in + * that KB_ENAB is a command to the 8042 to + * enable the keyboard interface, not the + * keyboard itself + */ +#define KB_ENABLE 0xF4 + +/* move later into immu.h */ +#ifndef PTSIZE +#define PTSIZE 4096 +#endif + +#define ptround(p) ((int *)(((int)p + PTSIZE-1) & ~(PTSIZE-1))) +#define FOURMEG 4194304 +#define FOURMB_PTE (PG_P | PG_RW | PG_SIZE) + +#ifdef __cplusplus +} +#endif + +#endif /* _MACHINE_H */ diff --git a/usr/src/psm/stand/boot/i386/common/mapfile b/usr/src/psm/stand/boot/i386/common/mapfile new file mode 100644 index 0000000000..85a3c88c5d --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/mapfile @@ -0,0 +1,28 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" + +multiboot = LOAD ?RWX V0x1000000 P0x1000000 A0x1000; +multiboot : ?A; diff --git a/usr/src/psm/stand/boot/i386/common/memory.c b/usr/src/psm/stand/boot/i386/common/memory.c new file mode 100644 index 0000000000..31857fb248 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/memory.c @@ -0,0 +1,216 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * i86pc memory routines + * + * This file contains memory management routines to provide + * functionality found in proms on Sparc machines + */ + +#include <sys/types.h> +#include <sys/sysmacros.h> +struct cpu; /* get around mmu.h warning */ +#include <sys/mmu.h> +#include <sys/promif.h> +#include <sys/memlist.h> +#include "standalloc.h" +#include "util.h" +#include "machine.h" +#include "debug.h" +#include "cpu_id.h" + +/* These are the various memory lists in boot.c */ +extern struct memlist *pfreelistp, /* physmem available */ + *vfreelistp, /* virtmem available */ + *pinstalledp, /* physmem installed */ + *pbooterp, /* booter occupied */ + *pramdiskp; /* ramdisk memory */ + +extern uint_t magic_phys; +extern uint_t bpd_loc; +extern int use_align; + +extern void start_paging(void); +extern int map_phys(int, size_t, caddr_t, uint64_t); + +static int global_pages; +static void fiximp(void); + +#define ALIGN(x, a) ((a) == 0 ? (intptr_t)(x) : \ + (((intptr_t)(x) + (intptr_t)(a) - 1l) & ~((intptr_t)(a) - 1l))) + +#define MMU_L1_INDEX(a) (((uint_t)(a)) >> 22) +#define MMU_L2_INDEX(a) ((((uint_t)(a)) >> 12) & 0x3ff) + +void +init_paging(void) +{ + ptbl_t *pdp; + int mode; + struct memlist *entry; + + fiximp(); /* figure out cpu capabilities */ + + /* allocate boot page table directory */ + pdp = (ptbl_t *)resalloc(RES_BOOTSCRATCH, MMU_PAGESIZE, 0, 0); + if (pdp == (ptbl_t *)0) { + prom_panic("init_paging dir"); + } + bpd_loc = (uint_t)pdp; + (void) bzero(pdp, MMU_PAGESIZE); + + /* map in scratch memory */ + mode = PG_P | PG_RW; + (void) map_phys(mode, magic_phys, 0, 0); + + /* map in booter occupied memory */ + entry = pbooterp; + while (entry) { + (void) map_phys(mode, (size_t)entry->size, + (caddr_t)entry->address, entry->address); + entry = entry->next; + } + + /* map in ramdisk memory: disallow write */ + entry = pramdiskp; + while (entry) { + (void) map_phys(PG_P, (size_t)entry->size, + (caddr_t)entry->address, entry->address); + entry = entry->next; + } + + start_paging(); + if (verbosemode) + printf("start paging\n"); +} + +static int +map_4m_page(caddr_t vaddr, uint64_t paddr) +{ + ptbl_t *pdp = (ptbl_t *)bpd_loc; + uint_t pdir = MMU_L1_INDEX(vaddr); + + if (pdp->page[pdir] & PG_P) + return (-1); /* already mapped */ + + /* don't set global flag for Pentium or earlier */ + pdp->page[pdir] = + (FOURMB_PTE | ((uint_t)paddr & FOURMB_PAGEMASK)); + if (global_pages) + pdp->page[pdir] |= PG_GLOBAL; + + return (0); +} + +static int +map_4k_pages(int mode, size_t bytes, caddr_t vaddr, uint64_t paddr) +{ + ptbl_t *pdp, *ptp; + uint_t v, vaddr_end; + + pdp = (ptbl_t *)bpd_loc; + + v = (uint_t)vaddr; + vaddr_end = (v + bytes + MMU_PAGESIZE - 1) & MMU_STD_PAGEMASK; + + while (v < vaddr_end) { + uint_t pdir = MMU_L1_INDEX(v); + + if (pdp->page[pdir] & PG_P) { + ptp = (ptbl_t *) + ((uint_t)pdp->page[pdir] & MMU_STD_PAGEMASK); + } else { + /* allocate a new page table */ + ptp = (ptbl_t *)resalloc(RES_BOOTSCRATCH, + MMU_PAGESIZE, 0, 0); + pdp->page[pdir] = ((uint_t)ptp | PG_P | PG_RW); + (void) bzero(ptp, MMU_PAGESIZE); + } + + /* as long as we are on this page table */ + while ((pdir == MMU_L1_INDEX(v)) && (v < vaddr_end)) { + uint_t pndx = MMU_L2_INDEX(v); + if (ptp->page[pndx] & PG_P) { + /* + * If we are already mapped, panic! + * This should not happen under the + * current memory allocation scheme + * where physmem is either mapped 1:1 + * or mapped above kernelbase. + */ + printf("remapping page at 0x%x\n", v); + prom_panic("remapping unsupported in booter"); + ptp->page[pndx] |= mode; + } else { + ptp->page[pndx] = + (((uint_t)paddr & MMU_STD_PAGEMASK) | mode); + } + paddr += MMU_PAGESIZE; + v += MMU_PAGESIZE; + } + } + + return (0); +} + +int +map_phys(int mode, size_t bytes, caddr_t vaddr, uint64_t paddr) +{ + if (paddr >> 32) /* don't handle PAE */ + return (-1); + + if (use_align && (bytes == FOURMB_PAGESIZE) && + ((uint_t)vaddr & (FOURMB_PAGESIZE - 1)) == 0 && + ((uint_t)paddr & (FOURMB_PAGESIZE - 1)) == 0) + return (map_4m_page(vaddr, paddr)); /* ignore mode */ + + if (mode == 0) + mode = PG_P | PG_RW; + return (map_4k_pages(mode, bytes, vaddr, paddr)); +} + +static void +fiximp(void) +{ + /* need to support at least standard cpuid level 1 to continue */ + (void) enable_cpuid(); + if (max_std_cpuid_level < 1) + return; + + use_align = largepage_supported(); + + if (use_align) { + (void) enable_large_pages(); + + global_pages = global_bit(); + } + + if (global_pages) + (void) enable_global_pages(); +} diff --git a/usr/src/psm/stand/boot/i386/common/mkbin.c b/usr/src/psm/stand/boot/i386/common/mkbin.c new file mode 100644 index 0000000000..423ecec781 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/mkbin.c @@ -0,0 +1,134 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1994, 2002 Sun Microsystems, Inc. + * All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#undef _KERNEL + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/exechdr.h> +#include <sys/elf.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int +main(int argc, char **argv) +{ + int ofd, + ifd; + struct stat sbuf; + void * elffile; + unsigned int i, + total, + bytes; + Elf32_Ehdr *ehdr; + Elf32_Shdr *s; + Elf32_Shdr *first_shdr = NULL, + *nobits_shdr = NULL; + + if (argc < 3) { + (void) printf("usage: mkbin elf_file binary_file \n"); + exit(1); + } + if ((ifd = open(argv[1], O_RDONLY)) == -1) { + perror("open elf input"); + exit(2); + } + + if ((ofd = open(argv[2], O_RDWR | O_TRUNC | O_CREAT, 0777)) == -1) { + perror("open output binary"); + exit(3); + } + if (fstat(ifd, &sbuf) == -1) { + perror("fstat"); + exit(1); + } + + /* + * mmap in the whole file to work with it. + */ + if ((elffile = (void *)mmap(NULL, sbuf.st_size, PROT_READ, + MAP_PRIVATE, ifd, 0)) == MAP_FAILED) { + perror("mmap failed"); + exit(1); + } + ehdr = (Elf32_Ehdr *)elffile; + + if (*(int *)(ehdr->e_ident) != *(int *)(ELFMAG)) { + perror("not elf file "); + exit(5); + } + + s = (Elf32_Shdr *)((char *)elffile + ehdr->e_shoff); + /* + * find a pointer to the first allocated section header + * and the bss(NOBITS) section header. + */ + for (i = 0; i < ehdr->e_shnum; i++, s++) { + if (!(s->sh_flags & SHF_ALLOC)) + continue; + if (!first_shdr) { + first_shdr = s; + continue; + } + if (s->sh_type == SHT_NOBITS) { + nobits_shdr = s; + break; + } + } + + if ((first_shdr == NULL) || (nobits_shdr == NULL)) { + (void) fprintf(stderr, "ERROR: Missing headers in elf file.\n"); + exit(1); + } + + bytes = nobits_shdr->sh_offset - first_shdr->sh_offset; + if (write(ofd, (char *)elffile + first_shdr->sh_offset, + bytes) != bytes) { + perror("write sections"); + exit(1); + } + total = bytes + nobits_shdr->sh_size; + /* + * round up to the next 512k block + */ + if (total % 512 != 0) + total += 512 - (total % 512); + + if (ftruncate(ofd, total) == -1) { + perror("ftruncate"); + exit(1); + } + + (void) close(ifd); + (void) close(ofd); + exit(0); +} diff --git a/usr/src/psm/stand/boot/i386/common/multiboot.c b/usr/src/psm/stand/boot/i386/common/multiboot.c new file mode 100644 index 0000000000..618c3b7a1b --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/multiboot.c @@ -0,0 +1,285 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This program is loaded and executed by GRUB on x86 platforms. + * It is responsible for interpreting the miniroot archive + * loaded by GRUB, read unix and krtld, and jump to the kernel. + * + * Currently the kernel (_kobj_boot) expects a syscall vector, + * bootops, and elfbootvec. So we oblige by providing the + * same services for now. + */ + +#include <sys/types.h> +#include <sys/memlist.h> +#include <sys/reboot.h> +#include "multiboot.h" +#include "debug.h" +#include "standalloc.h" +#include "bootprop.h" +#include "util.h" +#include "console.h" + +typedef int (*func_t)(); +extern void setup_bootops(); +extern void setup_memlists(); +extern void init_paging(void); +extern int mountroot(char *); +extern int openfile(char *, char *); +extern int close(int); +extern void console_init(char *); +extern void kmem_init(void); +extern void init_biosprog(); +extern func_t readfile(int fd, int print); +extern void exitto(func_t); + +static void print_mbinfo(void); + +int debug; + +#define dprintf if (debug & D_MBOOT) printf + +multiboot_info_t *mbi; +multiboot_header_t *mbh; +void *elfbootvec; /* XXX dummy for 32-bit exitto */ + +char *bootfile_prop = NULL; +char *inputdevice_prop = NULL; +char *outputdevice_prop = NULL; +char *console_prop = NULL; + +extern uint_t bpd_loc; +extern char *bootfile; +extern char *module_path; +extern int boot_verbose; +int is_amd64; + +#ifdef BOOTAMD64 +extern void amd64_handoff(uint64_t); +extern int amd64_config_cpu(); + +int amd64_elf64; +uint64_t elf64_go2; +#endif /* BOOTAMD64 */ + +extern int get_bootenv_props(void); +extern void vga_probe(void); + +void +main(ulong_t magic, ulong_t addr, ulong_t header) +{ + int fd; + char *grub_bootstr; + int (*entry)(); + + if (magic != MB_BOOTLOADER_MAGIC) { + /* printf isn't working, so we return to loader */ + return; + } + + /* Set MBI to the address of the Multiboot information structure. */ + mbi = (multiboot_info_t *)addr; + mbh = (multiboot_header_t *)header; + + grub_bootstr = (char *)mbi->cmdline; + console_init(grub_bootstr); /* so we can do printf */ + kmem_init(); /* initialize memory allocator */ + setup_memlists(); /* memory core for the allocator */ + + get_grub_bootargs(grub_bootstr); /* get grub cmd options */ + if (debug & D_MBINFO) + print_mbinfo(); + setup_bootops(); /* 32-bit memory ops and lists */ + init_paging(); /* turn on paging to before loading kernel */ + + if (mountroot("boot") != 0) { /* mount the ramdisk */ + panic("cannot mount boot archive\n"); + } else if (verbosemode) { + printf("mountroot succeeded\n"); + } + + init_biosprog(); /* install bios service program */ + get_bootenv_props(); /* read bootenv.rc properties */ + vga_probe(); /* probe bios for vga */ + + /* + * Set console as per eeprom(1M) if not yet specified. + * May set graphics mode, for which bios support is required. + */ + console_init2(inputdevice_prop, outputdevice_prop, + console_prop); + +#ifdef BOOTAMD64 + /* Test to see if this CPU is an AMD64 */ + is_amd64 = amd64_config_cpu(); + if (verbosemode && is_amd64) + printf("cpu is amd64 capable\n"); + if (is_amd64 == 0) + bsetprop(NULL, "CPU_not_amd64", "true", sizeof ("true")); +#endif /* BOOTAMD64 */ + + /* + * Determine the boot file + * precedence given to what's specified via grub, + * fall back to boot-file property set by eeprom(1M). + * If boot-file not set, fall back to defaults + */ + if (bootfile == NULL) { + get_eeprom_bootargs(bootfile_prop); + if (bootfile == NULL) { + bootfile = is_amd64 ? + "kernel/amd64/unix" : "kernel/unix"; + } + } + setup_bootprop(); /* set up boot properties for the kernel */ + + printf("\n"); + fd = openfile(bootfile, 0); /* open the kernel file */ + if (fd == -1) { + panic("cannot open %s\n", bootfile); + } else { + extern char filename[]; + (void) bsetprop(NULL, "whoami", filename, strlen(filename) + 1); + if (verbosemode) + printf("open kernel file: %s\n", filename); + } + + entry = readfile(fd, verbosemode); + (void) close(fd); + if (module_path) { + (void) bsetprop(NULL, "module-path", module_path, + strlen(module_path) + 1); + if (verbosemode) + printf("module_path set to: %s\n", module_path); + } + if (entry == (int (*)())-1) { + panic("no entry point in %s\n", bootfile); + } + +#ifdef BOOTAMD64 + if (amd64_elf64) { + if (verbosemode) + printf("Boot about to exit to AMD64 image at 0x%llx.\n", + (uint64_t)elf64_go2); + amd64_handoff(elf64_go2); + } +#endif + + if (verbosemode) + printf("Boot about to exit to 32-bit kernel image at 0x%x.\n", + entry); + exitto(entry); + + panic("failed to boot %s\n", bootfile); +} + +static void +print_mbinfo(void) +{ + int tmp; + + /* multiboot header */ + printf("header_addr = 0x%x\n", mbh->header_addr); + printf("load_addr = 0x%x, end = 0x%x, bss_end = 0x%x\n", + mbh->load_addr, mbh->load_end_addr, mbh->bss_end_addr); + printf("entry_addr = 0x%x\n", mbh->entry_addr); + + /* multiboot info location */ + printf("mbi = 0x%x, size = 0x%x\n", mbi, sizeof (*mbi)); + + /* flags */ + printf("flags = 0x%x\n", (unsigned)mbi->flags); + + /* memory range */ + if (MB_CHECK_FLAG(mbi->flags, 0)) + printf("mem_lower = %uKB, mem_upper = %uKB\n", + (unsigned)mbi->mem_lower, (unsigned)mbi->mem_upper); + + /* Is boot_device valid? */ + if (MB_CHECK_FLAG(mbi->flags, 1)) { + tmp = ((mbi->boot_device >> 24) & 0xff); + printf("boot_device = 0x%x", tmp); + tmp = ((mbi->boot_device >> 16) & 0xff); + printf(", part1 = 0x%x", tmp); + tmp = ((mbi->boot_device >> 8) & 0xff); + printf(", part2 = 0x%x", tmp); + tmp = (mbi->boot_device & 0xff); + printf(", part3 = 0x%x\n", tmp); + } + + /* Is the command line passed? */ + if (MB_CHECK_FLAG(mbi->flags, 2)) + printf("cmdline = %s\n", (char *)mbi->cmdline); + + /* Are mods_* valid? */ + if (MB_CHECK_FLAG(mbi->flags, 3)) { + mb_module_t *mod; + int i; + + printf("mods_count = %d, mods_addr = 0x%x\n", + (int)mbi->mods_count, (int)mbi->mods_addr); + for (i = 0, mod = (mb_module_t *)mbi->mods_addr; + i < mbi->mods_count; i++, mod++) { + printf( + " mod_start = 0x%x, mod_end = 0x%x, string = %s\n", + (unsigned)mod->mod_start, + (unsigned)mod->mod_end, (char *)mod->string); + } + } + + /* make sure we are not a.out */ + if (MB_CHECK_FLAG(mbi->flags, 4)) { + printf("Bit 4 is set, we shouldn't be using a.out format.\n"); + return; + } + + /* Is the section header table of ELF valid? */ + if (MB_CHECK_FLAG(mbi->flags, 5)) { + mb_elf_shtable_t *elf_sec = &(mbi->elf_sec); + + printf("elf_sec: num = %u, size = 0x%x," + " addr = 0x%x, shndx = 0x%x\n", + (unsigned)elf_sec->num, (unsigned)elf_sec->size, + (unsigned)elf_sec->addr, (unsigned)elf_sec->shndx); + } + + /* print drives info */ + if (MB_CHECK_FLAG(mbi->flags, 7)) { + printf("drives length %d, driver addr 0x%x\n", + mbi->drives_length, mbi->drives_addr); + } +} + +/*ARGSUSED*/ +void +trap(int trapno, int err) +{ + printf("trap type %d\n", trapno); + panic("unexpected trap in boot loader\n"); +} diff --git a/usr/src/psm/stand/boot/i386/common/multiboot.h b/usr/src/psm/stand/boot/i386/common/multiboot.h new file mode 100644 index 0000000000..2b2b1d01cf --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/multiboot.h @@ -0,0 +1,170 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MULTIBOOT_H +#define _MULTIBOOT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Multiboot header must be present withing the first + * 8192 bytes of the elf executable. The flag bit fields + * are defined to request multiboot info from the boot + * loader (see struct multiboot_info below): + * flag[0] mem_upper, mem_loader + * flag[1] boot_device + * flag[2] cmdline (for launching kernel) + * flag[3] mods_count, mods_addr + * flag[4] symbol table for a.out + * flag[5] symbol table for elf + * flag[6] mmap_length, mmap_addr + * flag[7] drives_length, drivers_addr + * flag[8] config_table + * flag[9] boot_loader_name + * flag[10] apm_table + * flag[11] vbe_control_info + * vbe_mode_info + * vbe_mode + * vbe_interface_seg + * vbe_interface_off + * vbe_interface_len + */ + +#define MB_HEADER_MAGIC 0x1BADB002 /* magic */ +#define MB_HEADER_FLAGS 0x00000003 /* flag */ +#define MB_HEADER_CHECKSUM -0x1BADB005 /* -(magic + flag) */ + +/* passed by boot loader to kernel */ +#define MB_BOOTLOADER_MAGIC 0x2BADB002 + +#define MB_NETWORK_DRIVE 0x20 /* not clear if part of spec */ + +#define STACK_SIZE 0x4000 + +#ifndef _ASM /* excluded from assembly routines */ + +#include <sys/types.h> + +/* The Multiboot header. */ +typedef struct multiboot_header { + ulong_t magic; + ulong_t flags; + ulong_t checksum; + ulong_t header_addr; + ulong_t load_addr; + ulong_t load_end_addr; + ulong_t bss_end_addr; + ulong_t entry_addr; +} multiboot_header_t; + +/* The section header table for ELF. */ +typedef struct mb_elf_shtable { + ulong_t num; + ulong_t size; + ulong_t addr; + ulong_t shndx; +} mb_elf_shtable_t; + +/* The Multiboot information. */ +typedef struct multiboot_info { + ulong_t flags; + ulong_t mem_lower; + ulong_t mem_upper; + ulong_t boot_device; + ulong_t cmdline; + ulong_t mods_count; + ulong_t mods_addr; + mb_elf_shtable_t elf_sec; + ulong_t mmap_length; + ulong_t mmap_addr; + ulong_t drives_length; /* overload with dhcpack */ + ulong_t drives_addr; + ulong_t config_table; + ulong_t boot_loader_name; + ulong_t apm_table; + ulong_t vbe_control_info; + ulong_t vbe_mode_info; + ushort_t vbe_mode; + ushort_t vbe_interface_seg; + ushort_t vbe_interface_off; + ushort_t vbe_interface_len; +} multiboot_info_t; + +/* The module structure. */ +typedef struct mb_module { + ulong_t mod_start; + ulong_t mod_end; + ulong_t string; + ulong_t reserved; +} mb_module_t; + +/* + * The memory map. Be careful that the offset 0 is base_addr_low + * but no size. + */ +typedef struct mb_memory_map { + ulong_t size; + ulong_t base_addr_low; + ulong_t base_addr_high; + ulong_t length_low; + ulong_t length_high; + ulong_t type; +} mb_memory_map_t; + +/* + * netinfo for Solaris diskless booting + * XXX - not part of multiboot spec + */ +struct sol_netinfo { + uint8_t sn_infotype; + uint8_t sn_mactype; + uint8_t sn_maclen; + uint8_t sn_padding; + ulong_t sn_ciaddr; + ulong_t sn_siaddr; + ulong_t sn_giaddr; + ulong_t sn_netmask; + uint8_t sn_macaddr[1]; +}; + +/* identify bootp/dhcp reply or rarp/ifconfig */ +#define SN_TYPE_BOOTP 2 +#define SN_TYPE_RARP 0xf0 + +/* Check if the bit BIT in FLAGS is set. */ +#define MB_CHECK_FLAG(flags, bit) ((flags) & (1 << (bit))) + +#endif /* _ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MULTIBOOT_H */ diff --git a/usr/src/psm/stand/boot/i386/common/serial.h b/usr/src/psm/stand/boot/i386/common/serial.h new file mode 100644 index 0000000000..d63264fa74 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/serial.h @@ -0,0 +1,83 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1997, Sun Microsystems, Inc. All Rights Reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* ---- ports on 16550 serial chips ---- */ +#define DAT 0 /* ... data */ +#define ICR 1 /* ... intr control reg */ +#define ISR 2 /* ... intr status reg */ +#define LCR 3 /* ... line control reg */ +#define MCR 4 /* ... modem control reg */ +#define LSR 5 /* ... line status reg */ +#define MSR 6 /* ... modem status reg */ +#define DLL 0 /* ... data latch low (used for baud rate) */ +#define DLH 1 /* ... data latch high (ditto) */ +#define FIFOR ISR /* ... fifo write reg */ + +/* ---- convenant macros ---- */ +/* this macro uses the _chario_io_p structure */ +#define INB(a, off) \ + (inb((a) + off)) +#define OUTB(a, off, val) \ + (outb((a)+(off), (char)(val))) + +/* ---- LSR bits ---- */ +#define RCA 0x01 /* ... receive char avail */ +#define XHRE 0x20 /* ... xmit hold buffer empty */ + +/* ---- Modem bits ---- */ +#define DTR 0x01 +#define RTS 0x02 +#define OUT2 0x08 + +#define FIFO_ON 0x01 +#define FIFO_OFF 0x00 +#define FIFORXFLSH 0x02 +#define FIFOTXFLSH 0x04 +#define FIFODMA 0x08 + +/* ---- LCR bits ---- */ +#define STOP1 00 +#define STOP2 0x04 +#define BITS5 0x00 /* 5 bits per char */ +#define BITS6 0x01 /* 6 bits per char */ +#define BITS7 0x02 /* 7 bits per char */ +#define BITS8 0x03 /* 8 bits per char */ + +/* baud rate definitions */ +#define DLAB 0x80 /* divisor latch access bit */ +#define ASY110 1047 /* 110 baud rate for serial console */ +#define ASY150 768 /* 150 baud rate for serial console */ +#define ASY300 384 /* 300 baud rate for serial console */ +#define ASY600 192 /* 600 baud rate for serial console */ +#define ASY1200 96 /* 1200 baud rate for serial console */ +#define ASY2400 48 /* 2400 baud rate for serial console */ +#define ASY4800 24 /* 4800 baud rate for serial console */ +#define ASY9600 12 /* 9600 baud rate for serial console */ +#define ASY19200 6 /* 19200 baud rate for serial console */ +#define ASY38400 3 /* 38400 baud rate for serial console */ +#define ASY57600 2 /* 57600 baud rate for serial console */ +#define ASY115200 1 /* 115200 baud rate for serial console */ diff --git a/usr/src/psm/stand/boot/i386/common/standalloc.c b/usr/src/psm/stand/boot/i386/common/standalloc.c new file mode 100644 index 0000000000..018625e773 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/standalloc.c @@ -0,0 +1,481 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/promif.h> +#include <sys/memlist.h> +#include <sys/bootconf.h> +#include "multiboot.h" +#include "util.h" +#include "standalloc.h" +#include "debug.h" + +#define dprintf if (debug & D_ALLOC) printf + +/* memory lists */ +struct memlist *pinstalledp, *pfreelistp, *vfreelistp, *pbooterp; +struct memlist *ppcimemp, *pramdiskp; + +extern multiboot_info_t *mbi; +extern multiboot_header_t *mbh; +extern int verbosemode; + +extern int map_phys(int, size_t, caddr_t, uint64_t); + +/* scratch memory */ +uint_t magic_phys = MAGIC_PHYS; +uint_t lomem_phys = 0x1000000; /* try not to use memory below 16M */ +uint64_t scratchmem_start, scratchmem_end; +uint64_t ramdisk_start, ramdisk_end; + +static void +memlist_dump(struct memlist *listp) +{ + while (listp) { + dprintf("(0x%x%x, 0x%x%x)", + (int)(listp->address >> 32), (int)listp->address, + (int)(listp->size >> 32), (int)listp->size); + listp = listp->next; + } + dprintf("\n"); +} + +static struct memlist * +memlist_alloc() +{ + return ((struct memlist *)bkmem_alloc(sizeof (struct memlist))); +} + +static void +memlist_free(struct memlist *buf) +{ + bkmem_free(buf, sizeof (struct memlist)); +} + +/* insert in the order of addresses */ +static void +memlist_insert(struct memlist **listp, uint64_t addr, uint64_t size) +{ + struct memlist *entry; + struct memlist *prev = 0, *next; + + /* find the location in list */ + next = *listp; + while (next && next->address < addr) { + prev = next; + next = prev->next; + } + + if (prev == 0) { + entry = memlist_alloc(); + entry->address = addr; + entry->size = size; + entry->next = *listp; + *listp = entry; + return; + } + + /* coalesce entries if possible */ + if (addr == prev->address + prev->size) { + prev->size += size; + } else { + entry = memlist_alloc(); + entry->address = addr; + entry->size = size; + entry->next = next; + prev->next = entry; + } +} + +/* delet memory chunks, assuming list sorted by address */ +static int +memlist_remove(struct memlist **listp, uint64_t addr, uint64_t size) +{ + struct memlist *entry; + struct memlist *prev = 0, *next; + + /* find the location in list */ + next = *listp; + while (next && (next->address + next->size < addr)) { + prev = next; + next = prev->next; + } + + if (next == 0 || (addr < next->address)) { + dprintf("memlist_remove: addr 0x%x%x, size 0x%x%x" + " not contained in list\n", + (int)(addr >> 32), (int)addr, + (int)(size >> 32), (int)size); + memlist_dump(*listp); + return (-1); + } + + if (addr > next->address) { + uint64_t oldsize = next->size; + next->size = addr - next->address; + if ((next->address + oldsize) > (addr + size)) { + entry = memlist_alloc(); + entry->address = addr + size; + entry->size = next->address + oldsize - addr - size; + entry->next = next->next; + next->next = entry; + } + } else if ((next->address + next->size) > (addr + size)) { + /* addr == next->address */ + next->address = addr + size; + next->size -= size; + } else { + /* the entire chunk is deleted */ + if (prev == 0) { + *listp = next->next; + } else { + prev->next = next->next; + } + memlist_free(next); + } + + return (0); +} + +/* + * find and claim a memory chunk of given size, bypassing + * scratch memory + room below 8MB + */ +static uint64_t +memlist_find(struct memlist **listp, uint_t size, int align) +{ + uint_t delta; + uint64_t paddr; + struct memlist *prev = 0, *next; + + /* find the chunk with sufficient size */ + next = *listp; + while (next && + (next->address < lomem_phys || (next->size < size + align - 1))) { + prev = next; + next = prev->next; + } + + if (next == NULL) + return (0); + + paddr = next->address; + delta = (uint_t)paddr & (align - 1); + if (delta) + paddr += align - delta; + (void) memlist_remove(listp, paddr, size); + return (paddr); +} + +static void +memlists_print() +{ + printf("Installed physical memory:\n"); + memlist_dump(pinstalledp); + printf("BIOS reserved physical memory:\n"); + memlist_dump(ppcimemp); + printf("Booter occupied memory (including modules):\n"); + memlist_dump(pbooterp); + printf("Ramdisk memory:\n"); + memlist_dump(pramdiskp); + printf("Available physical memory:\n"); + memlist_dump(pfreelistp); + printf("Available virtual memory:\n"); + memlist_dump(vfreelistp); +} + +void +setup_memlists(void) +{ + int i; + uint64_t address, size; + mb_memory_map_t *mmap; + mb_module_t *mod; + struct memlist *entry; + + /* + * initialize scratch memory so we can call bkmem_alloc + * to get memory for keeping track of memory lists + */ + reset_alloc(); + + /* + * initialize RAM list (pinstalledp) and available pci memory + * PCI memory excludes memory below 1M (realmode) + */ + memlist_insert(&ppcimemp, 0x100000, 0xFFF00000ULL); + for (mmap = (mb_memory_map_t *)mbi->mmap_addr; + (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length; + mmap = (mb_memory_map_t *)((unsigned long)mmap + + mmap->size + sizeof (mmap->size))) { + address = ((uint64_t)mmap->base_addr_high << 32) + + (uint64_t)mmap->base_addr_low; + size = ((uint64_t)mmap->length_high << 32) + + (uint64_t)mmap->length_low; + + switch (mmap->type) { + case 1: /* RAM */ + memlist_insert(&pinstalledp, address, size); + memlist_insert(&pfreelistp, address, size); + /*FALLTHROUGH*/ + default: /* Take out of available pci memory space */ + memlist_remove(&ppcimemp, address, size); + break; + } + } + + /* + * initialize memory occupied by the booter + * make the boundary page aligned to simplify + * MMU stuff + */ + address = rounddown(mbh->load_addr, PAGESIZE); + size = roundup(mbh->bss_end_addr, PAGESIZE) - + rounddown(mbh->load_addr, PAGESIZE); + memlist_insert(&pbooterp, address, size); + + /* where the modules are in memory */ + for (i = 0, mod = (mb_module_t *)mbi->mods_addr; + i < mbi->mods_count; i++, mod++) { + /* round up to page boundaries */ + address = rounddown(mod->mod_start, PAGESIZE); + size = roundup(mod->mod_end, PAGESIZE) - + rounddown(mod->mod_start, PAGESIZE); + + /* assume first one is ramdisk */ + if (ramdisk_end == 0) { + ramdisk_start = mod->mod_start; + ramdisk_end = mod->mod_end; + if (verbosemode) { + printf("ramdisk is at 0x%llx-0x%llx\n", + ramdisk_start, ramdisk_end); + } + memlist_insert(&pramdiskp, address, size); + } else { + memlist_insert(&pbooterp, address, size); + } + } + + /* delete booter memory from pfreelistp */ + entry = pbooterp; + while (entry) { + address = entry->address; + size = entry->size; + (void) memlist_remove(&pfreelistp, address, size); + entry = entry->next; + } + + /* delete ramdisk memory */ + entry = pramdiskp; + while (entry) { + address = entry->address; + size = entry->size; + (void) memlist_remove(&pfreelistp, address, size); + entry = entry->next; + } + + /* + * initialize free virtual memory list + * start withe the entire range + * delete booter memory + */ + memlist_insert(&vfreelistp, 0, 0x100000000LL); + entry = pbooterp; + while (entry) { + address = entry->address; + size = entry->size; + (void) memlist_remove(&vfreelistp, address, size); + entry = entry->next; + } + + if (debug & D_ALLOC) + memlists_print(); +} + +/* resource allocate routines */ +void +reset_alloc(void) +{ + if (verbosemode) + printf("initialize scratch memory \n"); + + /* reclaim existing scratch memory */ + if (scratchmem_end > scratchmem_start) { + memlist_insert(&pfreelistp, scratchmem_start, + (uint64_t)magic_phys - scratchmem_start); + } + + /* start allocating at 1MB */ + scratchmem_end = scratchmem_start = 0x100000; +} + +/* + * allocate memory with an identical physical and virtual address + */ +caddr_t +idmap_mem(uint32_t virthint, size_t bytes, int align) +{ + caddr_t addr = 0; + + /* sanity checks */ + if (bytes == 0) + return ((caddr_t)0); + + if (virthint == 0) { + addr = (caddr_t)memlist_find(&pfreelistp, bytes, align); + } else if (memlist_remove( + &pfreelistp, (uint64_t)virthint, (uint64_t)bytes) == 0) { + addr = (caddr_t)virthint; + } + + if (addr == 0) { + printf("idmap_mem: failed to find phys 0x%x bytes at 0x%x\n", + bytes, virthint); + return (0); + } + + /* + * For any piece of low (< kernelbase) physical memory, we + * either map it 1:1 or map it above kernelbase. Hence, the + * corresponding virtual memory is always available by design. + */ + if (memlist_remove(&vfreelistp, (uint64_t)addr, (uint64_t)bytes) != 0) { + printf("idmap_mem: failed to find virtual 0x%x bytes at 0x%x\n", + bytes, addr); + (void) memlist_insert(&pfreelistp, (uint64_t)addr, + (uint64_t)bytes); + return (0); + } + + if (map_phys(0, bytes, addr, (uint64_t)addr) == -1) { + printf("idmap_mem: failed to 1:1 map 0x%x bytes at 0x%x\n", + bytes, addr); + (void) memlist_insert(&pfreelistp, (uint64_t)addr, + (uint64_t)bytes); + (void) memlist_insert(&vfreelistp, (uint64_t)addr, + (uint64_t)bytes); + return (0); + } + + return (addr); +} + +/* + * allocate memory with a physical mapping + */ +/*ARGSUSED*/ +caddr_t +phys_alloc_mem(size_t bytes, int align) +{ + /* sanity checks */ + if (bytes == 0) + return ((caddr_t)0); + + return ((caddr_t)memlist_find(&pfreelistp, bytes, align)); +} + +/*ARGSUSED*/ +caddr_t +resalloc(enum RESOURCES type, size_t bytes, caddr_t virthint, int align) +{ + uint_t delta; + caddr_t vaddr; + uint64_t paddr; + + /* sanity checks */ + if (bytes == 0) + return ((caddr_t)0); + + if (scratchmem_end == 0) + prom_panic("scratch memory uninitialized\n"); + + switch (type) { + case RES_BOOTSCRATCH: + + /* scratch memory */ + vaddr = (caddr_t)scratchmem_end; + bytes = roundup(bytes, PAGESIZE); + scratchmem_end += bytes; + if (scratchmem_end > magic_phys) + prom_panic("scratch memory overflow!"); + return (vaddr); + /*NOTREACHED*/ + + case RES_CHILDVIRT: + + /* program memory */ + + delta = (uint_t)virthint & (PAGESIZE - 1); + if (delta) + goto fail; /* not page aligned */ + + vaddr = virthint - delta; + bytes += delta; + bytes = roundup(bytes, PAGESIZE); + + if (memlist_remove(&vfreelistp, + (uint64_t)vaddr, (uint64_t)bytes)) + goto fail; /* virtual memory not available */ + if (align == 0) + align = 1; + paddr = memlist_find(&pfreelistp, bytes, align); + if (paddr == -1) + goto fail; /* out of physical memory */ + if (map_phys(0, bytes, vaddr, paddr) == -1) + goto fail; + return (vaddr); + /*NOTREACHED*/ + } + +fail: + dprintf("resalloc of 0x%x bytes at 0x%x failed", bytes, virthint); + return (0); +} + +void +resfree(caddr_t addr, size_t bytes) +{ + /* scratch memory is freed one one shot */ + if ((uint_t)addr < magic_phys) + return; + dprintf("resfree: 0x%x 0x%x not implemented\n", addr, bytes); +} + +int +get_progmemory(caddr_t vaddr, size_t size, int align) +{ + uint_t n = (uint_t)vaddr & (PAGESIZE - 1); + + if (n) { + vaddr -= n; + size += n; + } + + if (resalloc(RES_CHILDVIRT, size, vaddr, align) != vaddr) + return (-1); + return (0); +} diff --git a/usr/src/psm/stand/boot/i386/common/standalloc.h b/usr/src/psm/stand/boot/i386/common/standalloc.h new file mode 100644 index 0000000000..ee99de104b --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/standalloc.h @@ -0,0 +1,67 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_STANDALLOC_H +#define _SYS_STANDALLOC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/saio.h> + +#define NULL 0 +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#define rounddown(x, y) (((x)/(y))*(y)) + +/* backing resources for memory allocation */ +caddr_t resalloc(enum RESOURCES type, size_t, caddr_t, int); +void resfree(caddr_t, size_t); +void reset_alloc(void); + +/* memory allocation */ +void *bkmem_alloc(size_t); +void *bkmem_zalloc(size_t); +void bkmem_free(void *, size_t); +int get_progmemory(caddr_t, size_t, int); +void *vmx_zalloc_identity(size_t); + +/* + * BOPF_X86_ALLOC_IDMAP: identical virtual/physical address + * BOPF_X86_ALLOC_PHYS: physical address + */ +caddr_t idmap_mem(uint32_t, size_t, int); +caddr_t phys_alloc_mem(size_t, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STANDALLOC_H */ diff --git a/usr/src/psm/stand/boot/i386/common/util.h b/usr/src/psm/stand/boot/i386/common/util.h new file mode 100644 index 0000000000..35e8fda205 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/util.h @@ -0,0 +1,61 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _STRINGS_H +#define _STRINGS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/varargs.h> +#include <sys/promif.h> + +/* + * This header file contains most of the libc-like interfaces + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void bzero(void *, size_t); +extern void bcopy(const void *, void *, size_t); +extern uint_t strlen(const char *); +extern int strcmp(const char *, const char *); +extern int strncmp(const char *, const char *, size_t); +extern char *strcat(char *, const char *); +extern char *strcpy(char *, const char *); +extern char *strrchr(const char *, int); +extern char *strstr(const char *, const char *); + +extern void printf(const char *, ...); +extern void panic(const char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* _STRINGS_H */ diff --git a/usr/src/psm/stand/boot/i386/common/vga.c b/usr/src/psm/stand/boot/i386/common/vga.c new file mode 100644 index 0000000000..c9b0f30443 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/vga.c @@ -0,0 +1,117 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Miniature VGA driver for bootstrap. + */ + +#include <sys/archsystm.h> +#include <sys/vgareg.h> +#include "vga.h" + +#define VGA_COLOR_CRTC_INDEX 0x3d4 +#define VGA_COLOR_CRTC_DATA 0x3d5 +#define VGA_SCREEN ((unsigned short *)0xb8000) + +static void vga_set_crtc(int index, unsigned char val); +static unsigned char vga_get_crtc(int index); + +void +vga_clear(int color) +{ + unsigned short val; + int i; + + val = (color << 8) | ' '; + + for (i = 0; i < VGA_TEXT_ROWS * VGA_TEXT_COLS; i++) { + VGA_SCREEN[i] = val; + } +} + +void +vga_drawc(int c, int color) +{ + int row; + int col; + + vga_getpos(&row, &col); + VGA_SCREEN[row*VGA_TEXT_COLS + col] = (color << 8) | c; +} + +void +vga_scroll(int color) +{ + unsigned short val; + int i; + + val = (color << 8) | ' '; + + for (i = 0; i < (VGA_TEXT_ROWS-1)*VGA_TEXT_COLS; i++) { + VGA_SCREEN[i] = VGA_SCREEN[i + VGA_TEXT_COLS]; + } + for (; i < VGA_TEXT_ROWS * VGA_TEXT_COLS; i++) { + VGA_SCREEN[i] = val; + } +} + +void +vga_setpos(int row, int col) +{ + int off; + + off = row * VGA_TEXT_COLS + col; + vga_set_crtc(VGA_CRTC_CLAH, off >> 8); + vga_set_crtc(VGA_CRTC_CLAL, off & 0xff); +} + +void +vga_getpos(int *row, int *col) +{ + int off; + + off = (vga_get_crtc(VGA_CRTC_CLAH) << 8) + + vga_get_crtc(VGA_CRTC_CLAL); + *row = off / VGA_TEXT_COLS; + *col = off % VGA_TEXT_COLS; +} + +static void +vga_set_crtc(int index, unsigned char val) +{ + outb(VGA_COLOR_CRTC_INDEX, index); + outb(VGA_COLOR_CRTC_DATA, val); +} + + +static unsigned char +vga_get_crtc(int index) +{ + outb(VGA_COLOR_CRTC_INDEX, index); + return (inb(VGA_COLOR_CRTC_DATA)); +} diff --git a/usr/src/psm/stand/boot/i386/common/vga.h b/usr/src/psm/stand/boot/i386/common/vga.h new file mode 100644 index 0000000000..ec7fd2c371 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/vga.h @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _VGA_H +#define _VGA_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Interface to the bootstrap's internal VGA driver. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define VGA_IO_WMR 0x3C8 /* vga io DAC write mode register */ +#define VGA_IO_DR 0x3C9 /* vga io DAC data register */ +#define VGA_IO_IS 0x3DA /* vga io input status register */ + +#define VGA_TEXT_COLS 80 +#define VGA_TEXT_ROWS 25 + +extern void vga_setpos(int, int); +extern void vga_getpos(int *, int *); +extern void vga_clear(int); +extern void vga_scroll(int); +extern void vga_drawc(int, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _VGA_H */ diff --git a/usr/src/psm/stand/boot/i386/common/vgaprobe.c b/usr/src/psm/stand/boot/i386/common/vgaprobe.c new file mode 100644 index 0000000000..833c6014f6 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/common/vgaprobe.c @@ -0,0 +1,204 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/controlregs.h> +#include <sys/bootconf.h> +#include <sys/bootvfs.h> +#include <sys/psw.h> +#include "multiboot.h" +#include "bootprop.h" +#include "biosint.h" +#include "machine.h" +#include "standalloc.h" +#include "console.h" +#include "util.h" +#include "debug.h" + +#define FP_SEG(fp) ((((unsigned long)(fp)) >> 16) & 0xffff) +#define FP_OFF(fp) (((unsigned long)(fp)) & 0xffff) + +#define VESABIOS_SUPP_FUNC 0x4f +#define VESABIOS_DISPLAY_ID_EXT 0x15 + +#pragma pack(1) +/* + * Structure returned by monitors that support VESA DDC + */ +struct EDIFinfo { + unsigned char hdr[8]; + unsigned short mfname; /* EISA style compressed id */ + unsigned short pid; + unsigned long serialno; + char mfweek; + unsigned char mfyear; + unsigned char edidver; + unsigned char edidrev; + unsigned char vidindef; + unsigned char maxHimagesz; /* cm */ + unsigned char maxVimagesz; /* cm */ + unsigned char displayxferchar; + unsigned char DPMSfeat; + unsigned char RGlowbits; + unsigned char BWlowbits; + unsigned char redx; + unsigned char redy; + unsigned char greenx; + unsigned char greeny; + unsigned char bluex; + unsigned char bluey; + unsigned char whitex; + unsigned char whitey; + unsigned char esttimings1; + unsigned char esttimings2; + unsigned char rsvdtimings; + short stdtimingid1; + short stdtimingid2; + short stdtimingid3; + short stdtimingid4; + short stdtimingid5; + short stdtimingid6; + short stdtimingid7; + short stdtimingid8; + unsigned char dettimingdesc1[18]; + unsigned char dettimingdesc2[18]; + unsigned char dettimingdesc3[18]; + unsigned char dettimingdesc4[18]; + unsigned char extflg; + unsigned char chksum; +}; +#pragma pack() + +/* + * Address at which we can read/write a structure + * in common with the bios. + * + * Current memory layout: + * 1mb: multiboot + * 0x6000: our scratch memory + * 0x5000: stack, grows downward + * 0x2000: biosint + * 0x1000: bios + */ +#define LOMEM_SCRATCH_ADDR 0x6000 + + +#define dprintf if (debug & D_BIOS) printf + +int (*bios_doint)(int, struct int_pb *); + + +static const char hextab[] = "0123456789ABCDEF"; + +static void +DecompressName(unsigned long id, char *np) +{ + /* + * Expand an EISA device name + * + * This converts a 32-bit EISA device "id" to a + * 7-byte ASCII device name, which is stored at "np". + */ + + *np++ = '@' + ((id >> 2) & 0x1F); + *np++ = '@' + ((id << 3) & 0x18) + ((id >> 13) & 0x07); + *np++ = '@' + ((id >> 8) & 0x1F); + *np++ = hextab[(id >> 20) & 0x0F]; + *np++ = hextab[(id >> 16) & 0x0F]; + *np++ = hextab[(id >> 28) & 0x0F]; + *np++ = hextab[(id >> 24) & 0x0F]; + *np = 0; +} + +void +vga_probe(void) +{ + int ret; + struct int_pb ic = {0}; + char *fp; + char name[8]; + struct EDIFinfo *edifp = (struct EDIFinfo *)LOMEM_SCRATCH_ADDR; + + /* + * See what level of VESA DDC is supported (if any) + */ + ic.ax = (VESABIOS_SUPP_FUNC << 8) | VESABIOS_DISPLAY_ID_EXT; + ic.bx = 0x00; /* Report DDC Capcbilities */ + ic.cx = 0; + ic.dx = 0; + ic.es = 0; + ic.dx = 0; + ret = bios_doint(0x10, &ic); + dprintf("vga probe report ddc: ret=%0x ax=0x%x dx=0x%x\n", + ret, ic.ax, ic.dx); + if (!(ret & PS_C) && (ic.ax & 0xff) == VESABIOS_SUPP_FUNC) { + /* + * BIOS supports VBE/DDC extension + */ + if (ic.bx & 0x03) { /* DDC1 or DDC2 supported */ + unsigned long mfn, compid; + + /* + * Get VESA DDC EDIF info + */ + edifp->edidver = 0; + ic.ax = (VESABIOS_SUPP_FUNC << 8) | + VESABIOS_DISPLAY_ID_EXT; + ic.bx = 0x01; /* Read EDID */ + ic.cx = 0; + ic.dx = 0; + fp = (char *)edifp; + ic.es = FP_SEG(fp); + ic.di = FP_OFF(fp); + dprintf("addr 0x%x, seg 0x%x, off 0x%x\n", + fp, FP_SEG(fp), FP_OFF(fp)); + + ret = bios_doint(0x10, &ic); + dprintf( + "vga probe read edid: ret=%0x ax=0x%x dx=0x%x\n", + ret, ic.ax, ic.dx); + if (!(ret & PS_C) && edifp->edidver != 0) { + dprintf("display-edif-block: len %d\n", + sizeof (struct EDIFinfo)); + (void) bsetprop(NULL, "display-edif-block", + edifp, sizeof (struct EDIFinfo)); + /* + * Set edif id as a property + */ + mfn = (long)edifp->mfname; + compid = (long)edifp->pid << 24 | mfn | + ((long)(edifp->pid & 0xff00) << 8); + DecompressName(compid, name); + dprintf("display-edif-id: %s\n", name); + (void) bsetprop(NULL, "display-edif-id", + name, strlen(name) + 1); + } + } + } +} diff --git a/usr/src/psm/stand/boot/i386/i86pc/Makefile b/usr/src/psm/stand/boot/i386/i86pc/Makefile new file mode 100644 index 0000000000..672e381b2c --- /dev/null +++ b/usr/src/psm/stand/boot/i386/i86pc/Makefile @@ -0,0 +1,52 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +TOPDIR = ../../../../.. +PLATFORM = i86pc +KARCH = $(PLATFORM) +ARCHVERS = +ARCHOPTS = -Di386 -D__i386 -DI386BOOT -DBOOTAMD64 -D_ELF64_SUPPORT +ARCHOPTS += -DMULTIBOOT + +PLAT_C_SRC = +ARCH_C_SRC = +ARCH_S_SRC = cpu_id.s idttab.s samuldiv64.s +START_S_SRC = asm.s +BIOS_S_SRC = biosint.s + +TOOLSRC = $(TOPDIR)/tools + +include ../Makefile.com + +$(ROOT_PSM_UNIBOOT):= OWNER= root +$(ROOT_PSM_UNIBOOT):= GROUP= sys +$(ROOT_PSM_UNIBOOT):= FILEMODE= 755 + +$(ROOT_PSM_BIOSINT):= OWNER= root +$(ROOT_PSM_BIOSINT):= GROUP= sys +$(ROOT_PSM_BIOSINT):= FILEMODE= 755 diff --git a/usr/src/psm/stand/boot/i386/i86pc/asm.s b/usr/src/psm/stand/boot/i386/i86pc/asm.s new file mode 100644 index 0000000000..7c4e5e9bb6 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/i86pc/asm.s @@ -0,0 +1,329 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright 2005 Sun Microsystems, Inc. All rights reserved. */ +/* Use is subject to license terms. */ + +#if defined(lint) + +#include <sys/types.h> +#include <sys/bootconf.h> + +extern void printf(const char *, ...); + +uint_t bpd_loc; +struct bootops *bop; + +void start(void) { main(0, 0, 0); } +void start_paging(void) { return; } +void halt(char *msg) { printf("%s", msg); } +void exitto(int (*entrypoint)()) {} +void reset(void); + +/* lint for inline functions in i86.il */ +/*ARGSUSED*/ +uint8_t inb(int port) { return (*(uint8_t *)port); } +uint16_t inw(int port) { return (*(uint16_t *)port); } +uint32_t inl(int port) { return (*(uint32_t *)port); } +void outb(int port, uint8_t v) { *(uint8_t *)port = v; } +void outw(int port, uint16_t v) { *(uint16_t *)port = v; } +void outl(int port, uint32_t v) { *(uint32_t *)port = v; } + +#else + +.ident "%Z%%M% %I% %E% SMI" + +#include <sys/asm_linkage.h> +#include <sys/controlregs.h> +#include <sys/segment.h> +#include "../common/multiboot.h" + +.file "asm.s" +.text + +.globl _start +_start: + jmp multiboot_entry + +/* + * The following header must be present within the first 8K of + * the binary, according to the Multiboot Specification + */ +.align 4 + +multiboot_header: + .long MB_HEADER_MAGIC / multiboot magic + .long MB_HEADER_FLAGS / flags + .long MB_HEADER_CHECKSUM / checksum + .long multiboot_header / header address + .long _start / load start addr + .long _edata / load end addr + .long _end / bss end + .long multiboot_entry / entry addr + +/* + * Start from where GRUB left off. The processor state is + * as defined in the Multiboot Specification. We start with: + * - initialize the stack, "stack" is declared at the end of file + * - push register contents to stack to pass multiboot info + * - initialize GDT and (a dummy) IDT + * - call main() to load the kernel + */ +multiboot_entry: + movl $[stack + STACK_SIZE], %esp + pushl $0 / reset flags + popf + + push $0 / terminate debugger + push $0 + movl %esp, %ebp + + movl $[multiboot_header], %ecx + pushl %ecx / multiboot header + pushl %ebx / multiboot info + pushl %eax / multiboot magic + + lgdt gdtdesc / load gdt + mov $0x08, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + ljmp $0x10, $newgdt +newgdt: + + movl $slbidt, %eax / load idt + movl $0x7ff, %ecx + call munge_table + lidt IDTptr + + call main / invoke the kernel + hlt / shouldn't get here + +/ help function +.globl halt +halt: + pushl $halt_message / halt + call printf / defined in kernel +loop1: + hlt + jmp loop1 + +halt_message: + .string "Halted." + +/ turn on paging + ENTRY(start_paging) + movl bpd_loc, %eax + movl %eax, %cr3 + + movl %cr0, %eax + orl $[CR0_PG|CR0_PE], %eax + movl %eax, %cr0 + + jmp page_flush / flush the prefetch queue +page_flush: + nop + nop + ret + SET_SIZE(start_paging) + +/ exitto 32-bit kernel + ENTRY(exitto) + push %ebp / save stack + mov %esp, %ebp + pushal / protect secondary boot + + movl %esp, %eax + movl %eax, save_esp2 + + movl $elfbootvec, %eax + pushl (%eax) + + movl $bop, %eax + movl (%eax), %ebx + pushl %ebx + + pushl $0 / no debug vector + + movl $sysp, %eax + movl (%eax), %ecx + pushl %ecx + + movl 8(%ebp), %eax + call *%eax / jump to the kernel + + movl save_esp2, %eax + movl %eax, %esp + + popal + pop %ebp / restore frame pointer + ret + SET_SIZE(exitto) + +/********************************************************************** */ +/**/ +/* munge_table: */ +/* This procedure will 'munge' a descriptor table to */ +/* change it from initialized format to runtime format. */ +/**/ +/* Assumes: */ +/* %eax -- contains the base address of table. */ +/* %ecx -- contains size of table. */ +/**/ +/* ********************************************************************* */ + ENTRY(munge_table) + + addl %eax, %ecx /* compute end of IDT array */ + movl %eax, %esi /* beginning of IDT */ + +moretable: + cmpl %esi, %ecx + jl donetable /* Have we done every descriptor?? */ + + movl %esi, %ebx /*long-vector/*short-selector/*char-rsrvd/*char- +type */ + + movb 7(%ebx), %al /* Find the byte containing the type field */ + testb $0x10, %al /* See if this descriptor is a segment */ + jne notagate + testb $0x04, %al /* See if this destriptor is a gate */ + je notagate + /* Rearrange a gate descriptor. */ + movl 4(%ebx), %edx /* Selector, type lifted out. */ + movw 2(%ebx), %ax /* Grab Offset 16..31 */ + movl %edx, 2(%ebx) /* Put back Selector, type */ + movw %ax, 6(%ebx) /* Offset 16..31 now in right place */ + jmp descdone + +notagate: /* Rearrange a non gate descriptor. */ + movw 4(%ebx), %dx /* Limit 0..15 lifted out */ + movw 6(%ebx), %ax /* acc1, acc2 lifted out */ + movb %ah, 5(%ebx) /* acc2 put back */ + movw 2(%ebx), %ax /* 16-23, 24-31 picked up */ + movb %al, 7(%ebx) /* 24-31 put back */ + movb %ah, 4(%ebx) /* 16-23 put back */ + movw (%ebx), %ax /* base 0-15 picked up */ + movw %ax, 2(%ebx) /* base 0-15 put back */ + movw %dx, (%ebx) /* lim 0-15 put back */ + +descdone: + addl $8, %esi /* Go for the next descriptor */ + jmp moretable + +donetable: + ret + SET_SIZE(munge_table) + +/ reset machine via triple fault + ENTRY(reset) + movw $0, IDTlimit / generate faulty table + lidt IDTptr / load faulty table + int $10 / trigger an interrupt + SET_SIZE(reset) + +/ Data definitions +.align 4 +.globl bpd_loc +bpd_loc: + .long 0 +.globl save_esp2 +save_esp2: + .long 0 +.globl save_esp +save_esp: + .long 0 +.globl bop +bop: + .long 0 +IDTptr: +IDTlimit: + .value 0x7ff +IDTbase: + .long slbidt + +.align 4 +gdt_start: + .long 0 + .long 0 + +flatdesc: / offset = 0x08 (GDT_BOOTFLAT << 3) + + .value 0xFFFF / segment limit 0..15 + .value 0x0000 / segment base 0..15 + .byte 0x0 / segment base 16..23; set for 0K + .byte 0x92 / flags; A=0, Type=001, DPL=00, P=1 + / Present expand down + .byte 0xCF / flags; Limit (16..19)=1111, AVL=0, G=1, B=1 + .byte 0x0 / segment base 24..32 + +codedesc: / offset = 0x10 (GDT_CODESEL << 3) + + .value 0xFFFF / segment limit 0..15 + .value 0x0000 / segment base 0..15 + .byte 0x0 / segment base 16..23; set for 0k + .byte 0x9E / flags; A=0, Type=111, DPL=00, P=1 + .byte 0xCF / flags; Limit (16..19)=1111, AVL=0, G=1, D=1 + .byte 0x0 / segment base 24..32 + +code16desc: / offset = 0x18 + + .value 0xFFFF / segment limit 0..15 + .value 0x0000 / segment base 0..15 + .byte 0x0 / segment base 16..23; set for 0k + .byte 0x9E / flags; A=0, Type=111, DPL=00, P=1 + .byte 0x0F / flags; Limit (16..19)=1111, AVL=0, G=0, D=0 + .byte 0x0 / segment base 24..32 + +datadesc: / offset = 0x20 + + .value 0xFFFF / segment limit 0..15 + .value 0x0000 / segment base 0..15 + .byte 0x0 / segment base 16..23; set for 0K + .byte 0x92 / flags; A=0, Type=001, DPL=00, P=1 + / Present expand down + .byte 0x4F / flags; Limit (16..19)=1111, AVL=0, G=1, B=1 + .byte 0x0 / segment base 24..32 + +dummy_entries: + .long 0 / 0x28 + .long 0 + .long 0 / 0x30 + .long 0 + +gsdesc: / 0x38 - for kmdb + .value 0 + .value 0 + .byte 0 + .byte 0x92 / flags; A=0, Type=001, DPL=00, P=1 + .byte 0xC0 / flags; Limit (16..19)=0000, AVL=0, G=1, B=1 + .byte 0 + +gdt_end: + +gdtdesc: + .value gdt_end - gdt_start + .long gdt_start + +.comm stack, STACK_SIZE / stack area + +#endif diff --git a/usr/src/psm/stand/boot/i386/i86pc/biosint.s b/usr/src/psm/stand/boot/i386/i86pc/biosint.s new file mode 100644 index 0000000000..1d70aeb002 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/i86pc/biosint.s @@ -0,0 +1,325 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * biosint.s - installed by kernel to make bios calls + * + * The kernel jumps here from protected mode to make a bios service call. + * Calling syntax: bios_doint(int intnum, struct int_pb *ic) + */ + .globl _start +_start: + pushl %ebp + movl %esp, %ebp + + / Save segment registers of caller. + movw %cs, call_cs + movw %ds, call_ds + movw %es, call_es + movw %fs, call_fs + movw %gs, call_gs + movw %ss, call_ss + movl %esp, call_esp + movl %esi, call_esi + movl %ebx, call_ebx + movl %ecx, call_ecx + movl %edx, call_edx + movl %edi, call_edi + + / switch stack to 0x5000 + movl $0x5000, %eax + movl %eax, %esp + jmp donelowstack +donelowstack: + + / copy args from high memory to low memory + pushl 12(%ebp) + pushl 8(%ebp) + call copyin_args + addl $8, %esp + + / insert proper interrupt for later. + movl ic_int, %eax + movb %al, newintcode+1 + + / Jump here for P5 94 byte instruction prefetch queue + jmp qflush1 +qflush1: + + / call print_regs + + / Switch interrupt descriptor tables. + cli + sidt kernIDTptr + lidt bioIDTptr + + / Save global descriptor table + sgdt kernGDTptr + + call goreal + +/ +/ NOW in REAL MODE +/ + / Clear the upper (extended) half of all registers. + / Having stray high bits on causes strange + / and unpredictable failures to occur in real mode. + / + data16; xorl %eax, %eax + addr16; movw ic_ds, %eax + push %eax / save for later + data16; addr16; movw ic_ax, %ax + data16; xorl %ebx, %ebx + addr16; mov ic_bx, %ebx + data16; xorl %ecx, %ecx + addr16; mov ic_cx, %ecx + data16; xorl %edx, %edx + addr16; mov ic_dx, %edx + data16; xorl %ebp, %ebp + addr16; mov ic_bp, %ebp + data16; xorl %edi,%edi + addr16; mov ic_di, %edi + data16; xorl %esi,%esi + addr16; mov ic_si, %esi + addr16; movw ic_es, %es + + sti + addr16; pop %ds / set effective ds +newintcode: + int $0x10 / do BIOS call + cli + pushf / save carry for later + + / save results of the BIOS call + / + addr16; movw %ax, ic_ax + addr16; movw %bx, ic_bx + addr16; movw %cx, ic_cx + addr16; movw %dx, ic_dx + addr16; movw %bp, ic_bp + addr16; movw %si, ic_si + addr16; movw %di, ic_di + addr16; movw %ds, ic_ds / real mode - stack 2-bytes word + addr16; movw %es, ic_es + + data16; movw %cs, %eax + movw %eax, %ds / restore entry ds, es + movw %eax, %es + + data16; call goprot / protect mode + +/ +/ NOW back in PROTECTED MODE. +/ + / copy results to caller's location + movl call_esp, %eax + pushl 12(%eax) + call copyout_args + addl $4, %esp + + xorl %eax, %eax / initialize return to zero + popw %ax / get eflags + + / Interrupt descriptor table + lidt kernIDTptr + + movl call_edx, %edx + movl call_ecx, %ecx + movl call_ebx, %ebx + movl call_edi, %edi + movl call_esi, %esi + / switch back to caller's stack + movl call_esp, %esp + popl %ebp + ret + +/ ---------------------------------------------------- +/ Enter real mode. +/ +/ Real mode GDT descriptors are always present as code 0x18, data 0x20 +/ + .globl goreal +goreal: + + / Transfer control to a 16 bit code segment + / This relies on knowledge of kernel's GDT + ljmp $0x18, $set16cs +set16cs: + + / need to have all segment regs sane + / before we can enter real mode + data16; movl $0x20, %eax + movw %ax, %es + movw %ax, %ds + movw %ax, %fs + movw %ax, %gs + + / clear the protection and paging bits + / jump should clear prefetch q + mov %cr0, %eax + data16; and $0x7ffffffe, %eax + mov %eax, %cr0 + + / Do a long jump here to establish %cs in real mode. + / It appears that this has to be a ljmp as opposed to + / a lret probably due to the way Intel fixed errata #25 + / on the A2 step. This leads to self modifying code. + + ljmp $0x0, $restorecs +restorecs: + / flush tlb + mov %cr3, %eax + mov %eax, %cr3 + + / we are loading in first 64K, so all segment reg should be zero + movw %cs, %ax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + data16; ret + +/ ---------------------------------------------------- +/ Enter protected mode. +/ + .globl goprot +goprot: + + / Workaround for BIOSes that mess with GDT during INT call without + / restoring original value on the way back. Hence restore it here. + + data16; addr16; lgdt kernGDTptr + + data16; popl %ebx / get return %eip, for later use + + / set protect mode and page mode + mov %cr0, %eax + data16; addr16; orl $0x80000001, %eax + mov %eax, %cr0 + + jmp qflush2 / flush the prefetch queue +qflush2: + + / Restore caller's segment registers. + / Still in 16-bit mode till %cs is restored + addr16; movw call_ds, %ds + addr16; movw call_es, %es + addr16; movw call_fs, %fs + addr16; movw call_gs, %gs + addr16; movw call_ss, %ss + + / Now, set up %cs by fiddling with the return stack and doing an lret + + data16; addr16; movw call_cs, %eax / push %cs + data16; pushl %eax + data16; pushl %ebx / push %eip + data16; lret + +/ Data definitions + .align 4 +bioIDTptr: +bioIDTlimit: + .value 0x3ff +bioIDTbase: + .long 0 + +kernGDTptr: +kernGDTlimit: + .value 0 +kernGDTbase: + .long 0 + +kernIDTptr: +kernIDTlimit: + .value 0 +kernIDTbase: + .long 0 + +/ BIOS int call arguments +.globl ic_int +ic_int: + .long 0 +.globl ic_ax +ic_ax: + .value 0 +.globl ic_bx +ic_bx: + .value 0 +.globl ic_cx +ic_cx: + .value 0 +.globl ic_dx +ic_dx: + .value 0 +.globl ic_bp +ic_bp: + .value 0 +.globl ic_si +ic_si: + .value 0 +.globl ic_di +ic_di: + .value 0 +.globl ic_ds +ic_ds: + .value 0 +.globl ic_es +ic_es: + .value 0 + +/ Caller's registers +.globl call_cs +call_cs: + .value 0 +call_ds: + .value 0 +call_es: + .value 0 +call_fs: + .value 0 +call_gs: + .value 0 +.globl call_ss +call_ss: + .value 0 +.globl call_esp +call_esp: + .long 0 +call_ebp: + .long 0 +call_esi: + .long 0 +call_edi: + .long 0 +call_ebx: + .long 0 +call_ecx: + .long 0 +call_edx: + .long 0 diff --git a/usr/src/psm/stand/boot/i386/i86pc/cpu_id.s b/usr/src/psm/stand/boot/i386/i86pc/cpu_id.s new file mode 100644 index 0000000000..8301a2a3b0 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/i86pc/cpu_id.s @@ -0,0 +1,246 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/regset.h> +#include <sys/psw.h> +#include <sys/privregs.h> +#include "../common/cpu_id.h" + +#ifdef __lint +int is486(void) { return (1); } +#else + + .file "cpu_id.s" + + .ident "%Z%%M% %I% %E% SMI" + + .text + +/ We only support 486 or better. So just return 1. + + .globl is486 +is486: + movl $1, %eax + ret + +#endif /* !lint */ + +#ifdef lint +/* + * Enable cpuid. Set max_std_cpuid_level and cpu_vendor appropriately. Returns + * 1 if cpuid present and enabled, 0 otherwise. + */ +int enable_cpuid(void) { return(1); } +int max_std_cpuid_level; +unsigned int cpu_vendor; +#else + .text + .globl enable_cpuid +enable_cpuid: + / Since no documented Cyrix cpu supports PSE, we do not care about + / enabling cpuid, yet. This routine is currently only responsible + / for setting max_std_cpuid_level and cpu_vendor. + pushl %esp + pushfl + popl %eax + movl %eax, %ecx + xorl $PS_ID, %eax + pushl %eax + popfl + pushfl + popl %eax / The above all lifted from locore.s + cmpl %eax, %ecx + jne has_it + movl $0, %eax / cpuid is not present or enabled + jmp enable_cpuid_out +has_it: + / store maxium standard cpuid level + movl $0, %eax + cpuid + movl %eax, max_std_cpuid_level + + / check to see if we are a GenuineIntel + cmpl $Genu, %ebx + jne not_intel + cmpl $ineI, %edx + jne not_intel + cmpl $ntel, %ecx + jne not_intel + movl $GenuineIntel, cpu_vendor + jmp vendor_done +not_intel: + / check to see if we are an AuthenticAMD + cmpl $Auth, %ebx + jne not_amd + cmpl $enti, %edx + jne not_amd + cmpl $cAMD, %ecx + jne not_amd + movl $AuthenticAMD, cpu_vendor +not_amd: +vendor_done: + movl $1, %eax / cpuid present and enabled +enable_cpuid_out: + popl %esp + ret + + .data + .align 4 + .globl max_std_cpuid_level + .globl cpu_vendor +max_std_cpuid_level: .long 0xffffffff +cpu_vendor: .long 0 +#endif + +#ifdef lint +int largepage_supported(void) { return(1); } +#else + .text + .globl largepage_supported +largepage_supported: + pushl %esp / save our stack value + + / test to see if cpuid level 1 supported + cmpl $1, max_std_cpuid_level + jl no + + / are we a vendor for which we know how to test for PSE + testl $[GenuineIntel|AuthenticAMD], cpu_vendor + jz no + + movl $1, %eax / capability test. Mov 1 to eax for cpuid + cpuid + andl $0x8, %edx / do you have large pages? + jz no + movl $1, %eax / yes we do have large pages + popl %esp + ret +no: + movl $0, %eax / no we don't have large pages + popl %esp + ret +#endif + +#ifdef lint +int enable_large_pages(void) { return(1); } +#else + .text + .globl enable_large_pages +enable_large_pages: + movl %cr4, %eax + orl $CR4_PSE, %eax / since we have large pages enable them + movl %eax, %cr4 +#endif + +#ifdef lint +int global_bit(void) { return(1); } +#else + .text + .globl global_bit +global_bit: + pushl %esp / save our stack value + + / test to see if cpuid level 1 supported + cmpl $1, max_std_cpuid_level + jl nogbit + + / are we a vendor for which we know how to test for PGE + testl $[GenuineIntel|AuthenticAMD], cpu_vendor + jz nogbit + + movl $1, %eax / capability test. Mov 1 to eax for cpuid + cpuid + + / are we an AMD + testl $AuthenticAMD, cpu_vendor + jz pge_at_13 + + / test to see if we are an AMD-K5 model 0 + andw $0xff0, %ax + cmpw $0x500, %ax + jl nogbit + jne pge_at_13 + + / we are an AMD-K5 model 0, so GPE is at bit 9 + testl $0x200, %edx / do you have GPE? + jmp test_pge + +pge_at_13: + testl $0x2000, %edx / do you have PGE? +test_pge: + jnz hasgbit +nogbit: + movl $0, %eax / no we don't have global pdtes + jmp global_bit_out +hasgbit: + movl $1, %eax / yes we do have global pdtes +global_bit_out: + popl %esp + ret +#endif + +#ifdef lint +int enable_global_pages(void) { return(1); } +#else + .text + .globl enable_global_pages +enable_global_pages: + movl %cr4, %eax + orl $CR4_PGE, %eax / since we have global pages enable them + movl %eax, %cr4 +#endif + +#ifdef lint +int pae_supported(void) { return (1); } +#else +.set PAE_AND_CXS, 0x140 / PAE = 0x40 & CXS = 0x100 + + .text + .globl pae_supported +pae_supported: + pushl %esp / save our stack value + + / test to see if cpuid level 1 supported + cmpl $1, max_std_cpuid_level + jl nopae + + / are we a vendor for which we know how to test for PAE and CXS + testl $[GenuineIntel|AuthenticAMD], cpu_vendor + jz nopae + + movl $1, %eax / capability test. Mov 1 to eax for cpuid + cpuid + andl $PAE_AND_CXS, %edx / do you support pae and cmpxchg8b? + cmpl $PAE_AND_CXS, %edx + jne nopae + movl $1, %eax / yes we do support pae and cmpxchg8b + popl %esp + ret +nopae: + movl $0, %eax / no we don't support pae and cmpxchg8b + popl %esp + ret +#endif diff --git a/usr/src/psm/stand/boot/i386/i86pc/idttab.s b/usr/src/psm/stand/boot/i386/i86pc/idttab.s new file mode 100644 index 0000000000..9f851fd295 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/i86pc/idttab.s @@ -0,0 +1,700 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#if defined(__lint) + +void *slbidt; + +#else + .file "idttab.s" + .ident "%Z%%M% %I% %E% SMI" + + .text + +#define VECT(label, num) \ + .align 4; \ + .globl label; \ +label: \ + push $0; \ + push $num; \ + call trap + + VECT(div0trap, 0) + VECT(dbgtrap, 1) + VECT(nmiint, 2) + VECT(brktrap, 3) + VECT(ovflotrap, 4) + VECT(boundstrap, 5) + VECT(invoptrap, 6) + VECT(ndptrap0, 7) + VECT(dbfault, 8) + VECT(overrun, 9) + VECT(invtsstrap, 10) + VECT(segnptrap, 11) + VECT(stktrap, 12) + VECT(gptrap, 13) + VECT(pftrap, 14) + VECT(resvtrap, 15) + VECT(ndperr, 16) + VECT(inval17, 17) + VECT(inval18, 18) + VECT(inval19, 19) + VECT(progent, 20) + VECT(inval21, 21) + VECT(inval22, 22) + VECT(inval23, 23) + VECT(inval24, 24) + VECT(inval25, 25) + VECT(inval26, 26) + VECT(inval27, 27) + VECT(inval28, 28) + VECT(inval29, 29) + VECT(inval30, 30) + VECT(inval31, 31) + VECT(ndptrap2, 32) + VECT(inval33, 33) + VECT(inval34, 34) + VECT(inval35, 35) + VECT(inval36, 36) + VECT(inval37, 37) + VECT(inval38, 38) + VECT(inval39, 39) + VECT(inval40, 40) + VECT(inval41, 41) + VECT(inval42, 42) + VECT(inval43, 43) + VECT(inval44, 44) + VECT(inval45, 45) + VECT(inval46, 46) + VECT(inval47, 47) + VECT(inval48, 48) + VECT(inval49, 49) + VECT(inval50, 50) + VECT(inval51, 51) + VECT(inval52, 52) + VECT(inval53, 53) + VECT(inval54, 54) + VECT(inval55, 55) + VECT(inval56, 56) + VECT(inval57, 57) + VECT(inval58, 58) + VECT(inval59, 59) + VECT(inval60, 60) + VECT(inval61, 61) + VECT(inval62, 62) + VECT(inval63, 63) + VECT(ivctM0, 64) + VECT(ivctM1, 65) + VECT(ivctM2, 66) + VECT(ivctM3, 67) + VECT(ivctM4, 68) + VECT(ivctM5, 69) + VECT(ivctM6, 70) + VECT(ivctM7, 71) + VECT(ivctM0S0, 72) + VECT(ivctM0S1, 73) + VECT(ivctM0S2, 74) + VECT(ivctM0S3, 75) + VECT(ivctM0S4, 76) + VECT(ivctM0S5, 77) + VECT(ivctM0S6, 78) + VECT(ivctM0S7, 79) + VECT(ivctM1S0, 80) + VECT(ivctM1S1, 81) + VECT(ivctM1S2, 82) + VECT(ivctM1S3, 83) + VECT(ivctM1S4, 84) + VECT(ivctM1S5, 85) + VECT(ivctM1S6, 86) + VECT(ivctM1S7, 87) + VECT(ivctM2S0, 88) + VECT(ivctM2S1, 89) + VECT(ivctM2S2, 90) + VECT(ivctM2S3, 91) + VECT(ivctM2S4, 92) + VECT(ivctM2S5, 93) + VECT(ivctM2S6, 94) + VECT(ivctM2S7, 95) + VECT(ivctM3S0, 96) + VECT(ivctM3S1, 97) + VECT(ivctM3S2, 98) + VECT(ivctM3S3, 99) + VECT(ivctM3S4, 100) + VECT(ivctM3S5, 101) + VECT(ivctM3S6, 102) + VECT(ivctM3S7, 103) + VECT(ivctM4S0, 104) + VECT(ivctM4S1, 105) + VECT(ivctM4S2, 106) + VECT(ivctM4S3, 107) + VECT(ivctM4S4, 108) + VECT(ivctM4S5, 109) + VECT(ivctM4S6, 110) + VECT(ivctM4S7, 111) + VECT(ivctM5S0, 112) + VECT(ivctM5S1, 113) + VECT(ivctM5S2, 114) + VECT(ivctM5S3, 115) + VECT(ivctM5S4, 116) + VECT(ivctM5S5, 117) + VECT(ivctM5S6, 118) + VECT(ivctM5S7, 119) + VECT(ivctM6S0, 120) + VECT(ivctM6S1, 121) + VECT(ivctM6S2, 122) + VECT(ivctM6S3, 123) + VECT(ivctM6S4, 124) + VECT(ivctM6S5, 125) + VECT(ivctM6S6, 126) + VECT(ivctM6S7, 127) + VECT(ivctM7S0, 128) + VECT(ivctM7S1, 129) + VECT(ivctM7S2, 130) + VECT(ivctM7S3, 131) + VECT(ivctM7S4, 132) + VECT(ivctM7S5, 133) + VECT(ivctM7S6, 134) + VECT(ivctM7S7, 135) + VECT(invaltrap, 255) + + .data + .align 4 + .globl slbidt +slbidt: + .4byte div0trap + .4byte 0x8f000010 + .4byte dbgtrap + .4byte 0x8f000010 + .4byte nmiint + .4byte 0x8e000010 + .4byte brktrap + .4byte 0x8f000010 + .4byte ovflotrap + .4byte 0x8f000010 + .4byte boundstrap + .4byte 0x8f000010 + .4byte invoptrap + .4byte 0x8f000010 + .4byte ndptrap0 + .4byte 0x8f000010 + .4byte dbfault + .4byte 0x8f000010 + .4byte overrun + .4byte 0x8f000010 + .4byte invtsstrap + .4byte 0x8f000010 + .4byte segnptrap + .4byte 0x8f000010 + .4byte stktrap + .4byte 0x8f000010 + .4byte gptrap + .4byte 0x8f000010 + .4byte pftrap + .4byte 0x8f000010 + .4byte resvtrap + .4byte 0x8f000010 + .4byte ndperr + .4byte 0x8f000010 + .4byte inval17 + .4byte 0x8f000010 + .4byte inval18 + .4byte 0x8f000010 + .4byte inval19 + .4byte 0x8f000010 + .4byte progent + .4byte 0x8f000010 + .4byte inval21 + .4byte 0x8f000010 + .4byte inval22 + .4byte 0x8f000010 + .4byte inval23 + .4byte 0x8f000010 + .4byte inval24 + .4byte 0x8f000010 + .4byte inval25 + .4byte 0x8f000010 + .4byte inval26 + .4byte 0x8f000010 + .4byte inval27 + .4byte 0x8f000010 + .4byte inval28 + .4byte 0x8f000010 + .4byte inval29 + .4byte 0x8f000010 + .4byte inval30 + .4byte 0x8f000010 + .4byte inval31 + .4byte 0x8f000010 + .4byte ndptrap2 + .4byte 0x8f000010 + .4byte inval33 + .4byte 0x8f000010 + .4byte inval34 + .4byte 0x8f000010 + .4byte inval35 + .4byte 0x8f000010 + .4byte inval36 + .4byte 0x8f000010 + .4byte inval37 + .4byte 0x8f000010 + .4byte inval38 + .4byte 0x8f000010 + .4byte inval39 + .4byte 0x8f000010 + .4byte inval40 + .4byte 0x8f000010 + .4byte inval41 + .4byte 0x8f000010 + .4byte inval42 + .4byte 0x8f000010 + .4byte inval43 + .4byte 0x8f000010 + .4byte inval44 + .4byte 0x8f000010 + .4byte inval45 + .4byte 0x8f000010 + .4byte inval46 + .4byte 0x8f000010 + .4byte inval47 + .4byte 0x8f000010 + .4byte inval48 + .4byte 0x8f000010 + .4byte inval49 + .4byte 0x8f000010 + .4byte inval50 + .4byte 0x8f000010 + .4byte inval51 + .4byte 0x8f000010 + .4byte inval52 + .4byte 0x8f000010 + .4byte inval53 + .4byte 0x8f000010 + .4byte inval54 + .4byte 0x8f000010 + .4byte inval55 + .4byte 0x8f000010 + .4byte inval56 + .4byte 0x8f000010 + .4byte inval57 + .4byte 0x8f000010 + .4byte inval58 + .4byte 0x8f000010 + .4byte inval59 + .4byte 0x8f000010 + .4byte inval60 + .4byte 0x8f000010 + .4byte inval61 + .4byte 0x8f000010 + .4byte inval62 + .4byte 0x8f000010 + .4byte inval63 + .4byte 0x8f000010 + .4byte ivctM0 + .4byte 0x8e000010 + .4byte ivctM1 + .4byte 0x8e000010 + .4byte ivctM2 + .4byte 0x8e000010 + .4byte ivctM3 + .4byte 0x8e000010 + .4byte ivctM4 + .4byte 0x8e000010 + .4byte ivctM5 + .4byte 0x8e000010 + .4byte ivctM6 + .4byte 0x8e000010 + .4byte ivctM7 + .4byte 0x8e000010 + .4byte ivctM0S0 + .4byte 0x8e000010 + .4byte ivctM0S1 + .4byte 0x8e000010 + .4byte ivctM0S2 + .4byte 0x8e000010 + .4byte ivctM0S3 + .4byte 0x8e000010 + .4byte ivctM0S4 + .4byte 0x8e000010 + .4byte ivctM0S5 + .4byte 0x8e000010 + .4byte ivctM0S6 + .4byte 0x8e000010 + .4byte ivctM0S7 + .4byte 0x8e000010 + .4byte ivctM1S0 + .4byte 0x8e000010 + .4byte ivctM1S1 + .4byte 0x8e000010 + .4byte ivctM1S2 + .4byte 0x8e000010 + .4byte ivctM1S3 + .4byte 0x8e000010 + .4byte ivctM1S4 + .4byte 0x8e000010 + .4byte ivctM1S5 + .4byte 0x8e000010 + .4byte ivctM1S6 + .4byte 0x8e000010 + .4byte ivctM1S7 + .4byte 0x8e000010 + .4byte ivctM2S0 + .4byte 0x8e000010 + .4byte ivctM2S1 + .4byte 0x8e000010 + .4byte ivctM2S2 + .4byte 0x8e000010 + .4byte ivctM2S3 + .4byte 0x8e000010 + .4byte ivctM2S4 + .4byte 0x8e000010 + .4byte ivctM2S5 + .4byte 0x8e000010 + .4byte ivctM2S6 + .4byte 0x8e000010 + .4byte ivctM2S7 + .4byte 0x8e000010 + .4byte ivctM3S0 + .4byte 0x8e000010 + .4byte ivctM3S1 + .4byte 0x8e000010 + .4byte ivctM3S2 + .4byte 0x8e000010 + .4byte ivctM3S3 + .4byte 0x8e000010 + .4byte ivctM3S4 + .4byte 0x8e000010 + .4byte ivctM3S5 + .4byte 0x8e000010 + .4byte ivctM3S6 + .4byte 0x8e000010 + .4byte ivctM3S7 + .4byte 0x8e000010 + .4byte ivctM4S0 + .4byte 0x8e000010 + .4byte ivctM4S1 + .4byte 0x8e000010 + .4byte ivctM4S2 + .4byte 0x8e000010 + .4byte ivctM4S3 + .4byte 0x8e000010 + .4byte ivctM4S4 + .4byte 0x8e000010 + .4byte ivctM4S5 + .4byte 0x8e000010 + .4byte ivctM4S6 + .4byte 0x8e000010 + .4byte ivctM4S7 + .4byte 0x8e000010 + .4byte ivctM5S0 + .4byte 0x8e000010 + .4byte ivctM5S1 + .4byte 0x8e000010 + .4byte ivctM5S2 + .4byte 0x8e000010 + .4byte ivctM5S3 + .4byte 0x8e000010 + .4byte ivctM5S4 + .4byte 0x8e000010 + .4byte ivctM5S5 + .4byte 0x8e000010 + .4byte ivctM5S6 + .4byte 0x8e000010 + .4byte ivctM5S7 + .4byte 0x8e000010 + .4byte ivctM6S0 + .4byte 0x8e000010 + .4byte ivctM6S1 + .4byte 0x8e000010 + .4byte ivctM6S2 + .4byte 0x8e000010 + .4byte ivctM6S3 + .4byte 0x8e000010 + .4byte ivctM6S4 + .4byte 0x8e000010 + .4byte ivctM6S5 + .4byte 0x8e000010 + .4byte ivctM6S6 + .4byte 0x8e000010 + .4byte ivctM6S7 + .4byte 0x8e000010 + .4byte ivctM7S0 + .4byte 0x8e000010 + .4byte ivctM7S1 + .4byte 0x8e000010 + .4byte ivctM7S2 + .4byte 0x8e000010 + .4byte ivctM7S3 + .4byte 0x8e000010 + .4byte ivctM7S4 + .4byte 0x8e000010 + .4byte ivctM7S5 + .4byte 0x8e000010 + .4byte ivctM7S6 + .4byte 0x8e000010 + .4byte ivctM7S7 + .4byte 0x8e000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + .4byte invaltrap + .4byte 0x8f000010 + +#endif /*__lint*/ diff --git a/usr/src/psm/stand/boot/i386/i86pc/samuldiv64.s b/usr/src/psm/stand/boot/i386/i86pc/samuldiv64.s new file mode 100644 index 0000000000..76fc0b1360 --- /dev/null +++ b/usr/src/psm/stand/boot/i386/i86pc/samuldiv64.s @@ -0,0 +1,1077 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. + * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T + * All Rights Reserved + * + * this file includes portions of uts/i86/ml/i86_subr.s + */ + +#ident "%Z%%M% %I% %E% SMI" + +#include <sys/asm_linkage.h> +#include <sys/asm_misc.h> +#include <sys/regset.h> + +#if defined(lint) || defined(__lint) +#include <sys/types.h> +#include <sys/thread.h> +#include <sys/archsystm.h> +#endif /* lint */ + +#if defined(lint) || defined(__lint) + +/* ARGSUSED */ +long long +__mul64(long long a, long long b) +{ return (0); } + +#else /* lint */ + +/ +/ function __mul64(A,B:Longint):Longint; +/ {Overflow is not checked} +/ +/ We essentially do multiply by longhand, using base 2**32 digits. +/ a b parameter A +/ x c d parameter B +/ --------- +/ ad bd +/ ac bc +/ ----------------- +/ ac ad+bc bd +/ +/ We can ignore ac and top 32 bits of ad+bc: if <> 0, overflow happened. +/ + ENTRY(__mul64) + push %ebp + mov %esp,%ebp + pushl %esi + mov 12(%ebp),%eax / A.hi (a) + mull 16(%ebp) / Multiply A.hi by B.lo (produces ad) + xchg %ecx,%eax / ecx = bottom half of ad. + movl 8(%ebp),%eax / A.Lo (b) + movl %eax,%esi / Save A.lo for later + mull 16(%ebp) / Multiply A.Lo by B.LO (dx:ax = bd.) + addl %edx,%ecx / cx is ad + xchg %eax,%esi / esi is bd, eax = A.lo (d) + mull 20(%ebp) / Multiply A.lo * B.hi (producing bc) + addl %ecx,%eax / Produce ad+bc + movl %esi,%edx + xchg %eax,%edx + popl %esi + movl %ebp,%esp + popl %ebp + ret $16 + SET_SIZE(__mul64) + +#endif /* lint */ + +/* + * multiply two long numbers and yield a u_longlong_t result, callable from C. + * Provided to manipulate hrtime_t values. + */ +#if defined(lint) || defined(__lint) + +/* result = a * b; */ + +/* ARGSUSED */ +unsigned long long +mul32(ulong a, ulong b) +{ return (0); } + +#else /* lint */ + + ENTRY(mul32) + movl 8(%esp), %eax + movl 4(%esp), %ecx + mull %ecx + ret + SET_SIZE(mul32) + +#endif /* lint */ + +/* + * C support for 64-bit modulo and division. + * Hand-customized compiler output - see comments for details. + */ + +#if defined(lint) || defined(__lint) + +/* ARGSUSED */ +uint64_t +__udiv64(uint64_t a, uint64_t b) +{ return (0); } + +/* ARGSUSED */ +uint64_t __udivrem64(uint64_t a, uint64_t b) +{ return (0); } + +/* ARGSUSED */ +uint64_t +__urem64(int64_t a, int64_t b) +{ return (0); } + +/* ARGSUSED */ +int64_t +__div64(int64_t a, int64_t b) +{ return (0); } + +/* ARGSUSED */ +int64_t __divrem64(int64_t a, int64_t b) +{ return (0); } + +/* ARGSUSED */ +int64_t +__rem64(int64_t a, int64_t b) + +{ return (0); } + +#else /* lint */ + +/* + * int32_t/int64_t division/manipulation + * + * Hand-customized compiler output: the non-GCC entry points depart from + * the SYS V ABI by requiring their arguments to be popped, and in the + * [u]divrem64 cases returning the remainder in %ecx:%esi. Note the + * compiler-generated use of %edx:%eax for the first argument of + * internal entry points. + * + * Inlines for speed: + * - counting the number of leading zeros in a word + * - multiplying two 32-bit numbers giving a 64-bit result + * - dividing a 64-bit number by a 32-bit number, giving both quotient + * and remainder + * - subtracting two 64-bit results + */ +/ #define LO(X) ((uint32_t)(X) & 0xffffffff) +/ #define HI(X) ((uint32_t)((X) >> 32) & 0xffffffff) +/ #define HILO(H, L) (((uint64_t)(H) << 32) + (L)) +/ +/ /* give index of highest bit */ +/ #define HIBIT(a, r) \ +/ asm("bsrl %1,%0": "=r"((uint32_t)(r)) : "g" (a)) +/ +/ /* multiply two uint32_ts resulting in a uint64_t */ +/ #define A_MUL32(a, b, lo, hi) \ +/ asm("mull %2" \ +/ : "=a"((uint32_t)(lo)), "=d"((uint32_t)(hi)) : "g" (b), "0"(a)) +/ +/ /* divide a uint64_t by a uint32_t */ +/ #define A_DIV32(lo, hi, b, q, r) \ +/ asm("divl %2" \ +/ : "=a"((uint32_t)(q)), "=d"((uint32_t)(r)) \ +/ : "g" (b), "0"((uint32_t)(lo)), "1"((uint32_t)hi)) +/ +/ /* subtract two uint64_ts (with borrow) */ +/ #define A_SUB2(bl, bh, al, ah) \ +/ asm("subl %4,%0\n\tsbbl %5,%1" \ +/ : "=&r"((uint32_t)(al)), "=r"((uint32_t)(ah)) \ +/ : "0"((uint32_t)(al)), "1"((uint32_t)(ah)), "g"((uint32_t)(bl)), \ +/ "g"((uint32_t)(bh))) +/ +/ /* +/ * Unsigned division with remainder. +/ * Divide two uint64_ts, and calculate remainder. +/ */ +/ uint64_t +/ UDivRem(uint64_t x, uint64_t y, uint64_t * pmod) +/ { +/ /* simple cases: y is a single uint32_t */ +/ if (HI(y) == 0) { +/ uint32_t div_hi, div_rem; +/ uint32_t q0, q1; +/ +/ /* calculate q1 */ +/ if (HI(x) < LO(y)) { +/ /* result is a single uint32_t, use one division */ +/ q1 = 0; +/ div_hi = HI(x); +/ } else { +/ /* result is a double uint32_t, use two divisions */ +/ A_DIV32(HI(x), 0, LO(y), q1, div_hi); +/ } +/ +/ /* calculate q0 and remainder */ +/ A_DIV32(LO(x), div_hi, LO(y), q0, div_rem); +/ +/ /* return remainder */ +/ *pmod = div_rem; +/ +/ /* return result */ +/ return (HILO(q1, q0)); +/ +/ } else if (HI(x) < HI(y)) { +/ /* HI(x) < HI(y) => x < y => result is 0 */ +/ +/ /* return remainder */ +/ *pmod = x; +/ +/ /* return result */ +/ return (0); +/ +/ } else { +/ /* +/ * uint64_t by uint64_t division, resulting in a one-uint32_t +/ * result +/ */ +/ uint32_t y0, y1; +/ uint32_t x1, x0; +/ uint32_t q0; +/ uint32_t normshift; +/ +/ /* normalize by shifting x and y so MSB(y) == 1 */ +/ HIBIT(HI(y), normshift); /* index of highest 1 bit */ +/ normshift = 31 - normshift; +/ +/ if (normshift == 0) { +/ /* no shifting needed, and x < 2*y so q <= 1 */ +/ y1 = HI(y); +/ y0 = LO(y); +/ x1 = HI(x); +/ x0 = LO(x); +/ +/ /* if x >= y then q = 1 (note x1 >= y1) */ +/ if (x1 > y1 || x0 >= y0) { +/ q0 = 1; +/ /* subtract y from x to get remainder */ +/ A_SUB2(y0, y1, x0, x1); +/ } else { +/ q0 = 0; +/ } +/ +/ /* return remainder */ +/ *pmod = HILO(x1, x0); +/ +/ /* return result */ +/ return (q0); +/ +/ } else { +/ /* +/ * the last case: result is one uint32_t, but we need to +/ * normalize +/ */ +/ uint64_t dt; +/ uint32_t t0, t1, x2; +/ +/ /* normalize y */ +/ dt = (y << normshift); +/ y1 = HI(dt); +/ y0 = LO(dt); +/ +/ /* normalize x (we need 3 uint32_ts!!!) */ +/ x2 = (HI(x) >> (32 - normshift)); +/ dt = (x << normshift); +/ x1 = HI(dt); +/ x0 = LO(dt); +/ +/ /* estimate q0, and reduce x to a two uint32_t value */ +/ A_DIV32(x1, x2, y1, q0, x1); +/ +/ /* adjust q0 down if too high */ +/ /* +/ * because of the limited range of x2 we can only be +/ * one off +/ */ +/ A_MUL32(y0, q0, t0, t1); +/ if (t1 > x1 || (t1 == x1 && t0 > x0)) { +/ q0--; +/ A_SUB2(y0, y1, t0, t1); +/ } +/ /* return remainder */ +/ /* subtract product from x to get remainder */ +/ A_SUB2(t0, t1, x0, x1); +/ *pmod = (HILO(x1, x0) >> normshift); +/ +/ /* return result */ +/ return (q0); +/ } +/ } +/ } + ENTRY(UDivRem) + pushl %ebp + pushl %edi + pushl %esi + subl $48, %esp + movl 68(%esp), %edi / y, + testl %edi, %edi / tmp63 + movl %eax, 40(%esp) / x, x + movl %edx, 44(%esp) / x, x + movl %edi, %esi /, tmp62 + movl %edi, %ecx / tmp62, tmp63 + jne .LL2 + movl %edx, %eax /, tmp68 + cmpl 64(%esp), %eax / y, tmp68 + jae .LL21 +.LL4: + movl 72(%esp), %ebp / pmod, + xorl %esi, %esi / <result> + movl 40(%esp), %eax / x, q0 + movl %ecx, %edi / <result>, <result> + divl 64(%esp) / y + movl %edx, (%ebp) / div_rem, + xorl %edx, %edx / q0 + addl %eax, %esi / q0, <result> + movl $0, 4(%ebp) + adcl %edx, %edi / q0, <result> + addl $48, %esp + movl %esi, %eax / <result>, <result> + popl %esi + movl %edi, %edx / <result>, <result> + popl %edi + popl %ebp + ret + .align 16 +.LL2: + movl 44(%esp), %eax / x, + xorl %edx, %edx + cmpl %esi, %eax / tmp62, tmp5 + movl %eax, 32(%esp) / tmp5, + movl %edx, 36(%esp) + jae .LL6 + movl 72(%esp), %esi / pmod, + movl 40(%esp), %ebp / x, + movl 44(%esp), %ecx / x, + movl %ebp, (%esi) + movl %ecx, 4(%esi) + xorl %edi, %edi / <result> + xorl %esi, %esi / <result> +.LL22: + addl $48, %esp + movl %esi, %eax / <result>, <result> + popl %esi + movl %edi, %edx / <result>, <result> + popl %edi + popl %ebp + ret + .align 16 +.LL21: + movl %edi, %edx / tmp63, div_hi + divl 64(%esp) / y + movl %eax, %ecx /, q1 + jmp .LL4 + .align 16 +.LL6: + movl $31, %edi /, tmp87 + bsrl %esi,%edx / tmp62, normshift + subl %edx, %edi / normshift, tmp87 + movl %edi, 28(%esp) / tmp87, + jne .LL8 + movl 32(%esp), %edx /, x1 + cmpl %ecx, %edx / y1, x1 + movl 64(%esp), %edi / y, y0 + movl 40(%esp), %esi / x, x0 + ja .LL10 + xorl %ebp, %ebp / q0 + cmpl %edi, %esi / y0, x0 + jb .LL11 +.LL10: + movl $1, %ebp /, q0 + subl %edi,%esi / y0, x0 + sbbl %ecx,%edx / tmp63, x1 +.LL11: + movl %edx, %ecx / x1, x1 + xorl %edx, %edx / x1 + xorl %edi, %edi / x0 + addl %esi, %edx / x0, x1 + adcl %edi, %ecx / x0, x1 + movl 72(%esp), %esi / pmod, + movl %edx, (%esi) / x1, + movl %ecx, 4(%esi) / x1, + xorl %edi, %edi / <result> + movl %ebp, %esi / q0, <result> + jmp .LL22 + .align 16 +.LL8: + movb 28(%esp), %cl + movl 64(%esp), %esi / y, dt + movl 68(%esp), %edi / y, dt + shldl %esi, %edi /, dt, dt + sall %cl, %esi /, dt + andl $32, %ecx + jne .LL23 +.LL17: + movl $32, %ecx /, tmp102 + subl 28(%esp), %ecx /, tmp102 + movl %esi, %ebp / dt, y0 + movl 32(%esp), %esi + shrl %cl, %esi / tmp102, + movl %edi, 24(%esp) / tmp99, + movb 28(%esp), %cl + movl %esi, 12(%esp) /, x2 + movl 44(%esp), %edi / x, dt + movl 40(%esp), %esi / x, dt + shldl %esi, %edi /, dt, dt + sall %cl, %esi /, dt + andl $32, %ecx + je .LL18 + movl %esi, %edi / dt, dt + xorl %esi, %esi / dt +.LL18: + movl %edi, %ecx / dt, + movl %edi, %eax / tmp2, + movl %ecx, (%esp) + movl 12(%esp), %edx / x2, + divl 24(%esp) + movl %edx, %ecx /, x1 + xorl %edi, %edi + movl %eax, 20(%esp) + movl %ebp, %eax / y0, t0 + mull 20(%esp) + cmpl %ecx, %edx / x1, t1 + movl %edi, 4(%esp) + ja .LL14 + je .LL24 +.LL15: + movl %ecx, %edi / x1, + subl %eax,%esi / t0, x0 + sbbl %edx,%edi / t1, + movl %edi, %eax /, x1 + movl %eax, %edx / x1, x1 + xorl %eax, %eax / x1 + xorl %ebp, %ebp / x0 + addl %esi, %eax / x0, x1 + adcl %ebp, %edx / x0, x1 + movb 28(%esp), %cl + shrdl %edx, %eax /, x1, x1 + shrl %cl, %edx /, x1 + andl $32, %ecx + je .LL16 + movl %edx, %eax / x1, x1 + xorl %edx, %edx / x1 +.LL16: + movl 72(%esp), %ecx / pmod, + movl 20(%esp), %esi /, <result> + xorl %edi, %edi / <result> + movl %eax, (%ecx) / x1, + movl %edx, 4(%ecx) / x1, + jmp .LL22 + .align 16 +.LL24: + cmpl %esi, %eax / x0, t0 + jbe .LL15 +.LL14: + decl 20(%esp) + subl %ebp,%eax / y0, t0 + sbbl 24(%esp),%edx /, t1 + jmp .LL15 +.LL23: + movl %esi, %edi / dt, dt + xorl %esi, %esi / dt + jmp .LL17 + SET_SIZE(UDivRem) + +/* + * Unsigned division without remainder. + */ +/ uint64_t +/ UDiv(uint64_t x, uint64_t y) +/ { +/ if (HI(y) == 0) { +/ /* simple cases: y is a single uint32_t */ +/ uint32_t div_hi, div_rem; +/ uint32_t q0, q1; +/ +/ /* calculate q1 */ +/ if (HI(x) < LO(y)) { +/ /* result is a single uint32_t, use one division */ +/ q1 = 0; +/ div_hi = HI(x); +/ } else { +/ /* result is a double uint32_t, use two divisions */ +/ A_DIV32(HI(x), 0, LO(y), q1, div_hi); +/ } +/ +/ /* calculate q0 and remainder */ +/ A_DIV32(LO(x), div_hi, LO(y), q0, div_rem); +/ +/ /* return result */ +/ return (HILO(q1, q0)); +/ +/ } else if (HI(x) < HI(y)) { +/ /* HI(x) < HI(y) => x < y => result is 0 */ +/ +/ /* return result */ +/ return (0); +/ +/ } else { +/ /* +/ * uint64_t by uint64_t division, resulting in a one-uint32_t +/ * result +/ */ +/ uint32_t y0, y1; +/ uint32_t x1, x0; +/ uint32_t q0; +/ unsigned normshift; +/ +/ /* normalize by shifting x and y so MSB(y) == 1 */ +/ HIBIT(HI(y), normshift); /* index of highest 1 bit */ +/ normshift = 31 - normshift; +/ +/ if (normshift == 0) { +/ /* no shifting needed, and x < 2*y so q <= 1 */ +/ y1 = HI(y); +/ y0 = LO(y); +/ x1 = HI(x); +/ x0 = LO(x); +/ +/ /* if x >= y then q = 1 (note x1 >= y1) */ +/ if (x1 > y1 || x0 >= y0) { +/ q0 = 1; +/ /* subtract y from x to get remainder */ +/ /* A_SUB2(y0, y1, x0, x1); */ +/ } else { +/ q0 = 0; +/ } +/ +/ /* return result */ +/ return (q0); +/ +/ } else { +/ /* +/ * the last case: result is one uint32_t, but we need to +/ * normalize +/ */ +/ uint64_t dt; +/ uint32_t t0, t1, x2; +/ +/ /* normalize y */ +/ dt = (y << normshift); +/ y1 = HI(dt); +/ y0 = LO(dt); +/ +/ /* normalize x (we need 3 uint32_ts!!!) */ +/ x2 = (HI(x) >> (32 - normshift)); +/ dt = (x << normshift); +/ x1 = HI(dt); +/ x0 = LO(dt); +/ +/ /* estimate q0, and reduce x to a two uint32_t value */ +/ A_DIV32(x1, x2, y1, q0, x1); +/ +/ /* adjust q0 down if too high */ +/ /* +/ * because of the limited range of x2 we can only be +/ * one off +/ */ +/ A_MUL32(y0, q0, t0, t1); +/ if (t1 > x1 || (t1 == x1 && t0 > x0)) { +/ q0--; +/ } +/ /* return result */ +/ return (q0); +/ } +/ } +/ } + ENTRY(UDiv) + pushl %ebp + pushl %edi + pushl %esi + subl $40, %esp + movl %edx, 36(%esp) / x, x + movl 60(%esp), %edx / y, + testl %edx, %edx / tmp62 + movl %eax, 32(%esp) / x, x + movl %edx, %ecx / tmp61, tmp62 + movl %edx, %eax /, tmp61 + jne .LL26 + movl 36(%esp), %esi / x, + cmpl 56(%esp), %esi / y, tmp67 + movl %esi, %eax /, tmp67 + movl %esi, %edx / tmp67, div_hi + jb .LL28 + movl %ecx, %edx / tmp62, div_hi + divl 56(%esp) / y + movl %eax, %ecx /, q1 +.LL28: + xorl %esi, %esi / <result> + movl %ecx, %edi / <result>, <result> + movl 32(%esp), %eax / x, q0 + xorl %ecx, %ecx / q0 + divl 56(%esp) / y + addl %eax, %esi / q0, <result> + adcl %ecx, %edi / q0, <result> +.LL25: + addl $40, %esp + movl %esi, %eax / <result>, <result> + popl %esi + movl %edi, %edx / <result>, <result> + popl %edi + popl %ebp + ret + .align 16 +.LL26: + movl 36(%esp), %esi / x, + xorl %edi, %edi + movl %esi, 24(%esp) / tmp1, + movl %edi, 28(%esp) + xorl %esi, %esi / <result> + xorl %edi, %edi / <result> + cmpl %eax, 24(%esp) / tmp61, + jb .LL25 + bsrl %eax,%ebp / tmp61, normshift + movl $31, %eax /, tmp85 + subl %ebp, %eax / normshift, normshift + jne .LL32 + movl 24(%esp), %eax /, x1 + cmpl %ecx, %eax / tmp62, x1 + movl 56(%esp), %esi / y, y0 + movl 32(%esp), %edx / x, x0 + ja .LL34 + xorl %eax, %eax / q0 + cmpl %esi, %edx / y0, x0 + jb .LL35 +.LL34: + movl $1, %eax /, q0 +.LL35: + movl %eax, %esi / q0, <result> + xorl %edi, %edi / <result> +.LL45: + addl $40, %esp + movl %esi, %eax / <result>, <result> + popl %esi + movl %edi, %edx / <result>, <result> + popl %edi + popl %ebp + ret + .align 16 +.LL32: + movb %al, %cl + movl 56(%esp), %esi / y, + movl 60(%esp), %edi / y, + shldl %esi, %edi + sall %cl, %esi + andl $32, %ecx + jne .LL43 +.LL40: + movl $32, %ecx /, tmp96 + subl %eax, %ecx / normshift, tmp96 + movl %edi, %edx + movl %edi, 20(%esp) /, dt + movl 24(%esp), %ebp /, x2 + xorl %edi, %edi + shrl %cl, %ebp / tmp96, x2 + movl %esi, 16(%esp) /, dt + movb %al, %cl + movl 32(%esp), %esi / x, dt + movl %edi, 12(%esp) + movl 36(%esp), %edi / x, dt + shldl %esi, %edi /, dt, dt + sall %cl, %esi /, dt + andl $32, %ecx + movl %edx, 8(%esp) + je .LL41 + movl %esi, %edi / dt, dt + xorl %esi, %esi / dt +.LL41: + xorl %ecx, %ecx + movl %edi, %eax / tmp1, + movl %ebp, %edx / x2, + divl 8(%esp) + movl %edx, %ebp /, x1 + movl %ecx, 4(%esp) + movl %eax, %ecx /, q0 + movl 16(%esp), %eax / dt, + mull %ecx / q0 + cmpl %ebp, %edx / x1, t1 + movl %edi, (%esp) + movl %esi, %edi / dt, x0 + ja .LL38 + je .LL44 +.LL39: + movl %ecx, %esi / q0, <result> +.LL46: + xorl %edi, %edi / <result> + jmp .LL45 +.LL44: + cmpl %edi, %eax / x0, t0 + jbe .LL39 +.LL38: + decl %ecx / q0 + movl %ecx, %esi / q0, <result> + jmp .LL46 +.LL43: + movl %esi, %edi + xorl %esi, %esi + jmp .LL40 + SET_SIZE(UDiv) +/* + * __udiv64 + * + * Perform division of two unsigned 64-bit quantities, returning the + * quotient in %edx:%eax. __udiv64 pops the arguments on return, + */ + ENTRY(__udiv64) + movl 4(%esp), %eax / x, x + movl 8(%esp), %edx / x, x + pushl 16(%esp) / y + pushl 16(%esp) + call UDiv + addl $8, %esp + ret $16 + SET_SIZE(__udiv64) + +/* + * __urem64 + * + * Perform division of two unsigned 64-bit quantities, returning the + * remainder in %edx:%eax. __urem64 pops the arguments on return + */ + ENTRY(__urem64) + subl $12, %esp + movl %esp, %ecx /, tmp65 + movl 16(%esp), %eax / x, x + movl 20(%esp), %edx / x, x + pushl %ecx / tmp65 + pushl 32(%esp) / y + pushl 32(%esp) + call UDivRem + movl 12(%esp), %eax / rem, rem + movl 16(%esp), %edx / rem, rem + addl $24, %esp + ret $16 + SET_SIZE(__urem64) + +/* + * __div64 + * + * Perform division of two signed 64-bit quantities, returning the + * quotient in %edx:%eax. __div64 pops the arguments on return. + */ +/ int64_t +/ __div64(int64_t x, int64_t y) +/ { +/ int negative; +/ uint64_t xt, yt, r; +/ +/ if (x < 0) { +/ xt = -(uint64_t) x; +/ negative = 1; +/ } else { +/ xt = x; +/ negative = 0; +/ } +/ if (y < 0) { +/ yt = -(uint64_t) y; +/ negative ^= 1; +/ } else { +/ yt = y; +/ } +/ r = UDiv(xt, yt); +/ return (negative ? (int64_t) - r : r); +/ } + ENTRY(__div64) + pushl %ebp + pushl %edi + pushl %esi + subl $8, %esp + movl 28(%esp), %edx / x, x + testl %edx, %edx / x + movl 24(%esp), %eax / x, x + movl 32(%esp), %esi / y, y + movl 36(%esp), %edi / y, y + js .LL84 + xorl %ebp, %ebp / negative + testl %edi, %edi / y + movl %eax, (%esp) / x, xt + movl %edx, 4(%esp) / x, xt + movl %esi, %eax / y, yt + movl %edi, %edx / y, yt + js .LL85 +.LL82: + pushl %edx / yt + pushl %eax / yt + movl 8(%esp), %eax / xt, xt + movl 12(%esp), %edx / xt, xt + call UDiv + popl %ecx + testl %ebp, %ebp / negative + popl %esi + je .LL83 + negl %eax / r + adcl $0, %edx /, r + negl %edx / r +.LL83: + addl $8, %esp + popl %esi + popl %edi + popl %ebp + ret $16 + .align 16 +.LL84: + negl %eax / x + adcl $0, %edx /, x + negl %edx / x + testl %edi, %edi / y + movl %eax, (%esp) / x, xt + movl %edx, 4(%esp) / x, xt + movl $1, %ebp /, negative + movl %esi, %eax / y, yt + movl %edi, %edx / y, yt + jns .LL82 + .align 16 +.LL85: + negl %eax / yt + adcl $0, %edx /, yt + negl %edx / yt + xorl $1, %ebp /, negative + jmp .LL82 + SET_SIZE(__div64) + +/* + * __rem64 + * + * Perform division of two signed 64-bit quantities, returning the + * remainder in %edx:%eax. __rem64 pops the arguments on return. + */ +/ int64_t +/ __rem64(int64_t x, int64_t y) +/ { +/ uint64_t xt, yt, rem; +/ +/ if (x < 0) { +/ xt = -(uint64_t) x; +/ } else { +/ xt = x; +/ } +/ if (y < 0) { +/ yt = -(uint64_t) y; +/ } else { +/ yt = y; +/ } +/ (void) UDivRem(xt, yt, &rem); +/ return (x < 0 ? (int64_t) - rem : rem); +/ } + ENTRY(__rem64) + pushl %edi + pushl %esi + subl $20, %esp + movl 36(%esp), %ecx / x, + movl 32(%esp), %esi / x, + movl 36(%esp), %edi / x, + testl %ecx, %ecx + movl 40(%esp), %eax / y, y + movl 44(%esp), %edx / y, y + movl %esi, (%esp) /, xt + movl %edi, 4(%esp) /, xt + js .LL92 + testl %edx, %edx / y + movl %eax, %esi / y, yt + movl %edx, %edi / y, yt + js .LL93 +.LL90: + leal 8(%esp), %eax /, tmp66 + pushl %eax / tmp66 + pushl %edi / yt + pushl %esi / yt + movl 12(%esp), %eax / xt, xt + movl 16(%esp), %edx / xt, xt + call UDivRem + addl $12, %esp + movl 36(%esp), %edi / x, + testl %edi, %edi + movl 8(%esp), %eax / rem, rem + movl 12(%esp), %edx / rem, rem + js .LL94 + addl $20, %esp + popl %esi + popl %edi + ret $16 + .align 16 +.LL92: + negl %esi + adcl $0, %edi + negl %edi + testl %edx, %edx / y + movl %esi, (%esp) /, xt + movl %edi, 4(%esp) /, xt + movl %eax, %esi / y, yt + movl %edx, %edi / y, yt + jns .LL90 + .align 16 +.LL93: + negl %esi / yt + adcl $0, %edi /, yt + negl %edi / yt + jmp .LL90 + .align 16 +.LL94: + negl %eax / rem + adcl $0, %edx /, rem + addl $20, %esp + popl %esi + negl %edx / rem + popl %edi + ret $16 + SET_SIZE(__rem64) + +/* + * __udivrem64 + * + * Perform division of two unsigned 64-bit quantities, returning the + * quotient in %edx:%eax, and the remainder in %ecx:%esi. __udivrem64 + * pops the arguments on return. + */ + ENTRY(__udivrem64) + subl $12, %esp + movl %esp, %ecx /, tmp64 + movl 16(%esp), %eax / x, x + movl 20(%esp), %edx / x, x + pushl %ecx / tmp64 + pushl 32(%esp) / y + pushl 32(%esp) + call UDivRem + movl 16(%esp), %ecx / rem, tmp63 + movl 12(%esp), %esi / rem + addl $24, %esp + ret $16 + SET_SIZE(__udivrem64) + +/* + * Signed division with remainder. + */ +/ int64_t +/ SDivRem(int64_t x, int64_t y, int64_t * pmod) +/ { +/ int negative; +/ uint64_t xt, yt, r, rem; +/ +/ if (x < 0) { +/ xt = -(uint64_t) x; +/ negative = 1; +/ } else { +/ xt = x; +/ negative = 0; +/ } +/ if (y < 0) { +/ yt = -(uint64_t) y; +/ negative ^= 1; +/ } else { +/ yt = y; +/ } +/ r = UDivRem(xt, yt, &rem); +/ *pmod = (x < 0 ? (int64_t) - rem : rem); +/ return (negative ? (int64_t) - r : r); +/ } + ENTRY(SDivRem) + pushl %ebp + pushl %edi + pushl %esi + subl $24, %esp + testl %edx, %edx / x + movl %edx, %edi / x, x + js .LL73 + movl 44(%esp), %esi / y, + xorl %ebp, %ebp / negative + testl %esi, %esi + movl %edx, 12(%esp) / x, xt + movl %eax, 8(%esp) / x, xt + movl 40(%esp), %edx / y, yt + movl 44(%esp), %ecx / y, yt + js .LL74 +.LL70: + leal 16(%esp), %eax /, tmp70 + pushl %eax / tmp70 + pushl %ecx / yt + pushl %edx / yt + movl 20(%esp), %eax / xt, xt + movl 24(%esp), %edx / xt, xt + call UDivRem + movl %edx, 16(%esp) /, r + movl %eax, 12(%esp) /, r + addl $12, %esp + testl %edi, %edi / x + movl 16(%esp), %edx / rem, rem + movl 20(%esp), %ecx / rem, rem + js .LL75 +.LL71: + movl 48(%esp), %edi / pmod, pmod + testl %ebp, %ebp / negative + movl %edx, (%edi) / rem,* pmod + movl %ecx, 4(%edi) / rem, + movl (%esp), %eax / r, r + movl 4(%esp), %edx / r, r + je .LL72 + negl %eax / r + adcl $0, %edx /, r + negl %edx / r +.LL72: + addl $24, %esp + popl %esi + popl %edi + popl %ebp + ret + .align 16 +.LL73: + negl %eax + adcl $0, %edx + movl 44(%esp), %esi / y, + negl %edx + testl %esi, %esi + movl %edx, 12(%esp) /, xt + movl %eax, 8(%esp) /, xt + movl $1, %ebp /, negative + movl 40(%esp), %edx / y, yt + movl 44(%esp), %ecx / y, yt + jns .LL70 + .align 16 +.LL74: + negl %edx / yt + adcl $0, %ecx /, yt + negl %ecx / yt + xorl $1, %ebp /, negative + jmp .LL70 + .align 16 +.LL75: + negl %edx / rem + adcl $0, %ecx /, rem + negl %ecx / rem + jmp .LL71 + SET_SIZE(SDivRem) + +/* + * __divrem64 + * + * Perform division of two signed 64-bit quantities, returning the + * quotient in %edx:%eax, and the remainder in %ecx:%esi. __divrem64 + * pops the arguments on return. + */ + ENTRY(__divrem64) + subl $20, %esp + movl %esp, %ecx /, tmp64 + movl 24(%esp), %eax / x, x + movl 28(%esp), %edx / x, x + pushl %ecx / tmp64 + pushl 40(%esp) / y + pushl 40(%esp) + call SDivRem + movl 16(%esp), %ecx + movl 12(%esp),%esi / rem + addl $32, %esp + ret $16 + SET_SIZE(__divrem64) +#endif /* lint */ diff --git a/usr/src/psm/stand/boot/inc.flg b/usr/src/psm/stand/boot/inc.flg new file mode 100644 index 0000000000..87b058d63e --- /dev/null +++ b/usr/src/psm/stand/boot/inc.flg @@ -0,0 +1,48 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Get required header files +# +find_files "s.*.h"\ + usr/src/uts/sparc\ + usr/src/uts/sun\ + usr/src/uts/common/sys\ + usr/src/uts/common/vm\ + usr/src/uts/common/rpc\ + usr/src/uts/common/nfs\ + usr/src/stand/sys +# +# Get required directories +# +find_files "s.*"\ + usr/src/psm/promif\ + usr/src/stand/lib + +echo_file usr/src/lib/Makefile.lib diff --git a/usr/src/psm/stand/boot/sparc/common/boot.c b/usr/src/psm/stand/boot/sparc/common/boot.c new file mode 100644 index 0000000000..acfbad580b --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/boot.c @@ -0,0 +1,108 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/salib.h> +#include <sys/stat.h> +#include <sys/promif.h> +#include <sys/bootvfs.h> +#include <sys/boot_redirect.h> +#include "boot_plat.h" + +/* + * This implementation of bootprog() is used by all bootloaders except wanboot. + */ + +#define SUCCESS 0 +#define FAILURE -1 + +/* + * bpath is the boot device path buffer. + * bargs is the boot arguments buffer. + */ +/*ARGSUSED*/ +int +bootprog(char *bpath, char *bargs, boolean_t user_specified_filename) +{ + boolean_t once = B_FALSE; + + systype = set_fstype(v2path, bpath); + +loop: + /* + * Beware: the following code may be executed twice, with different + * bpath's if we discover a redirection file. + */ + + if (verbosemode) { + printf("device path '%s'\n", bpath); + if (strcmp(bpath, v2path) != 0) + printf("client path '%s'\n", v2path); + } + + if (mountroot(bpath) != SUCCESS) + prom_panic("Could not mount filesystem."); + + /* + * kernname (default-name) might have changed if mountroot() called + * boot_nfs_mountroot(), and it called set_default_filename(). + */ + if (!user_specified_filename) + (void) strcpy(filename, kernname); + + if (verbosemode) + printf("standalone = `%s', args = `%s'\n", filename, bargs); + + set_client_bootargs(filename, bargs); + + if (!once && + (strcmp(systype, "ufs") == 0 || strcmp(systype, "hsfs") == 0)) { + char redirect[OBP_MAXPATHLEN]; + + post_mountroot(filename, redirect); + + /* + * If we return at all, it's because we discovered + * a redirection file - the 'redirect' string now contains + * the name of the disk slice we should be looking at. + * + * Unmount the filesystem, tweak the boot path and retry + * the whole operation one more time. + */ + closeall(1); + once = B_TRUE; + redirect_boot_path(bpath, redirect); + if (verbosemode) + printf("%sboot: using '%s'\n", systype, bpath); + + goto loop; + /*NOTREACHED*/ + } + + return (0); +} diff --git a/usr/src/psm/stand/boot/sparc/common/boot_plat.c b/usr/src/psm/stand/boot/sparc/common/boot_plat.c new file mode 100644 index 0000000000..0a74ed0980 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/boot_plat.c @@ -0,0 +1,682 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/obpdefs.h> +#include <sys/reboot.h> +#include <sys/promif.h> +#include <sys/stat.h> +#include <sys/bootvfs.h> +#include <sys/platnames.h> +#include <sys/salib.h> +#include <sys/elf.h> +#include <sys/link.h> +#include <sys/auxv.h> +#include <sys/boot_policy.h> +#include <sys/boot_redirect.h> +#include <sys/bootconf.h> +#include <sys/boot.h> +#include "boot_plat.h" + +#define SUCCESS 0 +#define FAILURE -1 + +#define ISSPACE(c) (c == ' ' || c == '\t') +#define SKIP_WHITESPC(cp) while (*cp && ISSPACE(*cp)) cp++; + + +#ifdef DEBUG +int debug = 0; +#else +static const int debug = 0; +#endif + +#define dprintf if (debug) printf + +#ifdef DEBUG_LISTS +void print_memlist(struct memlist *av); +#endif + +extern int (*readfile(int fd, int print))(); +extern void kmem_init(void); +extern void *kmem_alloc(size_t, int); +extern void kmem_free(void *, size_t); +extern void get_boot_args(char *buf); +extern void setup_bootops(void); +extern struct bootops bootops; +extern void exitto(int (*entrypoint)()); +extern void exitto64(int (*entrypoint)(), void *bootvec); + +int openfile(char *filename); + +int client_isLP64 = 1; /* SPARC clients are always LP64 */ + +/* + * filename is the name of the standalone we're going to execute. + */ +char filename[MAXPATHLEN]; +char *cmd_line_default_path; + +char * const defname = "kernel/sparcv9/unix"; + +/* + * We enable the cache by default + * but boot -n will leave it alone... + * that is, we use whatever state the PROM left it in. + */ +char *mfg_name; +int cache_state = 1; +char filename2[MAXPATHLEN]; + +int boothowto = 0; +int verbosemode = 0; + + +/* + * Copy filename and bargs into v2args_buf, which will be exported as the + * boot-args boot property. We should probably warn the user if anything gets + * cut off. + */ +void +set_client_bootargs(const char *filename, const char *bargs) +{ + int i = 0; + const char *s; + + s = filename; + while (*s != '\0' && i < V2ARGS_BUF_SZ - 1) + v2args_buf[i++] = *s++; + + if (i >= V2ARGS_BUF_SZ - 2) { + /* Not enough room for a space and any of bargs. */ + v2args_buf[i] = '\0'; + return; + } + + v2args_buf[i++] = ' '; + + s = bargs; + while (*s != '\0' && i < V2ARGS_BUF_SZ - 1) + v2args_buf[i++] = *s++; + + v2args_buf[i] = '\0'; +} + +/* + * The slice redirection file is used on the install CD + */ +static int +read_redirect(char *redirect) +{ + int fd; + char slicec; + size_t nread = 0; + + if ((fd = open(BOOT_REDIRECT, O_RDONLY)) != -1) { + /* + * Read the character out of the file - this is the + * slice to use, in base 36. + */ + nread = read(fd, &slicec, 1); + (void) close(fd); + if (nread == 1) + *redirect++ = slicec; + } + *redirect = '\0'; + + return (nread == 1); +} + +void +post_mountroot(char *bootfile, char *redirect) +{ + int (*go2)(); + int fd; + + /* Save the bootfile, just in case we need it again */ + (void) strcpy(filename2, bootfile); + + for (;;) { + if (boothowto & RB_ASKNAME) { + char tmpname[MAXPATHLEN]; + + printf("Enter filename [%s]: ", bootfile); + (void) cons_gets(tmpname, sizeof (tmpname)); + if (tmpname[0] != '\0') + (void) strcpy(bootfile, tmpname); + } + + if (boothowto & RB_HALT) { + printf("Boot halted.\n"); + prom_enter_mon(); + } + + if ((fd = openfile(bootfile)) == FAILURE) { + + /* + * There are many reasons why this might've + * happened .. but one of them is that we're + * on the installation CD, and we need to + * revector ourselves off to a different partition + * of the CD. Check for the redirection file. + */ + if (redirect != NULL && + read_redirect(redirect)) { + /* restore bootfile */ + (void) strcpy(bootfile, filename2); + return; + /*NOTREACHED*/ + } + + printf("%s: cannot open %s\n", my_own_name, bootfile); + boothowto |= RB_ASKNAME; + + /* restore bootfile */ + (void) strcpy(bootfile, filename2); + continue; + } + + if ((go2 = readfile(fd, boothowto & RB_VERBOSE)) != + (int(*)()) -1) { +#ifdef MPSAS + sas_bpts(); +#endif + (void) close(fd); + } else { + printf("boot failed\n"); + boothowto |= RB_ASKNAME; + continue; + } + + if (boothowto & RB_HALT) { + printf("Boot halted before exit to 0x%p.\n", + (void *)go2); + prom_enter_mon(); + } + + my_own_name = bootfile; + + dprintf("Calling exitto64(%p, %p)\n", (void *)go2, + (void *)elfbootvecELF64); + exitto64(go2, (void *)elfbootvecELF64); + } +} + +/*ARGSUSED*/ +static int +boot_open(char *pathname, void *arg) +{ + dprintf("trying '%s'\n", pathname); + return (open(pathname, O_RDONLY)); +} + +static int +boot_isdir(char *pathname) +{ + int fd, retval; + struct stat sbuf; + + dprintf("trying '%s'\n", pathname); + if ((fd = open(pathname, O_RDONLY)) == -1) + return (0); + retval = 1; + if (fstat(fd, &sbuf) == -1) + retval = 0; + else if ((sbuf.st_mode & S_IFMT) != S_IFDIR) + retval = 0; + (void) close(fd); + return (retval); +} + +/* + * Open the given filename, expanding to it's + * platform-dependent location if necessary. + * + * Boot supports OBP and IEEE1275. + * + * XXX: Move side effects out of this function! + */ +int +openfile(char *filename) +{ + static char *fullpath; + static char *iarch; + static char *orig_impl_arch_name; + static int once; + int fd; + + if (once == 0) { + + ++once; + + /* + * Setup exported 'boot' properties: 'mfg-name'. + * XXX: This shouldn't be a side effect of openfile(). + */ + if (mfg_name == NULL) + mfg_name = get_mfg_name(); + + /* + * If impl_arch_name was specified on the command line + * via the -I <arch> argument, remember the original value. + */ + if (impl_arch_name) { + orig_impl_arch_name = (char *) + kmem_alloc(strlen(impl_arch_name) + 1, 0); + (void) strcpy(orig_impl_arch_name, impl_arch_name); + } + + fullpath = (char *)kmem_alloc(MAXPATHLEN, 0); + iarch = (char *)kmem_alloc(MAXPATHLEN, 0); + } + + /* + * impl_arch_name is exported as boot property, and is + * set according to the following algorithm, depending + * on the contents of the filesystem. + * XXX: This shouldn't be a side effect of openfile(). + * + * impl_arch_name table: + * + * root name default name neither name + * boot args found found found + * + * relative path root name fail fail + * absolute path root name default name empty + * -I arch arch arch arch + * + */ + + /* + * If the caller -specifies- an absolute pathname, then we just try to + * open it. (Mostly for booting non-kernel standalones.) + * + * In case this absolute pathname is the kernel, make sure that + * impl_arch_name (exported as a boot property) is set to some + * valid string value. + */ + if (*filename == '/') { + if (orig_impl_arch_name == NULL) { + if (find_platform_dir(boot_isdir, iarch, 1) != 0) + impl_arch_name = iarch; + else + impl_arch_name = ""; + } + (void) strcpy(fullpath, filename); + fd = boot_open(fullpath, NULL); + return (fd); + } + + /* + * If the -I flag has been used, impl_arch_name will + * be specified .. otherwise we ask find_platform_dir() to + * look for the existance of a directory for this platform name. + * Preserve the given impl-arch-name, because the 'kernel file' + * may be elsewhere. (impl-arch-name could be 'SUNW,Ultra-1', + * but the kernel file itself might be in the 'sun4u' directory). + * + * When booting any file by relative pathname this code fails + * if the platform-name dir doesn't exist unless some + * -I <iarch> argument has been given on the command line. + */ + if (orig_impl_arch_name == NULL) { + if (find_platform_dir(boot_isdir, iarch, 0) != 0) + impl_arch_name = iarch; + else + return (-1); + } + + fd = open_platform_file(filename, boot_open, NULL, fullpath, + orig_impl_arch_name); + if (fd == -1) + return (-1); + + /* + * Copy back the name we actually found + */ + (void) strcpy(filename, fullpath); + return (fd); +} + +/* + * Get the boot arguments from the PROM and split it into filename and + * options components. + * + * As per IEEE1275 and boot(1M), the boot arguments will have the syntax + * "[filename] [-options]". If filename is specified, it is copied into the + * first buffer. (Otherwise, the buffer is left alone.) The rest of the string + * is copied into the second buffer. + */ +static void +init_bootargs(char *fname_buf, int fname_buf_sz, char *bargs_buf, + int bargs_buf_sz) +{ + const char *tp = prom_bootargs(); + + if (!tp || *tp == '\0') { + *bargs_buf = '\0'; + return; + } + + SKIP_WHITESPC(tp); + + /* + * If we don't have an option indicator, then we + * already have our filename prepended. + */ + if (*tp && *tp != '-') { + int i; + + /* + * Copy the filename into fname_buf. + */ + for (i = 0; i < fname_buf_sz && *tp && !ISSPACE(*tp); ++i) + *fname_buf++ = *tp++; + + if (i >= fname_buf_sz) { + printf("boot: boot filename too long!\n"); + printf("boot halted.\n"); + prom_enter_mon(); + /*NOTREACHED*/ + } else { + *fname_buf = '\0'; + } + + SKIP_WHITESPC(tp); + } + + /* The rest of the line is the options. */ + while (bargs_buf_sz > 1 && *tp) { + *bargs_buf++ = *tp++; + --bargs_buf_sz; + } + *bargs_buf = '\0'; + + if (bargs_buf_sz == 1) { + printf("boot: boot arguments too long!\n"); + printf("boot halted.\n"); + prom_enter_mon(); + /*NOTREACHED*/ + } +} + +boolean_t +is_netdev(char *devpath) +{ + dnode_t node = prom_finddevice(devpath); + char *options; + + if ((node == OBP_NONODE) || (node == OBP_BADNODE)) + return (B_FALSE); + if (prom_devicetype(node, "network") != 0) + return (B_TRUE); + + /* + * For Infiniband, network device names will be of the + * format XXX/ib@0:port=1,pkey=1234,protocol=ip[,YYY] where + * XXX is typically /pci@8,700000/pci@1. The device_type + * property will be "ib". + */ + if (prom_devicetype(node, "ib") != 0) { + options = prom_path_options(devpath); + if (options != NULL) { + +#define SEARCHSTRING ",protocol=ip" +#define SEARCHSTRLEN strlen(SEARCHSTRING) + + if (strstr(options, ",protocol=ip,") != NULL) + return (B_TRUE); + while ((options = strstr(options, SEARCHSTRING)) != + NULL) { + char nextc; + + nextc = options[SEARCHSTRLEN]; + if ((nextc == ',') || (nextc == 0)) + return (B_TRUE); + options += SEARCHSTRLEN; + } + } + } + return (B_FALSE); +} + +/* + * Hook for modifying the OS boot path. This hook allows us to handle + * device arguments that the OS can't handle. + */ +void +mangle_os_bootpath(char *bpath) +{ + dnode_t node; + char *stripped_pathname; + + node = prom_finddevice(bpath); + if (prom_devicetype(node, "network") == 0) + return; + + /* + * The OS can't handle network device arguments + * eg: boot net:promiscuous,speed=100,duplex=full + * So, we remove any argument strings in the device + * pathname we hand off to the OS for network devices. + * + * Internally, within boot, bpath is used to access + * the device, but v2path (as the boot property "boot-path") + * is the pathname passed to the OS. + */ + + stripped_pathname = kmem_alloc(OBP_MAXPATHLEN, 0); + prom_strip_options(bpath, stripped_pathname); + v2path = stripped_pathname; +} + +/* + * Given the boot path in the native firmware format use + * the redirection string to mutate the boot path to the new device. + * Fix up the 'v2path' so that it matches the new firmware path. + */ +void +redirect_boot_path(char *bpath, char *redirect) +{ + char slicec = *redirect; + char *p = bpath + strlen(bpath); + + /* + * If the redirection character doesn't fall in this + * range, something went horribly wrong. + */ + if (slicec < '0' || slicec > '7') { + printf("boot: bad redirection slice '%c'\n", slicec); + return; + } + + /* + * Handle fully qualified OpenBoot pathname. + */ + while (--p >= bpath && *p != '@' && *p != '/') + if (*p == ':') + break; + if (*p++ == ':') { + /* + * Convert slice number to partition 'letter'. + */ + *p++ = 'a' + slicec - '0'; + *p = '\0'; + v2path = bpath; + return; + } + prom_panic("redirect_boot_path: mangled boot path!"); +} + +#define PROM_VERS_MAX_LEN 64 + +void +system_check(void) +{ + char buf[PROM_VERS_MAX_LEN]; + + if (cpu_is_ultrasparc_1()) { + printf("UltraSPARC I processors are not supported by this " + "release of Solaris.\n"); + prom_exit_to_mon(); + } + + if (prom_version_check(buf, PROM_VERS_MAX_LEN, NULL) != PROM_VER64_OK) { + printf("The firmware on this system does not support the 64-bit" + " OS.\n\tPlease upgrade to at least the following version:" + "\n\n\t%s\n", buf); + prom_exit_to_mon(); + } +} + +/* + * Reads in the standalone (client) program and jumps to it. If this + * attempt fails, prints "boot failed" and returns to its caller. + * + * It will try to determine if it is loading a Unix file by + * looking at what should be the magic number. If it makes + * sense, it will use it; otherwise it jumps to the first + * address of the blocks that it reads in. + * + * This new boot program will open a file, read the ELF header, + * attempt to allocate and map memory at the location at which + * the client desires to be linked, and load the program at + * that point. It will then jump there. + */ +/*ARGSUSED*/ +int +main(void *cookie, char **argv, int argc) +{ + /* + * bpath is the boot device path buffer. + * bargs is the boot arguments buffer. + */ + static char bpath[OBP_MAXPATHLEN], bargs[OBP_MAXPATHLEN]; + boolean_t user_specified_filename; + + prom_init("boot", cookie); + fiximp(); + + system_check(); + + dprintf("\nboot: V%d /boot interface.\n", BO_VERSION); +#ifdef HALTBOOT + prom_enter_mon(); +#endif /* HALTBOOT */ + + init_memlists(); + +#ifdef DEBUG_LISTS + dprintf("Physmem avail:\n"); + if (debug) print_memlist(pfreelistp); + dprintf("Virtmem avail:\n"); + if (debug) print_memlist(vfreelistp); + dprintf("Phys installed:\n"); + if (debug) print_memlist(pinstalledp); + prom_enter_mon(); +#endif /* DEBUG_LISTS */ + + /* + * Initialize the default filename (exported as "default-name" and + * used by kadb). + */ + set_default_filename(defname); + + /* + * Parse the arguments ASAP in case there are any flags which may + * affect execution. + */ + + /* + * filename is the path to the standalone. Initialize it to the empty + * string so we can tell whether the user specified it in the + * arguments. + */ + filename[0] = '\0'; + + /* + * Fetch the boot arguments from the PROM and split the filename off + * if it's there. + */ + init_bootargs(filename, sizeof (filename), bargs, sizeof (bargs)); + + /* + * kadb was delivered as a standalone, and as such, people got used to + * typing `boot kadb'. kmdb isn't a standalone - it is loaded by krtld + * as just another kernel module. For compatibility, though, when we + * see an attempt to `boot kadb' or `boot kmdb', we'll transform that + * into a `boot -k' (or equivalent). + */ + if (strcmp(filename, "kmdb") == 0 || strcmp(filename, "kadb") == 0) { + boothowto |= RB_KMDB; + *filename = '\0'; /* let boot figure out which unix to use */ + } + + bootflags(bargs, sizeof (bargs)); + + user_specified_filename = (filename[0] != '\0'); + + /* Fetch the boot path from the PROM. */ + (void) strncpy(bpath, prom_bootpath(), sizeof (bpath) - 1); + bpath[sizeof (bpath) - 1] = '\0'; + + dprintf("bootpath: 0x%p %s\n", (void *)bpath, bpath); + dprintf("bootargs: 0x%p %s\n", (void *)bargs, bargs); + dprintf("filename: 0x%p %s\n", (void *)filename, filename); + dprintf("kernname: 0x%p %s\n", (void *)kernname, kernname); + + /* + * *v2path will be exported to the standalone as the boot-path boot + * property. + */ + v2path = bpath; + + /* + * Our memory lists should be "up" by this time + */ + + setup_bootops(); + + /* + * If bpath is a network card, set v2path to a copy of bpath with the + * options stripped off. + */ + mangle_os_bootpath(bpath); + +#ifdef sun4u + retain_nvram_page(); +#endif + + if (bootprog(bpath, bargs, user_specified_filename) == 0) { + post_mountroot(filename, NULL); + /*NOTREACHED*/ + } + + return (0); +} diff --git a/usr/src/psm/stand/boot/sparc/common/boot_plat.h b/usr/src/psm/stand/boot/sparc/common/boot_plat.h new file mode 100644 index 0000000000..99066f70bb --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/boot_plat.h @@ -0,0 +1,131 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _BOOT_PLAT_H +#define _BOOT_PLAT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* boot_plat.c */ +extern char *cmd_line_default_path; +extern int verbosemode; +extern char filename[]; +extern char *const defname; +extern char *const defname64; +extern char wanboot_arguments[]; + +extern int bootprog(char *, char *, boolean_t); +extern char *choose_default_filename(char *, char *); +extern char *get_default_filename(void); +extern void post_mountroot(char *, char *); +extern void redirect_boot_path(char *, char *); +extern void set_client_bootargs(const char *, const char *); +extern boolean_t is_netdev(char *devpath); + + +/* boot_1275entry.c */ +extern int boot1275_entry_asm(void *); +extern void boot_fail_gracefully_asm(void); + + +/* boot_services.c */ +extern int boot1275_entry(void *); + + +/* bootops.c */ +extern struct bootops bootops; + +extern void setup_bootops(void); +extern void update_memlist(char *, char *, struct memlist **); +extern void boot_fail_gracefully(void); + + +/* + * bootprop.c. These variables will be exported to the standalone as boot + * properties. + */ +extern char *v2path, *kernname, *systype, *my_own_name; +extern char v2args_buf[]; +#define V2ARGS_BUF_SZ OBP_MAXPATHLEN +extern char *v2args; +extern char *mfg_name; +extern char *impl_arch_name; +extern char *bootp_response; +extern char *boot_message; +extern char *cmd_line_default_path; +extern int cache_state; +extern uint64_t memlistextent; +extern char *netdev_path; + +extern void set_default_filename(char *filename); + + +/* get.c */ +extern int cons_gets(char *, int); + + +/* machdep.c */ +extern int vac; + +extern void fiximp(void); +extern void retain_nvram_page(); + +#ifdef MPSAS +extern void sas_bpts(void); +#endif + +extern int cpu_is_ultrasparc_1(void); + + +/* memlist.c */ +extern void init_memlists(void); +extern struct memlist *fill_memlists(char *name, char *prop, + struct memlist *old); + + +/* srt0.c */ +extern void _start(void *romp, ...); +extern void exitto(int (*entrypoint)()); +extern void exitto64(int (*entrypoint)(), void *bootvec); + + +/* standalloc.c */ +extern caddr_t memlistpage; +extern caddr_t scratchmemp; + + + +#ifdef __cplusplus +} +#endif + +#endif /* _BOOT_PLAT_H */ diff --git a/usr/src/psm/stand/boot/sparc/common/boot_services.c b/usr/src/psm/stand/boot/sparc/common/boot_services.c new file mode 100644 index 0000000000..16a7acaebe --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/boot_services.c @@ -0,0 +1,713 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Definitions of interfaces that provide services from the secondary + * boot program to its clients (primarily unix, krtld and their successors.) + * This interface replaces the bootops (BOP) implementation as the interface + * to be called by boot clients. The BOP macros are still used to make the + * integration easier. + * + * The bootops vector is vestigial. + * + * The kern_* routines used to implement many of the services here + * are in the usr/src/stand/lib/ modules. + * + */ + +#include <sys/types.h> +#include <sys/bootconf.h> +#include <sys/reboot.h> +#include <sys/param.h> +#include <sys/varargs.h> +#include <sys/obpdefs.h> +#include <sys/promif.h> +#include <sys/salib.h> +#include <sys/stat.h> +#include <sys/bootvfs.h> + +extern void kern_killboot(void); +extern int bgetprop(struct bootops *, char *name, void *buf); +extern int bgetproplen(struct bootops *, char *name); +extern char *bnextprop(struct bootops *, char *prev); +extern caddr_t resalloc_virt(caddr_t virt, size_t size); + +static int boot1275_serviceavail(void *p); + +static struct boot_nm2svc *nm2svcp(char *name); + +/* + * Implementation of the "version" service. + * Return the compiled version number of this implementation of boot. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] Res0: returned version number + */ +static int boot_version = BO_VERSION; +static int +boot1275_getversion(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + + args[3] = boot_int2cell(boot_version); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "open" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] filename string + * args[4] flags + * args[5] Res0: returned result + * + */ +static int +boot1275_open(void *p) +{ + int rc; + int flags; + char *name; + boot_cell_t *args = (boot_cell_t *)p; + + name = boot_cell2ptr(args[3]); + flags = boot_cell2int(args[4]); + rc = kern_open(name, flags); + args[5] = boot_int2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "read" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] boot-opened file descriptor + * args[4] client's buffer + * args[5] size of read request + * args[6] Res0: returned result + * + */ +static int +boot1275_read(void *p) +{ + int rc; + boot_cell_t *args = (boot_cell_t *)p; + + /* XXX use different routine to support larger I/O ? */ + int fd; + caddr_t buf; + size_t size; + + fd = boot_cell2int(args[3]); + buf = boot_cell2ptr(args[4]); + size = boot_cell2size(args[5]); + rc = kern_read(fd, buf, size); + args[6] = boot_int2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "seek" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] boot-opened file descriptor + * args[4] offset hi XXX just use one cell for offset? + * args[5] offset lo + * args[6] Res0: returned result + * + */ +static int +boot1275_seek(void *p) +{ + off_t rc; + int fd; + off_t hi, lo; + boot_cell_t *args = (boot_cell_t *)p; + + fd = boot_cell2int(args[3]); + hi = boot_cell2offt(args[4]); + lo = boot_cell2offt(args[5]); + rc = kern_lseek(fd, hi, lo); + args[6] = boot_offt2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "close" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] boot-opened file descriptor + * args[4] Res0: returned result + * + */ +static int +boot1275_close(void *p) +{ + int rc; + int fd; + boot_cell_t *args = (boot_cell_t *)p; + + fd = boot_cell2int(args[3]); + rc = kern_close(fd); + args[4] = boot_int2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "alloc" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] virtual hint + * args[4] size to allocate + * args[5] alignment + * args[6] Res0: returned result + */ +static int +boot1275_alloc(void *p) +{ + caddr_t virthint, addr; + size_t size; + int align; + boot_cell_t *args = (boot_cell_t *)p; + + virthint = boot_cell2ptr(args[3]); + size = boot_cell2size(args[4]); + align = boot_cell2int(args[5]); + addr = kern_resalloc(virthint, size, align); + args[6] = boot_ptr2cell(addr); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "alloc_virt" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #arguments cells + * args[2] #result cells + * args[3] virtual address + * args[4] size to allocate + * args[5] Res0: returned result + */ +static int +boot1275_alloc_virt(void *p) +{ + caddr_t virt, addr; + size_t size; + boot_cell_t *args = (boot_cell_t *)p; + + virt = boot_cell2ptr(args[3]); + size = boot_cell2size(args[4]); + addr = resalloc_virt(virt, size); + args[5] = boot_ptr2cell(addr); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "free" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] virtual addr + * args[4] size to free + * args[5] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_free(void *p) +{ + caddr_t virtaddr; + size_t size; + boot_cell_t *args = (boot_cell_t *)p; + + virtaddr = boot_cell2ptr(args[3]); + size = boot_cell2size(args[4]); + kern_resfree(virtaddr, size); + args[5] = (boot_cell_t)0; + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "map" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] virtual address + * args[4] space of phys addr + * args[5] phys addr + * args[6] size + * args[7] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_map(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + + args[6] = (boot_cell_t)0; + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "unmap" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] virtual address + * args[4] size of chunk + * args[5] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_unmap(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + + args[5] = (boot_cell_t)0; + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "quiesce" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_quiesce(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + + kern_killboot(); + args[3] = (boot_cell_t)0; + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "getproplen" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] property name string + * args[4] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_getproplen(void *p) +{ + int rc; + char *name; + boot_cell_t *args = (boot_cell_t *)p; + + + name = boot_cell2ptr(args[3]); + rc = bgetproplen((struct bootops *)0, name); + args[4] = boot_int2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "getprop" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] property name string + * args[4] buffer pointer to hold value of the property + * args[5] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_getprop(void *p) +{ + int rc; + char *name; + void *buf; + boot_cell_t *args = (boot_cell_t *)p; + + + name = boot_cell2ptr(args[3]); + buf = boot_cell2ptr(args[4]); + rc = bgetprop((struct bootops *)0, name, buf); + args[5] = boot_int2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "putsarg" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] string to print (with '%*' format) + * args[4] 64-bit thing to print + * + * The bootops interface can only pass one additional + * argument. Abusing the format string can cause failures + * in interesting ways that could be hard to debug when + * an argument is pulled off the stack or dereferenced, + * so if the format string indicates more than one argument, + * we note the problem rather print garbage or panic. + */ +/*ARGSUSED*/ +static int +boot1275_putsarg(void *p) +{ + const char *string; + boot_cell_t *args = (boot_cell_t *)p; + const char *fmt; + int ells = 0; + int arg_is_ptr = 0; + int nargs = 0; + uint64_t arg; + + + string = boot_cell2ptr(args[3]); + arg = boot_cell2uint64(args[4]); + + /* + * We need to do the minimum printf-like stuff here to figure + * out the size of argument, if present. + */ + for (fmt = string; *fmt; fmt++) { + if (*fmt != '%') + continue; + if (*(++fmt) == '%') + continue; + + nargs++; + while (*fmt >= '0' && *fmt <= '9') + fmt++; + for (ells = 0; *fmt == 'l'; fmt++) + ells++; + + switch (*fmt) { + case 's': + case 'p': + arg_is_ptr = 1; + break; + } + } + + if (nargs > 1) { + printf("boot1275_putsarg: unsupported format: \"%s\"\n", + string); + } else if (arg_is_ptr) { + printf(string, (void *)arg); + } else { + switch (ells) { + case 0: + printf(string, (uint_t)arg); + break; + case 1: + printf(string, (ulong_t)arg); + break; + default: + printf(string, arg); + break; + } + } + + return (BOOT_SVC_OK); +} +/* + * Implementation of the "puts" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] string to print + */ +/*ARGSUSED*/ +static int +boot1275_puts(void *p) +{ + char *string; + boot_cell_t *args = (boot_cell_t *)p; + + + string = boot_cell2ptr(args[3]); + printf("%s", string); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "nextprop" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] previous property name string + * args[4] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_nextprop(void *p) +{ + char *name, *np; + boot_cell_t *args = (boot_cell_t *)p; + + name = boot_cell2ptr(args[3]); + np = bnextprop((struct bootops *)0, name); + args[4] = boot_ptr2cell(np); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "mount" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] pathname string + * args[4] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_mountroot(void *p) +{ + int rc; + char *name; + boot_cell_t *args = (boot_cell_t *)p; + + name = boot_cell2ptr(args[3]); + rc = kern_mountroot(name); + args[4] = boot_cell2int(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "unmount" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] Res0: returned result + */ +/*ARGSUSED*/ +static int +boot1275_unmountroot(void *p) +{ + int rc; + boot_cell_t *args = (boot_cell_t *)p; + + rc = kern_unmountroot(); + args[3] = boot_cell2int(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "fstat" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] fd + * args[4] client's stat structure + */ +int +boot1275_fstat(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + int fd = boot_cell2int(args[3]); + struct bootstat *st = boot_cell2ptr(args[4]); + int rc = kern_fstat(fd, st); + + args[5] = boot_int2cell(rc); + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "interpret" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells (1) + * args[2] #result cells (0) + * args[3] string to interpret + */ +int +boot1275_interpret(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + char *str = boot_cell2ptr(args[3]); + + prom_interpret(str, 0, 0, 0, 0, 0); + + return (BOOT_SVC_OK); +} + +/* + * Implementation of the "enter_mon" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells (0) + * args[2] #result cells (0) + */ +/*ARGSUSED*/ +int +boot1275_enter_mon(void *p) +{ + prom_enter_mon(); + + return (BOOT_SVC_OK); +} + +/* + * The lookup table akin to the old bootops vec + * for boot. Not part of the exported interface. + */ +static struct boot_nm2svc { + char *b_name; + int (*b_funcptr)(void *); + int b_svcversion; +} boot_nm2svc[] = { + { "version", boot1275_getversion, 1 }, + { "open", boot1275_open, 1 }, + { "read", boot1275_read, 1 }, + { "seek", boot1275_seek, 1 }, + { "close", boot1275_close, 1 }, + { "alloc", boot1275_alloc, 1 }, + { "alloc_virt", boot1275_alloc_virt, 1 }, + { "free", boot1275_free, 1 }, + { "map", boot1275_map, 1 }, + { "unmap", boot1275_unmap, 1 }, + { "quiesce", boot1275_quiesce, 1 }, + { "getproplen", boot1275_getproplen, 1 }, + { "getprop", boot1275_getprop, 1 }, + { "nextprop", boot1275_nextprop, 1 }, + { "mountroot", boot1275_mountroot, 1 }, + { "unmountroot", boot1275_unmountroot, 1 }, + { "serviceavail", boot1275_serviceavail, 1 }, + { "puts", boot1275_puts, 1 }, + { "putsarg", boot1275_putsarg, 1 }, + { "fstat", boot1275_fstat, 1 }, + { "interpret", boot1275_interpret, 1 }, + { "enter_mon", boot1275_enter_mon, 1 }, + { 0, 0, 0 } +}; + +static struct boot_nm2svc * +nm2svcp(char *name) +{ + struct boot_nm2svc *pnm2svc = &boot_nm2svc[0]; + + while (pnm2svc->b_name != 0) { + if (strcmp(pnm2svc->b_name, name)) + pnm2svc++; + else { + return (pnm2svc); + } + } + return (NULL); +} + +/* + * Implementation of the "serviceavail" boot service. + * + * Calling spec: + * args[0] Service name string + * args[1] #argument cells + * args[2] #result cells + * args[3] name string of service to be tested for + * args[4] Res0: returned version number or 0 + */ +/*ARGSUSED*/ +static int +boot1275_serviceavail(void *p) +{ + boot_cell_t *args = (boot_cell_t *)p; + char *name; + struct boot_nm2svc *pnm2svc; + int version = 0; /* 0 means service not avail */ + + name = boot_cell2ptr(args[3]); + pnm2svc = nm2svcp(name); + if (pnm2svc != 0) + version = pnm2svc->b_svcversion; + args[4] = boot_int2cell(version); + return (BOOT_SVC_OK); +} + +int +boot1275_entry(void *p) +{ + int rc = 0; + char *name; + int (*fp)(); + boot_cell_t *args = (boot_cell_t *)p; + struct boot_nm2svc *pnm2svc; + + name = boot_cell2ptr(args[0]); + pnm2svc = nm2svcp(name); + if (pnm2svc != NULL) { + fp = (int(*)())(pnm2svc->b_funcptr); + rc = (*fp)(args); + } else { + prom_printf("call to undefined service \"%s\"\n", name); + } + return (rc); +} diff --git a/usr/src/psm/stand/boot/sparc/common/bootflags.c b/usr/src/psm/stand/boot/sparc/common/bootflags.c new file mode 100644 index 0000000000..abb4573d24 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/bootflags.c @@ -0,0 +1,274 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/bootconf.h> +#include <sys/reboot.h> +#include <sys/param.h> +#include <sys/salib.h> +#include <sys/debug.h> +#include <sys/promif.h> +#include <sys/boot.h> +#include <sys/sysmacros.h> +#include <util/getoptstr.h> +#include "boot_plat.h" + +static char impl_arch_buf[MAXNAMELEN]; +static char default_path_buf[MAXPATHLEN]; + +char wanboot_arguments[OBP_MAXPATHLEN]; /* args following "-o" */ + +/* + * Parse the boot arguments, adding the options found to the existing boothowto + * value (if any) or other state. Then rewrite the buffer with arguments for + * the standalone. + * + * We assume that the buffer contains only the arguments (no preceeding + * filename or whitespace). We start interpreting flags, ignoring those used + * by the boot block (-H, -X, and -F filename) and acting on those intended + * for us (those documented in boot(1M) as well as some undocumented), and + * stop at unknown flags. Finally we reconstitute flags to be passed on to + * the standalone and the remaining arguments, excluding the first "--", to + * the beginning of the buffer, and return an integer representing our flags. + * + * NOTE: boothowto may already have bits set when this function is called + */ +void +bootflags(char *args, size_t argsz) +{ + static char newargs[OBP_MAXPATHLEN]; + struct gos_params params; + const char *cp; + char *np; + size_t npres; + int c; + + impl_arch_name = NULL; + cmd_line_default_path = NULL; + + params.gos_opts = "HXF:VnI:D:advhko:"; + params.gos_strp = args; + getoptstr_init(¶ms); + while ((c = getoptstr(¶ms)) != -1) { + switch (c) { + /* + * Bootblock flags: ignore. + */ + case 'H': + case 'X': + case 'F': + break; + + /* + * Boot flags. + */ + case 'V': + verbosemode = 1; + break; + case 'n': + cache_state = 0; + printf("Warning: boot will not enable cache\n"); + break; + + case 'I': + if (params.gos_optarglen >= sizeof (impl_arch_buf)) { + printf("boot: -I argument too long. " + "Ignoring.\n"); + break; + } + (void) strncpy(impl_arch_buf, params.gos_optargp, + params.gos_optarglen); + impl_arch_buf[params.gos_optarglen] = '\0'; + impl_arch_name = impl_arch_buf; + break; + + case 'D': + if (params.gos_optarglen >= sizeof (default_path_buf)) { + printf("boot: -D argument too long. " + "Ignoring.\n"); + break; + } + (void) strncpy(default_path_buf, params.gos_optargp, + params.gos_optarglen); + default_path_buf[params.gos_optarglen] = '\0'; + cmd_line_default_path = default_path_buf; + break; + + case 'o': + if (params.gos_optarglen >= + sizeof (wanboot_arguments)) { + printf("boot: -o argument too long. " + "Ignoring.\n"); + break; + } + (void) strncpy(wanboot_arguments, params.gos_optargp, + params.gos_optarglen); + wanboot_arguments[params.gos_optarglen] = '\0'; + break; + + case 'a': + boothowto |= RB_ASKNAME; + break; + + case 'd': + boothowto |= RB_DEBUGENTER; + break; + case 'v': + boothowto |= RB_VERBOSE; + break; + case 'h': + boothowto |= RB_HALT; + break; + + /* Consumed by the kernel */ + case 'k': + boothowto |= RB_KMDB; + break; + + /* + * Unrecognized flags: stop. + */ + case '?': + /* + * Error. Either an unrecognized option, or an option + * without an argument. Check for the latter. + */ + switch (params.gos_last_opt) { + case 'F': + /* -F is a bootblock flag, so ignore. */ + break; + case 'I': + case 'D': + case 'o': + printf("boot: -%c flag missing required " + "argument. Ignoring.\n", + params.gos_last_opt); + break; + default: + /* Unrecognized option. Stop. */ + goto done; + } + break; + + default: + printf("boot: Ignoring unimplemented option -%c.\n", c); + } + } +done: + + /* + * Construct the arguments for the standalone. + */ + + *newargs = '\0'; + np = newargs; + + /* + * We need a dash if we encountered an unrecognized option or if we + * need to pass flags on. + */ + if (c == '?' || (boothowto & + /* These flags are to be passed to the standalone. */ + (RB_ASKNAME | RB_DEBUGENTER | RB_VERBOSE | RB_HALT | RB_KMDB))) { + *np++ = '-'; + + /* + * boot(1M) says to pass these on. + */ + if (boothowto & RB_ASKNAME) + *np++ = 'a'; + + /* + * boot isn't documented as consuming these flags, so pass + * them on. + */ + if (boothowto & RB_DEBUGENTER) + *np++ = 'd'; + if (boothowto & RB_KMDB) + *np++ = 'k'; + if (boothowto & RB_VERBOSE) + *np++ = 'v'; + if (boothowto & RB_HALT) + *np++ = 'h'; + + /* + * If we didn't encounter an unrecognized flag and there's + * more to copy, add a space to separate these flags. + * (Otherwise, unrecognized flags can be appended since we + * started this word with a dash.) + */ + if (c == -1 && params.gos_strp[0] != '\0') + *np++ = ' '; + } + + npres = sizeof (newargs) - (size_t)(np - newargs); + + if (c == '?') { + /* + * Unrecognized flag: Copy gos_errp to end of line or a "--" + * word. + */ + cp = params.gos_errp; + while (*cp && npres > 0) { + if (cp[0] == '-' && cp[1] == '-' && + (cp[2] == '\0' || ISSPACE(cp[2]))) { + cp += 2; + SKIP_SPC(cp); + break; + } else { + const char *sp = cp; + size_t sz; + + /* Copy until the next word. */ + while (*cp && !ISSPACE(*cp)) + cp++; + while (ISSPACE(*cp)) + cp++; + + sz = MIN(npres, (size_t)(cp - sp)); + npres -= sz; + bcopy(sp, np, sz); + np += sz; + } + } + } else { + cp = params.gos_strp; + } + + while (npres > 0 && (*np++ = *cp++) != '\0') + npres--; + + newargs[sizeof (newargs) - 1] = '\0'; + (void) strlcpy(args, newargs, argsz); + + /* + * If a default filename was specified in the args, set it. + */ + if (cmd_line_default_path) + set_default_filename(cmd_line_default_path); +} diff --git a/usr/src/psm/stand/boot/sparc/common/bootops.c b/usr/src/psm/stand/boot/sparc/common/bootops.c new file mode 100644 index 0000000000..662fcfaedc --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/bootops.c @@ -0,0 +1,213 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1996-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Implementation of the vestigial bootops vector for platforms using the + * 1275-like boot interfaces. + */ + +#include <sys/types.h> +#include <sys/bootconf.h> +#include <sys/param.h> +#include <sys/obpdefs.h> +#include <sys/promif.h> +#include <sys/salib.h> +#include <sys/boot.h> +#include <stddef.h> +#include "boot_plat.h" + +#ifdef DEBUG +extern int debug; +#else +static const int debug = 0; +#endif + +#define dprintf if (debug) printf + +extern void closeall(int); + +/* + * This is the number for this version of bootops, which is vestigial. + * Standalones that require the old bootops will look in bootops.bsys_version, + * see this number is higher than they expect and fail gracefully. + * They can make this "peek" successfully even if they are ILP32 programs. + */ +int boot_version = BO_VERSION; + +struct bootops bootops; + +void +setup_bootops(void) +{ + /* sanity-check bsys_printf - old kernels need to fail with a message */ +#if !defined(lint) + if (offsetof(struct bootops, bsys_printf) != 60) { + printf("boot: bsys_printf is at offset 0x%lx instead of 60\n" + "boot: this will likely make old kernels die without " + "printing a message.\n", + offsetof(struct bootops, bsys_printf)); + } + /* sanity-check bsys_1275_call - if it moves, kernels cannot boot */ + if (offsetof(struct bootops, bsys_1275_call) != 24) { + printf("boot: bsys_1275_call is at offset 0x%lx instead of 24\n" + "boot: this will likely break the kernel\n", + offsetof(struct bootops, bsys_1275_call)); + } +#endif + bootops.bsys_version = boot_version; + bootops.bsys_1275_call = (uint64_t)boot1275_entry; + /* so old kernels die with a message */ + bootops.bsys_printf = (uint32_t)boot_fail_gracefully; + + if (!memlistpage) /* paranoia runs rampant */ + prom_panic("\nMemlistpage not setup yet."); + /* + * The memory list should always be updated last. The prom + * calls which are made to update a memory list may have the + * undesirable affect of claiming physical memory. This may + * happen after the kernel has created its page free list. + * The kernel deals with this by comparing the n and n-1 + * snapshots of memory. Updating the memory available list + * last guarantees we will have a current, accurate snapshot. + * See bug #1260786. + */ + update_memlist("virtual-memory", "available", &vfreelistp); + update_memlist("memory", "available", &pfreelistp); + + dprintf("\nPhysinstalled: "); + if (debug) print_memlist(pinstalledp); + dprintf("\nPhysfree: "); + if (debug) print_memlist(pfreelistp); + dprintf("\nVirtfree: "); + if (debug) print_memlist(vfreelistp); +} + +void +install_memlistptrs(void) +{ + + /* prob only need 1 page for now */ + memlistextent = tablep - memlistpage; + + dprintf("physinstalled = %p\n", (void *)pinstalledp); + dprintf("physavail = %p\n", (void *)pfreelistp); + dprintf("virtavail = %p\n", (void *)vfreelistp); + dprintf("extent = 0x%lx\n", memlistextent); +} + +/* + * A word of explanation is in order. + * This routine is meant to be called during + * boot_release(), when the kernel is trying + * to ascertain the current state of memory + * so that it can use a memlist to walk itself + * thru kvm_init(). + */ + +void +update_memlist(char *name, char *prop, struct memlist **list) +{ + /* Just take another prom snapshot */ + *list = fill_memlists(name, prop, *list); + install_memlistptrs(); +} + +/* + * This routine is meant to be called by the + * kernel to shut down all boot and prom activity. + * After this routine is called, PROM or boot IO is no + * longer possible, nor is memory allocation. + */ +void +kern_killboot(void) +{ + if (verbosemode) { + dprintf("Entering boot_release()\n"); + dprintf("\nPhysinstalled: "); + if (debug) print_memlist(pinstalledp); + dprintf("\nPhysfree: "); + if (debug) print_memlist(pfreelistp); + dprintf("\nVirtfree: "); + if (debug) print_memlist(vfreelistp); + } + if (debug) { + dprintf("Calling quiesce_io()\n"); + prom_enter_mon(); + } + + /* close all open devices */ + closeall(1); + + /* + * Now we take YAPS (yet another Prom snapshot) of + * memory, just for safety sake. + * + * The memory list should always be updated last. The prom + * calls which are made to update a memory list may have the + * undesirable affect of claiming physical memory. This may + * happen after the kernel has created its page free list. + * The kernel deals with this by comparing the n and n-1 + * snapshots of memory. Updating the memory available list + * last guarantees we will have a current, accurate snapshot. + * See bug #1260786. + */ + update_memlist("virtual-memory", "available", &vfreelistp); + update_memlist("memory", "available", &pfreelistp); + + if (verbosemode) { + dprintf("physinstalled = %p\n", (void *)pinstalledp); + dprintf("physavail = %p\n", (void *)pfreelistp); + dprintf("virtavail = %p\n", (void *)vfreelistp); + dprintf("extent = 0x%lx\n", memlistextent); + dprintf("Leaving boot_release()\n"); + + dprintf("Physinstalled: \n"); + if (debug) + print_memlist(pinstalledp); + + dprintf("Physfree:\n"); + if (debug) + print_memlist(pfreelistp); + + dprintf("Virtfree: \n"); + if (debug) + print_memlist(vfreelistp); + } + +#ifdef DEBUG_MMU + dump_mmu(); + prom_enter_mon(); +#endif +} + +void +boot_fail_gracefully(void) +{ + prom_panic( + "mismatched version of /boot interface: new boot, old kernel"); +} diff --git a/usr/src/psm/stand/boot/sparc/common/bootprop.c b/usr/src/psm/stand/boot/sparc/common/bootprop.c new file mode 100644 index 0000000000..dcc69fa593 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/bootprop.c @@ -0,0 +1,263 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/promif.h> +#include <sys/bootconf.h> +#include <sys/salib.h> +#include <sys/boot.h> +#include "boot_plat.h" + +char *v2path, *kernname, *systype; +char *my_own_name = "boot"; +char v2args_buf[V2ARGS_BUF_SZ]; +char *v2args = v2args_buf; +char *mfg_name; +char *impl_arch_name; +char *bootp_response; +char *module_path; +int cache_state; +uint64_t memlistextent; /* replacement for old member of bootops */ + +/* These are the various memory lists */ +struct memlist *pfreelistp, /* physmem available */ + *vfreelistp, /* virtmem available */ + *pinstalledp; /* physmem installed */ + +char *boot_message; + +char *netdev_path; + +/* + * Support new boot properties "boot-start" and "boot-end" for + * Freeze/Thaw project. + */ +caddr_t start_addr, end_addr; + +#define BOOT_BADPROP -1 +#define BOOT_SUCCESS 0 +#define BOOT_FAILURE -1 +#define NIL 0 + +#define strequal(p, q) (strcmp((p), (q)) == 0) + + +/* + * This routine is used by stand/lib/$PROC/libnfs.a in case it comes up with a + * default filename, and by bootflags() if a default filename is specified in + * the boot arguments. + */ +void +set_default_filename(char *filename) +{ + kernname = filename; +} + + +static const struct bplist { + char *name; + void *val; + uint_t size; +} bprop_tab[] = { + "boot-args", &v2args, 0, + "boot-path", &v2path, 0, + "fstype", &systype, 0, + "whoami", &my_own_name, 0, + "mfg-name", &mfg_name, 0, + "impl-arch-name", &impl_arch_name, 0, + "module-path", &module_path, 0, + "virt-avail", &vfreelistp, 0, + "phys-avail", &pfreelistp, 0, + "phys-installed", &pinstalledp, 0, + "default-name", &kernname, 0, + "extent", &memlistextent, sizeof (memlistextent), + "vac", &vac, sizeof (vac), + "cache-on?", &cache_state, sizeof (int), + "memory-update", 0, 0, + "boot-start", &start_addr, sizeof (start_addr), + "boot-end", &scratchmemp, sizeof (scratchmemp), + "boot-message", &boot_message, 0, + "bootp-response", &bootp_response, 0, + "netdev-path", &netdev_path, 0, + 0, 0, 0 +}; + +/* + * These routines implement the boot getprop interface. + * They are designed to mimic the corresponding devr_{getprop,getproplen} + * functions. + * The assumptions is that the basic property is an unsigned int. Other + * types (including lists) are special cases. + */ + +/*ARGSUSED*/ +int +bgetproplen(struct bootops *bop, char *name) +{ + int size = 0; + struct bplist *p; + struct memlist *ml; + + /* this prop has side effects only. No length. */ + if (strequal(name, "memory-update")) + return (BOOT_SUCCESS); + + for (p = (struct bplist *)bprop_tab; p->name != (char *)0; p++) { + + /* got a linked list? */ + if ((strequal(name, "virt-avail") && strequal(name, p->name)) || + (strequal(name, "phys-avail") && strequal(name, p->name)) || + (strequal(name, "phys-installed") && + strequal(name, p->name))) { + + for (ml = *((struct memlist **)p->val); + ml != NIL; + ml = ml->next) + + /* + * subtract out the ptrs for our local + * linked list. The application will + * only see an array. + */ + size += (int)(sizeof (struct memlist) - + 2*sizeof (struct memlist *)); + return (size); + + } else if (strequal(name, p->name)) { + + /* if we already know the size, return it */ + if (p->size != 0) + return (p->size); + else { + if (*((char **)p->val) == NIL) + return (0); /* NULL is allowed */ + + /* don't forget the null termination */ + return (strlen(*((char **)p->val)) + 1); + } + } + } + printf("Property (%s) not supported by %s\n", name, my_own_name); + return (BOOT_BADPROP); +} + +/*ARGSUSED*/ +int +bgetprop(struct bootops *bop, char *name, void *buf) +{ + struct bplist *p; + struct memlist *ml; + + if (strequal(name, "memory-update")) { +/* + * dprintf("bgetprop: updating memlists.\n"); + */ + update_memlist("virtual-memory", "available", &vfreelistp); + update_memlist("memory", "available", &pfreelistp); + return (BOOT_SUCCESS); + } + + if (strequal(name, "boot-start")) { + start_addr = (caddr_t)_start; + bcopy((char *)(&start_addr), buf, sizeof (start_addr)); + return (BOOT_SUCCESS); + } + + if (strequal(name, "boot-end")) { + /* + * The true end of boot should be scratchmemp, + * boot gets its dynamic memory from the scratchmem + * which is the first 4M of the physical memory, + * and they are mapped 1:1. + */ + end_addr = scratchmemp; + bcopy((char *)(&end_addr), buf, sizeof (scratchmemp)); + return (BOOT_SUCCESS); + } + + for (p = (struct bplist *)bprop_tab; p->name != (char *)0; p++) { + + /* gotta linked list? */ + if ((strequal(name, "virt-avail") && strequal(name, p->name)) || + (strequal(name, "phys-avail") && strequal(name, p->name)) || + (strequal(name, "phys-installed") && + strequal(name, p->name))) { + + u_longlong_t *t = buf; + + for (ml = *((struct memlist **)p->val); + ml != NIL; + ml = ml->next) { + + /* copy out into an array */ + *t++ = ml->address; + *t++ = ml->size; + } + return (BOOT_SUCCESS); + } else if (strequal(name, p->name)) { + if (p->size != 0) { + bcopy(p->val, buf, p->size); + } else { + (void) strcpy((char *)buf, *((char **)p->val)); + } + return (BOOT_SUCCESS); + } + } + return (BOOT_FAILURE); +} + +/* + * If the user wants the first property in the list, he passes in a + * null string. The routine will always return a ptr to the name of the + * next prop, except when there are no more props. In that case, it will + * return a null string. + */ + +/*ARGSUSED*/ +char * +bnextprop(struct bootops *bop, char *prev) +{ + struct bplist *p; + + /* user wants the firstprop */ + if (*prev == 0) + return (bprop_tab->name); + + for (p = (struct bplist *)bprop_tab; p->name != (char *)0; p++) { + + if (strequal(prev, p->name)) + /* + * if prev is the last valid prop, + * we will return our terminator (0). + */ + return ((++p)->name); + + + } + return ((char *)0); +} diff --git a/usr/src/psm/stand/boot/sparc/common/get.c b/usr/src/psm/stand/boot/sparc/common/get.c new file mode 100644 index 0000000000..2fa5b99c0e --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/get.c @@ -0,0 +1,84 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/promif.h> + +int +getchar(void) +{ + register int c; + + while ((c = prom_mayget()) == -1) + ; + if (c == '\r') { + prom_putchar(c); + c = '\n'; + } + if (c == 0177 || c == '\b') { + prom_putchar('\b'); + prom_putchar(' '); + c = '\b'; + } + prom_putchar(c); + return (c); +} + +int +cons_gets(char *buf, int n) +{ + char *lp; + char *limit; + int c; + + lp = buf; + limit = &buf[n - 1]; + for (;;) { + c = getchar() & 0177; + switch (c) { + case '\n': + case '\r': + *lp = '\0'; + return (0); + case '\b': + if (lp > buf) + lp--; + continue; + case 'u'&037: /* ^U */ + lp = buf; + prom_putchar('\r'); + prom_putchar('\n'); + continue; + default: + if (lp < limit) + *lp++ = (char)c; + else + prom_putchar('\a'); /* bell */ + } + } +} diff --git a/usr/src/psm/stand/boot/sparc/common/hsfsconf.c b/usr/src/psm/stand/boot/sparc/common/hsfsconf.c new file mode 100644 index 0000000000..2f71220391 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/hsfsconf.c @@ -0,0 +1,50 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/stat.h> +#include <sys/bootvfs.h> + +/* HSFS Support */ +extern struct boot_fs_ops boot_hsfs_ops; + +struct boot_fs_ops *boot_fsw[] = { + &boot_hsfs_ops, +}; + +int boot_nfsw = sizeof (boot_fsw) / sizeof (boot_fsw[0]); +static char *fstype = "hsfs"; + +/*ARGSUSED*/ +char * +set_fstype(char *v2path, char *bpath) +{ + set_default_fs(fstype); + return (fstype); +} diff --git a/usr/src/psm/stand/boot/sparc/common/mapfile b/usr/src/psm/stand/boot/sparc/common/mapfile new file mode 100644 index 0000000000..069b68aa7e --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/mapfile @@ -0,0 +1,36 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2003 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +text = LOAD ?RX V0x120000; +text : $PROGBITS ?A!W; + +data = LOAD ?RWX A0x8; +data : $PROGBITS ?AW; +data : $NOBITS ?AW; + +note = NOTE; +note : $NOTE; + diff --git a/usr/src/psm/stand/boot/sparc/common/nfsconf.c b/usr/src/psm/stand/boot/sparc/common/nfsconf.c new file mode 100644 index 0000000000..ea9a8c5eb7 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/nfsconf.c @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/obpdefs.h> +#include <sys/stat.h> +#include <sys/bootvfs.h> +#include <sys/bootdebug.h> +#include <sys/promif.h> +#include <sys/salib.h> +#include "boot_plat.h" + +/* + * filesystem switch table, NFS + */ +extern struct boot_fs_ops boot_nfs_ops; +struct boot_fs_ops *boot_fsw[] = { + &boot_nfs_ops, +}; + +int boot_nfsw = sizeof (boot_fsw) / sizeof (boot_fsw[0]); +int nfs_readsize = 0; + +static char *nfsname = "nfs"; + +/* ARGSUSED */ +char * +set_fstype(char *v2path, char *bpath) +{ + set_default_fs(nfsname); + return (nfsname); +} diff --git a/usr/src/psm/stand/boot/sparc/common/ramdisk.c b/usr/src/psm/stand/boot/sparc/common/ramdisk.c new file mode 100644 index 0000000000..bba9f4b5d2 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/ramdisk.c @@ -0,0 +1,567 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/promif.h> +#include <sys/salib.h> +/* EXPORT DELETE START */ +#include <bootlog.h> +/* EXPORT DELETE END */ +#include "ramdisk.h" + +/* + * This is a chunk of Forth delivered by the OBP group. When loaded + * into OBP it creates a ramdisk device node whose functionality is + * defined in FWARC 2002/299. + * + * Note the %s in the line following " new-device" - this is where we + * plug the name of the node in. + */ +static const char ramdisk_fth[] = + +"headerless " + +"\" /\" find-package 0= if" +" .\" Can't find /\" abort " +"then push-package " + +"new-device" +" \" %s\" device-name" +" \" block\" encode-string \" device_type\" property" +/* CSTYLED */ +" \" SUNW,ramdisk\" encode-string \" compatible\" property" + +" hex" + +" headerless" + +" 0 value mmu-ihandle" +" 0 value mem-ihandle" + +" : get-memory-ihandles" /* ( -- ) */ +" \" /chosen\" find-package drop dup \" mmu\" rot" +" get-package-property if" +" .\" Can't find chosen mmu property\" cr abort" +" then" +" decode-int to mmu-ihandle 2drop" +" \" memory\" rot get-package-property if" +" .\" Can't find chosen memory property\" cr abort" +" then" +" decode-int to mem-ihandle 2drop" +" ;" + +" : get-page-size" /* ( -- page-size ) */ +" mmu-ihandle ihandle>phandle \" page-size\" rot get-package-property" +" if h# 2000 else decode-int nip nip then " +" ;" + +" : get-mode" /* ( -- rw-mode ) */ +" here \" translate\" mmu-ihandle $call-method if" +" nip nip" +" else" +" h# 27" +" then" +" ;" + +" : 64>32bit-phys" /* ( 64bit.lo 64bit.hi -- 32bit.lo 32bit.hi ) */ +" drop xlsplit" +" ;" + +" : 32>64bit-phys" /* ( 32bit.lo 32bit.hi -- 64bit.lo 64bit.hi ) */ +" lxjoin 0" +" ;" + +" : phy-claim" /* ( size align -- base.lo base.hi 0 | error ) */ +" \" claim\" mem-ihandle ['] $call-method catch if" +" drop 2drop 2drop -1" +" else" +" 64>32bit-phys 0" +" then" +" ;" + +" : phy-release" /* ( phys.lo phys.hi size -- ) */ +" >r 32>64bit-phys r> \" release\" mem-ihandle $call-method" +" ;" + +" : vir-claim" /* ( [ virt ] size align -- base ) */ +" \" claim\" mmu-ihandle $call-method" +" ;" + +" : vir-release" /* ( virt size -- ) */ +" \" release\" mmu-ihandle $call-method" +" ;" + +" : vir-map" /* ( phys-lo phys-hi virt size mode -- ) */ +" >r >r >r 32>64bit-phys r> r> r>" +" \" map\" mmu-ihandle $call-method" +" ;" + +" : vir-unmap" /* ( virt size -- ) */ +" \" unmap\" mmu-ihandle $call-method" +" ;" +" headers" + +/* \ This structure represents a physical "chunk" of ramdisk memory */ +" struct" +" /l field >res-pa.lo" /* \ lower 32bits of physical address */ +" /l field >res-pa.hi" /* \ upper 32bits of physical address */ +" /l field >res-len.lo" /* \ lower 32bits of chunk size */ +" /l field >res-len.hi" /* \ upper 32bits of chunk size */ +" constant /res-entry" + +" 4 value max-res-entries" /* \ Max # of non-contig phys chunks */ + +" max-res-entries /res-entry *" /* \ size of resource buffer */ +" ( value ) buffer: my-resources" /* \ resource buffer label */ +" 0 value num-res-entries" /* \ current # of chunks allocated */ +" h# 10 constant label-size" /* \ size of disk-label buffer */ +" label-size instance buffer: my-label" /* \ for disk-label argument string */ + +" get-memory-ihandles" /* \ So we can claim/map/free memory */ +" get-page-size value pagesize" /* \ get virt pagesize from vmem node */ +" get-mode value mode" /* \ get mode to map virt memory with */ + +" 0 instance value window-mapped?" /* \ just in case for pa's near 0 */ +" 0 instance value window-pa" /* \ physical base of virtual window */ +" 0 instance value window-base" /* \ virtual window base */ +" h# 10000 constant window-size" /* \ virtual window size */ + +" 0 instance value filepos" /* \ file position marker */ +" -1 value new-disk?" /* \ need to alloc new resources? */ + +" 0 instance value offset-low" /* \ Offset to start of partition */ +" 0 instance value offset-high" /* \ For partition relative seeks */ +" 0 instance value label-package" /* \ ihandle for disk-label package */ + +" external" /* \ Because device_type = block */ + +" 0 value size" /* \ size of disk */ +" 0 value #blocks" /* \ size of disk / decimal 512 */ + +" headerless" + +" : round-up" /* ( n -- n' ) */ +" 1- tuck + swap invert and" +" ;" + +" : init-label-package" /* ( adr len -- okay? ) */ +" 0 to offset-high 0 to offset-low" +" \" disk-label\" $open-package to label-package" +" label-package if" +" 0 0 \" offset\" label-package $call-method" +" to offset-high to offset-low" +" true" +" else" +" .\" Can't open disk label package\" cr false" +" then" +" ;" + +" : res-entry-len" /* ( n -- 64bit-len | 0 ) \ Get length of chunk n */ +" dup num-res-entries > if" +" drop 0" +" else" +" /res-entry * my-resources +" +" dup >res-len.lo l@ swap >res-len.hi l@" +" lxjoin" +" then" +" ;" + +" : res-entry-pa" /* ( n -- 64bit-pa | 0 ) \ Get phys address of chunk n */ +" dup num-res-entries > if" /* ( n ) */ +" drop 0" /* ( 0 ) */ +" else" /* ( n ) */ +" /res-entry * my-resources +" /* ( chunk-adr ) */ +" dup >res-pa.lo l@ swap >res-pa.hi l@" /* ( pa.lo pa.hi ) */ +" lxjoin" /* ( 64bit-pa ) */ +" then" /* ( 64bit-pa ) */ +" ;" + +" : claim-window" /* ( -- ) \ Claim mem for virt window */ +" window-size pagesize vir-claim to window-base" +" ;" + +" : release-window" /* ( -- ) \ Free virt window memory */ +" window-base window-size" +" 2dup vir-unmap" +" vir-release" +" ;" + +" : map-window" /* ( 64bit-pa -- ) \ Map a physical address to the v-window */ +" dup to window-pa" +" xlsplit window-base window-size mode vir-map" +" -1 to window-mapped?" +" ;" + +" : unmap-window" /* ( -- ) \ Unmap the virtual window */ +" window-base window-size vir-unmap" +" 0 to window-mapped?" +" ;" + +" : in-window?" /* ( pa -- in-window? ) */ +" window-mapped? if" +" window-pa dup window-size + 1- between" +" else" +" drop 0" +" then" +" ;" + +" : window-left" /* ( offset -- space-left-in-window ) */ +" window-size mod" +" window-size swap -" +" ;" + +" : release-resources" /* ( -- ) \ release previously claimed phys addrs */ +" num-res-entries 0 2dup = if" /* ( res-entries 0 ) */ +" 2drop exit" /* ( ) */ +" then" /* ( res-entries 0 ) */ +" do" /* ( ) */ +" i res-entry-pa xlsplit" /* ( pa.lo pa.hi ) */ +" i res-entry-len phy-release" /* ( ) */ +" loop" /* ( ) */ +" 0 to num-res-entries" /* ( ) */ +" my-resources max-res-entries /res-entry * erase" /* ( ) */ +" ;" + +" : fill-entry" /* ( pa.lo pa.hi size.lo size.hi -- ) \ fill chunk buf */ +" num-res-entries /res-entry * my-resources +" +" tuck >res-len.hi l!" +" tuck >res-len.lo l!" +" tuck >res-pa.hi l!" +" >res-pa.lo l!" +" num-res-entries 1+ to num-res-entries" +" ;" + +/* \ First attempt to claim the whole ramdisk contiguously. */ +/* \ If that doesn't work, try to claim it in smaller chunks */ + +" : attempt-claim" /* ( size -- error? ) */ +" size 0 begin" /* ( next totcl ) */ +" over pagesize phy-claim if" /* ( next totcl ) */ +" swap 2 / window-size" /* ( totcl next' ) */ +" round-up swap" /* ( next' totcl ) */ +" else" /* ( next totcl pa.lo,hi ) */ +" 2over drop xlsplit" /* ( next totcl pa.lo,hi len.lo,hi ) */ +" fill-entry" /* ( next totcl ) */ +" over +" /* ( next totcl ) */ +" then" /* ( next totcl ) */ +" 2dup size - 0>=" /* ( next totcl next comp? ) */ +" swap size max-res-entries /" /* ( next totcl comp? next smallest ) */ +" - 0< or" /* ( next totcl ) */ +" until" /* ( next totcl ) */ +" nip size - 0< if -1 else 0 then" +" ;" + +" : claim-resources" /* ( -- error? ) */ +" attempt-claim if release-resources -1 else 0 then" +" ;" + +/* \ Given a 0-relative disk offset compute the proper physical address */ +" : offset>pa" /* ( disk-offset -- 64bit-pa error? ) */ +" 0 num-res-entries 0 do" /* ( disk-offset 0 ) */ +" i res-entry-len +" /* ( disk-offset len' ) */ +" 2dup - 0< if" /* ( disk-offset len' ) */ +" - i res-entry-len +" /* ( offset-into-pa ) \ briefly -ve */ +" i res-entry-pa + 0" /* ( pa 0 ) */ +" unloop exit" /* ( pa 0 ) */ +" then" /* ( disk-offset len' ) */ +" loop" /* ( disk-offset len' ) */ +" drop -1" /* ( offset error ) */ +" ;" + +/* \ Map the virtual window to the physical-address corresponding to the */ +/* \ given 0-relative disk offset */ +" : get-window" /* ( offset -- va len error? ) */ +" dup offset>pa if" /* ( offset pa ) */ +" -1" /* ( offset pa -1 ) */ +" else" /* ( offset pa ) */ +" dup in-window? 0= if" /* ( offset pa ) */ +" unmap-window" /* ( offset pa ) */ +" over window-size mod - map-window" /* ( offset ) */ +" else" +" drop" +" then" +" window-base over window-size mod +" /* ( offset va ) */ +" swap window-left 0" /* ( va len 0 ) */ +" then" /* ( va len error? ) */ +" ;" + +" headers" + +/* \ Write len1 bytes from src into va. */ +" : partial-write" /* ( src len0 va len1 -- len' ) */ +" rot min dup >r move r>" +" ;" + +/* \ Read len1 bytes from src into va. */ +" : partial-read" /* ( src len0 va len1 -- len' ) */ +" rot min dup >r >r swap r> move r>" +" ;" + +" defer operation ' partial-write is operation" + +/* \ Write or Read len given the src address. The block-operation word */ +/* \ determines the physical address that corresponds to the current file */ +/* \ position, and maps/unmaps the 64K virtual window */ +" : block-operation" /* ( src len acf -- len' ) */ +" is operation" +" 0 -rot begin" /* ( 0 src len ) */ +" dup 0>" /* ( len' src len more? ) */ +" while" /* ( len' src len ) */ +" 2dup filepos" /* ( len' src len src len filepos ) */ +" get-window if" /* ( len' src len src len va len ) */ +" 2drop 2drop 2drop exit" /* ( len' ) */ +" then" /* ( len src len src len va len ) */ +" operation" /* ( len src len len' ) */ +" dup filepos + to filepos" /* ( len src len len' ) */ +" >r r@ - rot r@ + rot r> + rot" /* ( len' src' len' ) */ +" repeat" /* ( len' src' len' ) */ +" 2drop" /* ( len' ) */ +" ;" + +" : range-bad?" /* ( adr -- range-bad? ) */ +" 0 size between 0=" +" ;" + +" : space-left" /* ( -- space-left ) */ +" size filepos -" +" ;" + +" : hex-number" /* ( adr,len -- true | n false ) */ +" base @ >r hex $number r> base !" +" ;" + +" : parse-size" /* ( $nums -- 64bit-size | 0 ) \ poss ',' seperated ints */ +" ascii , left-parse-string" /* ( $num $num ) */ +" hex-number if 2drop 0 exit then" /* ( $num n ) */ +" over 0= if nip nip exit then" /* ( $num n ) */ +" -rot hex-number if drop 0 exit then" /* ( hi lo ) */ +" swap lxjoin" +" ;" + +" : set-size" /* ( adr len -- error? ) */ +" parse-size dup 0= if" /* ( size ) */ +" drop -1" /* ( -1 ) */ +" else" /* ( size ) */ +" window-size round-up" /* ( size' ) */ +" dup to size" /* ( size' ) */ +" d# 512 / to #blocks" /* ( ) */ +" \" nolabel\" my-label pack" /* \ first open cannot have a label */ +" drop 0" /* ( 0 ) */ +" then" /* ( error? ) */ +" ;" + +" : $=" /* (s adr1 len1 adr2 len2 -- same? ) */ +" rot tuck <> if 3drop false exit then" /* ( adr1 adr2 len1 ) */ +" comp 0=" /* ( same? ) */ +" ;" + +" : is-label?" /* ( adr len -- is-label? ) \ $= "nolabel" or <a-z> */ +" dup 1 = if" /* ( adr len ) */ +" drop c@ ascii a ascii z between" /* ( is-label? ) */ +" else" /* ( adr len ) */ +" \" nolabel\" $=" /* ( is-label? ) */ +" then" /* ( is-label? ) */ +" ;" + +" : set-label" /* ( adr len -- error? ) */ +" my-label label-size erase" +" dup 1+ label-size > if" +" 2drop -1" +" else" +" my-label pack drop 0" +" then" +" ;" + +" : process-args" /* ( arg$ -- error? ) */ +" ascii = left-parse-string" /* ( value$ key$ ) */ +" new-disk? if" /* ( value$ key$ ) */ +" 2dup \" size\" $= if" /* ( value$ key$ ) */ +" 2drop set-size exit" /* ( error? ) */ +" then" /* ( value$ key$ ) */ +" else" /* ( value$ key$ ) */ +" 2dup is-label? if" /* ( value$ key$ ) */ +" 2swap 2drop set-label exit" /* ( error? ) */ +" then" /* ( value$ key$ ) */ +" then" /* ( value$ key$ ) */ +" .\" Inappropriate argument \" type cr 2drop -1" /* ( -1 ) */ +" ;" + +/* \ Publish the physical chunks that make up the ramdisk in the */ +/* \ existing property */ +" : create-existing-prop" /* ( -- ) */ +" 0 0 encode-bytes" /* ( adr 0 ) */ +" num-res-entries 0 do" /* ( adr 0 ) */ +" i /res-entry * my-resources + >r" /* ( adr len ) */ +" r@ >res-pa.hi l@ encode-int encode+" /* ( adr len ) */ +" r@ >res-pa.lo l@ encode-int encode+" /* ( adr len ) */ +" r@ >res-len.hi l@ encode-int encode+" /* ( adr len ) */ +" r> >res-len.lo l@ encode-int encode+" /* ( adr len ) */ +" loop" /* ( adr len ) */ +" \" existing\" property" /* ( ) */ +" ;" + +" external" + +" : read" /* ( adr,len -- len' ) */ +" space-left" /* ( adr len space-left ) */ +" min ['] partial-read" /* ( adr len' read-acf ) */ +" block-operation" /* ( len' ) */ +" ;" + +" : write" /* ( adr,len -- len' ) */ +" space-left" /* ( adr len space-left ) */ +" min ['] partial-write" /* ( adr len' write-acf ) */ +" block-operation" /* ( len' ) */ +" ;" + +" : seek" /* ( offset other -- error? ) */ +" offset-high + swap offset-low + swap drop" /* \ "other" arg unused */ +" dup 0< if" /* ( offset ) */ +" size +" /* ( offset' ) */ +" then" /* ( offset' ) */ +" 0 + dup range-bad? if" /* ( offset' ) */ +" drop -1" /* ( -1 ) */ +" else" /* ( offset' ) */ +" to filepos false" /* ( 0 ) */ +" then" /* ( error? ) */ +" ;" + +" : load" /* ( addr -- size ) */ +" \" load\" label-package $call-method" +" ;" + +" : offset" /* ( rel -- abs ) \ needed for device_type = block */ +" offset-low +" +" ;" + +/* \ release resources, initialize data, remove existing property */ +/* \ Can be called with no instance data */ +" : destroy" /* ( -- ) */ +" \" existing\" delete-property" +" 0 to size" +" -1 to new-disk?" +" release-resources" +" ;" + +" : open" /* ( -- flag ) */ +" my-args process-args if" +" 0 exit" /* \ unrecognized arguments */ +" then" +" new-disk? if" +" claim-resources if 0 exit then" /* \ can't claim */ +" create-existing-prop" /* \ advertise resources */ +" 0 to new-disk?" /* \ no longer a new-disk */ +" then" +" claim-window" /* \ claim virtual window */ +" my-label count init-label-package 0= if 0 exit then" +" -1" +" ;" + +" : close" /* ( -- ) */ +" window-base if " +" release-window" +" then" +" ; " +"finish-device " + +"pop-package" + +; /* end of ramdisk_fth[] initialization */ + + +/* + * Create an actual ramdisk instance. + */ +static void +create_ramdisk_node(const char *ramdisk_name) +{ + char *fth_buf; + size_t buf_size; + + buf_size = sizeof (ramdisk_fth) + strlen(ramdisk_name); + + fth_buf = bkmem_alloc(buf_size); + if (fth_buf == NULL) { + prom_panic("unable to allocate Forth buffer for ramdisk"); + } + + (void) snprintf(fth_buf, buf_size, ramdisk_fth, ramdisk_name); + + prom_interpret(fth_buf, 0, 0, 0, 0, 0); + + bkmem_free(fth_buf, buf_size); +} + +int +create_ramdisk(const char *ramdisk_name, size_t size, char **device_path) +{ + static int first_time = 1; + char buf[OBP_MAXPATHLEN]; + ihandle_t ih; + + /* + * Ensure that size is a multiple of page size (rounded up). + */ + size = ptob(btopr(size)); + +/* EXPORT DELETE START */ + bootlog("wanboot", BOOTLOG_VERBOSE, "Creating ramdisk, size=0x%lx", + size); +/* EXPORT DELETE END */ + + if (strcmp(ramdisk_name, RD_ROOTFS) == 0 || + strcmp(ramdisk_name, RD_BOOTFS) == 0) { + + if (first_time) { + first_time = 0; + + create_ramdisk_node(RD_ROOTFS); + create_ramdisk_node(RD_BOOTFS); + } + + (void) snprintf(buf, sizeof (buf), "/%s:nolabel", ramdisk_name); + *device_path = strdup(buf); + + if (*device_path != NULL) { + (void) snprintf(buf, sizeof (buf), "/%s:size=%x,%x", + ramdisk_name, + (uint32_t)(size >> 32), (uint32_t)size); + + if ((ih = prom_open(buf)) != 0) { + return (ih); + } + } + } + +/* EXPORT DELETE START */ + bootlog("wanboot", BOOTLOG_CRIT, "Cannot create ramdisk \"%s\"", + ramdisk_name); +/* EXPORT DELETE END */ + prom_panic("create_ramdisk: fatal error"); + /* NOTREACHED */ +} diff --git a/usr/src/psm/stand/boot/sparc/common/ramdisk.h b/usr/src/psm/stand/boot/sparc/common/ramdisk.h new file mode 100644 index 0000000000..77eb021a11 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/ramdisk.h @@ -0,0 +1,50 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _RAMDISK_H +#define _RAMDISK_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Ramdisk names + */ +#define RD_BOOTFS "ramdisk-bootfs" +#define RD_ROOTFS "ramdisk-rootfs" + +extern int create_ramdisk(const char *, size_t, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _RAMDISK_H */ diff --git a/usr/src/psm/stand/boot/sparc/common/sparc.il b/usr/src/psm/stand/boot/sparc/common/sparc.il new file mode 100644 index 0000000000..0065a5f9b4 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/sparc.il @@ -0,0 +1,33 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1995 by Sun Microsystems, Inc. All Rights Reserved. + */ +#pragma ident "%Z%%M% %I% %E% SMI" +! +! In-line functions for sparc kernels. +! + +! stub function for now + .inline sync_instruction_memory,8 + nop + .end diff --git a/usr/src/psm/stand/boot/sparc/common/sparcv9_subr.s b/usr/src/psm/stand/boot/sparc/common/sparcv9_subr.s new file mode 100644 index 0000000000..bddd426161 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/sparcv9_subr.s @@ -0,0 +1,293 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/asm_linkage.h> +#include <sys/machparam.h> /* To get SYSBASE and PAGESIZE */ +#include <sys/privregs.h> + +#if !defined(lint) + + .seg ".text" + .align 4 + +#define PSR_PIL_BIT 0x8 + +/* + * Macro to raise processor priority level. + * Avoid dropping processor priority if already at high level. + * Also avoid going below CPU->cpu_base_spl, which could've just been set by + * a higher-level interrupt thread that just blocked. + * XXX4U: bring splr inline + */ +#define RAISE(level) \ + b splr; \ + mov ((level) << PSR_PIL_BIT), %o0 +/* + * Macro to set the priority to a specified level. + * Avoid dropping the priority below CPU->cpu_base_spl. + * XXX4U: bring splx inline + */ +#define SETPRI(level) \ + b splx; \ + mov ((level) << PSR_PIL_BIT), %o0 + +#endif /* lint */ + + /* + * Berkley 4.3 introduced symbolically named interrupt levels + * as a way deal with priority in a machine independent fashion. + * Numbered priorities are machine specific, and should be + * discouraged where possible. + * + * Note, for the machine specific priorities there are + * examples listed for devices that use a particular priority. + * It should not be construed that all devices of that + * type should be at that priority. It is currently were + * the current devices fit into the priority scheme based + * upon time criticalness. + * + * The underlying assumption of these assignments is that + * SPARC9 IPL 10 is the highest level from which a device + * routine can call wakeup. Devices that interrupt from higher + * levels are restricted in what they can do. If they need + * kernels services they should schedule a routine at a lower + * level (via software interrupt) to do the required + * processing. + * + * Examples of this higher usage: + * Level Usage + * 15 Asynchronous memory exceptions + * 14 Profiling clock (and PROM uart polling clock) + * 13 Audio device + * 12 Serial ports + * 11 Floppy controller + * + * The serial ports request lower level processing on level 6. + * Audio and floppy request lower level processing on level 4. + * + * Also, almost all splN routines (where N is a number or a + * mnemonic) will do a RAISE(), on the assumption that they are + * never used to lower our priority. + * The exceptions are: + * spl8() Because you can't be above 15 to begin with! + * splzs() Because this is used at boot time to lower our + * priority, to allow the PROM to poll the uart. + * spl0() Used to lower priority to 0. + * splsoftclock() Used by hardclock to lower priority. + */ + +#if defined(lint) + +int splimp(void) { return (0); } +int splnet(void) { return (0); } + +#ifdef notdef +int spl6(void) { return (0); } +int spl5(void) { return (0); } +#endif notdef + +#else /* lint */ + + /* locks out all interrupts, including memory errors */ + ENTRY(spl8) + SETPRI(15) + SET_SIZE(spl8) + + /* just below the level that profiling runs */ + ALTENTRY(splaudio) + ENTRY(spl7) + RAISE(13) + SET_SIZE(spl7) + SET_SIZE(splaudio) + + /* sun specific - highest priority onboard serial i/o zs ports */ + ALTENTRY(splzs) + SETPRI(12) /* Can't be a RAISE, as it's used to lower us */ + SET_SIZE(splzs) + + /* + * should lock out clocks and all interrupts, + * as you can see, there are exceptions + */ + ALTENTRY(splhigh) + ALTENTRY(splhi) + + /* the standard clock interrupt priority */ + ALTENTRY(splclock) + + /* highest priority for any tty handling */ + ALTENTRY(spltty) + + /* highest priority required for protection of buffered io system */ + ALTENTRY(splbio) + + /* machine specific */ + ENTRY2(spl6,spl5) + RAISE(10) + SET_SIZE(splhigh) + SET_SIZE(splhi) + SET_SIZE(splclock) + SET_SIZE(spltty) + SET_SIZE(splbio) + SET_SIZE(spl5) + SET_SIZE(spl6) + + /* + * machine specific + * for sun, some frame buffers must be at this priority + */ + ENTRY(spl4) + RAISE(8) + SET_SIZE(spl4) + + /* highest level that any network device will use */ + ALTENTRY(splimp) + + /* + * machine specific + * for sun, devices with limited buffering: tapes, ethernet + */ + ENTRY(spl3) + RAISE(6) + SET_SIZE(splimp) + SET_SIZE(spl3) + + /* + * machine specific - not as time critical as above + * for sun, disks + */ + ENTRY(spl2) + RAISE(4) + SET_SIZE(spl2) + + ENTRY(spl1) + RAISE(2) + SET_SIZE(spl1) + + /* highest level that any protocol handler will run */ + ENTRY(splnet) + RAISE(1) + SET_SIZE(splnet) + + /* softcall priority */ + /* used by hardclock to LOWER priority */ + ENTRY(splsoftclock) + SETPRI(1) + SET_SIZE(splsoftclock) + + /* allow all interrupts */ + ENTRY(spl0) + SETPRI(0) + SET_SIZE(spl0) + +#endif /* lint */ + +/* + * splx - set PIL back to that indicated by the old %PSR passed as an argument, + * or to the CPU's base priority, whichever is higher. + * sys_rtt (in locore.s) relies on this not to use %g1 or %g2. + */ + +#if defined(lint) + +/* ARGSUSED */ +void +splx(int level) +{ +} + +#else /* lint */ + + ENTRY(splx) + rdpr %pil, %o1 ! get current pil + wrpr %o0, %pil + retl + mov %o1, %o0 + SET_SIZE(splx) + +#endif /* level */ + +/* + * splr() + * + * splr is like splx but will only raise the priority and never drop it + * Be careful not to set priority lower than CPU->cpu_base_pri, + * even though it seems we're raising the priority, it could be set higher + * at any time by an interrupt routine, so we must block interrupts and + * look at CPU->cpu_base_pri. + * + */ + +#if defined(lint) +#ifdef notdef + +/* ARGSUSED */ +int +splr(int level) +{ return (0); } + +#endif notdef +#else /* lint */ + +/* + * splr(psr_pri_field) + * splr is like splx but will only raise the priority and never drop it + */ + + ENTRY(splr) + rdpr %pil, %o1 ! get current pil + cmp %o0, %o1 + ble 1f + nop + wrpr %o0, %pil +1: retl + mov %o1, %o0 ! return the old pil + SET_SIZE(splr) + +#endif /* lint */ + +/* + * get_ticks() + */ +#if defined(lint) + +/* ARGSUSED */ +uint64_t +get_ticks(void) +{ return (0); } + +#else /* lint */ + + ENTRY(get_ticks) + rdpr %tick, %o0 + sllx %o0, 1, %o0 + retl + srlx %o0, 1, %o0 ! shake off npt bit + SET_SIZE(get_ticks) + +#endif /* lint */ diff --git a/usr/src/psm/stand/boot/sparc/common/sun4dep.c b/usr/src/psm/stand/boot/sparc/common/sun4dep.c new file mode 100644 index 0000000000..b18456a47b --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/sun4dep.c @@ -0,0 +1,135 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/promif.h> +#include <sys/prom_plat.h> +#include <sys/salib.h> + +int pagesize = PAGESIZE; + +void +fiximp(void) +{ + extern int use_align; + + use_align = 1; +} + +void +setup_aux(void) +{ + dnode_t node; + /* big enough for OBP_NAME and for a reasonably sized OBP_COMPATIBLE. */ + static char cpubuf[5 * OBP_MAXDRVNAME]; + extern uint_t icache_flush; + extern char *cpulist; + + icache_flush = 1; + node = prom_findnode_bydevtype(prom_rootnode(), OBP_CPU); + if (node != OBP_NONODE && node != OBP_BADNODE) { + int nlen, clen, i; + + if ((nlen = prom_getproplen(node, OBP_NAME)) <= 0 || + nlen > sizeof (cpubuf) || + prom_getprop(node, OBP_NAME, cpubuf) <= 0) + prom_panic("no name in cpu node"); + /* nlen includes the terminating null character */ + if ((clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0) { + if ((clen + nlen) > sizeof (cpubuf)) + prom_panic("cpu node \"compatible\" too long"); + /* read in compatible, leaving space for ':' */ + if (prom_getprop(node, OBP_COMPATIBLE, + &cpubuf[nlen]) != clen) + prom_panic("cpu node \"compatible\" error"); + clen += nlen; /* total length */ + /* convert all null characters to ':' */ + clen--; /* except the final one... */ + for (i = 0; i < clen; i++) + if (cpubuf[i] == '\0') + cpubuf[i] = ':'; + } + cpulist = cpubuf; + } else + prom_panic("no cpu node"); +} + + +#ifdef MPSAS + +void sas_symtab(int start, int end); +extern int sas_command(char *cmdstr); + +/* + * SAS support - inform SAS of new symbols being dynamically added + * during simulation via the first standalone. + */ + +#ifndef BUFSIZ +#define BUFSIZ 1024 /* for cmd string buffer allocation */ +#endif + +int sas_symdebug = 0; /* SAS support */ + +void +sas_symtab(int start, int end) +{ + char *addstr = "symtab add $LD_KERNEL_PATH/%s%s 0x%x 0x%x\n"; + char *file, *prefix, cmdstr[BUFSIZ]; + extern char filename[]; + + file = filename; + prefix = *file == '/' ? "../../.." : ""; + + (void) sprintf(cmdstr, addstr, prefix, file, start, end); + + /* add the symbol table */ + if (sas_symdebug) (void) printf("sas_symtab: %s", cmdstr); + sas_command(cmdstr); +} + +void +sas_bpts() +{ + sas_command("file $KERN_SCRIPT_FILE\n"); +} +#endif /* MPSAS */ + +/* + * Allocate a region of virtual address space, unmapped. + */ +caddr_t +resalloc_virt(caddr_t virt, size_t size) +{ + if (prom_claim_virt(size, virt) == (caddr_t)-1) + return ((caddr_t)0); + + return (virt); +} diff --git a/usr/src/psm/stand/boot/sparc/common/sun4u_memlist.c b/usr/src/psm/stand/boot/sparc/common/sun4u_memlist.c new file mode 100644 index 0000000000..e25ea32d71 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/sun4u_memlist.c @@ -0,0 +1,219 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1992-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/promif.h> +#include <sys/memlist.h> +#include <sys/bootconf.h> +#include <sys/salib.h> + +/* + * This file defines the interface from the prom and platform-dependent + * form of the memory lists, to boot's more generic form of the memory + * list. For sun4u, the memory list properties are {hi, lo, size_hi, size_lo}, + * which is similar to boot's format, except boot's format is a linked + * list, and the prom's is an array of these structures. Note that the + * native property on sparc machines is identical to the property encoded + * format, so no property decoding is required. + * + * Note that the format of the memory lists is really 4 encoded integers, + * but the encoding is the same as that given in the following structure + * on SPARC systems ... + */ + +struct sun4u_prom_memlist { + u_longlong_t addr; + u_longlong_t size; +}; + +struct sun4u_prom_memlist scratch_memlist[200]; + +struct memlist *fill_memlists(char *name, char *prop, struct memlist *); +extern struct memlist *pfreelistp, *vfreelistp, *pinstalledp; + +static struct memlist *reg_to_list(struct sun4u_prom_memlist *a, size_t size, + struct memlist *old); +static void sort_reglist(struct sun4u_prom_memlist *ar, size_t size); +extern void kmem_init(void); + +void +init_memlists(void) +{ + /* this list is a map of pmem actually installed */ + pinstalledp = fill_memlists("memory", "reg", pinstalledp); + + vfreelistp = fill_memlists("virtual-memory", "available", vfreelistp); + pfreelistp = fill_memlists("memory", "available", pfreelistp); + + kmem_init(); +} + +struct memlist * +fill_memlists(char *name, char *prop, struct memlist *old) +{ + static dnode_t pmem = 0; + static dnode_t pmmu = 0; + dnode_t node; + size_t links; + struct memlist *al; + struct sun4u_prom_memlist *pm = scratch_memlist; + + if (pmem == (dnode_t)0) { + + /* + * Figure out the interesting phandles, one time + * only. + */ + + ihandle_t ih; + + if ((ih = prom_mmu_ihandle()) == (ihandle_t)-1) + prom_panic("Can't get mmu ihandle"); + pmmu = prom_getphandle(ih); + + if ((ih = prom_memory_ihandle()) == (ihandle_t)-1) + prom_panic("Can't get memory ihandle"); + pmem = prom_getphandle(ih); + } + + if (strcmp(name, "memory") == 0) + node = pmem; + else + node = pmmu; + + /* + * Read memory node and calculate the number of entries + */ + if ((links = prom_getproplen(node, prop)) == -1) + prom_panic("Cannot get list.\n"); + if (links > sizeof (scratch_memlist)) { + prom_printf("%s list <%s> exceeds boot capabilities\n", + name, prop); + prom_panic("fill_memlists - memlist size"); + } + links = links / sizeof (struct sun4u_prom_memlist); + + + (void) prom_getprop(node, prop, (caddr_t)pm); + sort_reglist(pm, links); + al = reg_to_list(pm, links, old); + return (al); +} + +/* + * Simple selection sort routine. + * Sorts platform dependent memory lists into ascending order + */ + +static void +sort_reglist(struct sun4u_prom_memlist *ar, size_t n) +{ + int i, j, min; + struct sun4u_prom_memlist temp; + + for (i = 0; i < n; i++) { + min = i; + + for (j = i+1; j < n; j++) { + if (ar[j].addr < ar[min].addr) + min = j; + } + + if (i != min) { + /* Swap ar[i] and ar[min] */ + temp = ar[min]; + ar[min] = ar[i]; + ar[i] = temp; + } + } +} + +/* + * This routine will convert our platform dependent memory list into + * struct memlists's. And it will also coalesce adjacent nodes if + * possible. + */ +static struct memlist * +reg_to_list(struct sun4u_prom_memlist *ar, size_t n, struct memlist *old) +{ + struct memlist *ptr, *head, *last; + int i; + u_longlong_t size = 0; + u_longlong_t addr = 0; + u_longlong_t start1, start2; + int flag = 0; + + if (n == 0) + return ((struct memlist *)0); + + /* + * if there was a memory list allocated before, free it first. + */ + if (old) + (void) add_to_freelist(old); + + head = NULL; + last = NULL; + + for (i = 0; i < n; i++) { + start1 = ar[i].addr; + start2 = ar[i+1].addr; + if (i < n-1 && (start1 + ar[i].size == start2)) { + size += ar[i].size; + if (!flag) { + addr = start1; + flag++; + } + continue; + } else if (flag) { + /* + * catch the last one on the way out of + * this iteration + */ + size += ar[i].size; + } + + ptr = (struct memlist *)get_memlist_struct(); + if (!head) + head = ptr; + if (last) + last->next = ptr; + ptr->address = flag ? addr : start1; + ptr->size = size ? size : ar[i].size; + ptr->prev = last; + last = ptr; + + size = 0; + flag = 0; + addr = 0; + } + + last->next = NULL; + return (head); +} diff --git a/usr/src/psm/stand/boot/sparc/common/sun4u_srt0.s b/usr/src/psm/stand/boot/sparc/common/sun4u_srt0.s new file mode 100644 index 0000000000..78a2d480c7 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/sun4u_srt0.s @@ -0,0 +1,214 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1986-1997, Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * standalone startup code for sun4u LP64 secondary booters. + */ + +#include <sys/asm_linkage.h> +#include <sys/privregs.h> +#include <sys/stack.h> + +#if defined(lint) + +/*ARGSUSED*/ +void +_start(void *a, ...) +{} + +#else + .seg ".text" + .align 8 + .global end + .global edata + .global main + + .seg ".bss" + .align 8 + +_local_p1275cif: + .skip 8 + +! +! Create a stack just below _start. +! +#define STACK_SIZE 0x14000 + + .skip STACK_SIZE +.ebootstack: ! end --top-- of boot stack + +! +! Enter here for all disk/secondary booters loaded by a bootblk program or +! inetboot loaded by OBP. +! Careful: don't touch %o4 until the save, since it contains the +! address of the IEEE 1275 SPARC v9 CIF handler; the linkage to the prom. +! + .seg ".text" + .global prom_exit_to_mon + .type prom_exit_to_mon, #function + + ENTRY(_start) + + ! + ! The stacks in bss now; use the stack we came in on (prom is supposed + ! to call us with a minimum of an 8k stack, bzero bss (and thus our + ! new stack), then switch to the new stack. Do all this without losing + ! track of the p1275cif address cached in %o4. + ! + + save %sp, -SA(MINFRAME), %sp + + ! + ! Zero the bss [edata to end] + ! + setn edata, %g1, %o0 + setn end, %g1, %i2 + call bzero + sub %i2, %o0, %o1 ! size + + restore %g0, %g0, %g0 ! Trivial restore + + ! + ! Switch to our new stack. + ! + setn (.ebootstack - STACK_BIAS), %g1, %o1 + save %o1, -SA(MINFRAME), %sp + + ! + ! Set supervisor mode, interrupt level >= 13, traps enabled + ! We don't set PSTATE_AM even though all our addresses are under 4G. + ! + wrpr %g0, PSTATE_PEF+PSTATE_PRIV+PSTATE_IE, %pstate + + sethi %hi(_local_p1275cif), %o1 + stx %i4, [%o1 + %lo(_local_p1275cif)] + call main ! main(prom-cookie) + mov %i4, %o0 ! SPARCV9/CIF + + ! print stupid error message here! + + call prom_enter_mon ! can't happen .. :-) + nop + SET_SIZE(_start) + +#endif /* lint */ + +#if defined(lint) + +/* ARGSUSED */ +void +exitto(int (*entrypoint)(void *romvec, void *dvec, void *bootops, + void *bootvec)) +{} + +/* ARGSUSED */ +void +exitto64(int (*entrypoint)(void *romvec, void *dvec, void *bootops, + void *bootvec), void *bootvec) +{} + +#else /* lint */ + + ENTRY(exitto) + ! + ! Setup args for client. + ! + ! 32 bit frame, 64 bit sized + sub %g0, SA(MINFRAME) - STACK_BIAS, %g1 + save %sp, %g1, %sp + sethi %hi(_local_p1275cif), %o0 ! 1275 CIF handler for callee. + ldx [%o0 + %lo(_local_p1275cif)], %o0 + clr %o1 ! boot passes no dvec + setn bootops, %g1, %o2 + sethi %hi(elfbootvec), %o3 ! pass elf bootstrap vector + ldx [%o3 + %lo(elfbootvec)], %o3 + rdpr %pstate, %l1 ! Get the present pstate value + wrpr %l1, PSTATE_AM, %pstate ! Set PSTATE_AM = 1 + jmpl %i0, %o7 ! call thru register to the standalone + mov %o0, %o4 ! 1210378: Pass cif in both %o0 & %o4 + + ! eek - we returned -- switch back to a 64-bit frame + ! then panic in a slightly informative way. + + restore %g0, %g0, %g0 + save %sp, -SA(MINFRAME), %sp + sethi %hi(.msg), %o0 + call prom_panic + or %o0, %lo(.msg), %o0 +.msg: .asciz "exitto returned from client program" + SET_SIZE(exitto) + + ENTRY(exitto64) + ! + ! Setup args for client. + ! + save %sp, -SA(MINFRAME), %sp + sethi %hi(_local_p1275cif), %o0 ! 1275 CIF handler for callee. + ldx [%o0 + %lo(_local_p1275cif)], %o0 + mov %i1, %o3 ! bootvec + clr %o1 ! boot passes no dvec + setn bootops, %g1, %o2 + jmpl %i0, %o7 ! call thru register to the standalone + mov %o0, %o4 ! 1210378: Pass cif in both %o0 & %o4 + + ! eek - we returned -- panic in a slightly informative way. + + sethi %hi(.msg64), %o0 + call prom_panic + or %o0, %lo(.msg64), %o0 +.msg64: .asciz "exitto64 returned from client program" + SET_SIZE(exitto64) + +#endif /* lint */ + +#if defined(lint) + +/* + * The interface for our 64-bit client program + * calling the 64-bit romvec OBP. + */ + +#include <sys/promif.h> +#include <sys/prom_isa.h> + +/* ARGSUSED */ +int +client_handler(void *cif_handler, void *arg_array) +{ return (0); } + +#else /* lint */ + + ENTRY(client_handler) + mov %o7, %g1 + mov %o0, %g5 + mov %o1, %o0 + jmp %g5 + mov %g1, %o7 + SET_SIZE(client_handler) + +#endif /* lint */ diff --git a/usr/src/psm/stand/boot/sparc/common/sun4x_standalloc.c b/usr/src/psm/stand/boot/sparc/common/sun4x_standalloc.c new file mode 100644 index 0000000000..5f4d258565 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/sun4x_standalloc.c @@ -0,0 +1,339 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/saio.h> +#include <sys/sysmacros.h> +#include <sys/promif.h> +#include <sys/bootconf.h> +#include <sys/salib.h> + +#define NIL 0 + +#ifdef DEBUG +static int resalloc_debug = 1; +#else /* DEBUG */ +static int resalloc_debug = 0; +#endif /* DEBUG */ +#define dprintf if (resalloc_debug) printf + +extern struct memlist *vfreelistp, *pfreelistp; +extern void reset_alloc(void); +extern void alloc_segment(caddr_t); + +caddr_t memlistpage; +caddr_t le_page; +caddr_t ie_page; +caddr_t scratchmemp; +extern int pagesize; + +#define N_FREELIST 20 /* keep the largest 20 free regions */ +static size_t free_size[N_FREELIST]; +static caddr_t free_addr[N_FREELIST]; + +/* + * OBP sets up a 1:1 mapping of virtual to physical in the range 8KB-10MB. The + * standalone is free to use any or all of this during its lifetime. + * Unfortunately, some platforms (Serengeti and LW8) can't use the full range. + * See 4799331 for more details. Limited platforms can use up to + * MAPPEDMEM_MINTOP; everyone else can use up to MAPPEDMEM_FULLTOP. + * resalloc_init makes the determination as to how much the machine being booted + * can use. + * + * But wait! There's more! resalloc handles three types of allocations: Two + * flavors of RES_BOOTSCRATCH (RES_BOOTSCRATCH and RES_BOOTSCRATCH_NOFAIL), and + * one of RES_CHILDVIRT. RES_CHILDVIRT is handled by prom_alloc, and is boring. + * We handle RES_BOOTSCRATCH allocations ourselves using the portion of the 1:1 + * range not consumed by boot. The unconsumed range is subdivided into two + * portions - the general area from top_resvmem to top_bootmem and the reserved + * area from above memlistpage to top_resvmem. Both RES_BOOTSCRATCH flavors are + * satisfied by the general area until said area is exhausted, at which point + * RES_BOOTSCRATCH allocations return failure. RES_BOOTSCRATCH_NOFAIL + * allocations can't fail, so we'll try to satisfy them from the reserved area + * if the general area is full. If we still can't satisfy the nofail + * allocation, we'll call prom_panic. + * + * This whole boot memory allocation thing needs some serious rethinking. + * + * Memory layout: + * + * |-------| top_bootmem + * | | } MAPPEDMEM_FULLTOP (only on non-serengeti, lw8) + * | | } MAPPEDMEM_MINTOP + * |-------| top_resvmem/scratchmemp + * | | } MAPPEDMEM_RESERVE + * |-------| scratchresvp + * | | } one page + * |-------| memlistpage (at roundup(_end, pagesize)) + * |-------| _end + * | boot | + * : : + * + */ + +#define MAPPEDMEM_RESERVE (512*1024) /* reserved for NOFAIL allocs */ + +#define MAPPEDMEM_MINTOP (caddr_t)(6*1024*1024) +#define MAPPEDMEM_FULLTOP (caddr_t)(10*1024*1024) + +static caddr_t top_bootmem = MAPPEDMEM_MINTOP; +static caddr_t top_resvmem, scratchresvp; + +static int +impl_name(char *buf, size_t bufsz) +{ + dnode_t n = prom_rootnode(); + size_t len = prom_getproplen(n, "name"); + + if (len == 0 || len >= bufsz) + return (-1); + + (void) prom_getprop(n, "name", buf); + buf[len] = '\0'; + + return (0); +} + +static caddr_t +vpage_from_freelist(size_t bytes) +{ + caddr_t v; + int i; + + /* find first region which fits */ + for (i = 0; i < N_FREELIST && free_size[i] < bytes; i++) + continue; + + if (i == N_FREELIST) { + dprintf("boot: failed to allocate %lu bytes from scratch " + "memory\n", bytes); + return (NULL); + } + + v = free_addr[i]; + free_addr[i] += bytes; + free_size[i] -= bytes; + dprintf("reuse freed temp scratch: bytes = %lu at %p\n", bytes, + (void *)v); + return (v); +} + +/* + * This routine will find the next PAGESIZE chunk in the + * low MAPPEDMEM_MINTOP. It is analogous to valloc(). It is only for boot + * scratch memory, because child scratch memory goes up in + * the the high memory. We just need to verify that the + * pages are on the list. The calling routine will actually + * remove them. + */ +static caddr_t +get_low_vpage(size_t numpages, enum RESOURCES type) +{ + size_t bytes; + caddr_t v; + + if (!numpages) + return (0); + + /* We know the page is mapped because the 1st MAPPEDMEM_MINTOP is 1:1 */ + bytes = numpages * pagesize; + if (scratchmemp + bytes <= top_bootmem) { + v = scratchmemp; + scratchmemp += bytes; + return (v); + } + + /* + * If we run out of scratch memory, look in the freelist + */ + if ((v = vpage_from_freelist(bytes)) != NULL) + return (v); + + /* + * Try really hard for allocations that can't fail. Look in the area + * that we've reserved for them. + */ + if (type == RES_BOOTSCRATCH_NOFAIL) { + if (scratchresvp + bytes <= top_resvmem) { + v = scratchresvp; + scratchresvp += bytes; + dprintf("using %lu bytes of reserved mem (%lu left)\n", + bytes, top_resvmem - scratchresvp); + return (v); + } else { + printf("boot: failed to allocate %lu bytes from " + "reserved scratch memory\n", bytes); + prom_panic("boot: scratch memory overflow.\n"); + } + } + + return (NULL); +} + +void +resalloc_init(void) +{ + char iarch[128]; + + if (impl_name(iarch, sizeof (iarch)) < 0) { + dprintf("boot: resalloc_init: failed to read iarch\n"); + return; + } + + dprintf("boot: resalloc_init: got iarch %s\n", iarch); + + /* + * Some versions of SG/LW8 firmware can actually handle the entire 10MB, + * but we don't have the ability to check for the firmware version here. + */ + if (strcmp(iarch, "SUNW,Sun-Fire") == 0 || + strcmp(iarch, "SUNW,Netra-T12") == 0) + return; + + top_bootmem = MAPPEDMEM_FULLTOP; + + dprintf("boot: resalloc_init: boosted top_bootmem to %p\n", + (void *)top_bootmem); +} + +caddr_t +resalloc(enum RESOURCES type, size_t bytes, caddr_t virthint, int align) +{ + caddr_t vaddr; + long pmap = 0; + + if (memlistpage == (caddr_t)0) + reset_alloc(); + + if (bytes == 0) + return ((caddr_t)0); + + /* extend request to fill a page */ + bytes = roundup(bytes, pagesize); + + dprintf("resalloc: bytes = %lu\n", bytes); + + switch (type) { + + /* + * even V2 PROMs never bother to indicate whether the + * first MAPPEDMEM_MINTOP is taken or not. So we do it all here. + * Smart PROM or no smart PROM. + */ + case RES_BOOTSCRATCH: + case RES_BOOTSCRATCH_NOFAIL: + vaddr = get_low_vpage((bytes/pagesize), type); + + if (resalloc_debug) { + dprintf("vaddr = %p, paddr = %lx\n", (void *)vaddr, + ptob(pmap)); + print_memlist(vfreelistp); + print_memlist(pfreelistp); + } + return (vaddr); + /*NOTREACHED*/ + + case RES_CHILDVIRT: + vaddr = (caddr_t)prom_alloc(virthint, bytes, align); + + if (vaddr == (caddr_t)virthint) + return (vaddr); + printf("Alloc of 0x%lx bytes at 0x%p refused.\n", + bytes, (void *)virthint); + return ((caddr_t)0); + /*NOTREACHED*/ + + default: + printf("Bad resurce type\n"); + return ((caddr_t)0); + } +} + +#ifdef lint +static char _end[1]; /* defined by the linker! */ +#endif /* lint */ + +void +reset_alloc(void) +{ + extern char _end[]; + + /* Cannot be called multiple times */ + if (memlistpage != (caddr_t)0) + return; + + /* + * Due to kernel history and ease of programming, we + * want to keep everything private to /boot BELOW MAPPEDMEM_MINTOP. + * In this way, the kernel can just snarf it all when + * when it is ready, and not worry about snarfing lists. + */ + memlistpage = (caddr_t)roundup((uintptr_t)_end, pagesize); + + /* + * This next is for scratch memory only + * We only need 1 page in memlistpage for now + */ + scratchresvp = (caddr_t)(memlistpage + pagesize); + scratchmemp = top_resvmem = scratchresvp + MAPPEDMEM_RESERVE; + le_page = (caddr_t)(scratchmemp + pagesize); + ie_page = (caddr_t)(le_page + pagesize); + + bzero(memlistpage, pagesize); + bzero(scratchmemp, pagesize); + dprintf("memlistpage = %p\n", (void *)memlistpage); + dprintf("le_page = %p\n", (void *)le_page); +} + +void +resfree(enum RESOURCES type, caddr_t virtaddr, size_t size) +{ + int i; + + /* make sure this is boot scratch memory */ + switch (type) { + case RES_BOOTSCRATCH: + if (virtaddr + size > top_bootmem) + return; + break; + default: + return; + } + + /* + * Add this to the end of the free list + * NOTE: This relies on the fact that KRTLD calls BOP_FREE + * from largest to smallest chunks. + */ + for (i = 0; i < N_FREELIST && free_size[i]; i++) + ; + if (i == N_FREELIST) + return; + free_size[i] = size; + free_addr[i] = virtaddr; +} diff --git a/usr/src/psm/stand/boot/sparc/common/ufsconf.c b/usr/src/psm/stand/boot/sparc/common/ufsconf.c new file mode 100644 index 0000000000..5d0195e5f3 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/ufsconf.c @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/obpdefs.h> +#include <sys/stat.h> +#include <sys/bootvfs.h> +#include <sys/bootdebug.h> +#include <sys/promif.h> +#include <sys/salib.h> +#include "boot_plat.h" + +/* + * filesystem switch table, UFS + */ +extern struct boot_fs_ops boot_ufs_ops; +struct boot_fs_ops *boot_fsw[] = { + &boot_ufs_ops, +}; + +int boot_nfsw = sizeof (boot_fsw) / sizeof (boot_fsw[0]); +int nfs_readsize = 0; + +static char *ufsname = "ufs"; + +/* ARGSUSED */ +char * +set_fstype(char *v2path, char *bpath) +{ + set_default_fs(ufsname); + return (ufsname); +} diff --git a/usr/src/psm/stand/boot/sparc/common/wanboot.c b/usr/src/psm/stand/boot/sparc/common/wanboot.c new file mode 100644 index 0000000000..b1f3ae836f --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/wanboot.c @@ -0,0 +1,1762 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +/* EXPORT DELETE START */ +#include <sys/promif.h> +#include <sys/obpdefs.h> +#include <sys/bootvfs.h> +#include <sys/bootconf.h> +#include <netinet/in.h> +#include <sys/wanboot_impl.h> +#include <boot_http.h> +#include <aes.h> +#include <des3.h> +#include <cbc.h> +#include <hmac_sha1.h> +#include <sys/sha1.h> +#include <sys/sha1_consts.h> +#include <bootlog.h> +#include <parseURL.h> +#include <netboot_paths.h> +#include <netinet/inetutil.h> +#include <sys/salib.h> +#include <inet/mac.h> +#include <inet/ipv4.h> +#include <dhcp_impl.h> +#include <inet/dhcpv4.h> +#include <bootinfo.h> +#include <wanboot_conf.h> +#include "boot_plat.h" +#include "ramdisk.h" +#include "wbcli.h" + +/* + * Types of downloads + */ +#define MINIINFO "miniinfo" +#define MINIROOT "miniroot" +#define WANBOOTFS "wanbootfs" + +#define WANBOOT_RETRY_NOMAX -1 +#define WANBOOT_RETRY_ROOT_MAX 50 +#define WANBOOT_RETRY_MAX 5 +#define WANBOOT_RETRY_SECS 5 +#define WANBOOT_RETRY_MAX_SECS 30 + +/* + * Our read requests should timeout after 25 seconds + */ +#define SOCKET_READ_TIMEOUT 25 + +/* + * Experimentation has shown that an 8K download buffer is optimal + */ +static char buffer[8192]; + +bc_handle_t bc_handle; + +extern int determine_fstype_and_mountroot(char *); +extern uint64_t get_ticks(void); + +/* + * The following is used to determine whether the certs and private key + * files will be in PEM format or PKCS12 format. 'use_p12' is zero + * to use PEM format, and 1 when PKCS12 format is to be used. It is + * done this way, as a global, so that it can be patched if needs be + * using the OBP debugger. + */ +uint32_t use_p12 = 1; + +#define CONTENT_LENGTH "Content-Length" + +#define NONCELEN (2 * HMAC_DIGEST_LEN) /* two hex nibbles/byte */ +#define WANBOOTFS_NONCE_FILE "/nonce" + +static char nonce[NONCELEN + 1]; + +enum URLtype { + URLtype_wanbootfs = 0, + URLtype_miniroot = 1 +}; + +static char *URLtoCGIcontent[] = { + "bootfs", + "rootfs" +}; +#define CGIcontent(urltype) URLtoCGIcontent[urltype] + +/* Encryption algorithms */ +typedef enum { + ENCR_NONE, + ENCR_3DES, + ENCR_AES +} encr_type_t; + +/* Hash algorithms */ +typedef enum { + HASH_NONE, + HASH_HMAC_SHA1 +} hash_type_t; + +/* + * Keys ... + */ +static encr_type_t encr_type = ENCR_NONE; +static unsigned char *g_encr_key = NULL; + +static hash_type_t hash_type = HASH_NONE; +static unsigned char *g_hash_key = NULL; + +void +print_errors(const char *func, http_handle_t handle) +{ + char const *msg; + ulong_t err; + uint_t src; + + while ((err = http_get_lasterr(handle, &src)) != 0) { + msg = http_errorstr(src, err); + bootlog("wanboot", BOOTLOG_ALERT, + "%s: errsrc %u, err %lu (0x%lx)", func, src, err, err); + bootlog("wanboot", BOOTLOG_ALERT, "%s", msg); + } +} + +/* + * This routine is called by a consumer to determine whether or not a + * retry should be attempted. If a retry is in order (depends upon the + * 'retry_cnt' and 'retry_max' arguments), then this routine will print a + * message indicating this is the case and will determine an appropriate + * "sleep" time before retrying. The "sleep" time will depend upon the + * 'retry_cnt' and will max out at WANBOOT_RETRY_MAX_SECS. + * + * Returns: + * B_TRUE = retry is in order + * B_FALSE = retry limit exceeded + */ +boolean_t +wanboot_retry(int retry_cnt, int retry_max) +{ + unsigned int seconds; + + if (retry_max == WANBOOT_RETRY_NOMAX || retry_cnt <= retry_max) { + seconds = WANBOOT_RETRY_SECS * retry_cnt; + if (seconds > WANBOOT_RETRY_MAX_SECS) { + seconds = WANBOOT_RETRY_MAX_SECS; + } + bootlog("wanboot", BOOTLOG_INFO, + "Will retry in %d seconds ...", seconds); + (void) sleep(seconds); + return (B_TRUE); + } else { + bootlog("wanboot", BOOTLOG_INFO, + "Maximum retries exceeded."); + return (B_FALSE); + } +} + +/* + * Determine which encryption algorithm the client is configured to use. + * WAN boot determines which key to use by order of priority. That is + * multiple encryption keys may exist in the PROM, but the first one found + * (while searching in a preferred order) is the one that will be used. + */ +static void +init_encryption(void) +{ + static unsigned char key[WANBOOT_MAXKEYLEN]; + size_t len = sizeof (key); + + if (bootinfo_get(BI_AES_KEY, (char *)&key, &len, NULL) == + BI_E_SUCCESS) { + encr_type = ENCR_AES; + g_encr_key = key; + } else if (bootinfo_get(BI_3DES_KEY, (char *)&key, &len, NULL) == + BI_E_SUCCESS) { + encr_type = ENCR_3DES; + g_encr_key = key; + } +} + +/* + * Determine whether the client is configured to use hashing. + */ +static void +init_hashing(void) +{ + static unsigned char key[WANBOOT_HMAC_KEY_SIZE]; + size_t len = sizeof (key); + + if (bootinfo_get(BI_SHA1_KEY, (char *)&key, &len, NULL) == + BI_E_SUCCESS) { + hash_type = HASH_HMAC_SHA1; + g_hash_key = key; + } +} + +/* + * Read some CPU-specific rapidly-varying data (assumed to be of length + * sizeof (hrtime_t) in the non-SPARC case), and digestify it to further + * randomize the output. + */ +char * +generate_nonce(void) +{ + uint64_t t; + SHA1_CTX c; + unsigned char digest[HMAC_DIGEST_LEN]; + uint_t nlen = sizeof (nonce); + + int err; + + /* + * Read SPARC %tick register or x86 TSC + */ + t = get_ticks(); + SHA1Init(&c); + SHA1Update(&c, (const uint8_t *)&t, sizeof (t)); + SHA1Final(digest, &c); + + err = octet_to_hexascii(digest, sizeof (digest), nonce, &nlen); + if (err != 0) { + bootlog("wanboot", BOOTLOG_CRIT, + "cannot convert nonce to ASCII: error %d", err); + return (NULL); + } + nonce[NONCELEN] = '\0'; + return (nonce); +} + +/* + * Given a server URL, builds a URL to request one of the wanboot + * datastreams. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + */ +static int +build_request_url(url_t *req_url, enum URLtype ut, const url_t *server_url) +{ + char clid[WB_MAX_CID_LEN]; + size_t clen; + char wid[WB_MAX_CID_LEN * 2 + 1]; + uint_t wlen; + struct in_addr ip; + struct in_addr mask; + char *netstr; + char *ppath; + size_t plen; + const char reqstr[] = "/?CONTENT=%s&IP=%s&CID=%s"; + + /* + * Initialize the request + */ + *req_url = *server_url; + + /* + * Build the network number string + */ + ipv4_getipaddr(&ip); + ipv4_getnetmask(&mask); + ip.s_addr = ip.s_addr & mask.s_addr; + netstr = inet_ntoa(ip); + + /* + * Get the wan id + */ + clen = sizeof (clid); + if (bootinfo_get(BI_CLIENT_ID, clid, &clen, NULL) != BI_E_SUCCESS) { + bootlog("wanboot", BOOTLOG_CRIT, + "Cannot retrieve the client ID"); + return (-1); + } + wlen = sizeof (wid); + (void) octet_to_hexascii(clid, clen, wid, &wlen); + + /* + * Build the request, making sure that the length of the + * constructed URL falls within the supported maximum. + */ + plen = strlen(req_url->abspath); + ppath = req_url->abspath + plen; + if (snprintf(ppath, URL_MAX_PATHLEN - plen, reqstr, + CGIcontent(ut), netstr, wid) >= URL_MAX_PATHLEN - plen) { + bootlog("wanboot", BOOTLOG_CRIT, + "The URL path length of the %s request is greater than " + "the maximum of %d", CGIcontent(ut), URL_MAX_PATHLEN); + return (-1); + } + + /* + * If the URL type requires a nonce, then supply it. + * It will be returned in the reply to detect attempted + * replays. + */ + if (ut == URLtype_wanbootfs) { + char *n = generate_nonce(); + + if (n != NULL) { + plen += strlen("&NONCE=") + NONCELEN; + if (plen > URL_MAX_PATHLEN) + return (-1); + (void) strcat(req_url->abspath, "&NONCE="); + (void) strcat(req_url->abspath, n); + } + } + + return (0); +} + +/* + * This routine reads data from an HTTP connection into a buffer. + * + * Returns: + * 0 = Success + * 1 = HTTP download error + */ +static int +read_bytes(http_handle_t handle, char *buffer, size_t cnt) +{ + int len; + size_t i; + + for (i = 0; i < cnt; i += len) { + len = http_read_body(handle, &buffer[i], cnt - i); + if (len <= 0) { + print_errors("http_read_body", handle); + return (1); + } + } + return (0); +} + +/* + * This routine compares two hash digests, one computed by the server and + * the other computed by the client to verify that a transmitted message + * was received without corruption. + * + * Notes: + * The client only computes a digest if it is configured with a + * hash key. If it is not, then the server should not have a hash + * key for the client either and therefore should have sent a + * zero filled digest. + * + * Returns: + * B_TRUE = digest was verified + * B_FALSE = digest did not verify + */ +static boolean_t +verify_digests(const char *what, unsigned char *cdigest, unsigned char *sdigest) +{ + static char null_digest[HMAC_DIGEST_LEN]; + + if (bcmp(sdigest, cdigest, HMAC_DIGEST_LEN) != 0) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: invalid hash digest", what); + bootlog("wanboot", BOOTLOG_CRIT, + "This may signify a client/server key mismatch"); + if (bcmp(sdigest, null_digest, HMAC_DIGEST_LEN) == 0) { + bootlog("wanboot", BOOTLOG_CRIT, + "(client has key but wrong signature_type?)"); + } else if (bcmp(cdigest, null_digest, HMAC_DIGEST_LEN) == 0) { + bootlog("wanboot", BOOTLOG_CRIT, + "(signature_type specified but no client key?)"); + } + bootlog("wanboot", BOOTLOG_CRIT, + "or possible corruption of the image in transit"); + return (B_FALSE); + } + + return (B_TRUE); +} + +/* + * This routine reads the part of a multipart message that contains a + * hash digest. Errors in reading the digest are differentiated from + * other kinds of errors so that the caller can decide whether or + * not a retry is worthwhile. + * + * Note: + * The hash digest can either be an HMAC digest or it can be + * a zero length message (representing no hash digest). + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = HTTP download error + */ +static int +read_digest(const char *what, http_handle_t handle, unsigned char *sdigest) +{ + char *lenstr; + size_t digest_size; + + /* + * Process the HMAC digest header. + */ + if (http_process_part_headers(handle, NULL) != 0) { + print_errors("http_process_part_headers", handle); + return (1); + } + lenstr = http_get_header_value(handle, CONTENT_LENGTH); + if (lenstr == NULL) { + bootlog("wanboot", BOOTLOG_ALERT, + "%s: error getting digest length", what); + return (1); + } + digest_size = (size_t)strtol(lenstr, NULL, 10); + free(lenstr); + + /* + * Validate the HMAC digest length. + */ + if (digest_size != HMAC_DIGEST_LEN) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: error validating response - invalid digest size", + what); + return (-1); + } + + /* + * Read the HMAC digest. + */ + if (read_bytes(handle, (char *)sdigest, digest_size) != 0) { + bootlog("wanboot", BOOTLOG_ALERT, + "%s: error reading digest", what); + return (1); + } + + return (0); +} + +/* + * This routine reads data from an HTTP connection and writes the data + * to a ramdisk. It also, optionally computes a hash digest of the processed + * data. This routine may be called to continue writing a previously aborted + * write. If this is the case, then the offset will be non-zero and the write + * pointer into the ramdisk will be positioned correctly by the caller. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = HTTP download error + */ +static int +write_msg_to_ramdisk(const char *what, int fd, http_handle_t handle, + size_t ramdisk_size, off_t *offset, SHA1_CTX *sha) +{ + int len; + long nleft; + static int bootlog_message_interval; + static int bootlog_progress; + int ret; + + /* + * Read the data and write it to the ramdisk. + */ + if (*offset == 0) { + bootlog_progress = 0; + bootlog_message_interval = ramdisk_size / sizeof (buffer); + if (bootlog_message_interval < 500) + bootlog_message_interval /= 5; + else + bootlog_message_interval /= 50; + + bootlog("wanboot", BOOTLOG_VERBOSE, + "Reading %s file system (%ld kB)", + what, ramdisk_size / 1024); + } else { + bootlog("wanboot", BOOTLOG_VERBOSE, + "Continuing read of %s file system (%ld kB)", + what, ramdisk_size / 1024); + } + for (ret = 0; ret == 0 && *offset < ramdisk_size; *offset += len) { + nleft = ramdisk_size - *offset; + + if (nleft > sizeof (buffer)) + nleft = sizeof (buffer); + + len = http_read_body(handle, buffer, nleft); + if (len <= 0) { + print_errors("http_read_body", handle); + /* + * In the case of a partial failure, http_read_body() + * returns into 'len', 1 - the number of bytes read. + * So, a -65 means 64 bytes read and an error occurred. + */ + if (len != 0) { + len = -(len + 1); + } + ret = 1; + } + if (sha != NULL) { + HMACUpdate(sha, (uchar_t *)buffer, (size_t)len); + } + if (prom_write(fd, buffer, (size_t)len, 0, 0) != (ssize_t)len) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: write to ramdisk failed", what); + ret = -1; + continue; + } + if (bootlog_progress == bootlog_message_interval) { + bootlog("wanboot", BOOTLOG_PROGRESS, + "%s: Read %ld of %ld kB (%ld%%)", what, + *offset / 1024, ramdisk_size / 1024, + *offset * 100 / ramdisk_size); + bootlog_progress = 0; + } else { + bootlog_progress++; + } + } + if (ret == 0) { + bootlog("wanboot", BOOTLOG_PROGRESS, + "%s: Read %ld of %ld kB (%ld%%)", what, + *offset / 1024, ramdisk_size / 1024, + *offset * 100 / ramdisk_size); + bootlog("wanboot", BOOTLOG_INFO, "%s: Download complete", what); + } + return (ret); +} + +/* + * This routine is called with a bootinfo parameter name. If the parameter + * has a value it should be a URL, and this will be used to initialize the + * http_url structure. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = DHCP option not set + */ +static int +get_url(char *name, url_t *url) +{ + char buf[URL_MAX_STRLEN]; + size_t len; + int ret; + + bzero(buf, sizeof (buf)); + len = sizeof (buf) - 1; + if (bootinfo_get(name, buf, &len, NULL) != BI_E_SUCCESS || len == 0) { + return (1); + } + + /* + * Parse the URL. + */ + ret = url_parse(buf, url); + if (ret != URL_PARSE_SUCCESS) { + bootlog("wanboot", BOOTLOG_CRIT, + "Unable to parse URL %s", buf); + return (-1); + } + + return (0); +} + +/* + * This routine initiates an HTTP request and returns a handle so that + * the caller can process the response. + * + * Notes: + * Requests may be either secure or not. If the request is secure, then + * this routine assumes that a wanboot file system exists and + * uses its contents to provide the HTTP library with the information + * that will be required by SSL. + * + * In order to facilitate transmission retries, this routine supports + * range requests. A caller may request a range by providing a non-zero + * offset. In which case, a range request is made that ranges from the + * offet to the end of the file. + * + * If the client is configured to use an HTTP proxy, then this routine + * will make the HTTP library aware of the proxy. + * + * Any HTTP errors encountered in downloading or processing the message + * are not deemed unrecoverable errors. The caller can simply try the + * request once again. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = HTTP download error + */ +static int +establish_http_connection(const char *what, http_handle_t *handlep, + url_t *url, off_t offset) +{ + static boolean_t is_auth_file_init = B_FALSE; + static boolean_t is_proxy_init = B_FALSE; + static boolean_t proxy_exists = B_FALSE; + static url_hport_t proxy_hp; + http_respinfo_t *resp; + char buf[URL_MAX_STRLEN]; + size_t len = sizeof (buf) - 1; + int ret; + + /* Check for HTTP proxy */ + if (!is_proxy_init && + bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == BI_E_SUCCESS && + strlen(buf) > 0) { + /* + * Parse the hostport. + */ + ret = url_parse_hostport(buf, &proxy_hp, URL_DFLT_PROXY_PORT); + if (ret == URL_PARSE_SUCCESS) { + proxy_exists = B_TRUE; + } else { + bootlog("wanboot", BOOTLOG_CRIT, + "%s is not set to a valid hostport value", + BI_HTTP_PROXY); + return (-1); + } + is_proxy_init = B_TRUE; + } + + http_set_p12_format(use_p12); + + /* + * Initialize the handle that will be used for the request. + */ + *handlep = http_srv_init(url); + if (*handlep == NULL) { + print_errors("http_srv_init", NULL); + return (-1); + } + + /* + * Is the request a secure one? If it is, then we need to do further + * setup. Search the wanboot file system for files that will be + * needed by SSL. + */ + if (url->https) { + char *cas; + boolean_t client_authentication = B_FALSE; + + if (http_set_random_file(*handlep, "/dev/urandom") < 0) { + print_errors("http_set_random_file", *handlep); + (void) http_srv_close(*handlep); + return (-1); + } + + /* + * We only need to initialize the CA once as it is not handle + * specific. + */ + if (!is_auth_file_init) { + if (http_set_certificate_authority_file(NB_CA_CERT_PATH) + < 0) { + print_errors( + "http_set_certificate_authority_file", + *handlep); + (void) http_srv_close(*handlep); + return (-1); + } + + is_auth_file_init = B_TRUE; + } + + /* + * The client certificate and key will not exist unless + * client authentication has been configured. If it is + * configured then the webserver will have added these + * files to the wanboot file system and the HTTP library + * needs to be made aware of their existence. + */ + if ((cas = bootconf_get(&bc_handle, + BC_CLIENT_AUTHENTICATION)) != NULL && + strcmp(cas, "yes") == 0) { + client_authentication = B_TRUE; + + if (http_set_client_certificate_file(*handlep, + NB_CLIENT_CERT_PATH) < 0) { + print_errors("http_set_client_certificate_file", + *handlep); + (void) http_srv_close(*handlep); + return (-1); + } + + if (http_set_private_key_file(*handlep, + NB_CLIENT_KEY_PATH) < 0) { + print_errors("http_set_private_key_file", + *handlep); + (void) http_srv_close(*handlep); + return (-1); + } + } + + /* + * We do not really need to set this unless client + * authentication is configured or unless pkcs12 files + * are used. + */ + if ((client_authentication || use_p12) && + http_set_password(*handlep, WANBOOT_PASSPHRASE) < 0) { + print_errors("http_set_password", *handlep); + (void) http_srv_close(*handlep); + return (-1); + } + } + + /* + * If the client is using a proxy, tell the library. + */ + if (proxy_exists) { + if (http_set_proxy(*handlep, &proxy_hp) != 0) { + print_errors("http_set_proxy", *handlep); + (void) http_srv_close(*handlep); + return (-1); + } + } + + (void) http_set_socket_read_timeout(*handlep, SOCKET_READ_TIMEOUT); + + /* + * Ok, connect to the webserver. + */ + if (http_srv_connect(*handlep) == -1) { + print_errors("http_srv_connect", *handlep); + (void) http_srv_close(*handlep); + return (1); + } + + /* + * If the offset is 0, then we assume that we want the entire + * message. If the offset is not 0, then we assume that we are + * retrying a previously interrupted transfer and thus we make + * a range request. + */ + if (offset == 0) { + if ((ret = http_get_request(*handlep, url->abspath)) == 0) { + bootlog("wanboot", BOOTLOG_VERBOSE, + "%s: http_get_request: sent", what); + } else { + print_errors("http_get_request", *handlep); + (void) http_srv_close(*handlep); + return (1); + } + } else { + if ((ret = http_get_range_request(*handlep, url->abspath, + offset, 0)) == 0) { + bootlog("wanboot", BOOTLOG_VERBOSE, + "%s: http_get_range_request: sent", what); + } else { + print_errors("http_get_range_request", *handlep); + (void) http_srv_close(*handlep); + return (1); + } + } + + /* + * Tell the library to read in the response headers. + */ + ret = http_process_headers(*handlep, &resp); + if (ret == -1) { + print_errors("http_process_headers", *handlep); + (void) http_srv_close(*handlep); + return (1); + } + + /* + * Check for a valid response code. + */ + if ((offset == 0 && resp->code != 200) || + (offset != 0 && resp->code != 206)) { + bootlog("wanboot", BOOTLOG_ALERT, + "%s: Request returned code %d", what, resp->code); + if (resp->statusmsg != NULL && resp->statusmsg[0] != '\0') + bootlog("wanboot", BOOTLOG_ALERT, + "%s", resp->statusmsg); + http_free_respinfo(resp); + (void) http_srv_close(*handlep); + return (1); + } + http_free_respinfo(resp); + + /* + * Success. + */ + return (0); +} + +/* + * This routine is called by get_miniinfo() to receive the reply + * to the request for the miniroot metadata. The reply is a two + * part multipart message. The first part of the message contains + * the miniroot file size. The second part of the message contains + * a hash digest of the miniroot as computed by the server. This + * routine receives both message parts and returns them to the caller. + * + * Notes: + * If the miniroot is going to be downloaded securely or if the + * the server has no hash key for the client, then the hash digest + * downloaded contains all zeros. + * + * Any HTTP errors encountered in downloading or processing the message + * are not deemed unrecoverable errors. That is, get_miniinfo() + * tries re-requesting the message and tries processing it again. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = HTTP download error + */ +static int +process_miniinfo(http_handle_t handle, size_t *mini_size, + unsigned char *sdigest) +{ + char *lenstr; + size_t cnt; + + /* + * Process the file size header. + */ + if (http_process_part_headers(handle, NULL) != 0) { + print_errors("http_process_part_headers", handle); + return (1); + } + lenstr = http_get_header_value(handle, CONTENT_LENGTH); + if (lenstr == NULL) { + bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length " + "of first part of multipart message", MINIINFO); + return (1); + } + cnt = (size_t)strtol(lenstr, NULL, 10); + free(lenstr); + if (cnt == 0 || cnt >= sizeof (buffer)) { + bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part " + "of multipart message not a legal size", MINIINFO); + return (1); + } + + if (read_bytes(handle, buffer, cnt) != 0) { + bootlog("wanboot", BOOTLOG_ALERT, + "%s: error reading miniroot size", MINIINFO); + return (1); + } + buffer[cnt] = '\0'; + + *mini_size = (size_t)strtol(buffer, NULL, 10); + if (*mini_size == 0) { + bootlog("wanboot", BOOTLOG_ALERT, "%s: body of first part " + "of multipart message not a legal size", MINIINFO); + return (1); + } + + return (read_digest(MINIINFO, handle, sdigest)); +} + +/* + * This routine is called by get_miniroot() to retrieve the miniroot + * metadata (miniroot size and a hash digest). This routine sends an + * HTTP GET request to the webserver to request the download of the + * miniroot metadata and relies on process_miniinfo() to receive the + * reply, process it and ultimately return to it the miniroot size and + * the hash digest. + * + * Note: + * Any HTTP errors encountered in downloading or processing the message + * are not deemed unrecoverable errors. That is, get_miniinfo() should + * try re-requesting the message and try processing again. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + */ +int +get_miniinfo(const url_t *server_url, size_t *mini_size, + unsigned char *sdigest) +{ + http_handle_t handle; + url_t req_url; + int retry_cnt = 0; + int retry_max = WANBOOT_RETRY_MAX; + int ret; + + /* + * Build the URL to request the miniroot info. + */ + if (build_request_url(&req_url, URLtype_miniroot, server_url) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "Can't build the URL to make the %s request", + CGIcontent(URLtype_miniroot)); + return (-1); + } + + /* + * Go get the miniroot info. If we fail reading the + * response we re-request the info in its entirety. + */ + bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot info"); + + do { + if ((ret = establish_http_connection(MINIINFO, &handle, + &req_url, 0)) < 0) { + break; + } else if (ret > 0) { + if (wanboot_retry(++retry_cnt, retry_max)) { + continue; + } else { + break; + } + } + + if ((ret = process_miniinfo(handle, mini_size, + sdigest)) > 0) { + if (!wanboot_retry(++retry_cnt, retry_max)) { + (void) http_srv_close(handle); + break; + } + } + + (void) http_srv_close(handle); + + } while (ret > 0); + + /* + * Success. + */ + if (ret == 0) { + bootlog("wanboot", BOOTLOG_VERBOSE, + "Miniroot info download successful"); + return (0); + } else { + bootlog("wanboot", BOOTLOG_CRIT, + "Miniroot info download aborted"); + return (-1); + } +} + +/* + * This routine is called by get_miniroot() to receive the reply to + * the request for the miniroot download. The miniroot is written + * to ramdisk as it is received and a hash digest is optionally computed + * as it does so. The miniroot is downloaded as one large message. + * Because the message is so large, this routine is prepared to deal + * with errors in the middle of download. If an error occurs during + * download, then this message processes all received data up to the + * point of the error and returns to get_miniroot() an error signifying + * that a download error has occurred. Presumably, get_miniroot() + * re-requests the remaining part of the miniroot not yet processed and + * calls this routine back to process the reply. When this routine + * returns succesfully, it returns a devpath to the ramdisk and the + * computed hash (if computed). + * + * Note: + * In order to facilitate reentry, the ramdisk is left open + * and the original miniroot_size and HMAC handle are kept + * static. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = HTTP download error + */ +static int +process_miniroot(http_handle_t handle, hash_type_t htype, + size_t length, char **devpath, off_t *offset, unsigned char *cdigest) +{ + static SHA1_CTX sha; + static size_t miniroot_size; + static int fd = -1; + int ret; + + if (fd == -1) { + if (htype == HASH_HMAC_SHA1) { + bootlog("wanboot", BOOTLOG_INFO, + "%s: Authentication will use HMAC-SHA1", MINIROOT); + HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE); + } + + miniroot_size = length; + + fd = create_ramdisk(RD_ROOTFS, miniroot_size, devpath); + } + + if (prom_seek(fd, *offset) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: prom_seek error", MINIROOT); + return (-1); + } + + if ((ret = write_msg_to_ramdisk(MINIROOT, fd, handle, miniroot_size, + offset, (htype == HASH_NONE) ? NULL : &sha)) != 0) { + if (ret < 0) { + /* + * Reentry not supported. + */ + (void) prom_close(fd); + } + return (ret); + } + + if (htype != HASH_NONE) { + HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest); + } + + (void) prom_close(fd); + + return (0); +} + +/* + * This routine retrieves the miniroot from the webserver. The miniroot + * is retrieved in two steps. First a request is made to the server + * to retrieve miniroot metadata (miniroot size and a hash digest). + * The second request actually results in the download of the miniroot. + * + * This routine relies on get_miniinfo() to make and process + * the request for the miniroot metadata and returns the + * miniroot size and the hash digest of the miniroot as computed by + * the server. + * + * If get_miniinfo() returns successfully, then this routine sends + * an HTTP GET request to the webserver to request download of the + * miniroot. This routine relies on process_miniroot() to receive + * the reply, process it and ultimately return to it a device path to + * a ramdisk containing the miniroot and a client computed hash digest. + * This routine verifies that the client computed hash digest matches + * the one retrieved by get_miniinfo(). + * + * If an error occurs in the transfer of the miniroot from the server + * to the client, then the client re-requests the download of the + * miniroot using a range request and only requests the part of the + * miniroot not previously downloaded and written to ramdisk. The + * process_miniroot() routine has the intelligence to recognize that + * it is processing a range request. Errors not related to the actual + * message download are deemed unrecoverable. + * + * Note: + * If the client request for the miniroot is a secure request or + * if the server is not configured with a hash key for the client, + * then the hash digest downloaded from the server will contain + * all zeros. This routine verifies that the server and client are + * in-sync with respect to the need for hash verification. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + */ +int +get_miniroot(char **devpath) +{ + http_handle_t handle; + unsigned char cdigest[HMAC_DIGEST_LEN]; + unsigned char sdigest[HMAC_DIGEST_LEN]; + char *urlstr; + url_t server_url; + size_t mini_size; + off_t offset; + int plen; + int retry_cnt = 0; + int retry_max = WANBOOT_RETRY_ROOT_MAX; + int ret; + + /* + * Get the miniroot URL. + */ + if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) { + bootlog("wanboot", BOOTLOG_CRIT, + "Missing root_server URL"); + return (-1); + } else if (url_parse(urlstr, &server_url) != URL_PARSE_SUCCESS) { + bootlog("wanboot", BOOTLOG_CRIT, + "Unable to parse URL %s", urlstr); + return (-1); + } + + /* + * We must get the miniroot info before we can request + * the miniroot itself. + */ + if (get_miniinfo(&server_url, &mini_size, sdigest) != 0) { + return (-1); + } + + plen = sizeof (server_url.abspath); + if ((urlstr = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL || + strlcpy(server_url.abspath, urlstr, plen) >= plen) { + bootlog("wanboot", BOOTLOG_CRIT, + "Cannot retrieve the miniroot path"); + return (-1); + } + + /* + * Go get the miniroot. If we fail reading the response + * then we re-request only the range we have yet to read, + * unless the error was "unrecoverable" in which case we + * re-request the entire file system. + */ + bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading miniroot"); + + bzero(cdigest, sizeof (cdigest)); + offset = 0; + do { + if ((ret = establish_http_connection(MINIROOT, &handle, + &server_url, offset)) < 0) { + break; + } else if (ret > 0) { + if (wanboot_retry(++retry_cnt, retry_max)) { + continue; + } else { + break; + } + } + + if ((ret = process_miniroot(handle, + server_url.https ? HASH_NONE : hash_type, + mini_size, devpath, &offset, cdigest)) > 0) { + if (!wanboot_retry(++retry_cnt, retry_max)) { + (void) http_srv_close(handle); + break; + } + } + + (void) http_srv_close(handle); + + } while (ret > 0); + + /* + * Validate the computed digest against the one received. + */ + if (ret != 0 || !verify_digests(MINIROOT, cdigest, sdigest)) { + bootlog("wanboot", BOOTLOG_CRIT, + "Miniroot download aborted"); + return (-1); + } + + bootlog("wanboot", BOOTLOG_VERBOSE, "Miniroot download successful"); + return (0); +} + +/* + * This routine is called to finish the decryption process. + * Its purpose is to free the resources allocated by the + * encryption init routines. + */ +static void +encr_fini(encr_type_t etype, void *eh) +{ + switch (etype) { + case ENCR_3DES: + des3_fini(eh); + break; + case ENCR_AES: + aes_fini(eh); + break; + default: + break; + } +} + +/* + * This routine is called by process_wanbootfs() to read the encrypted + * file system from ramdisk and decrypt it. This routine will rewrite + * the file system back to ramdisk in place. The method of decryption + * (algorithm) will have already been determined by process_wanbootfs() + * and the cbc_handle passed to this routine will already have been + * initialized appropriately. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + */ +static int +decrypt_wanbootfs(int fd, cbc_handle_t *ch, uint8_t *iv, + size_t block_size, size_t wanbootfs_size) +{ + size_t total; + size_t len; + size_t nleft; + size_t max_read_size; + + max_read_size = (sizeof (buffer) / block_size) * block_size; + for (total = 0; total < wanbootfs_size; total += len) { + if (prom_seek(fd, total) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: prom_seek error", WANBOOTFS); + return (-1); + } + nleft = wanbootfs_size - total; + if (nleft > max_read_size) + nleft = max_read_size; + len = prom_read(fd, buffer, nleft, 0, 0); + if (len != nleft) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: prom_read error", WANBOOTFS); + return (-1); + } + if (!cbc_decrypt(ch, (uint8_t *)buffer, len, iv)) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: cbc decrypt error", WANBOOTFS); + return (-1); + } + if (prom_seek(fd, total) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: prom_seek error", WANBOOTFS); + return (-1); + } + if (prom_write(fd, buffer, len, 0, 0) != len) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: prom_write error", WANBOOTFS); + return (-1); + } + } + return (0); +} + +/* + * This routine is called by get_wanbootfs() to receive the reply to + * the request for the wanboot file system. The reply is a multipart message. + * The first part of the message is the file system (which may or may + * not be encrypted). If encrypted, then the first block of the message + * part is the CBC IV value used by the server to encrypt the remaining + * part of the message part and is used by the client to decrypt it. The + * second message part is a hash digest of the first part (the file + * system) as computed by the server. If no hash key is configured + * for the client, then the hash digest simply contains all zeros. This + * routine receives both message parts. The file system is written to ramdisk + * as it is received and simultaneously computes a hash digest (if a hash + * key exists). Once the entire part is received, if the file system is + * encrypted, it is read from ramdisk, decrypted and rewritten back to + * ramdisk. The server computed hash digest is then read and along with the + * ramdisk device path and the client computed hash digest is returned to the + * caller. + * + * Notes: + * In order to decrypt the file system and to compute the client + * hash digest, an encryption key and a hash key is retrieved from + * the PROM (or the wanboot interpreter). The non-existence of these + * keys has implications on how the message response is processed and + * it is assumed that the server is configured identically. + * + * Any HTTP errors encountered in downloading or processing the message + * are not deemed unrecoverable errors. That is, get_wanbootfs() will + * try re-requesting the message and will try processing it again. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + * 1 = HTTP download error + */ +static int +process_wanbootfs(http_handle_t handle, char **devpath, + unsigned char *cdigest, unsigned char *sdigest) +{ + /* iv[] must be sized to store the largest possible encryption block */ + uint8_t iv[WANBOOT_MAXBLOCKLEN]; + cbc_handle_t ch; + void *eh; + SHA1_CTX sha; + char *lenstr; + size_t wanbootfs_size; + size_t block_size; + off_t offset; + static int fd = -1; + int ret; + + switch (hash_type) { + case HASH_HMAC_SHA1: + bootlog("wanboot", BOOTLOG_INFO, + "%s: Authentication will use HMAC-SHA1", WANBOOTFS); + HMACInit(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE); + break; + case HASH_NONE: + break; + default: + bootlog("wanboot", BOOTLOG_CRIT, + "%s: unrecognized hash type", WANBOOTFS); + return (-1); + } + + switch (encr_type) { + case ENCR_3DES: + bootlog("wanboot", + BOOTLOG_INFO, "%s: Decryption will use 3DES", WANBOOTFS); + if (des3_init(&eh) != 0) { + return (-1); + } + block_size = DES3_BLOCK_SIZE; + des3_key(eh, g_encr_key); + cbc_makehandle(&ch, eh, DES3_KEY_SIZE, block_size, + DES3_IV_SIZE, des3_encrypt, des3_decrypt); + + break; + case ENCR_AES: + bootlog("wanboot", + BOOTLOG_INFO, "%s: Decryption will use AES", WANBOOTFS); + if (aes_init(&eh) != 0) { + return (-1); + } + block_size = AES_BLOCK_SIZE; + aes_key(eh, g_encr_key, AES_128_KEY_SIZE); + cbc_makehandle(&ch, eh, AES_128_KEY_SIZE, block_size, + AES_IV_SIZE, aes_encrypt, aes_decrypt); + break; + case ENCR_NONE: + break; + default: + bootlog("wanboot", BOOTLOG_CRIT, + "%s: unrecognized encryption type", WANBOOTFS); + return (-1); + } + + /* + * Process the header. + */ + if (http_process_part_headers(handle, NULL) != 0) { + print_errors("http_process_part_headers", handle); + return (1); + } + lenstr = http_get_header_value(handle, CONTENT_LENGTH); + if (lenstr == NULL) { + bootlog("wanboot", BOOTLOG_ALERT, "%s: error getting length " + "of first part of multipart message", WANBOOTFS); + return (1); + } + wanbootfs_size = (size_t)strtol(lenstr, NULL, 10); + free(lenstr); + if (wanbootfs_size == 0) { + bootlog("wanboot", BOOTLOG_ALERT, "%s: length of first part " + "of multipart message not a legal size", WANBOOTFS); + return (1); + } + + /* + * If encrypted, then read the iv. + */ + if (encr_type != ENCR_NONE) { + if (read_bytes(handle, (char *)iv, block_size) != 0) { + bootlog("wanboot", BOOTLOG_ALERT, + "%s: error reading hash iv", WANBOOTFS); + return (1); + } + wanbootfs_size -= block_size; + if (hash_type != HASH_NONE) { + HMACUpdate(&sha, (uchar_t *)iv, block_size); + } + } + + /* + * We can only create the ramdisk once. So, if we've + * already created it, then it means we've re-entered + * this routine from an earlier partial failure. Use + * the already existing ramdisk and seek back to the + * beginning of the file. + */ + if (fd == -1) { + fd = create_ramdisk(RD_BOOTFS, wanbootfs_size, devpath); + } + + offset = 0; + if (prom_seek(fd, offset) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "%s: prom_seek error", WANBOOTFS); + return (-1); + } + + if ((ret = write_msg_to_ramdisk(WANBOOTFS, fd, handle, wanbootfs_size, + &offset, (hash_type == HASH_NONE) ? NULL : &sha)) != 0) { + if (ret < 0) { + /* + * Reentry not supported. + */ + (void) prom_close(fd); + } + return (ret); + } + + if (hash_type != HASH_NONE) { + HMACFinal(&sha, g_hash_key, WANBOOT_HMAC_KEY_SIZE, cdigest); + } + + /* + * If encrypted, then decrypt it. + */ + if (encr_type != ENCR_NONE) { + ret = decrypt_wanbootfs(fd, &ch, iv, block_size, + wanbootfs_size); + if (ret != 0) { + encr_fini(encr_type, eh); + (void) prom_close(fd); + return (-1); + } + encr_fini(encr_type, eh); + } + + (void) prom_close(fd); + + return (read_digest(WANBOOTFS, handle, sdigest)); +} + +/* + * This routine sends an HTTP GET request to the webserver to + * request the wanboot file system for the client. The server + * will reply by sending a multipart message. This routine will rely + * on process_wanbootfs() to receive the multipart message, process it + * and ultimately return to it a device path to a ramdisk containing + * the wanboot file system, a client computed hash digest and a + * server computed hash digest. This routine will verify that the + * client computed hash digest matches the one sent by the server. This + * routine will also verify that the nonce received in the reply matches + * the one sent in the request. + * + * If an error occurs in the transfer of the message from the server + * to the client, then the client re-requests the download in its + * entirety. Errors not related to the actual message download are + * deemed unrecoverable. + * + * Returns: + * -1 = Non-recoverable error + * 0 = Success + */ +int +get_wanbootfs(const url_t *server_url) +{ + http_handle_t handle; + unsigned char cdigest[HMAC_DIGEST_LEN]; + unsigned char sdigest[HMAC_DIGEST_LEN]; + url_t req_url; + char *devpath; + int ret; + int fd; + char buf[NONCELEN + 1]; + int retry_cnt = 0; + int retry_max = WANBOOT_RETRY_MAX; + + /* + * Build the URL to request the wanboot file system. This URL + * will include the CGI script name and the IP, CID, and + * NONCE parameters. + */ + if (build_request_url(&req_url, URLtype_wanbootfs, server_url) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "Can't build the URL to make the %s request", + CGIcontent(URLtype_wanbootfs)); + return (-1); + } + + /* + * Go get the wanboot file system. If we fail reading the + * response we re-request the entire file system. + */ + bootlog("wanboot", BOOTLOG_VERBOSE, "Downloading wanboot file system"); + + bzero(cdigest, sizeof (cdigest)); + do { + if ((ret = establish_http_connection(WANBOOTFS, &handle, + &req_url, 0)) < 0) { + break; + } else if (ret > 0) { + if (wanboot_retry(++retry_cnt, retry_max)) { + continue; + } else { + break; + } + } + + if ((ret = process_wanbootfs(handle, &devpath, + cdigest, sdigest)) > 0) { + if (!wanboot_retry(++retry_cnt, retry_max)) { + (void) http_srv_close(handle); + break; + } + } + + (void) http_srv_close(handle); + + } while (ret > 0); + + /* + * Validate the computed digest against the one received. + */ + if (ret != 0 || + !verify_digests(WANBOOTFS, cdigest, sdigest)) { + bootlog("wanboot", BOOTLOG_CRIT, + "The wanboot file system download aborted"); + return (-1); + } + + /* + * Mount the wanboot file system. + */ + if (determine_fstype_and_mountroot(devpath) != VFS_SUCCESS) { + bootlog("wanboot", BOOTLOG_CRIT, + "Could not mount the wanboot filesystem."); + bootlog("wanboot", BOOTLOG_CRIT, + "This may signify a client/server key mismatch"); + if (encr_type != ENCR_NONE) { + bootlog("wanboot", BOOTLOG_CRIT, + "(client has key but wrong encryption_type?)"); + } else { + bootlog("wanboot", BOOTLOG_CRIT, + "(encryption_type specified but no client key?)"); + } + return (-1); + } + bootlog("wanboot", BOOTLOG_VERBOSE, + "The wanboot file system has been mounted"); + + /* + * The wanboot file system should contain a nonce. Read it + * and compare it against the nonce sent in the request. + */ + if ((fd = open(WANBOOTFS_NONCE_FILE, O_RDONLY)) == -1) { + bootlog("wanboot", BOOTLOG_CRIT, + "No nonce found in the wanboot file system"); + bootlog("wanboot", BOOTLOG_CRIT, + "The wanboot file system download aborted"); + return (-1); + } + + if (read(fd, buf, NONCELEN) != NONCELEN || + bcmp(nonce, buf, NONCELEN) != 0) { + (void) close(fd); + bootlog("wanboot", BOOTLOG_CRIT, + "Invalid nonce found in the wanboot file system"); + bootlog("wanboot", BOOTLOG_CRIT, + "The wanboot file system download aborted"); + return (-1); + } + + (void) close(fd); + + bootlog("wanboot", BOOTLOG_VERBOSE, + "The wanboot file system download was successful"); + return (0); +} + +static boolean_t +init_netdev(char *bpath) +{ + dnode_t anode; + int proplen; + static char netalias[OBP_MAXPATHLEN]; + + /* + * Wanboot will either have loaded over the network (in which case + * bpath will name a network device), or from CD-ROM or disk. In + * both cases ensure that the 'net' alias corresponds to a network + * device, and that if a network boot was performed that it is + * identical to bpath. This is so that the interface name can always + * be determined for CD-ROM or disk boots, and for manually-configured + * network boots. The latter restriction may be relaxed in the future. + */ + anode = prom_alias_node(); + if ((proplen = prom_getproplen(anode, "net")) > 0 && + proplen < sizeof (netalias)) { + (void) prom_getprop(anode, "net", (caddr_t)netalias); + + if (is_netdev(netalias)) { + char *p; + + /* + * Strip device arguments from netalias[]. + */ + if ((p = strchr(netalias, ':')) != NULL) { + *p = '\0'; + } + + /* + * If bpath is a network device path, then v2path + * will be a copy of this sans device arguments. + */ + if (!is_netdev(bpath) || + strcmp(v2path, netalias) == 0) { + /* + * Stash the netdev_path bootprop value, then + * initialize the hardware and return success. + */ + netdev_path = netalias; + mac_init(netalias); + return (B_TRUE); + } + + bootlog("wanboot", BOOTLOG_CRIT, + "wanboot requires that the 'net' alias refers to "); + bootlog("wanboot", BOOTLOG_CRIT, + "the network device path from which it loaded"); + return (B_FALSE); + } + } + + /* + * If we haven't established a device path for a network interface, + * then we're doomed. + */ + bootlog("wanboot", BOOTLOG_CRIT, + "No network device available for wanboot!"); + bootlog("wanboot", BOOTLOG_CRIT, + "(Ensure that the 'net' alias is set correctly)"); + return (B_FALSE); +} + +/* + * This implementation of bootprog() is used solely by wanboot. + * + * The basic algorithm is as follows: + * + * - The wanboot options (those specified using the "-o" flag) are processed, + * and if necessary the wanboot interpreter is invoked to collect other + * options. + * + * - The wanboot filesystem (containing certificates, wanboot.conf file, etc.) + * is then downloaded into the bootfs ramdisk, which is mounted for use + * by OpenSSL, access to wanboot.conf, etc. + * + * - The wanboot miniroot is downloaded over http/https into the rootfs + * ramdisk. The bootfs filesystem is unmounted, and the rootfs filesystem + * is mounted. + */ +/* EXPORT DELETE END */ +/*ARGSUSED*/ +int +bootprog(char *bpath, char *bargs, boolean_t user_specified_filename) +{ +/* EXPORT DELETE START */ + char *miniroot_path; + url_t server_url; + int ret; + + if (!init_netdev(bpath)) { + return (-1); + } + + if (!bootinfo_init()) { + bootlog("wanboot", BOOTLOG_CRIT, "Cannot initialize bootinfo"); + return (-1); + } + + /* + * Get default values from PROM, etc., process any boot arguments + * (specified with the "-o" option), and initialize the interface. + */ + if (!wanboot_init_interface(wanboot_arguments)) { + return (-1); + } + + /* + * Determine which encryption and hashing algorithms the client + * is configured to use. + */ + init_encryption(); + init_hashing(); + + /* + * Get the bootserver value. Should be of the form: + * http://host[:port]/abspath. + */ + ret = get_url(BI_BOOTSERVER, &server_url); + if (ret != 0) { + bootlog("wanboot", BOOTLOG_CRIT, + "Unable to retrieve the bootserver URL"); + return (-1); + } + + /* + * Get the wanboot file system and mount it. Contains metdata + * needed by wanboot. + */ + if (get_wanbootfs(&server_url) != 0) { + return (-1); + } + + /* + * Check that there is a valid wanboot.conf file in the wanboot + * file system. + */ + if (bootconf_init(&bc_handle, NULL) != BC_E_NOERROR) { + bootlog("wanboot", BOOTLOG_CRIT, + "wanboot.conf error (code=%d)", bc_handle.bc_error_code); + return (-1); + } + + /* + * Set the time + */ + init_boot_time(); + + /* + * Verify that URLs in wanboot.conf can be reached, etc. + */ + if (!wanboot_verify_config()) { + return (-1); + } + + /* + * Retrieve the miniroot. + */ + if (get_miniroot(&miniroot_path) != 0) { + return (-1); + } + + /* + * We don't need the wanboot file system mounted anymore and + * should unmount it so that we can mount the miniroot. + */ + (void) unmountroot(); + + /* + * Mount the miniroot. + */ + if (determine_fstype_and_mountroot(miniroot_path) != VFS_SUCCESS) { + bootlog("wanboot", BOOTLOG_CRIT, + "Could not mount miniroot filesystem"); + return (-1); + } + bootlog("wanboot", BOOTLOG_VERBOSE, "The miniroot has been mounted"); + + v2path = "/ramdisk-rootfs:a"; + bootlog("wanboot", BOOTLOG_VERBOSE, "device path '%s'", v2path); + + /* + * kernname (default-name) might have changed if mountroot() called + * boot_nfs_mountroot(), and it called set_default_filename(). + */ + if (! user_specified_filename) + (void) strcpy(filename, kernname); + + bootlog("wanboot", BOOTLOG_VERBOSE, + "standalone = `%s', args = `%s'", filename, bargs); + + set_client_bootargs(filename, bargs); + + /* + * We're done with the mac interface that was initialized by + * mac_init() inside init_netdev(). + */ + mac_fini(); + + bootconf_end(&bc_handle); + bootinfo_end(); + +/* EXPORT DELETE END */ + return (0); +} diff --git a/usr/src/psm/stand/boot/sparc/common/wbcli.c b/usr/src/psm/stand/boot/sparc/common/wbcli.c new file mode 100644 index 0000000000..f6d6d9a00a --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/wbcli.c @@ -0,0 +1,1425 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* EXPORT DELETE START */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/salib.h> +#include <sys/promif.h> +#include <sys/wanboot_impl.h> +#include <netinet/in.h> +#include <parseURL.h> +#include <bootlog.h> +#include <sys/socket.h> +#include <netinet/inetutil.h> +#include <netinet/dhcp.h> +#include <dhcp_impl.h> +#include <lib/inet/mac.h> +#include <lib/inet/ipv4.h> +#include <lib/inet/dhcpv4.h> +#include <lib/sock/sock_test.h> +#include <sys/sunos_dhcp_class.h> +#include <aes.h> +#include <des3.h> +#include <hmac_sha1.h> +#include <netdb.h> +#include <wanboot_conf.h> +#include <bootinfo.h> +/* EXPORT DELETE END */ + +#include "wbcli.h" + +/* EXPORT DELETE START */ + +#define skipspace(p) while (isspace(*(p))) ++p + +#define skiptext(p) while (*(p) != '\0' && !isspace(*(p)) && \ + *(p) != '=' && *(p) != ',') ++p + +#define PROMPT "boot> " +#define TEST_PROMPT "boot-test> " + +#define CLI_SET 0 +#define CLI_FAIL (-1) +#define CLI_EXIT (-2) +#define CLI_CONT (-3) + +#define CLF_CMD 0x00000001 /* builtin command */ +#define CLF_ARG 0x00000002 /* boot argument directive */ + +#define CLF_IF 0x00000100 /* interface parameter */ +#define CLF_BM 0x00000200 /* bootmisc parameter */ + +#define CLF_VALSET 0x00010000 /* value set, may be null */ +#define CLF_HIDDEN 0x00020000 /* don't show its value (key) */ +#define CLF_VALMOD 0x00040000 /* value modified by the user */ + +/* + * Macros for use in managing the flags in the cli_list[]. + * The conventions we follow are: + * + * CLF_VALSET is cleared if a value is removed from varptr + * CLF_VALSET is set if a value has been placed in varptr + * (that value need not be vetted) + * CLF_HIDDEN is set if a value must not be exposed to the user + * CLF_HIDDEN is cleared if a value can be exposed to the user + * CLF_VALMOD is cleared if a value in varptr has not been modified + * CLF_VALMOD is set if a value in varptr has been modified by + * the user + */ +#ifdef DEBUG +#define CLF_SETVAL(var) { \ + (((var)->flags) |= CLF_VALSET); \ + printf("set %s\n", var->varname);\ + } + +#define CLF_ISSET(var) (printf("%s\n", \ + (((var)->flags) & CLF_VALSET) != 0 \ + ? "is set" : "not set"), \ + ((((var)->flags) & CLF_VALSET) != 0)) + +#define CLF_CLRHIDDEN(var) { \ + (((var)->flags) &= ~CLF_HIDDEN); \ + printf("unhide %s\n", var->varname); \ + } + +#define CLF_ISHIDDEN(var) (printf("%s\n", \ + (((var)->flags) & CLF_HIDDEN) != 0 \ + ? "is hidden" : "not hidden"), \ + ((((var)->flags) & CLF_HIDDEN) != 0)) + +#define CLF_MODVAL(var) { \ + (((var)->flags) |= \ + (CLF_VALMOD | CLF_VALSET)); \ + printf("modified %s\n", var->varname);\ + } + +#define CLF_ISMOD(var) (printf("%s\n", \ + (((var)->flags) & CLF_VALMOD) != 0 \ + ? "is set" : "not set"), \ + ((((var)->flags) & CLF_VALMOD) != 0)) +#else /* DEBUG */ + +#define CLF_SETVAL(var) (((var)->flags) |= CLF_VALSET) +#define CLF_ISSET(var) ((((var)->flags) & CLF_VALSET) != 0) +#define CLF_CLRHIDDEN(var) (((var)->flags) &= ~CLF_HIDDEN) +#define CLF_ISHIDDEN(var) ((((var)->flags) & CLF_HIDDEN) != 0) +#define CLF_MODVAL(var) (((var)->flags) |= (CLF_VALMOD | CLF_VALSET)) +#define CLF_ISMOD(var) ((((var)->flags) & CLF_VALMOD) != 0) + +#endif /* DEBUG */ + +/* + * The width of the widest varname below - currently "subnet_mask". + */ +#define VAR_MAXWIDTH strlen(BI_SUBNET_MASK) + +struct cli_ent; +typedef int claction_t(struct cli_ent *, char *, boolean_t); + +typedef struct cli_ent { + char *varname; + claction_t *action; + int flags; + void *varptr; + uint_t varlen; + uint_t varmax; +} cli_ent_t; + +static cli_ent_t *find_cli_ent(char *varstr); + +static char cmdbuf[2048]; /* interpreter buffer */ +static char hostip[INET_ADDRSTRLEN]; +static char subnet[INET_ADDRSTRLEN]; +static char router[INET_ADDRSTRLEN]; +static char hostname[MAXHOSTNAMELEN]; +static char httpproxy[INET_ADDRSTRLEN + 5]; /* a.b.c.d:p */ +static char bootserverURL[URL_MAX_STRLEN + 1]; +static unsigned char clientid[WB_MAX_CID_LEN]; +static unsigned char aeskey[AES_128_KEY_SIZE]; +static unsigned char des3key[DES3_KEY_SIZE]; +static unsigned char sha1key[WANBOOT_HMAC_KEY_SIZE]; +static boolean_t args_specified_prompt = B_FALSE; + +extern bc_handle_t bc_handle; +extern int getchar(void); + +static claction_t clcid, clkey, clip, clstr, clurl, clhp; +static claction_t clhelp, cllist, clprompt, cldhcp, cltest, clgo, clexit; + +static cli_ent_t cli_list[] = { + /* + * Commands/bootargs: + */ + { "test", cltest, CLF_ARG, + NULL, 0, 0 }, + { "dhcp", cldhcp, CLF_ARG, + NULL, 0, 0 }, + { "prompt", clprompt, CLF_CMD | CLF_ARG, + NULL, 0, 0 }, + { "list", cllist, CLF_CMD, + NULL, 0, 0 }, + { "help", clhelp, CLF_CMD, + NULL, 0, 0 }, + { "go", clgo, CLF_CMD, + NULL, 0, 0 }, + { "exit", clexit, CLF_CMD, + NULL, 0, 0 }, + + /* + * Interface: + */ + { BI_HOST_IP, clip, CLF_IF, + hostip, 0, sizeof (hostip) }, + { BI_SUBNET_MASK, clip, CLF_IF, + subnet, 0, sizeof (subnet) }, + { BI_ROUTER_IP, clip, CLF_IF, + router, 0, sizeof (router) }, + { BI_HOSTNAME, clstr, CLF_IF, + hostname, 0, sizeof (hostname) }, + { BI_HTTP_PROXY, clhp, CLF_IF, + httpproxy, 0, sizeof (httpproxy) }, + { BI_CLIENT_ID, clcid, CLF_IF, + clientid, 0, sizeof (clientid) }, + + /* + * Bootmisc: + */ + { BI_AES_KEY, clkey, CLF_BM | CLF_HIDDEN, + aeskey, 0, sizeof (aeskey) }, + { BI_3DES_KEY, clkey, CLF_BM | CLF_HIDDEN, + des3key, 0, sizeof (des3key) }, + { BI_SHA1_KEY, clkey, CLF_BM | CLF_HIDDEN, + sha1key, 0, sizeof (sha1key) }, + { BI_BOOTSERVER, clurl, CLF_BM, + bootserverURL, 0, sizeof (bootserverURL) }, +}; + +static int num_cli_ent = (sizeof (cli_list) / sizeof (cli_ent_t)); + +/* + * Fetch a line from the user, handling backspace appropriately. + */ +static int +editline(char *buf, int count) +{ + int i = 0; + char c; + + while (i < count - 1) { + c = getchar(); + if (c == '\n') { + break; + } else if (c == '\b') { + /* Clear for backspace. */ + if (i > 0) + i--; + continue; + } else { + buf[i++] = c; + } + } + buf[i] = '\0'; + return (i); +} + +/* + * Assign a client-id to cliptr, or output cliptr's value as a client-id. + * On assignment the value is specified in valstr, either in hexascii or + * as a quoted string; on output its value is printed in hexascii. + */ +static int +clcid(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + uint_t len, vmax; + boolean_t hexascii = B_TRUE; + char buffer[2 * WB_MAX_CID_LEN + 1]; + + if (out) { + len = cliptr->varlen * 2 + 1; + (void) octet_to_hexascii(cliptr->varptr, cliptr->varlen, + buffer, &len); + printf("%s", buffer); + return (CLI_CONT); + } else { + len = strlen(valstr); + vmax = cliptr->varmax - 1; /* space for the prefix */ + + /* + * Check whether the value is a quoted string; if so, strip + * the quotes and note that it's not in hexascii. + */ + if ((valstr[0] == '"' || valstr[0] == '\'') && + valstr[len-1] == valstr[0]) { + hexascii = B_FALSE; + ++valstr; + len -= 2; + valstr[len] = '\0'; + } else { + /* + * If the value contains any non-hex digits assume + * that it's not in hexascii. + */ + char *p; + + for (p = valstr; *p != '\0'; ++p) { + if (!isxdigit(*p)) { + hexascii = B_FALSE; + break; + } + } + } + + if (hexascii) { + if (len > vmax * 2 || + hexascii_to_octet(valstr, len, + (char *)(cliptr->varptr), &vmax) != 0) { + return (CLI_FAIL); + } + cliptr->varlen = vmax; + } else { + if (len > vmax) { + return (CLI_FAIL); + } + bcopy(valstr, cliptr->varptr, len); + cliptr->varlen = len; + } + + return (CLI_SET); + } +} + +/* + * Assign a key to cliptr, or output cliptr's value as a key. + * On assignment the value is specified in valstr in hexascii; + * on output its value is printed in hexascii, provided the key + * was entered at the interpreter (not obtained from OBP and + * thus hidden). + */ +static int +clkey(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + uint_t len, vmax; + + if (out) { + char buffer[2 * WANBOOT_MAXKEYLEN + 1]; + + if (!CLF_ISHIDDEN(cliptr)) { + len = cliptr->varlen * 2 + 1; + (void) octet_to_hexascii(cliptr->varptr, + cliptr->varlen, buffer, &len); + printf("%s", buffer); + } else { + printf("*HIDDEN*"); + } + return (CLI_CONT); + } else { + len = strlen(valstr); + vmax = cliptr->varmax; + if (len != vmax * 2 || hexascii_to_octet(valstr, len, + cliptr->varptr, &vmax) != 0) { + return (CLI_FAIL); + } + cliptr->varlen = vmax; + CLF_CLRHIDDEN(cliptr); + return (CLI_SET); + } +} + +/* + * Assign an IP address to cliptr, or output cliptr's value as an + * IP address. On assignment the value is specified in valstr in + * dotted-decimal format; on output its value is printed in dotted- + * decimal format. + */ +static int +clip(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + uint_t len; + + if (out) { + printf("%s", (char *)cliptr->varptr); + return (CLI_CONT); + } + + if (inet_addr(valstr) == (in_addr_t)-1 || + (len = strlen(valstr)) >= cliptr->varmax) { + return (CLI_FAIL); + } + + (void) strcpy(cliptr->varptr, valstr); + cliptr->varlen = len + 1; + return (CLI_SET); +} + +/* + * Assign an arbitrary string to cliptr, or output cliptr's value as a string. + */ +static int +clstr(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + uint_t len; + + if (out) { + printf("%s", (char *)cliptr->varptr); + return (CLI_CONT); + } else { + if ((len = strlen(valstr)) >= cliptr->varmax) { + return (CLI_FAIL); + } else { + (void) strcpy(cliptr->varptr, valstr); + cliptr->varlen = len + 1; + return (CLI_SET); + } + } +} + +/* + * Assign a URL to cliptr (having verified the format), or output cliptr's + * value as a URL. The host must be specified in dotted-decimal, and the + * scheme must not be https. + */ +static int +clurl(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + url_t u; + uint_t len; + + if (out) { + printf("%s", (char *)cliptr->varptr); + return (CLI_CONT); + } + + if (url_parse(valstr, &u) != URL_PARSE_SUCCESS || + u.https || inet_addr(u.hport.hostname) == (in_addr_t)-1 || + (len = strlen(valstr)) >= cliptr->varmax) { + return (CLI_FAIL); + } + + (void) strcpy(cliptr->varptr, valstr); + cliptr->varlen = len + 1; + return (CLI_SET); +} + +/* + * Assign a hostport to cliptr (having verified the format), or output cliptr's + * value as a hostport. The host must be specified in dotted-decimal. + */ +static int +clhp(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + url_hport_t u; + uint_t len; + + if (out) { + printf("%s", (char *)cliptr->varptr); + return (CLI_CONT); + } + + if (url_parse_hostport(valstr, &u, URL_DFLT_PROXY_PORT) != + URL_PARSE_SUCCESS || + inet_addr(u.hostname) == (in_addr_t)-1 || + (len = strlen(valstr)) >= cliptr->varmax) { + return (CLI_FAIL); + } + + (void) strcpy(cliptr->varptr, valstr); + cliptr->varlen = len + 1; + return (CLI_SET); +} + +/* + * Exit the interpreter and return to the booter. + */ +/*ARGSUSED*/ +static int +clgo(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + return (CLI_EXIT); +} + +/* + * Exit the interpreter and return to OBP. + */ +/*ARGSUSED*/ +static int +clexit(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + prom_exit_to_mon(); + /*NOTREACHED*/ + return (CLI_EXIT); +} + +/* + * Provide simple help information. + */ +/*ARGSUSED*/ +static int +clhelp(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + printf("var=val - set variable\n"); + printf("var= - unset variable\n"); + printf("var - print variable\n"); + printf("list - list variables and their values\n"); + printf("prompt - prompt for unset variables\n"); + printf("go - continue booting\n"); + printf("exit - quit boot interpreter and return to OBP\n"); + + return (CLI_CONT); +} + +/* + * List variables and their current values. + */ +/*ARGSUSED*/ +static int +cllist(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + int wanted = (int)valstr; + int i; + + wanted &= ~(CLF_CMD | CLF_ARG); + + for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; cliptr++) { + if ((cliptr->flags & (CLF_CMD | CLF_ARG)) != 0 || + (cliptr->flags & wanted) == 0) { + continue; + } + printf("%s: ", cliptr->varname); + /* + * Line the values up - space to the width of the widest + * varname + 1 for the ':'. + */ + for (i = VAR_MAXWIDTH + 1 - strlen(cliptr->varname); + i > 0; --i) { + printf(" "); + } + + if (CLF_ISSET(cliptr) || CLF_ISHIDDEN(cliptr)) { + (void) cliptr->action(cliptr, NULL, B_TRUE); + printf("\n"); + } else { + printf("UNSET\n"); + } + } + + return (CLI_CONT); +} + +/* + * Prompt for wanted values. + */ +/*ARGSUSED*/ +static int +clprompt(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + char *p; + int wanted = (int)valstr; + + /* + * If processing boot arguments, simply note the fact that clprompt() + * should be invoked later when other parameters may be supplied. + */ + if ((wanted & CLF_ARG) != 0) { + args_specified_prompt = B_TRUE; + return (CLI_CONT); + } + wanted &= ~(CLF_CMD | CLF_ARG); + + for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { + if ((cliptr->flags & wanted) == 0) { + continue; + } + + printf("%s", cliptr->varname); + if (CLF_ISSET(cliptr)) { + printf(" ["); + (void) cliptr->action(cliptr, NULL, B_TRUE); + printf("]"); + } + printf("? "); + (void) editline(cmdbuf, sizeof (cmdbuf)); + printf("\n"); + + p = cmdbuf; + skipspace(p); + if (*p == '\0') { /* nothing there */ + continue; + } + + /* Get valstr and nul terminate */ + valstr = p; + ++p; + skiptext(p); + *p = '\0'; + + /* If empty value, do nothing */ + if (strlen(valstr) == 0) { + continue; + } + + switch (cliptr->action(cliptr, valstr, B_FALSE)) { + case CLI_SET: + CLF_MODVAL(cliptr); + break; + case CLI_FAIL: + printf("Incorrect format, parameter unchanged!\n"); + break; + case CLI_EXIT: + return (CLI_EXIT); + case CLI_CONT: + break; + } + } + + return (CLI_CONT); +} + +/* + * If the PROM has done DHCP, bind the interface; otherwise do the full + * DHCP packet exchange. + */ +/*ARGSUSED*/ +static int +cldhcp(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + static boolean_t first_time = B_TRUE; + static int ret = CLI_CONT; + + if (first_time) { + /* + * Set DHCP's idea of the client_id from our cached value. + */ + cliptr = find_cli_ent(BI_CLIENT_ID); + if (CLF_ISMOD(cliptr)) { + dhcp_set_client_id(cliptr->varptr, cliptr->varlen); + } + + bootlog("wanboot", BOOTLOG_INFO, "Starting DHCP configuration"); + + (void) ipv4_setpromiscuous(B_TRUE); + if (dhcp() == 0) { + bootlog("wanboot", BOOTLOG_INFO, + "DHCP configuration succeeded"); + } else { + bootlog("wanboot", BOOTLOG_CRIT, + "DHCP configuration failed"); + ret = CLI_FAIL; + } + (void) ipv4_setpromiscuous(B_FALSE); + + first_time = B_FALSE; + } + + return (ret); +} + +/* + * Invoke the socket test interpreter (for testing purposes only). + */ +/*ARGSUSED*/ +static int +cltest(cli_ent_t *cliptr, char *valstr, boolean_t out) +{ + (void) ipv4_setpromiscuous(B_FALSE); + printf("\n"); + for (;;) { + printf(TEST_PROMPT); + if (editline(cmdbuf, sizeof (cmdbuf)) > 0) { + printf("\n"); + (void) st_interpret(cmdbuf); + } else { + prom_exit_to_mon(); + /* NOTREACHED */ + } + } + + /* NOTREACHED */ + return (CLI_CONT); +} + +/* + * Return the cliptr corresponding to the named variable. + */ +static cli_ent_t * +find_cli_ent(char *varstr) +{ + cli_ent_t *cliptr; + + for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { + if (strcmp(varstr, cliptr->varname) == 0) { + return (cliptr); + } + } + + return (NULL); +} + +/* + * Evaluate the commands provided by the user (either as "-o" boot arguments + * or interactively at the boot interpreter). + */ +static int +cli_eval_buf(char *inbuf, int wanted) +{ + char *p, *varstr, *end_varstr, *valstr, *end_valstr; + boolean_t assign; + cli_ent_t *cliptr; + + for (p = inbuf; *p != '\0'; ) { + skipspace(p); + + /* If nothing more on line, go get the next one */ + if (*p == '\0') { + break; + } else if (*p == ',') { /* orphan ',' ? */ + ++p; + continue; + } + + /* Get ptrs to start & end of variable */ + varstr = p; + ++p; + skiptext(p); + end_varstr = p; + skipspace(p); + + /* See if we're doing an assignment */ + valstr = NULL; + if (*p != '=') { /* nope, just printing */ + assign = B_FALSE; + } else { + assign = B_TRUE; + ++p; /* past '=' */ + skipspace(p); + + /* Assigning something? (else clear variable) */ + if (*p != '\0' && *p != ',') { + /* Get ptrs to start & end of valstr */ + valstr = p; + ++p; + skiptext(p); + end_valstr = p; + skipspace(p); + } + } + + /* Skip ',' delimiter if present */ + if (*p == ',') { + ++p; + } + + /* Nul-terminate varstr and valstr (if appropriate) */ + *end_varstr = '\0'; + if (valstr != NULL) { + *end_valstr = '\0'; + } + + if ((cliptr = find_cli_ent(varstr)) == NULL) { + printf("Unknown variable '%s'; ignored\n", varstr); + continue; + } + + /* + * It's an error to specify a parameter which can only be a + * boot argument (and not a command) when not processing the + * boot arguments. + */ + if ((cliptr->flags & (CLF_CMD | CLF_ARG)) == CLF_ARG && + (wanted & CLF_ARG) == 0) { + printf("'%s' may only be specified as a " + "boot argument; ignored\n", varstr); + continue; + } + + /* + * When doing an assignment, verify that it's not a command + * or argument name, and that it is permissible in the current + * context. An 'empty' assignment (var=) is treated the same + * as a null assignment (var=""). + * + * If processing the boot arguments, it is an error to not + * assign a value to a non-argument parameter. + */ + if (assign) { + if ((cliptr->flags & (CLF_CMD | CLF_ARG)) != 0) { + printf("'%s' is a command and cannot " + "be assigned\n", varstr); + return (CLI_FAIL); + } + if ((cliptr->flags & wanted) == 0) { + printf("'%s' cannot be assigned\n", varstr); + return (CLI_FAIL); + } + + if (valstr == NULL) { + cliptr->varlen = 0; + CLF_MODVAL(cliptr); + continue; + } + } else if ((wanted & CLF_ARG) != 0 && + (cliptr->flags & (CLF_CMD | CLF_ARG)) == 0) { + printf("'%s' must be assigned when specified in " + " the boot arguments\n", varstr); + return (CLI_FAIL); + } + + /* + * Pass 'wanted' to command-handling functions, in particular + * clprompt() and cllist(). + */ + if ((cliptr->flags & CLF_CMD) != 0) { + valstr = (char *)wanted; + } + + /* + * Call the parameter's action function. + */ + switch (cliptr->action(cliptr, valstr, !assign)) { + case CLI_SET: + CLF_MODVAL(cliptr); + break; + case CLI_FAIL: + printf("Incorrect format: variable '%s' not set\n", + cliptr->varname); + break; + case CLI_EXIT: + return (CLI_EXIT); + case CLI_CONT: + if (!assign) { + printf("\n"); + } + break; + } + } + + return (CLI_CONT); +} + +static void +cli_interpret(int wanted) +{ + printf("\n"); + do { + printf(PROMPT); + (void) editline(cmdbuf, sizeof (cmdbuf)); + printf("\n"); + + } while (cli_eval_buf(cmdbuf, wanted) != CLI_EXIT); +} + +#if defined(__sparcv9) +/* + * This routine queries the PROM to see what encryption keys exist. + */ +static void +get_prom_encr_keys() +{ + cli_ent_t *cliptr; + char encr_key[WANBOOT_MAXKEYLEN]; + int keylen; + int status; + int ret; + + /* + * At the top of the priority list, we have AES. + */ + ret = prom_get_security_key(WANBOOT_AES_128_KEY_NAME, encr_key, + WANBOOT_MAXKEYLEN, &keylen, &status); + if ((ret == 0) && (status == 0) && (keylen == AES_128_KEY_SIZE)) { + cliptr = find_cli_ent(BI_AES_KEY); + bcopy(encr_key, cliptr->varptr, AES_128_KEY_SIZE); + cliptr->varlen = AES_128_KEY_SIZE; + CLF_MODVAL(cliptr); + } + + /* + * Next, 3DES. + */ + ret = prom_get_security_key(WANBOOT_DES3_KEY_NAME, encr_key, + WANBOOT_MAXKEYLEN, &keylen, &status); + if ((ret == 0) && (status == 0) && (keylen == DES3_KEY_SIZE)) { + cliptr = find_cli_ent(BI_3DES_KEY); + bcopy(encr_key, cliptr->varptr, DES3_KEY_SIZE); + cliptr->varlen = DES3_KEY_SIZE; + CLF_MODVAL(cliptr); + } +} + +/* + * This routine queries the PROM to see what hashing keys exist. + */ +static void +get_prom_hash_keys() +{ + cli_ent_t *cliptr; + char hash_key[WANBOOT_HMAC_KEY_SIZE]; + int keylen; + int status; + int ret; + + /* + * The only supported key thus far is SHA1. + */ + ret = prom_get_security_key(WANBOOT_HMAC_SHA1_KEY_NAME, hash_key, + WANBOOT_HMAC_KEY_SIZE, &keylen, &status); + if ((ret == 0) && (status == 0) && (keylen == WANBOOT_HMAC_KEY_SIZE)) { + cliptr = find_cli_ent(BI_SHA1_KEY); + bcopy(hash_key, cliptr->varptr, WANBOOT_HMAC_KEY_SIZE); + cliptr->varlen = WANBOOT_HMAC_KEY_SIZE; + CLF_MODVAL(cliptr); + } +} +#endif /* defined(__sparcv9) */ + +/* + * For the given parameter type(s), get values from bootinfo and cache in + * the local variables used by the "boot>" interpreter. + */ +static void +bootinfo_defaults(int which) +{ + cli_ent_t *cliptr; + + for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { + if ((cliptr->flags & which) != 0 && !CLF_ISSET(cliptr)) { + size_t len = cliptr->varmax; + + if (bootinfo_get(cliptr->varname, cliptr->varptr, + &len, NULL) == BI_E_SUCCESS) { + cliptr->varlen = len; + CLF_SETVAL(cliptr); + } + } + } +} + +/* + * For the given parameter type(s), store values entered at the "boot>" + * interpreter back into bootinfo. + */ +static void +update_bootinfo(int which) +{ + cli_ent_t *cliptr; + + for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { + if ((cliptr->flags & which) != 0 && CLF_ISMOD(cliptr)) { + (void) bootinfo_put(cliptr->varname, + cliptr->varptr, cliptr->varlen, 0); + } + } +} + +/* + * Return the net-config-strategy: "dhcp", "manual" or "rarp" + */ +static char * +net_config_strategy(void) +{ + static char ncs[8]; /* "dhcp" or "manual" */ + size_t len = sizeof (ncs); + + if (ncs[0] == '\0' && + bootinfo_get(BI_NET_CONFIG_STRATEGY, ncs, &len, NULL) != + BI_E_SUCCESS) { + /* + * Support for old PROMs: create the net-config-strategy + * property under /chosen with an appropriate value. If we + * have a bootp-response (not interested in its value, just + * its presence) then we did DHCP; otherwise configuration + * is manual. + */ + if (bootinfo_get(BI_BOOTP_RESPONSE, NULL, NULL, + NULL) == BI_E_BUF2SMALL) { + (void) strcpy(ncs, "dhcp"); + } else { + (void) strcpy(ncs, "manual"); + } + (void) bootinfo_put(BI_NET_CONFIG_STRATEGY, ncs, strlen(ncs), + BI_R_CHOSEN); + + bootlog("wanboot", BOOTLOG_INFO, + "Default net-config-strategy: %s", ncs); + } + + return (ncs); +} + +/* + * If there is no client-id property published in /chosen (by the PROM or the + * boot interpreter) provide a default client-id based on the MAC address of + * the client. + * As specified in RFC2132 (section 9.14), this is prefixed with a byte + * which specifies the ARP hardware type defined in RFC1700 (for Ethernet, + * this should be 1). + */ +static void +generate_default_clientid(void) +{ + char clid[WB_MAX_CID_LEN]; + size_t len = sizeof (clid); + + if (bootinfo_get(BI_CLIENT_ID, clid, &len, NULL) != BI_E_SUCCESS) { + len = mac_get_addr_len() + 1; /* include hwtype */ + + if (len > sizeof (clid)) { + return; + } + + clid[0] = mac_arp_type(mac_get_type()); + bcopy(mac_get_addr_buf(), &clid[1], len - 1); + + (void) bootinfo_put(BI_CLIENT_ID, clid, len, 0); + } +} + +/* + * Determine the URL of the boot server from the 'file' parameter to OBP, + * the SbootURI or BootFile DHCP options, or the 'bootserver' value entered + * either as a "-o" argument or at the interpreter. + */ +static void +determine_bootserver_url(void) +{ + char bs[URL_MAX_STRLEN + 1]; + size_t len; + url_t url; + + if (bootinfo_get(BI_BOOTSERVER, bs, &len, NULL) != BI_E_SUCCESS) { + /* + * If OBP has published a network-boot-file property in + * /chosen (or there is a DHCP BootFile or SbootURI vendor + * option) and it's a URL, construct the bootserver URL + * from it. + */ + len = URL_MAX_STRLEN; + if (bootinfo_get(BI_NETWORK_BOOT_FILE, bs, &len, NULL) != + BI_E_SUCCESS) { + len = URL_MAX_STRLEN; + if (bootinfo_get(BI_BOOTFILE, bs, &len, NULL) != + BI_E_SUCCESS) { + return; + } + } + if (url_parse(bs, &url) == URL_PARSE_SUCCESS) { + (void) bootinfo_put(BI_BOOTSERVER, bs, len, 0); + } + } +} + +/* + * Provide a classful subnet mask based on the client's IP address. + */ +static in_addr_t +generate_classful_subnet(in_addr_t client_ipaddr) +{ + struct in_addr subnetmask; + char *netstr; + + if (IN_CLASSA(client_ipaddr)) { + subnetmask.s_addr = IN_CLASSA_NET; + } else if (IN_CLASSB(client_ipaddr)) { + subnetmask.s_addr = IN_CLASSB_NET; + } else { + subnetmask.s_addr = IN_CLASSC_NET; + } + + netstr = inet_ntoa(subnetmask); + (void) bootinfo_put(BI_SUBNET_MASK, netstr, strlen(netstr) + 1, 0); + + return (subnetmask.s_addr); +} + +/* + * Informational output to the user (if interactive) or the bootlogger. + */ +static void +info(const char *msg, boolean_t interactive) +{ + if (interactive) { + printf("%s\n", msg); + } else { + bootlog("wanboot", BOOTLOG_INFO, "%s", msg); + } +} + +/* + * Determine whether we have sufficient information to proceed with booting, + * either for configuring the interface and downloading the bootconf file, + * or for downloading the miniroot. + */ +static int +config_incomplete(int why, boolean_t interactive) +{ + boolean_t error = B_FALSE; + char buf[URL_MAX_STRLEN + 1]; + size_t len; + char *urlstr; + url_t u; + struct hostent *hp; + in_addr_t client_ipaddr, ipaddr, bsnet, pxnet; + static in_addr_t subnetmask, clnet; + static boolean_t have_router = B_FALSE; + static boolean_t have_proxy = B_FALSE; + boolean_t have_root_server = B_FALSE; + boolean_t have_boot_logger = B_FALSE; + in_addr_t rsnet, blnet; + + /* + * Note that 'have_router', 'have_proxy', 'subnetmask', and 'clnet' + * are static, so that their values (gathered when checking the + * interface configuration) may be used again when checking the boot + * configuration. + */ + if (why == CLF_IF) { + /* + * A valid host IP address is an absolute requirement. + */ + len = sizeof (buf); + if (bootinfo_get(BI_HOST_IP, buf, &len, NULL) == BI_E_SUCCESS) { + if ((client_ipaddr = inet_addr(buf)) == (in_addr_t)-1) { + info("host-ip invalid!", interactive); + error = B_TRUE; + } + } else { + info("host-ip not set!", interactive); + error = B_TRUE; + } + + /* + * If a subnet mask was provided, use it; otherwise infer it. + */ + len = sizeof (buf); + if (bootinfo_get(BI_SUBNET_MASK, buf, &len, NULL) == + BI_E_SUCCESS) { + if ((subnetmask = inet_addr(buf)) == (in_addr_t)-1) { + info("subnet-mask invalid!", interactive); + error = B_TRUE; + } + } else { + info("Defaulting to classful subnetting", interactive); + + subnetmask = generate_classful_subnet(client_ipaddr); + } + clnet = client_ipaddr & subnetmask; + + /* + * A legal bootserver URL is also an absolute requirement. + */ + len = sizeof (buf); + if (bootinfo_get(BI_BOOTSERVER, buf, &len, NULL) == + BI_E_SUCCESS) { + if (url_parse(buf, &u) != URL_PARSE_SUCCESS || + u.https || + (ipaddr = inet_addr(u.hport.hostname)) == + (in_addr_t)-1) { + info("bootserver not legal URL!", interactive); + error = B_TRUE; + } else { + bsnet = ipaddr & subnetmask; + } + } else { + info("bootserver not specified!", interactive); + error = B_TRUE; + } + + /* + * Is there a correctly-defined router? + */ + len = sizeof (buf); + if (bootinfo_get(BI_ROUTER_IP, buf, &len, NULL) == + BI_E_SUCCESS) { + if ((ipaddr = inet_addr(buf)) == (in_addr_t)-1) { + info("router-ip invalid!", interactive); + error = B_TRUE; + } else if (clnet != (ipaddr & subnetmask)) { + info("router not on local subnet!", + interactive); + error = B_TRUE; + } else { + have_router = B_TRUE; + } + } + + /* + * Is there a correctly-defined proxy? + */ + len = sizeof (buf); + if (bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == + BI_E_SUCCESS) { + url_hport_t u; + + if (url_parse_hostport(buf, &u, URL_DFLT_PROXY_PORT) != + URL_PARSE_SUCCESS || + (ipaddr = inet_addr(u.hostname)) == (in_addr_t)-1) { + info("http-proxy port invalid!", interactive); + error = B_TRUE; + } else { + /* + * The proxy is only of use to us if it's on + * our local subnet, or if a router has been + * specified (which should hopefully allow us + * to access the proxy). + */ + pxnet = ipaddr & subnetmask; + have_proxy = (have_router || pxnet == clnet); + } + } + + /* + * If there is no router and no proxy (either on the local + * subnet or reachable via a router), then the bootserver + * URL must be on the local net. + */ + if (!error && !have_router && !have_proxy && bsnet != clnet) { + info("bootserver URL not on local subnet", + interactive); + error = B_TRUE; + } + } else { + /* + * There must be a correctly-defined root_server URL. + */ + if ((urlstr = bootconf_get(&bc_handle, + BC_ROOT_SERVER)) == NULL) { + info("no root_server URL!", interactive); + error = B_TRUE; + } else if (url_parse(urlstr, &u) != URL_PARSE_SUCCESS) { + info("root_server not legal URL!", interactive); + error = B_TRUE; + } else if ((hp = gethostbyname(u.hport.hostname)) == NULL) { + info("cannot resolve root_server hostname!", + interactive); + error = B_TRUE; + } else { + rsnet = *(in_addr_t *)hp->h_addr & subnetmask; + have_root_server = B_TRUE; + } + + /* + * Is there a correctly-defined (non-empty) boot_logger URL? + */ + if ((urlstr = bootconf_get(&bc_handle, + BC_BOOT_LOGGER)) != NULL) { + if (url_parse(urlstr, &u) != URL_PARSE_SUCCESS) { + info("boot_logger not legal URL!", interactive); + error = B_TRUE; + } else if ((hp = gethostbyname(u.hport.hostname)) == + NULL) { + info("cannot resolve boot_logger hostname!", + interactive); + error = B_TRUE; + } else { + blnet = *(in_addr_t *)hp->h_addr & subnetmask; + have_boot_logger = B_TRUE; + } + } + + /* + * If there is no router and no proxy (either on the local + * subnet or reachable via a router), then the root_server + * URL (and the boot_logger URL if specified) must be on the + * local net. + */ + if (!error && !have_router && !have_proxy) { + if (have_root_server && rsnet != clnet) { + info("root_server URL not on local subnet", + interactive); + error = B_TRUE; + } + if (have_boot_logger && blnet != clnet) { + info("boot_logger URL not on local subnet", + interactive); + error = B_TRUE; + } + } + } + + return (error); +} + +/* + * Actually setup our network interface with the values derived from the + * PROM, DHCP or interactively from the user. + */ +static void +setup_interface() +{ + char str[MAXHOSTNAMELEN]; /* will accomodate an IP too */ + size_t len; + struct in_addr in_addr; + + len = sizeof (str); + if (bootinfo_get(BI_HOST_IP, str, &len, NULL) == BI_E_SUCCESS && + (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) { + in_addr.s_addr = htonl(in_addr.s_addr); + ipv4_setipaddr(&in_addr); + } + + len = sizeof (str); + if (bootinfo_get(BI_SUBNET_MASK, str, &len, NULL) == BI_E_SUCCESS && + (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) { + in_addr.s_addr = htonl(in_addr.s_addr); + ipv4_setnetmask(&in_addr); + } + + len = sizeof (str); + if (bootinfo_get(BI_ROUTER_IP, str, &len, NULL) == BI_E_SUCCESS && + (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) { + in_addr.s_addr = htonl(in_addr.s_addr); + ipv4_setdefaultrouter(&in_addr); + (void) ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL, &in_addr); + } + + len = sizeof (str); + if (bootinfo_get(BI_HOSTNAME, str, &len, NULL) == BI_E_SUCCESS) { + (void) sethostname(str, len); + } +} + +/* EXPORT DELETE END */ +boolean_t +wanboot_init_interface(char *boot_arguments) +{ +/* EXPORT DELETE START */ + boolean_t interactive; + int which; + +#if defined(__sparcv9) + /* + * Get the keys from PROM before we allow the user + * to override them from the CLI. + */ + get_prom_encr_keys(); + get_prom_hash_keys(); +#endif /* defined(__sparcv9) */ + + /* + * If there is already a bootp-response property under + * /chosen then the PROM must have done DHCP for us; + * invoke dhcp() to 'bind' the interface. + */ + if (bootinfo_get(BI_BOOTP_RESPONSE, NULL, NULL, NULL) == + BI_E_BUF2SMALL) { + (void) cldhcp(NULL, NULL, 0); + } + + /* + * Obtain default interface values from bootinfo. + */ + bootinfo_defaults(CLF_IF); + + /* + * Process the boot arguments (following the "-o" option). + */ + if (boot_arguments != NULL) { + (void) cli_eval_buf(boot_arguments, + (CLF_ARG | CLF_IF | CLF_BM)); + } + + /* + * Stash away any interface/bootmisc parameter values we got + * from either the PROM or the boot arguments. + */ + update_bootinfo(CLF_IF | CLF_BM); + + /* + * If we don't already have a value for bootserver, try to + * deduce one. Refresh wbcli's idea of these values. + */ + determine_bootserver_url(); + bootinfo_defaults(CLF_BM); + + /* + * Check that the information we have collected thus far is sufficient. + */ + interactive = args_specified_prompt; + + if (interactive) { + /* + * Drop into the boot interpreter to allow the input + * of keys, bootserver and bootmisc, and in the case + * that net-config-strategy == "manual" the interface + * parameters. + */ + which = CLF_BM | CLF_CMD; + if (strcmp(net_config_strategy(), "manual") == 0) + which |= CLF_IF; + + do { + cli_interpret(which); + update_bootinfo(CLF_IF | CLF_BM); + } while (config_incomplete(CLF_IF, interactive)); + } else { + /* + * The user is not to be given the opportunity to + * enter further values; fail. + */ + if (config_incomplete(CLF_IF, interactive)) { + bootlog("wanboot", BOOTLOG_CRIT, + "interface incorrectly configured"); + return (B_FALSE); + } + } + + /* + * If a wanboot-enabled PROM hasn't processed client-id in + * network-boot-arguments, or no value for client-id has been + * specified to the boot interpreter, then provide a default + * client-id based on our MAC address. + */ + generate_default_clientid(); + + /* + * If net-config-strategy == "manual" then we must setup + * the interface now; if "dhcp" then it will already have + * been setup. + */ + if (strcmp(net_config_strategy(), "manual") == 0) + setup_interface(); +/* EXPORT DELETE END */ + return (B_TRUE); +} + +boolean_t +wanboot_verify_config(void) +{ +/* EXPORT DELETE START */ + /* + * Check that the wanboot.conf file defines a valid root_server + * URL, and check that, if given, the boot_logger URL is valid. + */ + if (config_incomplete(0, B_FALSE)) { + bootlog("wanboot", BOOTLOG_CRIT, + "incomplete boot configuration"); + return (B_FALSE); + } +/* EXPORT DELETE END */ + return (B_TRUE); +} diff --git a/usr/src/psm/stand/boot/sparc/common/wbcli.h b/usr/src/psm/stand/boot/sparc/common/wbcli.h new file mode 100644 index 0000000000..ddec3db215 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/wbcli.h @@ -0,0 +1,51 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* wanboot booter specific definitions */ + +#ifndef _WBCLI_H +#define _WBCLI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/wanboot_impl.h> +#include <dhcp_impl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define WB_MAX_CID_LEN DHCP_MAX_CID_LEN + +extern boolean_t wanboot_init_interface(char *); +extern boolean_t wanboot_verify_config(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _WBCLI_H */ diff --git a/usr/src/psm/stand/boot/sparc/common/wbfsconf.c b/usr/src/psm/stand/boot/sparc/common/wbfsconf.c new file mode 100644 index 0000000000..fe558b5bc2 --- /dev/null +++ b/usr/src/psm/stand/boot/sparc/common/wbfsconf.c @@ -0,0 +1,62 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/boothsfs.h> +#include <sys/bootufs.h> +#include <sys/bootvfs.h> + +struct boot_fs_ops *boot_fsw[] = { + &boot_ufs_ops, + &boot_hsfs_ops +}; + +int boot_nfsw = sizeof (boot_fsw) / sizeof (boot_fsw[0]); + +char *systype; + +static char *ufsname = "ufs"; +static char *hsfsname = "hsfs"; + +int +determine_fstype_and_mountroot(char *path) +{ + set_default_fs(ufsname); + if (mountroot(path) == VFS_SUCCESS) { + systype = ufsname; + return (VFS_SUCCESS); + } + + set_default_fs(hsfsname); + if (mountroot(path) == VFS_SUCCESS) { + systype = hsfsname; + return (VFS_SUCCESS); + } + clr_default_fs(); + + return (VFS_FAILURE); +} diff --git a/usr/src/psm/stand/boot/sparcv9/Makefile b/usr/src/psm/stand/boot/sparcv9/Makefile new file mode 100644 index 0000000000..3f3cb6915b --- /dev/null +++ b/usr/src/psm/stand/boot/sparcv9/Makefile @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../../../../Makefile.master + +# firmware libraries, platform-group, and platform-specific +# subdirectories to visit. + +SUBDIRS = sun4u sun4v + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +all install clean clobber lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +# +# Cross-reference customization: include all boot-related source files. +# +UTSDIR= ../../../../uts +STANDLIBDIR= ../../../../stand/lib +STANDSYSDIR= ../../../../stand/sys +PROMDIRS= ../../../promif/ieee1275 +NAMESDIRS= ../../lib/names/sparcv9 ../../lib/names/sparc/common +XRDIRS += ../common ../sparc/common $(NAMESDIRS) $(PROMDIRS) \ + $(STANDSYSDIR) $(STANDLIBDIR)/sparcv9 $(STANDLIBDIR)/common \ + $(STANDLIBDIR)/fs + +cscope.out tags: FRC + $(XREF) -x $@ + +FRC: diff --git a/usr/src/psm/stand/boot/sparcv9/Makefile.com b/usr/src/psm/stand/boot/sparcv9/Makefile.com new file mode 100644 index 0000000000..e9967456f0 --- /dev/null +++ b/usr/src/psm/stand/boot/sparcv9/Makefile.com @@ -0,0 +1,360 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/boot/sparcv9/Makefile.com + + +include $(TOPDIR)/psm/stand/boot/Makefile.boot + +TARG_MACH = sparcv9 + +BOOTSRCDIR = ../.. + +TOP_CMN_DIR = $(SRC)/common +CMN_DIR = $(BOOTSRCDIR)/common +MACH_DIR = ../../sparc/common +PLAT_DIR = . + +BOOT_SRC = boot.c wanboot.c + +CONF_SRC = ufsconf.c nfsconf.c hsfsconf.c wbfsconf.c wbcli.c + +TOP_CMN_C_SRC = getoptstr.c + +MISC_SRC = ramdisk.c + +CMN_C_SRC = heap_kmem.c readfile.c + +MACH_C_SRC = boot_plat.c bootops.c bootprop.c boot_services.c bootflags.c +MACH_C_SRC += get.c + +BOOT_OBJS = $(BOOT_SRC:%.c=%.o) +BOOT_L_OBJS = $(BOOT_OBJS:%.o=%.ln) + +CONF_OBJS = $(CONF_SRC:%.c=%.o) +CONF_L_OBJS = $(CONF_OBJS:%.o=%.ln) + +MISC_OBJS = $(MISC_SRC:%.c=%.o) +MISC_L_OBJS = $(MISC_OBJS:%.o=%.ln) + +SRT0_OBJ = $(SRT0_S:%.s=%.o) +SRT0_L_OBJ = $(SRT0_OBJ:%.o=%.ln) + +C_SRC = $(TOP_CMN_C_SRC) $(CMN_C_SRC) $(MACH_C_SRC) $(ARCH_C_SRC) +C_SRC += $(PLAT_C_SRC) +S_SRC = $(MACH_S_SRC) $(ARCH_S_SRC) $(PLAT_S_SRC) + +OBJS = $(C_SRC:%.c=%.o) $(S_SRC:%.s=%.o) +L_OBJS = $(OBJS:%.o=%.ln) + +CPPDEFS = $(ARCHOPTS) -D$(PLATFORM) -D_BOOT -D_KERNEL -D_MACHDEP +CPPDEFS += -D_ELF64_SUPPORT +CPPINCS += -I$(TOP_CMN_DIR) +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sun4 +CPPINCS += -I$(SRC)/uts/$(PLATFORM) +CPPINCS += -I$(SRC)/uts/sparc/$(ARCHVERS) +CPPINCS += -I$(SRC)/uts/sparc +CPPINCS += -I$(SRC)/uts/$(ARCHMMU) +CPPINCS += -I$(SRC)/common/net/wanboot +CPPINCS += -I$(SRC)/common/net/wanboot/crypt +CPPINCS += -I$(ROOT)/usr/platform/$(PLATFORM)/include +CPPINCS += -I$(ROOT)/usr/include/$(ARCHVERS) +CPPINCS += -I$(PSMSYSHDRDIR) +CPPINCS += -I$(STANDDIR) +CPPINCS += -I$(STANDDIR)/lib +CPPINCS += -I$(STANDDIR)/lib/sa +CPPINCS += -I$(SRC)/common/net/dhcp +CPPFLAGS = $(CPPDEFS) $(CPPINCS) +CPPFLAGS += $(CCYFLAG)$(STANDDIR) +ASFLAGS += $(CPPDEFS) -P -D_ASM $(CPPINCS) +CFLAGS64 += ../../sparc/common/sparc.il + +# +# Until we are building on a MACH=sparcv9 machine, we have to override +# where to look for libraries. +# +PSMNAMELIBDIR = $(PSMSTANDDIR)/lib/names/$(TARG_MACH) +PSMPROMLIBDIR = $(PSMSTANDDIR)/lib/promif/$(TARG_MACH) + +# +# The following libraries are built in LIBNAME_DIR +# +LIBNAME_DIR += $(PSMNAMELIBDIR)/$(PLATFORM) +LIBNAME_LIBS += libnames.a + +# +# The following libraries are built in LIBPROM_DIR +# +LIBPROM_DIR += $(PSMPROMLIBDIR)/$(PROMVERS)/common +LIBPROM_LIBS += libprom.a + +# +# The following libraries are built in LIBSYS_DIR +# +LIBSYS_DIR += $(SYSLIBDIR) +LIBSYS_LIBS += libufs.a libhsfs.a libnfs.a libxdr.a \ + libsock.a libinet.a libtcp.a libtcpstubs.a libscrypt.a \ + libwanboot.a libsa.a libmd5.a libnvpair.a + +# +# Used to convert ELF to an a.out and ensure alignment +# +STRIPALIGN = stripalign + +# +# Program used to post-process the ELF executables +# +ELFCONV = ./$(STRIPALIGN) # Default value + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(CONF_OBJS) $(MISC_OBJS) $(SRT0_OBJ) $(BOOT_OBJS) +.PARALLEL: $(L_OBJS) $(CONF_L_OBJS) $(MISC_L_OBJS) $(SRT0_L_OBJ) \ + $(BOOT_L_OBJS) +.PARALLEL: $(UFSBOOT) $(HSFSBOOT) $(NFSBOOT) $(WANBOOT) + +all: $(ELFCONV) $(UFSBOOT) $(HSFSBOOT) $(NFSBOOT) $(WANBOOT) + +$(STRIPALIGN): $(CMN_DIR)/$$(@).c + $(NATIVECC) -o $@ $(CMN_DIR)/$@.c + +# 4.2 ufs filesystem booter +# +# Libraries used to build ufsboot +# +LIBUFS_LIBS = libufs.a libnames.a libsa.a libprom.a $(LIBPLAT_LIBS) +UFS_LIBS = $(LIBUFS_LIBS:lib%.a=-l%) +UFS_DIRS = $(LIBNAME_DIR:%=-L%) $(LIBSYS_DIR:%=-L%) +UFS_DIRS += $(LIBPLAT_DIR:%=-L%) $(LIBPROM_DIR:%=-L%) + +# +# Note that the presumption is that someone has already done a `make +# install' from usr/src/stand/lib, such that all of the standalone +# libraries have been built and placed in $ROOT/stand/lib. +# +LIBDEPS= $(LIBPROM_DIR)/libprom.a $(LIBPLAT_DEP) \ + $(LIBNAME_DIR)/libnames.a + +L_LIBDEPS= $(LIBPROM_DIR)/llib-lprom.ln $(LIBPLAT_DEP_L) \ + $(LIBNAME_DIR)/llib-lnames.ln + +# +# Loader flags used to build ufsboot +# +UFS_MAPFILE = $(MACH_DIR)/mapfile +UFS_LDFLAGS = -dn -M $(UFS_MAPFILE) -e _start $(UFS_DIRS) +UFS_L_LDFLAGS = $(UFS_DIRS) + +# +# Object files used to build ufsboot +# +UFS_SRT0 = $(SRT0_OBJ) +UFS_OBJS = $(OBJS) ufsconf.o boot.o +UFS_L_OBJS = $(UFS_SRT0:%.o=%.ln) $(UFS_OBJS:%.o=%.ln) + +# +# Build rules to build ufsboot +# + +$(UFSBOOT).elf: $(UFS_MAPFILE) $(UFS_SRT0) $(UFS_OBJS) $(LIBDEPS) + $(LD) $(UFS_LDFLAGS) -o $@ $(UFS_SRT0) $(UFS_OBJS) $(UFS_LIBS) + $(MCS) -d $@ + $(POST_PROCESS) + $(POST_PROCESS) + $(MCS) -c $@ + +$(UFSBOOT): $(UFSBOOT).elf + $(RM) $@; cp $@.elf $@ + $(STRIP) $@ + +$(UFSBOOT)_lint: $(L_LIBDEPS) $(UFS_L_OBJS) + @echo "" + @echo ufsboot lint: global crosschecks: + $(LINT.c) $(UFS_L_LDFLAGS) $(UFS_L_OBJS) $(UFS_LIBS) + +# WANboot booter +# +# Libraries used to build wanboot +# +# EXPORT DELETE START +LIBWANBOOT = libwanboot.a +LIBSCRYPT = libscrypt.a +LIBSSL = libssl.a +LIBCRYPTO = libcrypto.a +# EXPORT DELETE END + +LIBWAN_LIBS = \ + $(LIBWANBOOT) \ + libnvpair.a libufs.a libhsfs.a libnfs.a \ + libxdr.a libnames.a libsock.a libinet.a libtcp.a \ + $(LIBSCRYPT) $(LIBSSL) $(LIBCRYPTO) \ + libmd5.a libsa.a libprom.a \ + $(LIBSSL) \ + $(LIBPLAT_LIBS) +WAN_LIBS = $(LIBWAN_LIBS:lib%.a=-l%) +WAN_DIRS = $(LIBNAME_DIR:%=-L%) $(LIBSYS_DIR:%=-L%) +WAN_DIRS += $(LIBPLAT_DIR:%=-L%) $(LIBPROM_DIR:%=-L%) + +# +# Loader flags used to build wanboot +# +WAN_MAPFILE = $(MACH_DIR)/mapfile +WAN_LDFLAGS = -dn -M $(WAN_MAPFILE) -e _start $(WAN_DIRS) +WAN_L_LDFLAGS = $(WAN_DIRS) + +# +# Object files used to build wanboot +# +WAN_SRT0 = $(SRT0_OBJ) +WAN_OBJS = $(OBJS) wbfsconf.o wbcli.o wanboot.o ramdisk.o +WAN_L_OBJS = $(WAN_SRT0:%.o=%.ln) $(WAN_OBJS:%.o=%.ln) + +# +# Build rules to build wanboot +# + +$(WANBOOT).elf: $(WAN_MAPFILE) $(WAN_SRT0) $(WAN_OBJS) $(LIBDEPS) + $(LD) $(WAN_LDFLAGS) -o $@ $(WAN_SRT0) $(WAN_OBJS) $(WAN_LIBS) + $(MCS) -d $@ + $(POST_PROCESS) + $(POST_PROCESS) + $(MCS) -c $@ + +$(WANBOOT): $(WANBOOT).elf + $(RM) $@; cp $@.elf $@ + $(STRIP) $@ + +$(WANBOOT)_lint: $(L_LIBDEPS) $(WAN_L_OBJS) + @echo "" + @echo wanboot lint: global crosschecks: + $(LINT.c) $(WAN_L_LDFLAGS) $(WAN_L_OBJS) $(WAN_LIBS) + +# High-sierra filesystem booter. Probably doesn't work. + +# +# Libraries used to build hsfsboot +# +LIBHSFS_LIBS = libhsfs.a libnames.a libsa.a libprom.a $(LIBPLAT_LIBS) +HSFS_LIBS = $(LIBHSFS_LIBS:lib%.a=-l%) +HSFS_DIRS = $(LIBNAME_DIR:%=-L%) $(LIBSYS_DIR:%=-L%) +HSFS_DIRS += $(LIBPLAT_DIR:%=-L%) $(LIBPROM_DIR:%=-L%) + +# +# Loader flags used to build hsfsboot +# +HSFS_MAPFILE = $(MACH_DIR)/mapfile +HSFS_LDFLAGS = -dn -M $(HSFS_MAPFILE) -e _start $(HSFS_DIRS) +HSFS_L_LDFLAGS = $(HSFS_DIRS) + +# +# Object files used to build hsfsboot +# +HSFS_SRT0 = $(SRT0_OBJ) +HSFS_OBJS = $(OBJS) hsfsconf.o boot.o +HSFS_L_OBJS = $(HSFS_SRT0:%.o=%.ln) $(HSFS_OBJS:%.o=%.ln) + +$(HSFSBOOT).elf: $(HSFS_MAPFILE) $(HSFS_SRT0) $(HSFS_OBJS) $(LIBDEPS) + $(LD) $(HSFS_LDFLAGS) -o $@ $(HSFS_SRT0) $(HSFS_OBJS) $(HSFS_LIBS) + $(MCS) -d $@ + $(POST_PROCESS) + $(POST_PROCESS) + $(MCS) -c $@ + +$(HSFSBOOT): $(HSFSBOOT).elf + $(RM) $(@); cp $@.elf $@ + $(STRIP) $@ + +$(HSFSBOOT)_lint: $(HSFS_L_OBJS) $(L_LIBDEPS) + @echo "" + @echo hsfsboot lint: global crosschecks: + $(LINT.c) $(HSFS_L_LDFLAGS) $(HSFS_L_OBJS) $(HSFS_LIBS) + +# NFS booter + +# +# Libraries used to build nfsboot +# +LIBNFS_LIBS = libnfs.a libxdr.a libnames.a \ + libsock.a libinet.a libtcp.a libsa.a libprom.a \ + $(LIBPLAT_LIBS) +NFS_LIBS = $(LIBNFS_LIBS:lib%.a=-l%) +NFS_DIRS = $(LIBNAME_DIR:%=-L%) $(LIBSYS_DIR:%=-L%) +NFS_DIRS += $(LIBPLAT_DIR:%=-L%) $(LIBPROM_DIR:%=-L%) + +# +# Loader flags used to build inetboot +# +NFS_MAPFILE = $(MACH_DIR)/mapfile +NFS_LDFLAGS = -dn -M $(NFS_MAPFILE) -e _start $(NFS_DIRS) +NFS_L_LDFLAGS = $(NFS_DIRS) + +# +# Object files used to build inetboot +# +NFS_SRT0 = $(SRT0_OBJ) +NFS_OBJS = $(OBJS) nfsconf.o boot.o +NFS_L_OBJS = $(NFS_SRT0:%.o=%.ln) $(NFS_OBJS:%.o=%.ln) + +$(NFSBOOT).elf: $(ELFCONV) $(NFS_MAPFILE) $(NFS_SRT0) $(NFS_OBJS) $(LIBDEPS) + $(LD) $(NFS_LDFLAGS) -o $@ $(NFS_SRT0) $(NFS_OBJS) $(NFS_LIBS) + $(MCS) -d $@ + $(POST_PROCESS) + $(POST_PROCESS) + $(MCS) -c $@ + +# +# This is a bit strange because some platforms boot elf and some don't. +# So this rule strips the file no matter which ELFCONV is used. +# +$(NFSBOOT): $(NFSBOOT).elf + $(RM) $@.tmp; cp $@.elf $@.tmp; $(STRIP) $@.tmp + $(RM) $@; $(ELFCONV) $@.tmp $@; $(RM) $@.tmp + +$(NFSBOOT)_lint: $(NFS_L_OBJS) $(L_LIBDEPS) + @echo "" + @echo inetboot lint: global crosschecks: + $(LINT.c) $(NFS_L_LDFLAGS) $(NFS_L_OBJS) $(NFS_LIBS) + +include $(BOOTSRCDIR)/Makefile.rules + +install: $(ROOT_PSM_WANBOOT) + +clean: + $(RM) make.out lint.out + $(RM) $(OBJS) $(CONF_OBJS) $(MISC_OBJS) $(BOOT_OBJS) $(SRT0_OBJ) + $(RM) $(NFSBOOT).elf $(UFSBOOT).elf $(HSFSBOOT).elf $(WANBOOT).elf + $(RM) $(L_OBJS) $(CONF_L_OBJS) $(MISC_L_OBJS) $(BOOT_L_OBJS) \ + $(SRT0_L_OBJ) + +clobber: clean + $(RM) $(UFSBOOT) $(HSFSBOOT) $(NFSBOOT) $(WANBOOT) $(STRIPALIGN) + +lint: $(UFSBOOT)_lint $(NFSBOOT)_lint $(WANBOOT)_lint + +include $(BOOTSRCDIR)/Makefile.targ diff --git a/usr/src/psm/stand/boot/sparcv9/sun4u/Makefile b/usr/src/psm/stand/boot/sparcv9/sun4u/Makefile new file mode 100644 index 0000000000..b81cbc1c07 --- /dev/null +++ b/usr/src/psm/stand/boot/sparcv9/sun4u/Makefile @@ -0,0 +1,144 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +TOPDIR = ../../../../.. + +include $(TOPDIR)/uts/Makefile.uts + +MODULE = fs + +PLATLINKS = SUNW,Ultra-2 +PLATLINKS += SUNW,Ultra-250 +PLATLINKS += SUNW,Ultra-4 +PLATLINKS += SUNW,Ultra-Enterprise +PLATLINKS += SUNW,Ultra-Enterprise-10000 +PLATLINKS += SUNW,UltraSPARC-IIi-Netract +PLATLINKS += SUNW,UltraSPARC-IIe-NetraCT-40 +PLATLINKS += SUNW,UltraSPARC-IIe-NetraCT-60 +PLATLINKS += SUNW,Sun-Blade-100 +PLATLINKS += SUNW,Sun-Blade-1000 +PLATLINKS += SUNW,Sun-Blade-1500 +PLATLINKS += SUNW,Sun-Blade-2500 +PLATLINKS += SUNW,A70 +PLATLINKS += SUNW,Sun-Fire +PLATLINKS += SUNW,Sun-Fire-V240 +PLATLINKS += SUNW,Sun-Fire-V250 +PLATLINKS += SUNW,Sun-Fire-V440 +PLATLINKS += SUNW,Sun-Fire-280R +PLATLINKS += SUNW,Sun-Fire-15000 +PLATLINKS += SUNW,Sun-Fire-880 +PLATLINKS += SUNW,Sun-Fire-480R +PLATLINKS += SUNW,Sun-Fire-V890 +PLATLINKS += SUNW,Sun-Fire-V490 +PLATLINKS += SUNW,Serverblade1 +PLATLINKS += SUNW,Netra-T12 +PLATLINKS += SUNW,Netra-T4 +PLATLINKS += SUNW,Netra-CP2300 + +LINKED_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%) +LINKED_LIB_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib) +LINKED_LIB_FS_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib/fs) + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean + +TARG_MACH = sparcv9 +TARG_MACH_DIR = sparcv9 +ARCHVERS = v9 +PLATFORM = sun4u +ARCHMMU = sfmmu +PROMVERS = ieee1275 +ASFLAGS += $(sparcv9_XARCH) + +PLAT_C_SRC = machdep.c +ARCH_C_SRC = sun4u_memlist.c sun4x_standalloc.c sun4dep.c +ARCH_S_SRC = sparcv9_subr.s +SRT0_S = sun4u_srt0.s +INLINES = + +LDFLAGS += -L$(TOPDIR)/psm/stand/lib/promif/$(TARG_MACH)/$(PROMVERS)/common + +# +# The following libraries are build in LIBPLAT_DIR +# +LIBPLAT_DIR = $(TOPDIR)/psm/stand/lib/promif/$(TARG_MACH)/$(PROMVERS)/$(PLATFORM) +LIBPLAT_LIBS = libplat.a +LIBPLAT_L_LIBS= $(LIBPLAT_LIBS:lib%.a=llib-l%.ln) +LIBPLAT_DEP = $(LIBPLAT_DIR)/$(LIBPLAT_LIBS) +LIBPLAT_DEP_L = $(LIBPLAT_DIR)/$(LIBPLAT_L_LIBS) + +# +# Platform specific libraries +# +PSMLIBS += $(LIBPLAT_LIBS:lib%.a=-l%) +PSMLIB_DIRS += $(LIBPLAT_DIR) + + +# MPSAS support +MPSAS_BUILD:sh= echo \\043 +$(MPSAS_BUILD)ARCHOPTS += -DMPSAS + +include ../Makefile.com + +# re-define ELFCONV for 4u--- sun4u can boot ELF directly +ELFCONV = /usr/bin/cp + +# Don't need mapfile.inet for 4u inetboot +NFS_MAPFILE = $(MACH_DIR)/mapfile + +# +# Set the choice of compiler. + +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) + +# +# XXX this totally sucks since it effectively turns off -errchk=longptr64, +# which we really should be using. +# +LINTFLAGS64 = $(LINTFLAGS) -Xarch=v9 + +# +# Cross-reference customization: include all boot-related source files. +# +UTSDIR= ../../../../../uts +STANDLIBDIR= ../../../../../stand/lib +STANDSYSDIR= ../../../../../stand/sys +PROMDIRS= ../../../../promif +NAMESDIRS= ../../../lib/names/sparcv9 ../../../lib/names/sparc/common +XRDIRS += ../../sparc/common ../../common $(STANDLIBDIR) \ + $(STANDSYSDIR) $(PROMDIRS) $(NAMESDIRS) +XRDEL = sun4x_srt0* sun4x_memlist* +XRPRUNE = i86pc i386 + +cscope.out tags: FRC + $(XREF) -x $@ + +FRC: diff --git a/usr/src/psm/stand/boot/sparcv9/sun4u/machdep.c b/usr/src/psm/stand/boot/sparcv9/sun4u/machdep.c new file mode 100644 index 0000000000..48b1bcadf8 --- /dev/null +++ b/usr/src/psm/stand/boot/sparcv9/sun4u/machdep.c @@ -0,0 +1,173 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/promif.h> +#include <sys/prom_plat.h> +#include <sys/salib.h> + +int vac = 1; + +/* + * Check if the CPU should default to 64-bit or not. + * UltraSPARC-1's default to 32-bit mode. + * Everything else defaults to 64-bit mode. + */ + +/* + * Manufacturer codes for the CPUs we're interested in + */ +#define TI_JEDEC 0x17 +#define SUNW_JEDEC 0x22 + +/* + * Implementation codes for the CPUs we're interested in + */ +#define IMPL_US_I 0x10 + +static dnode_t +visit(dnode_t node) +{ + int impl, manu; + char name[32]; + static char ultrasparc[] = "SUNW,UltraSPARC"; + static char implementation[] = "implementation#"; + static char manufacturer[] = "manufacturer#"; + + /* + * if name isn't 'SUNW,UltraSPARC', continue. + */ + if (prom_getproplen(node, "name") != sizeof (ultrasparc)) + return ((dnode_t)0); + (void) prom_getprop(node, "name", name); + if (strncmp(name, ultrasparc, sizeof (ultrasparc)) != 0) + return ((dnode_t)0); + + if (prom_getproplen(node, manufacturer) != sizeof (int)) + return ((dnode_t)0); + (void) prom_getprop(node, manufacturer, (caddr_t)&manu); + + if ((manu != SUNW_JEDEC) && (manu != TI_JEDEC)) + return ((dnode_t)0); + + if (prom_getproplen(node, implementation) != sizeof (int)) + return ((dnode_t)0); + (void) prom_getprop(node, implementation, (caddr_t)&impl); + + if (impl != IMPL_US_I) + return ((dnode_t)0); + + return (node); +} + +/* + * visit each node in the device tree, until we get a non-null answer + */ +static dnode_t +walk(dnode_t node) +{ + dnode_t id; + + if (visit(node)) + return (node); + + for (node = prom_childnode(node); node; node = prom_nextnode(node)) + if ((id = walk(node)) != (dnode_t)0) + return (id); + + return ((dnode_t)0); +} + +/* + * Check if the CPU is an UltraSPARC-1 or not. + */ +int +cpu_is_ultrasparc_1(void) +{ + static int cpu_checked; + static int cpu_default; + + /* + * If we already checked, we already know the answer. + */ + if (cpu_checked == 0) { + if (walk(prom_rootnode())) + cpu_default = 1; + cpu_checked = 1; + } + + return (cpu_default); +} + +/* + * Retain a page or reclaim a previously retained page of physical + * memory for use by the prom upgrade. If successful, leave + * an indication that a page was retained by creating a boolean + * property in the root node. + * + * XXX: SUNW,retain doesn't work as expected on server systems, + * so we don't try to retain any memory on those systems. + * + * XXX: do a '0 to my-self' as a workaround for 4160914 + */ + +int dont_retain_memory; + +void +retain_nvram_page(void) +{ + unsigned long long phys = 0; + int len; + char name[32]; + static char create_prop[] = + "0 to my-self dev / 0 0 \" boot-retained-page\" property"; + static char ue10000[] = "SUNW,Ultra-Enterprise-10000"; + static char ue[] = "SUNW,Ultra-Enterprise"; + extern int verbosemode; + + if (dont_retain_memory) + return; + + len = prom_getproplen(prom_rootnode(), "name"); + if ((len != -1) && (len <= sizeof (name))) { + (void) prom_getprop(prom_rootnode(), "name", name); + if ((strcmp(name, ue) == 0) || (strcmp(name, ue10000) == 0)) + return; + } + + if (prom_retain("OBPnvram", PAGESIZE, PAGESIZE, &phys) != 0) { + printf("prom_retain failed\n"); + return; + } + if (verbosemode) + printf("retained OBPnvram page at 0x%llx\n", phys); + + prom_interpret(create_prop, 0, 0, 0, 0, 0); +} diff --git a/usr/src/psm/stand/boot/sparcv9/sun4v/Makefile b/usr/src/psm/stand/boot/sparcv9/sun4v/Makefile new file mode 100644 index 0000000000..8005ea80df --- /dev/null +++ b/usr/src/psm/stand/boot/sparcv9/sun4v/Makefile @@ -0,0 +1,121 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +TOPDIR = ../../../../.. + +include $(TOPDIR)/uts/Makefile.uts + +MODULE = fs + +PLATLINKS = SUNW,Sun-Fire-T200 + +LINKED_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%) +LINKED_LIB_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib) +LINKED_LIB_FS_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib/fs) + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean + +TARG_MACH = sparcv9 +TARG_MACH_DIR = sparcv9 +ARCHVERS = v9 +PLATFORM = sun4v +ARCHMMU = sfmmu +PROMVERS = ieee1275 +ASFLAGS += $(sparcv9_XARCH) + +PLAT_C_SRC = machdep.c +ARCH_C_SRC = sun4u_memlist.c sun4x_standalloc.c sun4dep.c +ARCH_S_SRC = sparcv9_subr.s +SRT0_S = sun4u_srt0.s +INLINES = + +LDFLAGS += -L$(TOPDIR)/psm/stand/lib/promif/$(TARG_MACH)/$(PROMVERS)/common + +# +# The following libraries are build in LIBPLAT_DIR +# +LIBPLAT_DIR = $(TOPDIR)/psm/stand/lib/promif/$(TARG_MACH)/$(PROMVERS)/$(PLATFORM) +LIBPLAT_LIBS = libplat.a +LIBPLAT_L_LIBS= $(LIBPLAT_LIBS:lib%.a=llib-l%.ln) +LIBPLAT_DEP = $(LIBPLAT_DIR)/$(LIBPLAT_LIBS) +LIBPLAT_DEP_L = $(LIBPLAT_DIR)/$(LIBPLAT_L_LIBS) + +# +# Platform specific libraries +# +PSMLIBS += $(LIBPLAT_LIBS:lib%.a=-l%) +PSMLIB_DIRS += $(LIBPLAT_DIR) + + +# MPSAS support +MPSAS_BUILD:sh= echo \\043 +$(MPSAS_BUILD)ARCHOPTS += -DMPSAS + +include ../Makefile.com + +CPPINCS += -I$(SRC)/uts/sun4u +CPPINCS += -I$(ROOT)/usr/platform/sun4u/include + +# re-define ELFCONV for 4v--- sun4v can boot ELF directly +ELFCONV = /usr/bin/cp + +# Don't need mapfile.inet for 4v inetboot +NFS_MAPFILE = $(MACH_DIR)/mapfile + +# +# Set the choice of compiler. + +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) + +# +# XXX this totally sucks since it effectively turns off -errchk=longptr64, +# which we really should be using. +# +LINTFLAGS64 = $(LINTFLAGS) -Xarch=v9 + +# +# Cross-reference customization: include all boot-related source files. +# +UTSDIR= ../../../../../uts +STANDLIBDIR= ../../../../../stand/lib +STANDSYSDIR= ../../../../../stand/sys +PROMDIRS= ../../../../promif +NAMESDIRS= ../../../lib/names/sparcv9 ../../../lib/names/sparc/common +XRDIRS += ../../sparc/common ../../common $(STANDLIBDIR) \ + $(STANDSYSDIR) $(PROMDIRS) $(NAMESDIRS) +XRDEL = sun4x_srt0* sun4x_memlist* +XRPRUNE = i86pc i386 + +cscope.out tags: FRC + $(XREF) -x $@ + +FRC: diff --git a/usr/src/psm/stand/boot/sparcv9/sun4v/machdep.c b/usr/src/psm/stand/boot/sparcv9/sun4v/machdep.c new file mode 100644 index 0000000000..cada0384e2 --- /dev/null +++ b/usr/src/psm/stand/boot/sparcv9/sun4v/machdep.c @@ -0,0 +1,80 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/promif.h> +#include <sys/prom_plat.h> +#include <sys/salib.h> + +int vac = 0; + +/* + * Check if the CPU is an UltraSPARC-1 or not. + */ +int +cpu_is_ultrasparc_1(void) +{ + return (0); +} + +/* + * Retain a page or reclaim a previously retained page of physical + * memory for use by the prom upgrade. If successful, leave + * an indication that a page was retained by creating a boolean + * property in the root node. + * + * XXX: SUNW,retain doesn't work as expected on server systems, + * so we don't try to retain any memory on those systems. + * + * XXX: do a '0 to my-self' as a workaround for 4160914 + */ + +int dont_retain_memory; + +void +retain_nvram_page(void) +{ + unsigned long long phys = 0; + static char create_prop[] = + "0 to my-self dev / 0 0 \" boot-retained-page\" property"; + extern int verbosemode; + + if (dont_retain_memory) + return; + + if (prom_retain("OBPnvram", PAGESIZE, PAGESIZE, &phys) != 0) { + printf("prom_retain failed\n"); + return; + } + if (verbosemode) + printf("retained OBPnvram page at 0x%llx\n", phys); + + prom_interpret(create_prop, 0, 0, 0, 0, 0); +} diff --git a/usr/src/psm/stand/bootblks/Makefile b/usr/src/psm/stand/bootblks/Makefile new file mode 100644 index 0000000000..81530b7c2b --- /dev/null +++ b/usr/src/psm/stand/bootblks/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994 by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/Makefile +# +include ../../../Makefile.master + +SUBDIRS = ufs hsfs + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/bootblks/Makefile.1275 b/usr/src/psm/stand/bootblks/Makefile.1275 new file mode 100644 index 0000000000..1066fef16c --- /dev/null +++ b/usr/src/psm/stand/bootblks/Makefile.1275 @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# +# psm/stand/bootblks/Makefile.1275 +# + +# +# Sources and objects used to build the Forth-based bootblock +# for all Sun OpenFirmware machines (IEEE Std. 1275) +# +# Same names for both filesystems. +# +FORTH_SRC = boot_1275.fth +FORTH_FCODE = $(FORTH_SRC:%.fth=%.fcode) + +# +# Targets +# +$(PROG): $(FORTH_FCODE) + @-$(RM) $@ + cp -p $(FORTH_FCODE) $@ + +clean: + -$(RM) $(FORTH_FCODE) + +clobber: clean + -$(RM) $(PROG) + +lint: FRC + +FRC: + diff --git a/usr/src/psm/stand/bootblks/Makefile.com b/usr/src/psm/stand/bootblks/Makefile.com new file mode 100644 index 0000000000..9d4ddab575 --- /dev/null +++ b/usr/src/psm/stand/bootblks/Makefile.com @@ -0,0 +1,94 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 1994-2003 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/bootblks/Makefile.com +# +TOPDIR = ../../../$(BASEDIR) + +# +# Hack until stand makefiles are fixed +# +CLASS = 32 + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/Makefile.psm + +STANDDIR = $(TOPDIR)/stand +PSMSTANDDIR = $(TOPDIR)/psm/stand + +SYSHDRDIR = $(STANDDIR) +SYSLIBDIR = $(ROOT)/stand/lib + +PSMSYSHDRDIR = $(PSMSTANDDIR) +PSMNAMELIBDIR = $(PSMSTANDDIR)/lib/names/$(MACH) +PSMPROMLIBDIR = $(PSMSTANDDIR)/lib/promif/$(MACH) + +# +# 'bootblk' is the basic target we build - in many flavours +# +PROG = bootblk + +# +# Used to convert Forth source to isa-independent FCode. +# +TOKENIZE = tokenize + +# +# Common install modes and owners +# +FILEMODE = 444 +DIRMODE = 755 +OWNER = root +GROUP = sys + +# +# Lint rules (adapted from Makefile.uts) +# +LHEAD = ( $(ECHO) "\n$@"; +LGREP = grep -v "pointer cast may result in improper alignment" +LTAIL = ) 2>&1 | $(LGREP) +LINT_DEFS += -Dlint + +# +# For building lint objects +# +LINTFLAGS.c = -nsxum +LINT.c = $(LINT) $(LINTFLAGS.c) $(LINT_DEFS) $(CPPFLAGS) -c +LINT.s = $(LINT) $(LINTFLAGS.s) $(LINT_DEFS) $(CPPFLAGS) -c + +# +# For building lint libraries +# +LINTFLAGS.lib = -nsxum +LINT.lib = $(LINT) $(LINTFLAGS.lib) $(LINT_DEFS) $(CPPFLAGS) + +# +# For complete pass 2 cross-checks +# XXX: lint flags should exclude -u, but the standalone libs confuse lint. +# +LINTFLAGS.2 = -nsxum +LINT.2 = $(LINT) $(LINTFLAGS.2) $(LINT_DEFS) $(CPPFLAGS) diff --git a/usr/src/psm/stand/bootblks/Makefile.obp b/usr/src/psm/stand/bootblks/Makefile.obp new file mode 100644 index 0000000000..4572164d4b --- /dev/null +++ b/usr/src/psm/stand/bootblks/Makefile.obp @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# +# psm/stand/bootblks/Makefile.obp +# + +# +# Sources and objects used to build the Forth-based bootblock +# for Sun OBP V2 and V3 machines (using the romvec client interface) +# +# Same names for both filesystem versions. +# +FORTH_SRC = boot_obp.fth +FORTH_FCODE = $(FORTH_SRC:%.fth=%.fcode) + +# +# Targets +# +$(PROG): $(FORTH_FCODE) + @-$(RM) $@ + cp -p $(FORTH_FCODE) $@ + +clean: + -$(RM) $(FORTH_FCODE) + +clobber: clean + -$(RM) $(PROG) + +lint: FRC + +FRC: + diff --git a/usr/src/psm/stand/bootblks/Makefile.targ b/usr/src/psm/stand/bootblks/Makefile.targ new file mode 100644 index 0000000000..94257fc963 --- /dev/null +++ b/usr/src/psm/stand/bootblks/Makefile.targ @@ -0,0 +1,39 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/Makefile.targ +# + +# +# Targets common to all versions. +# +install: all $(USR_PSM_BOOTBLOCK) $(USR_PSM_UFS_DIR_LINKS) + +# +# Install rules +# +include $(TOPDIR)/Makefile.psm.targ diff --git a/usr/src/psm/stand/bootblks/hsfs/Makefile b/usr/src/psm/stand/bootblks/hsfs/Makefile new file mode 100644 index 0000000000..cfae7b9a31 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/Makefile @@ -0,0 +1,51 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1989-1994, by Sun Microsystems, Inc. +# +# psm/stand/bootblks/hsfs/Makefile +# +SUBDIRS = $(MACH) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber lint : $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +# +# XXX There's no point in installing the hsfs stuff if we +# never use it (or test it!) +# +install: FRC + +FRC: + diff --git a/usr/src/psm/stand/bootblks/hsfs/Makefile.hsfs b/usr/src/psm/stand/bootblks/hsfs/Makefile.hsfs new file mode 100644 index 0000000000..72ee6d8fd1 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/Makefile.hsfs @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# +# psm/stand/bootblks/hsfs/Makefile.hsfs +# +include $(BASEDIR)/Makefile.com +include $(BASEDIR)/hsfs/common/Makefile.com + +# +# Where stuff gets installed +# +USR_PSM_BOOTBLOCK = $(USR_PSM_LIB_HSFS_DIR)/$(PROG) diff --git a/usr/src/psm/stand/bootblks/hsfs/common/Makefile.com b/usr/src/psm/stand/bootblks/hsfs/common/Makefile.com new file mode 100644 index 0000000000..26b9823359 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/common/Makefile.com @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/hsfs/common/Makefile.com +# + +THISDIR = $(BASEDIR)/hsfs/common + +# +# Files that define the fs-reading capabilities of the C-based boot block +# +# uncomment following line if want to build big bootblk +# FS_C_SRCS = hsfs.c +# uncomment following line if want to build small bootblk +FS_C_SRCS = hsfs_small.c + +# +# Allow hsfs-specific files to find hsfs-specific include files +# +$(FS_C_SRCS:%.c=%.o) := CPPINCS += -I$(THISDIR) + +# +# Pattern-matching rules for source in this directory +# +%.o: $(THISDIR)/%.c + $(COMPILE.c) -o $@ $< + +%.ln: $(THISDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +%.fcode: $(THISDIR)/%.fth + $(TOKENIZE) $< diff --git a/usr/src/psm/stand/bootblks/hsfs/common/boot_obp.fth b/usr/src/psm/stand/bootblks/hsfs/common/boot_obp.fth new file mode 100644 index 0000000000..3ab085f7ba --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/common/boot_obp.fth @@ -0,0 +1,598 @@ +\ ident "%Z%%M% %I% %E% SMI" +\ purpose: Rock Ridge Boot Block +\ copyright: Copyright 2005 Sun Microsystems, Inc. All rights reserved. +\ copyright: Use is subject to license terms. +\ copyright: +\ copyright: CDDL HEADER START +\ copyright: +\ copyright: The contents of this file are subject to the terms of the +\ copyright: Common Development and Distribution License, Version 1.0 only +\ copyright: (the "License"). You may not use this file except in compliance +\ copyright: with the License. +\ copyright: +\ copyright: You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ copyright: or http://www.opensolaris.org/os/licensing. +\ copyright: See the License for the specific language governing permissions +\ copyright: and limitations under the License. +\ copyright: +\ copyright: When distributing Covered Code, include this CDDL HEADER in each +\ copyright: file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ copyright: If applicable, add the following below this CDDL HEADER, with the +\ copyright: fields enclosed by brackets "[]" replaced with your own identifying +\ copyright: information: Portions Copyright [yyyy] [name of copyright owner] +\ copyright: +\ copyright: CDDL HEADER END +\ copyright: + +\ High Sierra, Rock Ridge (CD-ROM) file system reader and boot block +\ Original HSFS code from Mitch Bradley, RR extensions by Sam Cramer + +\ There's some code in there that would be a shame to throw out, +\ but which currently doesn't fit in the boot block. This code is commented +\ out, with #ifdef style comment lines. The "options" are: +\ HSFSNAMES -- look at hsfs names if you can't find Rock Ridge names +\ PROCESS_CE -- process continuation (CE) signatures; this is +\ potentially useful, but it looks like the RR disks +\ we're dealing with don't use them, and it is a bit +\ of work to implement continuations. +\ PATHLOOKUP -- handle pathnames, not just filenames which are in +\ the root directory + +\ FIXME need some way of returning exceptions cleanly +\ The culprit is the "abort" in read-blocks + +\ Fcode-version1 +decimal +headerless + +\ +\ Forth utility routines +\ +\ : $find 2dup type cr $find ; + +: boot-eval ( adr len -- ) + $find if + execute + else + type ." ?" cr exit + then +; + +\ " romvec" boot-eval constant romvec +variable boot-romvec + +: find-romvec + " romvec" $find if + execute + else + 2drop h# ffe8.0010 + then + boot-romvec ! +; + +find-romvec + +: roment ( offset -- adr ) boot-romvec @ + l@ ; + +" load-base" $find drop constant 'loadbase +\ " (is" $find drop constant '(is +\ " $=" $find drop constant '$= +" call" $find drop constant 'call + +: loadbase ( -- adr ) 'loadbase execute ; +\ : (is ( val acf -- ) '(is execute ; +\ : $= ( str1 str2 -- [ -1 | 0 | 1 ] ) '$= execute ; +: call ( ... addr -- ??? ) 'call execute ; +: loadbase! ( value -- ) 'loadbase " (is" boot-eval ; + + +\ defer open-disk ( -- ) +\ defer read-dev-bytes ( adr len byte# -- error? ) +\ defer close-disk ( -- ) + + +: devname ( -- cstr ) + h# 88 roment @ \ bootpath +; + +\ Debug V2 or later PROMs +\ : devname " /sbus/esp/sd@3,0:b" drop ; + + +\ Debug V0 PROMS +\ : devname " sd(0,0,0)" drop ; + +variable devid +: open-disk ( -- error? ) + devname + " op-open" + boot-eval dup if + dup devid ! + then + 0= ( invert sense of error flag ) +; + +: close-disk ( -- ) + devid @ " op-close" boot-eval drop +; + +: read-blks ( adr len -- error? ) + ( len adr devid -- #bytes_read ) + tuck swap devid @ " op-read" boot-eval <> +; + +: seek ( low high -- error? ) + ( low high devid -- ? ) + devid @ " op-seek" boot-eval 0< +; + +: read-dev-bytes ( adr len byte# -- error? ) + 0 seek ?dup if exit then + ( adr len ) read-blks +; + +\ : xl@ ( adr -- l ) la1+ unaligned-l@ ; \ For big-endian machines +\ unaligned-l@ is not define in OBP... +: xl@ ( adr -- l ) \ For big-endian machines + dup c@ swap ( c1 adr ) + 1+ dup c@ swap ( c0 c1 adr+1 ) + 1+ dup c@ swap ( c0 c1 c2 adr+2 ) + 1+ c@ ( c0 c1 c2 c3 ) + 8 << + 8 << + 8 << + +; + +\ : xl@ ( adr -- l ) unaligned-l@ ; \ For little-endian machines +: xw@ ( adr -- w ) dup c@ swap 1+ c@ 8 << + ; + +\ compare two strings for equality +: $= ( adr1 len1 adr2 len2 -- same? ) + rot over = if ( adr1 adr2 len2 ) + comp 0= + else + 2drop drop false + then +; + +0 value dir-buf \ buffer for current directory block +0 value sua-buf \ buffer for current sua block +0 value vol-desc \ volume descriptor + +2048 constant /sector + +16 constant vol-desc-sector# ( -- n ) + +\ logical block size (from volume descriptor) +: /block ( -- n ) vol-desc 128 + xw@ ; + +\ root directory entry (in volume descriptor) +: root-dirent ( -- adr ) vol-desc 156 + ; + +: release ( -- ) + dir-buf /block free-mem + sua-buf /block free-mem + vol-desc /sector free-mem + close-disk +; + +: read-abort ( adr len byte# -- error? ) +\ read-dev-bytes if release ." Disk read failed" abort then + 0 seek ?dup if exit then + read-blks drop \ Ignore error code !! +; + +: get-vol-desc ( -- ) + vol-desc /sector vol-desc-sector# /sector * read-abort +; + +\ **** Allocate memory for necessary data structures +: allocate-hsfs-buffers ( -- ) + /sector alloc-mem is vol-desc + get-vol-desc + /block alloc-mem is dir-buf + /block alloc-mem is sua-buf +; + +\ File handles + +\ #ifdef HSFSNAMES +\ \ Remove any version number ( ;nnn ) from the name. +\ : -version ( adr len -- adr len' ) +\ 2dup +\ bounds ?do ( adr len ) +\ \ If a ; is located, set len to the length before the ; +\ i c@ ascii ; = +\ if drop i over - leave then ( adr len' ) +\ loop +\ ; +\ #endif HSFSNAMES + +0 value file-desc \ points to current dir entry +0 value sua-desc \ points to current SUA entry + +: select-file ( adr -- ) is file-desc ; +: +fd ( n -- adr ) file-desc + ; +: file-extent ( -- n ) 2 +fd xl@ ; +: filesize ( -- n ) 10 +fd xl@ ; + +: hsfs-file-name ( -- adr len ) 33 +fd 32 +fd c@ ; +: dir? ( -- flag ) 25 +fd c@ h# 02 and 0<> ; +: dir-len ( -- len ) file-desc c@ ; + +\ Directories + +variable dir-block0 \ First block number in the directory file +variable dir-size \ Number of bytes in the directory file + +variable dir-block# \ Next block number in the directory file +variable dir-last-block# \ Last block number in the directory file +variable diroff \ Offset into the current directory block +variable totoff \ Total offset into the directory + +\ RR fields + +\ SUAs +variable sua-off \ Offset into the current sua entry +: select-sua ( adr -- ) is sua-desc ; +: +suad ( n -- adr ) sua-desc + ; + +\ return address of SUA, = addr of filename + len(filename) + 0/1 byte pad +: file-sua ( -- adr ) + hsfs-file-name dup ( addr len len ) + \ add in pad: 1 if len is even, 0 if odd + 2 mod 0= if 1 else 0 then + ( addr len' ) + + +; + +: suf-sig ( -- adr len ) sua-desc 2 ; \ signature bytes +: suf-len ( -- len ) 2 +suad c@ ; \ suf length + +\ #ifdef PROCESS_CE +\ \ location of continuation area, if parsed CE signature +\ variable ce-lbn +\ variable ce-offset +\ variable ce-len +\ +\ \ CE signature, continuation block +\ : suf-parse-ce-lbn ( -- loc ) 4 +suad xl@ ; \ location of cont +\ : suf-parse-ce-offset ( -- n ) 12 +suad xl@ ; \ offset of cont +\ : suf-parse-ce-len ( -- n ) 20 +suad xl@ ; \ len of cont +\ +\ : clear-cont-flags ( -- ) 0 ce-lbn ! 0 ce-len ! 0 ce-offset ! ; +\ +\ \ read the continuation area specified by CE signature +\ : read-cont ( -- ) sua-buf /block ce-lbn /sector * read-abort ; +\ #endif /* PROCESS_CE */ + +\ NM signature, alternate name +: suf-parse-nm ( -- addr len ) + 5 +suad + suf-len 5 - +; + +\ current suf is at or past end of the sua? +: end-sua ( -- end? ) + \ if (sua-off >= block size) then return (true); + \ if (sua-desc[0] == 0 || sua-desc[1] == 0) then return (true); + \ return (len(sua entry) == 0) + sua-off @ /block >= if true exit then + sua-desc c@ 0= if true exit then + 1 +suad c@ 0= if true exit then + suf-len 0= +; + +\ select the next system use field +: next-suf ( -- ) + \ sua-off += len(suf); sua-desc += len(suf); + suf-len dup sua-off +! +suad select-sua +; + +\ return the rock ridge file name associated with the current +\ dir-ent; returns 0 0 if can't find name. +\ ignores continuations +: rr-file-name ( -- adr len ) + \ select start of sua, record sua offset + file-sua select-sua + diroff @ sua-off ! + \ while (1) do + \ if (end of sua) { + \ break + \ } + \ if parse(sua) == 'NM' return suf-parse-nm; + \ next-suf; + \ done + begin + end-sua if 0 0 exit then + suf-sig + " NM" $= if suf-parse-nm exit then + next-suf + false + until +; + +\ #ifdef PROCESS_CE +\ \ Alternate verson of rr-file-name which chases continuations +\ \ +\ \ return the rock ridge file name associated with the current +\ \ dir-ent; returns 0 0 if can't find name. +\ \ chases continuations +\ : rr-file-name ( -- adr len ) +\ clear-cont-flags +\ \ select start of sua, record sua offset +\ file-sua select-sua +\ diroff @ sua-off ! +\ \ while (1) do +\ \ if (end of sua) { +\ \ if (ce-lbn) +\ \ read-continuation; +\ \ clear-continuation-info; +\ \ fiddle sua pointers; +\ \ else +\ \ break; +\ \ } +\ \ if parse(sua) == 'NM' return suf-parse-nm; +\ \ if parse(sua) == 'CE' +\ \ ce-lbn = suf-parse-ce-lbn(); +\ \ ce-len = suf-parse-ce-len(); +\ \ ce-offset = suf-parse-ce-offset(); +\ \ next-suf; +\ \ done +\ begin +\ end-sua if +\ ce-lbn @ if +\ read-cont +\ clear-cont-flags +\ sua-buf select-sua +\ 0 sua-off ! +\ end-sua if 0 0 exit then +\ else +\ 0 0 exit +\ then +\ then +\ suf-sig +\ 2dup " NM" $= if \ NM +\ 2drop suf-parse-nm exit +\ then +\ 2dup " CE" $= if \ CE +\ suf-parse-ce-lbn ce-lbn ! +\ suf-parse-ce-offset ce-offset ! +\ suf-parse-ce-len ce-len ! +\ \ XXX debug " had CE" type cr +\ then +\ 2drop +\ next-suf +\ false +\ until +\ ; +\ #endif /* PROCESS_CE */ + + +\ file name of dir entry +: file-name ( -- adr len ) + rr-file-name +\ #ifdef HSFSNAMES +\ \ if no rr name, use hsfs name minus version +\ dup 0= if 2drop hsfs-file-name -version then +\ #endif /* HSFSNAMES */ +; + +\ Read the next directory block, updating diroff and dir-block# +: get-dirblk ( -- ) + dir-buf /block dir-block# @ /block * read-abort + 0 diroff ! + 1 dir-block# +! +; + +\ **** Select the next directory entry +: next-file ( -- end? ) + \ diroff += len(dir entry); totoff += len(dir entry); + \ if (totoff >= dir-size) then return (true) + \ if (diroff = block size) then get-dirblk + \ if (len (next dir entry) == 0 && totoff < dir-size) then get-dirblk + \ file-desc = dir-buf + diroff + \ return (len(dir entry) == 0) + file-desc c@ dup diroff +! totoff +! + totoff @ dir-size @ >= if true exit then + diroff @ /block = if get-dirblk then + dir-buf diroff @ + c@ 0= + dir-block# @ dir-last-block# @ < + and if get-dirblk then + dir-buf diroff @ + select-file + file-desc c@ 0= +; + +\ **** Select the first file in the current directory +: reset-dir ( -- ) + dir-block0 @ dir-block# ! + get-dirblk + 0 totoff ! + dir-buf diroff @ + select-file + next-file drop next-file drop \ Skip the "parent" and "self" entries +; + +\ **** "cd" to the current file (read directory pointed to by dirent) +: set-dir ( -- ) + file-extent dir-block0 ! + filesize dir-size ! + filesize /block / dir-block0 @ + dir-last-block# ! + reset-dir +; + +\ **** Select the root directory +: froot ( -- ) root-dirent select-file set-dir ; + +: dir ( -- ) begin file-name type cr next-file until ; + + +\ search directory block for file name +: lookup ( adr len -- not-found? ) + \ #ifndef PATHLOOKUP + froot + \ #endif /* PATHLOOKUP */ + begin + 2dup file-name $= if 2drop false exit then + next-file + until + 2drop true +; + +\ #ifdef PATHLOOKUP +\ : /string ( adr len size -- adr+size len-size ) tuck - >r + r> ; +\ +\ \ Splits a string around a delimiter. If the delimiter is found, +\ \ two strings are returned under true, otherwise one string under false. +\ : $split ( adr len char -- remaining-adr,len [ initial-adr,len ] found? ) +\ 2 pick 2 pick bounds ?do +\ dup i c@ = if i nip -1 then +\ loop ( adr len adr' -1 | char ) +\ -1 = if ( adr len adr' ) +\ swap >r ( adr adr' ) ( r: len ) +\ 2dup swap - swap ( adr [adr'-adr] adr' ) ( r: len ) +\ 1+ r> ( adr [adr'-adr] adr'+1 len ) +\ 2 pick - 1- ( adr [adr'-adr] adr'+1 len-[adr'-adr-1] ) +\ 2swap true ( rem-adr,len initial-adr,len true ) +\ else +\ false +\ then +\ ; +\ +\ : path-lookup ( adr len -- not-found? ) +\ dup 0= if 2drop true exit then +\ over c@ ascii / = if 1 /string then +\ froot +\ begin +\ ascii / $split ( rem-adr,len [ adr,len ] delim-found? ) +\ while +\ lookup if ." Bad path" cr 2drop true exit then +\ dir? 0= if ." Bad path" cr 2drop true exit then +\ set-dir +\ repeat ( rem-adr,len ) +\ +\ \ Now we have found the directory containing the file +\ lookup if +\ ." File not found among: " cr +\ reset-dir dir +\ true +\ else +\ false \ File is already selected +\ then ( flag ) +\ ; +\ #endif /* PATHLOOKUP */ + +\ File reading +: read-file ( adr -- error? ) + filesize file-extent /block * read-dev-bytes ( error? ) +; + + +\ +\ ELF support +\ + +0 constant elfhdr +0 constant phdr + +: +w_elfhdr ( index -- value ) elfhdr swap ca+ w@ ; +: +l_elfhdr ( index -- value ) elfhdr swap ca+ l@ ; +: e_entry ( -- n ) 24 +l_elfhdr ; +: e_phoff ( -- n ) 28 +l_elfhdr ; +: e_phentsize ( -- n ) 42 +w_elfhdr ; +: e_phnum ( -- n ) 44 +w_elfhdr ; + +1 constant pt_load +: +phdr ( index -- value ) phdr swap la+ l@ ; +: p_type ( -- n ) 0 +phdr ; +: p_offset ( -- n ) 1 +phdr ; +: p_vaddr ( -- n ) 2 +phdr ; +: p_filesz ( -- n ) 4 +phdr ; +: p_memsz ( -- n ) 5 +phdr ; +\ : p_flags ( -- n ) 6 +phdr ; +\ : p_align ( -- n ) 7 +phdr ; + +: check-elf ( filebase -- is-elf? ) + l@ h# 7f454c46 ( \x7fELF ) = +; + +: get-phdr ( filebase index -- ) + e_phentsize * e_phoff + + + phdr e_phentsize move +; + +: load-elf ( filebase -- entry-point ) + dup is elfhdr + e_phentsize alloc-mem is phdr + e_phnum 0 ?do + dup i get-phdr + p_type pt_load = if + ( read it ) + dup p_offset + p_vaddr p_filesz move + p_memsz p_filesz > if + ( zero the bss ) + p_vaddr p_filesz + p_memsz p_filesz - 0 fill + then + then + loop drop + phdr e_phentsize free-mem + e_entry +; + +\ Installation + +: initialize ( -- ) + open-disk ?dup if exit then + allocate-hsfs-buffers +; + +hex +headers +( external ) + +: get-file ( load-adr name-adr name-len -- error? ) + initialize + \ #ifndef PATHLOOKUP + lookup if ." lookup failed" cr drop release true exit then + \ #else /* PATHLOOKUP */ + \ path-lookup if drop release true exit then + \ #endif /* PATHLOOKUP */ + dir? if + ." Requested file is a directory" cr drop release true exit + then + read-file ?dup if ." File read failed." cr exit then + filesize " file-size" boot-eval ! + release + false +; + +: reloc&go ( -- ) + loadbase + \ Is it ELF? + dup check-elf if ( base-adr ) + load-elf ( entry-point ) + loadbase! + " init-program" boot-eval + else ( base-adr ) +\ Let FORTH handle anything else + " adjust-header" boot-eval if + " init-program" boot-eval + then ( entry-point ) + loadbase! + then + 4000 loadbase! + " ?go" boot-eval +; + +\ +\ The boot stuff itself +\ +: do-boot + 4000 loadbase! + \ #ifndef PATHLOOKUP + loadbase " hsfsboot" get-file if + \ #else /* PATHLOOKUP */ + \ loadbase " /hsfsboot" get-file if + \ #endif /* PATHLOOKUP */ + ." Boot load failed." cr exit + then + reloc&go +; + +do-boot diff --git a/usr/src/psm/stand/bootblks/hsfs/common/hsfs.c b/usr/src/psm/stand/bootblks/hsfs/common/hsfs.c new file mode 100644 index 0000000000..2ff62f6c24 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/common/hsfs.c @@ -0,0 +1,683 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1991, 2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The routines in this file are called only after the PROM + * version has been determined to be sunMON. + * + * Basic file system reading code for standalone I/O system. + * Simulates a primitive UNIX I/O system (read(), write(), open(), etc). + * Does not support writes. + */ + +#include <sys/param.h> +#include <sys/saio.h> +#include <sys/sysmacros.h> +#include <sys/vnode.h> +#include <sys/fs/ufs_fsdir.h> +#include <sys/fs/ufs_fs.h> +#include <sys/fs/ufs_inode.h> + +#include <sys/fs/hsfs_spec.h> +#include <sys/fs/hsfs_isospec.h> +#include <sys/fs/hsfs_node.h> +#include <sys/fs/hsfs_susp.h> +#include <sys/fs/hsfs_rrip.h> + +#include <iob.h> +#include "hsfs_sig.h" + +#define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n)) + +#define NULL 0 + +#define TRUE 1 +#define FALSE 0 + +char *bootname = "/hsfsboot"; + +extern int (*printf_p)(); + +struct dirstuff { + int loc; + struct iob *io; +}; + +struct hs_direct { + struct direct hs_ufs_dir; + struct hs_direntry hs_dir; +}; + +/* These are the pools of buffers, iob's, etc. */ +struct iob iob[1]; + +/* This is the fd for the file(s) */ +static i_fd = 1; + +/* May not need this... */ +static uint_t root_ino = 0; + +/* + * Non-local prototypes + */ +extern int devread(struct saioreq *s); +extern int devopen(struct saioreq *s); +extern int devclose(struct saioreq *s); + +/* + * Local prototypes + */ +static struct hs_direct *readdir(struct dirstuff *); +static ino_t dlook(char *, struct iob *); +static ino_t find(char *, struct iob *); +static uint_t parse_dir(struct iob *, int, struct hs_direct *); +static uint_t parse_susp(char *, uint_t *, struct hs_direct *); +static int opendir(ino_t, struct iob *); +static int mountroot(void); + +extern int prom_type; /* Determined in main() */ +/* + * Exported functions + */ +extern int open(char *str, int flags); +extern int close(int fd); +extern int read(int fdesc, char *buf, int count); +extern int lseek(int fdesc, off_t addr); + +static int +opendir(ino_t inode, struct iob *io) +{ + struct hs_direct hsdep; + uint_t i; + int retval; + + /* Set up the saio request */ + io->i_offset = 0; + io->i_bn = hdbtodb(inode); + io->i_cc = ISO_SECTOR_SIZE; + + if ((retval = devread(&io->i_si)) != ISO_SECTOR_SIZE) + return (0); + + io->i_offset = 0; + io->i_bn = hdbtodb(inode); + + if (inode != root_ino) + return (0); + + if (parse_dir(io, 0, &hsdep) > 0) { + register struct inode *ip = &io->i_ino; + + bzero(io->i_ino, sizeof (struct inode)); + ip->i_size = hsdep.hs_dir.ext_size; + ip->i_smode = hsdep.hs_dir.mode; + ip->i_number = inode; + return (0); + } + return (1); +} + +static ino_t +find(char *path, struct iob *file) +{ + char *q; + char c; + ino_t n; + + if (path == NULL || *path == '\0') + return (0); + + if (opendir(root_ino, file)) + return (0); + + while (*path) { + while (*path == '/') + path++; + q = path; + while (*q != '/' && *q != '\0') + q++; + c = *q; + *q = '\0'; + + if ((n = dlook(path, file)) != 0) { + if (c == '\0') + break; + if (opendir(n, file)) + return (0); + *q = c; + path = q; + continue; + } else { + return (0); + } + } + return ((ino_t)n); +} + +static ino_t +dlook(char *s, struct iob *io) +{ + register struct hs_direct *hsdep; + register struct direct *udp; + register struct inode *ip; + struct dirstuff dirp; + register int len; + + ip = &io->i_ino; + if (s == NULL || *s == '\0') + return (0); + if ((ip->i_smode & IFMT) != IFDIR) { + return (0); + } + if (ip->i_size == 0) { + return (0); + } + len = strlen(s); + dirp.loc = 0; + dirp.io = io; + for (hsdep = readdir(&dirp); hsdep != NULL; hsdep = readdir(&dirp)) { + udp = &hsdep->hs_ufs_dir; + if (udp->d_namlen == 1 && + udp->d_name[0] == '.' && + udp->d_name[1] == '\0') + continue; + if (udp->d_namlen == 2 && + udp->d_name[0] == '.' && + udp->d_name[1] == '.' && + udp->d_name[2] == '\0') + continue; + if (udp->d_namlen == len && (strcmp(s, udp->d_name)) == 0) { + register struct inode *ip = &io->i_ino; + + io->i_offset = 0; + io->i_bn = hdbtodb(udp->d_ino); + + bzero(io->i_ino, sizeof (struct inode)); + ip->i_size = hsdep->hs_dir.ext_size; + ip->i_smode = hsdep->hs_dir.mode; + ip->i_number = udp->d_ino; + return (udp->d_ino); + } + } + return (0); +} + +/* + * get next entry in a directory. + */ +static struct hs_direct * +readdir(struct dirstuff *dirp) +{ + static struct hs_direct hsdep; + register struct direct *udp = &hsdep.hs_ufs_dir; + struct inode *ip; + struct iob *io; + daddr_t lbn, d; + int off; + + io = dirp->io; + ip = &io->i_ino; + for (;;) { + if (dirp->loc >= ip->i_size) { + return (NULL); + } + off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1); + if (off == 0) { + lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT); + io->i_bn = lbn + hdbtodb(ip->i_number); + io->i_ma = io->i_buf; + io->i_cc = ISO_SECTOR_SIZE; + if (devread(&io->i_si) != io->i_cc) { + return (NULL); + } + } + dirp->loc += parse_dir(io, off, &hsdep); + if (udp->d_reclen == 0 && dirp->loc <= ip->i_size) { + dirp->loc = roundup(dirp->loc, ISO_SECTOR_SIZE); + continue; + } + return (&hsdep); + } +} + +static int +getblock(struct iob *io) +{ + register struct hs_volume *fsp; + register struct inode *ip = &io->i_ino; + register int off, size, diff; + register daddr_t lbn; +#ifdef SPIN_IND + static int pos; + static char ind[] = "|/-\\"; + static int blks_read; +#endif /* SPIN_IND */ + + diff = ip->i_size - io->i_offset; + if (diff <= 0) + return (-1); + + fsp = &io->ui_hsfs; + + /* which block (or frag) in the file do we read? */ + lbn = hdbtodb(io->i_offset >> ISO_SECTOR_SHIFT); + io->i_bn = lbn + hdbtodb(ip->i_number); + + off = io->i_offset & ((1 << ISO_SECTOR_SHIFT) - 1); + size = sizeof (io->i_buf); + io->i_ma = io->i_buf; + io->i_cc = size; + + if (devread(&io->i_si) != size) /* Trap errors */ + return (-1); + +#ifdef SPIN_IND + /* + * round and round she goes (though not on every block.. + * - Even SunMON proms take some time to actually print stuff) + */ + if ((blks_read++ & 0x3) == 0) + (*printf_p)("%c\b", ind[pos++ & 3]); +#endif /* SPIN_IND */ + + if (io->i_offset - off + size >= ip->i_size) + io->i_cc = diff + off; + io->i_cc -= off; + + io->i_ma = &io->i_buf[off]; + return (0); +} + +int +read(int fd, caddr_t buf, int count) +{ + register i, j; + register struct iob *io = &iob[fd]; + register struct inode *ip = &io->i_ino; + caddr_t n; + + n = buf; + + if (io->i_offset + count > ip->i_size) + count = ip->i_size - io->i_offset; + + if ((i = count) <= 0) + return (0); + + while (i > 0) { + if (io->i_cc <= 0) { + if (getblock(io) == -1) + return (0); + } + j = MIN(i, io->i_cc); + bcopy(io->i_ma, buf, (unsigned)j); + buf += j; + io->i_ma += j; + io->i_offset += j; + io->i_cc -= j; + i -= j; + } + return (buf - n); +} + +/* + * We use the token iob for reading the "super block". + */ +static int +mountroot() +{ + struct bootparam *bp; + struct hs_volume *fsp; + char *bufp; + int err; + int i; + + /* This really has to be done only once. */ + if (root_ino == 0) { + + bp = *(romp->sunmon.v_bootparam); + + fsp = &iob->ui_hsfs; + bufp = iob->i_buf; + + iob->i_boottab = bp->bp_boottab; + iob->i_ino.i_dev = 0; + iob->i_ctlr = bp->bp_ctlr; + iob->i_unit = bp->bp_unit; + iob->i_boff = bp->bp_part; + + /* make the prom open the device */ + if (err = devopen(&iob->i_si)) + return (-1); /* if devopen fails, open fails */ + + /* now opening file system; read the superblock. */ + iob->i_ma = iob->i_buf; + iob->i_cc = ISO_SECTOR_SIZE; + iob->i_bn = hdbtodb(ISO_VOLDESC_SEC); + iob->i_offset = 0; + if ((err = devread(&iob->i_si)) != ISO_SECTOR_SIZE) + return (-1); + + bufp = iob->i_buf; + fsp = &iob->ui_hsfs; + + /* Since RRIP is based on ISO9660, that's where we start */ + + if (ISO_DESC_TYPE(bufp) != ISO_VD_PVD) + return (-1); + if (strncmp(ISO_std_id(bufp), ISO_ID_STRING, ISO_ID_STRLEN) != 0) + return (-1); + if (ISO_STD_VER(bufp) != ISO_ID_VER) + return (-1); + + /* Now we fill in the volume descriptor */ + fsp->vol_size = ISO_VOL_SIZE(bufp); + fsp->lbn_size = ISO_BLK_SIZE(bufp); + fsp->lbn_shift = ISO_SECTOR_SHIFT; + fsp->lbn_secshift = ISO_SECTOR_SHIFT; + fsp->vol_set_size = (ushort_t)ISO_SET_SIZE(bufp); + fsp->vol_set_seq = (ushort_t)ISO_SET_SEQ(bufp); + + /* Make sure we have a valid logical block size */ + if (fsp->lbn_size & ~(1 << fsp->lbn_shift)) { + (*printf_p)("%d invalid logical block size\n", + fsp->lbn_size); + return (-1); + } + + /* Since an HSFS root could be located anywhere on the media! */ + root_ino = IDE_EXT_LBN(ISO_root_dir(bufp)); + } +} + +/* + * Open a file. For the bootblock, we assume one file can be opened + * on a ufs filesystem. The underlying device is the one we rode in on. + */ +int +open(char *str, int flags) +{ + register struct iob *ior; + register struct bootparam *bp; + register struct hs_volume *fsp; + register struct hs_direntry *dirp; + register char *bufp; + ino_t ino; + int err; + + /* Make sure we are set up */ + mountroot(); + + bp = *(romp->sunmon.v_bootparam); + + ior = iob; + fsp = &ior->ui_hsfs; + dirp = &fsp->root_dir; + bufp = ior->i_buf; + + ior->i_boottab = bp->bp_boottab; + ior->i_ino.i_dev = 0; + ior->i_ctlr = bp->bp_ctlr; + ior->i_unit = bp->bp_unit; + ior->i_boff = bp->bp_part; + + if ((ino = find(str, ior)) == 0) { + (*printf_p)("%s not found\n", str); + return (-1); + } + + ior->i_bn = hdbtodb(ino); + ior->i_offset = 0; + ior->i_cc = 0; + + return (0); +} + +int +close(int fd) +{ + struct iob *file = &iob[fd]; + + return (devclose(&file->i_si)); +} + +/* + * This version of seek() only performs absolute seeks (whence == 0). + */ +int +seek(int fd, off_t addr) +{ + struct iob *io = &iob[fd]; + + io->i_offset = addr; + io->i_bn = addr / DEV_BSIZE; + io->i_cc = 0; + return (0); +} + +/* + * Parse a directory entry. + * + */ +static uint_t +parse_dir( + struct iob *io, /* current dir block */ + int offset, /* offset into dir blk for dir entry */ + struct hs_direct *hsdep) /* return value: parsed entry */ +{ + char *bufp = (char *)(io->i_ma + offset); + struct hs_volume *fsp = &io->ui_hsfs; + struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style dir info */ + struct hs_direntry *hdp = &hsdep->hs_dir; /* hsfs-style dir info */ + int ce_buf[ISO_SECTOR_SIZE/sizeof (int)]; /* continuation area buffer */ + uint_t ce_lbn; + uint_t ce_len; + uint_t nmlen; + uint_t i; + uchar_t c; + int ret_code; + + /* a zero length dir entry terminates the dir block */ + if (!(udp->d_reclen = IDE_DIR_LEN(bufp))) + return (0); + + /* fill in some basic hsfs info */ + hdp->ext_lbn = IDE_EXT_LBN(bufp); + hdp->ext_size = IDE_EXT_SIZE(bufp); + hdp->xar_len = IDE_XAR_LEN(bufp); + hdp->intlf_sz = IDE_INTRLV_SIZE(bufp); + hdp->intlf_sk = IDE_INTRLV_SKIP(bufp); + hdp->sym_link = NULL; + + /* we use lbn of data extent as an inode # equivalent */ + udp->d_ino = hdp->ext_lbn; + + c = IDE_FLAGS(bufp); + if (IDE_REGULAR_FILE(c)) { + hdp->type = VREG; + hdp->mode = IFREG; + hdp->nlink = 1; + } else if (IDE_REGULAR_DIR(c)) { + hdp->type = VDIR; + hdp->mode = IFDIR; + hdp->nlink = 2; + } else { + (*printf_p)("pd(): file type=0x%x unknown.\n", c); + return (-1); + } + + /* + * Massage hsfs name, recognizing special entries for . and .. + * else lopping off version junk. + */ + + /* Some initial conditions */ + nmlen = IDE_NAME_LEN(bufp); + c = *IDE_NAME(bufp); + /* Special Case: Current Directory */ + if (nmlen == 1 && c == '\0') { + udp->d_name[0] = '.'; + udp->d_name[1] = '\0'; + udp->d_namlen = 1; + /* Special Case: Parent Directory */ + } else if (nmlen == 1 && c == '\001') { + udp->d_name[0] = '.'; + udp->d_name[1] = '.'; + udp->d_name[2] = '\0'; + udp->d_namlen = 2; + /* Other file name */ + } else { + udp->d_namlen = 0; + for (i = 0; i < nmlen; i++) { + c = *(IDE_name(bufp)+i); + if (c == ';') + break; + else if (c == ' ') + continue; + else + udp->d_name[udp->d_namlen++] = c; + } + udp->d_name[udp->d_namlen] = '\0'; + } + + /* System Use Fields */ + ce_len = IDE_SUA_LEN(bufp); + + if (ce_len > 0) { + /* there is an SUA for this dir entry; go parse it */ + ce_lbn = parse_susp((char *)IDE_sys_use_area(bufp), + &ce_len, hsdep); + + if (ce_lbn) { + /* + * store away current position in dir, + * as we will be using the iobuf to reading SUA. + */ + daddr_t save_bn = io->i_bn; + daddr_t save_offset = io->i_offset; + caddr_t save_ma = io->i_ma; + int save_cc = io->i_cc; + do { + io->i_cc = ISO_SECTOR_SIZE; + io->i_offset = 0; + io->i_bn = hdbtodb(ce_lbn); + io->i_ma = (char *)ce_buf; + ret_code = devread(&io->i_si); + if (ret_code != ISO_SECTOR_SIZE) { + ce_len = 0; + ce_lbn = 0; + break; + } + ce_lbn = parse_susp(io->i_ma, &ce_len, hsdep); + } while (ce_lbn); + io->i_bn = save_bn; + io->i_offset = save_offset; + io->i_ma = save_ma; + io->i_cc = save_cc; + } + } + return (udp->d_reclen); +} + +/* + * Parse the System Use Fields in this System Use Area. + * Return blk number of continuation/SUA, or 0 if no continuation/not a SUA. + */ +static uint_t +parse_susp(char *bufp, uint_t *len, struct hs_direct *hsdep) +{ + register struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style info */ + char *susp; + uint_t cur_off = 0; + uint_t blk_len = *len; + uint_t susp_len = 0; + uint_t ce_lbn = 0; + uint_t i; + + while (cur_off < blk_len) { + susp = (char *)(bufp + cur_off); + + /* + * A null entry, or an entry with zero length + * terminates the SUSP. + */ + if (susp[0] == '\0' || susp[1] == '\0' || + (susp_len = SUF_LEN(susp)) == 0) + break; + + /* + * Compare current entry to all known signatures. + */ + for (i = 0; i < hsfs_num_sig; i++) + if (strncmp(hsfs_sig_tab[i], susp, SUF_SIG_LEN) == 0) + break; + switch (i) { + case SUSP_SP_IX: + /* SP signature: field tells us where SUA is */ + if (CHECK_BYTES_OK(susp)) { + cur_off = SP_SUA_OFFSET(susp); + } + break; + case SUSP_CE_IX: + /* + * CE signature: continuation of SUSP. + * will want to return new lbn, len. + */ + ce_lbn = CE_BLK_LOC(susp); + *len = CE_CONT_LEN(susp); + cur_off += susp_len; + break; + case SUSP_ST_IX: + /* ST signature: terminates SUSP */ + return (ce_lbn); + case RRIP_RR_IX: + /* XXX do we want to break when we see a RR? */ + cur_off += susp_len; + break; + case RRIP_NM_IX: + /* NM signature: POSIX-style file name */ + if (!RRIP_NAME_FLAGS(susp)) { + udp->d_namlen = RRIP_NAME_LEN(susp); + bcopy((char *)RRIP_name(susp), + udp->d_name, udp->d_namlen); + udp->d_name[udp->d_namlen] = '\0'; + } + break; + + case HSFS_NUM_SIG: + /* couldn't find a legit susp, terminate loop */ + (*printf_p)("parse_susp(): Bad SUSP\n"); + cur_off = blk_len; + break; + + default: + cur_off += susp_len; + } + } + return (ce_lbn); +} diff --git a/usr/src/psm/stand/bootblks/hsfs/common/hsfs_sig.h b/usr/src/psm/stand/bootblks/hsfs/common/hsfs_sig.h new file mode 100644 index 0000000000..2b18abe8e7 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/common/hsfs_sig.h @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright, 1991-1994, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HANDLE_CONTINUATION +static char *hsfs_sig_tab[] = { + SUSP_SP, + SUSP_CE, + SUSP_PD, + SUSP_ST, + SUSP_ER, + RRIP_PX, + RRIP_PN, + RRIP_SL, + RRIP_CL, + RRIP_PL, + RRIP_RE, + RRIP_TF, + RRIP_RR, + RRIP_NM +}; + +static int hsfs_num_sig = sizeof (hsfs_sig_tab) / sizeof (hsfs_sig_tab[0]); +#endif /* HANDLE_CONTINUATION */ + +#define HSFS_NUM_SIG 14 + +#define SUSP_SP_IX 0 +#define SUSP_CE_IX 1 +#define SUSP_PD_IX 2 +#define SUSP_ST_IX 3 +#define SUSP_ER_IX 4 + +#define RRIP_PX_IX 5 +#define RRIP_PN_IX 6 +#define RRIP_SL_IX 7 +#define RRIP_CL_IX 8 +#define RRIP_PL_IX 9 +#define RRIP_RE_IX 10 +#define RRIP_RF_IX 11 +#define RRIP_RR_IX 12 +#define RRIP_NM_IX 13 diff --git a/usr/src/psm/stand/bootblks/hsfs/common/hsfs_small.c b/usr/src/psm/stand/bootblks/hsfs/common/hsfs_small.c new file mode 100644 index 0000000000..b89892eafd --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/common/hsfs_small.c @@ -0,0 +1,674 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1991-1994, Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* from "@(#)boot/ufssys.c 1.1 90/03/28 SMI" */ + +/* + * Basic file system reading code for standalone I/O system. + */ + +/* + * This code must be kept very small. If space allows, you can + * turn on the ability to handle continuations (and other signatures) + * by #defining HANDLE_CONTINUATION. + */ + +#include <sys/param.h> +#include <sys/vnode.h> +#include <sys/fs/ufs_fsdir.h> +#include <sys/fs/ufs_fs.h> +#include <sys/fs/ufs_inode.h> + +#include <sys/fs/hsfs_spec.h> +#include <sys/fs/hsfs_isospec.h> +#include <sys/fs/hsfs_node.h> +#include <sys/fs/hsfs_susp.h> +#include <sys/fs/hsfs_rrip.h> + +#include "iob.h" +#include "cbootblk.h" + +#include "hsfs_sig.h" + +#define NULL 0 + +#define TRUE 1 +#define FALSE 0 + +#define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n)) + +#ifdef DEBUG +/* debugging printfs */ +#define DEBUG_PRINTF0(s) \ + fprintf(stderr, s) +#define DEBUG_PRINTF1(s, a1) \ + fprintf(stderr, s, (a1)) +#define DEBUG_PRINTF2(s, a1, a2) \ + fprintf(stderr, s, (a1), (a2)) +#define DEBUG_PRINTF3(s, a1, a2, a3) \ + fprintf(stderr, s, (a1), (a2), (a3)) +#define DEBUG_PRINTF4(s, a1, a2, a3, a4) \ + fprintf(stderr, s, (a1), (a2), (a3), (a4)) +#define DEBUG_PRINTF5(s, a1, a2, a3, a4, a5) \ + fprintf(stderr, s, (a1), (a2), (a3), (a4), (a5)) +#else +#define DEBUG_PRINTF0(s) +#define DEBUG_PRINTF1(s, a1) +#define DEBUG_PRINTF2(s, a1, a2) +#define DEBUG_PRINTF3(s, a1, a2, a3) +#define DEBUG_PRINTF4(s, a1, a2, a3, a4) +#define DEBUG_PRINTF5(s, a1, a2, a3, a4, a5) +#endif + +char fscompname[] = "hsfsboot"; + +static struct iob iob[1]; /* only one open file! */ + +static u_int dlook(char *, register struct iob *); +static int parse_dir(struct iob *, int, u_char *, u_int *, u_int *); +static u_int parse_susp(u_char *, u_int *, u_char *, u_int *, u_int *); +static int read_sector(struct iob *, u_int, char *, u_char); + +static int +read_sector(struct iob *io, u_int iso_secno, char *buf, u_char next) +{ +#ifdef DEBUG + static char *msg = "rs:[%c] o=%d b=%d c=%d n=%d\n"; +#endif + DEBUG_PRINTF5(msg, 'I', io->i_offset, io->i_bn, io->i_cc, next); + + io->i_cc = ISO_SECTOR_SIZE; + io->i_ma = buf; + + if (next == TRUE) { + io->i_bn += (ISO_SECTOR_SIZE / DEV_BSIZE); + } else { + io->i_offset = 0; + io->i_bn = hdbtodb(iso_secno); + } + + if (devbread(&io->i_si, io->i_ma, + io->i_bn, io->i_cc) != ISO_SECTOR_SIZE) { + DEBUG_PRINTF5(msg, '0', io->i_offset, + io->i_bn, io->i_cc, next); + return (0); + } + + DEBUG_PRINTF5(msg, '1', io->i_offset, io->i_bn, io->i_cc, next); + return (1); +} + +/* + * Look up a file, pathname component by pathname component. + * Return lbn of file if found, 0 otherwise. + */ +static u_int +find(char *path, struct iob *file) +{ + char *q; + char c; + u_int n; + + if (path == NULL || *path == '\0') + return (0); + + while (*path) { + while (*path == '/') + path++; + q = path; + while (*q != '/' && *q != '\0') + q++; + c = *q; + *q = '\0'; + + if ((n = dlook(path, file)) != 0) { + DEBUG_PRINTF1("fnd: n=%d\n", n); + if (c == '\0') + break; + if (!read_sector(file, n, file->i_buf, FALSE)) + return (0); + *q = c; + path = q; + continue; + } else { + return (0); + } + } + return (n); +} + +/* + * Look up the file in the directory. + * Return lbn of file extent on success, 0 on failure. + */ +static u_int +dlook(char *s, struct iob *io) +{ + struct hs_volume *fsp = &io->ui_hsfs; + struct hs_direntry *dirp = &fsp->root_dir; + int dirsz = dirp->ext_size; + u_char nameb[MAXPATHLEN]; + u_int nml; + u_int blkloc = 0; + u_int dirloc; + u_int reclen; + u_int len; + u_int altnm; + + if (s == NULL || *s == '\0') + return (0); + + if (dirp->type != VDIR) + return (0); + + len = strlen(s); + + while (blkloc < dirsz) { + dirloc = 0; + while (dirloc < ISO_SECTOR_SIZE) { + altnm = 0; + nml = sizeof (nameb); + reclen = parse_dir(io, dirloc, nameb, &nml, &altnm); + dirloc += reclen; + if (!reclen) + break; + if (altnm) { + if (len != nml || + strncmp(s, (char *)nameb, len) != 0) + continue; + } else { + if (strncmp(s, (char *)nameb, len) != 0) + continue; + } + DEBUG_PRINTF1("dl: ret lb=%d\n", dirp->ext_lbn); + return ((u_int) dirp->ext_lbn); + } + if (blkloc + ISO_SECTOR_SIZE < dirsz) { + if (!read_sector(io, 0, io->i_buf, TRUE)) + return (0); + } + blkloc += ISO_SECTOR_SIZE; + } + return (0); +} + +static int +getblock(register struct iob *io) +{ + u_int lbn; + int off, size, diff; + struct hs_volume *fsp = &io->ui_hsfs; + struct hs_direntry *dirp = &fsp->root_dir; + + diff = dirp->ext_size - io->i_offset; + if (diff <= 0) + return (-1); + lbn = hdbtodb(io->i_offset >> ISO_SECTOR_SHIFT); + io->i_bn = lbn + hdbtodb(dirp->ext_lbn); + off = io->i_offset % ISO_SECTOR_SIZE; + size = sizeof (io->i_buf); + io->i_cc = size; + io->i_ma = io->i_buf; + + if (devbread(&io->i_si, io->i_ma, + io->i_bn, io->i_cc) != io->i_cc) /* Trap errors */ + return (-1); + + if (io->i_offset - off + size >= dirp->ext_size) + io->i_cc = diff + off; + io->i_cc -= off; + + io->i_ma = &io->i_buf[off]; + return (0); +} + +int +readfile(int fd, char *buf, int count) +{ + int i, j; + struct iob *io = &iob[fd]; + struct iob *file = io; + struct hs_volume *fsp = &file->ui_hsfs; + struct hs_direntry *dirp = &fsp->root_dir; + + if (file->i_offset + count > dirp->ext_size) + count = dirp->ext_size - file->i_offset; + if ((i = count) <= 0) + return (0); + while (i > 0) { + if (file->i_cc <= 0) { + if (getblock(file) == -1) + return (0); + } + j = (i < file->i_cc) ? i : file->i_cc; + bcopy(file->i_ma, buf, (unsigned)j); + buf += j; + file->i_ma += j; + file->i_offset += j; + file->i_cc -= j; + i -= j; + } + return (count); +} + +/* + * Open a file. For the bootblock, we assume one file can be opened + * on a hsfs filesystem. The underlying device is the one we rode in on. + */ +int +openfile(char *device, char *pathname) +{ + struct iob *io = &iob[0]; /* only one open file! */ + register struct hs_volume *fsp; + register char *bufp; + u_int lbn; + + DEBUG_PRINTF0("open\n"); + + fsp = &io->ui_hsfs; + bufp = io->i_buf; + + if ((io->i_si = devopen(device)) == NULL) + return (-1); /* if devopen fails, open fails */ + /* + * Pseudo-mount a file system; read the superblock. + */ + if (!read_sector(io, ISO_VOLDESC_SEC, bufp, FALSE)) + goto failed; + + /* Make sure we start with a clean slate. */ + (void) bzero((char *)fsp, sizeof (io->ui_hsfs)); + + /* Since RRIP is based on ISO9660, that's where we start */ + + if (ISO_DESC_TYPE(bufp) != ISO_VD_PVD || + strncmp((char *)ISO_std_id(bufp), ISO_ID_STRING, + ISO_ID_STRLEN) != 0 || + ISO_STD_VER(bufp) != ISO_ID_VER) { + puts("bootblk: not an ISO9660 file system.\n"); + goto failed; + } + + /* Now we fill in the volume descriptor */ + fsp->vol_size = ISO_VOL_SIZE(bufp); + fsp->lbn_size = ISO_BLK_SIZE(bufp); + fsp->lbn_shift = ISO_SECTOR_SHIFT; + fsp->lbn_secshift = ISO_SECTOR_SHIFT; + fsp->vol_set_size = (u_short) ISO_SET_SIZE(bufp); + fsp->vol_set_seq = (u_short) ISO_SET_SEQ(bufp); + + /* Make sure we have a valid logical block size */ + if (fsp->lbn_size & ~(1 << fsp->lbn_shift)) { + DEBUG_PRINTF1("%d byte logical block size invalid.", + fsp->lbn_size); + goto failed; + } + + /* Read the ROOT directory */ + if (!read_sector(io, IDE_EXT_LBN(ISO_root_dir(bufp)), bufp, FALSE)) + goto failed; + + /* Extract the ROOT directory information from the directory block */ + (void) parse_dir(io, 0, NULL, (u_int *) 0, (u_int *) 0); + + if (!(lbn = find(pathname, io))) + goto failed; + + DEBUG_PRINTF1("lb=%d\n", lbn); + + io->i_bn = hdbtodb(lbn); + io->i_offset = 0; + io->i_cc = 0; + + return (0); /* only one open file! */ +failed: + (void) devclose(io->i_si); + return (-1); +} + +int +closefile(int fd) +{ + struct iob *io = &iob[fd]; + + return (devclose(io->i_si)); +} + +/* + * This version of seek() only performs absolute seeks (whence == 0). + */ +void +seekfile(int fd, off_t addr) +{ + struct iob *io = &iob[fd]; + + io->i_offset = addr; + io->i_bn = addr >> DEV_BSHIFT; + io->i_cc = 0; +} + +/* + * Return the next directory entry. + * Return 0 if no next entry, length of directory entry otherwise. + */ +static int +parse_dir( + struct iob *io, /* current dir block */ + int offset, /* dir entry offset into dir blk */ + u_char *namep, /* output: name found */ + u_int *namelen, /* output: length of name found */ + u_int *anm) /* output: found RR (altrnt) nm flg */ +{ + u_char *bufp = (u_char *)(io->i_buf + offset); + struct hs_direntry *dirp = &(io->ui_hsfs.root_dir); + static u_char ce_buf[ISO_SECTOR_SIZE]; + u_int ce_len; + static u_char nmbuf[MAXPATHLEN]; + u_int nmlen; + u_int altnm = 0; /* found RR name flag */ + u_char c; + u_int dir_len = IDE_DIR_LEN(bufp); + + DEBUG_PRINTF1("pd %d\n", dir_len); + + if (!dir_len) + /* zero length directory, done */ + return (0); + + dirp->ext_lbn = IDE_EXT_LBN(bufp); + dirp->ext_size = IDE_EXT_SIZE(bufp); + dirp->xar_len = IDE_XAR_LEN(bufp); + dirp->intlf_sz = IDE_INTRLV_SIZE(bufp); + dirp->intlf_sk = IDE_INTRLV_SKIP(bufp); + dirp->sym_link = NULL; + + c = IDE_FLAGS(bufp); + if (IDE_REGULAR_FILE(c)) { + dirp->type = VREG; + dirp->mode = IFREG; + dirp->nlink = 1; + } else if (IDE_REGULAR_DIR(c)) { + dirp->type = VDIR; + dirp->mode = IFDIR; + dirp->nlink = 2; + } else { + DEBUG_PRINTF1("pd: ftype=0x%x unknown.\n", c); + return (-1); + } + + /* + * Massage hsfs name, recognizing special entries for . and .. + * else lopping off version junk. + */ + + /* Some initial conditions */ + nmlen = IDE_NAME_LEN(bufp); + c = *IDE_NAME(bufp); + /* Special Case: Current Directory */ + if (nmlen == 1 && c == '\0') { + nmbuf[0] = '.'; + nmbuf[1] = '\0'; + nmlen = 1; + /* Special Case: Parent Directory */ + } else if (nmlen == 1 && c == '\001') { + nmbuf[0] = '.'; + nmbuf[1] = '.'; + nmbuf[2] = '\0'; + nmlen = 2; + /* Other file name */ + } else { + register int l = nmlen; + register int i; + + nmlen = 0; + for (i = 0; i < l; i++) { + c = *(IDE_name(bufp)+i); + if (c == ';') + break; + else if (c == ' ') + continue; + else + nmbuf[nmlen++] = c; + } + nmbuf[nmlen] = '\0'; + } + + DEBUG_PRINTF0("pd bf sua"); + +#ifdef HANDLE_CONTINUATION + /* System Use Fields */ + ce_len = IDE_SUA_LEN(bufp); + if (ce_len) { + /* there is an SUA for this dir entry; go parse it */ + u_int ce_lbn; + u_int nmbsz = sizeof (nmbuf); + + bcopy((char *)IDE_sys_use_area(bufp), (char *)ce_buf, ce_len); + ce_lbn = parse_susp(ce_buf, &ce_len, nmbuf, &nmbsz, &altnm); + + while (ce_lbn) { + /* + * Process continuation of SUA, + * saving current position in dir, + * as will be using iobuf to read SUA continuation. + */ + daddr_t save_bn = io->i_bn; + daddr_t save_offset = io->i_offset; + int save_cc = io->i_cc; + int rd_ok; + + rd_ok = read_sector(io, ce_lbn, (char *)ce_buf, FALSE); + + io->i_bn = save_bn; + io->i_offset = save_offset; + io->i_cc = save_cc; + + if (!rd_ok) + return (0); + + ce_lbn = parse_susp(ce_buf, &ce_len, nmbuf, &nmbsz, + &altnm); + } + if (altnm) + nmlen = nmbsz; + } +#else /* HANDLE_CONTINUATION */ + /* System Use Fields */ + ce_len = IDE_SUA_LEN(bufp); + if (ce_len) { + /* there is an SUA for this dir entry; go parse it */ + + u_int nmbsz = sizeof (nmbuf); + + bcopy((char *)IDE_sys_use_area(bufp), (char *)ce_buf, ce_len); + (void) parse_susp(ce_buf, &ce_len, nmbuf, &nmbsz, &altnm); + + if (altnm) + nmlen = nmbsz; + } +#endif /* HANDLE_CONTINUATION */ + + DEBUG_PRINTF0("pd af sua"); + + if (anm != NULL) + *anm = altnm; + + if (namep != NULL && namelen != NULL && *namelen) { + /* assert(namelen >= nmlen) */ + bcopy((char *)nmbuf, (char *)namep, nmlen); + *namelen = nmlen; + } + +#ifdef DEBUG + if (altnm) + nmbuf[nmlen] = '\0'; +#endif /* DEBUG */ + + DEBUG_PRINTF2("Nm(%d)=%s\n", nmlen, nmbuf); + DEBUG_PRINTF2(" lbn/len = %d/%d\n", dirp->ext_lbn, dirp->ext_size); + DEBUG_PRINTF0("pd end\n"); + + return (dir_len); +} + +#ifdef HANDLE_CONTINUATION +/* + * Parse the System Use Fields in the System Use Area. + * Return block number of continuation (if any), + * or 0 if no continuation. + */ +static u_int +parse_susp( + u_char *bufp, + u_int *len, + u_char *nmp, + u_int *nmlen, + u_int *altnm) /* found RR name */ +{ + u_char *susp; + u_int cur_off = 0; + u_int blk_len = *len; + u_int susp_len = 0; + u_int ce_lbn = 0; + u_int i; + + DEBUG_PRINTF1("ps: l=%d\n", *len); + + while (cur_off < blk_len) { + susp = (u_char *)(bufp + cur_off); + /* + * A null entry, or an entry with zero length + * terminates the SUSP. + */ + if (susp[0] == '\0' || susp[1] == '\0' || + (susp_len = SUF_LEN(susp)) == 0) + break; + + /* Compare current entry to all known signatures */ + for (i = 0; i < HSFS_NUM_SIG; i++) { + if (strncmp(hsfs_sig_tab[i], susp, SUF_SIG_LEN) == 0) { + DEBUG_PRINTF3("SUSP_%c%c %d\n", susp[0], + susp[1], susp_len); + break; + } + } + + switch (i) { + case SUSP_CE_IX: + /* + * CE signature: continuation of SUSP. + * will want to return new lbn, len. + */ + ce_lbn = CE_BLK_LOC(susp); + *len = CE_CONT_LEN(susp); + break; + case SUSP_ST_IX: + /* ST signature: terminates SUSP */ + return (ce_lbn); + case RRIP_RR_IX: + /* XXX do we want to break when we see a RR? */ + break; + case RRIP_NM_IX: + /* NM signature: POSIX-style file name */ + DEBUG_PRINTF0(" NM\n"); + if (!RRIP_NAME_FLAGS(susp)) { + /* copy out new name if requested */ + if (*nmlen) { + *nmlen = RRIP_NAME_LEN(susp); + /* assert(old(nmlen) >= new(nmlen)) */ + bcopy((char *)RRIP_name(susp), + (char *)nmp, *nmlen); + *altnm = 1; + } + } + break; + case HSFS_NUM_SIG: + /* couldn't find a legit susp, complain and continue */ + (*printf_p)("parse_susp(): Bad SUSP\n"); + break; + default: + break; + } + + cur_off += susp_len; + DEBUG_PRINTF1("ps: o=%d\n", cur_off); + } + return (ce_lbn); +} + +#else /* HANDLE_CONTINUATION */ +/* + * Parse the System Use Fields in the System Use Area. + * Return block number of continuation (if any), + * or 0 if no continuation. + */ +static u_int +parse_susp( + u_char *bufp, + u_int *len, + u_char *nmp, + u_int *nmlen, + u_int *altnm) /* found RR name */ +{ + u_char *susp; + u_int cur_off = 0; + u_int blk_len = *len; + u_int susp_len = 0; + + DEBUG_PRINTF1("ps: l=%d\n", *len); + + while (cur_off < blk_len) { + susp = (u_char *)(bufp + cur_off); + + /* + * A null entry, or an entry with zero length + * terminates the SUSP. + */ + if (susp[0] == '\0' || susp[1] == '\0' || + (susp_len = SUF_LEN(susp)) == 0) + break; + + /* Compare current entry to all known signatures */ + if ((susp[0] == 'N' && susp[1] == 'M') && + !RRIP_NAME_FLAGS(susp)) { + /* copy out new name if requested */ + if (*nmlen) { + *nmlen = RRIP_NAME_LEN(susp); + /* assert(old(nmlen) >= new(nmlen)) */ + bcopy((char *)RRIP_name(susp), (char *)nmp, + *nmlen); + *altnm = 1; + } + return (0); + } + cur_off += susp_len; + DEBUG_PRINTF1("ps: o=%d\n", cur_off); + } + return (0); +} +#endif /* HANDLE_CONTINUATION */ diff --git a/usr/src/psm/stand/bootblks/hsfs/common/iob.h b/usr/src/psm/stand/bootblks/hsfs/common/iob.h new file mode 100644 index 0000000000..844f1152fb --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/common/iob.h @@ -0,0 +1,51 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1990-1994, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This struct keeps track of an open file in the standalone I/O system. + * + * It includes an IOB for device addess, a buffer for reading directory blocks + * and a structure for volume. + */ +struct iob { + void *i_si; /* I/O handle for this file */ + struct { + off_t si_offset; /* byte offset */ + char *si_ma; /* memory address to r/w */ + int si_cc; /* character count to r/w */ + int si_bn; /* block number to r/w */ + } i_saio; + struct inode i_ino; /* Buffer for inode information */ + struct hs_volume ui_hsfs; /* Superblock for file system */ + char i_buf[MAXBSIZE]; /* Buffer for reading dirs */ +}; + +#define i_offset i_saio.si_offset +#define i_bn i_saio.si_bn +#define i_ma i_saio.si_ma +#define i_cc i_saio.si_cc diff --git a/usr/src/psm/stand/bootblks/hsfs/i386/Makefile b/usr/src/psm/stand/bootblks/hsfs/i386/Makefile new file mode 100644 index 0000000000..7f3dd6b25c --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/i386/Makefile @@ -0,0 +1,44 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/hsfs/i386/Makefile +# +BASEDIR = ../.. + +include $(BASEDIR)/hsfs/Makefile.hsfs + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all install lint clean clobber: FRC + +FRC: diff --git a/usr/src/psm/stand/bootblks/hsfs/sparc/Makefile b/usr/src/psm/stand/bootblks/hsfs/sparc/Makefile new file mode 100644 index 0000000000..00d81e23f9 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/sparc/Makefile @@ -0,0 +1,49 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1994, 2001-2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/hsfs/sparc/Makefile +# +BASEDIR = ../.. + +include $(BASEDIR)/hsfs/Makefile.hsfs + +SUBDIRS = unix + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all install lint clean clobber: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/bootblks/hsfs/sparc/unix/Makefile b/usr/src/psm/stand/bootblks/hsfs/sparc/unix/Makefile new file mode 100644 index 0000000000..8aa0b74787 --- /dev/null +++ b/usr/src/psm/stand/bootblks/hsfs/sparc/unix/Makefile @@ -0,0 +1,71 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/hsfs/sparc/unix/Makefile +# + +# +# Build the "Unix" version of the boot block. +# Useful solely for testing. DO NOT INSTALL IT! +# +BASEDIR = ../../.. +PLATFORM = unix +PLATFORM_INCS = ./ +PLATLINKS = + +include $(BASEDIR)/hsfs/Makefile.hsfs +include $(BASEDIR)/obp-c/Makefile.rules + +CPPINCS += -I$(SRC)/head +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc +CPPINCS += -I$(PLATFORM_INCS) + +UNIX_OBJS = hsfs_small.o unix_devio.o + +$(UNIX_OBJS) := CFLAGS += -g + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(UNIX_OBJS) + $(CC) $(CFLAGS) $(CPPFLAGS) -g -o $@ $(UNIX_OBJS) + +lint: FRC + +clean: + $(RM) $(UNIX_OBJS) + +clobber: clean + $(RM) $(PROG) + +install: FRC + +FRC: + diff --git a/usr/src/psm/stand/bootblks/obp-c/Makefile.rules b/usr/src/psm/stand/bootblks/obp-c/Makefile.rules new file mode 100644 index 0000000000..b320f564ac --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/Makefile.rules @@ -0,0 +1,105 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/obp-c/Makefile.rules +# + +OBPSRCDIR = $(BASEDIR)/obp-c +OBPCMNDIR = $(OBPSRCDIR)/common +OBPMACHDIR = $(OBPSRCDIR)/$(MACH)/common +OBPPLATDIR = $(OBPSRCDIR)/$(MACH)/$(PLATFORM) + +# +# Sources and objects used to build the C-based bootblock for +# deprecated OBP V0 and V2 platforms. +# +OBPDEP_C_SRCS = stub.c +OBPDEP_S_SRCS = +OBPDEP_SRCS = $(OBPDEP_C_SRCS) $(OBPDEP_S_SRCS) +OBPDEP_SRT = obp_srt0.o +OBPDEP_OBJS = $(OBPDEP_C_SRCS:%.c=%.o) $(OBPDEP_S_SRCS:%.s=%.o) bbvers.o +OBPDEP_L_OBJS = $(OBPDEP_SRT:%.o=%.ln) $(OBPDEP_OBJS:%.o=%.ln) +OBPDEP_LD_LIBS = + +# +# Rules used to build boot blocks. PROM_TYPE is defined in the platform +# specific Makefile in ../<fs>/<mach>/<platform>/Makefile and is set to one +# of OBP or IEEE1275. +# +BOOT_OBJS = $($(PROM_TYPE)_OBJS) +BOOT_SRT = $($(PROM_TYPE)_SRT) +BOOT_L_OBJS = $($(PROM_TYPE)_L_OBJS) +BOOT_LD_LIBS = $($(PROM_TYPE)_LD_LIBS) + +MAPFILE = $(OBPMACHDIR)/mapfile + +CPPINCS += -I$(OBPCMNDIR) -I$(PSMSYSHDRDIR) +CPPFLAGS += -D_BOOT -D_KERNEL +CPPFLAGS += $(CPPINCS) $(CCYFLAG)$(PSMSYSHDRDIR) +ASFLAGS += -D_BOOT -D_ASM -P $(CPPINCS) +LDFLAGS = -dn -e start -M $(MAPFILE) +LDLIBS = $(BOOT_LD_LIBS) + +# +# lint pass1 enforcement +# +CFLAGS += $(CCVERBOSE) + +MKBOOT = mkboot +MKVERS = makevers + +# +# Pattern matching rules to compile the source in this directory +# +%.o: $(OBPCMNDIR)/%.c + $(COMPILE.c) -o $@ $< + +%.o: $(OBPMACHDIR)/%.s + $(COMPILE.s) -o $@ $< + +%.o: $(OBPMACHDIR)/%.c + $(COMPILE.c) -o $@ $< + +%.o: $(OBPPLATDIR)/%.s + $(COMPILE.s) -o $@ $< + +%.ln: $(OBPCMNDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +%.ln: $(OBPMACHDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + +%.ln: $(OBPMACHDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +%.ln: $(OBPPLATHDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + +%: $(OBPCMNDIR)/%.sh + $(RM) $@ + cat $< > $@ + chmod +x $@ diff --git a/usr/src/psm/stand/bootblks/obp-c/Makefile.targ b/usr/src/psm/stand/bootblks/obp-c/Makefile.targ new file mode 100644 index 0000000000..1b9e6bf55d --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/Makefile.targ @@ -0,0 +1,61 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/obp-c/Makefile.targ +# + +# +# Targets for the C-only bootblock +# +.PARALLEL: $(BOOT_SRT) $(BOOT_OBJS) $(BOOT_L_OBJS) + +$(PROG).elf: $(BOOT_SRT) $(BOOT_OBJS) $(MAPFILE) + $(LD) $(LDFLAGS) -o $@ $(BOOT_SRT) $(BOOT_OBJS) $(LDLIBS) + +$(MKBOOT): $(OBPCMNDIR)/$$(@).c + $(NATIVECC) -o $@ $(OBPCMNDIR)/$@.c + +$(PROG): $(PROG).elf + +bbvers.c: $(MKVERS) + @-$(RM) $@ + ./$(MKVERS) ${ECHO} $(PROG) $@ + +clean: + -$(RM) $(BOOT_SRT) $(BOOT_OBJS) + -$(RM) $(BOOT_L_OBJS) + -$(RM) bbvers.c a.out core + +clobber: clean + -$(RM) $(PROG) $(PROG).elf bootblk.version + -$(RM) $(MKVERS) $(MKBOOT) + +lint: $(BOOT_L_OBJS) + @echo "Global Cross-checks:" + $(LINT.2) $(BOOT_L_OBJS) $(LDLIBS) + +FRC: diff --git a/usr/src/psm/stand/bootblks/obp-c/common/cbootblk.h b/usr/src/psm/stand/bootblks/obp-c/common/cbootblk.h new file mode 100644 index 0000000000..7a0565e88c --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/common/cbootblk.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1994, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _CBOOTBLK_H +#define _CBOOTBLK_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int openfile(char *, char *); +extern int closefile(int); +extern int readfile(int, char *, int); +extern void seekfile(int, off_t); + +extern void exit(void); +extern void puts(char *); +extern int utox(char *p, u_int n); + +extern void fw_init(void *); + +extern char *getbootdevice(char *); + +extern int devbread(void *, void *, int, int); +extern void *devopen(char *); +extern int devclose(void *); +extern void get_rootfs_start(char *device); +extern u_int fdisk2rootfs(u_int offset); + +extern void bcopy(const void *, void *, size_t); +extern void bzero(void *, size_t); +extern int strcmp(const char *, const char *); +extern int strncmp(const char *, const char *, size_t); +extern size_t strlen(const char *); +extern char *strcpy(char *, const char *); + +extern void main(void *); +extern void exitto(void *, void *); + +extern char ident[]; +extern char fscompname[]; +extern unsigned long read_elf_file(int, char *); +void sync_instruction_memory(caddr_t, u_int); + +#ifdef __cplusplus +} +#endif + +#endif /* _CBOOTBLK_H */ diff --git a/usr/src/psm/stand/bootblks/obp-c/common/makevers.sh b/usr/src/psm/stand/bootblks/obp-c/common/makevers.sh new file mode 100644 index 0000000000..4665376d29 --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/common/makevers.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 1991-2000, 2003 Sun Microsystems, Inc. +# All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +ECHO=$1 +BOOTER=$2 +FILENAME=$3 + +BANNER="${BOOTER} 1.0 #" + +test -f ${BOOTER}.version || echo 0 > ${BOOTER}.version +read OLDVERS < ${BOOTER}.version; export OLDVERS +VERS=`expr ${OLDVERS} + 1` +echo $VERS > ${BOOTER}.version + +( + SCCSSTRING="@(#)${FILENAME}\tDERIVED\t%E% SMI" + ${ECHO} "/*" ; \ + ${ECHO} " * This file is derived by makevers.sh" ; \ + ${ECHO} " */\n" ; \ + ${ECHO} "#pragma\tident\t\"${SCCSSTRING}\"\n" ; \ + ${ECHO} "char ident[] = \"@(#)${BANNER}${VERS} %G%\\\n\";" +) > ${FILENAME} diff --git a/usr/src/psm/stand/bootblks/obp-c/common/mkboot.c b/usr/src/psm/stand/bootblks/obp-c/common/mkboot.c new file mode 100644 index 0000000000..5f2f058723 --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/common/mkboot.c @@ -0,0 +1,172 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1992-1994, 2002-2003 Sun Microsystems, Inc. + * All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/exechdr.h> +#include <sys/elf.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <strings.h> + +#define BBSIZE (15 * 512) + +static Elf32_Ehdr elfhdr; +static Elf32_Phdr phdr, dphdr; +static char buf[4096]; + +int +main(int argc, char **argv) +{ + struct exec exec; + int ifd, ofd; + int count; + int text_written = 0; + int data_written = 0; + + if (argc < 3) { + (void) printf("usage: %s elf_file a.outfile\n", argv[0]); + exit(1); + } + if ((ifd = open(argv[1], O_RDONLY)) == -1) { + perror("open input"); + exit(1); + } + if (read(ifd, &elfhdr, sizeof (elfhdr)) < sizeof (elfhdr)) { + perror("read elfhdr"); + exit(1); + } + if ((ofd = open(argv[2], O_RDWR | O_TRUNC | O_CREAT, 0777)) == -1) { + perror("open aout"); + exit(1); + } + + if (elfhdr.e_ident[EI_MAG0] != ELFMAG0 || + elfhdr.e_ident[EI_MAG1] != ELFMAG1 || + elfhdr.e_ident[EI_MAG2] != ELFMAG2 || + elfhdr.e_ident[EI_MAG3] != ELFMAG3) { + perror("elfmagic"); + exit(1); + } + if (lseek(ifd, elfhdr.e_phoff, 0) == -1) { + perror("lseek"); + exit(1); + } + if (read(ifd, &phdr, sizeof (phdr)) < sizeof (phdr)) { + perror("read phdr"); + exit(1); + } + if (read(ifd, &dphdr, sizeof (dphdr)) < sizeof (dphdr)) { + perror("read dphdr"); + exit(1); + } + + /* + * Create an a.out header that will fool the PROM + */ + bzero(&exec, sizeof (exec)); + exec.a_toolversion = 1; +#ifdef sparc + exec.a_machtype = M_SPARC; +#else +#error "unknown machine type!" +#endif + exec.a_magic = OMAGIC; + exec.a_text = dphdr.p_vaddr - phdr.p_vaddr; + exec.a_data = dphdr.p_filesz; + exec.a_bss = dphdr.p_memsz - dphdr.p_filesz; + exec.a_entry = elfhdr.e_entry; + +#define text exec.a_text +#define data exec.a_data +#define bss exec.a_bss + + if (write(ofd, &exec, sizeof (exec)) != sizeof (exec)) { + perror("write exec"); + exit(1); + } + + /* + * Text section + */ + (void) printf("%d", text); + if (lseek(ifd, phdr.p_offset, 0) == -1) { + perror("lseek text"); + exit(1); + } + while (text_written < text && + (count = read(ifd, buf, sizeof (buf))) > 0) { + if (count > exec.a_text - text_written) + count = (exec.a_text - text_written); + if (write(ofd, buf, count) < count) { + perror("write text file"); + exit(1); + } + text_written += count; + } + /* Include a.out header in the accounting */ + text_written += sizeof (exec); + + /* + * Data section + */ + if (lseek(ifd, dphdr.p_offset, 0) == -1) { + perror("lseek data"); + exit(1); + } + (void) printf(" + %d (%d/0x%x)", data, text+data, text+data); + while (data_written < data && + (count = read(ifd, buf, sizeof (buf))) > 0) { + if (count > data - data_written) + count = (data - data_written); + if (write(ofd, buf, count) < count) { + perror("write data file"); + exit(1); + } + data_written += count; + } + (void) printf(" + %d (%d/0x%x)\n", bss, text+data+bss, text+data+bss); + (void) close(ofd); + (void) close(ifd); + + if (text_written + data_written > BBSIZE) { + (void) printf("*** WARNING! ***\n" + "Do not install this bootblock!\n"); + (void) printf("bootblock image is %d bytes too big.\n", + (text_written + data_written) - BBSIZE); + exit(1); + } + + (void) printf("bootblock %d%% full - %d bytes to spare.\n", + (text_written + data_written) * 100 / BBSIZE, + BBSIZE - (text_written + data_written)); + return (0); +} diff --git a/usr/src/psm/stand/bootblks/obp-c/common/romp.h b/usr/src/psm/stand/bootblks/obp-c/common/romp.h new file mode 100644 index 0000000000..faa6ceca4a --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/common/romp.h @@ -0,0 +1,226 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_ROMP_H +#define _SYS_ROMP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Autoconfig operations + */ + +struct config_ops { +#ifdef _KERNEL + dnode_t (*devr_next)(/* dnode_t nodeid */); + dnode_t (*devr_child)(/* dnode_t nodeid */); +#else /* _KERNEL */ + int (*devr_next)(/* dnode_t nodeid */); + int (*devr_child)(/* dnode_t nodeid */); +#endif /* _KERNEL */ + int (*devr_getproplen)(/* dnode_t nodeid, char *name */); + int (*devr_getprop)(/* dnode_t nodeid, char *name, caddr_t buf */); + int (*devr_setprop)(/* dnode_t nodeid, char *name, caddr_t value, + uint_t size */); + caddr_t (*devr_nextprop)(/* dnode_t nodeid, char *previous */); +}; + +struct romvec_obp { + uint_t op_magic; /* magic mushroom */ + uint_t op_romvec_version; /* Version number of "romvec" */ + uint_t op_plugin_version; /* Plugin Architecture version */ + uint_t op_mon_id; /* version # of monitor firmware */ + + struct memlist **v_physmemory; /* total physical memory list */ + struct memlist **v_virtmemory; /* taken virtual memory list */ + struct memlist **v_availmemory; /* available physical memory */ + struct config_ops *op_config_ops; /* dev_info configuration access */ + + /* + * storage device access facilities + */ + char **v_bootcmd; /* expanded with PROM defaults */ + uint_t (*v_open)(/* char *name */); + uint_t (*v_close)(/* ihandle_t fileid */); + + /* + * block-oriented device access + */ + uint_t (*v_read_blocks)(); + uint_t (*v_write_blocks)(); + + /* + * network device access + */ + uint_t (*v_xmit_packet)(); + uint_t (*v_poll_packet)(); + + /* + * byte-oriented device access + */ + uint_t (*v_read_bytes)(); + uint_t (*v_write_bytes)(); + + /* + * 'File' access - i.e., Tapes for byte devices. + * TFTP for network devices + */ + uint_t (*v_seek)(); + + /* + * single character I/O + */ + uchar_t *v_insource; /* Current source of input */ + uchar_t *v_outsink; /* Currrent output sink */ + uchar_t (*v_getchar)(); /* Get a character from input */ + void (*v_putchar)(); /* Put a character to output sink. */ + int (*v_mayget)(); /* Maybe get a character, or "-1". */ + int (*v_mayput)(); /* Maybe put a character, or "-1". */ + + /* + * Frame buffer + */ + void (*v_fwritestr)(); /* write a string to framebuffer */ + + /* + * Miscellaneous Goodies + */ + void (*op_boot)(/* char *bootspec */); /* reboot machine */ + int (*v_printf)(); /* handles fmt string plus 5 args */ + void (*op_enter)(); /* Entry for keyboard abort. */ + int *op_milliseconds; /* Counts in milliseconds. */ + void (*op_exit)(); /* Exit from user program. */ + + /* + * Note: Different semantics for V0 versus other op_vector_cmd: + */ + void (**op_vector_cmd)(); /* Handler for the vector */ + void (*op_interpret)(/* char *string, ... */); + /* interpret forth string */ + + /* boot parameters and 'old' style device access */ + struct bootparam **v_bootparam; + + uint_t (*v_mac_address)(/* int fd, caddr_t buf */); + /* Copyout ether address */ + + /* + * new V2 openprom stuff + */ + + char **op2_bootpath; /* Full path name of boot device */ + char **op2_bootargs; /* Boot command line after dev spec */ + +#ifdef _KERNEL + ihandle_t *op2_stdin; /* Console input device */ + ihandle_t *op2_stdout; /* Console output device */ + + phandle_t (*op2_phandle)(/* ihandle_t */); + /* Convert ihandle to phandle */ +#else /* _KERNEL */ + int *op2_stdin; /* Console input device */ + int *op2_stdout; /* Console output device */ + + int (*op2_phandle)(/* ihandle_t */); + /* Convert ihandle to phandle */ +#endif /* _KERNEL */ + + caddr_t (*op2_alloc)(/* caddr_t virthint, uint_t size */); + /* Allocate physical memory */ + + void (*op2_free)(/* caddr_t virthint, uint_t size */); + /* Deallocate physical memory */ + + caddr_t (*op2_map)(/* caddr_t virthint, uint_t space, uint_t phys, + uint_t size */); /* Create device mapping */ + + void (*op2_unmap)(/* caddr_t virt, uint_t size */); + /* Destroy device mapping */ + +#ifdef _KERNEL + ihandle_t (*op2_open)(/* char *name */); +#else /* _KERNEL */ + int (*op2_open)(/* char *name */); +#endif /* _KERNEL */ + uint_t (*op2_close)(/* int ihandle */); + + int (*op2_read)(/* int ihandle, caddr_t buf, uint_t len */); + int (*op2_write)(/* int ihandle, caddr_t buf, uint_t len */); + int (*op2_seek)(/* int ihandle, uint_t offsh, uint_t offsl */); + + void (*op2_chain)(/* caddr_t virt, uint_t size, caddr_t entry, + caddr_t argaddr, uint_t arglen */); + + void (*op2_release)(/* caddr_t virt, uint_t size */); + + /* + * End V2 stuff + */ + + caddr_t (*op3_alloc)(/* caddr_t virthint, uint_t size, int align */); + /* Allocate mem and align */ + + int *v_reserved[14]; + + /* + * Sun4c specific romvec routines (From sys/sun4c/machine/romvec.h) + * Common to all PROM versions. + */ + + void (*op_setcxsegmap)(/* int ctx, caddr_t v, int pmgno */); + /* Set segment in any context. */ + + /* + * V3 MP only functions: It's a fatal error to call these from a UP. + */ + + int (*op3_startcpu)(/* dnode_t moduleid, dev_reg_t contextable, + int whichcontext, caddr_t pc */); + + int (*op3_stopcpu)(/* dnode_t */); + + int (*op3_idlecpu)(/* dnode_t */); + int (*op3_resumecpu)(/* dnode_t */); +}; + +union sunromvec { + struct romvec_obp obp; +}; + +extern union sunromvec *romp; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_ROMP_H */ diff --git a/usr/src/psm/stand/bootblks/obp-c/common/stub.c b/usr/src/psm/stand/bootblks/obp-c/common/stub.c new file mode 100644 index 0000000000..13b204597b --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/common/stub.c @@ -0,0 +1,101 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999, 2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Stub for deprecated OBP V0 and V2 systems (sun4c). + */ + +#include <sys/param.h> +#include <sys/promif.h> +#include "romp.h" + +/* + * XXX Should be 'static'; 'extern' definition in header files prevent this + */ +union sunromvec *romp; + +#define OBP_V0_ROMVEC_VERSION 0 +#define OBP_ROMVEC_VERSION (romp->obp.op_romvec_version) +#define OBP_V0_PRINTF (*romp->obp.v_printf) +#define OBP_V2_WRITE (*romp->obp.op2_write) +#define OBP_V2_STDOUT (*romp->obp.op2_stdout) +#define OBP_EXIT_TO_MON (*romp->obp.op_exit) + +static void +fw_init(void *ptr) +{ + romp = ptr; +} + +void +exit() +{ + OBP_EXIT_TO_MON(); +} + +static void +putchar(char c) +{ + while (OBP_V2_WRITE(OBP_V2_STDOUT, &c, 1) != 1) + ; +} + +static void +puts(char *msg) +{ + char c; + + if (OBP_ROMVEC_VERSION == OBP_V0_ROMVEC_VERSION) + OBP_V0_PRINTF(msg); + else { + /* prepend carriage return to linefeed */ + while ((c = *msg++) != '\0') { + if (c == '\n') + putchar('\r'); + putchar(c); + } + } +} + +void +main(void *ptr) +{ + fw_init(ptr); + puts("This hardware platform is not supported by this " + "release of Solaris.\n"); +} + +void +bzero(void *p, size_t n) +{ + char zeero = 0; + char *cp = p; + + while (n != 0) + *cp++ = zeero, n--; /* Avoid clr for 68000, still... */ +} diff --git a/usr/src/psm/stand/bootblks/obp-c/common/unix_devio.c b/usr/src/psm/stand/bootblks/obp-c/common/unix_devio.c new file mode 100644 index 0000000000..b1399b9ccd --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/common/unix_devio.c @@ -0,0 +1,124 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1991-1994, Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Emulate the firmware on Unix + * Only useful for testing the boot block code. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/param.h> + +int +devbread(void *handle, void *buf, int blkno, int size) +{ + int fd = (int)handle; + + if (lseek(fd, (off_t) blkno * DEV_BSIZE, SEEK_SET) == -1) + perror("lseek"), exit(1); + return (read(fd, buf, size)); +} + +void * +devopen(char *devname) +{ + int fd; + + if ((fd = open(devname, O_RDONLY)) == -1) { + perror(devname); + return (NULL); + } + return ((void *)fd); +} + +int +devclose(void *handle) +{ + int fd = (int)handle; + + return (close(fd)); +} + +#define SZBUF 511 /* or 513? */ + +static void +usage(void) +{ + char mess[] = "Usage:\ta.out raw-device pathname\n"; + + write(2, mess, strlen(mess) + 1); + exit(1); +} + +static void +openfail(void) +{ + char mess[] = "openfile failed\n"; + + write(2, mess, strlen(mess) + 1); + exit(2); +} + +extern int openfile(char *, char *); +extern int readfile(int, char *, size_t); +extern int closefile(int); + +int +main(int argc, char *argv[]) +{ + char buf[SZBUF]; + int fd, count; + + if (argc != 3) + usage(); + if ((fd = openfile(argv[1], argv[2])) == -1) + openfail(); + while ((count = readfile(fd, buf, SZBUF)) != 0) + write(1, buf, count); + (void) closefile(fd); + return (0); +} + +/* + * Sigh. These shouldn't be needed. + */ +void +bcopy(void *from, void *to, size_t howmany) +{ + (void) memcpy(to, from, howmany); +} + +void +bzero(void *addr, size_t howmany) +{ + (void) memset(addr, 0, howmany); +} diff --git a/usr/src/psm/stand/bootblks/obp-c/sparc/common/mapfile b/usr/src/psm/stand/bootblks/obp-c/sparc/common/mapfile new file mode 100644 index 0000000000..5a96e9e689 --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/sparc/common/mapfile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 1992 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +text = LOAD ?RX V0x4000; +text : $PROGBITS ?A!W; + +data = LOAD ?RWX A0x1; +data : $PROGBITS ?AW; +data : $NOBITS ?AW; + +note = NOTE; +note : $NOTE; diff --git a/usr/src/psm/stand/bootblks/obp-c/sparc/common/obp_srt0.s b/usr/src/psm/stand/bootblks/obp-c/sparc/common/obp_srt0.s new file mode 100644 index 0000000000..e2d36ca37a --- /dev/null +++ b/usr/src/psm/stand/bootblks/obp-c/sparc/common/obp_srt0.s @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1986-1994, by Sun Microsystems, Inc. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * simple standalone startup code + */ + +#include <sys/asm_linkage.h> + +#if defined(lint) + +#include "cbootblk.h" + +/*ARGSUSED*/ +void +start(void *romp) +{} + +#else /* lint */ + + ENTRY(start) + .global end + .global edata + .global main + ! + ! OBP gives us control right here .. + ! + ! On entry, %o0 contains the romp. + ! + sethi %hi(start), %o1 ! Top of stack + or %o1, %lo(start), %o1 + save %o1, -SA(MINFRAME), %sp + ! + ! zero the bss + ! + sethi %hi(edata), %o0 ! Beginning of bss + or %o0, %lo(edata), %o0 + sethi %hi(end), %o2 ! End of the whole wad + or %o2, %lo(end), %o2 + call bzero + sub %o2, %o0, %o1 ! end - edata = size of bss + call main + mov %i0, %o0 ! romvec pointer + call exit + mov 0, %o0 + ret ! ret to prom + restore + SET_SIZE(start) + +#endif /* lint */ diff --git a/usr/src/psm/stand/bootblks/ufs/Makefile b/usr/src/psm/stand/bootblks/ufs/Makefile new file mode 100644 index 0000000000..bf5167906d --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/Makefile @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1989-1994,1998 by by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/ufs/Makefile +# + +SUBDIRS = $(MACH) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all install clean clobber lint : $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +# +# install targets +# +$(USR_SBIN): $(USR) + -$(INS.dir.root.bin) + +$(USR_SBIN)/%: % $(USR_SBIN) + $(INS.file) diff --git a/usr/src/psm/stand/bootblks/ufs/Makefile.ufs b/usr/src/psm/stand/bootblks/ufs/Makefile.ufs new file mode 100644 index 0000000000..31c97a8635 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/Makefile.ufs @@ -0,0 +1,58 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/ufs/Makefile.ufs +# + +include $(BASEDIR)/Makefile.com +include $(BASEDIR)/ufs/common/Makefile.com + +# +# This program is used to install the boot block +# +INSTALLBOOT = installboot + +# +# Where and how stuff gets installed +# +USR_PSM_BOOTBLOCK = $(USR_PSM_LIB_UFS_DIR)/$(PROG) + +USR = $(ROOT)/usr +USR_SBIN = $(USR)/sbin +USR_SBIN_INSTALLBOOT = $(USR_SBIN)/$(INSTALLBOOT) + +# +# Overrides for installing installboot. +# +INS.file.555 = $(RM) $@; $(INS) -s -m 555 -f $(@D) $< +$(CH)INS.file.555 = $(INS) -s -m 555 -u $(OWNER) -g $(GROUP) -f $(@D) $< + +# +# install rules +# +$(USR_SBIN)/%: % $(USR_SBIN) + $(INS.file.555) diff --git a/usr/src/psm/stand/bootblks/ufs/common/Makefile.com b/usr/src/psm/stand/bootblks/ufs/common/Makefile.com new file mode 100644 index 0000000000..b759d5cf8f --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/common/Makefile.com @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/ufs/common/Makefile.com +# + +THISDIR = $(BASEDIR)/ufs/common + +# +# Files that define the fs-reading capabilities of the C-based boot block +# +FS_C_SRCS = ufs.c + +# +# Allow ufs-specific files to find ufs-specific include files +# +$(FS_C_SRCS:%.c=%.o) := CPPINCS += -I$(THISDIR) + +# +# Pattern-matching rules for source in this directory +# +%.o: $(THISDIR)/%.c + $(COMPILE.c) -o $@ $< + +%.ln: $(THISDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +%.fcode: $(THISDIR)/%.fth + sed 's/sun4u/$(PLATFORM)/g' $< >$(<F) + $(TOKENIZE) $(<F) + @$(RM) -f $(<F) diff --git a/usr/src/psm/stand/bootblks/ufs/common/boot_1275.fth b/usr/src/psm/stand/bootblks/ufs/common/boot_1275.fth new file mode 100644 index 0000000000..8d0fe85209 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/common/boot_1275.fth @@ -0,0 +1,898 @@ +\ ident "%Z%%M% %I% %E% SMI" +\ Copyright 2005 Sun Microsystems, Inc. All rights reserved. +\ Use is subject to license terms. +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License, Version 1.0 only +\ (the "License"). You may not use this file except in compliance +\ with the License. +\ +\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ or http://www.opensolaris.org/os/licensing. +\ See the License for the specific language governing permissions +\ and limitations under the License. +\ +\ When distributing Covered Code, include this CDDL HEADER in each +\ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ If applicable, add the following below this CDDL HEADER, with the +\ fields enclosed by brackets "[]" replaced with your own identifying +\ information: Portions Copyright [yyyy] [name of copyright owner] +\ +\ CDDL HEADER END +\ +\ + + +id: @(#)ufs.fth 1.4 95/08/04 +purpose: UFS file system support package +copyright: Copyright 1995 Sun Microsystems, Inc. All Rights Reserved + +headers +" /packages" find-package 0= if + ." Can't find /packages" abort +then push-package +new-device + diagnostic-mode? if ." Loading " then + " ufs-file-system" device-name + diagnostic-mode? if + ." package 1.4 04 Aug 1995 13:02:54. " cr + then + + 0 0 " support" property + + : cstrlen ( cstr -- len ) + dup begin + dup c@ + while + char+ + repeat swap - + ; + + : cscount ( cstr -- adr,len ) dup cstrlen ; + + \ Append str1 to the end of str2 + : $append ( adr,len1 adr,len2 -- ) + 2over 2over ca+ swap cmove ( adr,len1 adr,len2 ) + rot + ca+ 0 swap c! drop ( ) + ; + + : $= ( str1$ str2$ -- same? ) + rot tuck <> if + 3drop false exit + then comp 0= + ; + + " /openprom/client-services" find-package 0= if + ." Can't find client-services" abort + then constant cif-phandle + + instance defer cif-claim ( align size virt -- base ) + instance defer cif-release ( size virt -- ) + + : find-cif-method ( adr,len -- acf ) + cif-phandle find-method drop + ; + + " claim" find-cif-method to cif-claim + " release" find-cif-method to cif-release + + : ufs-alloc-mem ( size -- virt ) 1 swap 0 cif-claim ; + : ufs-free-mem ( virt size -- ) swap cif-release ; + + \ + \ UFS low-level block routines + \ + + d# 512 constant ublock + d# 512 constant /super-block + d# 8 constant ndaddr + d# 16 constant super-block# ( -- n ) + + 0 instance value temp-block + 0 instance value indirect-block + 0 instance value indirect1-block + 0 instance value inode + 0 instance value super-block + + + \ Deblocker needs following + + \ read-blocks ( adr #blocks block# -- #blocks-read ) + \ write-blocks ( adr #blocks block# -- #blocks-written ) + + : quad@ ( adr -- l ) + \ For little-endian machines + \ l@ + \ For big-endian machines + la1+ l@ + ; + + : +sb ( index -- value ) super-block swap la+ l@ ; + : iblkno ( -- n ) d# 04 +sb ; + : cgoffset ( -- n ) d# 06 +sb ; + : cgmask ( -- n ) d# 07 +sb ; + : bsize ( -- n ) d# 12 +sb ; + : fragshift ( -- n ) d# 24 +sb ; + : fsbtodbc ( -- n ) d# 25 +sb ; + : inopb ( -- n ) d# 30 +sb ; + : ipg ( -- n ) d# 46 +sb ; + : fpg ( -- n ) d# 47 +sb ; + + : /frag ( -- fragsize ) bsize fragshift rshift ; + + + : read-ublocks ( adr len dev-block# -- error? ) + ublock * 0 " seek" $call-parent ?dup if exit then + ( adr len ) tuck " read" $call-parent <> + ; + : get-super-block ( -- error? ) + super-block /super-block super-block# read-ublocks + ; + + : cgstart ( cg -- block# ) + dup cgmask invert and cgoffset * swap fpg * + + ; + : cgimin ( cg -- block# ) cgstart iblkno + ; + + : blkstofrags ( #blocks -- #frags ) fragshift lshift ; + + : fsbtodb ( fs-blk# -- dev-blk# ) fsbtodbc lshift ; + + : read-fs-blocks ( adr len fs-blk# -- error? ) fsbtodb read-ublocks ; + + \ + \ UFS inode routines + \ + + h# 80 constant /inode + + instance variable blkptr + instance variable blklim + instance variable indirptr + instance variable indir1ptr + 0 instance value lblk# + + : itoo ( i# -- offset ) inopb mod ; + : itog ( i# -- group ) ipg / ; + : itod ( i# -- block# ) + dup itog cgimin swap ipg mod inopb / blkstofrags + + ; + + : +i ( n -- ) inode + ; + + : ftype ( -- n ) 0 +i w@ h# f000 and ; + : dir? ( -- flag ) ftype h# 4000 = ; + : symlink? ( -- flag ) ftype h# a000 = ; + : regular? ( -- flag ) ftype h# 8000 = ; + + : file-size ( -- n ) 8 +i quad@ ; + : direct0 ( -- adr ) d# 40 +i ; + : indirect0 ( -- adr ) d# 88 +i ; + \ : indirect1 ( -- adr ) d# 92 +i ; + + \ **** Select the indicated file for subsequent accesses + : rewind ( -- ) + direct0 blkptr ! indirect0 blklim ! indirect0 indirptr ! + 0 to lblk# + ; + + 0 instance value current-file + : select-file ( i# -- error? ) + dup to current-file + dup temp-block bsize rot itod + read-fs-blocks ?dup if exit then + itoo /inode * temp-block + inode /inode move + rewind + false + ; + + : l@++ ( ptr -- value ) dup @ l@ /l rot +! ; + + \ **** Locate the next block within the current file + : next-block# ( -- [ n ] error? ) + blkptr @ blklim @ = if + indirptr @ indirect0 = if + indirect-block bsize indirptr l@++ ( adr,len ) + read-fs-blocks if true exit then + indirect-block blkptr ! indirect-block bsize + blklim ! + + indirect1-block bsize indirptr l@++ ( adr,len ) + read-fs-blocks if true exit then + indirect1-block indir1ptr ! + else + indirect-block bsize indir1ptr l@++ ( adr,len ) + read-fs-blocks if true exit then + indirect-block blkptr ! indirect-block bsize + blklim ! + then + then + lblk# 1+ to lblk# + blkptr l@++ ( blk# ) ?dup 0= + ; + + : block#>fs-block# ( lblk# -- [ n ] error? ) + dup lblk# < if rewind then ( target-blk# ) + begin dup lblk# <> while ( target-blk# ) + next-block# if ( target-blk# ) + drop true exit + else ( target-blk# blk# ) + drop ( target-blk# ) + then ( target-blk# ) + repeat drop next-block# ( [ n ] error? ) + ; + + : read-one-block ( adr block# -- error? ) + block#>fs-block# ?dup if drop exit then + bsize swap read-fs-blocks + ; + + : get-dirblk ( -- error? ) + temp-block bsize next-block# 0= if + read-fs-blocks + else + 2drop true + then + ; + + \ + \ UFS directory routines + \ + + instance variable diroff + instance variable totoff + + 0 instance value current-dir + + \ **** Select the directory file + : init-dir ( i# -- error? ) + dup to current-dir + select-file ?dup if exit then + get-dirblk ?dup if exit then + 0 diroff ! 0 totoff ! + false + ; + + : root-dir? ( -- flag ) current-dir 2 = ; + + \ **** Return the address of the current directory entry + : dirent ( -- adr ) temp-block diroff @ + ; + + \ **** Select the next directory entry + : next-dirent ( -- end? ) + dirent la1+ w@ dup diroff +! totoff +! + totoff @ file-size >= if true exit then + diroff @ bsize = if + get-dirblk ?dup if exit then + diroff off + then + false + ; + + \ **** From directory, get handle of the file or subdir that it references + \ For Unix, file handle is the inode # + : file-handle ( -- i# ) dirent l@ ; + + \ **** From directory, get name of file + : file-name ( -- adr len ) dirent la1+ wa1+ dup wa1+ swap w@ ; + + \ **** Select the root directory + : froot ( -- error? ) 2 init-dir ; + + \ + \ UFS high-level routines + \ + \ After this point, the code should be independent of the disk format! + + : lookup ( adr len -- i# false | true ) + begin + 2dup file-name $= if ( adr,len ) + 2drop file-handle ( i# ) + dup select-file ?dup if ( i# true ) + nip ( true ) + else ( i# ) + false ( i# false ) + then exit + then ( adr,len ) + next-dirent ( adr,len end? ) + until 2drop true ( true ) + ; + + + h# 200 instance buffer: fpath-buf + + : follow-symlink ( tail$ -- tail$" ) + temp-block 0 read-one-block if 2drop exit then ( tail-$ ) + temp-block cscount ( tail-$ head-$' ) + fpath-buf 0 $append ( $tail-$ ) + ?dup if ( $tail-$ ) + " /" fpath-buf cscount $append ( $tail-$ ) + fpath-buf cscount $append ( ) + else drop then ( ) + fpath-buf cscount ( tail-$' ) + over c@ ascii / = if ( path$ ) + froot if 2drop true exit then ( \path$ ) + ascii / left-parse-string 2drop ( path$ ) + else ( path$ ) + current-dir init-dir if 2drop true exit then ( tail-$ ) + then + ; + + : ($chdir ( adr len -- error? ) \ Fail if path is file, not dir + ?dup 0= if drop true exit then + over c@ ascii / = if ( path$ ) + froot if 2drop true exit then ( \path$ ) + ascii / left-parse-string 2drop ( path$ ) + else ( path$ ) + current-dir init-dir drop ( path$ ) + then ( path$ ) + begin ( path-$ ) + ascii / left-parse-string ( tail-$ head-$ ) + dup + while ( tail-$ head-$ ) + lookup if 2drop true exit then ( tail-$ i# ) + symlink? if ( tail-$ i# ) + drop follow-symlink ( tail-$' ) + else ( tail-$ i# ) + dir? 0= if 2drop drop true exit then ( tail-$ i# ) + init-dir if 2drop true exit then ( tail$ ) + then ( tail$ ) + repeat ( tail-$ head-$ ) + 2drop 2drop false + ; + + : $chdir ( dirpath$ -- error? ) + current-dir >r ($chdir if ( ) ( r: prev-dir ) + r> init-dir drop true ( error ) + else ( ) ( r: prev-dir ) + r> drop false ( ok ) + then ( error? ) + ; + + : .dirname ( inode# -- ) + begin ( inode# ) + file-handle over = if ( inode# ) + ." /" ( inode# ) + file-name type true ( inode# done ) + else ( inode# ) + false ( inode# done? ) + then ( inode# done? ) + next-dirent or ( inode# done? ) + until drop ( ) + ; + + \ + \ UFS installation routines + \ + + \ **** Allocate memory for necessary data structures + : allocate-ufs-buffers ( -- error? ) + /super-block ufs-alloc-mem to super-block + get-super-block ?dup if + ." failed to read super block" cr + super-block /super-block ufs-free-mem true exit + then + bsize ufs-alloc-mem to temp-block + bsize ufs-alloc-mem to indirect-block + bsize ufs-alloc-mem to indirect1-block + /inode ufs-alloc-mem to inode + false + ; + + : release ( -- ) + inode /inode ufs-free-mem + indirect-block bsize ufs-free-mem + indirect1-block bsize ufs-free-mem + temp-block bsize ufs-free-mem + super-block /super-block ufs-free-mem + ; + + false instance value file-open? + + \ UFS file interface + + 0 instance value deblocker + : init-deblocker ( -- okay? ) + " " " deblocker" $open-package to deblocker + deblocker if + true + else + ." Can't open deblocker package" cr false + then + ; + + \ Splits a string into two halves after the last occurrence of + \ a delimiter character. + \ adra,lena is the string after the delimiter + \ adrb,lenb is the string before and including the delimiter + \ lena = 0 if there was no delimiter + + \ adra,lena is the string after the delimiter + \ adrb,lenb is the string before and including the delimiter + \ lena = 0 if there was no delimiter + + : right-parse-string ( adr len char -- adra lena adrb lenb ) + >r 2dup + 0 ( adrb lenb adra 0 ) + + \ Throughout the loop, we maintain both substrings. + \ Each time through, we add a character to the "after" + \ string and remove it from the "before". + \ The loop terminates when either the "before" string + \ is empty or the desired character is found + + begin 2 pick while ( adrb lenb adra lena ) + over 1- c@ r@ = if \ Found it ( adrb lenb adra lena ) + r> drop 2swap exit ( adrb lenb adra lena ) + then + 2swap 1- 2swap swap 1- swap 1+ ( adrb lenb adra lena ) + repeat ( adrb lenb adr1 len1 ) + + dup if ( adrb lenb adr1 len1 ) + 2swap dup if 1- then ( adr1 len1 adrb lenb' ) + else ( adrb lenb adr1 len1 ) + 2swap ( adr1 len1 adrb lenb ) + then ( adra lena adrb lenb ) + + \ Character not found. lena is 0. + r> drop + ; + + h# 200 instance buffer: fpath1-buf + + : file-lookup ( fname$ -- i# false | true ) + begin lookup 0= while ( i# ) + dup select-file if drop true exit then ( i# ) + symlink? if ( i# ) + drop 0 0 follow-symlink ( path$/file$ ) + fpath1-buf 0 $append fpath1-buf cscount ( path$/file$ ) + ascii / right-parse-string ( file$ path$ ) + ?dup if ( file$ path$ ) + $chdir if 2drop true exit then else drop + then ( file$ ) + else false exit then ( file$ ) + current-dir init-dir if 2drop true exit then ( file$ ) + repeat true ( true ) + ; + + : ufs-open ( adr len -- success? ) + file-lookup if ( ) + false ( fail ) + else ( i# ) + select-file if ( ) + false ( fail ) + else ( ) + init-deblocker ( success? ) + then ( success? ) + then ( success? ) + ; + + : (cwd) ( -- ) tokenizer[ reveal ]tokenizer + root-dir? 0= if + current-dir " .." $chdir drop + (cwd) dup .dirname init-dir drop + then + ; + + h# 100 instance buffer: ufs-args + + : get-my-args ( -- adr,len ) + my-args ?dup if ( arg$ ) + ufs-args pack count bounds ?do + i c@ ascii | = if ascii / i c! then + i c@ ascii \ = if ascii / i c! then + loop + else + drop 0 ufs-args c! + then ufs-args count + ; + : ufs-args$ ( -- arg$ ) ufs-args count ; + + 0 instance value file-offset + + external + : block-size ( -- #bytes/block ) bsize ; + : max-transfer ( -- #bytes/block ) block-size 4 * ; + + : dma-alloc ( size -- virt ) " dma-alloc" $call-parent ; + : dma-free ( virt size -- ) " dma-free" $call-parent ; + + : read-blocks ( adr block# #blocks -- #read ) + 0 -rot bounds ?do ( adr block-count ) + over i read-one-block ?leave ( adr count ) + 1+ swap bsize ca+ swap ( adr' count+1 ) + loop nip + ; + + \ UFS Write is not supported + : write-blocks ( adr #blocks block# -- #blocks-written ) 3drop 0 ; + + : open ( -- okay? ) + allocate-ufs-buffers if false exit then + + \ Select the root directory + froot drop + + get-my-args " <NoFile>" $= if true exit then + + ufs-args$ ascii / right-parse-string ( file$ path$ ) + $chdir if 2drop release false exit then ( file$ ) + + \ Filename ends in "/"; select the directory and exit with success + dup 0= if 2drop true exit then ( file$ ) + + ufs-open ?dup if exit then ( failed? ) + + release false + ; + + : close ( -- ) + deblocker ?dup if close-package then + release + ; + + : read ( addr len -- actual-len ) + " read" deblocker $call-method dup if ( #bytes-read ) + dup file-offset + file-size > if ( #bytes-read ) + drop file-size file-offset - ( #bytes-left ) + then ( #bytes-read ) + then ( #bytes-read ) + dup file-offset + to file-offset ( actual-len ) + ; + + \ UFS Write is not supported + : write ( addr len -- actual-len ) 2drop 0 ; + + : size ( -- d ) file-size 0 ; + + + : seek ( offset.low offset.high -- failed? ) + + \ Return error if offset.hi != 0 + dup 0<> if 2drop true exit then ( offset.lo offset.hi ) + + \ Return error if offset.lo > file-size + over file-size > if 2drop true exit then ( offset.lo offset.hi ) + + \ Looks like a reasonable offset + over to file-offset ( offset.lo offset.hi ) + + \ Finally give the deblocker chance to adjust + " seek" deblocker $call-method ( offset.lo offset.hi failed? ) + ; + : load ( adr -- size ) file-size read ; + + headers + : restore-file ( i# -- ) + ?dup if + select-file 0= if regular? if file-offset 0 seek drop then then + then + ; + external + : dir ( -- ) + current-file + current-dir init-dir drop + begin file-name type cr next-dirent until + restore-file + ; + : cwd ( -- ) + current-file + root-dir? if ." /" else (cwd) then + restore-file + ; + + headers + +finish-device +pop-package + +id: @(#)boot.fth 1.6 95/08/04 +purpose: UFS File System Boot Block +copyright: Copyright 1995 Sun Microsystems, Inc. All Rights Reserved + +headers +" /packages/disk-label" find-package 0= if + ." Can't find /packages/disk-label" abort +then dup push-package ( phandle ) + +\ Find the previous "open" definition. +defer prev-open ( -- ok? ) +' false to prev-open +" open" rot find-method if to prev-open then + +external +: open ( -- okay? ) + \ Arg string is <part>[,<filespec>] + \ Split off partition, and handle filename + my-args ascii , left-parse-string ( file$ part$ ) + 2drop ?dup if ( file$ ) + " ufs-file-system" find-package if ( file$ phandle ) + interpose ( ) + else ( file$ ) + 2drop ( ) + then ( ) + else ( file ) + drop ( ) + then prev-open ( okay? ) +; +headers + +pop-package + +headers +" /chosen" find-package 0= if false then ( phandle ) +constant chosen-phandle + +" /openprom/client-services" find-package 0= if false then ( phandle ) +constant cif-phandle + +defer cif-claim ( align size virt -- base ) +defer cif-release ( size virt -- ) +defer cif-open ( cstr -- ihandle|0 ) +defer cif-close ( ihandle -- ) +defer cif-read ( len adr ihandle -- #read ) +defer cif-seek ( low high ihandle -- -1|0|1 ) +defer cif-peer ( phandle -- phandle ) +defer cif-getprop ( len adr cstr phandle -- ) + +: find-cif-method ( adr,len -- acf ) + cif-phandle find-method drop +; + +" claim" find-cif-method to cif-claim +" release" find-cif-method to cif-release +" open" find-cif-method to cif-open +" close" find-cif-method to cif-close +" read" find-cif-method to cif-read +" seek" find-cif-method to cif-seek +" peer" find-cif-method to cif-peer +" getprop" find-cif-method to cif-getprop + + +d# 256 constant /devname-buf +/devname-buf buffer: devname +: clear-devname-buf ( -- ) + devname /devname-buf 0 fill +; + +: devname$ ( -- adr,len ) devname cscount ; + +: chosen-property ( name$ -- value$ false -or- true ) + chosen-phandle get-package-property if true + else + decode-string 2swap 2drop false + then +; +: get-devname ( -- ) + clear-devname-buf + " bootpath" chosen-property if ( ) + ." Can't find bootpath" abort ( ) + then devname$ $append ( ) +; + +get-devname \ Initialize the device name buffer + +: bootargs ( -- adr,len ) + " bootargs" chosen-property if + ." Can't find bootargs" abort + then +; + +: printable? ( n -- flag ) \ true if n is a printable ascii character + dup bl th 7f within swap th 80 th ff between or +; +: white-space? ( n -- flag ) \ true is n is non-printable? or a blank + dup printable? 0= swap bl = or +; + +: -leading ( adr len -- adr' len' ) + begin dup while ( adr' len' ) + over c@ white-space? 0= if exit then + swap 1+ swap 1- + repeat +; + +: -trailing (s adr len -- adr len' ) + dup 0 ?do 2dup + 1- c@ white-space? 0= ?leave 1- loop +; +: strip-blanks ( adr,len -- adr,len' ) -trailing -leading ; + +: (option?) ( char -- rem$ true -or- false ) + >r bootargs begin strip-blanks ?dup while ( $r ) + bl left-parse-string r@ -rot ( $r char $l ) + strip-blanks ?dup if ( $r char $l ) + over dup c@ ascii - = if ( $r char $l adr ) + 1+ c@ ascii - = if ( $r char $l ) + 2drop r> 2drop 2drop false exit + then ( $r char $l ) + bounds 0 -rot ?do ( $r char flag ) + over i c@ = or ( $r char flag ) + loop nip if r> drop true exit then + else ( $r char $l adr ) + 2drop 2drop ( $r ) + then ( $r ) + else ( $r char adr ) + 2drop ( $r ) + then ( $r ) + repeat r> 2drop false ( false ) +; +: option? ( char -- flag ) + (option?) if 2drop true else false then +; + +\ : don't-boot? ( -- flag ) ascii L option? ; +: halt? ( -- flag ) ascii H option? ; + +: alternate-booter? ( -- fname true -or- false ) + ascii F (option?) if ( adr,len ) + strip-blanks ( adr,len' ) + bl left-parse-string 2swap 2drop ?dup if ( fname$ ) + true exit + then drop ( ) + then false ( false ) +; + +d# 256 constant /booter-name +/booter-name buffer: booter-name +: booter-name$ ( -- adr,len ) booter-name cscount ; +: clear-booter-name ( -- ) booter-name /booter-name 0 fill ; +: $cat-booter-name ( adr,len -- ) booter-name$ $append ; + +d# 256 constant /root-name +/root-name buffer: root-name +: root-name$ ( -- adr,len ) root-name cscount ; +: clear-root-name ( -- ) root-name /root-name 0 fill ; + +: root$ ( -- adr,len ) + clear-root-name ( ) + /root-name root-name ( len,adr ) + " name" drop ( len,adr cstr ) + 0 cif-peer ( len,adr cstr root ) + cif-getprop drop ( ) + " /" root-name$ $append ( ) + root-name$ ( rootname$ ) +; + +: plat-booter$ ( -- adr,len ) + clear-booter-name ( ) + alternate-booter? 0= if ( ) + " ufsboot" ( filename$ ) + then ( filename$ ) + over c@ ascii / <> if ( filename$ ) + " /platform/" $cat-booter-name ( filename$ ) + root$ $cat-booter-name ( filename$ ) + then $cat-booter-name booter-name$ ( booter$ ) +; + +: def-dirname$ ( -- dir$ ) " /platform/sun4u/" ; + +: def-booter$ ( -- adr,len ) + clear-booter-name ( ) + alternate-booter? 0= if ( ) + " ufsboot" ( filename$ ) + then ( filename$ ) + over c@ ascii / <> if ( filename$ ) + def-dirname$ $cat-booter-name ( filename$ ) + then $cat-booter-name booter-name$ ( booter$ ) +; + +d# 256 constant /filename-buf +/filename-buf buffer: filename-buf +: filename-buf$ ( -- adr,len ) filename-buf cscount ; +: clear-filename-buf ( -- ) filename-buf /filename-buf 0 fill ; +: $cat-filename ( adr,len -- ) filename-buf$ $append ; + +h# 10.0000 constant 1meg + +: ufs-fopen ( adr,len -- ihandle|0 ) drop cif-open ; +: ufs-fread ( buf,len ihandle -- #read ) >r swap r> cif-read ; +: ufs-fclose ( ihandle -- ) cif-close ; + +: fname>devname$ ( fname$ -- dev$ ) + clear-filename-buf ( fname$ ) + devname$ tuck $cat-filename ( fname$ len ) + " ," $cat-filename ( fname$ len ) + >r $cat-filename r> ( len ) + filename-buf$ rot ?do ( bufadr ) + dup i ca+ c@ ascii / = if ( bufadr ) + ascii | over i ca+ c! ( bufadr ) + then ( bufadr ) + loop drop filename-buf$ ( dev$ ) +; + +: set-file-size ( ihandle -- ) + " size" rot $call-method ( size.lo size.hi ) + drop " to file-size" evaluate +; + +h# 6000 constant loader-base + +: get-file ( adr fname$ -- fail? ) + fname>devname$ ufs-fopen ?dup if ( adr ihandle ) + dup set-file-size ( adr ihandle ) + over to loader-base ( adr ihandle ) + >r begin ( adr ) + dup 1meg r@ ufs-fread ( adr #read ) + ?dup while ( adr #read ) + ca+ ( adr" ) + repeat drop r> ufs-fclose false ( ok ) + else ( adr ) + drop true ( failed ) + then ( failed? ) +; + +: get-redirect-info ( -- partition true -or- false ) + loader-base " /.SUNW-boot-redirect" get-file if ( ) + false ( false ) + else ( adr ) + loader-base c@ ( part ) + dup ascii 0 ascii 9 between if ( part ) + diagnostic-mode? if ( part ) + ." Redirected to slice: " dup emit cr + then ( part ) + ascii 0 - ascii a + true ( part' true ) + else ( part ) + drop false ( false ) + then ( part true | false ) + then ( part true | false ) +; + +: update-devname ( part -- ) + clear-devname-buf ( part ) + get-devname devname$ ( part adr,len ) + + ca+ 1- dup 1- c@ ascii : = if ( part adr:x ) + c! ( ) + else ( part adr:x ) + 2drop ( ) + then ( ) +; + +: real-devname ( -- ) + get-redirect-info if ( part ) + update-devname ( ) + then ( ) +; + +: allocate-memory ( size -- virtual ) 1 swap 0 cif-claim ; +: free-memory ( virt size -- ) swap cif-release ; + +: sign-on ( -- ) + diagnostic-mode? if + ." FCode UFS Reader %I% %E% %U%. " cr + then +; + +: check-elf ( vadr -- flag ) l@ h# 7f454c46 ( \x7fELF ) = ; + +: force? ( -- flag ) ascii X option? ; + +: execit ( -- ) + \ we rely on the prom to do the right thing with the executable, since + \ it understands ELF32 and ELF64 + loader-base dup check-elf force? or if + " to load-base init-program" evaluate + else + drop ." Not a valid ELF file" cr exit + then +; + +: do-boot ( -- ) + sign-on real-devname +\ don't-boot? if exit then + halt? if + ." Halted with -H flag. " cr + exit + then + loader-base plat-booter$ ( adr,len ) + diagnostic-mode? if ." Loading: " 2dup type cr then + get-file if + loader-base def-booter$ + diagnostic-mode? if ." Loading: " 2dup type cr then + get-file if + ." Boot load failed." cr exit + then + then + execit +; + +do-boot diff --git a/usr/src/psm/stand/bootblks/ufs/common/boot_obp.fth b/usr/src/psm/stand/bootblks/ufs/common/boot_obp.fth new file mode 100644 index 0000000000..9714b61f56 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/common/boot_obp.fth @@ -0,0 +1,463 @@ +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License, Version 1.0 only +\ (the "License"). You may not use this file except in compliance +\ with the License. +\ +\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ or http://www.opensolaris.org/os/licensing. +\ See the License for the specific language governing permissions +\ and limitations under the License. +\ +\ When distributing Covered Code, include this CDDL HEADER in each +\ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ If applicable, add the following below this CDDL HEADER, with the +\ fields enclosed by brackets "[]" replaced with your own identifying +\ information: Portions Copyright [yyyy] [name of copyright owner] +\ +\ CDDL HEADER END +\ +\ Copyright 2000 Sun Microsystems, Inc. All rights reserved. +\ Use is subject to license terms. +\ +\ ident "%Z%%M% %I% %E% SMI" +\ +\ Unix 4.2 file system reader +\ + +\ When debugging, the sign on banner is on the stack +\ #ifdef DEBUG_BOOTBLK +\ type +\ #endif /* DEBUG_BOOTBLK */ + +decimal +headerless + +\ +\ Forth utility routines +\ +\ : $find 2dup type cr $find ; + +: boot-eval ( adr len -- ) + $find if + execute + else + type ." ?" cr exit + then +; + +\ " romvec" boot-eval constant romvec +variable boot-romvec + +: find-romvec + " romvec" $find if + execute + else + 2drop h# ffe8.0010 + then + boot-romvec ! +; + +find-romvec + +: roment ( offset -- adr ) boot-romvec @ + l@ ; + +" load-base" $find drop constant 'loadbase +\ " (is" $find drop constant '(is +\ " $=" $find drop constant '$= +" call" $find drop constant 'call + +: loadbase ( -- adr ) 'loadbase execute ; +\ : (is ( val acf -- ) '(is execute ; +\ : $= ( str1 str2 -- [ -1 | 0 | 1 ] ) '$= execute ; +: call ( ... addr -- ??? ) 'call execute ; +: loadbase! ( value -- ) 'loadbase " (is" boot-eval ; + +: devr_next ( nodeid -- next-nodeid ) h# 1c roment l@ call nip ; +: devr_getprop ( adr namecstr nodeid -- len|-1 ) h# 1c roment 3 la+ l@ call nip nip nip ; + +: boot-/string ( adr len size -- adr+size len-size ) tuck - >r + r> ; + +\ Splits a string around a delimiter. If the delimiter is found, +\ two strings are returned under true, otherwise one string under false. +: boot-$split ( adr len char -- remaining-adr len [ initial-adr len ] found? ) + 2 pick 2 pick bounds ?do + dup i c@ = if i nip -1 then + loop ( adr len adr' -1 | char ) + -1 = if ( adr len adr' ) + swap >r ( adr adr' ) ( r: len ) + 2dup swap - swap ( adr [adr'-adr] adr' ) ( r: len ) + 1+ r> ( adr [adr'-adr] adr'+1 len ) + 2 pick - 1- ( adr [adr'-adr] adr'+1 len-[adr'-adr-1] ) + 2swap true ( rem-adr,len initial-adr,len true ) + else + false + then +; + +\ +\ Device and driver section +\ + +512 constant ublock + +variable devid +variable nextblock \ holds seek target for V1 read-blocks + +: devname ( -- cstr ) + h# 88 roment @ \ bootpath +; + +\ Debug V2 or later PROMs +\ : devname " disk" drop ; + + +\ Debug V0 PROMS +\ : devname " sd(0,0,0)" drop ; + +: open-disk ( -- error? ) + devname + " op-open" + boot-eval dup if + dup devid ! + then + 0= ( invert sense of error flag ) +; + +: close-disk ( -- ) + devid @ " op-close" boot-eval drop +; + +: read-blks ( adr len -- error? ) + ( len adr devid -- #bytes_read ) + tuck swap devid @ " op-read" boot-eval <> +; + +: seek ( low high -- error? ) + ( low high devid -- ? ) + devid @ " op-seek" boot-eval 0< +; + +\ +\ UFS low-level block routines +\ + +512 constant /super-block +8 constant ndaddr +16 constant super-block# ( -- n ) + +0 constant temp-block +0 constant indirect-block +0 constant inode +0 constant super-block + +: quad@ ( adr -- l ) +\ For little-endian machines +\ l@ +\ For big-endian machines + la1+ l@ +; + +: +sb ( index -- value ) super-block swap la+ l@ ; +: iblkno ( -- n ) 4 +sb ; +: cgoffset ( -- n ) 6 +sb ; +: cgmask ( -- n ) 7 +sb ; +: bsize ( -- n ) 12 +sb ; +: fragshift ( -- n ) 24 +sb ; +: fsbtodbc ( -- n ) 25 +sb ; +: inopb ( -- n ) 30 +sb ; +: ipg ( -- n ) 46 +sb ; +: fpg ( -- n ) 47 +sb ; + +: read-ublocks ( adr len dev-block# -- error? ) + ublock * 0 seek ?dup if exit then + ( adr len ) read-blks +; + +: get-super-block ( -- error? ) + super-block /super-block super-block# read-ublocks +; + +: cgstart ( cg -- block# ) + dup cgmask not and cgoffset * swap fpg * + +; +: cgimin ( cg -- block# ) cgstart iblkno + ; + +: blkstofrags ( #blocks -- #frags ) fragshift << ; + +: fsbtodb ( fs-blk# -- dev-blk# ) fsbtodbc << ; + +: read-fs-blocks ( adr len fs-blk# -- error? ) fsbtodb read-ublocks ; + +\ +\ UFS inode routines +\ + +h# 80 constant /inode + +variable blkptr +variable blklim +variable indirptr + +: itoo ( n -- offset ) inopb mod ; +: itog ( n -- group ) ipg / ; +: itod ( n -- block# ) + dup itog cgimin swap ipg mod inopb / blkstofrags + +; + +: +i ( n -- ) inode + ; +: dir? ( -- flag ) 0 +i w@ h# 4000 and 0<> ; \ **** +: filesize ( -- n ) 8 +i quad@ ; \ **** +: direct0 ( -- adr ) 40 +i ; +: indirect0 ( -- adr ) 88 +i ; + +\ **** Select the indicated file for subsequent accesses +: select-file ( file-handle -- error? ) + dup temp-block bsize rot itod + read-fs-blocks ?dup if exit then + itoo /inode * temp-block + inode /inode move + direct0 blkptr ! indirect0 blklim ! indirect0 indirptr ! + false +; + +: l@++ ( ptr -- value ) dup @ l@ /l rot +! ; + +\ **** Locate the next block within the current file +: next-block# ( -- n ) + blkptr @ blklim @ = if + indirect-block bsize indirptr l@++ + read-fs-blocks drop ( XXX - what about the error? ) + indirect-block blkptr ! indirect-block bsize + blklim ! + then + blkptr l@++ ( blk# ) +; +: get-dirblk ( -- error? ) temp-block bsize next-block# read-fs-blocks ; + +\ +\ UFS directory routines +\ + +variable diroff +variable totoff +variable current-dir + +\ **** Select the directory file +: init-dir ( file-handle -- error? ) + dup current-dir ! + select-file ?dup if exit then + get-dirblk ?dup if exit then + 0 diroff ! 0 totoff ! + false +; + +\ **** Return the address of the current directory entry +: dirent ( -- adr ) temp-block diroff @ + ; + +\ **** Select the next directory entry +: next-dirent ( -- end? ) + dirent la1+ w@ dup diroff +! totoff +! + totoff @ filesize >= if true exit then + diroff @ bsize = if + get-dirblk ?dup if exit then + diroff off + then + false +; + +\ **** From directory, get handle of the file or subdir that it references +\ For Unix, file handle is the inode # +: file-handle ( -- file-handle ) dirent l@ ; + +\ **** From directory, get name of file +: file-name ( -- adr len ) dirent la1+ wa1+ dup wa1+ swap w@ ; + +\ **** Select the root directory +: froot ( -- error? ) 2 init-dir ; + +\ +\ UFS high-level routines +\ +\ After this point, the code should be independent of the disk format! + +: dir ( -- ) begin file-name type cr next-dirent until ; + +: lookup ( adr len -- not-found? ) + begin + 2dup file-name " $=" boot-eval if 2drop false exit then + next-dirent + until + 2drop true +; +: path-lookup ( adr len -- not-found? ) + dup 0= if 2drop true exit then + over c@ ascii / = if 1 boot-/string then + froot if 2drop true exit then + begin + ascii / boot-$split ( rem-adr len [ adr len ] delim-found? ) + while + lookup if 2drop true exit then + dir? 0= if 2drop true exit then + file-handle init-dir if 2drop true exit then + repeat ( rem-adr len ) + + \ Now we have found the directory containing the file + lookup ?dup if exit then + file-handle select-file +; + +\ +\ File reading, loading, etc. +\ ELF-specific routines go here. +\ + +: read-file ( adr -- error? ) + filesize begin ( adr remaining ) + dup 0> + while + over bsize next-block# + read-fs-blocks ?dup if exit then + ( adr remaining ) bsize boot-/string + repeat + 2drop false +; + +\ +\ ELF support +\ + +0 constant elfhdr +0 constant phdr + +: +w_elfhdr ( index -- value ) elfhdr swap ca+ w@ ; +: +l_elfhdr ( index -- value ) elfhdr swap ca+ l@ ; +: e_entry ( -- n ) 24 +l_elfhdr ; +: e_phoff ( -- n ) 28 +l_elfhdr ; +: e_phentsize ( -- n ) 42 +w_elfhdr ; +: e_phnum ( -- n ) 44 +w_elfhdr ; + +1 constant pt_load +: +phdr ( index -- value ) phdr swap la+ l@ ; +: p_type ( -- n ) 0 +phdr ; +: p_offset ( -- n ) 1 +phdr ; +: p_vaddr ( -- n ) 2 +phdr ; +: p_filesz ( -- n ) 4 +phdr ; +: p_memsz ( -- n ) 5 +phdr ; +: p_flags ( -- n ) 6 +phdr ; +: p_align ( -- n ) 7 +phdr ; + +: check-elf ( filebase -- is-elf? ) + l@ h# 7f454c46 ( \x7fELF ) = +; + +: get-phdr ( filebase index -- ) + e_phentsize * e_phoff + + + phdr e_phentsize move +; + +: load-elf ( filebase -- entry-point ) + dup is elfhdr + e_phentsize alloc-mem is phdr + e_phnum 0 ?do + dup i get-phdr + p_type pt_load = if + ( read it ) + dup p_offset + p_vaddr p_filesz move + p_memsz p_filesz > if + ( zero the bss ) + p_vaddr p_filesz + p_memsz p_filesz - 0 fill + then + then + loop drop + phdr e_phentsize free-mem + e_entry +; + +\ +\ UFS installation routines +\ + +\ **** Allocate memory for necessary data structures +: allocate-ufs-buffers ( -- error? ) + /super-block alloc-mem is super-block + get-super-block ?dup if + ." failed to read super block" cr + super-block /super-block free-mem close-disk exit + then + bsize alloc-mem is temp-block + bsize alloc-mem is indirect-block + /inode alloc-mem is inode + false +; + +: release ( -- ) + inode /inode free-mem + indirect-block bsize free-mem + temp-block bsize free-mem + super-block /super-block free-mem + close-disk +; + +: initialize ( -- error? ) + open-disk ?dup if exit then + allocate-ufs-buffers +; + +hex +headers +( external ) + +: get-file ( load-adr name-adr name-len -- error? ) + initialize ?dup if nip nip nip exit then ( ) + path-lookup ?dup if nip release exit then ( ) + dir? ?dup if ( load-adr error? ) + nip ." File is a directory." cr release exit + then ( load-adr ) + read-file ?dup if ." File read failed." cr exit then ( ) + \ Set FORTH file-size variable + filesize " file-size" boot-eval ! + release false ( ok ) +; + +: reloc&go ( -- ) + loadbase + \ Is it ELF? + dup check-elf if ( base-adr ) + load-elf ( entry-point ) + loadbase! + " init-program" boot-eval + else ( base-adr ) +\ Let FORTH handle anything else + " adjust-header" boot-eval if " init-program" boot-eval then ( entry-point ) + loadbase! + then + 4000 loadbase! + " ?go" boot-eval +; + +d# 128 buffer: boot-name + +: get-boot-name ( -- adr,len ) + boot-name d# 128 erase + " /platform/" boot-name swap dup >r cmove r> ( len0 ) + boot-name over + " name" drop ( len0 bufadr namestr ) + 0 devr_next devr_getprop ( len0 len ) + 1- + boot-name over + ( len1 adr ) + " /ufsboot" ( len1 adr adr,len ) + >r swap r@ cmove r> ( len1 len ) + + boot-name swap +; + +\ +\ The boot stuff itself +\ +: do-boot + 4000 loadbase! + loadbase get-boot-name get-file if + ." Boot load failed." cr exit + then + reloc&go +; + +do-boot diff --git a/usr/src/psm/stand/bootblks/ufs/common/iob.h b/usr/src/psm/stand/bootblks/ufs/common/iob.h new file mode 100644 index 0000000000..7797839b4a --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/common/iob.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1990-1994, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" /* from SunOS 4.1 */ + +/* + * This stuff keeps track of an open file in the standalone I/O system. + * + * The definitions herein are *private* to ufs.c + * + * It includes an IOB for device addess, an inode, a buffer for reading + * indirect blocks and inodes, and a buffer for the superblock of the + * file system (if any). + * + * To make the boot block smaller, we're using a 'bnode' (for boot node) + * struct instead of an inode struct. This contains just the common + * data from the on-disk inode. + */ + +struct saioreq { + off_t si_offset; + char *si_ma; /* memory address to r/w */ + int si_cc; /* character count to r/w */ +}; + +struct bnode +{ + dev_t i_dev; /* from inode struct */ + struct icommon i_ic; /* disk inode struct */ +}; + + +struct iob { + void *i_si; /* I/O handle for this file */ + struct { + off_t si_offset; + char *si_ma; /* memory address to r/w */ + int si_cc; /* character count to r/w */ + } i_saio; /* I/O request block */ + struct bnode i_ino; /* Inode for this file */ + char i_buf[MAXBSIZE]; /* Buffer for reading inodes & dirs */ + union { + struct fs ui_fs; /* Superblock for file system */ + char dummy[SBSIZE]; + } i_un; +}; + +/* + * XXX: i_fs conflicts with a definition in ufs_inode.h... + */ +#define iob_fs i_un.ui_fs diff --git a/usr/src/psm/stand/bootblks/ufs/common/ufs.c b/usr/src/psm/stand/bootblks/ufs/common/ufs.c new file mode 100644 index 0000000000..0d1f0f0540 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/common/ufs.c @@ -0,0 +1,375 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1991-1994, 2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* from "@(#)boot/ufssys.c 1.1 90/03/28 SMI" */ + +/* + * Basic file system reading code for standalone I/O system. + */ + +#include <sys/param.h> +#include <sys/vnode.h> +#include <sys/fs/ufs_fsdir.h> +#include <sys/fs/ufs_fs.h> +#include <sys/fs/ufs_inode.h> + +#include "iob.h" +#include "cbootblk.h" + +/* + * private definitions of ufs macros from sys/fs/ufs_fs.h + * due to boot block size problems, these macros are coded + * to use the older narrow file offset type (31 bit). This + * saves a lot of code space. Since we will never encounter + * a large file here, it is safe to cast offset_t to off_t. + */ + +#define bb_fragroundup(fs, size) /* roundup(size, fs->fs_fsize) */ \ + ((off_t)((size) + (fs)->fs_fsize - 1) & (off_t)(fs)->fs_fmask) + +#define bb_blksize(fs, ip, lbn) \ + (((lbn) >= NDADDR || \ + (off_t)(ip)->i_size >= (off_t)((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (bb_fragroundup(fs, blkoff(fs, (off_t)(ip)->i_size)))) + +#define NULL 0 + +static struct direct *readdir(struct iob *, int *); +static ino_t dlook(char *, struct iob *); +static int getblock(struct iob *io); + +char fscompname[] = "ufsboot"; + +static struct iob iob[1]; /* only one open file! */ + +static int +openi(ino_t n, struct iob *io) +{ + struct dinode *dp; + struct fs *fs = &io->iob_fs; + + io->i_saio.si_offset = 0; + if (devbread(io->i_si, io->i_buf, + fsbtodb(fs, itod(fs, n)), fs->fs_bsize) != fs->fs_bsize) + return (0); + dp = (struct dinode *)io->i_buf; + io->i_ino.i_ic = dp[itoo(fs, n)].di_ic; + return (1); +} + +static ino_t +find(char *nm, struct iob *file) +{ + char *q; + char c; + ino_t n; + char pathbuf[MAXPATHLEN], *path; + char *link; + size_t linklen; + int fmt = IFDIR; + + if (nm == NULL || *nm == '\0') + return (0); + bcopy(nm, pathbuf, strlen(nm) + 1); +root: + path = pathbuf; + if (openi((ino_t)UFSROOTINO, file) == 0) + return (0); + while (*path) { + while (*path == '/') + path++; + q = path; + while (*q != '/' && *q != '\0') + q++; + c = *q; + *q = '\0'; + + if ((n = dlook(path, file)) != 0) { + + *q = c; + if (openi(n, file) == 0) + return (0); + switch (fmt = (file->i_ino.i_smode & IFMT)) { + case IFREG: + case IFDIR: + break; + + case IFLNK: + if (getblock(file) != 0) + return (0); + link = (char *)file->i_saio.si_ma; + linklen = strlen(link); + if (*link == '/') + path = pathbuf; + /* + * Copy unprocessed pathname up & prepend link + * (Yes, this bcopy handles overlapping args) + */ + bcopy(q, path + linklen, strlen(q) + 1); + bcopy(link, path, linklen); + path = pathbuf; + goto root; + /*NOTREACHED*/ + + default: + return (0); + } + if (c == '\0') + break; + path = q; + continue; + } else + return (0); + } + + return (fmt == IFREG ? n : 0); +} + +static daddr_t +sbmap(struct iob *io, daddr_t bn) +{ + struct bnode *ip; + int i, j, sh; + daddr_t nb, *bap; + + /* These are the pools of buffers, iob's, etc. */ + + static union { + char b[NIADDR+1][MAXBSIZE]; + daddr_t *dummy; /* force alignment */ + } b; + static daddr_t blknos[NIADDR+1]; + + ip = &io->i_ino; + + /* + * blocks 0..NDADDR are direct blocks + */ + if (bn < NDADDR) + return (ip->i_db[bn]); + + /* + * addresses NIADDR have single and double indirect blocks. + * the first step is to determine how many levels of indirection. + */ + sh = 1; + bn -= NDADDR; + for (j = NIADDR; j > 0; j--) { + sh *= NINDIR(&io->iob_fs); + if (bn < sh) + break; + bn -= sh; + } + if (j == 0) + return ((daddr_t)0); + + /* + * fetch the first indirect block address from the inode + */ + nb = ip->i_ib[NIADDR - j]; + if (nb == 0) + return ((daddr_t)0); + + /* + * fetch through the indirect blocks + */ + for (; j <= NIADDR; j++) { + if (blknos[j] != nb) { + if (devbread(io->i_si, b.b[j], + fsbtodb(&io->iob_fs, nb), + io->iob_fs.fs_bsize) != io->iob_fs.fs_bsize) + return ((daddr_t)0); + blknos[j] = nb; + } + bap = (daddr_t *)b.b[j]; + sh /= NINDIR(&io->iob_fs); + i = (bn / sh) % NINDIR(&io->iob_fs); + nb = bap[i]; + if (nb == 0) + return ((daddr_t)0); + } + return (nb); +} + +static ino_t +dlook(char *s, struct iob *io) +{ + struct direct *dp; + struct bnode *ip; + int len, loc = 0; + + ip = &io->i_ino; + if (s == NULL || *s == '\0') + return (0); + if ((ip->i_smode & IFMT) != IFDIR || ip->i_size == 0) + return (0); + len = strlen(s); + for (dp = readdir(io, &loc); dp != NULL; dp = readdir(io, &loc)) { + if (dp->d_ino == 0) + continue; + if (dp->d_namlen == len && strcmp(s, dp->d_name) == 0) + return (dp->d_ino); + } + return (0); +} + +/* + * get next entry in a directory. + */ +static struct direct * +readdir(struct iob *io, int *loc_p) +{ + struct direct *dp; + daddr_t lbn, d; + int off; + int loc = *loc_p; + int bsize; + + for (;;) { + if (loc >= io->i_ino.i_size) + return (NULL); + off = blkoff(&io->iob_fs, loc); + if (off == 0) { + lbn = lblkno(&io->iob_fs, loc); + if ((d = sbmap(io, lbn)) == 0) + return (NULL); + bsize = bb_blksize(&io->iob_fs, &io->i_ino, lbn); + if (devbread(io->i_si, io->i_buf, + fsbtodb(&io->iob_fs, d), bsize) != bsize) + return (NULL); + } + dp = (struct direct *)(io->i_buf + off); + *loc_p = (loc += dp->d_reclen); + if (dp->d_ino == 0) + continue; + return (dp); + } +} + +static int +getblock(struct iob *io) +{ + struct fs *fs; + int off, size, diff; + daddr_t lbn; + + diff = io->i_ino.i_size - io->i_saio.si_offset; + if (diff <= 0) + return (-1); + fs = &io->iob_fs; + lbn = lblkno(fs, io->i_saio.si_offset); + off = blkoff(fs, io->i_saio.si_offset); + size = bb_blksize(fs, &io->i_ino, lbn); + io->i_saio.si_cc = size; + if (devbread(io->i_si, io->i_buf, + fsbtodb(fs, sbmap(io, lbn)), size) != size) + return (-1); + if (io->i_saio.si_offset - off + size >= io->i_ino.i_size) + io->i_saio.si_cc = diff + off; + io->i_saio.si_cc -= off; + + io->i_saio.si_ma = &io->i_buf[off]; + return (0); +} + +int +readfile(int fd, char *buf, int count) +{ + struct iob *io = &iob[fd]; + int i, j; + + if (io->i_saio.si_offset + count > io->i_ino.i_size) + count = io->i_ino.i_size - io->i_saio.si_offset; + if ((i = count) <= 0) + return (0); + while (i > 0) { + if (io->i_saio.si_cc <= 0) { + if (getblock(io) == -1) + return (0); + } + j = (i < io->i_saio.si_cc) ? i : io->i_saio.si_cc; + bcopy(io->i_saio.si_ma, buf, (size_t)j); + buf += j; + io->i_saio.si_ma += j; + io->i_saio.si_offset += j; + io->i_saio.si_cc -= j; + i -= j; + } + return (count); +} + +/* + * Open a file. + */ +int +openfile(char *device, char *pathname) +{ + struct iob *io = &iob[0]; /* only one open file! */ + + io->i_ino.i_dev = 0; + if ((io->i_si = devopen(device)) == NULL) + return (-1); /* if devopen fails, open fails */ + + /* Pseudo-mount a file system; read the superblock. */ + + if (devbread(io->i_si, &io->iob_fs, SBLOCK, SBSIZE) != SBSIZE) + goto failed; + if (io->iob_fs.fs_magic != FS_MAGIC) { + puts("bootblk: not a UFS file system.\n"); + goto failed; + } + if (find(pathname, io) == 0) + goto failed; + io->i_saio.si_offset = io->i_saio.si_cc = 0; + + return (0); /* only one open file! */ +failed: + (void) devclose(io->i_si); + return (-1); +} + +int +closefile(int fd) +{ + struct iob *io = &iob[fd]; + + return (devclose(io->i_si)); +} + +/* + * This version of seek() only performs absolute seeks (whence == 0). + */ +void +seekfile(int fd, off_t addr) +{ + struct iob *io = &iob[fd]; + + io->i_saio.si_offset = addr; + io->i_saio.si_cc = 0; +} diff --git a/usr/src/psm/stand/bootblks/ufs/i386/Makefile b/usr/src/psm/stand/bootblks/ufs/i386/Makefile new file mode 100644 index 0000000000..b11205a287 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/i386/Makefile @@ -0,0 +1,84 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/bootblks/ufs/i386/Makefile +# +.KEEP_STATE: + +BASEDIR = ../.. + +include $(BASEDIR)/ufs/Makefile.ufs + + +CC = $(GNU_ROOT)/bin/gcc +ASFLAGS = -B$(GNU_ROOT)/bin/ -fno-builtin -nostdinc +CPPFLAGS = + +LD = $(GNU_ROOT)/bin/gld +LDFLAGS = -nostdlib -N -Ttext 600 + +OBJCOPY = $(GNU_ROOT)/bin/gobjcopy + +INSTALL_DIR = $(USR)/lib/fs/ufs +INSTALL_TARGETS = $(PROGS:%=$(INSTALL_DIR)/%) + +$(INSTALL_TARGETS) := FILEMODE = 0444 + +PROGS = mboot + + +all: $(INSTALLBOOT) $(PROGS) + +$(PROGS): $$(@).exec + $(OBJCOPY) -O binary $@.exec $@ + +%.exec: %.o + $(LD) $(LDFLAGS) -o $@ $(@:exec=o) + + +install: all $(INSTALL_TARGETS) $(USR_SBIN_INSTALLBOOT) + +$(INSTALL_DIR)/%: $(INSTALL_DIR) % + $(INS.file) + +$(INSTALL_DIR): + $(INS.dir) + + +clean: + $(RM) $(PROGS) *.exec *.o $(INSTALLBOOT) + +clobber: clean + $(RM) $(INSTALL_TARGETS) $(INSTALLBOOT) + +# +# Pattern matching rules for source in this directory +# +%: %.sh + $(RM) $@ + cat $< > $@ + chmod +x $@ diff --git a/usr/src/psm/stand/bootblks/ufs/i386/installboot.sh b/usr/src/psm/stand/bootblks/ufs/i386/installboot.sh new file mode 100644 index 0000000000..6a3c365a12 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/i386/installboot.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +away() { + echo $2 1>&2 + exit $1 +} + +Error="Error: `basename $0` is obsolete. Use installgrub(1M)" +Usage="Usage: `basename $0` --force_realmode pboot bootblk raw-device" + +test $# -ne 4 && away 1 "$Error" +test $1 != "--force_realmode" && away 1 "$Error" +shift 1 + +PBOOT=$1 +BOOTBLK=$2 +DEVICE=$3 +test ! -f $PBOOT && away 1 "$PBOOT: File not found" +test ! -f $BOOTBLK && away 1 "$BOOTBLK: File not found" +test ! -c $DEVICE && away 1 "$DEVICE: Not a character device" +test ! -w $DEVICE && away 1 "$DEVICE: Not writeable" + +# pboot at block 0, label at blocks 1 and 2, bootblk from block 3 on +stderr=`dd if=$PBOOT of=$DEVICE bs=1b count=1 conv=sync 2>&1` +err=$? ; test $err -ne 0 && away $err "$stderr" +stderr=`dd if=$BOOTBLK of=$DEVICE bs=1b oseek=3 conv=sync 2>&1` +err=$? ; test $err -ne 0 && away $err "$stderr" +exit 0 diff --git a/usr/src/psm/stand/bootblks/ufs/i386/mboot.S b/usr/src/psm/stand/bootblks/ufs/i386/mboot.S new file mode 100644 index 0000000000..646f1ef554 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/i386/mboot.S @@ -0,0 +1,394 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * ident "%Z%%M% %I% %E% SMI" + */ + +/* + * SOLARIS MASTER BOOT: + * + * PURPOSE: loads the primary boot from the active fdisk partition. + * in effect, this routine mimics the functionality of INT 0x19. + * + * resides on the first physical sector of the hard drive media. + * loaded by INT 0x19 (ROM bootstrap loader) at address 0x7C00 + * limited to 512 bytes total, including embedded fdisk table. + * + * for compatibility with the ROM BIOS, we contain standard DOS structures: + * + * the fdisk partition table (at offset 0x1BE-0x1FE) + * boot signature bytes (0x55, 0xAA at 0x1FE, 0x1FF) + * + * the above two entities are required in order to be compatible with + * the manner in which the DOS BIOS has always performed its boot operation. + * In the event that our master boot record is inadvertently replaced by + * a standard DOS boot sector, the booting operation will still succeed! + * + * This master boot record uses the relsect/numsect fields of the partition + * table entry, to compute the start of the active partition; therefore, + * it is geometry independent. This means that the drive could be "built" + * on a system with a disk controller that uses a given disk geometry, but + * would run on any other controller. + * + * SYNOPSIS: + * begins execution at 0:0x7C00 + * relocates to 0:0x600 (to get out of the way!) + * reads fdisk table to locate bootable partition + * load boot record from the active fdisk partition at 0x7C00 + * verify boot record signature bytes + * jump to/execute the SOLARIS PARTITION PRIMARY BOOT + * error handler - can either reboot, or invoke INT 0x18. + * + * interface from DOS INT 0x19: BootDev in DL + * (this fails sometimes, so we look for a signature to determine whether + * to rely on DL from the floppy boot, or if we should assume 0x80 from + * the BIOS) + * + * interface to partition boot: BootDev in DL + * + *============================================================================= + * Master boot record: resides on first physical sector of device + */ + +/* + * This file is written in GNU as syntax using Intel assembler syntax. The + * startup label _start will be executed at address PBOOT_ADDR (0x7C00), but + * the text section must be set at address RELOC_ADDR (0x600). With GNU ld + * this can be done using the "-Ttext 600" option. + */ + + +#define PBOOT_ADDR 0x7C00 +#define RELOC_ADDR 0x600 + +#define FDISK_START 0x1BE +#define BOOT_SIG 0xAA55 +#define N_RETRIES 5 + +#define FD_NUMPART 4 +#define FD_PTESIZE 0x10 +#define ACTIVE 0x80 + +/* + * A convenience macro for declaring a message string (using .ascii directive-- + * NOT nul-terminated) surrounded by two labels, which can then be used with + * the SIZEOF() macro to get its length. + */ +#define MSG(label, string) label: .ascii string; label##_end: + +/* + * Returns the length of some consecutive bytes. These bytes must be placed + * between two labels. The ending label must be the same as the starting label + * but with a suffix "_end". + */ +#define SIZEOF(label) (offset label##_end - offset label) + + + .title "Solaris_Master_Boot" + + .intel_syntax noprefix /* use Intel syntax */ + .code16 /* 16-bit mode (real mode) */ + + .text /* code segment begins here */ + + .global BootDev + .global _start + +_start: /* _start is loaded at PBOOT_ADDR */ + jmp bootrun + +Version: + .ascii "M3.0" /* ident string */ + +bootrun: + cli /* don't bother me now! */ + + /* prepare to relocate ourselves */ + cld /* prepare for relocation */ + mov si, PBOOT_ADDR + mov di, RELOC_ADDR + + /* set up segment registers */ + mov ax, cs /* initialize segment registers */ + mov ss, ax + mov sp, si /* stack starts down from 7C00 */ + mov es, ax + mov ds, ax + + push cx /* save possible signature on stack */ + mov cx, 0x100 + rep movsw + pop cx /* restore saved cx */ + + /* running at PBOOT_ADDR, jump to RELOC_ADDR-rel addr */ + jmp (new_home - PBOOT_ADDR + RELOC_ADDR) + +new_home: + sti /* re-enable interrupts */ + + /* + * assuming boot device number is in dl has caused problems in the past + * since we still don't absolutely have to rely on it, I've just + * removed the now-pointless code to check for the FACE-CAFE signature + * from mdexec, which doesn't do anything anymore, but left the + * assumption that BootDev is 0x80 and nothing but. If we ever need to + * have BIOS load us from a drive not numbered 0x80, we'll need to + * uncomment the following line; otherwise, the initialized value of + * BootDev, namely 0x80, will be used for disk accesses. + */ + /* mov BootDev, dl */ + + /* set debug flag based on seeing "both shift down" */ + mov ah, 2 /* get shift state */ + int 0x16 + and al, 3 /* isolate shift-key bits */ + cmp al, 3 + jne nodbg + mov byte ptr [debugmode], 1 /* set to 1 */ + +nodbg: + /* + * Search the fdisk table sequentially to find a physical partition + * that is marked as "active" (bootable). + */ + mov bx, RELOC_ADDR + FDISK_START + mov cx, FD_NUMPART + +nxtpart: + cmp byte ptr [bx], ACTIVE + je got_active_part + add bx, FD_PTESIZE + loop nxtpart + +noparts: + mov bp, offset NoActiveErrMsg + mov cx, SIZEOF(NoActiveErrMsg) + jmp fatal_err + +got_active_part: + mov ah, 0 /* reset disk */ + int 0x13 + + push bx /* save partition pointer */ + + /* Check for LBA BIOS */ + mov ah, 0x41 /* chkext function */ + mov bx, 0x55AA /* signature to change */ + mov cx, 0 + int 0x13 + jc noLBA /* carry == failure */ + cmp bx, 0xAA55 + jne noLBA /* bad signature in BX == failure */ + test cx, 1 /* cx & 1 must be true, or... */ + jz noLBA /* ...no LBA */ + + mov bp, offset lbastring + mov cx, SIZEOF(lbastring) + call debugout + + /* + * LBA case: form a packet on the stack and call fn 0x42 to read + * packet, backwards (from hi to lo addresses): + * 8-byte LBA + * seg:ofs buffer address + * byte reserved + * byte nblocks + * byte reserved + * packet size in bytes (>= 0x10) + */ + + pop bx /* restore partition pointer */ + push bx /* and save again */ + mov cx, N_RETRIES /* retry count */ +retryLBA: + pushd 0 /* hi 32 bits of 64-bit sector number */ + push dword ptr [bx+8] /* relsect (lo 32 of 64-bit number) */ + push dword ptr [solaris_priboot] /* seg:ofs of buffer */ + push 1 /* reserved, one block */ + push 0x10 /* reserved, size (0x10) */ + mov ah, 0x42 /* "read LBA" */ + mov si, sp /* (ds already == ss) */ + int 0x13 + lahf /* save flags */ + add sp, 16 /* restore stack */ + sahf /* restore flags */ + jnc readok /* got it */ + mov ah, 0 /* reset disk */ + int 0x13 + loop retryLBA /* try again */ + jmp readerr /* exhausted retries; give up */ + +noLBA: + mov bp, offset chsstring + mov cx, SIZEOF(chsstring) + call debugout + + pop bx /* restore partition pointer */ + push bx /* and save again */ + + /* get BIOS disk parameters */ + mov dl, byte ptr [BootDev] + mov ah, 0x8 + int 0x13 + + jnc geomok + + /* error reading geom; die */ + mov bp, offset GeomErrMsg + mov cx, SIZEOF(GeomErrMsg) + jmp fatal_err + +geomok: + /* calculate sectors per track */ + mov al, cl /* ah doesn't matter; mul dh will set it */ + and al, 0x3F + mov byte ptr [secPerTrk], al + + /* calculate sectors per cylinder */ + inc dh + mul dh + mov word ptr [secPerCyl], ax + + /* calculate cylinder # */ + mov ax, [bx+8] /* ax = loword(relsect) */ + mov dx, [bx+10] /* dx:ax = relsect */ + div word ptr [secPerCyl] /* ax = cyl, */ + /* dx = sect in cyl (0 - cylsize-1) */ + mov bx, ax /* bx = cyl */ + + /* calculate head/sector # */ + mov ax, dx /* ax = sect in cyl (0 - cylsize-1) */ + div byte ptr [secPerTrk] /* al = head, */ + /* ah = 0-rel sect in track */ + inc ah /* ah = 1-rel sector */ + + xor cl,cl /* cl = 0 */ + mov ch, bh /* ch = hi bits of cyl (if any) */ + shr cx, 2 /* cl{7:6} = cyl{9:8} (if any) */ + and cl, 0xC0 /* cl = cyl{9:8} to merge with sect (if any) */ + + or cl, ah /* cl{7:6} = cyl bits, cl{5:0} = sect */ + mov ch, bl /* ch = lo cyl bits */ + mov dh, al /* dh = head */ + mov dl, byte ptr [BootDev] /* dl = drivenum */ + les bx, solaris_priboot /* es:bx points to buffer */ + + mov si, N_RETRIES +retry_noLBA: + mov ax, 0x201 /* 02=read, sector count = 1 */ + + int 0x13 + jnc readok + mov ah, 0 /* reset disk */ + int 0x13 + dec si + cmp si, 0 + jne retry_noLBA /* retry, or fall through to read error */ + +readerr: + mov bp, offset ReadErrMsg + mov cx, SIZEOF(ReadErrMsg) + jmp fatal_err + +readok: + /* verify boot record signature */ + mov bx, PBOOT_ADDR + cmp word ptr [bx+0x1FE], BOOT_SIG + je sigok + + mov bp, offset SigErrMsg + mov cx, SIZEOF(SigErrMsg) + jmp fatal_err + +sigok: + mov dl, byte ptr [BootDev] /* pass BootDev to next boot phase */ + pop si /* and pass partition pointer ds:si */ + call dword ptr [solaris_priboot] /* call doesn't return! */ + + mov bp, offset ReturnErrMsg + mov cx, SIZEOF(ReturnErrMsg) + +fatal_err: /* land of no return....... */ + /* + * bp contains pointer to error message string, + * cx contains string length + */ + mov bx, 0x4F /* video page, attribute */ + call msgout + int 0x18 + +debugout: + /* call with string pointer in es:bp, len in cx */ + cmp byte ptr [debugmode], 0 + je debugout_ret /* skip if not in debug mode */ + + mov bx, 0x1F /* page, attr (white on blue) */ + + /* alternate entry for fatal_err */ +msgout: + pusha + mov ax, 0x1301 + mov dx, 0x1700 /* row, col */ + int 0x10 + + mov al, 7 /* BEL */ + mov cx, 1 + int 0x10 + + mov ah, 0 /* get key */ + int 0x16 + popa + +debugout_ret: + ret + +secPerTrk: + .byte 0 +secPerCyl: + .word 0 +solaris_priboot: + .long PBOOT_ADDR +BootDev: + .byte 0x80 /* assumes drive 80 (see comment above) */ +debugmode: + .byte 0 + +MSG(GeomErrMsg, "Can't read geometry") +MSG(NoActiveErrMsg, "No active partition") +MSG(ReadErrMsg, "Can't read PBR") +MSG(SigErrMsg, "Bad PBR sig") +MSG(ReturnErrMsg, "!!!") +MSG(lbastring, "LBA") +MSG(chsstring, "CHS") + +/* + * For debugging: Here's a representative FDISK table entry + * + * .org 0x1BE + * .byte 0x80,1,1,0,0x82,0xfe,0x7f,4,0x3f,0,0,0,0x86,0xfa,0x3f,0 + */ + .org 0x1FE + + .word BOOT_SIG diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/Makefile new file mode 100644 index 0000000000..69ec178a4e --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/Makefile @@ -0,0 +1,65 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/ufs/sparc/Makefile +# + +BASEDIR = ../.. + +include $(BASEDIR)/ufs/Makefile.ufs + +SUBDIRS = unix sun4c sun4m sun4d sun4u sun4v + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all: $(INSTALLBOOT) $(SUBDIRS) + +install: $(USR_SBIN_INSTALLBOOT) $(SUBDIRS) + +lint clean: $(SUBDIRS) + +clobber: $(SUBDIRS) + -$(RM) $(INSTALLBOOT) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +# +# Pattern matching rules for source in this directory +# +%: %.sh + $(RM) $@ + cat $< > $@ + chmod +x $@ diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/installboot.sh b/usr/src/psm/stand/bootblks/ufs/sparc/installboot.sh new file mode 100644 index 0000000000..cd463bef71 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/installboot.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1994-1997, by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" +# + +away() { + echo $2 1>&2 + exit $1 +} + +Usage="Usage: `basename $0` bootblk raw-device" + +test $# -ne 2 && away 1 "$Usage" + +BOOTBLK=$1 +DEVICE=$2 +test ! -f $BOOTBLK && away 1 "$BOOTBLK: File not found" +test ! -c $DEVICE && away 1 "$DEVICE: Not a character device" +test ! -w $DEVICE && away 1 "$DEVICE: Not writeable" + +# label at block 0, bootblk from block 1 through 15 +stderr=`dd if=$BOOTBLK of=$DEVICE bs=1b oseek=1 count=15 conv=sync 2>&1` +err=$? ; test $err -ne 0 && away $err "$stderr" +exit 0 diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/sun4c/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/sun4c/Makefile new file mode 100644 index 0000000000..e177bae10b --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/sun4c/Makefile @@ -0,0 +1,59 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, 1999, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/ufs/sparc/sun4c/Makefile +# + +# +# Platform specific Makefile for the boot block. +# +# PLATFORM is the target for the binary installation. +# +# PLATLINKS is a list of platforms which are to be linked to this binary +# at the file level. +# +# PROM_TYPE is the type of prom OBP, IEEE1275, etc... +# +BASEDIR = ../../.. +PLATFORM = sun4c +PLATLINKS = +PROM_TYPE = OBPDEP + +include $(BASEDIR)/ufs/Makefile.ufs +include $(BASEDIR)/obp-c/Makefile.rules + +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc + +.KEEP_STATE: + +all: $(MKBOOT) $(PROG).elf + ./$(MKBOOT) $(PROG).elf $(PROG); chmod -x $(PROG) + +include $(BASEDIR)/obp-c/Makefile.targ +include $(BASEDIR)/Makefile.targ diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/sun4d/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/sun4d/Makefile new file mode 100644 index 0000000000..abb8f28aec --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/sun4d/Makefile @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, 2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/ufs/sparc/sun4d/Makefile +# + +# +# Platform specific Makefile for the boot block. +# +# PLATFORM is the target for the binary installation. +# +# PLATFORM_INCS is a list of directories to look in for platform specific +# header files to include +# +# PLATLINKS is a list of platforms which are to be linked to this binary +# at the file level. +# +# PROM_TYPE is the type of prom OBP, IEEE1275, etc... +# +BASEDIR = ../../.. +PLATFORM = sun4d +PLATLINKS = +PROM_TYPE = OBPDEP + +include $(BASEDIR)/ufs/Makefile.ufs +include $(BASEDIR)/obp-c/Makefile.rules + +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc + +.KEEP_STATE: + +all: $(MKBOOT) $(PROG).elf + ./$(MKBOOT) $(PROG).elf $(PROG); chmod -x $(PROG) + +include $(BASEDIR)/obp-c/Makefile.targ +include $(BASEDIR)/Makefile.targ diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/sun4m/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/sun4m/Makefile new file mode 100644 index 0000000000..5177d46a29 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/sun4m/Makefile @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1994, 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/ufs/sparc/sun4m/Makefile +# + +# +# Platform specific Makefile for the boot block. +# +# PLATFORM is the target for the binary installation. +# +# PROM_TYPE is the type of prom OBP, IEEE1275, etc... +# +BASEDIR = ../../.. +PLATFORM = sun4m +PROM_TYPE = OBPDEP + +include $(BASEDIR)/ufs/Makefile.ufs +include $(BASEDIR)/obp-c/Makefile.rules + +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc + +.KEEP_STATE: + +all: $(MKBOOT) $(PROG).elf + ./$(MKBOOT) $(PROG).elf $(PROG); chmod -x $(PROG) + +include $(BASEDIR)/obp-c/Makefile.targ +include $(BASEDIR)/Makefile.targ diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/sun4u/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/sun4u/Makefile new file mode 100644 index 0000000000..47061d5bba --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/sun4u/Makefile @@ -0,0 +1,76 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1994,2000-2003 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/ufs/sparc/sun4u/Makefile +# + +# +# Platform specific Makefile for the boot block. +# +# PLATFORM is the target for the binary installation. +# +# PLATLINKS is a list of platforms which are to be linked to the ../fs +# directory. +# +BASEDIR = ../../.. +PLATFORM = sun4u + +PLATLINKS = SUNW,Ultra-2 +PLATLINKS += SUNW,Ultra-250 +PLATLINKS += SUNW,Ultra-4 +PLATLINKS += SUNW,Ultra-Enterprise +PLATLINKS += SUNW,Ultra-Enterprise-10000 +PLATLINKS += SUNW,Sun-Blade-100 +PLATLINKS += SUNW,Sun-Blade-1000 +PLATLINKS += SUNW,Sun-Blade-1500 +PLATLINKS += SUNW,Sun-Blade-2500 +PLATLINKS += SUNW,Sun-Fire +PLATLINKS += SUNW,Sun-Fire-V240 +PLATLINKS += SUNW,Sun-Fire-V250 +PLATLINKS += SUNW,Sun-Fire-V440 +PLATLINKS += SUNW,Sun-Fire-280R +PLATLINKS += SUNW,Sun-Fire-15000 +PLATLINKS += SUNW,Sun-Fire-880 +PLATLINKS += SUNW,Sun-Fire-480R +PLATLINKS += SUNW,Sun-Fire-V890 +PLATLINKS += SUNW,Sun-Fire-V490 +PLATLINKS += SUNW,Serverblade1 +PLATLINKS += SUNW,Netra-T12 +PLATLINKS += SUNW,Netra-T4 + +LINKED_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%) +LINKED_LIB_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib) +LINKED_LIB_FS_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib/fs) + +include $(BASEDIR)/ufs/Makefile.ufs +include $(BASEDIR)/Makefile.1275 + +.KEEP_STATE: + +all: $(PROG) + +include $(BASEDIR)/Makefile.targ diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/sun4v/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/sun4v/Makefile new file mode 100644 index 0000000000..62a45edd98 --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/sun4v/Makefile @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/bootblks/ufs/sparc/sun4v/Makefile +# + +# +# Platform specific Makefile for the boot block. +# +# PLATFORM is the target for the binary installation. +# +# PLATLINKS is a list of platforms which are to be linked to the ../fs +# directory. +# +BASEDIR = ../../.. +PLATFORM = sun4v + +#PLATLINKS = SUNW,... + +#LINKED_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%) +#LINKED_LIB_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib) +#LINKED_LIB_FS_DIRS = $(PLATLINKS:%=$(USR_PLAT_DIR)/%/lib/fs) + +include $(BASEDIR)/ufs/Makefile.ufs +include $(BASEDIR)/Makefile.1275 + +.KEEP_STATE: + +all: $(PROG) + +include $(BASEDIR)/Makefile.targ diff --git a/usr/src/psm/stand/bootblks/ufs/sparc/unix/Makefile b/usr/src/psm/stand/bootblks/ufs/sparc/unix/Makefile new file mode 100644 index 0000000000..ae83da4aea --- /dev/null +++ b/usr/src/psm/stand/bootblks/ufs/sparc/unix/Makefile @@ -0,0 +1,72 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/bootblks/ufs/sparc/unix/Makefile +# + +# +# Build the "Unix" version of the boot block. +# Useful solely for testing. DO NOT INSTALL IT! +# + +BASEDIR = ../../.. +PLATFORM = unix +PLATFORM_INCS = ./ +PLATLINKS = + +include $(BASEDIR)/ufs/Makefile.ufs +include $(BASEDIR)/obp-c/Makefile.rules + +CPPINCS += -I$(SRC)/head +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc +CPPINCS += -I$(PLATFORM_INCS) + +UNIX_OBJS = ufs.o unix_devio.o + +$(UNIX_OBJS) := CFLAGS += -g + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(UNIX_OBJS) + $(CC) $(CFLAGS) $(CPPFLAGS) -g -o $@ $(UNIX_OBJS) + +lint: FRC + +clean: + $(RM) $(UNIX_OBJS) + +clobber: clean + $(RM) $(PROG) + +install: FRC + +FRC: + diff --git a/usr/src/psm/stand/cpr/Makefile b/usr/src/psm/stand/cpr/Makefile new file mode 100644 index 0000000000..1c7ecca4ab --- /dev/null +++ b/usr/src/psm/stand/cpr/Makefile @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 1994, 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/Makefile.master + +# All the real work gets done in kernel-architecture directories, +# and that's where the targets wind up. This makefile just gets us there. + +sparcv9_ARCHITECTURES = sparcv9 +sparc_ARCHITECTURES = $(sparcv9_ARCHITECTURES) +SUBDIRS = $($(MACH)_ARCHITECTURES) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +clean.lint := TARGET= clean.lint + +.KEEP_STATE: + +all install clean clobber lint clean.lint: $(SUBDIRS) + +TOPDIR= ../../.. + +# +# Cross-reference customization: include other relevant CPR-related code +# in the cross-reference. +# +STANDDIR = $(TOPDIR)/stand +XRDIRS += $(STANDDIR)/lib $(STANDDIR)/sys ../../promif \ + $(TOPDIR)/uts/*/cpr $(TOPDIR)/uts/*/sys/cpr_* + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/cpr/common/Makefile.com b/usr/src/psm/stand/cpr/common/Makefile.com new file mode 100644 index 0000000000..aeeefbd7c0 --- /dev/null +++ b/usr/src/psm/stand/cpr/common/Makefile.com @@ -0,0 +1,147 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/cpr/common/Makefile.com +# +GREP = egrep +WC = wc +TOPDIR = ../../../../.. + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/Makefile.psm +include $(TOPDIR)/psm/stand/lib/Makefile.lib + +SYSDIR = $(TOPDIR)/uts +COMDIR = ../../common +OSDIR = $(SYSDIR)/common/os +ARCHDIR = $(SYSDIR)/$(ARCH) +MACHDIR = $(SYSDIR)/$(MACH) +MMUDIR = $(SYSDIR)/$(MMU) +PROMLIBDIR= $(TOPDIR)/psm/stand/lib/promif/$(ARCH_PROMDIR) +PROMLIB = $(PROMLIBDIR)/libprom.a + +SALIBS += $(PROMLIB) +LDLIBS += -L$(PROMLIBDIR) -lprom +LDFLAGS = -dn -M mapfile $(MAP_FLAG) + +LINTLIBS += $(PROMLIBDIR)/llib-lprom.ln +LINTFLAGS.lib = -ysxmun + +CPRBOOTOBJ += support.o compress.o + +L_SRCS = $(COMDIR)/support.c $(OSDIR)/compress.c +L_COBJ = $(CPRBOOTOBJ:%.o=%.ln) + +CPPDEFS = $(ARCHOPTS) -D$(ARCH) -D__$(ARCH) -D$(MACH) -D__$(MACH) +CPPDEFS += -D_KERNEL -D_MACHDEP -D__ELF + +CPPINCS = -I. -I$(ARCHDIR) -I$(MMUDIR) -I$(MACHDIR) +CPPINCS += -I$(MACHDIR)/$(ARCHVER) -I$(SYSDIR)/sun +CPPINCS += -I$(SYSDIR)/sun4 -I$(SYSDIR)/common -I$(TOPDIR)/head + +CPPFLAGS = $(CPPDEFS) $(CPPINCS) $(CPPFLAGS.master) +CPPFLAGS += $(CCYFLAG)$(SYSDIR)/common + +CFLAGS = $(CCVERBOSE) -O + +ASFLAGS = -P -D_ASM $(CPPDEFS) -DLOCORE -D_LOCORE -D__STDC__ +AS_CPPFLAGS = $(CPPINCS) $(CPPFLAGS.master) + +# install values +CPRFILES= $(ALL:%=$(ROOT_PSM_DIR)/$(ARCH)/%) +FILEMODE= 644 +OWNER= root +GROUP= sys + +# lint stuff +LINTFLAGS += -Dlint +LOPTS = -hbxn + +# install rule +$(ROOT_PSM_DIR)/$(ARCH)/%: % + $(INS.file) + + +all: $(ALL) + +install: all $(CPRFILES) + + +LINT.c= $(LINT) $(LINTFLAGS.c) $(LINT_DEFS) $(CPPFLAGS) -c +LINT.s= $(LINT) $(LINTFLAGS.s) $(LINT_DEFS) $(CPPFLAGS) -c + +# build rule + +compress.o: $(OSDIR)/compress.c + $(COMPILE.c) $(OSDIR)/compress.c + +support.o: $(COMDIR)/support.c + $(COMPILE.c) $(COMDIR)/support.c + +compress.ln: $(OSDIR)/compress.c + @$(LHEAD) $(LINT.c) $(OSDIR)/compress.c $(LTAIL) + +support.ln: $(COMDIR)/support.c + @$(LHEAD) $(LINT.c) $(COMDIR)/support.c $(LTAIL) + +%.ln: %.c + @$(LHEAD) $(LINT.c) $< $(LTAIL) + +%.ln: %.s + @$(LHEAD) $(LINT.s) $< $(LTAIL) + +.KEEP_STATE: + +.PARALLEL: $(CPRBOOTOBJ) $(L_COBJ) + +cprboot: $(CPRBOOT_MAPFILE) $(CPRBOOTOBJ) $(SALIBS) + $(LD) $(LDFLAGS) -o $@ $(CPRBOOTOBJ) $(LDLIBS) + $(POST_PROCESS) + +$(SALIBS): FRC + @cd $(@D); $(MAKE) $(MFLAGS) + +$(LINTLIBS): FRC + @cd $(@D); $(MAKE) $(MFLAGS) $(@F) + +$(ROOTDIR): + $(INS.dir) + +lint: $(L_COBJ) $(LINTLIBS) + @$(ECHO) "\nperforming global crosschecks: $@" + @$(LINT.2) $(L_COBJ) $(LDLIBS) + +clean.lint: + $(RM) *.ln + +clean: + $(RM) *.o *.ln + +clobber: + $(RM) *.o *.ln $(ALL) + +FRC: diff --git a/usr/src/psm/stand/cpr/common/support.c b/usr/src/psm/stand/cpr/common/support.c new file mode 100644 index 0000000000..c0082cb770 --- /dev/null +++ b/usr/src/psm/stand/cpr/common/support.c @@ -0,0 +1,243 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1987-2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpr.h> +#include <sys/pte.h> +#include <sys/promimpl.h> +#include <sys/prom_plat.h> + +extern int cpr_ufs_close(int); +extern int cpr_ufs_open(char *, char *); +extern int cpr_ufs_read(int, char *, int); +extern int cpr_read(int, char *, size_t); +extern void prom_unmap(caddr_t, uint_t); + +extern int cpr_debug; +static int cpr_show_props = 0; + + +/* + * Read the config file and pass back the file path, filesystem + * device path. + */ +int +cpr_read_cprinfo(int fd, char *file_path, char *fs_path) +{ + struct cprconfig cf; + + if (cpr_ufs_read(fd, (char *)&cf, sizeof (cf)) != sizeof (cf) || + cf.cf_magic != CPR_CONFIG_MAGIC) + return (-1); + + (void) prom_strcpy(file_path, cf.cf_path); + (void) prom_strcpy(fs_path, cf.cf_dev_prom); + + return (0); +} + + +/* + * Read the location of the state file from the root filesystem. + * Pass back to the caller the full device path of the filesystem + * and the filename relative to that fs. + */ +int +cpr_locate_statefile(char *file_path, char *fs_path) +{ + int fd; + char *boot_path = prom_bootpath(); + int rc; + + if ((fd = cpr_ufs_open(CPR_CONFIG, boot_path)) != -1) { + rc = cpr_read_cprinfo(fd, file_path, fs_path); + (void) cpr_ufs_close(fd); + } else + rc = -1; + + return (rc); +} + + +/* + * Open the "defaults" file in the root fs and read the values of the + * properties saved during the checkpoint. Restore the values to nvram. + * + * Note: an invalid magic number in the "defaults" file means that the + * state file is bad or obsolete so our caller should not proceed with + * the resume. + */ +int +cpr_reset_properties(void) +{ + char *str, *boot_path, *default_path; + int fd, len, rc, prop_errors; + cprop_t *prop, *tail; + cdef_t cdef; + dnode_t node; + + str = "cpr_reset_properties"; + default_path = CPR_DEFAULT; + boot_path = prom_bootpath(); + + if ((fd = cpr_ufs_open(default_path, boot_path)) == -1) { + prom_printf("%s: unable to open %s on %s\n", + str, default_path, boot_path); + return (-1); + } + + rc = 0; + len = cpr_ufs_read(fd, (char *)&cdef, sizeof (cdef)); + if (len != sizeof (cdef)) { + prom_printf("%s: error reading %s\n", str, default_path); + rc = -1; + } else if (cdef.mini.magic != CPR_DEFAULT_MAGIC) { + prom_printf("%s: bad magic number in %s\n", str, default_path); + rc = -1; + } + + (void) cpr_ufs_close(fd); + if (rc) + return (rc); + + node = prom_optionsnode(); + if (node == OBP_NONODE || node == OBP_BADNODE) { + prom_printf("%s: cannot find \"options\" node\n"); + return (-1); + } + + /* + * reset nvram to the original property values + */ + if (cpr_show_props) + prom_printf("\n\ncpr_show_props:\n"); + for (prop_errors = 0, prop = cdef.props, tail = prop + CPR_MAXPROP; + prop < tail; prop++) { + if (cpr_show_props) { + prom_printf("mod=%c, name=\"%s\",\tvalue=\"%s\"\n", + prop->mod, prop->name, prop->value); + } + if (prop->mod != PROP_MOD) + continue; + + len = prom_strlen(prop->value); + if (prom_setprop(node, prop->name, prop->value, len + 1) < 0 || + prom_getproplen(node, prop->name) != len) { + prom_printf("%s: error setting \"%s\" to \"%s\"\n", + str, prop->name, prop->value); + prop_errors++; + } + } + + return (prop_errors ? -1 : 0); +} + + +/* + * Read and verify cpr dump descriptor + */ +int +cpr_read_cdump(int fd, cdd_t *cdp, ushort_t mach_type) +{ + char *str; + int nread; + + str = "\ncpr_read_cdump:"; + nread = cpr_read(fd, (caddr_t)cdp, sizeof (*cdp)); + if (nread != sizeof (*cdp)) { + prom_printf("%s Error reading cpr dump descriptor\n", str); + return (-1); + } + + if (cdp->cdd_magic != CPR_DUMP_MAGIC) { + prom_printf("%s bad dump magic 0x%x, expected 0x%x\n", + str, cdp->cdd_magic, CPR_DUMP_MAGIC); + return (-1); + } + + if (cdp->cdd_version != CPR_VERSION) { + prom_printf("%s bad cpr version %d, expected %d\n", + str, cdp->cdd_version, CPR_VERSION); + return (-1); + } + + if (cdp->cdd_machine != mach_type) { + prom_printf("%s bad machine type 0x%x, expected 0x%x\n", + str, cdp->cdd_machine, mach_type); + return (-1); + } + + if (cdp->cdd_bitmaprec <= 0) { + prom_printf("%s bad bitmap %d\n", str, cdp->cdd_bitmaprec); + return (-1); + } + + if (cdp->cdd_dumppgsize <= 0) { + prom_printf("%s Bad pg tot %d\n", str, cdp->cdd_dumppgsize); + return (-1); + } + + cpr_debug = cdp->cdd_debug; + + return (0); +} + + +/* + * update cpr dump terminator + */ +void +cpr_update_terminator(ctrm_t *file_term, caddr_t mapva) +{ + ctrm_t *mem_term; + + /* + * Add the offset to reach the terminator in the kernel so that we + * can directly change the restored kernel image. + */ + mem_term = (ctrm_t *)(mapva + (file_term->va & MMU_PAGEOFFSET)); + + mem_term->real_statef_size = file_term->real_statef_size; + mem_term->tm_shutdown = file_term->tm_shutdown; + mem_term->tm_cprboot_start.tv_sec = file_term->tm_cprboot_start.tv_sec; + mem_term->tm_cprboot_end.tv_sec = prom_gettime() / 1000; +} + + +/* + * simple bcopy for cprboot + */ +void +bcopy(const void *s, void *d, size_t count) +{ + const char *src = s; + char *dst = d; + + while (count--) + *dst++ = *src++; +} diff --git a/usr/src/psm/stand/cpr/sparcv9/Makefile b/usr/src/psm/stand/cpr/sparcv9/Makefile new file mode 100644 index 0000000000..b5030d3f65 --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/Makefile @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994-1997, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/cpr/sparcv9/Makefile +# + +SUBDIRS = sun4u + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +clean.lint := TARGET= clean.lint + +.KEEP_STATE: + +all install clean clobber lint clean.lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/Makefile b/usr/src/psm/stand/cpr/sparcv9/sun4u/Makefile new file mode 100644 index 0000000000..b687625d6d --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/Makefile @@ -0,0 +1,69 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 1995-1999,2002-2003 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +TOPDIR = ../../../../.. + +# override global macros as necessary +TARGET_ARCH = sun4u +TARG_MACH = sparcv9 +ARCH = sun4u +MACH = sparc +MMU = sfmmu +ARCHVER = v9 +PROMTYPE = ieee1275 +ARCH_PROMDIR = $(TARG_MACH)/$(PROMTYPE)/common +PROMIFDIR = $(TOPDIR)/psm/stand/lib/promif +PLATLIBDIR = $(PROMIFDIR)/$(TARG_MACH)/$(PROMTYPE)/$(TARGET_ARCH) +PLATLIB = $(PLATLIBDIR)/libplat.a +LDLIBS = -L$(PLATLIBDIR) -lplat +SALIBS = $(PLATLIB) +LINTLIBS = $(PLATLIBDIR)/llib-lplat.ln + +CPRBOOTOBJ = cb_srt0.o cprboot.o machdep.o pages.o bitmap.o util.o + +ALL = cprboot + +include ../../common/Makefile.com +include $(TOPDIR)/psm/Makefile.psm.64 +CFLAGS64 += -xchip=ultra $(CCABS32) + +.KEEP_STATE: + +STANDDIR = $(TOPDIR)/stand +CPPINCS += -I$(STANDDIR) + +# +# Cross-reference customization: build a cross-reference over all of +# the sun4u-related CPR source files. +# +XRDIRS += ../../common \ + $(STANDDIR)/lib $(STANDDIR)/sys \ + ../../../../promif/ieee1275 \ + $(TOPDIR)/uts/common/os/compress.c \ + $(TOPDIR)/uts/common/sys/cpr.h \ + $(TOPDIR)/uts/sun4u/sys/cpr_impl.h diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/bitmap.c b/usr/src/psm/stand/cpr/sparcv9/sun4u/bitmap.c new file mode 100644 index 0000000000..fd265db6d5 --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/bitmap.c @@ -0,0 +1,599 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpr.h> +#include <sys/fs/ufs_fs.h> +#include <sys/prom_plat.h> +#include "cprboot.h" + + +/* + * max space for a copy of physavail data + * prop size is usually 80 to 128 bytes + */ +#define PA_BUFSIZE 1024 + +#define CB_SETBIT 1 +#define CB_ISSET 2 +#define CB_ISCLR 3 + +/* + * globals + */ +int cb_nbitmaps; + +/* + * file scope + */ +static arange_t *cb_physavail; +static char pabuf[PA_BUFSIZE]; +static caddr_t high_virt; + +static cbd_t cb_bmda[CPR_MAX_BMDESC]; +static int tracking_init; + + +static int +cb_bitop(pfn_t ppn, int op) +{ + int rel, rval = 0; + char *bitmap; + cbd_t *dp; + + for (dp = cb_bmda; dp->cbd_size; dp++) { + if (PPN_IN_RANGE(ppn, dp)) { + bitmap = (char *)dp->cbd_reg_bitmap; + rel = ppn - dp->cbd_spfn; + if (op == CB_SETBIT) + setbit(bitmap, rel); + else if (op == CB_ISSET) + rval = isset(bitmap, rel); + else if (op == CB_ISCLR) + rval = isclr(bitmap, rel); + break; + } + } + + return (rval); +} + + +/* + * count pages that are isolated from the kernel + * within each available range + */ +static void +count_free_pages(void) +{ + arange_t *arp; + pfn_t bitno; + int cnt; + + for (arp = cb_physavail; arp->high; arp++) { + cnt = 0; + for (bitno = arp->low; bitno <= arp->high; bitno++) { + if (cb_bitop(bitno, CB_ISCLR)) + cnt++; + } + arp->nfree = cnt; + } +} + + +/* + * scan the physavail list for a page + * that doesn't clash with the kernel + */ +static pfn_t +search_phav_pages(void) +{ + static arange_t *arp; + static pfn_t bitno; + int rescan; + + if (arp == NULL) { + count_free_pages(); + arp = cb_physavail; + bitno = arp->low; + } + + /* + * begin scanning from the previous position and if the scan + * reaches the end of the list, scan a second time from the top; + * nfree is checked to eliminate scanning overhead when most + * of the available space gets used up. when a page is found, + * set a bit so the page wont be found by another scan. + */ + for (rescan = 0; rescan < 2; rescan++) { + for (; arp->high; bitno = (++arp)->low) { + if (arp->nfree == 0) + continue; + for (; bitno <= arp->high; bitno++) { + if (cb_bitop(bitno, CB_ISCLR)) { + (void) cb_bitop(bitno, CB_SETBIT); + arp->nfree--; + return (bitno++); + } + } + } + arp = cb_physavail; + bitno = arp->low; + } + + return (PFN_INVALID); +} + + +/* + * scan statefile buffer pages for reusable tmp space + */ +static pfn_t +search_buf_pages(void) +{ + size_t coff, src_base; + static size_t lboff; + pfn_t ppn; + + if (tracking_init == 0) + return (PFN_INVALID); + + /* + * when scanning the list of statefile buffer ppns, we know that + * all pages from lboff to the page boundary of buf_offset have + * already been restored; when the associated page bit is clear, + * that page is isolated from the kernel and we can reuse it for + * tmp space; otherwise, when SF_DIFF_PPN indicates a page had + * been moved, we know the page bit was previously clear and + * later set, and we can reuse the new page. + */ + src_base = sfile.buf_offset & MMU_PAGEMASK; + while (lboff < src_base) { + coff = lboff; + lboff += MMU_PAGESIZE; + ppn = SF_ORIG_PPN(coff); + if (cb_bitop(ppn, CB_ISCLR)) { + (void) cb_bitop(ppn, CB_SETBIT); + SF_STAT_INC(recycle); + return (ppn); + } else if (SF_DIFF_PPN(coff)) { + SF_STAT_INC(recycle); + return (SF_BUF_PPN(coff)); + } + } + + return (PFN_INVALID); +} + + +/* + * scan physavail and statefile buffer page lists + * for a page that doesn't clash with the kernel + */ +pfn_t +find_apage(void) +{ + pfn_t ppn; + + ppn = search_phav_pages(); + if (ppn != PFN_INVALID) + return (ppn); + ppn = search_buf_pages(); + if (ppn != PFN_INVALID) + return (ppn); + + prom_printf("\n%s: ran out of available/free pages!\n%s\n", + prog, rsvp); + cb_exit_to_mon(); + + /* NOTREACHED */ + return (PFN_INVALID); +} + + +/* + * reserve virt range, find available phys pages, + * and map-in each phys starting at vaddr + */ +static caddr_t +map_free_phys(caddr_t vaddr, size_t size, char *name) +{ + int pages, ppn, err; + physaddr_t phys; + caddr_t virt; + char *str; + + str = "map_free_phys"; + virt = prom_claim_virt(size, vaddr); + CB_VPRINTF(("\n%s: claim vaddr 0x%x, size 0x%x, ret 0x%x\n", + str, vaddr, size, virt)); + if (virt != vaddr) { + prom_printf("\n%s: cant reserve (0x%p - 0x%p) for \"%s\"\n", + str, vaddr, vaddr + size, name); + return (virt); + } + + for (pages = mmu_btop(size); pages--; virt += MMU_PAGESIZE) { + /* + * map virt page to free phys + */ + ppn = find_apage(); + phys = PN_TO_ADDR(ppn); + + err = prom_map_phys(-1, MMU_PAGESIZE, virt, phys); + if (err || verbose) { + prom_printf(" map virt 0x%p, phys 0x%lx, " + "ppn 0x%lx, ret %d\n", virt, phys, ppn, err); + } + if (err) + return ((caddr_t)ERR); + } + + return (vaddr); +} + + +/* + * check bitmap desc and relocate bitmap data + * to pages isolated from the kernel + * + * sets globals: + * high_virt + */ +int +cb_set_bitmap(void) +{ + size_t bmda_size, all_bitmap_size, alloc_size; + caddr_t newvirt, src, dst, base; + cbd_t *dp; + char *str; + + str = "cb_set_bitmap"; + CB_VPRINTF((ent_fmt, str, entry)); + + /* + * max is checked in the cpr module; + * this condition should never occur + */ + if (cb_nbitmaps > (CPR_MAX_BMDESC - 1)) { + prom_printf("%s: too many bitmap descriptors %d, max %d\n", + str, cb_nbitmaps, (CPR_MAX_BMDESC - 1)); + return (ERR); + } + + /* + * copy bitmap descriptors to aligned space, check magic numbers, + * and set the total size of all bitmaps + */ + bmda_size = cb_nbitmaps * sizeof (cbd_t); + src = SF_DATA(); + bcopy(src, cb_bmda, bmda_size); + base = src + bmda_size; + all_bitmap_size = 0; + for (dp = cb_bmda; dp < &cb_bmda[cb_nbitmaps]; dp++) { + if (dp->cbd_magic != CPR_BITMAP_MAGIC) { + prom_printf("%s: bad magic 0x%x, expect 0x%x\n", + str, dp->cbd_magic, CPR_BITMAP_MAGIC); + return (ERR); + } + all_bitmap_size += dp->cbd_size; + dp->cbd_reg_bitmap = (cpr_ptr)base; + base += dp->cbd_size; + } + + /* + * reserve new space for bitmaps + */ + alloc_size = PAGE_ROUNDUP(all_bitmap_size); + if (verbose || CPR_DBG(7)) { + prom_printf("%s: nbitmaps %d, bmda_size 0x%lx\n", + str, cb_nbitmaps); + prom_printf("%s: all_bitmap_size 0x%lx, alloc_size 0x%lx\n", + str, all_bitmap_size, alloc_size); + } + high_virt = (caddr_t)CB_HIGH_VIRT; + newvirt = map_free_phys(high_virt, alloc_size, "bitmaps"); + if (newvirt != high_virt) + return (ERR); + + /* + * copy the bitmaps, clear any unused space trailing them, + * and set references into the new space + */ + base = src + bmda_size; + dst = newvirt; + bcopy(base, dst, all_bitmap_size); + if (alloc_size > all_bitmap_size) + bzero(dst + all_bitmap_size, alloc_size - all_bitmap_size); + for (dp = cb_bmda; dp->cbd_size; dp++) { + dp->cbd_reg_bitmap = (cpr_ptr)dst; + dst += dp->cbd_size; + } + + /* advance past all the bitmap data */ + SF_ADV(bmda_size + all_bitmap_size); + high_virt += alloc_size; + + return (0); +} + + +/* + * create a new stack for cprboot; + * this stack is used to avoid clashes with kernel pages and + * to avoid exceptions while remapping cprboot virt pages + */ +int +cb_get_newstack(void) +{ + caddr_t newstack; + + CB_VENTRY(cb_get_newstack); + newstack = map_free_phys((caddr_t)CB_STACK_VIRT, + CB_STACK_SIZE, "new stack"); + if (newstack != (caddr_t)CB_STACK_VIRT) + return (ERR); + return (0); +} + + +/* + * since kernel phys pages span most of the installed memory range, + * some statefile buffer pages will likely clash with the kernel + * and need to be moved before kernel pages are restored; a list + * of buf phys page numbers is created here and later updated as + * buf pages are moved + * + * sets globals: + * sfile.buf_map + * tracking_init + */ +int +cb_tracking_setup(void) +{ + pfn_t ppn, lppn; + uint_t *imap; + caddr_t newvirt; + size_t size; + int pages; + + CB_VENTRY(cb_tracking_setup); + + pages = mmu_btop(sfile.size); + size = PAGE_ROUNDUP(pages * sizeof (*imap)); + newvirt = map_free_phys(high_virt, size, "buf tracking"); + if (newvirt != high_virt) + return (ERR); + sfile.buf_map = (uint_t *)newvirt; + high_virt += size; + + /* + * create identity map of sfile.buf phys pages + */ + imap = sfile.buf_map; + lppn = sfile.low_ppn + pages; + for (ppn = sfile.low_ppn; ppn < lppn; ppn++, imap++) + *imap = (uint_t)ppn; + tracking_init = 1; + + return (0); +} + + +/* + * get "available" prop from /memory node + * + * sets globals: + * cb_physavail + */ +int +cb_get_physavail(void) +{ + int len, glen, scnt, need, space; + char *str, *pdev, *mem_prop; + dnode_t mem_node; + physaddr_t phys; + pgcnt_t pages; + arange_t *arp; + pphav_t *pap; + size_t size; + pfn_t ppn; + int err; + + str = "cb_get_physavail"; + CB_VPRINTF((ent_fmt, str, entry)); + + /* + * first move cprboot pages off the physavail list + */ + size = PAGE_ROUNDUP((uintptr_t)_end) - (uintptr_t)_start; + ppn = cpr_vatopfn((caddr_t)_start); + phys = PN_TO_ADDR(ppn); + err = prom_claim_phys(size, phys); + CB_VPRINTF((" text/data claim (0x%lx - 0x%lx) = %d\n", + ppn, ppn + mmu_btop(size) - 1, err)); + if (err) + return (ERR); + + pdev = "/memory"; + mem_node = prom_finddevice(pdev); + if (mem_node == OBP_BADNODE) { + prom_printf("%s: cant find \"%s\" node\n", str, pdev); + return (ERR); + } + mem_prop = "available"; + + /* + * prop data is treated as a struct array; + * verify pabuf has enough room for the array + * in the original and converted forms + */ + len = prom_getproplen(mem_node, mem_prop); + scnt = len / sizeof (*pap); + need = len + (sizeof (*arp) * (scnt + 1)); + space = sizeof (pabuf); + CB_VPRINTF((" %s node 0x%x, len %d\n", pdev, mem_node, len)); + if (len == -1 || need > space) { + prom_printf("\n%s: bad \"%s\" length %d, min %d, max %d\n", + str, mem_prop, len, need, space); + return (ERR); + } + + /* + * read-in prop data and clear trailing space + */ + glen = prom_getprop(mem_node, mem_prop, pabuf); + if (glen != len) { + prom_printf("\n%s: %s,%s: expected len %d, got %d\n", + str, mem_node, mem_prop, len, glen); + return (ERR); + } + bzero(&pabuf[len], space - len); + + /* + * convert the physavail list in place + * from (phys_base, phys_size) to (low_ppn, high_ppn) + */ + if (verbose) + prom_printf("\nphysavail list:\n"); + cb_physavail = (arange_t *)pabuf; + arp = cb_physavail + scnt - 1; + pap = (pphav_t *)cb_physavail + scnt - 1; + for (; scnt--; pap--, arp--) { + pages = mmu_btop(pap->size); + arp->low = ADDR_TO_PN(pap->base); + arp->high = arp->low + pages - 1; + if (verbose) { + prom_printf(" %d: (0x%lx - 0x%lx),\tpages %d\n", + (int)(arp - cb_physavail), + arp->low, arp->high, (arp->high - arp->low + 1)); + } + } + + return (0); +} + + +/* + * search for an available phys page, + * copy the old phys page to the new one + * and remap the virt page to the new phys + */ +static int +move_page(caddr_t vaddr, pfn_t oldppn) +{ + physaddr_t oldphys, newphys; + pfn_t newppn; + int err; + + newppn = find_apage(); + newphys = PN_TO_ADDR(newppn); + oldphys = PN_TO_ADDR(oldppn); + CB_VPRINTF((" remap vaddr 0x%p, old 0x%x/0x%x, new 0x%x/0x%x\n", + vaddr, oldppn, oldphys, newppn, newphys)); + phys_xcopy(oldphys, newphys, MMU_PAGESIZE); + err = prom_remap(MMU_PAGESIZE, vaddr, newphys); + if (err) + prom_printf("\nmove_page: remap error\n"); + return (err); +} + + +/* + * physically relocate any text/data pages that clash + * with the kernel; since we're already running on + * a new stack, the original stack area is skipped + */ +int +cb_relocate(void) +{ + int is_ostk, is_clash, clash_cnt, ok_cnt; + char *str, *desc, *skip_fmt; + caddr_t ostk_low, ostk_high; + caddr_t virt, saddr, eaddr; + pfn_t ppn; + + str = "cb_relocate"; + CB_VPRINTF((ent_fmt, str, entry)); + + ostk_low = (caddr_t)&estack - CB_STACK_SIZE; + ostk_high = (caddr_t)&estack - MMU_PAGESIZE; + saddr = (caddr_t)_start; + eaddr = (caddr_t)PAGE_ROUNDUP((uintptr_t)_end); + + install_remap(); + + skip_fmt = " skip vaddr 0x%p, clash=%d, %s\n"; + clash_cnt = ok_cnt = 0; + ppn = cpr_vatopfn(saddr); + + for (virt = saddr; virt < eaddr; virt += MMU_PAGESIZE, ppn++) { + is_clash = (cb_bitop(ppn, CB_ISSET) != 0); + if (is_clash) + clash_cnt++; + else + ok_cnt++; + + is_ostk = (virt >= ostk_low && virt <= ostk_high); + if (is_ostk) + desc = "orig stack"; + else + desc = "text/data"; + + /* + * page logic: + * + * if (original stack page) + * clash doesn't matter, just skip the page + * else (not original stack page) + * if (no clash) + * setbit to avoid later alloc and overwrite + * else (clash) + * relocate phys page + */ + if (is_ostk) { + CB_VPRINTF((skip_fmt, virt, is_clash, desc)); + } else if (is_clash == 0) { + CB_VPRINTF((skip_fmt, virt, is_clash, desc)); + (void) cb_bitop(ppn, CB_SETBIT); + } else if (move_page(virt, ppn)) + return (ERR); + } + CB_VPRINTF(("%s: total %d, clash %d, ok %d\n", + str, clash_cnt + ok_cnt, clash_cnt, ok_cnt)); + + /* + * free original stack area for reuse + */ + ppn = cpr_vatopfn(ostk_low); + prom_free_phys(CB_STACK_SIZE, PN_TO_ADDR(ppn)); + CB_VPRINTF(("%s: free old stack (0x%lx - 0x%lx)\n", + str, ppn, ppn + mmu_btop(CB_STACK_SIZE) - 1)); + + return (0); +} diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/cb_srt0.s b/usr/src/psm/stand/cpr/sparcv9/sun4u/cb_srt0.s new file mode 100644 index 0000000000..a75271d06c --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/cb_srt0.s @@ -0,0 +1,405 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * cb_srt0.s - cprboot startup code + */ +#include <sys/asm_linkage.h> +#include <sys/machthread.h> +#include <sys/privregs.h> +#include <sys/cpr_impl.h> +#include <sys/param.h> +#include <sys/mmu.h> + +#if defined(lint) +#include <sys/cpr.h> +void *estack; +caddr_t _end[1]; +#endif + +#include "cprboot.h" + + +#if defined(lint) + +/* ARGSUSED */ +void +_start(void *a, ...) +{} + +#else /* !lint */ + + .seg ".bss" + .align MMU_PAGESIZE + .skip CB_SSS +eslave_stack: ! top of slave cpu stack + .skip CB_MSS +estack: ! top of cprboot stack + .global estack + + .seg ".data" + .align 8 +local_cif: + .xword 0 ! space for prom cookie + + .seg ".text" + .align 8 + + ! + ! regs on entry: + ! %o4 = prom cookie + ! + ENTRY(_start) + set estack - STACK_BIAS, %o5 + save %o5, -SA(MINFRAME), %sp + + ! + ! clear the bss + ! + set _edata, %o0 + set _end, %g2 + call bzero + sub %g2, %o0, %o1 ! bss size = (_end - _edata) + + ! + ! Set pstate to a known state: + ! enable fp, privilege, interrupt enable + ! + wrpr %g0, PSTATE_PEF|PSTATE_PRIV|PSTATE_IE, %pstate + + ! + ! first stage + ! + set local_cif, %g2 + stx %i4, [%g2] + mov %i4, %o0 ! SPARCV9/CIF + call main ! Mcprboot [tag] + mov 1, %o1 ! first=true + + ! + ! switch to new stack + ! + set CB_STACK_VIRT + CB_STACK_SIZE, %o5 + sub %o5, STACK_BIAS + SA(MINFRAME), %sp + + ! + ! second stage + ! + set local_cif, %g2 + ldx [%g2], %o0 ! SPARCV9/CIF + call main ! Mcprboot [tag] + mov 0, %o1 ! first=false + + call prom_exit_to_mon ! can't happen... :-) + nop + SET_SIZE(_start) + +#endif /* lint */ + + +#if defined(lint) + +/* + * args from cprboot main: + * %o0 prom cookie + * %o1 struct sun4u_machdep *mdp + * + * Any change to this register assignment requires + * changes to uts/sun4u/ml/cpr_resume_setup.s + */ + +/* ARGSUSED */ +void +exit_to_kernel(void *cookie, csu_md_t *mdp) +{} + +#else /* lint */ + + ENTRY(exit_to_kernel) + ! + ! setup temporary stack and adjust + ! by the saved kernel stack bias + ! + set tmp_stack, %g1 ! g1 = &tmp_stack + ldx [%g1], %l2 ! l2 = tmp_stack + sub %l2, SA(MINFRAME), %l2 + ld [%o1 + CPR_MD_KSB], %l4 ! mdp->ksb + sub %l2, %l4, %sp + + ! + ! set pstate and wstate from saved values + ! + lduh [%o1 + CPR_MD_KPSTATE], %l4 ! l4 = mdp->kpstate + wrpr %g0, %l4, %pstate + lduh [%o1 + CPR_MD_KWSTATE], %l4 ! l4 = mdp->kwstate + wrpr %g0, %l4, %wstate + + ! + ! jump to kernel with %o0 and %o1 unchanged + ! + ldx [%o1 + CPR_MD_FUNC], %l3 ! l3 = mdp->func + jmpl %l3, %g0 + nop + + /* there is no return from here */ + unimp 0 + SET_SIZE(exit_to_kernel) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +int +client_handler(void *cif_handler, void *arg_array) +{ return (0); } + +#else + + ! + ! 64/64 client interface for ieee1275 prom + ! + ENTRY(client_handler) + mov %o7, %g1 + mov %o0, %g5 + mov %o1, %o0 + jmp %g5 + mov %g1, %o7 + SET_SIZE(client_handler) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +bzero(void *base, size_t len) +{} + +#else + + ENTRY(bzero) + brz,pn %o1, 2f + nop + mov %o0, %o2 + mov %o1, %o3 +1: + stub %g0, [%o2] + dec %o3 + brgz,pt %o3, 1b + inc %o2 +2: + retl + nop + SET_SIZE(bzero) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +phys_xcopy(physaddr_t phys_src, physaddr_t phys_dst, size_t len) +{} + +#else + + ! + ! copy len bytes from src to dst phys addrs; + ! requires src/dst/len 8-byte alignment; + ! used only for copying phys pages + ! + ENTRY(phys_xcopy) + brz,pn %o2, 2f + mov %o0, %o3 ! %o3 = src + mov %o1, %o4 ! %o4 = dst +1: + ldxa [%o3]ASI_MEM, %o5 ! %o5 = *src + stxa %o5, [%o4]ASI_MEM ! *dst = %o5 + dec 8, %o2 ! len -= 8 + inc 8, %o3 ! src += 8 + brgz,pt %o2, 1b ! branch when (len > 0) + inc 8, %o4 ! dst += 8 +2: + retl + nop + SET_SIZE(phys_xcopy) + +#endif + + +#if defined(lint) + +/* ARGSUSED */ +void +get_dtlb_entry(int index, caddr_t *vaddrp, tte_t *tte) +{} + +#else /* lint */ + + ENTRY(get_dtlb_entry) + sllx %o0, 3, %o0 + ldxa [%o0]ASI_DTLB_ACCESS, %o3 + stx %o3, [%o2] + ldxa [%o0]ASI_DTLB_TAGREAD, %o4 + retl + stx %o4, [%o1] + SET_SIZE(get_dtlb_entry) + +#endif + + +#if defined(lint) + +/* ARGSUSED */ +void +set_itlb_entry(int index, caddr_t vaddr, tte_t *tte) +{} + +/* ARGSUSED */ +void +set_dtlb_entry(int index, caddr_t vaddr, tte_t *tte) +{} + +#else /* lint */ + + ENTRY(set_dtlb_entry) + sllx %o0, 3, %o0 + srlx %o1, MMU_PAGESHIFT, %o1 + sllx %o1, MMU_PAGESHIFT, %o1 + set MMU_TAG_ACCESS, %o4 + ldx [%o2], %o3 + stxa %o1, [%o4]ASI_DMMU + stxa %o3, [%o0]ASI_DTLB_ACCESS + membar #Sync + retl + nop + SET_SIZE(set_dtlb_entry) + + ENTRY(set_itlb_entry) + sllx %o0, 3, %o0 + srlx %o1, MMU_PAGESHIFT, %o1 + sllx %o1, MMU_PAGESHIFT, %o1 + set MMU_TAG_ACCESS, %o4 + ldx [%o2], %o3 + stxa %o1, [%o4]ASI_IMMU + stxa %o3, [%o0]ASI_ITLB_ACCESS + membar #Sync + retl + nop + SET_SIZE(set_itlb_entry) + +#endif + + +#if defined(lint) + +uint_t +getmid(void) +{ return (0); } + +#else /* lint */ + + ENTRY(getmid) + CPU_INDEX(%o0, %o1) + retl + nop + SET_SIZE(getmid) + +#endif + + +#if defined(lint) + +/* ARGSUSED */ +void +cpu_launch(int cpuid) +{ + slave_init(cpuid); +} + +#else /* lint */ + + ENTRY(cpu_launch) + set CB_STACK_VIRT + CB_SSS, %o5 + sub %o5, STACK_BIAS + SA(MINFRAME), %sp + wrpr %g0, PSTATE_PEF|PSTATE_PRIV|PSTATE_IE, %pstate + call slave_init + nop + unimp 0 + SET_SIZE(cpu_launch) + +#endif + + +#if defined(lint) + +void +membar_stld(void) +{} + +#else /* lint */ + + ENTRY(membar_stld) + retl + membar #StoreLoad + SET_SIZE(membar_stld) + +#endif + + +#if defined(lint) + +/* ARGSUSED */ +void +cb_usec_wait(int usecs) +{} + +#else + + .align 32 ! cache alignment for next 8 instr + ENTRY(cb_usec_wait) + + sethi %hi(cpu_delay), %o1 + ld [%o1 + %lo(cpu_delay)], %o1 + mov %o1, %o2 +1: brnz,pt %o2, 1b ! usec countdown loop + dec %o2 ! 2 instr in loop + + dec %o0 ! for each usec: + brgz,pt %o0, 1b ! run the above loop + mov %o1, %o2 + + retl + nop + SET_SIZE(cb_usec_wait) + +#endif diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/cprboot.c b/usr/src/psm/stand/cpr/sparcv9/sun4u/cprboot.c new file mode 100644 index 0000000000..d622b1e594 --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/cprboot.c @@ -0,0 +1,577 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * cprboot - prom client that restores kadb/kernel pages + * + * simple cprboot overview: + * reset boot-file/boot-device to their original values + * open cpr statefile, usually "/.CPR" + * read in statefile + * close statefile + * restore kernel pages + * jump back into kernel text + * + * + * cprboot supports a restartable statefile for FAA/STARS, + * Federal Aviation Administration + * Standard Terminal Automation Replacement System + */ + +#include <sys/types.h> +#include <sys/cpr.h> +#include <sys/promimpl.h> +#include <sys/ddi.h> +#include "cprboot.h" + + +/* + * local defs + */ +#define CB_MAXPROP 256 +#define CB_MAXARGS 8 + + +/* + * globals + */ +struct statefile sfile; + +char cpr_statefile[OBP_MAXPATHLEN]; +char cpr_filesystem[OBP_MAXPATHLEN]; + +int cpr_debug; /* cpr debug, set with uadmin 3 10x */ +uint_t cb_msec; /* cprboot start runtime */ +uint_t cb_dents; /* number of dtlb entries */ + +int do_halt = 0; /* halt (enter mon) after load */ +int verbose = 0; /* verbose, traces cprboot ops */ + +char rsvp[] = "please reboot"; +char prog[] = "cprboot"; +char entry[] = "ENTRY"; +char ent_fmt[] = "\n%s %s\n"; + + +/* + * file scope + */ +static char cb_argbuf[CB_MAXPROP]; +static char *cb_args[CB_MAXARGS]; + +static int reusable; +static char *specialstate; + + +static int +cb_intro(void) +{ + static char cstr[] = "\014" "\033[1P" "\033[18;21H"; + + CB_VENTRY(cb_intro); + + /* + * build/debug aid; this condition should not occur + */ + if ((uintptr_t)_end > CB_SRC_VIRT) { + prom_printf("\ndata collision:\n" + "(_end=0x%p > CB_LOW_VIRT=0x%p), recompile...\n", + _end, CB_SRC_VIRT); + return (ERR); + } + + /* clear console */ + prom_printf(cstr); + + prom_printf("Restoring the System. Please Wait... "); + return (0); +} + + +/* + * read bootargs and convert to arg vector + * + * sets globals: + * cb_argbuf + * cb_args + */ +static void +get_bootargs(void) +{ + char *cp, *tail, *argp, **argv; + + CB_VENTRY(get_bootargs); + + (void) prom_strcpy(cb_argbuf, prom_bootargs()); + tail = cb_argbuf + prom_strlen(cb_argbuf); + + /* + * scan to the trailing NULL so the last arg + * will be found without any special-case code + */ + argv = cb_args; + for (cp = argp = cb_argbuf; cp <= tail; cp++) { + if (prom_strchr(" \t\n\r", *cp) == NULL) + continue; + *cp = '\0'; + if (cp - argp) { + *argv++ = argp; + if ((argv - cb_args) == (CB_MAXARGS - 1)) + break; + } + argp = cp + 1; + } + *argv = NULLP; + + if (verbose) { + for (argv = cb_args; *argv; argv++) { + prom_printf(" %d: \"%s\"\n", + (argv - cb_args), *argv); + } + } +} + + +static void +usage(char *expect, char *got) +{ + if (got == NULL) + got = "(NULL)"; + prom_printf("\nbad OBP boot args: expect %s, got %s\n" + "Usage: boot -F %s [-R] [-S <diskpath>]\n%s\n\n", + expect, got, prog, rsvp); + prom_exit_to_mon(); +} + + +/* + * bootargs should start with "-F cprboot" + * + * may set globals: + * specialstate + * reusable + * do_halt + * verbose + */ +static void +check_bootargs(void) +{ + char **argv, *str, *cp; + + argv = cb_args; + + /* expect "-F" */ + str = "-F"; + if (*argv == NULL || prom_strcmp(*argv, str)) + usage(str, *argv); + argv++; + + /* expect "cprboot*" */ + if (*argv == NULL || prom_strncmp(*argv, prog, sizeof (prog) - 1)) + usage(prog, *argv); + + /* + * optional args + */ + str = "-[SR]"; + for (argv++; *argv; argv++) { + cp = *argv; + if (*cp != '-') + usage(str, *argv); + + switch (*++cp) { + case 'R': + case 'r': + reusable = 1; + break; + case 'S': + case 's': + if (*++argv) + specialstate = *argv; + else + usage("statefile-path", *argv); + break; + case 'h': + do_halt = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(str, *argv); + break; + } + } +} + + +/* + * reset prom props and get statefile info + * + * sets globals: + * cpr_filesystem + * cpr_statefile + */ +static int +cb_startup(void) +{ + CB_VENTRY(cb_startup); + + if (!reusable) { + /* + * Restore the original values of the nvram properties modified + * during suspend. Note: if we can't get this info from the + * defaults file, the state file may be obsolete or bad, so we + * abort. However, failure to restore one or more properties + * is NOT fatal (better to continue the resume). + */ + if (cpr_reset_properties() == -1) { + prom_printf("\n%s: cannot read saved " + "nvram info, %s\n", prog, rsvp); + return (ERR); + } + } + + /* + * simple copy if using specialstate, + * otherwise read in fs and statefile from a config file + */ + if (specialstate) + (void) prom_strcpy(cpr_statefile, specialstate); + else if (cpr_locate_statefile(cpr_statefile, cpr_filesystem) == -1) { + prom_printf("\n%s: cannot find cpr statefile, %s\n", + prog, rsvp); + return (ERR); + } + + return (0); +} + + +static int +cb_open_sf(void) +{ + CB_VENTRY(cb_open_sf); + + sfile.fd = cpr_statefile_open(cpr_statefile, cpr_filesystem); + if (sfile.fd == -1) { + prom_printf("\n%s: can't open %s", prog, cpr_statefile); + if (specialstate) + prom_printf(" on %s", cpr_filesystem); + prom_printf("\n%s\n", rsvp); + return (ERR); + } + + /* + * for block devices, seek past the disk label and bootblock + */ + if (specialstate) + (void) prom_seek(sfile.fd, CPR_SPEC_OFFSET); + + return (0); +} + + +static int +cb_close_sf(void) +{ + CB_VENTRY(cb_close_sf); + + /* + * close the device so the prom will free up 20+ pages + */ + (void) cpr_statefile_close(sfile.fd); + return (0); +} + + +/* + * to restore kernel pages, we have to open a prom device to read-in + * the statefile contents; a prom "open" request triggers the driver + * and various packages to allocate 20+ pages; unfortunately, some or + * all of those pages always clash with kernel pages, and we cant write + * to them without corrupting the prom. + * + * to solve that problem, the only real solution is to close the device + * to free up those pages; this means we need to open, read-in the entire + * statefile, and close; and to store the statefile, we need to allocate + * plenty of space, usually around 2 to 60 MB. + * + * the simplest alloc means is prom_alloc(), which will "claim" both + * virt and phys pages, and creates mappings with a "map" request; + * "map" also causes the prom to alloc pages, and again these clash + * with kernel pages... + * + * to solve the "map" problem, we just reserve virt and phys pages and + * manage the translations by creating our own tlb entries instead of + * relying on the prom. + * + * sets globals: + * cpr_test_mode + * sfile.kpages + * sfile.size + * sfile.buf + * sfile.low_ppn + * sfile.high_ppn + */ +static int +cb_read_statefile(void) +{ + size_t alsize, len, resid; + physaddr_t phys, dst_phys; + char *str, *dst_virt; + int err, cnt, mmask; + uint_t dtlb_index; + ssize_t nread; + cdd_t cdump; + + str = "cb_read_statefile"; + CB_VPRINTF((ent_fmt, str, entry)); + + /* + * read-in and check cpr dump header + */ + if (cpr_read_cdump(sfile.fd, &cdump, CPR_MACHTYPE_4U)) + return (ERR); + if (cpr_debug) + prom_printf("\n"); + cb_nbitmaps = cdump.cdd_bitmaprec; + cpr_test_mode = cdump.cdd_test_mode; + sfile.kpages = cdump.cdd_dumppgsize; + DEBUG4(prom_printf("%s: total kpages %d\n", prog, sfile.kpages)); + + /* + * alloc virt and phys space with 512K alignment; + * alloc size should be (n * tte size); + */ + sfile.size = PAGE_ROUNDUP(cdump.cdd_filesize); + alsize = (cdump.cdd_filesize + MMU_PAGEOFFSET512K) & + MMU_PAGEMASK512K; + phys = 0; + err = cb_alloc(alsize, MMU_PAGESIZE512K, &sfile.buf, &phys); + CB_VPRINTF(("%s:\n alloc size 0x%lx, buf size 0x%lx\n" + " virt 0x%p, phys 0x%lx\n", + str, alsize, sfile.size, sfile.buf, phys)); + if (err) { + prom_printf("%s: cant alloc statefile buf, size 0x%lx\n%s\n", + str, sfile.size, rsvp); + return (ERR); + } + + /* + * record low and high phys page numbers for sfile.buf + */ + sfile.low_ppn = ADDR_TO_PN(phys); + sfile.high_ppn = sfile.low_ppn + mmu_btop(sfile.size) - 1; + + /* + * setup destination virt and phys addrs for reads; + * mapin-mask tells when to create a new tlb entry for the + * next set of reads; NB: the read and tlb method needs + * ((big-pagesize % read-size) == 0) + */ + dst_phys = phys; + mmask = (MMU_PAGESIZE512K / PROM_MAX_READ) - 1; + + cnt = 0; + dtlb_index = cb_dents - 1; + (void) prom_seek(sfile.fd, specialstate ? CPR_SPEC_OFFSET : 0); + DEBUG1(prom_printf("%s: reading statefile... ", prog)); + for (resid = cdump.cdd_filesize; resid; resid -= len) { + /* + * do a full spin (4 spin chars) + * for every MB read (8 reads = 256K) + */ + if ((cnt & 0x7) == 0) + cb_spin(); + + /* + * map-in statefile buf pages in 512K blocks; + * see MMU_PAGESIZE512K above + */ + if ((cnt & mmask) == 0) { + dst_virt = sfile.buf; + cb_mapin(dst_virt, ADDR_TO_PN(dst_phys), + TTE512K, TTE_HWWR_INT, dtlb_index); + } + + cnt++; + + len = min(PROM_MAX_READ, resid); + nread = prom_read(sfile.fd, dst_virt, len, 0, 0); + if (nread != (ssize_t)len) { + prom_printf("\n%s: prom read error, " + "expect %ld, got %ld\n", str, len, nread); + return (ERR); + } + dst_virt += len; + dst_phys += len; + } + DEBUG1(prom_printf(" \b\n")); + + /* + * free up any unused phys pages trailing the statefile buffer; + * these pages will later appear on the physavail list + */ + if (alsize > sfile.size) { + len = alsize - sfile.size; + prom_free_phys(len, phys + sfile.size); + CB_VPRINTF(("%s: freed %ld phys pages (0x%lx - 0x%lx)\n", + str, mmu_btop(len), phys + sfile.size, phys + alsize)); + } + + /* + * start the statefile buffer offset at the base of + * the statefile buffer and skip past the dump header + */ + sfile.buf_offset = 0; + SF_ADV(sizeof (cdump)); + + /* + * finish with the first block mapped-in to provide easy virt access + * to machdep structs and the bitmap; for 2.8, the combined size of + * (cdd_t + cmd_t + csu_md_t + prom_words + cbd_t) is about 1K, + * leaving room for a bitmap representing nearly 32GB + */ + cb_mapin(sfile.buf, sfile.low_ppn, + TTE512K, TTE_HWWR_INT, dtlb_index); + + return (0); +} + + +/* + * cprboot first stage worklist + */ +static int (*first_worklist[])(void) = { + cb_intro, + cb_startup, + cb_get_props, + cb_usb_setup, + cb_open_sf, + cb_read_statefile, + cb_close_sf, + cb_check_machdep, + cb_interpret, + cb_get_physavail, + cb_set_bitmap, + cb_get_newstack, + NULL +}; + +/* + * cprboot second stage worklist + */ +static int (*second_worklist[])(void) = { + cb_relocate, + cb_tracking_setup, + cb_restore_kpages, + cb_terminator, + cb_ksetup, + cb_mpsetup, + NULL +}; + + +/* + * simple loop driving major cprboot operations; + * exits to prom if any error is returned + */ +static void +cb_drive(int (**worklist)(void)) +{ + int i; + + for (i = 0; worklist[i] != NULL; i++) { + if (worklist[i]()) + cb_exit_to_mon(); + } +} + + +/* + * debugging support: drop to prom if do_halt is set + */ +static void +check_halt(char *str) +{ + if (do_halt) { + prom_printf("\n%s halted by -h flag\n==> before %s\n\n", + prog, str); + cb_enter_mon(); + } +} + + +/* + * main is called twice from "cb_srt0.s", args are: + * cookie ieee1275 cif handle + * first (true): first stage, (false): second stage + * + * first stage summary: + * various setup + * allocate a big statefile buffer + * read in the statefile + * setup the bitmap + * create a new stack + * + * return to "cb_srt0.s", switch to new stack + * + * second stage summary: + * relocate cprboot phys pages + * setup tracking for statefile buffer pages + * restore kernel pages + * various cleanup + * install tlb entries for the nucleus and cpr module + * restore registers and jump into cpr module + */ +int +main(void *cookie, int first) +{ + if (first) { + prom_init(prog, cookie); + cb_msec = prom_gettime(); + get_bootargs(); + check_bootargs(); + check_halt("first_worklist"); + cb_drive(first_worklist); + return (0); + } else { + cb_drive(second_worklist); + if (verbose || CPR_DBG(1)) { + prom_printf("%s: milliseconds %d\n", + prog, prom_gettime() - cb_msec); + prom_printf("%s: resume pc 0x%p\n", prog, mdinfo.func); + prom_printf("%s: exit_to_kernel(0x%p, 0x%p)\n\n", + prog, cookie, &mdinfo); + } + check_halt("exit_to_kernel"); + exit_to_kernel(cookie, &mdinfo); + return (ERR); + } +} diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/cprboot.h b/usr/src/psm/stand/cpr/sparcv9/sun4u/cprboot.h new file mode 100644 index 0000000000..52807b6616 --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/cprboot.h @@ -0,0 +1,259 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _CPRBOOT_H +#define _CPRBOOT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * defs for sun4u cprboot + */ + +/* + * select virt ranges well past _end; + * these ranges are used for tmp tlb entries + * + * CB_SRC_VIRT source statefile buffer pages + * CB_DST_VIRT destination kernel pages + * CB_STACK_VIRT new stack + * CB_HIGH_VIRT ...and above for the bitmap and co. + */ + +#define CB_SRC_VIRT 0x200000 +#define CB_DST_VIRT 0x300000 +#define CB_STACK_VIRT 0x400000 +#define CB_HIGH_VIRT 0x500000 + +/* + * master cpu and slave cpu stack sizes + * their sum should be (n * MMU_PAGESIZE) + */ +#define CB_MSS 0x009000 +#define CB_SSS 0x001000 +#define CB_STACK_SIZE (CB_MSS + CB_SSS) + + +/* + * max number of tlb entries and tmp pages for + * src statefile buf pages and dst kernel pages + */ +#define CB_MAX_KPAGES mmu_btop(CPR_MAX_BLOCK) +#define CB_MAX_BPAGES (CB_MAX_KPAGES + 1) + +#define ERR -1 + + +#ifndef _ASM + +#define CB_VPRINTF(args) \ + if (verbose) prom_printf args + +#define CB_VENTRY(name) \ + CB_VPRINTF((ent_fmt, #name, entry)) + +#define NULLP (char *)0 + +#define CPR_DBG(n) (cpr_debug & LEVEL##n) + + +/* + * info for handling statefile data + */ +struct statefile { + int fd; /* prom file handle */ + int kpages; /* total number of kernel pages */ + size_t size; /* file size, rounded for alloc */ + caddr_t buf; /* allocated file buffer */ + size_t buf_offset; /* byte offset from buf */ + uint_t *buf_map; /* map of buf phys page numbers */ + pfn_t low_ppn; /* lowest buf ppn */ + pfn_t high_ppn; /* highest buf ppn */ + int npages; /* nubmer of pages restored */ + int ngroups; /* number of page groups restored */ + int outside; /* kpage is outside of buf range */ + int precede; /* kpage preceeds buf offset */ + int move; /* number of buf pages moved */ + int recycle; /* free tmp page for reuse */ +}; + +/* + * convert a statefile buffer byte-offset into a buffer ppn; + * buf_map starts out as an identity map, and gets updated as + * pages are moved; the original ppn can always be derived + * from the ORIG macro: + */ +#define SF_BUF_PPN(off) *(sfile.buf_map + mmu_btop(off)) +#define SF_ORIG_PPN(off) sfile.low_ppn + mmu_btop(off) +#define SF_SAME_PPN(off) (SF_BUF_PPN(off) == SF_ORIG_PPN(off)) +#define SF_DIFF_PPN(off) (SF_BUF_PPN(off) != SF_ORIG_PPN(off)) + +#define SF_STAT_INC(field) sfile.field++ + + +/* + * next data in statefile buffer + */ +#define SF_DATA() sfile.buf + sfile.buf_offset + +/* + * advance statefile buffer offset + */ +#define SF_ADV(len) sfile.buf_offset += len + +/* + * struct data is written to the statefile without any alignment + * handling; for easy access, struct data gets copied to aligned + * space and the buf data pointer is advanced + */ +#define SF_DCOPY(space) \ + bcopy(SF_DATA(), &space, sizeof (space)); \ + SF_ADV(sizeof (space)) + + +/* + * structure of "available" property from /memory node + */ +struct prom_physavail { + physaddr_t base; /* start of phys range */ + size_t size; /* size of phys range */ +}; + +struct avail_range { + pfn_t low; + pfn_t high; + pgcnt_t nfree; +}; + +typedef struct prom_physavail pphav_t; +typedef struct avail_range arange_t; + + +/* + * prom properties and data + */ +struct cb_props { + caddr_t prop; + uint_t *datap; +}; + + +/* + * ../../common/support.c + */ +extern int cpr_reset_properties(void); +extern int cpr_locate_statefile(char *, char *); +extern void cpr_update_terminator(ctrm_t *, caddr_t); + +/* + * cprboot.c + */ +extern struct statefile sfile; +extern char prog[]; +extern char rsvp[]; +extern char entry[]; +extern char ent_fmt[]; +extern int verbose; +extern uint_t cb_dents; +extern uint_t cb_msec; + +/* + * machdep.c + */ +extern int cpr_test_mode; +extern csu_md_t mdinfo; +extern uint_t cpu_delay; +extern uint_t cb_mid; +extern uint_t cb_clock_freq; +extern int cb_check_machdep(void); +extern int cb_interpret(void); +extern int cb_ksetup(void); +extern int cb_mpsetup(void); +extern void slave_init(int); + +/* + * pages.c + */ +extern int cb_restore_kpages(void); +extern int cb_terminator(void); + +/* + * bitmap.c + */ +extern int cb_nbitmaps; +extern pfn_t find_apage(void); +extern int cb_set_bitmap(void); +extern int cb_get_newstack(void); +extern int cb_tracking_setup(void); +extern int cb_get_physavail(void); +extern int cb_relocate(void); + +/* + * util.c + */ +extern int cpr_statefile_open(char *, char *); +extern int cpr_statefile_close(int); +extern int cpr_read(int, caddr_t, size_t); +extern void cb_spin(void); +extern pfn_t cpr_vatopfn(caddr_t); +extern int prom_remap(size_t, caddr_t, physaddr_t); +extern void install_remap(void); +extern int cb_alloc(size_t, uint_t, caddr_t *, physaddr_t *); +extern int cb_get_props(void); +extern void cb_mapin(caddr_t, pfn_t, uint_t, uint_t, uint_t); +extern int cb_usb_setup(void); +extern void cb_enter_mon(void); +extern void cb_exit_to_mon(void); + +/* + * cb_srt0.s + */ +extern caddr_t _end[]; +extern void *estack; +extern void _start(void *, ...); +extern void exit_to_kernel(void *, csu_md_t *); +extern void bzero(void *, size_t); +extern void phys_xcopy(physaddr_t, physaddr_t, size_t); +extern void ptov_bcopy(physaddr_t, void *, size_t); +extern void get_dtlb_entry(int, caddr_t *, tte_t *); +extern void set_dtlb_entry(int, caddr_t, tte_t *); +extern void set_itlb_entry(int, caddr_t, tte_t *); +extern void cpu_launch(int); +extern void cb_usec_wait(int); +extern void membar_stld(void); +extern uint_t getmid(void); + +#endif /* !_ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _CPRBOOT_H */ diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/machdep.c b/usr/src/psm/stand/cpr/sparcv9/sun4u/machdep.c new file mode 100644 index 0000000000..43ab650fd7 --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/machdep.c @@ -0,0 +1,315 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpr.h> +#include <sys/promimpl.h> +#include <sys/privregs.h> +#include <sys/stack.h> +#include <sys/cpuvar.h> +#include "cprboot.h" + + +#define TIMEOUT_MSECS 1000 + + +/* + * globals + */ +int cpr_test_mode; +csu_md_t mdinfo; +caddr_t tmp_stack; +uint_t cb_mid; +uint_t cb_clock_freq; +uint_t cpu_delay; + + +/* + * file scope + */ +typedef void (*tlb_func_t)(int, caddr_t, tte_t *); +static uint_t mdlen; +static cpuset_t slave_set; +static int has_scbc; + + +/* + * check machdep desc and cpr_machdep info + * + * sets globals: + * mdinfo + * mdlen + */ +int +cb_check_machdep(void) +{ + uint16_t wst32, wst64; + char *fmt, *str; + cmd_t cmach; + + str = "cb_check_machdep"; + CB_VPRINTF((ent_fmt, str, entry)); + + /* + * get machdep desc and set length of prom words + */ + SF_DCOPY(cmach); + if (cmach.md_magic != CPR_MACHDEP_MAGIC) { + prom_printf("%s: bad machdep magic 0x%x, expect 0x%x\n", + str, cmach.md_magic, CPR_MACHDEP_MAGIC); + return (ERR); + } + mdlen = cmach.md_size - sizeof (csu_md_t); + + /* + * get machep info, check for valid stack bias and wstate + */ + SF_DCOPY(mdinfo); + fmt = "found bad statefile data: %s (0x%x), expect 0x%x or 0x%x\n"; + if (mdinfo.ksb != 0x0 && mdinfo.ksb != V9BIAS64) { + prom_printf(fmt, "stack bias", mdinfo.ksb, 0, V9BIAS64); + return (ERR); + } + wst32 = WSTATE(WSTATE_U32, WSTATE_K32); + wst64 = WSTATE(WSTATE_U32, WSTATE_K64); + if (mdinfo.kwstate != wst32 && mdinfo.kwstate != wst64) { + prom_printf(fmt, "wstate", mdinfo.kwstate, wst32, wst64); + return (ERR); + } + + return (0); +} + + +/* + * interpret saved prom words + */ +int +cb_interpret(void) +{ + int bytes, wlen, s; + char minibuf[60]; + char *words; + + CB_VENTRY(cb_interpret); + + /* + * The variable length machdep section for sun4u consists of + * a sequence of null-terminated strings stored contiguously. + * + * The first string defines Forth words which help the prom + * handle kernel translations. + * + * The second string defines Forth words required by kadb to + * interface with the prom when a trap is taken. + */ + words = SF_DATA(); + bytes = mdlen; + while (bytes) { + wlen = prom_strlen(words) + 1; /* include the null */ + if (verbose) { + s = sizeof (minibuf) - 4; + (void) prom_strncpy(minibuf, words, s); + if (wlen > s) + (void) prom_strcpy(&minibuf[s], "..."); + prom_printf(" interpret \"%s\"\n", minibuf); + } + prom_interpret(words, 0, 0, 0, 0, 0); + words += wlen; + bytes -= wlen; + } + + /* advance past prom words */ + SF_ADV(mdlen); + + return (0); +} + + +/* + * write dtlb/itlb entries + */ +static void +restore_tlb(struct sun4u_tlb *utp, int cpu_id) +{ + struct sun4u_tlb *tail; + tlb_func_t tfunc; + caddr_t virt; + char tname; + + if (utp == mdinfo.dtte) { + tfunc = set_dtlb_entry; + tname = 'd'; + } else if (utp == mdinfo.itte) { + tfunc = set_itlb_entry; + tname = 'i'; + } + + for (tail = utp + CPR_MAX_TLB; utp < tail; utp++) { + if (utp->va_tag == NULL) + continue; + virt = (caddr_t)utp->va_tag; + (*tfunc)(utp->index, virt, &utp->tte); + if (verbose || CPR_DBG(4)) { + prom_printf(" cpu_id %d: write %ctlb " + "(index %x, virt 0x%p, size 0x%x)\n", + cpu_id, tname, utp->index, utp->va_tag, + TTEBYTES(utp->tte.tte_size)); + } + } +} + + +/* + * install locked tlb entries for the kernel and cpr module; + * also sets up the tmp stack + */ +int +cb_ksetup(void) +{ + CB_VENTRY(cb_ksetup); + + restore_tlb(mdinfo.dtte, cb_mid); + restore_tlb(mdinfo.itte, cb_mid); + tmp_stack = (caddr_t)(mdinfo.tmp_stack + mdinfo.tmp_stacksize); + + return (0); +} + + +static void +cb_park_err(int cpu_id) +{ + prom_printf("\ncpu_id %d did not stop!...\n", cpu_id); + cb_exit_to_mon(); +} + + +/* + * local copy of an older interface for OBP revs < 4.6 + */ +static int +cb_prom_stop_self(void) +{ + cell_t ci[3]; + + ci[0] = p1275_ptr2cell("SUNW,stop-self"); /* Service name */ + ci[1] = (cell_t)0; /* #argument cells */ + ci[2] = (cell_t)0; /* #result cells */ + (void) p1275_cif_handler(&ci); /* Do NOT lock */ + return (0); +} + + +/* + * install locked tlb entries and spin or park in a prom idle-loop + */ +void +slave_init(int cpu_id) +{ + restore_tlb(mdinfo.dtte, cpu_id); + restore_tlb(mdinfo.itte, cpu_id); + CPUSET_ADD(slave_set, cpu_id); + membar_stld(); + if (has_scbc) { + /* just spin, master will park this cpu */ + /* CONSTCOND */ + while (1); + } else { + (void) cb_prom_stop_self(); + cb_park_err(cpu_id); + } +} + + +/* + * when any cpu is started, they naturally rely on the prom for all + * text/data translations until switching to the kernel trap table. + * to jump back into the cpr module and to restart slave cpus, cprboot + * needs to reinstall translations for the nucleus and some cpr pages. + * + * the easy method is creating one set of global translations available + * to all cpus with prom_map(); unfortunately, a 4MB "map" request will + * allocate and overwrite a few pages, and these are often kernel pages + * that were just restored. + * + * to solve the "map" problem, all cpus install their own set of locked + * tlb entries to translate the nucleus and parts of the cpr module; + * after all cpus have switched to kernel traps, any of these locked + * tlb entries for pages outside the nucleus will be cleared. + */ +int +cb_mpsetup(void) +{ + struct sun4u_cpu_info *scip, *tail; + int timeout, ncpu; + char *str, *intf; + + intf = "SUNW,stop-cpu-by-cpuid"; + has_scbc = (prom_test(intf) == 0); + CB_VPRINTF(("\n\"%s\" test %d\n", intf, has_scbc)); + + str = "cb_mp_setup"; + CB_VPRINTF((ent_fmt, str, entry)); + + /* + * launch any slave cpus from the .sci array into cprboot text + * and wait about a second for them to checkin with slave_set + */ + ncpu = 0; + CPUSET_ZERO(slave_set); + for (scip = mdinfo.sci, tail = scip + NCPU; scip < tail; scip++) { + if (scip->node == 0 || scip->cpu_id == cb_mid) + continue; + (void) prom_startcpu(scip->node, + (caddr_t)cpu_launch, scip->cpu_id); + + for (timeout = TIMEOUT_MSECS; timeout; timeout--) { + if (CPU_IN_SET(slave_set, scip->cpu_id)) + break; + cb_usec_wait(MILLISEC); + } + + if (timeout == 0) { + prom_printf("\n%s: cpu did not start, " + "cpu_id %d, node 0x%x\n", + prog, scip->cpu_id, scip->node); + return (ERR); + } + + if (has_scbc && prom_stopcpu_bycpuid(scip->cpu_id)) + cb_park_err(scip->cpu_id); + + ncpu++; + } + + if (verbose && ncpu) + prom_printf("\n%s: slave cpu count: %d\n", str, ncpu); + + return (0); +} diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/mapfile b/usr/src/psm/stand/cpr/sparcv9/sun4u/mapfile new file mode 100644 index 0000000000..51e01a8c7e --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/mapfile @@ -0,0 +1,35 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#pragma ident "%Z%%M% %I% %E% SMI" + +text = LOAD ?RX V0x100000; +text : $PROGBITS ?A!W; + +data = LOAD ?RWX A0x8; +data : $PROGBITS ?AW; +data : $NOBITS ?AW; + +note = NOTE; +note : $NOTE; diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/pages.c b/usr/src/psm/stand/cpr/sparcv9/sun4u/pages.c new file mode 100644 index 0000000000..7b163a7aca --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/pages.c @@ -0,0 +1,364 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpr.h> +#include <sys/ddi.h> +#include "cprboot.h" + + +/* + * check if any cpd_t pages clash with the statefile buffer and shuffle + * buf pages to free space; since kpages are saved in ascending order, + * any buf pages preceding the current statefile buffer offset can be + * written because those pages have already been read and restored + */ +static void +shuffle_pages(cpd_t *descp) +{ + pfn_t low_src_ppn, dst_ppn, tail_ppn, new_ppn; + size_t dst_off; + + /* + * set the lowest source buf ppn for the (precede) comparison + * below; the ORIG macro is used for the case where the src buf + * page had already been moved - and would confuse the compare + */ + low_src_ppn = SF_ORIG_PPN(sfile.buf_offset); + + tail_ppn = descp->cpd_pfn + descp->cpd_pages; + for (dst_ppn = descp->cpd_pfn; dst_ppn < tail_ppn; dst_ppn++) { + /* + * if the dst page is outside the range of statefile + * buffer phys pages, it's OK to write that page; + * buf pages may have been moved outside the range, + * but only to locations isolated from any dst page + */ + if (dst_ppn < sfile.low_ppn || dst_ppn > sfile.high_ppn) { + SF_STAT_INC(outside); + continue; + } + + /* + * the dst page is inside the range of buf ppns; + * dont need to move the buf page if the dst page + * precedes the lowest src buf page + */ + if (dst_ppn < low_src_ppn) { + SF_STAT_INC(precede); + continue; + } + + /* + * the dst page clashes with the statefile buffer; + * move the buf page to a free location and update + * the buffer map + */ + new_ppn = find_apage(); + phys_xcopy(PN_TO_ADDR(dst_ppn), PN_TO_ADDR(new_ppn), + MMU_PAGESIZE); + dst_off = mmu_ptob(dst_ppn - sfile.low_ppn); + SF_BUF_PPN(dst_off) = new_ppn; + SF_STAT_INC(move); + } +} + + +/* + * map-in source statefile buffer pages (read-only) at CB_SRC_VIRT; + * sets the starting source vaddr with correct page offset + */ +static void +mapin_buf_pages(size_t datalen, caddr_t *srcp) +{ + int dtlb_index, pg_off; + caddr_t vaddr, tail; + size_t off, bytes; + pfn_t src_ppn; + + dtlb_index = cb_dents - CB_MAX_KPAGES - 1; + off = sfile.buf_offset; + pg_off = off & MMU_PAGEOFFSET; + bytes = PAGE_ROUNDUP(pg_off + datalen); + vaddr = (caddr_t)CB_SRC_VIRT; + *srcp = vaddr + pg_off; + + for (tail = vaddr + bytes; vaddr < tail; vaddr += MMU_PAGESIZE) { + src_ppn = SF_BUF_PPN(off); + cb_mapin(vaddr, src_ppn, TTE8K, 0, dtlb_index); + dtlb_index--; + off += MMU_PAGESIZE; + } +} + + +/* + * map-in destination kernel pages (read/write) at CB_DST_VIRT + */ +static void +mapin_dst_pages(cpd_t *descp) +{ + int dtlb_index, pages; + caddr_t vaddr; + pfn_t dst_ppn; + + dtlb_index = cb_dents - 1; + vaddr = (caddr_t)CB_DST_VIRT; + dst_ppn = descp->cpd_pfn; + for (pages = 0; pages < descp->cpd_pages; pages++) { + cb_mapin(vaddr, dst_ppn, TTE8K, TTE_HWWR_INT, dtlb_index); + dtlb_index--; + vaddr += MMU_PAGESIZE; + dst_ppn++; + } +} + + +/* + * run a checksum on un/compressed data when flag is set + */ +static int +kdata_cksum(void *data, cpd_t *descp, uint_t flag) +{ + uint_t sum, expect; + size_t len; + + if ((descp->cpd_flag & flag) == 0) + return (0); + else if (flag == CPD_CSUM) { + expect = descp->cpd_csum; + len = descp->cpd_length; + } else { + expect = descp->cpd_usum; + len = mmu_ptob(descp->cpd_pages); + } + sum = checksum32(data, len); + if (sum != expect) { + prom_printf("\n%scompressed data checksum error, " + "expect 0x%x, got 0x%x\n", (flag == CPD_USUM) ? "un" : "", + expect, sum); + return (ERR); + } + + return (0); +} + + +/* + * primary kpage restoration routine + */ +static int +restore_page_group(cpd_t *descp) +{ + caddr_t dst, datap; + size_t size, len; + caddr_t src; + int raw; + +#if defined(lint) + (void) compress(0, 0, 0); +#endif + + /* + * move any source buf pages that clash with dst kernel pages; + * create tlb entries for the orig/new source buf pages and + * the dst kpages + */ + shuffle_pages(descp); + mapin_buf_pages(descp->cpd_length, &src); + mapin_dst_pages(descp); + + /* + * for compressed pages, run a checksum at the src vaddr and + * decompress to the mapped-in dst kpages; for uncompressed pages, + * just copy direct; uncompressed checksums are used for either + * uncompressed src data or decompressed result data + */ + dst = (caddr_t)CB_DST_VIRT; + if (descp->cpd_flag & CPD_COMPRESS) { + if (kdata_cksum(src, descp, CPD_CSUM)) + return (ERR); + size = mmu_ptob(descp->cpd_pages); + len = decompress(src, dst, descp->cpd_length, size); + if (len != size) { + prom_printf("\nbad decompressed len %d, size %d\n", + len, size); + return (ERR); + } + raw = 0; + datap = dst; + } else { + raw = 1; + datap = src; + } + if (kdata_cksum(datap, descp, CPD_USUM)) + return (ERR); + if (raw) + bcopy(src, dst, descp->cpd_length); + + /* + * advance past the kdata for this cpd_t + */ + SF_ADV(descp->cpd_length); + + return (0); +} + + +/* + * mapin part of the statefile buffer, copy to the virt destination, + * and advance the statefile buffer offset. this is used primarily + * to copy thousands of tiny cpd_t into aligned struct space. + */ +static void +get_phys_data(void *vdst, size_t size) +{ + caddr_t src; + + mapin_buf_pages(size, &src); + bcopy(src, vdst, size); + SF_ADV(size); +} + + +/* + * clear leftover locked dtlb entries + */ +static void +dtlb_cleanup(void) +{ + int dtlb_index; + caddr_t vaddr; + tte_t tte; + + CB_VENTRY(dtlb_cleanup); + + dtlb_index = cb_dents - CB_MAX_KPAGES - CB_MAX_BPAGES - 1; + for (; dtlb_index < cb_dents; dtlb_index++) { + get_dtlb_entry(dtlb_index, &vaddr, &tte); + if (TTE_IS_LOCKED(&tte)) { + tte.ll = 0; + set_dtlb_entry(dtlb_index, (caddr_t)0, &tte); + CB_VPRINTF((" cleared dtlb entry %x\n", dtlb_index)); + } + } +} + + +/* + * before calling this routine, all cprboot phys pages + * are isolated from kernel pages; now we can restore + * kpages from the statefile buffer + */ +int +cb_restore_kpages(void) +{ + int npages, compressed, regular; + cpd_t desc; + char *str; + + str = "cb_restore_kpages"; + CB_VPRINTF((ent_fmt, str, entry)); + + DEBUG1(prom_printf("%s: restoring kpages... ", prog)); + npages = compressed = regular = 0; + while (npages < sfile.kpages) { + get_phys_data(&desc, sizeof (desc)); + if (desc.cpd_magic != CPR_PAGE_MAGIC) { + prom_printf("\nbad page magic 0x%x, expect 0x%x\n", + desc.cpd_magic, CPR_PAGE_MAGIC); + return (ERR); + } + if (restore_page_group(&desc)) + return (ERR); + npages += desc.cpd_pages; + + if (desc.cpd_flag & CPD_COMPRESS) + compressed += desc.cpd_pages; + else + regular += desc.cpd_pages; + + /* + * display a spin char for every 32 page groups + * (a full spin <= each MB restored) + */ + if ((sfile.ngroups++ & 0x1f) == 0) + cb_spin(); + } + DEBUG1(prom_printf(" \b\n")); + + dtlb_cleanup(); + + if (verbose) { + prom_printf("\npage stats: total %d, outside %d, " + "move %d, precede %d\n", sfile.kpages, sfile.outside, + sfile.move, sfile.precede); + prom_printf("page stats: ngroups %d, recycle %d\n", + sfile.ngroups, sfile.recycle); + } + + DEBUG4(prom_printf( + "%s: total=%d, npages=%d, compressed=%d, regular=%d\n", + str, sfile.kpages, npages, compressed, regular)); + + /* + * sanity check + */ + if (npages != sfile.kpages) { + prom_printf("\n%s: page count mismatch, expect %d, got %d\n", + str, sfile.kpages, npages); + return (ERR); + } + + return (0); +} + + +/* + * check and update the statefile terminator; + * on exit there will be a leftover tlb entry, + * but it will soon get replaced by restore_tlb() + */ +int +cb_terminator(void) +{ + ctrm_t cterm; + + CB_VENTRY(cb_terminator); + get_phys_data(&cterm, sizeof (cterm)); + if (cterm.magic != CPR_TERM_MAGIC) { + prom_printf("\nbad term magic 0x%x, expect 0x%x\n", + cterm.magic, CPR_TERM_MAGIC); + return (ERR); + } + cterm.tm_cprboot_start.tv_sec = cb_msec / 1000; + cb_mapin((caddr_t)CB_DST_VIRT, cterm.pfn, + TTE8K, TTE_HWWR_INT, cb_dents - 1); + cpr_update_terminator(&cterm, (caddr_t)CB_DST_VIRT); + return (0); +} diff --git a/usr/src/psm/stand/cpr/sparcv9/sun4u/util.c b/usr/src/psm/stand/cpr/sparcv9/sun4u/util.c new file mode 100644 index 0000000000..e2e6667929 --- /dev/null +++ b/usr/src/psm/stand/cpr/sparcv9/sun4u/util.c @@ -0,0 +1,495 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/cpr.h> +#include <sys/promimpl.h> +#include "cprboot.h" + + +static int reset_input = 0; +static char kbd_input[] = "keyboard input"; +static char null_input[] = "\" /nulldev\" input"; + + +/* + * Ask prom to open a disk file given either the OBP device path, or the + * device path representing the target drive/partition and the fs-relative + * path of the file. Handle file pathnames with or without leading '/'. + * if fs points to a null char, it indicates that we are opening a device. + */ +/* ARGSUSED */ +int +cpr_statefile_open(char *path, char *fs) +{ + char full_path[OBP_MAXPATHLEN]; + char *fp; + int handle; + int c; + + /* + * instead of using specialstate, we use fs as the flag + */ + if (*fs == '\0') { /* device open */ + handle = prom_open(path); + /* IEEE1275 prom_open returns 0 on failure; we return -1 */ + return (handle ? handle : -1); + } + + /* + * IEEE 1275 prom needs "device-path,|file-path" where + * file-path can have embedded |'s. + */ + fp = full_path; + (void) prom_strcpy(fp, fs); + fp += prom_strlen(fp); + *fp++ = ','; + *fp++ = '|'; + + /* Skip a leading slash in file path -- we provided for it above. */ + if (*path == '/') + path++; + + /* Copy file path and convert separators. */ + while ((c = *path++) != '\0') + if (c == '/') + *fp++ = '|'; + else + *fp++ = c; + *fp = '\0'; + + handle = prom_open(full_path); + if (verbose) { + if (fp = prom_strrchr(full_path, '/')) + fp++; + else + fp = full_path; + prom_printf("cso: prom_open(\"%s\") = 0x%x\n", fp, handle); + } + + /* + * IEEE1275 prom_open returns 0 on failure; we return -1 + */ + return (handle ? handle : -1); +} + + +/* + * Ask prom to open a disk file given the device path representing + * the target drive/partition and the fs-relative path of the file. + * Handle file pathnames with or without leading '/'. if fs points + * to a null char, it indicates that we are opening a device. + */ +/* ARGSUSED */ +int +cpr_ufs_open(char *path, char *fs) +{ + CB_VENTRY(cpr_ufs_open); + + /* + * screen invalid state, then just use the other code rather than + * duplicating it + */ + if (*fs == '\0') { /* device open */ + prom_printf("cpr_ufs_open: NULL fs, path %s\n", path); + return (ERR); + } + return (cpr_statefile_open(path, fs)); +} + + +/* + * On sun4u there's no difference here, since prom groks ufs directly + */ +int +cpr_read(int fd, caddr_t buf, size_t len) +{ + return (prom_read(fd, buf, len, 0, 0)); +} + + +int +cpr_ufs_read(int fd, caddr_t buf, int len) +{ + return (prom_read(fd, buf, len, 0, 0)); +} + + +int +cpr_ufs_close(int fd) +{ + CB_VPRINTF(("cpr_ufs_close 0x%x\n", fd)); + return (prom_close(fd)); +} + + +int +cpr_statefile_close(int fd) +{ + return (prom_close(fd)); +} + + +void +cb_spin(void) +{ + static int spindex = 0; + static char *spin_pairs[] = { "|\b", "/\b", "-\b", "\\\b" }; + const size_t nspin_pairs = sizeof (spin_pairs) / sizeof (spin_pairs[0]); + + prom_printf(spin_pairs[spindex]); + spindex = (spindex + 1) % nspin_pairs; +} + + +/* + * translate vaddr to phys page number + */ +pfn_t +cpr_vatopfn(caddr_t vaddr) +{ + physaddr_t paddr; + int valid, mode; + + (void) prom_translate_virt(vaddr, &valid, &paddr, &mode); + if (valid != -1) + return (PFN_INVALID); + return (paddr >> MMU_PAGESHIFT); +} + + +/* + * unmap virt, then map virt to new phys; + * see remap definition below + */ +int +prom_remap(size_t size, caddr_t virt, physaddr_t phys) +{ + ihandle_t immu; + cell_t ci[8]; + int rv; + + immu = prom_mmu_ihandle(); + if (immu == (ihandle_t)-1) + return (ERR); + + ci[0] = p1275_ptr2cell("call-method"); /* Service name */ + ci[1] = (cell_t)5; /* #argument cells */ + ci[2] = (cell_t)0; /* #result cells */ + ci[3] = p1275_ptr2cell("remap"); /* Arg1: Method name */ + ci[4] = p1275_ihandle2cell(immu); /* Arg2: memory ihandle */ + ci[5] = p1275_size2cell(size); /* remap arg0 */ + ci[6] = p1275_ptr2cell(virt); /* remap arg1 */ + ci[7] = p1275_ull2cell_low(phys); /* remap arg2 */ + + promif_preprom(); + rv = p1275_cif_handler(ci); + promif_postprom(); + + if (rv) + return (rv); /* Service "call-method" failed */ + return (0); +} + + +/* + * install remap definition in /virtual-memory node; + * used for replacing a virt->phys mapping in one promif call; + * this needs to be atomic from the client's perspective to + * avoid faults while relocating client text. + */ +void +install_remap(void) +{ + static char remap_def[] = + "\" /virtual-memory\" find-device " + ": remap ( phys.lo virt size -- )" + " 2dup unmap ( phys.lo virt size )" + " 0 -rot -1 map ( ) ; " + "device-end"; + + prom_interpret(remap_def, 0, 0, 0, 0, 0); +} + + +/* + * allocate virt and phys space without any mapping; + * stores virt and phys addrs at *vap and *pap + */ +int +cb_alloc(size_t size, uint_t align, caddr_t *vap, physaddr_t *pap) +{ + physaddr_t phys; + caddr_t virt; + + virt = prom_allocate_virt(align, (size_t)align); + if (virt == (caddr_t)-1) + return (ERR); + if (prom_allocate_phys(size, align, &phys) == -1) { + prom_free_virt(size, virt); + return (ERR); + } + + *vap = virt; + *pap = phys; + return (0); +} + + +static int +get_intprop(dnode_t node, caddr_t prop, void *dst) +{ + int len, glen; + + len = sizeof (uint_t); + glen = prom_getprop(node, prop, dst); + if (glen != len) + return (ERR); + + return (0); +} + + +/* + * find cpu node for the boot processor + * + * sets globals: + * cb_mid + */ +static dnode_t +get_cpu_node(void) +{ + static char *props[] = { "upa-portid", "portid", NULL }; + dnode_t node; + char *str, *name, **propp; + uint_t cpu_id; + int err; + + str = "get_cpu_node"; + name = "cpu"; + + cb_mid = getmid(); + for (node = prom_rootnode(); ; node = prom_nextnode(node)) { + node = prom_findnode_bydevtype(node, name); + if (node == OBP_NONODE) { + prom_printf("\n%s: cant find node for devtype \"%s\"\n", + str, name); + break; + } + + cpu_id = (uint_t)-1; + for (propp = props; *propp; propp++) { + err = get_intprop(node, *propp, &cpu_id); + CB_VPRINTF((" cpu node 0x%x, " + "prop \"%s\", cpu_id %d\n", + node, *propp, (int)cpu_id)); + if (err == 0) + break; + } + + if (cpu_id == cb_mid) + return (node); + } + + return (OBP_NONODE); +} + + +/* + * lookup prom properties + * + * sets globals: + * cb_dents + * cb_clock_freq + * cpu_delay + */ +int +cb_get_props(void) +{ + uint_t clock_mhz; + dnode_t node; + struct cb_props *cbp; + static struct cb_props cpu_data[] = { + "#dtlb-entries", &cb_dents, + "clock-frequency", &cb_clock_freq, + NULL, NULL, + }; + + CB_VENTRY(cb_get_props); + + node = get_cpu_node(); + if (node == OBP_NONODE) + return (ERR); + for (cbp = cpu_data; cbp->prop; cbp++) { + if (get_intprop(node, cbp->prop, cbp->datap)) { + prom_printf("\n%s: getprop error, " + "node 0x%x, prop \"%s\"\n", + prog, node, cbp->prop); + return (ERR); + } + CB_VPRINTF((" \"%s\" = 0x%x\n", + cbp->prop, *cbp->datap)); + } + + /* + * setup cpu_delay for cb_usec_wait + */ + clock_mhz = (cb_clock_freq + 500000) / 1000000; + cpu_delay = clock_mhz - 7; + CB_VPRINTF((" clock_mhz %d, cpu_delay %d\n", + clock_mhz, cpu_delay)); + + return (0); +} + + +/* + * map-in data pages + * size should fit tte_bit.sz + * rw should be 0 or TTE_HWWR_INT + */ +void +cb_mapin(caddr_t vaddr, pfn_t ppn, uint_t size, uint_t rw, uint_t dtlb_index) +{ + tte_t tte; + + tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(size) | + TTE_PFN_INTHI(ppn); + tte.tte_intlo = TTE_PFN_INTLO(ppn) | TTE_LCK_INT | + TTE_CP_INT | TTE_CV_INT | TTE_PRIV_INT | rw; + set_dtlb_entry(dtlb_index, vaddr, &tte); +} + + +static char * +prom_strstr(char *string, char *substr) +{ + char *strp, *subp, *tmp, c; + + if (substr == NULL || *substr == '\0') + return (string); + + strp = string; + subp = substr; + c = *subp; + + while (*strp) { + if (*strp++ == c) { + tmp = strp; + while ((c = *++subp) == *strp++ && c) + ; + if (c == '\0') + return (tmp - 1); + strp = tmp; + subp = substr; + c = *subp; + } + } + + return (NULL); +} + + +static void +cb_set_idev(char *istr) +{ + if (reset_input) { + prom_interpret(istr, 0, 0, 0, 0, 0); + CB_VPRINTF(("\ncb_set_idev: reset with [%s]\n", istr)); + } +} + + +/* + * workaround for USB keyboard: + * USB DMA activity has been known to corrupt kernel pages while cprboot + * is restoring them. to quiesce the USB chip, we craft a "null" device + * and temporarily use that as the prom's input device. this effectively + * disables the USB keyboard until the cpr module restores the original + * prom and a kernel driver re-inits and takes-over control of USB. + * + * may set globals: + * reset_input + */ +int +cb_usb_setup(void) +{ + char sp[OBP_MAXPATHLEN]; + static char cb_nulldev[] = { + "\" /\" select-dev " + "new-device " + "\" nulldev\" device-name " + ": read 2drop -2 ; " + ": open true ; " + ": close ; " + ": install-abort ; " + ": remove-abort ; " + ": write 2drop 0 ; " + ": restore ; " + "finish-device " + "unselect-dev" + }; + + CB_VENTRY(cb_usb_setup); + + bzero(sp, sizeof (sp)); + prom_interpret("stdin @ ihandle>devname swap -rot move", + (uintptr_t)sp, 0, 0, 0, 0); + if (prom_strstr(sp, "usb") && prom_strstr(sp, "keyboard")) { + prom_interpret(cb_nulldev, 0, 0, 0, 0, 0); + reset_input = 1; + cb_set_idev(null_input); + } + + return (0); +} + + +/* + * switch input to keyboard before entering the prom, and switch to the + * crafted nulldev after returning from the prom. this occurs only when + * stdinpath is a USB keyboard; entering the prom is usually done only + * for debugging purposes - see check_halt() and above DMA comment. + */ +void +cb_enter_mon(void) +{ + cb_set_idev(kbd_input); + prom_enter_mon(); + cb_set_idev(null_input); +} + + +/* + * similar to above before exiting to the prom + */ +void +cb_exit_to_mon(void) +{ + cb_set_idev(kbd_input); + prom_exit_to_mon(); +} diff --git a/usr/src/psm/stand/lib/Makefile b/usr/src/psm/stand/lib/Makefile new file mode 100644 index 0000000000..eab3a61f2f --- /dev/null +++ b/usr/src/psm/stand/lib/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994 by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/Makefile + +include ../../../Makefile.master + +SUBDIRS = boot names promif + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/Makefile.lib b/usr/src/psm/stand/lib/Makefile.lib new file mode 100644 index 0000000000..3c55bdbc2d --- /dev/null +++ b/usr/src/psm/stand/lib/Makefile.lib @@ -0,0 +1,88 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1994, 2003 Sun Microsystems, Inc. +# All rights reserved. +# Use is subject to license terms. +# +# psm/stand/lib/Makefile.lib + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/Makefile.psm + +STANDDIR = $(TOPDIR)/stand +PSMSTANDDIR = $(TOPDIR)/psm/stand + +SYSHDRDIR = $(STANDDIR) +SYSLIBDIR = $(STANDDIR)/lib/$(MACH) + +PSMSYSHDRDIR = $(PSMSTANDDIR) +PSMBOOTLIBDIR = $(PSMSTANDDIR)/lib/boot/$(MACH) +PSMNAMELIBDIR = $(PSMSTANDDIR)/lib/names/$(MACH) +PSMPROMLIBDIR = $(PSMSTANDDIR)/lib/promif/$(MACH) + +# +# Lint rules (adapted from Makefile.uts) +# +LHEAD = ( $(ECHO) "\n$@"; +LGREP = grep -v "pointer cast may result in improper alignment" +LTAIL = ) 2>&1 | $(LGREP) +LINT_DEFS += -Dlint + +# +# For building lint objects +# +LINTFLAGS.c = -nsxum +LINTFLAGS.c += $(ALWAYS_LINT_DEFS) +LINTFLAGS64.c = -nsxum +LINTFLAGS64.c += $(ALWAYS_LINT_DEFS) +LINT64.c = $(LINT) $(LINTFLAGS64.c) $(LINT_DEFS) $(CPPFLAGS) -c +LINT.c = $(LINT) $(LINTFLAGS.c) $(LINT_DEFS) $(CPPFLAGS) -c +LINT.s = $(LINT) $(LINTFLAGS.s) $(LINT_DEFS) $(CPPFLAGS) -c + +# +# For building lint libraries +# +LINTFLAGS.lib = -nsxumy +LINTFLAGS.lib += $(ALWAYS_LINT_DEFS) +LINT.lib = $(LINT) $(LINTFLAGS.lib) $(LINT_DEFS) $(CPPFLAGS) + +# +# For complete pass 2 cross-checks +# +LINTFLAGS.2 = -nsxm +LINT.2 = $(LINT) $(LINTFLAGS.2) $(LINT_DEFS) $(CPPFLAGS) + +# +# Simple rule for making objs/%.ln from %.c and %.s +# + +objs/%.ln: %.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +objs/%.ln: %.s + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + diff --git a/usr/src/psm/stand/lib/Makefile.rules b/usr/src/psm/stand/lib/Makefile.rules new file mode 100644 index 0000000000..10a1229837 --- /dev/null +++ b/usr/src/psm/stand/lib/Makefile.rules @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1994, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/Makefile.rules + +# +# Pattern matching rules to compile the source into the OBJSDIR directory +# +$(OBJSDIR)/%.o: $(SRCSDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(SRCSDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +# +# Pattern matching rules to lint the source into the OBJSDIR directory +# +$(OBJSDIR)/%.ln: $(SRCSDIR)/%.c + @($(LHEAD) $(LINT.c) -c $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(SRCSDIR)/%.s + @($(LHEAD) $(LINT.s) -c $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/lib/boot/Makefile b/usr/src/psm/stand/lib/boot/Makefile new file mode 100644 index 0000000000..d9872f907f --- /dev/null +++ b/usr/src/psm/stand/lib/boot/Makefile @@ -0,0 +1,49 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/lib/boot/Makefile + +include ../../../../Makefile.master + +sparcv7_ARCHITECTURES = sparc +sparcv9_ARCHITECTURES = sparcv9 +sparc_ARCHITECTURES = $(sparcv9_ARCHITECTURES) $(sparcv7_ARCHITECTURES) + +SUBDIRS = $($(MACH)_ARCHITECTURES) + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/boot/inc.flg b/usr/src/psm/stand/lib/boot/inc.flg new file mode 100644 index 0000000000..50d7ef0de3 --- /dev/null +++ b/usr/src/psm/stand/lib/boot/inc.flg @@ -0,0 +1,30 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# +# Find all of the header files +# + +echo_file usr/src/uts/sparc/os/bootops.c diff --git a/usr/src/psm/stand/lib/boot/sparc/Makefile b/usr/src/psm/stand/lib/boot/sparc/Makefile new file mode 100644 index 0000000000..554e9730c6 --- /dev/null +++ b/usr/src/psm/stand/lib/boot/sparc/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1997, 2001-2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/lib/boot/sparc/Makefile + +include ../../../../../Makefile.master + +SUBDIRS = sun4u + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/boot/sparc/Makefile.com b/usr/src/psm/stand/lib/boot/sparc/Makefile.com new file mode 100644 index 0000000000..495ca3d0ed --- /dev/null +++ b/usr/src/psm/stand/lib/boot/sparc/Makefile.com @@ -0,0 +1,112 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/lib/boot/sparc/Makefile.com +# +# SPARC architecture Makefile for Standalone Library +# Platform-specific, but shared between platforms. +# Firmware dependent. +# + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/lib/Makefile.lib +include $(TOPDIR)/psm/stand/lib/Makefile.lib + +PSMSYSHDRDIR = $(TOPDIR)/psm/stand + +LIBBOOT = libboot.a +LINTLIBBOOT = llib-lboot.ln + +# ARCHCMNDIR - common code for several machines of a given isa +# OBJSDIR - where the .o's go + +ARCHCMNDIR = $(TOPDIR)/uts/sparc/os +OBJSDIR = objs + +CMNSRCS = bootops.c +BOOTSRCS = $(PLATSRCS) $(CMNSRCS) +BOOTOBJS = $(BOOTSRCS:%.c=%.o) + +OBJS = $(BOOTOBJS:%=$(OBJSDIR)/%) +L_OBJS = $(OBJS:%.o=%.ln) +L_SRCS = $(CMNSRCS:%=$(ARCHCMNDIR)/%) $(PLATSRCS) + +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc +CPPINCS += -I$(SRC)/uts/sparc/$(ARCHVERS) +CPPINCS += -I$(SRC)/uts/$(PLATFORM) +CPPINCS += -I$(ROOT)/usr/include/$(ARCHVERS) +CPPINCS += -I$(ROOT)/usr/platform/$(PLATFORM)/include +CPPINCS += -I$(PSMSYSHDRDIR) +CPPFLAGS = $(CPPINCS) $(CCYFLAG)$(PSMSYSHDRDIR) +CPPFLAGS += -D_KERNEL -D_BOOT +ASFLAGS = -P -D__STDC__ -D_ASM $(CPPINCS) +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(L_OBJS) + +all install: $(LIBBOOT) .WAIT + +lint: $(LINTLIBBOOT) + +clean: + $(RM) $(OBJS) $(L_OBJS) + +clobber: clean + $(RM) $(LIBBOOT) $(LINTLIBBOOT) a.out core + +$(LIBBOOT): $(OBJSDIR) .WAIT $(OBJS) + $(BUILD.AR) $(OBJS) + +$(LINTLIBBOOT): $(OBJSDIR) .WAIT $(L_OBJS) + @$(ECHO) "\nlint library construction:" $@ + @$(LINT.lib) -o boot $(L_SRCS) + +$(OBJSDIR): + -@[ -d $@ ] || mkdir $@ + +# +# build rules using standard library object subdirectory +# +$(OBJSDIR)/%.o: $(ARCHCMNDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(ARCHCMNDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.ln: $(ARCHCMNDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(ARCHCMNDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/lib/boot/sparc/sun4u/Makefile b/usr/src/psm/stand/lib/boot/sparc/sun4u/Makefile new file mode 100644 index 0000000000..51700d7fdc --- /dev/null +++ b/usr/src/psm/stand/lib/boot/sparc/sun4u/Makefile @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1997, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/boot/sparc/sun4u/Makefile +# +# Platform-specific, but shared between platforms. +# + +PLATFORM = sun4u +ARCHVERS = v9 +TOPDIR = ../../../../../.. +PLATSRCS = + +include ../Makefile.com diff --git a/usr/src/psm/stand/lib/boot/sparcv9/Makefile b/usr/src/psm/stand/lib/boot/sparcv9/Makefile new file mode 100644 index 0000000000..f0b2521715 --- /dev/null +++ b/usr/src/psm/stand/lib/boot/sparcv9/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1997 by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/boot/sparcv9/Makefile + +include ../../../../../Makefile.master + +SUBDIRS = sun4u + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/boot/sparcv9/Makefile.com b/usr/src/psm/stand/lib/boot/sparcv9/Makefile.com new file mode 100644 index 0000000000..f160c1405e --- /dev/null +++ b/usr/src/psm/stand/lib/boot/sparcv9/Makefile.com @@ -0,0 +1,112 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/lib/boot/sparcv9/Makefile.com +# +# SPARC architecture Makefile for Standalone Library +# Platform-specific, but shared between platforms. +# Firmware dependent. +# + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/lib/Makefile.lib +include $(TOPDIR)/psm/stand/lib/Makefile.lib + +PSMSYSHDRDIR = $(TOPDIR)/psm/stand + +LIBBOOT = libboot.a +LINTLIBBOOT = llib-lboot.ln + +# ARCHCMNDIR - common code for several machines of a given isa +# OBJSDIR - where the .o's go + +ARCHCMNDIR = $(TOPDIR)/uts/sparc/os +OBJSDIR = objs + +CMNSRCS = bootops.c +BOOTSRCS = $(PLATSRCS) $(CMNSRCS) +BOOTOBJS = $(BOOTSRCS:%.c=%.o) + +OBJS = $(BOOTOBJS:%=$(OBJSDIR)/%) +L_OBJS = $(OBJS:%.o=%.ln) +L_SRCS = $(CMNSRCS:%=$(ARCHCMNDIR)/%) $(PLATSRCS) + +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc +CPPINCS += -I$(SRC)/uts/sparc/$(ARCHVERS) +CPPINCS += -I$(SRC)/uts/$(PLATFORM) +CPPINCS += -I$(ROOT)/usr/include/$(ARCHVERS) +CPPINCS += -I$(ROOT)/usr/platform/$(PLATFORM)/include +CPPINCS += -I$(PSMSYSHDRDIR) +CPPFLAGS = $(CPPINCS) $(CCYFLAG)$(PSMSYSHDRDIR) +CPPFLAGS += -D_KERNEL +ASFLAGS = -P -D__STDC__ -D_ASM $(CPPINCS) +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(L_OBJS) + +all install: $(LIBBOOT) .WAIT + +lint: $(LINTLIBBOOT) + +clean: + $(RM) $(OBJS) $(L_OBJS) + +clobber: clean + $(RM) $(LIBBOOT) $(LINTLIBBOOT) a.out core + +$(LIBBOOT): $(OBJSDIR) .WAIT $(OBJS) + $(BUILD.AR) $(OBJS) + +$(LINTLIBBOOT): $(OBJSDIR) .WAIT $(L_OBJS) + @$(ECHO) "\nlint library construction:" $@ + @$(LINT.lib) -o boot $(L_SRCS) + +$(OBJSDIR): + -@[ -d $@ ] || mkdir $@ + +# +# build rules using standard library object subdirectory +# +$(OBJSDIR)/%.o: $(ARCHCMNDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(ARCHCMNDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.ln: $(ARCHCMNDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(ARCHCMNDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/lib/boot/sparcv9/sun4u/Makefile b/usr/src/psm/stand/lib/boot/sparcv9/sun4u/Makefile new file mode 100644 index 0000000000..b14037da89 --- /dev/null +++ b/usr/src/psm/stand/lib/boot/sparcv9/sun4u/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1997, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/boot/sparcv9/sun4u/Makefile +# +# Platform-specific +# + +PLATFORM = sun4u +ARCHVERS = v9 +TOPDIR = ../../../../../.. +PLATSRCS = + +include ../Makefile.com + +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) diff --git a/usr/src/psm/stand/lib/names/Makefile b/usr/src/psm/stand/lib/names/Makefile new file mode 100644 index 0000000000..0f88fc896e --- /dev/null +++ b/usr/src/psm/stand/lib/names/Makefile @@ -0,0 +1,48 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/lib/names/Makefile + +include ../../../../Makefile.master + +sparcv9_ARCHITECTURES = sparcv9 +sparc_ARCHITECTURES = $(sparcv9_ARCHITECTURES) + +SUBDIRS = $($(MACH)_ARCHITECTURES) + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/names/sparc/common/mfgname.c b/usr/src/psm/stand/lib/names/sparc/common/mfgname.c new file mode 100644 index 0000000000..358c0ac38f --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparc/common/mfgname.c @@ -0,0 +1,59 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/promif.h> + +#include <sys/platnames.h> + +#define MAXNMLEN 80 /* # of chars in an impl-arch name */ + +/* + * Return the manufacturer name for this platform. + * + * This is exported (solely) as the rootnode name property in + * the kernel's devinfo tree via the 'mfg-name' boot property. + * So it's only used by boot, not the boot blocks. + */ +char * +get_mfg_name(void) +{ + dnode_t n; + int len; + + static char mfgname[MAXNMLEN]; + + if ((n = prom_rootnode()) != OBP_NONODE && + (len = prom_getproplen(n, OBP_NAME)) > 0 && len < MAXNMLEN) { + (void) prom_getprop(n, OBP_NAME, mfgname); + mfgname[len] = '\0'; /* broken clones don't terminate name */ + return (mfgname); + } + + return ("Unknown"); +} diff --git a/usr/src/psm/stand/lib/names/sparc/common/uname-i.c b/usr/src/psm/stand/lib/names/sparc/common/uname-i.c new file mode 100644 index 0000000000..42f8a90bd4 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparc/common/uname-i.c @@ -0,0 +1,213 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/idprom.h> +#include <sys/promif.h> +#include <sys/salib.h> + +#include <sys/platnames.h> + +/* + * This source is (and should be ;-) shared between the boot blocks + * and the boot programs. So if you change it, be sure to test them all! + */ + +#define MAXNMLEN 1024 /* # of chars in a property */ + +/* + * Supplied by modpath.c + * + * Making these externs here allows all sparc machines to share + * get_impl_arch_name(). + */ +extern char *default_name; +extern char *default_path; + +enum ia_state_mach { + STATE_NAME, + STATE_COMPAT_INIT, + STATE_COMPAT, + STATE_DEFAULT, + STATE_FINI +}; + +/* + * Return the implementation architecture name (uname -i) for this platform. + * + * Use the named rootnode property to determine the iarch. + */ +static char * +get_impl_arch_name(enum ia_state_mach *state, int use_default) +{ + static char iarch[MAXNMLEN]; + static int len; + static char *ia; + + dnode_t n; + char *cp; + char *namename; + +newstate: + switch (*state) { + case STATE_NAME: + *state = STATE_COMPAT_INIT; + namename = OBP_NAME; + n = (dnode_t)prom_rootnode(); + len = prom_getproplen(n, namename); + if (len <= 0 || len >= MAXNMLEN) + goto newstate; + (void) prom_getprop(n, namename, iarch); + iarch[len] = '\0'; /* fix broken clones */ + ia = iarch; + break; + + case STATE_COMPAT_INIT: + *state = STATE_COMPAT; + namename = OBP_COMPATIBLE; + n = (dnode_t)prom_rootnode(); + len = prom_getproplen(n, namename); + if (len <= 0 || len >= MAXNMLEN) { + *state = STATE_DEFAULT; + goto newstate; + } + (void) prom_getprop(n, namename, iarch); + iarch[len] = '\0'; /* ensure null termination */ + ia = iarch; + break; + + case STATE_COMPAT: + /* + * Advance 'ia' to point to next string in + * compatible property array (if any). + */ + while (*ia++) + ; + if ((ia - iarch) >= len) { + *state = STATE_DEFAULT; + goto newstate; + } + break; + + case STATE_DEFAULT: + *state = STATE_FINI; + if (!use_default || default_name == NULL) + goto newstate; + (void) strcpy(iarch, default_name); + ia = iarch; + break; + + case STATE_FINI: + return (NULL); + } + + /* + * Crush filesystem-awkward characters. See PSARC/1992/170. + * (Convert the property to a sane directory name in UFS) + */ + for (cp = ia; *cp; cp++) + if (*cp == '/' || *cp == ' ' || *cp == '\t') + *cp = '_'; + return (ia); +} + +static void +make_platform_path(char *fullpath, char *iarch, char *filename) +{ + (void) strcpy(fullpath, "/platform/"); + (void) strcat(fullpath, iarch); + if (filename != NULL) { + (void) strcat(fullpath, "/"); + (void) strcat(fullpath, filename); + } +} + +/* + * Generate impl_arch_name by searching the /platform hierarchy + * for a matching directory. We are not looking for any particular + * file here, but for a directory hierarchy for the module path. + */ +int +find_platform_dir(int (*isdirfn)(char *), char *iarch, int use_default) +{ + char fullpath[MAXPATHLEN]; + char *ia; + enum ia_state_mach state = STATE_NAME; + + /* + * Hunt the filesystem looking for a directory hierarchy. + */ + while ((ia = get_impl_arch_name(&state, use_default)) != NULL) { + make_platform_path(fullpath, ia, NULL); + if (((*isdirfn)(fullpath)) != 0) { + (void) strcpy(iarch, ia); + return (1); + } + } + return (0); +} + +/* + * Search the /platform hierarchy looking for a particular file. + * + * impl_arch_name is given as an optional hint as to where the + * file might be found. + */ +int +open_platform_file( + char *filename, + int (*openfn)(char *, void *), + void *arg, + char *fullpath, + char *given_iarch) +{ + char *ia; + int fd; + enum ia_state_mach state = STATE_NAME; + + /* + * First try the impl_arch_name hint. + * + * This is only here to support the -I flag to boot. + */ + if (given_iarch != NULL) { + make_platform_path(fullpath, given_iarch, filename); + return ((*openfn)(fullpath, arg)); + } + + /* + * Hunt the filesystem for one that works .. + */ + while ((ia = get_impl_arch_name(&state, 1)) != NULL) { + make_platform_path(fullpath, ia, filename); + if ((fd = (*openfn)(fullpath, arg)) != -1) + return (fd); + } + + return (-1); +} diff --git a/usr/src/psm/stand/lib/names/sparc/common/uname-m.c b/usr/src/psm/stand/lib/names/sparc/common/uname-m.c new file mode 100644 index 0000000000..780ef78443 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparc/common/uname-m.c @@ -0,0 +1,101 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1994-1995, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/modctl.h> +#include <sys/salib.h> + +#include <sys/platnames.h> + +/* + * Supplied by modpath.c + * + * Making these externs here allows all sparc machines to share + * mod_path_uname_m(). + */ +extern char *default_name; +extern char *default_path; + +/* + * Is path "/platform/"dir"/" ? + */ +static int +platcmp(char *path, char *dir) +{ + static char prefix[] = "/platform/"; + static char suffix[] = "/kernel"; + int len; + + if (strncmp(path, prefix, sizeof (prefix) - 1) != 0) + return (0); + len = strlen(dir); + path += sizeof (prefix) - 1; + if (strncmp(path, dir, len) != 0) + return (0); + path += len; + if (strcmp(path, suffix) != 0) + return (0); + return (1); +} + +/* + * This function provides a hook for enhancing the module_path. + */ +/*ARGSUSED*/ +void +mod_path_uname_m(char *mod_path, char *ia_name) +{ + + if (ia_name == NULL) + return; + + /* + * If we found the kernel in the default dir, prepend the ia_name + * directory (e.g. /platform/SUNW,foo/kernel) to the mod_path unless + * ia_name is the same as the default dir. This can happen if we + * found the kernel via the "compatible" property. + * + * If we found the kernel in the ia_name dir, append the default + * directory to the modpath. + * + * If neither of the above are true, we were given a specific kernel + * to boot, so we leave things well enough alone. + */ + if (platcmp(mod_path, default_name)) { + if (strcmp(ia_name, default_name) != 0) { + char tmp[MOD_MAXPATH]; + + (void) strcpy(tmp, mod_path); + (void) strcpy(mod_path, "/platform/"); + (void) strcat(mod_path, ia_name); + (void) strcat(mod_path, "/kernel "); + (void) strcat(mod_path, tmp); + } + } else if (platcmp(mod_path, ia_name)) + (void) strcat(mod_path, default_path); +} diff --git a/usr/src/psm/stand/lib/names/sparcv9/Makefile b/usr/src/psm/stand/lib/names/sparcv9/Makefile new file mode 100644 index 0000000000..e5f119a296 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparcv9/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/lib/names/sparcv9/Makefile + +include ../../../../../Makefile.master + +SUBDIRS = sun4u sun4v + +all install clean clobber lint: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint +install := TARGET = install + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/names/sparcv9/Makefile.com b/usr/src/psm/stand/lib/names/sparcv9/Makefile.com new file mode 100644 index 0000000000..ca39db2192 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparcv9/Makefile.com @@ -0,0 +1,116 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/lib/names/sparcv9/Makefile.com +# +# SPARCv9 architecture Makefile for Standalone Library +# Platform-specific, but shared between platforms. +# Firmware dependent. +# + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/lib/Makefile.lib +include $(TOPDIR)/psm/stand/lib/Makefile.lib + +PSMSYSHDRDIR = $(TOPDIR)/psm/stand +STANDDIR = $(TOPDIR)/stand + +LIBNAMES = libnames.a +LINTLIBNAMES = llib-lnames.ln + +# ARCHCMNDIR - common code for several machines of a given isa +# OBJSDIR - where the .o's go + +ARCHCMNDIR = ../../sparc/common +OBJSDIR = objs + +CMNSRCS = uname-i.c uname-m.c mfgname.c +NAMESRCS = $(PLATSRCS) $(CMNSRCS) +NAMEOBJS = $(NAMESRCS:%.c=%.o) + +OBJS = $(NAMEOBJS:%=$(OBJSDIR)/%) +L_OBJS = $(OBJS:%.o=%.ln) +L_SRCS = $(CMNSRCS:%=$(ARCHCMNDIR)/%) $(PLATSRCS) + +CPPINCS += -I$(SRC)/uts/common +CPPINCS += -I$(SRC)/uts/sun +CPPINCS += -I$(SRC)/uts/sparc +CPPINCS += -I$(SRC)/uts/sparc/$(ARCHVERS) +CPPINCS += -I$(SRC)/uts/sun4 +CPPINCS += -I$(SRC)/uts/$(PLATFORM) +CPPINCS += -I$(ROOT)/usr/include/$(ARCHVERS) +CPPINCS += -I$(ROOT)/usr/platform/$(PLATFORM)/include +CPPINCS += -I$(PSMSYSHDRDIR) +CPPINCS += -I$(STANDDIR) +CPPINCS += -I$(STANDDIR)/lib/sa +CPPFLAGS = $(CPPINCS) $(CCYFLAG)$(PSMSYSHDRDIR) +CPPFLAGS += -D_KERNEL +ASFLAGS = -P -D__STDC__ -D_ASM $(CPPINCS) +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(L_OBJS) + +all install: $(LIBNAMES) .WAIT + +lint: $(LINTLIBNAMES) + +clean: + $(RM) $(OBJS) $(L_OBJS) + +clobber: clean + $(RM) $(LIBNAMES) $(LINTLIBNAMES) a.out core + +$(LIBNAMES): $(OBJSDIR) .WAIT $(OBJS) + $(BUILD.AR) $(OBJS) + +$(LINTLIBNAMES): $(OBJSDIR) .WAIT $(L_OBJS) + @$(ECHO) "\nlint library construction:" $@ + @$(LINT.lib) -o names $(L_SRCS) + +$(OBJSDIR): + -@[ -d $@ ] || mkdir $@ + +# +# build rules using standard library object subdirectory +# +$(OBJSDIR)/%.o: $(ARCHCMNDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(ARCHCMNDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.ln: $(ARCHCMNDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(ARCHCMNDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/lib/names/sparcv9/sun4u/Makefile b/usr/src/psm/stand/lib/names/sparcv9/sun4u/Makefile new file mode 100644 index 0000000000..288b990d54 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparcv9/sun4u/Makefile @@ -0,0 +1,41 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1997, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/names/sparcv9/sun4u/Makefile +# +# Platform-specific +# + +PLATFORM = sun4u +ARCHVERS = v9 +TOPDIR = ../../../../../.. +PLATSRCS = modpath.c + +include ../Makefile.com +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) diff --git a/usr/src/psm/stand/lib/names/sparcv9/sun4u/modpath.c b/usr/src/psm/stand/lib/names/sparcv9/sun4u/modpath.c new file mode 100644 index 0000000000..5637eba938 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparcv9/sun4u/modpath.c @@ -0,0 +1,34 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Platform specific vars used by uname-i.c + */ + +char *default_name = "sun4u"; +char *default_path = " /platform/sun4u/kernel"; diff --git a/usr/src/psm/stand/lib/names/sparcv9/sun4v/Makefile b/usr/src/psm/stand/lib/names/sparcv9/sun4v/Makefile new file mode 100644 index 0000000000..0b776f972b --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparcv9/sun4v/Makefile @@ -0,0 +1,41 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/lib/names/sparcv9/sun4v/Makefile +# +# Platform-specific +# + +PLATFORM = sun4v +ARCHVERS = v9 +TOPDIR = ../../../../../.. +PLATSRCS = modpath.c + +include ../Makefile.com +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) diff --git a/usr/src/psm/stand/lib/names/sparcv9/sun4v/modpath.c b/usr/src/psm/stand/lib/names/sparcv9/sun4v/modpath.c new file mode 100644 index 0000000000..21f7689804 --- /dev/null +++ b/usr/src/psm/stand/lib/names/sparcv9/sun4v/modpath.c @@ -0,0 +1,34 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Platform specific vars used by uname-i.c + */ + +char *default_name = "sun4v"; +char *default_path = " /platform/sun4v/kernel"; diff --git a/usr/src/psm/stand/lib/promif/Makefile b/usr/src/psm/stand/lib/promif/Makefile new file mode 100644 index 0000000000..1123c4259c --- /dev/null +++ b/usr/src/psm/stand/lib/promif/Makefile @@ -0,0 +1,48 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/lib/promif/Makefile +# + +include ../../../../Makefile.master + +sparc_ARCHITECTURES = sparcv9 + +SUBDIRS = $($(MACH)_ARCHITECTURES) + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +all install clean clobber lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/promif/sparcv9/Makefile b/usr/src/psm/stand/lib/promif/sparcv9/Makefile new file mode 100644 index 0000000000..6fd7361218 --- /dev/null +++ b/usr/src/psm/stand/lib/promif/sparcv9/Makefile @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# +# Copyright (c) 1997, by Sun Microsystems, Inc. +# All rights reserved. +# +# psm/stand/lib/promif/sparcv9/Makefile +# + +include ../../../../../Makefile.master + +SUBDIRS = ieee1275 + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +all install clean clobber lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/Makefile b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/Makefile new file mode 100644 index 0000000000..7817f55bf9 --- /dev/null +++ b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/Makefile @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/boot/sparcv9/ieee1275/Makefile +# + +# shared and platform-specific firmware libraries + +SUBDIRS = common sun4u sun4v + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +all install clean clobber lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(MFLAGS) $(TARGET) + +FRC: diff --git a/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/common/Makefile b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/common/Makefile new file mode 100644 index 0000000000..e24b92b763 --- /dev/null +++ b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/common/Makefile @@ -0,0 +1,146 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# psm/stand/lib/promif/sparcv9/ieee1275/common/Makefile +# + +# usr/src +TOPDIR = ../../../../../../.. + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/lib/Makefile.lib +include $(TOPDIR)/psm/stand/lib/Makefile.lib +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) + +PROMDIR = $(TOPDIR)/psm/promif/ieee1275/common +SYSDIR = $(TOPDIR)/uts + +LIBPROM = libprom.a +LINTLIBPROM = llib-lprom.ln + +PROM_CFILES = \ + prom_2path.c \ + prom_boot.c \ + prom_devname.c \ + prom_devtype.c \ + prom_enter.c \ + prom_env.c \ + prom_exit.c \ + prom_fb.c \ + prom_getchar.c \ + prom_gettime.c \ + prom_handler.c \ + prom_inpath.c \ + prom_interp.c \ + prom_io.c \ + prom_kbd.c \ + prom_key.c \ + prom_node.c \ + prom_outpath.c \ + prom_panic.c \ + prom_path.c \ + prom_phandle.c \ + prom_printf.c \ + prom_prop.c \ + prom_putchar.c \ + prom_reboot.c \ + prom_stdin.c \ + prom_stdout.c \ + prom_string.c \ + prom_test.c \ + prom_trap.c \ + prom_version.c \ + prom_wrtestr.c + +PROM_SFILES = + +PROM_FILES = $(PROM_CFILES) $(PROM_SFILES) + +KARCH = sun4u +MMU = sfmmu + +OBJSDIR = objs + +PROM_COBJ = $(PROM_CFILES:%.c=$(OBJSDIR)/%.o) +PROM_SOBJ = $(PROM_SFILES:%.s=$(OBJSDIR)/%.o) +OBJS = $(PROM_COBJ) $(PROM_SOBJ) +L_OBJS = $(OBJS:%.o=%.ln) +L_SRCS = $(PROM_FILES:%=$(PROMDIR)/%) + +ARCHOPTS = -DSTACK_64BIT -Dsun4u +ASFLAGS = -P -D__STDC__ -D_BOOT -D_ASM +CPPDEFS = $(ARCHOPTS) -D$(KARCH) -D_BOOT -D_KERNEL -D_MACHDEP +CPPINCS = -I. -I$(SYSDIR)/sun4 -I$(SYSDIR)/$(KARCH) -I$(SYSDIR)/$(MMU) \ + -I$(SYSDIR)/sparc/v9 -I$(SYSDIR)/sparc \ + -I$(SYSDIR)/sun -I$(SYSDIR)/common +CPPFLAGS = $(CPPDEFS) $(CPPINCS) $(CPPFLAGS.master) +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(L_OBJS) + +all install: $(LIBPROM) + +lint: $(LINTLIBPROM) + +clean: + $(RM) $(OBJS) $(L_OBJS) + +clobber: clean + $(RM) $(LIBPROM) $(LINTLIBPROM) a.out core + +$(LIBPROM): $(OBJSDIR) .WAIT $(OBJS) + $(BUILD.AR) $(OBJS) + +$(LINTLIBPROM): $(OBJSDIR) .WAIT $(L_OBJS) + @$(ECHO) "\nlint library construction:" $@ + @$(LINT.lib) -o prom $(L_SRCS) + +$(OBJSDIR): + -@[ -d $@ ] || mkdir $@ + +# +# build rules using standard library object subdirectory +# +$(OBJSDIR)/%.o: $(PROMDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PROMDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.ln: $(PROMDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PROMDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/sun4u/Makefile b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/sun4u/Makefile new file mode 100644 index 0000000000..0d47a6ef89 --- /dev/null +++ b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/sun4u/Makefile @@ -0,0 +1,144 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/boot/sparcv9/ieee1275/sun4u/Makefile +# +# +#ident "%Z%%M% %I% %E% SMI" +# +TOPDIR = ../../../../../../.. + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/lib/Makefile.lib +include $(TOPDIR)/psm/stand/lib/Makefile.lib +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) + +PLATDIR = $(TOPDIR)/psm/promif/ieee1275/sun4u +PLATSUN4DIR = $(TOPDIR)/psm/promif/ieee1275/sun4 +SYSDIR = $(TOPDIR)/uts + +LIBPLAT = libplat.a +LINTLIBPLAT = llib-lplat.ln + +PLAT_PFILES = \ + prom_heartbeat.c \ + prom_mmu.c \ + prom_serengeti.c \ + prom_sunfire.c \ + prom_vercheck.c + +PLAT_PSUN4FILES = \ + prom_alloc.c \ + prom_cpuctl.c \ + prom_getunum.c \ + prom_idprom.c \ + prom_init.c \ + prom_macaddr.c \ + prom_map.c \ + prom_mem.c \ + prom_retain.c \ + prom_sparc.c + +KARCH = sun4u +MMU = sfmmu + +OBJSDIR = objs + +PLAT_POBJ = $(PLAT_PFILES:%.c=$(OBJSDIR)/%.o) +PLAT_PSUN4OBJ = $(PLAT_PSUN4FILES:%.c=$(OBJSDIR)/%.o) +OBJS = $(PLAT_POBJ) $(PLAT_PSUN4OBJ) +L_OBJS = $(OBJS:%.o=%.ln) +L_SRCS = $(PLAT_PFILES:%=$(PLATDIR)/%) +L_SRCS += $(PLAT_PSUN4FILES:%=$(PLATSUN4DIR)/%) + +ARCHOPTS= -Dsun4u +ASFLAGS = -P -D__STDC__ -D_BOOT -D_ASM +CPPDEFS = $(ARCHOPTS) -D$(KARCH) -D_BOOT -D_KERNEL -D_MACHDEP +CPPINCS = -I. -I$(SYSDIR)/sun4 -I$(SYSDIR)/$(KARCH) -I$(SYSDIR)/$(MMU) \ + -I$(SYSDIR)/sparc/v9 -I$(SYSDIR)/sparc \ + -I$(SYSDIR)/sun -I$(SYSDIR)/common +CPPFLAGS= $(CPPDEFS) $(CPPINCS) $(CPPFLAGS.master) +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(L_OBJS) + +all install: $(LIBPLAT) + +lint: $(LINTLIBPLAT) + +clean: + $(RM) $(OBJS) $(L_OBJS) + +clobber: clean + $(RM) $(LIBPLAT) $(LINTLIBPLAT) a.out core + +$(LIBPLAT): $(OBJSDIR) .WAIT $(OBJS) + $(BUILD.AR) $(OBJS) + +$(LINTLIBPLAT): $(OBJSDIR) .WAIT $(L_OBJS) + @$(ECHO) "\nlint library construction:" $@ + @$(LINT.lib) -o plat $(L_SRCS) + +$(OBJSDIR): + -@[ -d $@ ] || mkdir $@ + +# +# build rules using standard library object subdirectory +# +$(OBJSDIR)/%.o: $(PLATDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PLATDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PLATSUN4DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PLATSUN4DIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.ln: $(PLATDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PLATDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PLATSUN4DIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PLATSUN4DIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/sun4v/Makefile b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/sun4v/Makefile new file mode 100644 index 0000000000..c02f97839c --- /dev/null +++ b/usr/src/psm/stand/lib/promif/sparcv9/ieee1275/sun4v/Makefile @@ -0,0 +1,143 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# psm/stand/boot/sparcv9/ieee1275/sun4v/Makefile +# +# +#ident "%Z%%M% %I% %E% SMI" +# +TOPDIR = ../../../../../../.. + +include $(TOPDIR)/Makefile.master +include $(TOPDIR)/lib/Makefile.lib +include $(TOPDIR)/psm/stand/lib/Makefile.lib +include $(TOPDIR)/psm/Makefile.psm.64 + +CFLAGS64 += -xchip=ultra $(CCABS32) + +PLATDIR = $(TOPDIR)/psm/promif/ieee1275/sun4u +PLATSUN4DIR = $(TOPDIR)/psm/promif/ieee1275/sun4 +SYSDIR = $(TOPDIR)/uts + +LIBPLAT = libplat.a +LINTLIBPLAT = llib-lplat.ln + +PLAT_PFILES = \ + prom_heartbeat.c \ + prom_mmu.c \ + prom_vercheck.c + +PLAT_PSUN4FILES = \ + prom_alloc.c \ + prom_cpuctl.c \ + prom_getunum.c \ + prom_idprom.c \ + prom_init.c \ + prom_macaddr.c \ + prom_map.c \ + prom_mem.c \ + prom_retain.c \ + prom_sparc.c + +KARCH = sun4v +MMU = sfmmu + +OBJSDIR = objs + +PLAT_POBJ = $(PLAT_PFILES:%.c=$(OBJSDIR)/%.o) +PLAT_PSUN4OBJ = $(PLAT_PSUN4FILES:%.c=$(OBJSDIR)/%.o) +OBJS = $(PLAT_POBJ) $(PLAT_PSUN4OBJ) +L_OBJS = $(OBJS:%.o=%.ln) +L_SRCS = $(PLAT_PFILES:%=$(PLATDIR)/%) +L_SRCS += $(PLAT_PSUN4FILES:%=$(PLATSUN4DIR)/%) + +ARCHOPTS= -Dsun4v +ASFLAGS = -P -D__STDC__ -D_BOOT -D_ASM +CPPDEFS = $(ARCHOPTS) -D$(KARCH) -D_BOOT -D_KERNEL -D_MACHDEP +CPPINCS = -I. -I$(SYSDIR)/sun4 -I$(SYSDIR)/$(KARCH) -I$(SYSDIR)/$(MMU) \ + -I$(SYSDIR)/sun4u \ + -I$(SYSDIR)/sparc/v9 -I$(SYSDIR)/sparc \ + -I$(SYSDIR)/sun -I$(SYSDIR)/common +CPPFLAGS= $(CPPDEFS) $(CPPINCS) $(CPPFLAGS.master) +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(L_OBJS) + +all install: $(LIBPLAT) + +lint: $(LINTLIBPLAT) + +clean: + $(RM) $(OBJS) $(L_OBJS) + +clobber: clean + $(RM) $(LIBPLAT) $(LINTLIBPLAT) a.out core + +$(LIBPLAT): $(OBJSDIR) .WAIT $(OBJS) + $(BUILD.AR) $(OBJS) + +$(LINTLIBPLAT): $(OBJSDIR) .WAIT $(L_OBJS) + @$(ECHO) "\nlint library construction:" $@ + @$(LINT.lib) -o plat $(L_SRCS) + +$(OBJSDIR): + -@[ -d $@ ] || mkdir $@ + +# +# build rules using standard library object subdirectory +# +$(OBJSDIR)/%.o: $(PLATDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PLATDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PLATSUN4DIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.o: $(PLATSUN4DIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +$(OBJSDIR)/%.ln: $(PLATDIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PLATDIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PLATSUN4DIR)/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + @$(MV) $(@F) $@ + +$(OBJSDIR)/%.ln: $(PLATSUN4DIR)/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + @$(MV) $(@F) $@ diff --git a/usr/src/psm/stand/old/bootblks/common/goforth.s b/usr/src/psm/stand/old/bootblks/common/goforth.s new file mode 100644 index 0000000000..5d424a7ebe --- /dev/null +++ b/usr/src/psm/stand/old/bootblks/common/goforth.s @@ -0,0 +1,60 @@ +! +! CDDL HEADER START +! +! The contents of this file are subject to the terms of the +! Common Development and Distribution License, Version 1.0 only +! (the "License"). You may not use this file except in compliance +! with the License. +! +! You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +! or http://www.opensolaris.org/os/licensing. +! See the License for the specific language governing permissions +! and limitations under the License. +! +! When distributing Covered Code, include this CDDL HEADER in each +! file and include the License file at usr/src/OPENSOLARIS.LICENSE. +! If applicable, add the following below this CDDL HEADER, with the +! fields enclosed by brackets "[]" replaced with your own identifying +! information: Portions Copyright [yyyy] [name of copyright owner] +! +! CDDL HEADER END +! +! Copyright 2000 Sun Microsystems, Inc. All rights reserved. +! Use is subject to license terms. +! +! #ident "%Z%%M% %I% %E% SMI" +! + +#include <sys/asm_linkage.h> + +#if defined(lint) +void +goforth(struct sunromvec *romp, caddr_t start, caddr_t end) +{ return; } +#endif + + .text +! +! goforth(struct sunromvec *romp, +! char *start, char *end) +! + ENTRY(goforth) + save %sp, -SA(MINFRAME), %sp + ld [%i0 + 0x7c], %l2 ! Address of romp->v_interpret + set byteload, %i1 + sethi %hi(forthblock), %i2 + or %i2, %lo(forthblock), %i2 +v2: + ! + ! op_interpret(cmd, 1, forthblock); + ! + mov %i1, %o0 + mov %i2, %o2 + + call %l2 + mov 1, %o1 +/*NOTREACHED*/ + +byteload: + .asciz "byte-load" + .align 4 diff --git a/usr/src/psm/stand/old/bootblks/common/process.c b/usr/src/psm/stand/old/bootblks/common/process.c new file mode 100644 index 0000000000..d8e96bc778 --- /dev/null +++ b/usr/src/psm/stand/old/bootblks/common/process.c @@ -0,0 +1,43 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +#ident "%Z%%M% %I% %E% SMI" + +/* + * Copyright (c) 1991 Sun Microsystems, Inc. + * + * Produce a big hunk o' data from an Fcode input file. + * Usage: process <infile.fcode >outfile + */ + +#include <stdio.h> + +main() +{ + int c, count = 0; + + (void) printf("const unsigned char forthblock[] = {\n"); + while ((c = getchar()) != EOF) + (void) printf("0x%02x,%c", c & 0xff, + (count = ++count % 8) ? ' ' : '\n'); + (void) printf("\n};\n"); + return (0); +} diff --git a/usr/src/psm/stand/sys/boot.h b/usr/src/psm/stand/sys/boot.h new file mode 100644 index 0000000000..8138fa0121 --- /dev/null +++ b/usr/src/psm/stand/sys/boot.h @@ -0,0 +1,82 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _BOOT_H +#define _BOOT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Platform-independent declarations for the secondary bootloader + * (in psm/stand/boot). + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include <sys/link.h> + + + +/* + * Common variable declarations. + */ +extern int boothowto; +extern int verbosemode; +extern char *systype; + +extern struct memlist *pfreelistp, *vfreelistp, *pinstalledp; + + + +/* + * Global variables from readfile.c + */ +extern int (*readfile(int fd, int print))(); + +#ifdef _ELF64_SUPPORT +extern Elf32_Boot *elfbootvecELF32_64; /* Bootstrap vector ELF32 LP64 client */ +extern Elf64_Boot *elfbootvecELF64; /* Bootstrap vector for Elf64 LP64 */ +#endif + + + +/* + * Prototypes from heap_kmem.c + */ +extern void kmem_init(void); +extern void *kmem_alloc(size_t, int); +extern void kmem_free(void *, size_t); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _BOOT_H */ diff --git a/usr/src/psm/stand/sys/boot_policy.h b/usr/src/psm/stand/sys/boot_policy.h new file mode 100644 index 0000000000..141cd1f4cb --- /dev/null +++ b/usr/src/psm/stand/sys/boot_policy.h @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SYS_POLICY_H +#define _SYS_POLICY_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * External interfaces + */ +extern void policy_open(void); +extern void policy_close(void); +extern char *policy_lookup(char *pattern, int ignore_case); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_POLICY_H */ diff --git a/usr/src/psm/stand/sys/boot_redirect.h b/usr/src/psm/stand/sys/boot_redirect.h new file mode 100644 index 0000000000..a444049658 --- /dev/null +++ b/usr/src/psm/stand/sys/boot_redirect.h @@ -0,0 +1,45 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1994, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SYS_BOOT_REDIRECT_H +#define _SYS_BOOT_REDIRECT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The name of the redirection file used on the install CD-ROM + */ +#define BOOT_REDIRECT ".SUNW-boot-redirect" + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_BOOT_REDIRECT_H */ diff --git a/usr/src/psm/stand/sys/platnames.h b/usr/src/psm/stand/sys/platnames.h new file mode 100644 index 0000000000..e63b357104 --- /dev/null +++ b/usr/src/psm/stand/sys/platnames.h @@ -0,0 +1,49 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1994-1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SYS_PLATNAMES_H +#define _SYS_PLATNAMES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * External interfaces + */ +extern char *get_mfg_name(void); +extern int find_platform_dir(int (*)(char *), char *, int); +extern int open_platform_file(char *, + int (*)(char *, void *), void *, char *, char *); +extern void mod_path_uname_m(char *, char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PLATNAMES_H */ |
