From 80e2ca8596e3435bc3b76f3c597833ea0a87f85e Mon Sep 17 00:00:00 2001 From: Date: Wed, 21 Apr 2010 07:18:39 -0600 Subject: 6927649 merge common code from solaris10 and sn1 brands 6916737 s10_indir function in s10_brand library invokes incorrect argument --HG-- rename : usr/src/lib/brand/sn1/Makefile => usr/src/lib/brand/shared/Makefile rename : usr/src/lib/brand/sn1/sn1_brand/Makefile => usr/src/lib/brand/shared/brand/Makefile rename : usr/src/lib/brand/sn1/sn1_brand/Makefile.com => usr/src/lib/brand/shared/brand/Makefile.com rename : usr/src/lib/brand/sn1/sn1_brand/amd64/Makefile => usr/src/lib/brand/shared/brand/amd64/Makefile rename : usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_crt.s => usr/src/lib/brand/shared/brand/amd64/crt.s rename : usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_handler.s => usr/src/lib/brand/shared/brand/amd64/handler.s rename : usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_runexe.s => usr/src/lib/brand/shared/brand/amd64/runexe.s rename : usr/src/lib/brand/sn1/sn1_brand/common/sn1_brand.c => usr/src/lib/brand/shared/brand/common/brand_util.c rename : usr/src/lib/brand/sn1/sn1_brand/common/offsets.in => usr/src/lib/brand/shared/brand/common/offsets.in rename : usr/src/lib/brand/sn1/sn1_brand/i386/Makefile => usr/src/lib/brand/shared/brand/i386/Makefile rename : usr/src/lib/brand/sn1/sn1_brand/i386/sn1_crt.s => usr/src/lib/brand/shared/brand/i386/crt.s rename : usr/src/lib/brand/sn1/sn1_brand/i386/sn1_handler.s => usr/src/lib/brand/shared/brand/i386/handler.s rename : usr/src/lib/brand/sn1/sn1_brand/i386/sn1_runexe.s => usr/src/lib/brand/shared/brand/i386/runexe.s rename : usr/src/lib/brand/sn1/sn1_brand/sparc/Makefile => usr/src/lib/brand/shared/brand/sparc/Makefile rename : usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_crt.s => usr/src/lib/brand/shared/brand/sparc/crt.s rename : usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_handler.s => usr/src/lib/brand/shared/brand/sparc/handler.s rename : usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_runexe.s => usr/src/lib/brand/shared/brand/sparc/runexe.s rename : usr/src/lib/brand/sn1/sn1_brand/sparcv9/Makefile => usr/src/lib/brand/shared/brand/sparcv9/Makefile rename : usr/src/lib/brand/sn1/sn1_brand/sys/sn1_misc.h => usr/src/lib/brand/shared/brand/sys/brand_misc.h rename : usr/src/lib/brand/sn1/librtld_db/Makefile.com => usr/src/lib/brand/shared/librtld_db/Makefile.com rename : usr/src/lib/brand/sn1/librtld_db/common/sn1_librtld_db.c => usr/src/lib/brand/shared/librtld_db/common/brand_librtld_db.c rename : usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers => usr/src/lib/brand/shared/librtld_db/common/mapfile-vers rename : usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers.64 => usr/src/lib/brand/shared/librtld_db/common/mapfile-vers.64 rename : usr/src/lib/brand/sn1/Makefile => usr/src/lib/brand/shared/zone/Makefile rename : usr/src/lib/brand/shared/common.ksh => usr/src/lib/brand/shared/zone/common.ksh rename : usr/src/lib/brand/shared/query.ksh => usr/src/lib/brand/shared/zone/query.ksh rename : usr/src/lib/brand/shared/uninstall.ksh => usr/src/lib/brand/shared/zone/uninstall.ksh rename : usr/src/uts/intel/brand/common/brand_asm.h => usr/src/uts/intel/brand/common/brand_solaris.s rename : usr/src/uts/sun4/brand/sn1/sn1_brand_asm.s => usr/src/uts/sun4/brand/common/brand_solaris.s --- usr/src/lib/brand/Makefile | 5 +- usr/src/lib/brand/Makefile.brand | 5 +- usr/src/lib/brand/shared/Makefile | 42 +- usr/src/lib/brand/shared/brand/Makefile | 46 + usr/src/lib/brand/shared/brand/Makefile.com | 73 ++ usr/src/lib/brand/shared/brand/amd64/Makefile | 32 + usr/src/lib/brand/shared/brand/amd64/crt.s | 72 ++ usr/src/lib/brand/shared/brand/amd64/handler.s | 218 ++++ usr/src/lib/brand/shared/brand/amd64/runexe.s | 79 ++ usr/src/lib/brand/shared/brand/common/brand_util.c | 452 ++++++++ usr/src/lib/brand/shared/brand/common/offsets.in | 34 + usr/src/lib/brand/shared/brand/i386/Makefile | 29 + usr/src/lib/brand/shared/brand/i386/crt.s | 76 ++ usr/src/lib/brand/shared/brand/i386/handler.s | 195 ++++ usr/src/lib/brand/shared/brand/i386/runexe.s | 79 ++ usr/src/lib/brand/shared/brand/sparc/Makefile | 31 + usr/src/lib/brand/shared/brand/sparc/crt.s | 79 ++ usr/src/lib/brand/shared/brand/sparc/handler.s | 224 ++++ usr/src/lib/brand/shared/brand/sparc/runexe.s | 81 ++ usr/src/lib/brand/shared/brand/sparcv9/Makefile | 33 + usr/src/lib/brand/shared/brand/sys/brand_misc.h | 232 +++++ usr/src/lib/brand/shared/common.ksh | 1086 -------------------- usr/src/lib/brand/shared/librtld_db/Makefile.com | 76 ++ .../shared/librtld_db/common/brand_librtld_db.c | 297 ++++++ .../brand/shared/librtld_db/common/mapfile-vers | 56 + .../brand/shared/librtld_db/common/mapfile-vers.64 | 42 + usr/src/lib/brand/shared/query.ksh | 47 - usr/src/lib/brand/shared/uninstall.ksh | 721 ------------- usr/src/lib/brand/shared/zone/Makefile | 54 + usr/src/lib/brand/shared/zone/common.ksh | 1085 +++++++++++++++++++ usr/src/lib/brand/shared/zone/query.ksh | 46 + usr/src/lib/brand/shared/zone/uninstall.ksh | 720 +++++++++++++ usr/src/lib/brand/sn1/librtld_db/Makefile.com | 57 +- usr/src/lib/brand/sn1/librtld_db/amd64/Makefile | 7 +- .../lib/brand/sn1/librtld_db/common/mapfile-vers | 57 - .../brand/sn1/librtld_db/common/mapfile-vers.64 | 43 - .../brand/sn1/librtld_db/common/sn1_librtld_db.c | 299 ------ usr/src/lib/brand/sn1/librtld_db/sparcv9/Makefile | 7 +- usr/src/lib/brand/sn1/sn1_brand/Makefile.com | 43 +- usr/src/lib/brand/sn1/sn1_brand/amd64/Makefile | 7 +- usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_crt.s | 73 -- .../lib/brand/sn1/sn1_brand/amd64/sn1_handler.s | 219 ---- usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_runexe.s | 80 -- usr/src/lib/brand/sn1/sn1_brand/common/offsets.in | 35 - usr/src/lib/brand/sn1/sn1_brand/common/sn1_brand.c | 407 +------- usr/src/lib/brand/sn1/sn1_brand/i386/Makefile | 7 +- usr/src/lib/brand/sn1/sn1_brand/i386/sn1_crt.s | 77 -- usr/src/lib/brand/sn1/sn1_brand/i386/sn1_handler.s | 196 ---- usr/src/lib/brand/sn1/sn1_brand/i386/sn1_runexe.s | 80 -- usr/src/lib/brand/sn1/sn1_brand/sparc/Makefile | 7 +- usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_crt.s | 80 -- .../lib/brand/sn1/sn1_brand/sparc/sn1_handler.s | 225 ---- usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_runexe.s | 82 -- usr/src/lib/brand/sn1/sn1_brand/sparcv9/Makefile | 7 +- usr/src/lib/brand/sn1/sn1_brand/sys/sn1_misc.h | 174 ---- .../lib/brand/solaris10/librtld_db/Makefile.com | 57 +- .../lib/brand/solaris10/librtld_db/amd64/Makefile | 7 +- .../brand/solaris10/librtld_db/common/mapfile-vers | 57 - .../solaris10/librtld_db/common/mapfile-vers.64 | 43 - .../librtld_db/common/solaris10_librtld_db.c | 299 ------ .../brand/solaris10/librtld_db/sparcv9/Makefile | 7 +- usr/src/lib/brand/solaris10/s10_brand/Makefile.com | 43 +- .../lib/brand/solaris10/s10_brand/amd64/Makefile | 7 +- .../lib/brand/solaris10/s10_brand/amd64/s10_crt.s | 73 -- .../brand/solaris10/s10_brand/amd64/s10_handler.s | 219 ---- .../brand/solaris10/s10_brand/amd64/s10_runexe.s | 80 -- .../brand/solaris10/s10_brand/common/offsets.in | 35 - .../brand/solaris10/s10_brand/common/s10_brand.c | 510 ++------- .../brand/solaris10/s10_brand/common/s10_deleted.c | 10 +- .../brand/solaris10/s10_brand/common/s10_signal.c | 44 +- .../lib/brand/solaris10/s10_brand/i386/Makefile | 7 +- .../lib/brand/solaris10/s10_brand/i386/s10_crt.s | 77 -- .../brand/solaris10/s10_brand/i386/s10_handler.s | 195 ---- .../brand/solaris10/s10_brand/i386/s10_runexe.s | 80 -- .../lib/brand/solaris10/s10_brand/sparc/Makefile | 7 +- .../lib/brand/solaris10/s10_brand/sparc/s10_crt.s | 80 -- .../brand/solaris10/s10_brand/sparc/s10_handler.s | 225 ---- .../brand/solaris10/s10_brand/sparc/s10_runexe.s | 82 -- .../lib/brand/solaris10/s10_brand/sparcv9/Makefile | 7 +- .../lib/brand/solaris10/s10_brand/sys/s10_misc.h | 164 +-- usr/src/uts/common/brand/sn1/sn1_brand.c | 581 +---------- usr/src/uts/common/brand/sn1/sn1_brand.h | 61 +- usr/src/uts/common/brand/sn1/sn1_offsets.in | 30 - usr/src/uts/common/brand/solaris10/s10_brand.c | 603 +---------- usr/src/uts/common/brand/solaris10/s10_brand.h | 64 +- usr/src/uts/common/brand/solaris10/s10_offsets.in | 30 - usr/src/uts/common/os/brand.c | 676 +++++++++++- usr/src/uts/common/sys/brand.h | 88 +- usr/src/uts/i86pc/ml/offsets.in | 6 +- usr/src/uts/intel/brand/common/brand_asm.h | 61 +- usr/src/uts/intel/brand/common/brand_solaris.s | 195 ++++ usr/src/uts/intel/brand/sn1/sn1_brand_asm.s | 117 +-- usr/src/uts/intel/brand/solaris10/s10_brand_asm.s | 117 +-- usr/src/uts/intel/ia32/ml/modstubs.s | 15 +- usr/src/uts/intel/s10_brand/Makefile | 15 +- usr/src/uts/intel/sn1_brand/Makefile | 15 +- usr/src/uts/sparc/ml/modstubs.s | 15 +- usr/src/uts/sun4/brand/common/brand_solaris.s | 302 ++++++ usr/src/uts/sun4/brand/sn1/sn1_brand_asm.s | 272 +---- usr/src/uts/sun4/brand/solaris10/s10_brand_asm.s | 272 +---- usr/src/uts/sun4/ml/offsets.in | 6 +- usr/src/uts/sun4u/s10_brand/Makefile | 15 +- usr/src/uts/sun4u/sn1_brand/Makefile | 15 +- usr/src/uts/sun4v/s10_brand/Makefile | 15 +- usr/src/uts/sun4v/sn1_brand/Makefile | 15 +- 105 files changed, 6019 insertions(+), 8613 deletions(-) create mode 100644 usr/src/lib/brand/shared/brand/Makefile create mode 100644 usr/src/lib/brand/shared/brand/Makefile.com create mode 100644 usr/src/lib/brand/shared/brand/amd64/Makefile create mode 100644 usr/src/lib/brand/shared/brand/amd64/crt.s create mode 100644 usr/src/lib/brand/shared/brand/amd64/handler.s create mode 100644 usr/src/lib/brand/shared/brand/amd64/runexe.s create mode 100644 usr/src/lib/brand/shared/brand/common/brand_util.c create mode 100644 usr/src/lib/brand/shared/brand/common/offsets.in create mode 100644 usr/src/lib/brand/shared/brand/i386/Makefile create mode 100644 usr/src/lib/brand/shared/brand/i386/crt.s create mode 100644 usr/src/lib/brand/shared/brand/i386/handler.s create mode 100644 usr/src/lib/brand/shared/brand/i386/runexe.s create mode 100644 usr/src/lib/brand/shared/brand/sparc/Makefile create mode 100644 usr/src/lib/brand/shared/brand/sparc/crt.s create mode 100644 usr/src/lib/brand/shared/brand/sparc/handler.s create mode 100644 usr/src/lib/brand/shared/brand/sparc/runexe.s create mode 100644 usr/src/lib/brand/shared/brand/sparcv9/Makefile create mode 100644 usr/src/lib/brand/shared/brand/sys/brand_misc.h delete mode 100644 usr/src/lib/brand/shared/common.ksh create mode 100644 usr/src/lib/brand/shared/librtld_db/Makefile.com create mode 100644 usr/src/lib/brand/shared/librtld_db/common/brand_librtld_db.c create mode 100644 usr/src/lib/brand/shared/librtld_db/common/mapfile-vers create mode 100644 usr/src/lib/brand/shared/librtld_db/common/mapfile-vers.64 delete mode 100644 usr/src/lib/brand/shared/query.ksh delete mode 100644 usr/src/lib/brand/shared/uninstall.ksh create mode 100644 usr/src/lib/brand/shared/zone/Makefile create mode 100644 usr/src/lib/brand/shared/zone/common.ksh create mode 100644 usr/src/lib/brand/shared/zone/query.ksh create mode 100644 usr/src/lib/brand/shared/zone/uninstall.ksh delete mode 100644 usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers delete mode 100644 usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers.64 delete mode 100644 usr/src/lib/brand/sn1/librtld_db/common/sn1_librtld_db.c delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_crt.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_handler.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_runexe.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/common/offsets.in delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/i386/sn1_crt.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/i386/sn1_handler.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/i386/sn1_runexe.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_crt.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_handler.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_runexe.s delete mode 100644 usr/src/lib/brand/sn1/sn1_brand/sys/sn1_misc.h delete mode 100644 usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers delete mode 100644 usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers.64 delete mode 100644 usr/src/lib/brand/solaris10/librtld_db/common/solaris10_librtld_db.c delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/amd64/s10_crt.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/amd64/s10_handler.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/amd64/s10_runexe.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/common/offsets.in delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/i386/s10_crt.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/i386/s10_handler.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/i386/s10_runexe.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/sparc/s10_crt.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/sparc/s10_handler.s delete mode 100644 usr/src/lib/brand/solaris10/s10_brand/sparc/s10_runexe.s delete mode 100644 usr/src/uts/common/brand/sn1/sn1_offsets.in delete mode 100644 usr/src/uts/common/brand/solaris10/s10_offsets.in create mode 100644 usr/src/uts/intel/brand/common/brand_solaris.s create mode 100644 usr/src/uts/sun4/brand/common/brand_solaris.s diff --git a/usr/src/lib/brand/Makefile b/usr/src/lib/brand/Makefile index bf01723084..cd19a0bf2c 100644 --- a/usr/src/lib/brand/Makefile +++ b/usr/src/lib/brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # lib/brand/Makefile # @@ -34,7 +33,7 @@ include ../../Makefile.master i386_SUBDIRS= lx i386_MSGSUBDIRS= lx -SUBDIRS= sn1 solaris10 ipkg labeled shared $($(MACH)_SUBDIRS) +SUBDIRS= shared .WAIT sn1 solaris10 ipkg labeled $($(MACH)_SUBDIRS) MSGSUBDIRS= solaris10 shared $($(MACH)_MSGSUBDIRS) all := TARGET= all diff --git a/usr/src/lib/brand/Makefile.brand b/usr/src/lib/brand/Makefile.brand index a2cf9bd250..08a994899b 100644 --- a/usr/src/lib/brand/Makefile.brand +++ b/usr/src/lib/brand/Makefile.brand @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # include $(SRC)/Makefile.master @@ -38,6 +37,8 @@ ROOTXMLDOCS= $(XMLDOCS:%=$(ROOTBRANDDIR)/%) ROOTSHARED= $(SHARED:%=$(ROOTSHAREDDIR)/%) ETCUSER= $(USERFILES:%=$(ETCBRANDDIR)/%) +BRAND_SHARED= $(SRC)/lib/brand/shared + ROOTTEMPLATES= $(TEMPLATES:%=$(ROOTTEMPLATEDIR)/%) $(ROOTBRANDDIR) := FILEMODE = 755 diff --git a/usr/src/lib/brand/shared/Makefile b/usr/src/lib/brand/shared/Makefile index 6c0aa73c13..9cb19dc163 100644 --- a/usr/src/lib/brand/shared/Makefile +++ b/usr/src/lib/brand/shared/Makefile @@ -18,38 +18,32 @@ # # CDDL HEADER END # - # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # -PROG=query -SHARED= common.ksh query uninstall.ksh -CLOBBERFILES= query - -include $(SRC)/cmd/Makefile.cmd -include ../Makefile.brand - -$(ROOTSHAREDDIR)/common.ksh := FILEMODE = 0444 -$(ROOTSHAREDDIR)/uninstall.ksh := FILEMODE = 0444 +default: all -CLOBBERFILES= $(ROOTSHARED) $(PROG) +# Build everything in parallel; use .WAIT for dependencies +.PARALLEL: -POFILES= common.po query.po uninstall.po -POFILE= shared.po +SUBDIRS = brand zone +MSGSUBDIRS = zone -$(POFILE): $(POFILES) - $(RM) $@ - $(CAT) $(POFILES) > $@ +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +_msg := TARGET= _msg -all: $(PROG) +.KEEP_STATE: -install: $(ROOTSHARED) +all install clean clobber lint: $(SUBDIRS) -clean: - -$(RM) $(PROG) $(POFILES) +_msg: $(MSGSUBDIRS) -lint: +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) -include $(SRC)/cmd/Makefile.targ +FRC: diff --git a/usr/src/lib/brand/shared/brand/Makefile b/usr/src/lib/brand/shared/brand/Makefile new file mode 100644 index 0000000000..1bb18cd84d --- /dev/null +++ b/usr/src/lib/brand/shared/brand/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 (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include $(SRC)/lib/Makefile.lib + +default: all + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +_msg := TARGET= _msg + +.KEEP_STATE: + +all install clean clobber lint _msg: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/brand/shared/brand/Makefile.com b/usr/src/lib/brand/shared/brand/Makefile.com new file mode 100644 index 0000000000..de2decae37 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/Makefile.com @@ -0,0 +1,73 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +COBJS = brand_util.o +ASOBJS = crt.o handler.o runexe.o +OFFSETS_SRC = ../common/offsets.in +OFFSETS_H = assym.h +OBJECTS = $(COBJS) $(ASOBJS) +CLOBBERFILES += $(OFFSETS_H) + +include $(SRC)/lib/Makefile.lib + +SRCDIR = ../common +CSRCS = $(COBJS:%o=../common/%c) +ASSRCS = $(ASOBJS:%o=$(ISASRCDIR)/%s) +SRCS = $(CSRCS) $(ASSRCS) + +# +# Ugh, this is a gross hack. Our assembly routines uses lots of defines +# to simplify variable access. All these defines work fine for amd64 +# compiles because when compiling for amd64 we use the GNU assembler, +# gas. For 32-bit code we use the Sun assembler, as. Unfortunatly +# as does not handle certian constructs that gas does. So rather than +# make our code less readable, we'll just use gas to compile our 32-bit +# code as well. +# +i386_AS = $(amd64_AS) + +CPPFLAGS += -D_REENTRANT -U_ASM -I. -I../sys +CFLAGS += $(CCVERBOSE) +ASFLAGS = -P $(ASFLAGS_$(CURTYPE)) -D_ASM -I. -I../sys + +.KEEP_STATE: + +# +# build the offset header before trying to compile any files. (it's included +# by brand_misc.h, so it's needed for all objects, not just assembly ones.) +# +all: $(OFFSETS_H) pics .WAIT $(PICS) + +lint: lintcheck + +$(OBJECTS:%=pics/%): $(OFFSETS_H) + +$(OFFSETS_H): $(OFFSETS_SRC) + $(OFFSETS_CREATE) $(CTF_FLAGS) < $(OFFSETS_SRC) >$@ + +pics/%.o: $(ISASRCDIR)/%.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/brand/shared/brand/amd64/Makefile b/usr/src/lib/brand/shared/brand/amd64/Makefile new file mode 100644 index 0000000000..3a6cd15af6 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +ISASRCDIR = . + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +CPPFLAGS += -D_SYSCALL32 + +install: all diff --git a/usr/src/lib/brand/shared/brand/amd64/crt.s b/usr/src/lib/brand/shared/brand/amd64/crt.s new file mode 100644 index 0000000000..831aa6b240 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/amd64/crt.s @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include + +#if defined(lint) + +void +_start(void) +{ +} + +#else /* lint */ + /* + * Initial entry point for the brand emulation library. + * + * This platform specific assembly entry point exists just to invoke + * the common brand library startup routine. That routine expects to + * be called with the following arguments: + * brand_init(int argc, char *argv[], char *envp[]) + * + * There are no arguments explicitly passed to this entry point, + * routine, but we do know how our initial stack has been setup by + * the kernel. The stack format is documented in: + * usr/src/cmd/sgs/rtld/amd64/boot.s + * + * So this routine will troll through the stack to setup the argument + * values for the common brand library startup routine and then invoke + * it. This routine is modeled after the default crt1.s`_start() + * routines. + */ + ENTRY_NP(_start) + + /* Make stack traces look pretty, build a fake stack frame. */ + pushq $0 / Build a stack frame. retpc = NULL + pushq $0 / fp = NULL + movq %rsp, %rbp / first stack frame + + /* + * Calculate the location of the envp array by adding the size of + * the argv array to the start of the argv array. + */ + movq 16(%rbp), %rdi / argc in %rax (1st param) + leaq 24(%rbp), %rsi / &argv[0] in %rbx (2nd param) + leaq 32(%rbp,%rdi,8), %rdx / envp in %rcx (3rd param) + call brand_init + + /*NOTREACHED*/ + SET_SIZE(_start) +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/amd64/handler.s b/usr/src/lib/brand/shared/brand/amd64/handler.s new file mode 100644 index 0000000000..fb5d3c2bb4 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/amd64/handler.s @@ -0,0 +1,218 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include + +/* + * Each JMP must occupy 16 bytes + */ +#define JMP \ + pushq $_CONST(. - brand_handler_table); \ + jmp brand_handler; \ + .align 16; + +#define JMP4 JMP; JMP; JMP; JMP +#define JMP16 JMP4; JMP4; JMP4; JMP4 +#define JMP64 JMP16; JMP16; JMP16; JMP16 +#define JMP256 JMP64; JMP64; JMP64; JMP64 + +#if defined(lint) + +void +brand_handler_table(void) +{} + +void +brand_handler(void) +{ +} + +#else /* lint */ + + /* + * On entry to this table, %rax will hold the return address. The + * location where we enter the table is a function of the system + * call number. The table needs the same alignment as the individual + * entries. + */ + .align 16 + ENTRY_NP(brand_handler_table) + JMP256 + SET_SIZE(brand_handler_table) + + /* + * %rax - userland return address + * stack contains: + * | -------------------------------------- + * v 8 | syscall arguments | + * %rsp+0 | syscall number | + * -------------------------------------- + */ + ENTRY_NP(brand_handler) + pushq %rbp /* allocate stack frame */ + movq %rsp, %rbp + + /* Save registers at the time of the syscall. */ + movq $0, EH_LOCALS_GREG(REG_TRAPNO)(%rbp) + movq $0, EH_LOCALS_GREG(REG_ERR)(%rbp) + movq %r15, EH_LOCALS_GREG(REG_R15)(%rbp) + movq %r14, EH_LOCALS_GREG(REG_R14)(%rbp) + movq %r13, EH_LOCALS_GREG(REG_R13)(%rbp) + movq %r12, EH_LOCALS_GREG(REG_R12)(%rbp) + movq %r11, EH_LOCALS_GREG(REG_R11)(%rbp) + movq %r10, EH_LOCALS_GREG(REG_R10)(%rbp) + movq %r9, EH_LOCALS_GREG(REG_R9)(%rbp) + movq %r8, EH_LOCALS_GREG(REG_R8)(%rbp) + movq %rdi, EH_LOCALS_GREG(REG_RDI)(%rbp) + movq %rsi, EH_LOCALS_GREG(REG_RSI)(%rbp) + movq %rbx, EH_LOCALS_GREG(REG_RBX)(%rbp) + movq %rcx, EH_LOCALS_GREG(REG_RCX)(%rbp) + movq %rdx, EH_LOCALS_GREG(REG_RDX)(%rbp) + xorq %rcx, %rcx + movw %cs, %cx + movq %rcx, EH_LOCALS_GREG(REG_CS)(%rbp) + movw %ds, %cx + movq %rcx, EH_LOCALS_GREG(REG_DS)(%rbp) + movw %es, %cx + movq %rcx, EH_LOCALS_GREG(REG_ES)(%rbp) + movw %fs, %cx + movq %rcx, EH_LOCALS_GREG(REG_FS)(%rbp) + movw %gs, %cx + movq %rcx, EH_LOCALS_GREG(REG_GS)(%rbp) + movw %ss, %cx + movq %rcx, EH_LOCALS_GREG(REG_SS)(%rbp) + pushfq /* save syscall flags */ + popq %r12 + movq %r12, EH_LOCALS_GREG(REG_RFL)(%rbp) + movq EH_ARGS_OFFSET(0)(%rbp), %r12 /* save syscall rbp */ + movq %r12, EH_LOCALS_GREG(REG_RBP)(%rbp) + movq %rbp, %r12 /* save syscall rsp */ + addq $CPTRSIZE, %r12 + movq %r12, EH_LOCALS_GREG(REG_RSP)(%rbp) + movq %fs:0, %r12 /* save syscall fsbase */ + movq %r12, EH_LOCALS_GREG(REG_FSBASE)(%rbp) + movq $0, EH_LOCALS_GREG(REG_GSBASE)(%rbp) + + /* + * The kernel drops us into the middle of the brand_handle_table + * above that then pushes that table offset onto the stack, and calls + * into brand_handler. That offset indicates the system call number + * while %rax holds the return address for the system call. We replace + * the value on the stack with the return address, and use the value to + * compute the system call number by dividing by the table entry size. + */ + xchgq CPTRSIZE(%rbp), %rax /* swap JMP table offset and ret addr */ + shrq $4, %rax /* table_offset/size = syscall num */ + movq %rax, EH_LOCALS_GREG(REG_RAX)(%rbp) /* save syscall num */ + + /* + * Finish setting up our stack frame. We would normally do this + * upon entry to this function, but in this case we delayed it + * because a "sub" operation can modify flags and we wanted to + * save the flags into the gregset_t above before they get modified. + * + * Our stack frame format is documented in brand_misc.h. + */ + subq $EH_LOCALS_SIZE, %rsp + + /* Look up the system call's entry in the sysent table */ + movq brand_sysent_table@GOTPCREL(%rip), %r11 /* %r11 = sysent_tbl */ + shlq $4, %rax /* each entry is 16 bytes */ + addq %rax, %r11 /* %r11 = sysent entry address */ + + /* + * Get the return value flag and the number of arguments from the + * sysent table. + */ + movq CPTRSIZE(%r11), %r12 /* number of args + rv flag */ + andq $RV_MASK, %r12 /* strip out number of args */ + movq %r12, EH_LOCALS_RVFLAG(%rbp) /* save rv flag */ + + /* + * Setup arguments for our emulation call. Our input arguments, + * 0 to N, will become emulation call arguments 1 to N+1. + * + * Note: Syscall argument passing is different from function call + * argument passing on amd64. For function calls, the fourth arg + * is passed via %rcx, but for system calls the 4th argument is + * passed via %r10. This is because in amd64, the syscall + * instruction puts lower 32 bit of %rflags in %r11 and puts the + * %rip value to %rcx. + */ + movq EH_ARGS_OFFSET(4)(%rbp), %r12 /* copy 8th arg */ + movq %r12, EH_ARGS_OFFSET(2)(%rsp) + movq EH_ARGS_OFFSET(3)(%rbp), %r12 /* copy 7th arg */ + movq %r12, EH_ARGS_OFFSET(1)(%rsp) + movq %r9, EH_ARGS_OFFSET(0)(%rsp) + movq %r8, %r9 + movq %r10, %r8 + movq %rdx, %rcx + movq %rsi, %rdx + movq %rdi, %rsi + + /* + * The first parameter to the emulation callback function is a + * pointer to a sysret_t structure. + */ + movq %rbp, %rdi + addq $EH_LOCALS_SYSRET, %rdi /* arg0 == sysret_t ptr */ + + /* invoke the emulation routine */ + ALTENTRY(brand_handler_savepc) + call *(%r11) + + /* restore scratch and parameter registers */ + movq EH_LOCALS_GREG(REG_R12)(%rbp), %r12 /* restore %r12 */ + movq EH_LOCALS_GREG(REG_R11)(%rbp), %r11 /* restore %r11 */ + movq EH_LOCALS_GREG(REG_R10)(%rbp), %r10 /* restore %r10 */ + movq EH_LOCALS_GREG(REG_R9)(%rbp), %r9 /* restore %r9 */ + movq EH_LOCALS_GREG(REG_R8)(%rbp), %r8 /* restore %r8 */ + movq EH_LOCALS_GREG(REG_RCX)(%rbp), %rcx /* restore %rcx */ + movq EH_LOCALS_GREG(REG_RDX)(%rbp), %rdx /* restore %rdx */ + movq EH_LOCALS_GREG(REG_RSI)(%rbp), %rsi /* restore %rsi */ + movq EH_LOCALS_GREG(REG_RDI)(%rbp), %rdi /* restore %rdi */ + + /* Check for syscall emulation success or failure */ + cmpq $0, %rax + je success + stc /* failure, set carry flag */ + jmp return /* return, %rax == errno */ + +success: + /* There is always at least one return value. */ + movq EH_LOCALS_SYSRET1(%rbp), %rax /* %rax == sys_rval1 */ + cmpq $RV_DEFAULT, EH_LOCALS_RVFLAG(%rbp) /* check rv flag */ + je clear_carry + mov EH_LOCALS_SYSRET2(%rbp), %rdx /* %rdx == sys_rval2 */ +clear_carry: + clc /* success, clear carry flag */ + +return: + movq %rbp, %rsp /* restore stack */ + popq %rbp + ret /* ret to instr after syscall */ + SET_SIZE(brand_handler) + + +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/amd64/runexe.s b/usr/src/lib/brand/shared/brand/amd64/runexe.s new file mode 100644 index 0000000000..418c8726e1 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/amd64/runexe.s @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include + +#if defined(lint) + +/*ARGSUSED*/ +void +brand_runexe(void *argv, ulong_t entry) +{ +} + +#else /* lint */ + /* + * Prepare to jump to the target program we actually want to run. + * If this program is dynamically linked then we'll be jumping to + * another copy of the linker. If it's a statically linked program + * we'll be jumping directy to it's main entry point. In any case, + * we need to reset our current state stack and register state to + * something similar to the initial process state setup by the kernel + * and documented at: + * usr/src/cmd/sgs/rtld/i386/boot.s + * usr/src/cmd/sgs/rtld/sparcv9/boot.s + * + * Of course this is the same stack format as when this executable + * was first started, so here we'll just roll back the stack and + * frame pointers to their values when this processes first started + * execution. + */ + ENTRY_NP(brand_runexe) + + movq %rdi, %rax / %rax = &argv[0] + movq %rsi, %rbx / Brand app entry point in %rbx + subq $8, %rax / Top of stack - must point at argc + movq %rax, %rsp / Set %rsp to what linkers expect + + /* + * We also have to make sure to clear %rdx since nornally ld.so.1 will + * set that to non-zero if there is an exit function that should be + * invoked when the process is terminating. This isn't actually + * necessary if the target program we're jumping to is a dynamically + * linked program since in that case we're actually jumping to another + * copy of ld.so.1 and it will just reset %rdx, but if the target + * program we're jumping to is a statically linked binary that uses + * the standard sun compiler supplied crt1.o`_start(), it will check + * to see if %g1 is set. + */ + movq $0, %rdx + + jmp *%rbx / And away we go... + /* + * target will never return. + */ + SET_SIZE(brand_runexe) +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/common/brand_util.c b/usr/src/lib/brand/shared/brand/common/brand_util.c new file mode 100644 index 0000000000..051cbccb21 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/common/brand_util.c @@ -0,0 +1,452 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern brand_sysent_table_t brand_sysent_table[]; + +/*LINTED: static unused*/ +static volatile int brand_abort_err; +/*LINTED: static unused*/ +static volatile const char *brand_abort_msg; +/*LINTED: static unused*/ +static volatile const char *brand_abort_file; +/*LINTED: static unused*/ +static volatile int brand_abort_line; + +/* + * Principles of emulation 101. + * + * + * *** Setting errno + * + * Just don't do it. This emulation library is loaded onto a + * seperate link map from the application who's address space we're + * running in. We have our own private copy of libc, so there for, + * the errno value accessible from here is is also private and changing + * it will not affect any errno value that the processes who's address + * space we are running in will see. To return an error condition we + * should return the errno value we'd like the system to return. + * For more information about this see the comments in brand_misc.h. + * Basically, when we return to the caller that initiated the system + * call it's their responsibility to set errno. + * + * + * *** Recursion Considerations + * + * When emulating system calls we need to be very careful about what + * library calls we invoke. Library calls should be kept to a minimum. + * One issue is that library calls can invoke system calls, so if we're + * emulating a system call and we invoke a library call that depends on + * that system call we will probably enter a recursive loop, which would + * be bad. + * + * + * *** Return Values. + * + * See brand_misc.h. + * + * *** Agent lwp considerations + * + * It is currently impossible to do any emulation for these system call + * when they are being invoked on behalf of an agent lwp. To understand why + * it's impossible you have to understand how agent lwp syscalls work. + * + * The agent lwp syscall process works as follows: + * 1 The controlling process stops the target. + * 2 The controlling process injects an agent lwp which is also stopped. + * This agent lwp assumes the userland stack and register values + * of another stopped lwp in the current process. + * 3 The controlling process configures the agent lwp to start + * executing the requested system call. + * 4 The controlling process configure /proc to stop the agent lwp when + * it enters the requested system call. + * 5 The controlling processes allows the agent lwp to start executing. + * 6 The agent lwp traps into the kernel to perform the requested system + * call and immediately stop. + * 7 The controlling process copies all the arguments for the requested + * system call onto the agent lwp's stack. + * 8 The controlling process configures /proc to stop the agent lwp + * when it completes the requested system call. + * 9 The controlling processes allows the agent lwp to start executing. + * 10 The agent lwp executes the system call and then stop before returning + * to userland. + * 11 The controlling process copies the return value and return arguments + * back from the agent lwps stack. + * 12 The controlling process destroys the agent lwp and restarts + * the target process. + * + * The fundamental problem is that when the agent executes the request + * system call in step 5, if we're emulating that system call then the + * lwp is redirected back to our emulation layer without blocking + * in the kernel. But our emulation layer can't access the arguments + * for the system call because they haven't been copied to the stack + * yet and they still only exist in the controlling processes address + * space. This prevents us from being able to do any emulation of + * agent lwp system calls. Hence, currently our brand trap interposition + * callback (XXX_brand_syscall_callback_common) will detect if a system + * call is being made by an agent lwp, and if this is the case it will + * never redirect the system call to this emulation library. + * + * In the future, if this proves to be a problem the the easiest solution + * would probably be to replace the branded versions of these application + * with their native counterparts. Ie, truss, plimit, and pfiles could be + * replace with wrapper scripts that execute the native versions of these + * applications. In the case of plimit and pfiles this should be pretty + * strait forward. Truss would probably be more tricky since it can + * execute applications which would be branded applications, so in that + * case it might be necessary to create a loadable library which could + * be LD_PRELOADed into truss and this library would interpose on the + * exec() system call to allow truss to correctly execute branded + * processes. It should be pointed out that this solution could work + * because "native agent lwps" (ie, agent lwps created by native + * processes) can be treated differently from "branded aged lwps" (ie, + * agent lwps created by branded processes), since native agent lwps + * would presumably be making native system calls and hence not need + * any interposition. + * + * *** General considerations + * + * One of the differences between the lx brand and the s10 + * brand, is that the s10 brand only interposes on syscalls + * that need some kind of emulation, whereas the lx brand interposes + * on _all_ system calls. Lx branded system calls that don't need + * any emulation are then redirected back to the kernel from the + * userland library via the IN_KERNEL_SYSCALL macro. The lx-syscall + * dtrace provider depends on this behavior. + * + */ + +/*ARGSUSED*/ +void +_brand_abort(int err, const char *msg, const char *file, int line) +{ + sysret_t rval; + + /* Save the error message into convenient globals */ + brand_abort_err = err; + brand_abort_msg = msg; + brand_abort_file = file; + brand_abort_line = line; + + /* kill ourselves */ + abort(); + + /* If abort() didn't work, try something stronger. */ + (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGKILL); +} + +int +brand_uucopy(const void *from, void *to, size_t size) +{ + sysret_t rval; + + if (__systemcall(&rval, SYS_uucopy + 1024, from, to, size) != 0) + return (EFAULT); + return (0); +} + +/* + * ATTENTION: uucopystr() does NOT ensure that string are null terminated! + */ +int +brand_uucopystr(const void *from, void *to, size_t size) +{ + sysret_t rval; + + if (__systemcall(&rval, SYS_uucopystr + 1024, from, to, size) != 0) + return (EFAULT); + return (0); +} + +/* + * This function is defined to be NOSYS but it won't be called from the + * the kernel since the NOSYS system calls are not enabled in the kernel. + * Thus, the only time this function is called is directly from within the + * indirect system call path. + */ +/*ARGSUSED*/ +long +brand_unimpl(sysret_t *rv, uintptr_t p1) +{ + sysret_t rval; + + /* + * We'd like to print out some kind of error message here like + * "unsupported syscall", but we can't because it's not safe to + * assume that stderr or STDERR_FILENO actually points to something + * that is a terminal, and if we wrote to those files we could + * inadvertantly write to some applications open files, which would + * be bad. + * + * Normally, if an application calls an invalid system call + * it get a SIGSYS sent to it. So we'll just go ahead and send + * ourselves a signal here. Note that this is far from ideal since + * if the application has registered a signal handler, that signal + * handler may recieve a ucontext_t as the third parameter to + * indicate the context of the process when the signal was + * generated, and in this case that context will not be what the + * application is expecting. Hence, we should probably create a + * brandsys() kernel function that can deliver the signal to us + * with the correct ucontext_t. + */ + (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGSYS); + return (ENOSYS); +} + +#if defined(__sparc) && !defined(__sparcv9) +/* + * Yuck. For 32-bit sparc applications, handle indirect system calls. + * Note that we declare this interface to use the maximum number of + * system call arguments. If we recieve a system call that uses less + * arguments, then the additional arguments will be garbage, but they + * will also be ignored so that should be ok. + */ +long +brand_indir(sysret_t *rv, int code, + uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, + uintptr_t a5, uintptr_t a6, uintptr_t a7) +{ + brand_sysent_table_t *sst = &(brand_sysent_table[code]); + + brand_assert(code < NSYSCALL); + switch (sst->st_args & NARGS_MASK) { + case 0: + return ((sst->st_callc)(rv)); + case 1: + return ((sst->st_callc)(rv, a0)); + case 2: + return ((sst->st_callc)(rv, a0, a1)); + case 3: + return ((sst->st_callc)(rv, a0, a1, a2)); + case 4: + return ((sst->st_callc)(rv, a0, a1, a2, a3)); + case 5: + return ((sst->st_callc)(rv, a0, a1, a2, a3, a4)); + case 6: + return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5)); + case 7: + return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6)); + case 8: + return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6, a7)); + } + brand_abort(0, "invalid entry in brand_sysent_table"); + return (EINVAL); +} +#endif /* __sparc && !__sparcv9 */ + +/* + * Close a libc file handle, but don't actually close the underlying + * file descriptor. + */ +static void +brand_close_fh(FILE *file) +{ + int fd, fd_new; + + if (file == NULL) + return; + + if ((fd = fileno(file)) < 0) + return; + + /* + * We're a branded process but our handler isn't installed yet. We + * can't use the dup() syscall since it no longer exists. + */ + fd_new = fcntl(fd, F_DUPFD, 0); + if (fd_new == -1) + return; + + (void) fclose(file); + (void) dup2(fd_new, fd); + (void) close(fd_new); +} + +/*ARGSUSED*/ +void +brand_pre_init() +{ + int i; + + /* Sanity check our translation table return value codes */ + for (i = 0; i < NSYSCALL; i++) { + brand_sysent_table_t *est = &(brand_sysent_table[i]); + brand_assert(BIT_ONLYONESET(est->st_args & RV_MASK)); + } + + /* + * We need to shutdown all libc stdio. libc stdio normally goes to + * file descriptors, but since we're actually part of a another + * process we don't own these file descriptors and we can't make + * any assumptions about their state. + */ + brand_close_fh(stdin); + brand_close_fh(stdout); + brand_close_fh(stderr); +} + +/*ARGSUSED*/ +ulong_t +brand_post_init(int version, int argc, char *argv[], char *envp[]) +{ + sysret_t rval; + brand_proc_reg_t reg; + brand_elf_data_t sed; + auxv_t *ap; + uintptr_t *p; + int err; + + /* + * Register our syscall emulation table with the kernel. + * Note that we don't have to do invoke (syscall_number + 1024) + * until we've actually establised a syscall emulation callback + * handler address, which is what we're doing with this brand + * syscall. + */ + reg.sbr_version = version; +#ifdef __x86 + reg.sbr_handler = (caddr_t)brand_handler_table; +#else /* !__x86 */ + reg.sbr_handler = (caddr_t)brand_handler; +#endif /* !__x86 */ + + if ((err = __systemcall(&rval, SYS_brand, B_REGISTER, ®)) != 0) { + brand_abort(err, "Failed to brand current process"); + + /*NOTREACHED*/ + } + + /* Get data about the executable we're running from the kernel. */ + if ((err = __systemcall(&rval, SYS_brand + 1024, + B_ELFDATA, (void *)&sed)) != 0) { + brand_abort(err, + "Failed to get required brand ELF data from the kernel"); + /*NOTREACHED*/ + } + + /* + * Find the aux vector on the stack. + */ + p = (uintptr_t *)envp; + while (*p != NULL) + p++; + + /* + * p is now pointing at the 0 word after the environ pointers. + * After that is the aux vectors. + * + * The aux vectors are currently pointing to the brand emulation + * library and associated linker. We're going to change them to + * point to the brand executable and associated linker (or to no + * linker for static binaries). This matches the process data + * stored within the kernel and visible from /proc, which was + * all setup in sn1_elfexec(). We do this so that when a debugger + * attaches to the process it sees the process as a normal solaris + * process, this brand emulation library and everything on it's + * link map will not be visible, unless our librtld_db plugin + * is used. Note that this is very different from how Linux + * branded processes are implemented within lx branded zones. + * In that situation, the primary linkmap of the process is the + * brand emulation libraries linkmap, not the Linux applications + * linkmap. + * + * We also need to clear the AF_SUN_NOPLM flag from the AT_SUN_AUXFLAGS + * aux vector. This flag told our linker that we don't have a + * primary link map. Now that our linker is done initializing, we + * want to clear this flag before we transfer control to the + * applications copy of the linker, since we want that linker to have + * a primary link map which will be the link map for the application + * we're running. + */ + p++; + for (ap = (auxv_t *)p; ap->a_type != AT_NULL; ap++) { + switch (ap->a_type) { + case AT_BASE: + /* Hide AT_BASE if static binary */ + if (sed.sed_base == NULL) { + ap->a_type = AT_IGNORE; + ap->a_un.a_val = NULL; + } else { + ap->a_un.a_val = sed.sed_base; + } + break; + case AT_ENTRY: + ap->a_un.a_val = sed.sed_entry; + break; + case AT_PHDR: + ap->a_un.a_val = sed.sed_phdr; + break; + case AT_PHENT: + ap->a_un.a_val = sed.sed_phent; + break; + case AT_PHNUM: + ap->a_un.a_val = sed.sed_phnum; + break; + case AT_SUN_AUXFLAGS: + ap->a_un.a_val &= ~AF_SUN_NOPLM; + break; + case AT_SUN_EMULATOR: + /* + * ld.so.1 inspects AT_SUN_EMULATOR to see if + * if it is the linker for the brand emulation + * library. Hide AT_SUN_EMULATOR, as the + * linker we are about to jump to is the linker + * for the binary. + */ + ap->a_type = AT_IGNORE; + ap->a_un.a_val = NULL; + break; + case AT_SUN_LDDATA: + /* Hide AT_SUN_LDDATA if static binary */ + if (sed.sed_lddata == NULL) { + ap->a_type = AT_IGNORE; + ap->a_un.a_val = NULL; + } else { + ap->a_un.a_val = sed.sed_lddata; + } + break; + default: + break; + } + } + + return (sed.sed_ldentry); +} diff --git a/usr/src/lib/brand/shared/brand/common/offsets.in b/usr/src/lib/brand/shared/brand/common/offsets.in new file mode 100644 index 0000000000..ec47a6adca --- /dev/null +++ b/usr/src/lib/brand/shared/brand/common/offsets.in @@ -0,0 +1,34 @@ +\ +\ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License (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 +\ + + +#include +#include +#include +#include + +greg_t SIZEOF_GREG_T + +gregset_t SIZEOF_GREGSET_T + +sysret_t SIZEOF_SYSRET_T diff --git a/usr/src/lib/brand/shared/brand/i386/Makefile b/usr/src/lib/brand/shared/brand/i386/Makefile new file mode 100644 index 0000000000..b049d76f71 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +ISASRCDIR = . + +include ../Makefile.com + +install: all diff --git a/usr/src/lib/brand/shared/brand/i386/crt.s b/usr/src/lib/brand/shared/brand/i386/crt.s new file mode 100644 index 0000000000..ed1ec1e18a --- /dev/null +++ b/usr/src/lib/brand/shared/brand/i386/crt.s @@ -0,0 +1,76 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include + +#if defined(lint) + +void +_start(void) +{ +} + +#else /* lint */ + /* + * Initial entry point for the brand emulation library. + * + * This platform specific assembly entry point exists just to invoke + * the common brand library startup routine. That routine expects to + * be called with the following arguments: + * brand_init(int argc, char *argv[], char *envp[]) + * + * There are no arguments explicitly passed to this entry point, + * routine, but we do know how our initial stack has been setup by + * the kernel. The stack format is documented in: + * usr/src/cmd/sgs/rtld/i386/boot.s + * + * So this routine will troll through the stack to setup the argument + * values for the common brand library startup routine and then invoke + * it. This routine is modeled after the default crt1.s`_start() + * routines. + */ + ENTRY_NP(_start) + + /* Make stack traces look pretty, build a fake stack frame. */ + pushl $0 / retpc = NULL + pushl $0 / fp = NULL + movl %esp, %ebp / first stack frame + + /* + * Calculate the location of the envp array by adding the size of + * the argv array to the start of the argv array. + */ + movl 8(%ebp), %eax / argc in %eax + leal 12(%ebp), %ebx / &argv[0] in %ebx + leal 16(%ebp,%eax,4), %ecx / envp in %ecx + + pushl %ecx / push envp (3rd param) + pushl %ebx / push argv (2nd param) + pushl %eax / push argc (1st param) + call brand_init + + /*NOTREACHED*/ + SET_SIZE(_start) +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/i386/handler.s b/usr/src/lib/brand/shared/brand/i386/handler.s new file mode 100644 index 0000000000..f2e51ac367 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/i386/handler.s @@ -0,0 +1,195 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include + +/* + * Each JMP must occupy 16 bytes + */ +#define JMP \ + pushl $_CONST(. - brand_handler_table); \ + jmp brand_handler; \ + .align 16; + +#define JMP4 JMP; JMP; JMP; JMP +#define JMP16 JMP4; JMP4; JMP4; JMP4 +#define JMP64 JMP16; JMP16; JMP16; JMP16 +#define JMP256 JMP64; JMP64; JMP64; JMP64 + +#if defined(lint) + +void +brand_handler_table(void) +{} + +void +brand_handler(void) +{ +} + +#else /* lint */ + + /* + * On entry to this table, %eax will hold the return address. The + * location where we enter the table is a function of the system + * call number. The table needs the same alignment as the individual + * entries. + */ + .align 16 + ENTRY_NP(brand_handler_table) + JMP256 + SET_SIZE(brand_handler_table) + +#define PIC_SETUP(r) \ + call 9f; \ +9: \ + popl r; \ + addl $_GLOBAL_OFFSET_TABLE_ + [. - 9b], r + + /* + * %eax - userland return address + * stack contains: + * | -------------------------------------- + * v 4 | syscall arguments | + * %esp+0 | syscall number | + * -------------------------------------- + */ + ENTRY_NP(brand_handler) + pushl %ebp /* allocate a stack frame */ + movl %esp, %ebp + + /* Save registers at the time of the syscall. */ + movl $0, EH_LOCALS_GREG(TRAPNO)(%ebp) + movl $0, EH_LOCALS_GREG(ERR)(%ebp) + movl %ebx, EH_LOCALS_GREG(EBX)(%ebp) + movl %ecx, EH_LOCALS_GREG(ECX)(%ebp) + movl %edx, EH_LOCALS_GREG(EDX)(%ebp) + movl %edi, EH_LOCALS_GREG(EDI)(%ebp) + movl %esi, EH_LOCALS_GREG(ESI)(%ebp) + mov %cs, EH_LOCALS_GREG(CS)(%ebp) + mov %ds, EH_LOCALS_GREG(DS)(%ebp) + mov %es, EH_LOCALS_GREG(ES)(%ebp) + mov %fs, EH_LOCALS_GREG(FS)(%ebp) + mov %gs, EH_LOCALS_GREG(GS)(%ebp) + pushfl /* save syscall flags */ + popl %ecx + movl %ecx, EH_LOCALS_GREG(EFL)(%ebp) + movl EH_ARGS_OFFSET(0)(%ebp), %ecx /* save syscall ebp */ + movl %ecx, EH_LOCALS_GREG(EBP)(%ebp) + movl %ebp, %ecx /* save syscall esp */ + addl $CPTRSIZE, %ecx + movl %ecx, EH_LOCALS_GREG(ESP)(%ebp) + + /* + * The kernel drops us into the middle of the brand_handle_table + * above that then pushes that table offset onto the stack, and calls + * into brand_handler. That offset indicates the system call number + * while %eax holds the return address for the system call. We replace + * the value on the stack with the return address, and use the value to + * compute the system call number by dividing by the table entry size. + */ + xchgl CPTRSIZE(%ebp), %eax /* swap JMP table offset and ret addr */ + shrl $4, %eax /* table_offset/size = syscall num */ + movl %eax, EH_LOCALS_GREG(EAX)(%ebp) /* save syscall num */ + + /* + * Finish setting up our stack frame. We would normally do this + * upon entry to this function, but in this case we delayed it + * because a "sub" operation can modify flags and we wanted to + * save the flags into the gregset_t above before they get modified. + * + * Our stack frame format is documented in brand_misc.h. + */ + subl $EH_LOCALS_SIZE, %esp + + /* Look up the system call's entry in the sysent table */ + PIC_SETUP(%ecx) + movl brand_sysent_table@GOT(%ecx), %edx /* %edx = sysent_table */ + shll $3, %eax /* each entry is 8 bytes */ + add %eax, %edx /* %edx = sysent entry address */ + + /* + * Get the return value flag and the number of arguments from the + * sysent table. + */ + movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ + andl $RV_MASK, %ecx /* strip out number of args */ + movl %ecx, EH_LOCALS_RVFLAG(%ebp) /* save rv flag */ + movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ + andl $NARGS_MASK, %ecx /* strip out rv flag */ + + /* + * Setup arguments for our emulation call. Our input arguments, + * 0 to N, will become emulation call arguments 1 to N+1. + * %ecx == number of arguments. + */ + movl %ebp, %esi /* args are at 12(%ebp) */ + addl $EH_ARGS_OFFSET(3), %esi + movl %esp, %edi /* copy args to 4(%esp) */ + addl $EH_ARGS_OFFSET(1), %edi + rep; smovl /* copy: (%esi) -> (%edi) */ + /* copy: %ecx 32-bit words */ + movl EH_LOCALS_GREG(ESI)(%ebp), %esi /* restore %esi */ + movl EH_LOCALS_GREG(EDI)(%ebp), %edi /* restore %edi */ + + /* + * The first parameter to the emulation callback function is a + * pointer to a sysret_t structure. + */ + movl %ebp, %ecx + addl $EH_LOCALS_SYSRET, %ecx + movl %ecx, EH_ARGS_OFFSET(0)(%esp) /* arg0 == sysret_t ptr */ + + /* invoke the emulation routine */ + ALTENTRY(brand_handler_savepc) + call *(%edx) /* call emulation routine */ + + /* restore scratch registers */ + movl EH_LOCALS_GREG(ECX)(%ebp), %ecx /* restore %ecx */ + movl EH_LOCALS_GREG(EDX)(%ebp), %edx /* restore %edx */ + + /* Check for syscall emulation success or failure */ + cmpl $0, %eax /* check for an error */ + je success + stc /* failure, set carry flag */ + jmp return /* return, %rax == errno */ + +success: + /* There is always at least one return value. */ + movl EH_LOCALS_SYSRET1(%ebp), %eax /* %eax == sys_rval1 */ + cmpl $RV_DEFAULT, EH_LOCALS_RVFLAG(%ebp) /* check rv flag */ + je clear_carry + mov EH_LOCALS_SYSRET2(%ebp), %edx /* %edx == sys_rval2 */ +clear_carry: + clc /* success, clear carry flag */ + +return: + movl %ebp, %esp /* restore stack */ + popl %ebp + ret /* ret to instr after syscall */ + SET_SIZE(brand_handler) + + +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/i386/runexe.s b/usr/src/lib/brand/shared/brand/i386/runexe.s new file mode 100644 index 0000000000..b7e0408bf2 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/i386/runexe.s @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include + +#if defined(lint) + +/*ARGSUSED*/ +void +brand_runexe(void *argv, ulong_t entry) +{ +} + +#else /* lint */ + /* + * Prepare to jump to the target program we actually want to run. + * If this program is dynamically linked then we'll be jumping to + * another copy of the linker. If it's a statically linked program + * we'll be jumping directy to it's main entry point. In any case, + * we need to reset our current state stack and register state to + * something similar to the initial process state setup by the kernel + * and documented at: + * usr/src/cmd/sgs/rtld/i386/boot.s + * usr/src/cmd/sgs/rtld/sparcv9/boot.s + * + * Of course this is the same stack format as when this executable + * was first started, so here we'll just roll back the stack and + * frame pointers to their values when this processes first started + * execution. + */ + ENTRY_NP(brand_runexe) + + movl 4(%esp), %eax / %eax = &argv[0] + movl 8(%esp), %ebx / Brand app entry point in %ebx + subl $4, %eax / Top of stack - must point at argc + movl %eax, %esp / Set %esp to what linkers expect + + /* + * We also have to make sure to clear %edx since nornally ld.so.1 will + * set that to non-zero if there is an exit function that should be + * invoked when the process is terminating. This isn't actually + * necessary if the target program we're jumping to is a dynamically + * linked program since in that case we're actually jumping to another + * copy of ld.so.1 and it will just reset %edx, but if the target + * program we're jumping to is a statically linked binary that uses + * the standard sun compiler supplied crt1.o`_start(), it will check + * to see if %g1 is set. + */ + movl $0, %edx + + jmp *%ebx / And away we go... + /* + * target will never return. + */ + SET_SIZE(brand_runexe) +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/sparc/Makefile b/usr/src/lib/brand/shared/brand/sparc/Makefile new file mode 100644 index 0000000000..89efaf5adc --- /dev/null +++ b/usr/src/lib/brand/shared/brand/sparc/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +ISASRCDIR = . + +include ../Makefile.com + +ASFLAGS += -xarch=v8plus ${AS_PICFLAGS} + +install: all diff --git a/usr/src/lib/brand/shared/brand/sparc/crt.s b/usr/src/lib/brand/shared/brand/sparc/crt.s new file mode 100644 index 0000000000..7845f1a7c6 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/sparc/crt.s @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include + +#if defined(lint) + +void +_start(void) +{ +} + +#else /* lint */ + .section ".text" + /* + * Initial entry point for the brand emulation library. + * + * This platform specific assembly entry point exists just to invoke + * the common brand library startup routine. That routine expects to + * be called with the following arguments: + * brand_init(int argc, char *argv[], char *envp[]) + * + * There are no arguments explicitly passed to this entry point, + * routine, but we do know how our initial stack has been setup by + * the kernel. The stack format is documented in: + * usr/src/cmd/sgs/rtld/sparc/boot.s + * usr/src/cmd/sgs/rtld/sparcv9/boot.s + * + * So this routine will troll through the stack to setup the argument + * values for the common brand library startup routine and then invoke + * it. + */ + ENTRY_NP(_start) +#if defined (__sparcv9) + save %sp, -SA(MINFRAME + EB_MAX_SIZE64), %sp +#else /* !__sparcv9 */ + save %sp, -SA(MINFRAME + EB_MAX_SIZE32), %sp +#endif /* !__sparcv9 */ + + /* get argc */ + ldn [%fp + WINDOWSIZE + STACK_BIAS], %o0 + + /* get argv */ + add %fp, + WINDOWSIZE + CPTRSIZE + STACK_BIAS, %o1 + + /* get envp */ + add %o0, 1, %l0 ! add 1 to argc for last element of 0 + sll %l0, CPTRSHIFT, %l0 ! multiply argc by pointer size + add %o1, %l0, %o2 ! and add to argv to get first env ptr + + call brand_init + nop + + /*NOTREACHED*/ + SET_SIZE(_start) +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/sparc/handler.s b/usr/src/lib/brand/shared/brand/sparc/handler.s new file mode 100644 index 0000000000..8bea770587 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/sparc/handler.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 (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include + +#if defined(lint) + +void +brand_handler(void) +{ +} + +#else /* !lint */ + +#define PIC_SETUP(r) \ + mov %o7, %g1; \ +9: call 8f; \ + sethi %hi(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ +8: or r, %lo(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ + add r, %o7, r; \ + mov %g1, %o7 + +/* + * Translate a global symbol into an address. The resulting address + * is returned in the first register parameter. The second register + * is just for scratch space. + */ +#if defined(__sparcv9) +#define GET_SYM_ADDR(r1, r2, name) \ + PIC_SETUP(r1) ;\ + sethi %hi(name), r2 ;\ + or r2, %lo(name), r2 ;\ + ldn [r2 + r1], r1 +#else /* !__sparcv9 */ +#define GET_SYM_ADDR(r1, r2, name) \ + PIC_SETUP(r1); \ + ld [r1 + name], r1 +#endif /* !__sparcv9 */ + + .section ".text" + + /* + * When we get here, %g1 should contain the system call and + * %g5 should contain the address immediately after the trap + * instruction. + */ + ENTRY_NP(brand_handler) + + /* + * 64-bit sparc may need to save 3 parameters on the stack. + * 32-bit sparc may need to save 4 parameters on the stack. + * + * Our stack frame format is documented in brand_misc.h. + */ + save %sp, -SA(MINFRAME + EH_LOCALS_SIZE), %sp + + /* + * Save the current caller state into gregs and gwins. + * Note that this state isn't exact, %g1 and %g5 have been + * already been lost. Also, we've pushed a stack frame so + * the callers output registers are our input registers. + */ + stn %g0, [%sp + EH_LOCALS_GREG(REG_G1)] /* %g1 is lost */ + stn %g2, [%sp + EH_LOCALS_GREG(REG_G2)] + stn %g3, [%sp + EH_LOCALS_GREG(REG_G3)] + stn %g4, [%sp + EH_LOCALS_GREG(REG_G4)] + stn %g0, [%sp + EH_LOCALS_GREG(REG_G5)] /* %g5 is lost */ + stn %g6, [%sp + EH_LOCALS_GREG(REG_G6)] + stn %g7, [%sp + EH_LOCALS_GREG(REG_G7)] + stn %i0, [%sp + EH_LOCALS_GREG(REG_O0)] + stn %i1, [%sp + EH_LOCALS_GREG(REG_O1)] + stn %i2, [%sp + EH_LOCALS_GREG(REG_O2)] + stn %i3, [%sp + EH_LOCALS_GREG(REG_O3)] + stn %i4, [%sp + EH_LOCALS_GREG(REG_O4)] + stn %i5, [%sp + EH_LOCALS_GREG(REG_O5)] + stn %i6, [%sp + EH_LOCALS_GREG(REG_O6)] + stn %i7, [%sp + EH_LOCALS_GREG(REG_O7)] + sub %g5, 4, %o0 + stn %o0, [%sp + EH_LOCALS_GREG(REG_PC)] + stn %g5, [%sp + EH_LOCALS_GREG(REG_nPC)] + rd %y, %o0 + stn %o0, [%sp + EH_LOCALS_GREG(REG_Y)] +#if defined(__sparcv9) + stn %g0, [%sp + EH_LOCALS_GREG(REG_ASI)] + rd %fprs, %o0 + stn %o0, [%sp + EH_LOCALS_GREG(REG_FPRS)] +#endif /* __sparcv9 */ + + /* + * Look up the system call's entry in the sysent table + * and obtain the address of the proper emulation routine (%l2). + */ + mov %g1, %l5 /* save syscall number */ + GET_SYM_ADDR(%l1, %l2, brand_sysent_table) + mov %l5, %g1 /* restore syscall number */ + sll %g1, (1 + CLONGSHIFT), %l2 /* Each entry has 2 longs */ + add %l2, %l1, %l2 /* index to proper entry */ + ldn [%l2], %l2 /* emulation func address */ + + /* + * Look up the system call's entry in the sysent table, + * taking into account the posibility of indirect system calls, and + * obtain the number of arguments (%l4) and return value flag (%l3). + */ +#if defined(__sparcv9) + mov %g1, %l3 /* %g1 == syscall number */ +#else /* !__sparcv9 */ + /* + * Check for indirect system calls, in which case the real syscall + * number is the first parameter to the indirect system call. + */ + cmp %g1, %g0 /* saved syscall number */ + bne,a,pt %icc, no_indir /* indirect syscall? */ + mov %g1, %l3 /* %g1 == syscall number */ + mov %i0, %l3 /* %i0 == syscall number */ +no_indir: +#endif /* !__sparcv9 */ + sll %l3, (1 + CLONGSHIFT), %l3 /* Each entry has 2 longs */ + add %l3, %l1, %l3 /* index to proper entry */ + ldn [%l3 + CPTRSIZE], %l4 /* number of args + rv flag */ + sethi %hi(RV_MASK), %l5 + or %l5, %lo(RV_MASK), %l5 + andcc %l4, %l5, %l3 /* strip out number of args*/ + andcc %l4, NARGS_MASK, %l4 /* strip out rv flag */ + + /* + * Setup arguments for our emulation call. Our input arguments, + * 0 to N, will become emulation call arguments 1 to N+1. + * %l4 == number of arguments. + */ + mov %i0, %o1 + mov %i1, %o2 + mov %i2, %o3 + mov %i3, %o4 + mov %i4, %o5 + + /* 7th argument and above get passed on the stack */ + cmp %l4, 0x6 + bl,pt %ncc, args_copied + nop + stn %i5, [%sp + EH_ARGS_OFFSET(0)] /* copy 6th syscall arg */ + cmp %l4, 0x7 + bl,pt %ncc, args_copied + nop + ldn [%fp + EH_ARGS_OFFSET(0)], %l5 /* copy 7th syscall arg */ + stn %l5, [%sp + EH_ARGS_OFFSET(1)] + cmp %l4, 0x8 + bl,pt %ncc, args_copied + nop + ldn [%fp + EH_ARGS_OFFSET(1)], %l5 + stn %l5, [%sp + EH_ARGS_OFFSET(2)] /* copy 8th syscall arg */ +#if !defined(__sparcv9) + cmp %l4, 0x9 + bl,pt %ncc, args_copied + nop + ldn [%fp + EH_ARGS_OFFSET(2)], %l5 + stn %l5, [%sp + EH_ARGS_OFFSET(3)] /* copy 9th syscall arg */ +#endif /* !__sparcv9 */ + +args_copied: + /* + * The first parameter to the emulation callback function is a + * pointer to a sysret_t structure. + * + * invoke the emulation routine. + */ + ALTENTRY(brand_handler_savepc) + call %l2 + add %sp, EH_LOCALS_SYSRET, %o0 /* arg0 == sysret_t ptr */ + + /* Check for syscall emulation success or failure */ + cmp %g0, %o0 + be success + nop + subcc %g0, 1, %g0 /* failure, set carry flag */ + ba return + mov %o0, %i0 /* return, %o0 == errno */ + +success: + /* There is always at least one return value. */ + ldn [%sp + EH_LOCALS_SYSRET1], %i0 /* %i0 == sys_rval1 */ + cmp %l3, RV_DEFAULT /* check rv flag */ + be,a clear_carry + mov %g0, %i1 /* clear second rval */ + ldn [%sp + EH_LOCALS_SYSRET2], %i1 /* %i1 == sys_rval2 */ +clear_carry: + addcc %g0, %g0, %g0 /* success, clear carry flag */ + +return: + /* + * Our syscall emulation is complete. Return to the caller that + * originally invoked a system which needed emulation. Note that + * we have to load the return address that we saved earlier because + * it's possible that %g5 was overwritten by a nested call into + * this emulation library. + */ + ldn [%sp + EH_LOCALS_GREG(REG_nPC)], %g5 + jmp %g5 + restore /* delay slot */ + SET_SIZE(brand_handler) + + +#endif /* !lint */ diff --git a/usr/src/lib/brand/shared/brand/sparc/runexe.s b/usr/src/lib/brand/shared/brand/sparc/runexe.s new file mode 100644 index 0000000000..b29c416122 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/sparc/runexe.s @@ -0,0 +1,81 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include + +#if defined(lint) + +/*ARGSUSED*/ +void +brand_runexe(void *argv, ulong_t entry) +{ +} + +#else /* lint */ + .section ".text" + ENTRY_NP(brand_runexe) + /* + * Prepare to jump to the target program we actually want to run. + * If this program is dynamically linked then we'll be jumping to + * another copy of the linker. If it's a statically linked program + * we'll be jumping directy to it's main entry point. In any case, + * we need to reset our current state stack and register state to + * something similar to the initial process state setup by the kernel + * and documented at: + * usr/src/cmd/sgs/rtld/sparc/boot.s + * usr/src/cmd/sgs/rtld/sparcv9/boot.s + * + * Of course this is the same stack format as when this executable + * was first started, so here we'll just roll back the stack and + * frame pointers to their values when this processes first started + * execution. + * + * Our input parameters are stored in the %o? registers since we + * don't bother to allocate a new stack frame. + */ + sub %o0, CPTRSIZE + WINDOWSIZE + STACK_BIAS, %sp + clr %fp + + /* + * We also have to make sure to clear %g1 since nornally ld.so.1 will + * set that to non-zero if there is an exit function that should be + * invoked when the process is terminating. This isn't actually + * necessary if the target program we're jumping to is a dynamically + * linked program since in that case we're actually jumping to another + * copy of ld.so.1 and it will just reset %g1, but if the target + * program we're jumping to is a statically linked binary that uses + * the standard sun compiler supplied crt1.o`_start(), it will check + * to see if %g1 is set. + */ + clr %g1 + + jmp %o1 ! jump to the target processes entry point + nop + /* + * target will never return. + */ + SET_SIZE(brand_runexe) +#endif /* lint */ diff --git a/usr/src/lib/brand/shared/brand/sparcv9/Makefile b/usr/src/lib/brand/shared/brand/sparcv9/Makefile new file mode 100644 index 0000000000..82473698ab --- /dev/null +++ b/usr/src/lib/brand/shared/brand/sparcv9/Makefile @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +ISASRCDIR = ../sparc + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +ASFLAGS_$(CURTYPE) += ${AS_PICFLAGS} + +install: all + echo $(PICS) diff --git a/usr/src/lib/brand/shared/brand/sys/brand_misc.h b/usr/src/lib/brand/shared/brand/sys/brand_misc.h new file mode 100644 index 0000000000..483c8976f1 --- /dev/null +++ b/usr/src/lib/brand/shared/brand/sys/brand_misc.h @@ -0,0 +1,232 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _BRAND_MISC_H +#define _BRAND_MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This header file must uses _ASM defines to allow it to be included + * in assmebly source files + */ +#include +#include +#include +#if !defined(_ASM) +#include +#endif +#include "assym.h" + +/* + * Our syscall emulation callback handler adds one argument to each + * system call, so we'll need to allocate space for one more argument + * above the maximum number of arguments that a system call can normally + * take. Also, we assume that each syscall argument is a long, ie, we + * don't support long long syscall parameters. + */ +#if defined(__sparc) +/* + * 32-bit and 64-bit sparc syscalls can take up to 8 arguments. + * 32-bit sparc indirect syscalls can take up to 9 arguments. + * Arguments 1 - 6 are passed via %o0 - %o5. + * Additional arguments are passed on the stack. + * So make space for 4 arguments on the stack. + */ +#define EH_ARGS_COUNT 4 +#elif defined(__amd64) +/* + * amd64 syscalls can take up to 8 arguments. + * Arguments 1 - 6 are passed via: %rdi, %rsi, %rdx, %r10, %r8, %r9 + * Additional arguments are passed on the stack. + * So make space for 3 arguments on the stack. + */ +#define EH_ARGS_COUNT 3 +#else /* !__sparc && !__amd64 */ +/* + * ia32 syscalls can take up to 8 arguments. + * All arguments are passed on the stack. + * So make space for 9 arguments on the stack. + */ +#define EH_ARGS_COUNT 9 +#endif /* !__sparc && !__amd64 */ + + +#define EH_ARGS_SIZE (CPTRSIZE * EH_ARGS_COUNT) +#define EH_ARGS_OFFSET(x) (STACK_BIAS + MINFRAME + (CPTRSIZE * (x))) +#define EH_LOCALS_SIZE (EH_ARGS_SIZE + SIZEOF_GREGSET_T + \ + SIZEOF_SYSRET_T + CPTRSIZE) + +#if defined(__sparc) +/* + * On sparc, all emulation callback handler variable access is done + * relative to %sp, so access offsets are positive. + */ +#define EH_LOCALS_START (STACK_BIAS + MINFRAME + EH_ARGS_SIZE) +#define EH_LOCALS_END_TGT (STACK_BIAS + MINFRAME + EH_LOCALS_SIZE) +#else /* !__sparc */ +/* + * On x86, all emulation callback handler variable access is done + * relative to %ebp/%rbp, so access offsets are negative. + */ +#define EH_LOCALS_START (-(EH_LOCALS_SIZE - \ + (STACK_BIAS + MINFRAME + EH_ARGS_SIZE))) +#define EH_LOCALS_END_TGT 0 +#endif /* !__sparc */ + +/* + * In our emulation callback handler, our stack will look like: + * ------------------------------------------------- + * %bp | long rvflag | + * | | sysret_t sysret | + * v | gregset_t gregs | + * %sp | long callback args[EH_ARGS_COUNT] | + * ------------------------------------------------- + * For ia32, use %ebp and %esp instead of %bp and %sp. + * For amd64, use %rbp and %rsp instead of %bp and %sp. + * + * Our emulation callback handler always saves enough space to hold the + * maximum number of stack arguments to a system call. This is architecture + * specific and is defined via EH_ARGS_COUNT. + */ +#define EH_LOCALS_GREGS (EH_LOCALS_START) +#define EH_LOCALS_GREG(x) (EH_LOCALS_GREGS + (SIZEOF_GREG_T * (x))) +#define EH_LOCALS_SYSRET (EH_LOCALS_GREGS + SIZEOF_GREGSET_T) +#define EH_LOCALS_SYSRET1 (EH_LOCALS_SYSRET) +#define EH_LOCALS_SYSRET2 (EH_LOCALS_SYSRET + CPTRSIZE) +#define EH_LOCALS_RVFLAG (EH_LOCALS_SYSRET + SIZEOF_SYSRET_T) +#define EH_LOCALS_END (EH_LOCALS_RVFLAG + CPTRSIZE) + +#if (EH_LOCALS_END != EH_LOCALS_END_TGT) +#error "brand_misc.h EH_LOCALS_* macros don't add up" +#endif /* (EH_LOCALS_END != EH_LOCALS_END_TGT) */ + +/* + * The second parameter of each entry in the {BRAND}_sysent_table + * contains the number of parameters and flags that describe the + * syscall return value encoding. + * + * When declaring new syscall emulation functions, it is very important + * to to set the proper RV_* flags in the brand_sysent_table. Upon failure, + * syscall emulation fuctions should return an errno value. Upon success + * syscall emulation functions should return 0 and set the sysret_t return + * value parameters accordingly. + * + * There are five possible syscall macro wrappers used in the kernel's system + * call sysent table. These turn into the following return values: + * SYSENT_CL -> SYSENT_C or SYSENT_CI + * SYSENT_C SE_64RVAL RV_DEFAULT + * SYSENT_CI SE_32RVAL1 RV_DEFAULT + * SYSENT_2CI SE_32RVAL1|SE_32RVAL2 RV_32RVAL2 + * SYSENT_AP SE_64RVAL RV_64RVAL + * + */ +#define NARGS_MASK 0x000000FF /* Mask for syscalls argument count */ +#define RV_MASK 0x0000FF00 /* Mask for return value flags */ +#define RV_DEFAULT 0x00000100 /* syscall returns "default" values */ +#define RV_32RVAL2 0x00000200 /* syscall returns two 32-bit values */ +#define RV_64RVAL 0x00000400 /* syscall returns a 64-bit value */ + +#if !defined(_ASM) + +/* + * We define our own version of assert because the default one will + * try to emit a localized message. That is bad because first, we can't + * emit messages to random file descriptors, and second localizing a message + * requires allocating memory and we can't do that either. + */ +#define brand_assert(ex) (void)((ex) || \ + (_brand_abort(0, #ex, __FILE__, __LINE__), 0)) +#define brand_abort(err, msg) _brand_abort((err), (msg), __FILE__, __LINE__) +#define EMULATE(cb, args) { (sysent_cb_t)(cb), (args) } +#define NOSYS EMULATE(brand_unimpl, (0 | RV_DEFAULT)) + +typedef long (*sysent_cb_t)(); +typedef struct brand_sysent_table { + sysent_cb_t st_callc; + uintptr_t st_args; +} brand_sysent_table_t; + +/* + * These macros invoke a brandsys subcommand, B_TRUSS_POINT, used to expose + * a call to an interpositioned syscall that would have otherwise gone + * unnoticed by truss(1) because the interpositioned system call did not call + * any system calls before returning. + */ +#define B_TRUSS_POINT_5(rval, syscall_num, err, a0, a1, a2, a3, a4) \ + __systemcall(rval, SYS_brand + 1024, \ + B_TRUSS_POINT, (syscall_num), (err), (a0), (a1), (a2), (a3), \ + (a4)) + +#define B_TRUSS_POINT_4(rval, syscall_num, err, a0, a1, a2, a3) \ + B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), (a2), (a3), 0) + +#define B_TRUSS_POINT_3(rval, syscall_num, err, a0, a1, a2) \ + B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), (a2), 0, 0) + +#define B_TRUSS_POINT_2(rval, syscall_num, err, a0, a1) \ + B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), 0, 0, 0) + +#define B_TRUSS_POINT_1(rval, syscall_num, err, a0) \ + B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), 0, 0, 0, 0) + +#define B_TRUSS_POINT_0(rval, syscall_num, err) \ + B_TRUSS_POINT_5(rval, (syscall_num), (err), 0, 0, 0, 0, 0) + +/* + * From runexe.s + */ +extern void brand_runexe(void *, ulong_t); + +/* + * From handler.s + */ +extern void brand_handler_table(void); +extern void brand_handler(void); +extern void brand_error(void); +extern void brand_success(void); + +/* + * From brand_util.c + */ +extern long brand_unimpl(sysret_t *rv, uintptr_t p1); +extern void _brand_abort(int, const char *, const char *, int); +extern int brand_uucopy(const void *, void *, size_t); +extern int brand_uucopystr(const void *, void *, size_t); +extern void brand_pre_init(); +extern ulong_t brand_post_init(int, int, char **, char **); +#if defined(__sparc) && !defined(__sparcv9) +extern long brand_indir(sysret_t *, int, uintptr_t, uintptr_t, uintptr_t, + uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); +#endif /* __sparc && !__sparcv9 */ + +#endif /* !_ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BRAND_MISC_H */ diff --git a/usr/src/lib/brand/shared/common.ksh b/usr/src/lib/brand/shared/common.ksh deleted file mode 100644 index 95abe86351..0000000000 --- a/usr/src/lib/brand/shared/common.ksh +++ /dev/null @@ -1,1086 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# Send the error message to the screen and to the logfile. -# -error() -{ - typeset fmt="$1" - shift - - printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@" - [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2 -} - -fatal() -{ - typeset fmt="$1" - shift - - error "$fmt" "$@" - exit $EXIT_CODE -} - -fail_fatal() { - printf "ERROR: " - printf "$@" - printf "\n" - exit $ZONE_SUBPROC_FATAL -} - -# -# Send the provided printf()-style arguments to the screen and to the logfile. -# -log() -{ - typeset fmt="$1" - shift - - printf "${MSG_PREFIX}${fmt}\n" "$@" - [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2 -} - -# -# Print provided text to the screen if the shell variable "OPT_V" is set. -# The text is always sent to the logfile. -# -vlog() -{ - typeset fmt="$1" - shift - - [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@" - [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2 -} - -# -# Validate that the directory is safe. -# -# It is possible for a malicious zone root user to modify a zone's filesystem -# so that modifications made to the zone's filesystem by administrators in the -# global zone modify the global zone's filesystem. We can prevent this by -# ensuring that all components of paths accessed by scripts are real (i.e., -# non-symlink) directories. -# -# NOTE: The specified path should be an absolute path as would be seen from -# within the zone. Also, this function does not check parent directories. -# If, for example, you need to ensure that every component of the path -# '/foo/bar/baz' is a directory and not a symlink, then do the following: -# -# safe_dir /foo -# safe_dir /foo/bar -# safe_dir /foo/bar/baz -# -safe_dir() -{ - typeset dir="$1" - - if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then - fatal "$e_baddir" "$dir" - fi -} - -# Like safe_dir except the dir doesn't have to exist. -safe_opt_dir() -{ - typeset dir="$1" - - [[ ! -e $ZONEROOT/$dir ]] && return - - if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then - fatal "$e_baddir" "$dir" - fi -} - -# Only make a copy if we haven't already done so. -safe_backup() -{ - typeset src="$1" - typeset dst="$2" - - if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then - /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src" - fi -} - -# Make a copy even if the destination already exists. -safe_copy() -{ - typeset src="$1" - typeset dst="$2" - - if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then - /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src" - fi -} - -# Move a file -safe_move() -{ - typeset src="$1" - typeset dst="$2" - - if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then - /usr/bin/mv $src $dst || fatal "$e_badfile" "$src" - fi -} - -safe_rm() -{ - if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then - rm -f "$ZONEROOT/$1" - fi -} - -# -# Replace the file with a wrapper pointing to the native brand code. -# However, we only do the replacement if the file hasn't already been -# replaced with our wrapper. This function expects the cwd to be the -# location of the file we're replacing. -# -# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm' -# the file before we setup the wrapper while others are hardlinks to rc scripts -# that we need to maintain. -# -safe_replace() -{ - typeset filename="$1" - typeset runname="$2" - typeset mode="$3" - typeset own="$4" - typeset rem="$5" - - if [ -h $filename -o ! -f $filename ]; then - return - fi - - egrep -s "Solaris Brand Replacement" $filename - if [ $? -eq 0 ]; then - return - fi - - safe_backup $filename $filename.pre_p2v - if [ $rem = "remove" ]; then - rm -f $filename - fi - - cat <<-END >$filename || exit 1 - #!/bin/sh - # - # Solaris Brand Replacement - # - # Attention. This file has been replaced with a new version for - # use in a virtualized environment. Modification of this script is not - # supported and all changes will be lost upon reboot. The - # {name}.pre_p2v version of this file is a backup copy of the - # original and should not be deleted. - # - END - - echo ". $runname \"\$@\"" >>$filename || exit 1 - - chmod $mode $filename - chown $own $filename -} - -safe_wrap() -{ - typeset filename="$1" - typeset runname="$2" - typeset mode="$3" - typeset own="$4" - - if [ -f $filename ]; then - log "$e_cannot_wrap" "$filename" - exit 1 - fi - - cat <<-END >$filename || exit 1 - #!/bin/sh - # - # Solaris Brand Wrapper - # - # Attention. This file has been created for use in a - # virtualized environment. Modification of this script - # is not supported and all changes will be lost upon reboot. - # - END - - echo ". $runname \"\$@\"" >>$filename || exit 1 - - chmod $mode $filename - chown $own $filename -} - -# -# Read zonecfg ipd and fs entries and save the relevant data, one entry per -# line. -# This assumes the properties from the zonecfg output, e.g.: -# inherit-pkg-dir: -# dir: /usr -# fs: -# dir: /opt -# special: /opt -# raw not specified -# type: lofs -# options: [noexec,ro,noatime] -# -# and it assumes the order of the fs properties as above. This also saves the -# inherit-pkg-dir patterns into the ipd.{cpio|pax} temporary files for -# filtering while extracting the image into the zonepath. We have to save the -# IPD patterns in the appropriate format for filtering with the different -# archivers and we don't know what format we'll get until after the flash -# archive is unpacked. -# -get_fs_info() -{ - zonecfg -z $zonename info inherit-pkg-dir | \ - nawk -v ipdcpiof=$ipdcpiofile -v ipdpaxf=$ipdpaxfile '{ - if ($1 == "dir:") { - dir=$2; - printf("%s lofs %s ro\n", dir, dir); - - if (substr(dir, 1, 1) == "/") { - printf("%s\n", substr(dir, 2)) >> ipdcpiof - printf("%s/*\n", substr(dir, 2)) >> ipdcpiof - } else { - printf("%s\n", dir) >> ipdcpiof - printf("%s/*\n", dir) >> ipdcpiof - } - - if (substr(dir, 1, 1) == "/") { - printf("%s ", substr(dir, 2)) >> ipdpaxf - } else { - printf("%s ", dir) >> ipdpaxf - } - } - }' >> $fstmpfile - - zonecfg -z $zonename info fs | nawk '{ - if ($1 == "options:") { - # Remove brackets. - options=substr($2, 2, length($2) - 2); - printf("%s %s %s %s\n", dir, type, special, options); - } else if ($1 == "dir:") { - dir=$2; - } else if ($1 == "special:") { - special=$2; - } else if ($1 == "type:") { - type=$2 - } - }' >> $fstmpfile -} - -# -# Mount zonecfg fs entries into the zonepath. -# -mnt_fs() -{ - if [ ! -s $fstmpfile ]; then - return; - fi - - # Sort the fs entries so we can handle nested mounts. - sort $fstmpfile | nawk -v zonepath=$zonepath '{ - if (NF == 4) - options="-o " $4; - else - options="" - - # Create the mount point. Ignore errors since we might have - # a nested mount with a pre-existing mount point. - cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1" - system(cmd); - - cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \ - zonepath "/root" $1; - if (system(cmd) != 0) { - printf("command failed: %s\n", cmd); - exit 1; - } - }' >>$LOGFILE -} - -# -# Unmount zonecfg fs entries from the zonepath. -# -umnt_fs() -{ - if [ ! -s $fstmpfile ]; then - return; - fi - - # Reverse sort the fs entries so we can handle nested unmounts. - sort -r $fstmpfile | nawk -v zonepath=$zonepath '{ - cmd="/usr/sbin/umount " zonepath "/root" $1 - if (system(cmd) != 0) { - printf("command failed: %s\n", cmd); - } - }' >>$LOGFILE -} - -# Find the dataset mounted on the zonepath. -get_zonepath_ds() { - ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \ - /usr/bin/nawk -v zonepath=$1 '{ - if ($2 == zonepath) - print $1 - }'` - - if [ -z "$ZONEPATH_DS" ]; then - fail_fatal "$f_no_ds" - fi -} - -# -# Perform any cleanup in the zoneroot after unpacking the archive. -# -post_unpack() -{ - ( cd "$ZONEROOT" && \ - find . \( -type b -o -type c \) -exec rm -f "{}" \; ) -} - -# -# Determine flar compression style from identification file. -# -get_compression() -{ - typeset ident=$1 - typeset line=$(grep "^files_compressed_method=" $ident) - - print ${line##*=} -} - -# -# Determine flar archive style from identification file. -# -get_archiver() -{ - typeset ident=$1 - typeset line=$(grep "^files_archived_method=" $ident) - - print ${line##*=} -} - -# -# Unpack flar into current directory (which should be zoneroot). The flash -# archive is standard input. See flash_archive(4) man page. -# -# We can't use "flar split" since it will only unpack into a directory called -# "archive". We need to unpack in place in order to properly handle nested -# fs mounts within the zone root. This function does the unpacking into the -# current directory. -# -# This code is derived from the gen_split() function in /usr/sbin/flar so -# we keep the same style as the original. -# -install_flar() -{ - typeset result - typeset archiver_command - typeset archiver_arguments - - vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar" - - # Read cookie - read -r input_line - if (( $? != 0 )); then - log "$not_readable" "$install_media" - return 1 - fi - # The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers. - if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then - log "$not_flar" - return 1 - fi - - while [ true ] - do - # We should always be at the start of a section here - read -r input_line - if [[ ${input_line%%=*} != "section_begin" ]]; then - log "$bad_flar" - return 1 - fi - section_name=${input_line##*=} - - # If we're at the archive, we're done skipping sections. - if [[ "$section_name" == "archive" ]]; then - break - fi - - # - # Save identification section to a file so we can determine - # how to unpack the archive. - # - if [[ "$section_name" == "identification" ]]; then - /usr/bin/rm -f identification - while read -r input_line - do - if [[ ${input_line%%=*} == \ - "section_begin" ]]; then - /usr/bin/rm -f identification - log "$bad_flar" - return 1 - fi - - if [[ $input_line == \ - "section_end=$section_name" ]]; then - break; - fi - echo $input_line >> identification - done - - continue - fi - - # - # Otherwise skip past this section; read lines until detecting - # section_end. According to flash_archive(4) we can have - # an arbitrary number of sections but the archive section - # must be last. - # - success=0 - while read -r input_line - do - if [[ $input_line == "section_end=$section_name" ]]; - then - success=1 - break - fi - # Fail if we miss the end of the section - if [[ ${input_line%%=*} == "section_begin" ]]; then - /usr/bin/rm -f identification - log "$bad_flar" - return 1 - fi - done - if (( $success == 0 )); then - # - # If we get here we read to the end of the file before - # seeing the end of the section we were reading. - # - /usr/bin/rm -f identification - log "$bad_flar" - return 1 - fi - done - - # Check for an archive made from a ZFS root pool. - egrep -s "^rootpool=" identification - if (( $? == 0 )); then - /usr/bin/rm -f identification - log "$bad_zfs_flar" - return 1 - fi - - # Get the information needed to unpack the archive. - archiver=$(get_archiver identification) - if [[ $archiver == "pax" ]]; then - # pax archiver specified - archiver_command="/usr/bin/pax" - if [[ -s $ipdpaxfile ]]; then - archiver_arguments="-r -p e -c \ - $(/usr/bin/cat $ipdpaxfile)" - else - archiver_arguments="-r -p e" - fi - elif [[ $archiver == "cpio" || -z $archiver ]]; then - # cpio archived specified OR no archiver specified - use default - archiver_command="/usr/bin/cpio" - archiver_arguments="-icdumfE $ipdcpiofile" - else - # unknown archiver specified - log "$unknown_archiver" $archiver - return 1 - fi - - if [[ ! -x $archiver_command ]]; then - /usr/bin/rm -f identification - log "$cmd_not_exec" $archiver_command - return 1 - fi - - compression=$(get_compression identification) - - # We're done with the identification file - /usr/bin/rm -f identification - - # Extract archive - if [[ $compression == "compress" ]]; then - /usr/bin/zcat | \ - $archiver_command $archiver_arguments 2>/dev/null - else - $archiver_command $archiver_arguments 2>/dev/null - fi - result=$? - - post_unpack - - (( $result != 0 )) && return 1 - - return 0 -} - -# -# Get the archive base. -# -# We must unpack the archive in the right place within the zonepath so -# that files are installed into the various mounted filesystems that are set -# up in the zone's configuration. These are already mounted for us by the -# mntfs function. -# -# Archives can be made of either a physical host's root file system or a -# zone's zonepath. For a physical system, if the archive is made using an -# absolute path (/...) we can't use it. For a zone the admin can make the -# archive from a variety of locations; -# -# a) zonepath itself: This will be a single dir, probably named with the -# zone name, it will contain a root dir and under the root we'll see all -# the top level dirs; etc, var, usr... We must be above the ZONEPATH -# when we unpack the archive but this will only work if the the archive's -# top-level dir name matches the ZONEPATH base-level dir name. If not, -# this is an error. -# -# b) inside the zonepath: We'll see root and it will contain all the top -# level dirs; etc, var, usr.... We must be in the ZONEPATH when we unpack -# the archive. -# -# c) inside the zonepath root: We'll see all the top level dirs, ./etc, -# ./var, ./usr.... This is also the case we see when we get an archive -# of a physical sytem. We must be in ZONEROOT when we unpack the archive. -# -# Note that there can be a directory named "root" under the ZONEPATH/root -# directory. -# -# This function handles the above possibilities so that we reject absolute -# path archives and figure out where in the file system we need to be to -# properly unpack the archive into the zone. It sets the ARCHIVE_BASE -# variable to the location where the achive should be unpacked. -# -get_archive_base() -{ - stage1=$1 - archive=$2 - stage2=$3 - - vlog "$m_analyse_archive" - - base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{ - # Check for an absolute path archive - if (substr($0, 1, 1) == "/") - exit 1 - - if ($1 != ".") - dirs[$1] = 1 - else - dirs[$2] = 1 - } - END { - for (d in dirs) { - cnt++ - if (d == "bin") sawbin = 1 - if (d == "etc") sawetc = 1 - if (d == "root") sawroot = 1 - if (d == "var") sawvar = 1 - } - - if (cnt == 1) { - # If only one top-level dir named root, we are in the - # zonepath, otherwise this must be an archive *of* - # the zonepath so print the top-level dir name. - if (sawroot) - print "*zonepath*" - else - for (d in dirs) print d - } else { - # We are either in the zonepath or in the zonepath/root - # (or at the top level of a full system archive which - # looks like the zonepath/root case). Figure out which - # one. - if (sawroot && !sawbin && !sawetc && !sawvar) - print "*zonepath*" - else - print "*zoneroot*" - } - }'` - - if (( $? != 0 )); then - umnt_fs - fatal "$e_absolute_archive" - fi - - if [[ "$base" == "*zoneroot*" ]]; then - ARCHIVE_BASE=$ZONEROOT - elif [[ "$base" == "*zonepath*" ]]; then - ARCHIVE_BASE=$ZONEPATH - else - # We need to be in the dir above the ZONEPATH but we need to - # validate that $base matches the final component of ZONEPATH. - bname=`basename $ZONEPATH` - - if [[ "$bname" != "$base" ]]; then - umnt_fs - fatal "$e_mismatch_archive" "$base" "$bname" - fi - ARCHIVE_BASE=`dirname $ZONEPATH` - fi -} - -# -# Unpack cpio archive into zoneroot. -# -install_cpio() -{ - stage1=$1 - archive=$2 - - get_archive_base "$stage1" "$archive" "cpio -it" - - cpioopts="-idmfE $ipdcpiofile" - - vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts" - - # Ignore errors from cpio since we expect some errors depending on - # how the archive was made. - ( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts ) - - post_unpack - - return 0 -} - -# -# Unpack pax archive into zoneroot. -# -install_pax() -{ - archive=$1 - - get_archive_base "cat" "$archive" "pax" - - if [[ -s $ipdpaxfile ]]; then - filtopt="-c $(/usr/bin/cat $ipdpaxfile)" - fi - - vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt" - - # Ignore errors from pax since we expect some errors depending on - # how the archive was made. - ( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt ) - - post_unpack - - return 0 -} - -# -# Unpack UFS dump into zoneroot. -# -install_ufsdump() -{ - archive=$1 - - vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\"" - - # - # ufsrestore goes interactive if you ^C it. To prevent that, - # we make sure its stdin is not a terminal. - # Note that there is no way to filter inherit-pkg-dirs for a full - # restore so there will be warnings in the log file. - # - ( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null ) - result=$? - - post_unpack - - return $result -} - -# -# Copy directory hierarchy into zoneroot. -# -install_dir() -{ - source_dir=$1 - - cpioopts="-pdm" - - first=1 - filt=$(for i in $(cat $ipdpaxfile) - do - echo $i | egrep -s "/" && continue - if [[ $first == 1 ]]; then - printf "^%s" $i - first=0 - else - printf "|^%s" $i - fi - done) - - list=$(cd "$source_dir" && ls -d * | egrep -v "$filt") - flist=$(for i in $list - do - printf "%s " "$i" - done) - findopts="-xdev ( -type d -o -type f -o -type l ) -print" - - vlog "cd \"$source_dir\" && find $flist $findopts | " - vlog "cpio $cpioopts \"$ZONEROOT\"" - - # Ignore errors from cpio since we expect some errors depending on - # how the archive was made. - ( cd "$source_dir" && find $flist $findopts | \ - cpio $cpioopts "$ZONEROOT" ) - - post_unpack - - return 0 -} - -# -# This is a common function for laying down a zone image from a variety of -# different sources. This can be used to either install a fresh zone or as -# part of zone migration during attach. -# -# The first argument specifies the type of image: archive, directory or stdin. -# The second argument specifies the image itself. In the case of stdin, the -# second argument specifies the format of the stream (cpio, flar, etc.). -# Any validation or post-processing on the image is done elsewhere. -# -# This function calls a 'sanity_check' function which must be provided by -# the script which includes this code. -# -install_image() -{ - intype=$1 - insrc=$2 - - if [[ -z "$intype" || -z "$insrc" ]]; then - return 1 - fi - - filetype="unknown" - filetypename="unknown" - stage1="cat" - - if [[ "$intype" == "directory" ]]; then - if [[ "$insrc" == "-" ]]; then - # Indicates that the existing zonepath is prepopulated. - filetype="existing" - filetypename="existing" - else - if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then - fatal "$e_path_abs" "$insrc" - fi - - if [[ ! -e "$insrc" ]]; then - log "$e_not_found" "$insrc" - fatal "$e_install_abort" - fi - - if [[ ! -r "$insrc" ]]; then - log "$e_not_readable" "$insrc" - fatal "$e_install_abort" - fi - - if [[ ! -d "$insrc" ]]; then - log "$e_not_dir" - fatal "$e_install_abort" - fi - - sanity_check $insrc - - filetype="directory" - filetypename="directory" - fi - - else - # Common code for both archive and stdin stream. - - if [[ "$intype" == "archive" ]]; then - if [[ ! -f "$insrc" ]]; then - log "$e_unknown_archive" - fatal "$e_install_abort" - fi - ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)" - else - # For intype == stdin, the insrc parameter specifies - # the stream format coming on stdin. - ftype="$insrc" - insrc="-" - fi - - # Setup vars for the archive type we have. - case "$ftype" in - *cpio*) filetype="cpio" - filetypename="cpio archive" - ;; - *bzip2*) filetype="bzip2" - filetypename="bzipped cpio archive" - ;; - *gzip*) filetype="gzip" - filetypename="gzipped cpio archive" - ;; - *ufsdump*) filetype="ufsdump" - filetypename="ufsdump archive" - ;; - "flar") - filetype="flar" - filetypename="flash archive" - ;; - "flash") - filetype="flar" - filetypename="flash archive" - ;; - *Flash\ Archive*) - filetype="flar" - filetypename="flash archive" - ;; - "tar") - filetype="tar" - filetypename="tar archive" - ;; - *USTAR\ tar\ archive) - filetype="tar" - filetypename="tar archive" - ;; - "pax") - filetype="xustar" - filetypename="pax (xustar) archive" - ;; - *USTAR\ tar\ archive\ extended\ format*) - filetype="xustar" - filetypename="pax (xustar) archive" - ;; - "zfs") - filetype="zfs" - filetypename="ZFS send stream" - ;; - *ZFS\ snapshot\ stream*) - filetype="zfs" - filetypename="ZFS send stream" - ;; - *) log "$e_unknown_archive" - fatal "$e_install_abort" - ;; - esac - fi - - vlog "$filetypename" - - # Check for a non-empty root if no '-d -' option. - if [[ "$filetype" != "existing" ]]; then - cnt=$(ls $ZONEROOT | wc -l) - if (( $cnt != 0 )); then - fatal "$e_root_full" "$ZONEROOT" - fi - fi - - fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp) - if [[ -z "$fstmpfile" ]]; then - fatal "$e_tmpfile" - fi - - # Make sure we always have the files holding the directories to filter - # out when extracting from a CPIO or PAX archive. We'll add the fs - # entries to these files in get_fs_info() (there may be no IPDs for - # some brands but thats ok). - ipdcpiofile=$(/usr/bin/mktemp -t -p /var/tmp ipd.cpio.XXXXXX) - if [[ -z "$ipdcpiofile" ]]; then - rm -f $fstmpfile - fatal "$e_tmpfile" - fi - - # In addition to the IPDs, also filter out these directories. - echo 'dev/*' >>$ipdcpiofile - echo 'devices/*' >>$ipdcpiofile - echo 'devices' >>$ipdcpiofile - echo 'proc/*' >>$ipdcpiofile - echo 'tmp/*' >>$ipdcpiofile - echo 'var/run/*' >>$ipdcpiofile - echo 'system/contract/*' >>$ipdcpiofile - echo 'system/object/*' >>$ipdcpiofile - - ipdpaxfile=$(/usr/bin/mktemp -t -p /var/tmp ipd.pax.XXXXXX) - if [[ -z "$ipdpaxfile" ]]; then - rm -f $fstmpfile $ipdcpiofile - fatal "$e_tmpfile" - fi - - printf "%s " \ - "dev devices proc tmp var/run system/contract system/object" \ - >>$ipdpaxfile - - # Set up any fs mounts so the archive will install into the correct - # locations. - get_fs_info - mnt_fs - if (( $? != 0 )); then - umnt_fs >/dev/null 2>&1 - rm -f $fstmpfile $ipdcpiofile $ipdpaxfile - fatal "$mount_failed" - fi - - if [[ "$filetype" == "existing" ]]; then - log "$no_installing" - else - log "$installing" - fi - - # - # Install the image into the zonepath. - # - unpack_result=0 - stage1="cat" - if [[ "$filetype" == "gzip" ]]; then - stage1="gzcat" - filetype="cpio" - elif [[ "$filetype" == "bzip2" ]]; then - stage1="bzcat" - filetype="cpio" - fi - - if [[ "$filetype" == "cpio" ]]; then - install_cpio "$stage1" "$insrc" - unpack_result=$? - - elif [[ "$filetype" == "flar" ]]; then - ( cd "$ZONEROOT" && $stage1 $insrc | install_flar ) - unpack_result=$? - - elif [[ "$filetype" == "xustar" ]]; then - install_pax "$insrc" - unpack_result=$? - - elif [[ "$filetype" = "tar" ]]; then - vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\"" - # Ignore errors from tar since we expect some errors depending - # on how the archive was made. - ( cd "$ZONEROOT" && tar -xf "$insrc" ) - unpack_result=0 - post_unpack - - elif [[ "$filetype" == "ufsdump" ]]; then - install_ufsdump "$insrc" - unpack_result=$? - - elif [[ "$filetype" == "directory" ]]; then - install_dir "$insrc" - unpack_result=$? - - elif [[ "$filetype" == "zfs" ]]; then - # - # Given a 'zfs send' stream file, receive the snapshot into - # the zone's dataset. We're getting the original system's - # zonepath dataset. Destroy the existing dataset created - # above since this recreates it. - # - if [[ -z "$DATASET" ]]; then - fatal "$f_nodataset" - fi - /usr/sbin/zfs destroy "$DATASET" - if (( $? != 0 )); then - log "$f_zfsdestroy" "$DATASET" - fi - - vlog "$stage1 $insrc | zfs receive -F $DATASET" - ( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET ) - unpack_result=$? - fi - - # Clean up any fs mounts used during unpacking. - umnt_fs - rm -f $fstmpfile $ipdcpiofile $ipdpaxfile - - chmod 700 $zonepath - - (( $unpack_result != 0 )) && fatal "$f_unpack_failed" - - # Verify this is a valid image. - sanity_check $ZONEROOT - - return 0 -} - -# Setup i18n output -TEXTDOMAIN="SUNW_OST_OSCMD" -export TEXTDOMAIN - -e_cannot_wrap=$(gettext "%s: error: wrapper file already exists") -e_baddir=$(gettext "Invalid '%s' directory within the zone") -e_badfile=$(gettext "Invalid '%s' file within the zone") -e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.") -e_not_found=$(gettext "%s: error: file or directory not found.") -e_install_abort=$(gettext "Installation aborted.") -e_not_readable=$(gettext "Cannot read directory '%s'") -e_not_dir=$(gettext "Error: must be a directory") -e_unknown_archive=$(gettext "Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.") -e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.") -e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).") -e_tmpfile=$(gettext "Unable to create temporary file") -e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.") -f_mkdir=$(gettext "Unable to create directory %s.") -f_chmod=$(gettext "Unable to chmod directory %s.") -f_chown=$(gettext "Unable to chown directory %s.") - - -m_analyse_archive=$(gettext "Analysing the archive") - -not_readable=$(gettext "Cannot read file '%s'") -not_flar=$(gettext "Input is not a flash archive") -bad_flar=$(gettext "Flash archive is a corrupt") -bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.") -f_unpack_failed=$(gettext "Unpacking the archive failed") -unknown_archiver=$(gettext "Archiver %s is not supported") -cmd_not_exec=$(gettext "Required command '%s' not executable!") - -# -# Exit values used by the script, as #defined in -# -# ZONE_SUBPROC_OK -# =============== -# Installation was successful -# -# ZONE_SUBPROC_USAGE -# ================== -# Improper arguments were passed, so print a usage message before exiting -# -# ZONE_SUBPROC_NOTCOMPLETE -# ======================== -# Installation did not complete, but another installation attempt can be -# made without an uninstall -# -# ZONE_SUBPROC_FATAL -# ================== -# Installation failed and an uninstall will be required before another -# install can be attempted -# -ZONE_SUBPROC_OK=0 -ZONE_SUBPROC_USAGE=253 -ZONE_SUBPROC_NOTCOMPLETE=254 -ZONE_SUBPROC_FATAL=255 - diff --git a/usr/src/lib/brand/shared/librtld_db/Makefile.com b/usr/src/lib/brand/shared/librtld_db/Makefile.com new file mode 100644 index 0000000000..dc34726f4e --- /dev/null +++ b/usr/src/lib/brand/shared/librtld_db/Makefile.com @@ -0,0 +1,76 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include $(SRC)/lib/Makefile.lib + +LIBRARY = $(BRAND)_librtld_db.a +VERS = .1 + +CSRCS = $(COBJS:%o=$(BRAND_SHARED)/librtld_db/common/%c) +SRCS = $(CSRCS) + +SRCDIR = $(BRAND_SHARED)/librtld_db/common +UTSBASE = $(SRC)/uts + +# +# ATTENTION: +# Librtl_db brand plugin libraries should NOT directly invoke any +# libproc.so interfaces or be linked against libproc. If a librtl_db +# brand plugin library uses libproc.so interfaces then it may break +# any other librtld_db consumers (like mdb) that tries to attach +# to a branded process. The only safe interfaces that the a librtld_db +# brand plugin library can use to access a target process are the +# proc_service(3PROC) apis. +# +DYNFLAGS += $(VERSREF) -M$(BRAND_SHARED)/librtld_db/common/mapfile-vers +LIBS = $(DYNLIB) +LDLIBS += -lc -lrtld_db +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT \ + -I$(SRC)/cmd/sgs/librtld_db/common \ + -I$(SRC)/cmd/sgs/include \ + -I$(SRC)/cmd/sgs/include/$(MACH) + +ROOTLIBDIR = $(ROOT)/usr/lib/brand/$(BRAND) +ROOTLIBDIR64 = $(ROOT)/usr/lib/brand/$(BRAND)/$(MACH64) + +# +# The top level Makefiles define define TEXT_DOMAIN. But librtld_db.so.1 +# isn't internationalized and this library won't be either. The only +# messages that this library can generate are messages used for debugging +# the operation of the library itself. +# +DTEXTDOM = + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +pics/%64.o: $(BRAND_SHARED)/librtld_db/common/%.c + $(COMPILE.c) -D_ELF64 $(PICFLAGS) -o $@ $< + $(POST_PROCESS_O) + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/brand/shared/librtld_db/common/brand_librtld_db.c b/usr/src/lib/brand/shared/librtld_db/common/brand_librtld_db.c new file mode 100644 index 0000000000..e428330c8f --- /dev/null +++ b/usr/src/lib/brand/shared/librtld_db/common/brand_librtld_db.c @@ -0,0 +1,297 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ATTENTION: + * Librtl_db brand plugin libraries should NOT directly invoke any + * libproc.so interfaces or be linked against libproc. If a librtl_db + * brand plugin library uses libproc.so interfaces then it may break + * any other librtld_db consumers (like mdb) that tries to attach + * to a branded process. The only safe interfaces that the a librtld_db + * brand plugin library can use to access a target process are the + * proc_service(3PROC) apis. + */ + +/* + * M_DATA comes from some streams header file but is also redifined in + * _rtld_db.h, so nuke the old streams definition here. + */ +#ifdef M_DATA +#undef M_DATA +#endif /* M_DATA */ + +/* + * For 32-bit versions of this library, this file get's compiled once. + * For 64-bit versions of this library, this file get's compiled twice, + * once with _ELF64 defined and once without. The expectation is that + * the 64-bit version of the library can properly deal with both 32-bit + * and 64-bit elf files, hence in the 64-bit library there are two copies + * of all the interfaces in this file, one set named *32 and one named *64. + * + * This also means that we need to be careful when declaring local pointers + * that point to objects in another processes address space, since these + * pointers may not match the current processes pointer width. Basically, + * we should not use any objects that change size between 32 and 64 bit + * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc. + * Instead we should declare all pointers as uint32_t. Then when we + * are compiled to deal with 64-bit targets we'll re-define uing32_t + * to be a uint64_t. + */ +#ifdef _LP64 +#ifdef _ELF64 +#define uint32_t uint64_t +#define Elf32_Dyn Elf64_Dyn +#define validate_rdebug32 validate_rdebug64 +#define _rd_loadobj_iter32 _rd_loadobj_iter64 +#define _rd_get_dyns32 _rd_get_dyns64 +#define dummy_ldb32 dummy_ldb64 +#define dummy_ldb_init32 dummy_ldb_init64 +#define dummy_ldb_fini32 dummy_ldb_fini64 +#define dummy_ldb_loadobj_iter32 dummy_ldb_loadobj_iter64 +#define dummy_ldb_get_dyns32 dummy_ldb_get_dyns64 +#define brand_ldb_init32 brand_ldb_init64 +#define brand_ldb_fini32 brand_ldb_fini64 +#define brand_ldb_loadobj_iter32 brand_ldb_loadobj_iter64 +#define brand_ldb_get_dyns32 brand_ldb_get_dyns64 +#endif /* _ELF64 */ +#endif /* _LP64 */ + +/* Included from usr/src/cmd/sgs/librtld_db/common */ +#include <_rtld_db.h> + +/*ARGSUSED*/ +static rd_helper_data_t +dummy_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) +{ + return (NULL); +} + +/*ARGSUSED*/ +static void +dummy_ldb_fini32(rd_helper_data_t rhd) +{ +} + +/*ARGSUSED*/ +static int +dummy_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) +{ + return (RD_OK); +} + +/*ARGSUSED*/ +static rd_err_e +dummy_ldb_get_dyns32(rd_helper_data_t rhd, + psaddr_t addr, void **dynpp, size_t *dynpp_sz) +{ + *dynpp = NULL; + *dynpp_sz = 0; + return (RD_OK); +} + +static rd_helper_ops_t dummy_ldb32 = { + LM_ID_BRAND, + dummy_ldb_init32, + dummy_ldb_fini32, + dummy_ldb_loadobj_iter32, + dummy_ldb_get_dyns32 +}; + +static uint32_t +brand_ldb_getauxval32(struct ps_prochandle *php, int type) +{ + const auxv_t *auxvp = NULL; + + if (ps_pauxv(php, &auxvp) != PS_OK) + return ((uint32_t)-1); + + while (auxvp->a_type != AT_NULL) { + if (auxvp->a_type == type) + return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr); + auxvp++; + } + return ((uint32_t)-1); +} + +/* + * Normally, the native Solaris librtldb_db plugin uses a bunch of different + * methods to try and find the rdebug structure associated with the target + * process we're debugging. For details on the different methods see + * _rd_reset32(). Thankfully our job is easier. We know that the brand + * library is always linked against the native linker, and when the + * process was first executed we saved off a pointer to the brand linkers + * rdebug structure in one of our brand specific aux vectors, + * AT_SUN_BRAND_COMMON_LDDATA. So we'll just look that up here. + */ +/*ARGSUSED*/ +static rd_helper_data_t +brand_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) +{ + struct rd_agent *rap_new; + uint32_t lddata_addr; + int rd_dmodel; + + if (ps_pdmodel(php, &rd_dmodel) != PS_OK) { + ps_plog("brand_ldb_init: lookup of data model failed"); + return (NULL); + } +#ifdef _ELF64 + assert(rd_dmodel == PR_MODEL_LP64); +#else /* !_ELF64 */ + assert(rd_dmodel == PR_MODEL_ILP32); +#endif /* !_ELF64 */ + + lddata_addr = brand_ldb_getauxval32(php, AT_SUN_BRAND_COMMON_LDDATA); + if (lddata_addr == (uint32_t)-1) { + ps_plog("brand_ldb_init: no LDDATA found in aux vector"); + return (NULL); + } + ps_plog("brand_ldb_init: found LDDATA auxv ld.so.1 data seg " + "at: 0x%p", lddata_addr); + + /* + * Ok. So this is kinda ugly. Basically we know that we're going to + * be parsing data from link maps that are generated by a Solaris + * linker. As it turns out, that's exactly what the default + * Solaris librtld_db library is designed to do. So rather than + * duplicate all that link map parsing code here we'll simply + * invoke the native librtld_db that normally does this, and when + * we do we'll point them at our emulation libraries link map. + * + * Of course these interfacess aren't really public interfaces + * and they take a "struct rd_agent" as a parameter. So here + * we'll allocate and initialize a new "struct rd_agent", point + * it at our emulation libraries link map, and initialize just + * enough of the structure to make the librtld_db interfaces + * that we want to use happy. + */ + if ((rap_new = calloc(sizeof (*rap_new), 1)) == NULL) { + ps_plog("brand_ldb_init: can't allocate memory"); + return (NULL); + } + rap_new->rd_dmodel = rd_dmodel; + rap_new->rd_psp = php; + rap_new->rd_rdebug = lddata_addr; + (void) mutex_init(&rap_new->rd_mutex, USYNC_THREAD, 0); + + /* + * When we get invoked from librtld_db, and we call back into it, + * librtld_db will once again check if there is a plugin and + * invoke it. Since we don't want to enter a recursive loop + * we're going to specify a different plugin interface for + * our linkmap, and these new plugin interfaces won't actually + * do anything other than return. + */ + rap_new->rd_helper.rh_ops = &dummy_ldb32; + + /* + * validate_rdebug32() requires the following "struct rd_agent" + * members to be initialized: + * rd_psp, rd_rdebug + * + * validate_rdebug32() initializes the following "struct rd_agent" + * members: + * rd_flags, rd_rdebugvers, rd_rtlddbpriv + */ + if (validate_rdebug32(rap_new) != RD_OK) { + ps_plog("brand_ldb_init: can't find valid r_debug data"); + free(rap_new); + return (NULL); + } + + ps_plog("brand_ldb_init: finished, helper_data=0x%p", rap_new); + return ((rd_helper_data_t)rap_new); +} + +static void +brand_ldb_fini32(rd_helper_data_t rhd) +{ + struct rd_agent *rap = (struct rd_agent *)rhd; + ps_plog("brand_ldb_fini: cleaning up brand helper"); + free(rap); +} + +/*ARGSUSED*/ +static int +brand_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) +{ + struct rd_agent *rap = (struct rd_agent *)rhd; + int err; + + ps_plog("brand_ldb_loadobj_iter(helper_data=0x%p)", rhd); + assert(rap->rd_psp == php); + RDAGLOCK(rap); + /* + * _rd_loadobj_iter32() requires the following "struct rd_agent" + * members to be initialized: + * rd_rtlddbpriv, rd_rdebugvers, rd_flags, + * rd_helper.rh_ops, rd_dmodel + */ + err = _rd_loadobj_iter32(rap, cb, client_data); + RDAGUNLOCK(rap); + ps_plog("brand_ldb_loadobj_iter: finished, err = %d", err); + return (err); +} + +/*ARGSUSED*/ +static rd_err_e +brand_ldb_get_dyns32(rd_helper_data_t rhd, + psaddr_t addr, void **dynpp, size_t *dynpp_sz) +{ + struct rd_agent *rap = (struct rd_agent *)rhd; + int err; + + ps_plog("brand_ldb_get_dyns(helper_data=0x%p)", rhd); + err = _rd_get_dyns32(rap, addr, (Elf32_Dyn **)dynpp, dynpp_sz); + ps_plog("brand_ldb_get_dyns: finished, err = %d", err); + return (err); +} + +/* + * Librtld_db plugin linkage struct. + * + * When we get loaded by librtld_db, it will look for the symbol below + * to find our plugin entry points. + */ +rd_helper_ops_t RTLD_DB_BRAND_OPS = { + LM_ID_NONE, + brand_ldb_init32, + brand_ldb_fini32, + brand_ldb_loadobj_iter32, + brand_ldb_get_dyns32 +}; diff --git a/usr/src/lib/brand/shared/librtld_db/common/mapfile-vers b/usr/src/lib/brand/shared/librtld_db/common/mapfile-vers new file mode 100644 index 0000000000..571267a133 --- /dev/null +++ b/usr/src/lib/brand/shared/librtld_db/common/mapfile-vers @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNWprivate_1.1 { + global: + rtld_db_brand_ops32; + local: + *; +}; + +#Externally defined symbols +{ + global: + ps_pauxv = NODIRECT PARENT; + ps_pdmodel = NODIRECT PARENT; + ps_pglobal_lookup = NODIRECT PARENT; + ps_pglobal_sym = NODIRECT PARENT; + ps_plog = NODIRECT PARENT; + ps_pread = NODIRECT PARENT; + ps_pwrite = NODIRECT PARENT; +}; diff --git a/usr/src/lib/brand/shared/librtld_db/common/mapfile-vers.64 b/usr/src/lib/brand/shared/librtld_db/common/mapfile-vers.64 new file mode 100644 index 0000000000..ca437818fc --- /dev/null +++ b/usr/src/lib/brand/shared/librtld_db/common/mapfile-vers.64 @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNWprivate_1.1 { + global: + rtld_db_brand_ops64; +}; diff --git a/usr/src/lib/brand/shared/query.ksh b/usr/src/lib/brand/shared/query.ksh deleted file mode 100644 index fe79f1bc71..0000000000 --- a/usr/src/lib/brand/shared/query.ksh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/ksh -p -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -PATH=/usr/bin:/usr/sbin -export PATH - -. /usr/lib/brand/shared/common.ksh - -zonename=$1 -zonepath=$2 -cmd=$3 - -if [ $3 == "datasets" ]; then - get_zonepath_ds $zonepath - - DS=`/usr/sbin/zfs list -H -t filesystem -o name $ZONEPATH_DS/ROOT` - if [ ! -z "$DS" ]; then - echo "$DS\c" - else - fail_fatal "$f_no_ds" - fi -fi - -exit $ZONE_SUBPROC_OK diff --git a/usr/src/lib/brand/shared/uninstall.ksh b/usr/src/lib/brand/shared/uninstall.ksh deleted file mode 100644 index 0ad45a790d..0000000000 --- a/usr/src/lib/brand/shared/uninstall.ksh +++ /dev/null @@ -1,721 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# get script name (bname) -# -bname=`basename $0` - -# -# common shell script functions -# -. /usr/lib/brand/shared/common.ksh - -# -# error messages -# -m_usage=$(gettext "Usage: %s: [-hFn]") - -m_1_zfs_promote=$(gettext "promoting '%s'.") -m_1_zfs_destroy=$(gettext "destroying '%s'.") -m_2_zfs_rename=$(gettext "renaming '%s' to '%s'.") -m_3_zfs_set=$(gettext "setting property %s='%s' for '%s'.") -m_rm_r=$(gettext "recursively deleting '%s'.") -m_rm=$(gettext "deleting '%s'.") - -w_no_ds=$(gettext "Warning: no zonepath dataset found.") - -f_usage_err=$(gettext "Error: invalid usage") -f_abort=$(gettext "Error: internal error detected, aborting.") -f_1_zfs_promote=$(gettext "Error: promoting ZFS dataset '%s'.") -f_2_zfs_rename=$(gettext "Error: renaming ZFS dataset '%s' to '%s'.") -f_3_zfs_set=$(gettext "Error: setting ZFS propery %s='%s' for '%s'.") -f_1_zfs_destroy=$(gettext "Error: destroying ZFS dataset.") -f_2_zfs_get=$(gettext "Error: reading ZFS dataset property '%s' from '%s'.") -f_user_snap=$(gettext "Error: user snapshot(s) detected.") -f_stray_snap=$(gettext "Error: uncloned snapshot(s) detected.") -f_stray_clone=$(gettext "Error: cloned zone datasets found outsize of zone.") -f_rm_snap=$(gettext "Error: please delete snapshot(s) and retry uninstall.") -f_rm_clone=$(gettext "Error: please delete clone(s) and retry uninstall.") -f_iu_clone=$(gettext "Error: cloned zone dataset(s) in use.") -f_dis_clone=$(gettext "Error: please stop using clone(s) and retry uninstall.") - -# -# functions -# -print_array() -{ - typeset -n pa_array=$1 - - (( pa_i = 0 )) - while (( $pa_i < ${#pa_array[@]} )); do - printf "\t${pa_array[$pa_i]}\n" - (( pa_i = $pa_i + 1 )) - done -} - -usage() -{ - printf "$m_usage\n" "$bname" - exit $ZONE_SUBPROC_USAGE -} - -usage_err() -{ - printf "$f_usage_err\n" >&2 - usage >&2 -} - -rm_zonepath() -{ - # cleanup stuff we know about and leave any user data alone - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_rm\n" "$zonepath/SUNWattached.xml" - $nop /bin/rm -f "$zonepath/SUNWattached.xml" - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_rm_r\n" "$zonepath/lu" - $nop /bin/rm -rf "$zonepath/lu" - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_rm_r\n" "$zonepath/dev" - $nop /bin/rm -rf "$zonepath/dev" - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_rm_r\n" "$zonepath/root" - $nop /bin/rm -rf "$zonepath/root" - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_rm\n" "$zonepath" - $nop /bin/rmdir "$zonepath" 2>/dev/null -} - -zfs_destroy() -{ - zd_fs1="$1" - - # first figure out if the target fs has an origin snapshot - zd_origin=`/sbin/zfs get -H -o value origin "$zd_fs1"` - if [[ $? != 0 ]]; then - printf "$f_2_zfs_get\n" origin "$zd_fs1" >&2 - exit $ZONE_SUBPROC_FATAL - fi - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_1_zfs_destroy\n" "$zd_fs1" - - # - # note that we specify the '-r' flag so that we destroy any - # descendants (filesystems and snapshot) of the specified - # filesystem. - # - $nop /sbin/zfs destroy -r "$zd_fs1" - if [[ $? != 0 ]]; then - printf "$f_1_zfs_destroy\n" "$zd_fs1" >&2 - exit $ZONE_SUBPROC_FATAL - fi - - [[ "$zd_origin" == "-" ]] && return - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_1_zfs_destroy\n" "$zd_origin" - - $nop /sbin/zfs destroy "$zd_origin" 2>/dev/null - # - # we ignore errors while trying to destroy the origin since - # the origin could have been used as the source for other - # clones - # -} - -zfs_promote() -{ - zp_fs1="$1" - - [[ -z "$opt_n" ]] && - printf "$m_1_zfs_promote\n" "$zp_fs1" - - $nop /sbin/zfs promote "$zp_fs1" - if [[ $? != 0 ]]; then - printf "$f_1_zfs_promote\n" "$zp_fs1" >&2 - exit $ZONE_SUBPROC_FATAL - fi -} - -zfs_rename() -{ - zr_fs1="$1" - zr_fs2="$2" - - [[ -z "$opt_n" ]] && - printf "$m_2_zfs_rename\n" "$zr_fs1" "$zr_fs2" - - $nop /sbin/zfs rename "$zr_fs1" "$zr_fs2" - if [[ $? != 0 ]]; then - printf "$f_2_zfs_rename\n" "$zr_fs1" "$zr_fs2" >&2 - return 1 - fi - return 0 -} - -zfs_set() -{ - zs_prop=$1 - zs_value=$2 - zs_fs1=$3 - - [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && - printf "$m_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1" - - $nop /sbin/zfs set "$zs_prop"="$zs_value" "$zs_fs1" - if [[ $? != 0 ]]; then - printf "$f_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1" - return 1 - fi - return 0 -} - -zfs_set_array() -{ - zsa_prop=$1 - zsa_value=$2 - typeset -n zsa_array=$3 - zsa_ignore_errors=$4 - - (( zsa_i = 0 )) - while (( $zsa_i < ${#zsa_array[@]} )); do - zfs_set "$zsa_prop" "$zsa_value" "${zsa_array[$zsa_i]}" - [[ $? != 0 ]] && [[ -z "$zsa_ignore_errors" ]] && - return 1 - (( zsa_i = $zsa_i + 1 )) - done - return 0 -} - - -(( snap_rename_zbe_i = 1 )) -(( snap_rename_snap_i = 1 )) -snap_rename_init() -{ - (( snap_rename_zbe_i = 1 )) - (( snap_rename_snap_i = 1 )) -} - -snap_rename() -{ - eval sr_fs=\${$1} - eval sr_snap=\${$2} - - if [[ "$sr_snap" == ~(Elr)(zbe-[0-9][0-9]*) ]]; then - sr_snap="zbe-$snap_rename_zbe_i" - (( snap_rename_zbe_i = $snap_rename_zbe_i + 1 )) - elif [[ "$sr_snap" == ~(Er)(_snap[0-9]*) ]]; then - sr_snap=${sr_snap##~(Er)([0-9]*)} - sr_snap="${sr_snap}${snap_rename_snap_i}" - (( snap_rename_snap_i = $snap_rename_snap_i + 1 )) - else - printf "$f_user_snap\n" >&2 - printf "\t$sr_fs@$sr_snap\n" >&2 - printf "$f_rm_snap\n" >&2 - exit $ZONE_SUBPROC_FATAL - fi - - eval $2="$sr_snap" -} - -# find the dataset associated with $zonepath -uninstall_get_zonepath_ds() -{ - ZONEPATH_DS=`/sbin/zfs list -t filesystem -o name,mountpoint | \ - /bin/nawk -v zonepath=$zonepath '{ - if ($2 == zonepath) - print $1 - }'` - - if [ -z "$ZONEPATH_DS" ]; then - # there is no $zonepath dataset - rm_zonepath - exit $ZONE_SUBPROC_OK - fi -} - -# find the dataset associated with $ZONEPATH_DS/ROOT -uninstall_get_zonepath_root_ds() -{ - ZONEPATH_RDS=`/sbin/zfs list -H -t filesystem -o name \ - $ZONEPATH_DS/ROOT 2>/dev/null` - - if [ -z "$ZONEPATH_RDS" ]; then - # there is no $ZONEPATH_DS/ROOT dataset - c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l` - if [ $c = 1 ]; then - # $zonepath dataset has no descendents - zfs_destroy "$ZONEPATH_DS" - fi - rm_zonepath - exit $ZONE_SUBPROC_OK - fi -} - -destroy_zone_dataset() -{ - fs=$1 - - pool=${fs%%/*} - - # Fastpath. if there are no snapshots of $fs then just delete it. - c=`/sbin/zfs list -H -t snapshot -o name -r $fs | grep "^$fs@" | - LC_ALL=C LANG=C wc -l` - if (( $c == 0 )) ; then - zfs_destroy "$fs" - return - fi - - # - # This zone BE has snapshots. This can happen if a zone has - # multiple BEs (in which case we have snapshots named "zbe-XXX"), - # if this zone has been used as the source for a clone of - # another zone (in which case we have snapshots named - # "XXX_snap"), or if an administrator has been doing manual - # snapshotting. - # - # To be able to destroy this dataset (which we'll call the - # origin) we need to get rid of all it's snapshots. The "easiest" - # way to do this is to: - # - # - delete any uncloned origin snapshots - # - find the oldest clone of the youngest origin snapshot (which - # we'll call the oldest clone) - # - check if there are any snapshots naming conflicts between - # the origin and the oldest clone. - # - if so, find any clones of those conflicting origin snapshots - # - make sure that those clones are not zoned an in-use. - # - if any of those clones are zoned, unzone them. - # - rename origin snapshots to eliminate naming conflicts - # - for any clones that we unzoned, rezone them. - # - promote the oldest clone - # - destroy the origin and all it's descendants - # - - # - # Get a list of all the cloned datasets within the zpool - # containing the origin filesystem. Filter out any filesystems - # that are descendants of origin because we are planning to - # destroy them anyway. - # - unset clones clones_origin - (( clones_c = 0 )) - pool=${fs%%/*} - LANG=C LC_ALL=C /sbin/zfs list -H -t filesystem -s creation \ - -o name,origin -r "$pool" | - while IFS=" " read name origin; do - - # skip non-clone filesystems - [[ "$origin" == "-" ]] && - continue - - # skip desendents of the origin we plan to destroy - [[ "$name" == ~()(${fs}/*) ]] && - continue - - # record this clone and it's origin - clones[$clones_c]="$name" - clones_origin[$clones_c]="$origin" - (( clones_c = $clones_c + 1 )) - done - - # - # Now do a sanity check. Search for clones of a child datasets - # of the dataset we want to destroy, that are not themselves - # children of the dataset we're going to destroy). This should - # really never happen unless the global zone admin has cloned a - # snapshot of a zone filesystem to a location outside of that - # zone. bad admin... - # - unset stray_clones - (( stray_clones_c = 0 )) - (( j = 0 )) - while (( $j < $clones_c )); do - # is the clone origin a descendant of $fs? - if [[ "${clones_origin[$j]}" != ~()(${fs}/*) ]]; then - # we don't care. - (( j = $j + 1 )) - continue - fi - stray_clones[$stray_clones_c]=${clones[$j]} - (( stray_clones_c = $stray_clones_c + 1 )) - (( j = $j + 1 )) - done - if (( stray_clones_c > 0 )); then - # - # sigh. the admin has done something strange. - # tell them to clean it up and retry. - # - printf "$f_stray_clone\n" >&2 - print_array stray_clones >&2 - printf "$f_rm_clone\n" >&2 - exit $ZONE_SUBPROC_FATAL - fi - - # Find all the snapshots of the origin filesystem. - unset s_origin - (( s_origin_c = 0 )) - /sbin/zfs list -H -t snapshot -s creation -o name -r $fs | - grep "^$fs@" | while read name; do - s_origin[$s_origin_c]=$name - (( s_origin_c = $s_origin_c + 1 )) - done - - # - # Now go through the origin snapshots and find those which don't - # have clones. We're going to explicity delete these snapshots - # before we do the promotion. - # - unset s_delete - (( s_delete_c = 0 )) - (( j = 0 )) - while (( $j < $s_origin_c )); do - (( k = 0 )) - while (( $k < $clones_c )); do - # if we have a match then break out of this loop - [[ "${s_origin[$j]}" == "${clones_origin[$k]}" ]] && - break - (( k = $k + 1 )) - done - if (( $k != $clones_c )); then - # this snapshot has a clone, move on to the next one - (( j = $j + 1 )) - continue - fi - - # snapshot has no clones so add it to our delete list - s_delete[$s_delete_c]=${s_origin[$j]} - (( s_delete_c = $s_delete_c + 1 )) - # remove it from the origin snapshot list - (( k = $j + 1 )) - while (( $k < $s_origin_c )); do - s_origin[(( $k - 1 ))]=${s_origin[$k]} - (( k = $k + 1 )) - done - (( s_origin_c = $s_origin_c - 1 )) - done - - # - # Fastpath. If there are no remaining snapshots then just - # delete the origin filesystem (and all it's descendents) and - # move onto the next zone BE. - # - if (( $s_origin_c == 0 )); then - zfs_destroy "$fs" - return - fi - - # find the youngest snapshot of $fs - s_youngest=${s_origin[(( $s_origin_c - 1 ))]} - - # Find the oldest clone of the youngest snapshot of $fs - unset s_clone - (( j = $clones_c - 1 )) - while (( $j >= 0 )); do - if [[ "$s_youngest" == "${clones_origin[$j]}" ]]; then - s_clone=${clones[$j]} - break - fi - (( j = $j - 1 )) - done - if [[ -z "$s_clone" ]]; then - # uh oh. something has gone wrong. bail. - printf "$f_stray_snap\n" >&2 - printf "\t$s_youngest\n" >&2 - printf "$f_rm_snap\n" >&2 - exit $ZONE_SUBPROC_FATAL - fi - - # create an array of clone snapshot names - unset s_clone_s - (( s_clone_s_c = 0 )) - /sbin/zfs list -H -t snapshot -s creation -o name -r $s_clone | - grep "^$s_clone@" | while read name; do - s_clone_s[$s_clone_s_c]=${name##*@} - (( s_clone_s_c = $s_clone_s_c + 1 )) - done - - # create an arrays of possible origin snapshot renames - unset s_origin_snap - unset s_rename - (( j = 0 )) - while (( $j < $s_origin_c )); do - s_origin_snap[$j]=${s_origin[$j]##*@} - s_rename[$j]=${s_origin[$j]##*@} - (( j = $j + 1 )) - done - - # - # Search for snapshot name collisions between the origin and - # oldest clone. If we find one, generate a new name for the - # origin snapshot and re-do the collision check. - # - snap_rename_init - (( j = 0 )) - while (( $j < $s_origin_c )); do - (( k = 0 )) - while (( $k < $s_clone_s_c )); do - - # if there's no naming conflict continue - if [[ "${s_rename[$j]}" != "${s_clone_s[$k]}" ]]; then - (( k = $k + 1 )) - continue - fi - - # - # The origin snapshot conflicts with a clone - # snapshot. Choose a new name and then restart - # then check that against clone snapshot names. - # - snap_rename fs "s_rename[$j]" - (( k = 0 )) - continue; - done - - # if we didn't rename this snapshot then continue - if [[ "${s_rename[$j]}" == "${s_origin_snap[$j]}" ]]; then - (( j = $j + 1 )) - continue - fi - - # - # We need to rename this origin snapshot because it - # conflicts with a clone snapshot name. So above we - # chose a name that didn't conflict with any other clone - # snapshot names. But we also have to avoid naming - # conflicts with any other origin snapshot names. So - # check for that now. - # - (( k = 0 )) - while (( $k < $s_origin_c )); do - - # don't compare against ourself - if (( $j == $k )); then - (( k = $k + 1 )) - continue - fi - - # if there's no naming conflict continue - if [[ "${s_rename[$j]}" != "${s_rename[$k]}" ]]; then - (( k = $k + 1 )) - continue - fi - - # - # The new origin snapshot name conflicts with - # another origin snapshot name. Choose a new - # name and then go back to check the new name - # for uniqueness against all the clone snapshot - # names. - # - snap_rename fs "s_rename[$j]" - continue 2; - done - - # - # A new unique name has been chosen. Move on to the - # next origin snapshot. - # - (( j = $j + 1 )) - snap_rename_init - done - - # - # So now we know what snapshots need to be renamed before the - # promotion. But there's an additional problem. If any of the - # filesystems cloned from these snapshots have the "zoned" - # attribute set (which is highly likely) or if they are in use - # (and can't be unmounted and re-mounted) then the snapshot - # rename will fail. So now we'll search for all the clones of - # snapshots we plan to rename and look for ones that are zoned. - # - # We'll ignore any snapshot clones that may be in use but are - # not zoned. If these clones are in-use, the rename will fail - # and we'll abort, there's not much else we can do about it. - # But if they are not in use the snapshot rename will unmount - # and remount the clone. This is ok because when the zoned - # attribute is off, we know that the clone was originally - # mounted from the global zone. (So unmounting and remounting - # it from the global zone is ok.) - # - # But we'll abort this whole operation if we find any clones - # that that are zoned and in use. (This can happen if another - # zone has been cloned from this one and is now booted.) The - # reason we do this is because those zoned filesystems could - # have originally mounted from within the zone. So if we - # cleared the zone attribute and did the rename, we'd be - # remounting the filesystem from the global zone. This would - # result in the zone losing the ability to unmount the - # filesystem, which would be bad. - # - unset zoned_clones zoned_iu_clones - (( zoned_clones_c = 0 )) - (( zoned_iu_clones_c = 0 )) - (( j = 0 )) - # walk through all the clones - while (( $j < $clones_c )); do - # walk through all the origin snapshots - (( k = 0 )) - while (( $k < $s_origin_c )); do - # - # check if this clone originated from a snapshot that - # we need to rename. - # - [[ "${clones_origin[$j]}" == "${s_origin[$k]}" ]] && - [[ "${s_origin_snap[$k]}" != "${s_rename[$k]}" ]] && - break - (( k = $k + 1 )) - continue - done - if (( $k == $s_origin_c )); then - # This isn't a clone of a snapshot we want to rename. - (( j = $j + 1 )) - continue; - fi - - # get the zoned attr for this clone. - zoned=`LC_ALL=C LANG=C \ - /sbin/zfs get -H -o value zoned ${clones[$j]}` - if [[ "$zoned" != on ]]; then - # This clone isn't zoned so ignore it. - (( j = $j + 1 )) - continue - fi - - # remember this clone so we can muck with it's zoned attr. - zoned_clones[$zoned_clones_c]=${clones[$j]} - (( zoned_clones_c = $zoned_clones_c + 1 )) - - # check if it's in use - mounted=`LC_ALL=C LANG=C \ - /sbin/zfs get -H -o value mounted ${clones[$j]}` - if [[ "$mounted" != yes ]]; then - # Good news. This clone isn't in use. - (( j = $j + 1 )) - continue - fi - - # Sigh. This clone is in use so we're destined to fail. - zoned_iu_clones[$zoned_iu_clones_c]=${clones[$j]} - (( zoned_iu_clones_c = $zoned_iu_clones_c + 1 )) - - # keep looking for errors so we can report them all at once. - (( j = $j + 1 )) - done - if (( zoned_iu_clones_c > 0 )); then - # - # Tell the admin - # - printf "$f_iu_clone\n" >&2 - print_array zoned_iu_clones >&2 - printf "$f_dis_clone\n" >&2 - exit $ZONE_SUBPROC_FATAL - fi - - # - # Ok. So we're finally done with planning and we can do some - # damage. We're going to: - # - destroy unused snapshots - # - unzone clones which originate from snapshots we need to rename - # - rename conflicting snapshots - # - rezone any clones which we unzoned - # - promote the oldest clone of the youngest snapshot - # - finally destroy the origin filesystem. - # - - # delete any unsed snapshot - (( j = 0 )) - while (( $j < $s_delete_c )); do - zfs_destroy "${s_delete[$j]}" - (( j = $j + 1 )) - done - - # unzone clones - zfs_set_array zoned off zoned_clones || - zfs_set_array zoned on zoned_clones 1 - - # rename conflicting snapshots - (( j = 0 )) - while (( $j < $s_origin_c )); do - if [[ "${s_origin_snap[$j]}" != "${s_rename[$j]}" ]]; then - zfs_rename "${s_origin[$j]}" "$fs@${s_rename[$j]}" - if [[ $? != 0 ]]; then - # re-zone the clones before aborting - zfs_set_array zoned on zoned_clones 1 - exit $ZONE_SUBPROC_FATAL - fi - fi - (( j = $j + 1 )) - done - - # re-zone the clones - zfs_set_array zoned on zoned_clones 1 - - # promote the youngest clone of the oldest snapshot - zfs_promote "$s_clone" - - # destroy the origin filesystem and it's descendants - zfs_destroy "$fs" -} - -# -# This function expects an array named fs_all to exist which is initialized -# with the zone's ZFS datasets that should be destroyed. fs_all_c is the -# count of the number of elements in the array. ZONEPATH_RDS is the -# zonepath/root dataset and ZONEPATH_DS is the zonepath dataset. -# -destroy_zone_datasets() -{ - # Destroy the zone BEs datasets one by one. - (( i = 0 )) - while (( $i < $fs_all_c )); do - fs=${fs_all[$i]} - - destroy_zone_dataset "$fs" - (( i = $i + 1 )) - done - - # - # Check if there are any other datasets left. There may be datasets - # associated with other GZ BEs, so we need to leave things alone in - # that case. - # - c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_RDS | wc -l` - if [ $c = 1 ]; then - zfs_destroy "$ZONEPATH_RDS" - fi - c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l` - if [ $c = 1 ]; then - zfs_destroy "$ZONEPATH_DS" - fi - - rm_zonepath -} diff --git a/usr/src/lib/brand/shared/zone/Makefile b/usr/src/lib/brand/shared/zone/Makefile new file mode 100644 index 0000000000..9a768d62dd --- /dev/null +++ b/usr/src/lib/brand/shared/zone/Makefile @@ -0,0 +1,54 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +PROG=query +SHARED= common.ksh query uninstall.ksh +CLOBBERFILES= query + +include $(SRC)/cmd/Makefile.cmd +include ../../Makefile.brand + +$(ROOTSHAREDDIR)/common.ksh := FILEMODE = 0444 +$(ROOTSHAREDDIR)/uninstall.ksh := FILEMODE = 0444 + +CLOBBERFILES= $(ROOTSHARED) $(PROG) + +POFILES= common.po query.po uninstall.po +POFILE= shared.po + +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +all: $(PROG) + +install: $(ROOTSHARED) + +clean: + -$(RM) $(PROG) $(POFILES) + +lint: + +include $(SRC)/cmd/Makefile.targ diff --git a/usr/src/lib/brand/shared/zone/common.ksh b/usr/src/lib/brand/shared/zone/common.ksh new file mode 100644 index 0000000000..d9bc1abbef --- /dev/null +++ b/usr/src/lib/brand/shared/zone/common.ksh @@ -0,0 +1,1085 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# Send the error message to the screen and to the logfile. +# +error() +{ + typeset fmt="$1" + shift + + printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@" + [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2 +} + +fatal() +{ + typeset fmt="$1" + shift + + error "$fmt" "$@" + exit $EXIT_CODE +} + +fail_fatal() { + printf "ERROR: " + printf "$@" + printf "\n" + exit $ZONE_SUBPROC_FATAL +} + +# +# Send the provided printf()-style arguments to the screen and to the logfile. +# +log() +{ + typeset fmt="$1" + shift + + printf "${MSG_PREFIX}${fmt}\n" "$@" + [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2 +} + +# +# Print provided text to the screen if the shell variable "OPT_V" is set. +# The text is always sent to the logfile. +# +vlog() +{ + typeset fmt="$1" + shift + + [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@" + [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2 +} + +# +# Validate that the directory is safe. +# +# It is possible for a malicious zone root user to modify a zone's filesystem +# so that modifications made to the zone's filesystem by administrators in the +# global zone modify the global zone's filesystem. We can prevent this by +# ensuring that all components of paths accessed by scripts are real (i.e., +# non-symlink) directories. +# +# NOTE: The specified path should be an absolute path as would be seen from +# within the zone. Also, this function does not check parent directories. +# If, for example, you need to ensure that every component of the path +# '/foo/bar/baz' is a directory and not a symlink, then do the following: +# +# safe_dir /foo +# safe_dir /foo/bar +# safe_dir /foo/bar/baz +# +safe_dir() +{ + typeset dir="$1" + + if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then + fatal "$e_baddir" "$dir" + fi +} + +# Like safe_dir except the dir doesn't have to exist. +safe_opt_dir() +{ + typeset dir="$1" + + [[ ! -e $ZONEROOT/$dir ]] && return + + if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then + fatal "$e_baddir" "$dir" + fi +} + +# Only make a copy if we haven't already done so. +safe_backup() +{ + typeset src="$1" + typeset dst="$2" + + if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then + /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src" + fi +} + +# Make a copy even if the destination already exists. +safe_copy() +{ + typeset src="$1" + typeset dst="$2" + + if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then + /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src" + fi +} + +# Move a file +safe_move() +{ + typeset src="$1" + typeset dst="$2" + + if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then + /usr/bin/mv $src $dst || fatal "$e_badfile" "$src" + fi +} + +safe_rm() +{ + if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then + rm -f "$ZONEROOT/$1" + fi +} + +# +# Replace the file with a wrapper pointing to the native brand code. +# However, we only do the replacement if the file hasn't already been +# replaced with our wrapper. This function expects the cwd to be the +# location of the file we're replacing. +# +# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm' +# the file before we setup the wrapper while others are hardlinks to rc scripts +# that we need to maintain. +# +safe_replace() +{ + typeset filename="$1" + typeset runname="$2" + typeset mode="$3" + typeset own="$4" + typeset rem="$5" + + if [ -h $filename -o ! -f $filename ]; then + return + fi + + egrep -s "Solaris Brand Replacement" $filename + if [ $? -eq 0 ]; then + return + fi + + safe_backup $filename $filename.pre_p2v + if [ $rem = "remove" ]; then + rm -f $filename + fi + + cat <<-END >$filename || exit 1 + #!/bin/sh + # + # Solaris Brand Replacement + # + # Attention. This file has been replaced with a new version for + # use in a virtualized environment. Modification of this script is not + # supported and all changes will be lost upon reboot. The + # {name}.pre_p2v version of this file is a backup copy of the + # original and should not be deleted. + # + END + + echo ". $runname \"\$@\"" >>$filename || exit 1 + + chmod $mode $filename + chown $own $filename +} + +safe_wrap() +{ + typeset filename="$1" + typeset runname="$2" + typeset mode="$3" + typeset own="$4" + + if [ -f $filename ]; then + log "$e_cannot_wrap" "$filename" + exit 1 + fi + + cat <<-END >$filename || exit 1 + #!/bin/sh + # + # Solaris Brand Wrapper + # + # Attention. This file has been created for use in a + # virtualized environment. Modification of this script + # is not supported and all changes will be lost upon reboot. + # + END + + echo ". $runname \"\$@\"" >>$filename || exit 1 + + chmod $mode $filename + chown $own $filename +} + +# +# Read zonecfg ipd and fs entries and save the relevant data, one entry per +# line. +# This assumes the properties from the zonecfg output, e.g.: +# inherit-pkg-dir: +# dir: /usr +# fs: +# dir: /opt +# special: /opt +# raw not specified +# type: lofs +# options: [noexec,ro,noatime] +# +# and it assumes the order of the fs properties as above. This also saves the +# inherit-pkg-dir patterns into the ipd.{cpio|pax} temporary files for +# filtering while extracting the image into the zonepath. We have to save the +# IPD patterns in the appropriate format for filtering with the different +# archivers and we don't know what format we'll get until after the flash +# archive is unpacked. +# +get_fs_info() +{ + zonecfg -z $zonename info inherit-pkg-dir | \ + nawk -v ipdcpiof=$ipdcpiofile -v ipdpaxf=$ipdpaxfile '{ + if ($1 == "dir:") { + dir=$2; + printf("%s lofs %s ro\n", dir, dir); + + if (substr(dir, 1, 1) == "/") { + printf("%s\n", substr(dir, 2)) >> ipdcpiof + printf("%s/*\n", substr(dir, 2)) >> ipdcpiof + } else { + printf("%s\n", dir) >> ipdcpiof + printf("%s/*\n", dir) >> ipdcpiof + } + + if (substr(dir, 1, 1) == "/") { + printf("%s ", substr(dir, 2)) >> ipdpaxf + } else { + printf("%s ", dir) >> ipdpaxf + } + } + }' >> $fstmpfile + + zonecfg -z $zonename info fs | nawk '{ + if ($1 == "options:") { + # Remove brackets. + options=substr($2, 2, length($2) - 2); + printf("%s %s %s %s\n", dir, type, special, options); + } else if ($1 == "dir:") { + dir=$2; + } else if ($1 == "special:") { + special=$2; + } else if ($1 == "type:") { + type=$2 + } + }' >> $fstmpfile +} + +# +# Mount zonecfg fs entries into the zonepath. +# +mnt_fs() +{ + if [ ! -s $fstmpfile ]; then + return; + fi + + # Sort the fs entries so we can handle nested mounts. + sort $fstmpfile | nawk -v zonepath=$zonepath '{ + if (NF == 4) + options="-o " $4; + else + options="" + + # Create the mount point. Ignore errors since we might have + # a nested mount with a pre-existing mount point. + cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1" + system(cmd); + + cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \ + zonepath "/root" $1; + if (system(cmd) != 0) { + printf("command failed: %s\n", cmd); + exit 1; + } + }' >>$LOGFILE +} + +# +# Unmount zonecfg fs entries from the zonepath. +# +umnt_fs() +{ + if [ ! -s $fstmpfile ]; then + return; + fi + + # Reverse sort the fs entries so we can handle nested unmounts. + sort -r $fstmpfile | nawk -v zonepath=$zonepath '{ + cmd="/usr/sbin/umount " zonepath "/root" $1 + if (system(cmd) != 0) { + printf("command failed: %s\n", cmd); + } + }' >>$LOGFILE +} + +# Find the dataset mounted on the zonepath. +get_zonepath_ds() { + ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \ + /usr/bin/nawk -v zonepath=$1 '{ + if ($2 == zonepath) + print $1 + }'` + + if [ -z "$ZONEPATH_DS" ]; then + fail_fatal "$f_no_ds" + fi +} + +# +# Perform any cleanup in the zoneroot after unpacking the archive. +# +post_unpack() +{ + ( cd "$ZONEROOT" && \ + find . \( -type b -o -type c \) -exec rm -f "{}" \; ) +} + +# +# Determine flar compression style from identification file. +# +get_compression() +{ + typeset ident=$1 + typeset line=$(grep "^files_compressed_method=" $ident) + + print ${line##*=} +} + +# +# Determine flar archive style from identification file. +# +get_archiver() +{ + typeset ident=$1 + typeset line=$(grep "^files_archived_method=" $ident) + + print ${line##*=} +} + +# +# Unpack flar into current directory (which should be zoneroot). The flash +# archive is standard input. See flash_archive(4) man page. +# +# We can't use "flar split" since it will only unpack into a directory called +# "archive". We need to unpack in place in order to properly handle nested +# fs mounts within the zone root. This function does the unpacking into the +# current directory. +# +# This code is derived from the gen_split() function in /usr/sbin/flar so +# we keep the same style as the original. +# +install_flar() +{ + typeset result + typeset archiver_command + typeset archiver_arguments + + vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar" + + # Read cookie + read -r input_line + if (( $? != 0 )); then + log "$not_readable" "$install_media" + return 1 + fi + # The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers. + if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then + log "$not_flar" + return 1 + fi + + while [ true ] + do + # We should always be at the start of a section here + read -r input_line + if [[ ${input_line%%=*} != "section_begin" ]]; then + log "$bad_flar" + return 1 + fi + section_name=${input_line##*=} + + # If we're at the archive, we're done skipping sections. + if [[ "$section_name" == "archive" ]]; then + break + fi + + # + # Save identification section to a file so we can determine + # how to unpack the archive. + # + if [[ "$section_name" == "identification" ]]; then + /usr/bin/rm -f identification + while read -r input_line + do + if [[ ${input_line%%=*} == \ + "section_begin" ]]; then + /usr/bin/rm -f identification + log "$bad_flar" + return 1 + fi + + if [[ $input_line == \ + "section_end=$section_name" ]]; then + break; + fi + echo $input_line >> identification + done + + continue + fi + + # + # Otherwise skip past this section; read lines until detecting + # section_end. According to flash_archive(4) we can have + # an arbitrary number of sections but the archive section + # must be last. + # + success=0 + while read -r input_line + do + if [[ $input_line == "section_end=$section_name" ]]; + then + success=1 + break + fi + # Fail if we miss the end of the section + if [[ ${input_line%%=*} == "section_begin" ]]; then + /usr/bin/rm -f identification + log "$bad_flar" + return 1 + fi + done + if (( $success == 0 )); then + # + # If we get here we read to the end of the file before + # seeing the end of the section we were reading. + # + /usr/bin/rm -f identification + log "$bad_flar" + return 1 + fi + done + + # Check for an archive made from a ZFS root pool. + egrep -s "^rootpool=" identification + if (( $? == 0 )); then + /usr/bin/rm -f identification + log "$bad_zfs_flar" + return 1 + fi + + # Get the information needed to unpack the archive. + archiver=$(get_archiver identification) + if [[ $archiver == "pax" ]]; then + # pax archiver specified + archiver_command="/usr/bin/pax" + if [[ -s $ipdpaxfile ]]; then + archiver_arguments="-r -p e -c \ + $(/usr/bin/cat $ipdpaxfile)" + else + archiver_arguments="-r -p e" + fi + elif [[ $archiver == "cpio" || -z $archiver ]]; then + # cpio archived specified OR no archiver specified - use default + archiver_command="/usr/bin/cpio" + archiver_arguments="-icdumfE $ipdcpiofile" + else + # unknown archiver specified + log "$unknown_archiver" $archiver + return 1 + fi + + if [[ ! -x $archiver_command ]]; then + /usr/bin/rm -f identification + log "$cmd_not_exec" $archiver_command + return 1 + fi + + compression=$(get_compression identification) + + # We're done with the identification file + /usr/bin/rm -f identification + + # Extract archive + if [[ $compression == "compress" ]]; then + /usr/bin/zcat | \ + $archiver_command $archiver_arguments 2>/dev/null + else + $archiver_command $archiver_arguments 2>/dev/null + fi + result=$? + + post_unpack + + (( $result != 0 )) && return 1 + + return 0 +} + +# +# Get the archive base. +# +# We must unpack the archive in the right place within the zonepath so +# that files are installed into the various mounted filesystems that are set +# up in the zone's configuration. These are already mounted for us by the +# mntfs function. +# +# Archives can be made of either a physical host's root file system or a +# zone's zonepath. For a physical system, if the archive is made using an +# absolute path (/...) we can't use it. For a zone the admin can make the +# archive from a variety of locations; +# +# a) zonepath itself: This will be a single dir, probably named with the +# zone name, it will contain a root dir and under the root we'll see all +# the top level dirs; etc, var, usr... We must be above the ZONEPATH +# when we unpack the archive but this will only work if the the archive's +# top-level dir name matches the ZONEPATH base-level dir name. If not, +# this is an error. +# +# b) inside the zonepath: We'll see root and it will contain all the top +# level dirs; etc, var, usr.... We must be in the ZONEPATH when we unpack +# the archive. +# +# c) inside the zonepath root: We'll see all the top level dirs, ./etc, +# ./var, ./usr.... This is also the case we see when we get an archive +# of a physical sytem. We must be in ZONEROOT when we unpack the archive. +# +# Note that there can be a directory named "root" under the ZONEPATH/root +# directory. +# +# This function handles the above possibilities so that we reject absolute +# path archives and figure out where in the file system we need to be to +# properly unpack the archive into the zone. It sets the ARCHIVE_BASE +# variable to the location where the achive should be unpacked. +# +get_archive_base() +{ + stage1=$1 + archive=$2 + stage2=$3 + + vlog "$m_analyse_archive" + + base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{ + # Check for an absolute path archive + if (substr($0, 1, 1) == "/") + exit 1 + + if ($1 != ".") + dirs[$1] = 1 + else + dirs[$2] = 1 + } + END { + for (d in dirs) { + cnt++ + if (d == "bin") sawbin = 1 + if (d == "etc") sawetc = 1 + if (d == "root") sawroot = 1 + if (d == "var") sawvar = 1 + } + + if (cnt == 1) { + # If only one top-level dir named root, we are in the + # zonepath, otherwise this must be an archive *of* + # the zonepath so print the top-level dir name. + if (sawroot) + print "*zonepath*" + else + for (d in dirs) print d + } else { + # We are either in the zonepath or in the zonepath/root + # (or at the top level of a full system archive which + # looks like the zonepath/root case). Figure out which + # one. + if (sawroot && !sawbin && !sawetc && !sawvar) + print "*zonepath*" + else + print "*zoneroot*" + } + }'` + + if (( $? != 0 )); then + umnt_fs + fatal "$e_absolute_archive" + fi + + if [[ "$base" == "*zoneroot*" ]]; then + ARCHIVE_BASE=$ZONEROOT + elif [[ "$base" == "*zonepath*" ]]; then + ARCHIVE_BASE=$ZONEPATH + else + # We need to be in the dir above the ZONEPATH but we need to + # validate that $base matches the final component of ZONEPATH. + bname=`basename $ZONEPATH` + + if [[ "$bname" != "$base" ]]; then + umnt_fs + fatal "$e_mismatch_archive" "$base" "$bname" + fi + ARCHIVE_BASE=`dirname $ZONEPATH` + fi +} + +# +# Unpack cpio archive into zoneroot. +# +install_cpio() +{ + stage1=$1 + archive=$2 + + get_archive_base "$stage1" "$archive" "cpio -it" + + cpioopts="-idmfE $ipdcpiofile" + + vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts" + + # Ignore errors from cpio since we expect some errors depending on + # how the archive was made. + ( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts ) + + post_unpack + + return 0 +} + +# +# Unpack pax archive into zoneroot. +# +install_pax() +{ + archive=$1 + + get_archive_base "cat" "$archive" "pax" + + if [[ -s $ipdpaxfile ]]; then + filtopt="-c $(/usr/bin/cat $ipdpaxfile)" + fi + + vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt" + + # Ignore errors from pax since we expect some errors depending on + # how the archive was made. + ( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt ) + + post_unpack + + return 0 +} + +# +# Unpack UFS dump into zoneroot. +# +install_ufsdump() +{ + archive=$1 + + vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\"" + + # + # ufsrestore goes interactive if you ^C it. To prevent that, + # we make sure its stdin is not a terminal. + # Note that there is no way to filter inherit-pkg-dirs for a full + # restore so there will be warnings in the log file. + # + ( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null ) + result=$? + + post_unpack + + return $result +} + +# +# Copy directory hierarchy into zoneroot. +# +install_dir() +{ + source_dir=$1 + + cpioopts="-pdm" + + first=1 + filt=$(for i in $(cat $ipdpaxfile) + do + echo $i | egrep -s "/" && continue + if [[ $first == 1 ]]; then + printf "^%s" $i + first=0 + else + printf "|^%s" $i + fi + done) + + list=$(cd "$source_dir" && ls -d * | egrep -v "$filt") + flist=$(for i in $list + do + printf "%s " "$i" + done) + findopts="-xdev ( -type d -o -type f -o -type l ) -print" + + vlog "cd \"$source_dir\" && find $flist $findopts | " + vlog "cpio $cpioopts \"$ZONEROOT\"" + + # Ignore errors from cpio since we expect some errors depending on + # how the archive was made. + ( cd "$source_dir" && find $flist $findopts | \ + cpio $cpioopts "$ZONEROOT" ) + + post_unpack + + return 0 +} + +# +# This is a common function for laying down a zone image from a variety of +# different sources. This can be used to either install a fresh zone or as +# part of zone migration during attach. +# +# The first argument specifies the type of image: archive, directory or stdin. +# The second argument specifies the image itself. In the case of stdin, the +# second argument specifies the format of the stream (cpio, flar, etc.). +# Any validation or post-processing on the image is done elsewhere. +# +# This function calls a 'sanity_check' function which must be provided by +# the script which includes this code. +# +install_image() +{ + intype=$1 + insrc=$2 + + if [[ -z "$intype" || -z "$insrc" ]]; then + return 1 + fi + + filetype="unknown" + filetypename="unknown" + stage1="cat" + + if [[ "$intype" == "directory" ]]; then + if [[ "$insrc" == "-" ]]; then + # Indicates that the existing zonepath is prepopulated. + filetype="existing" + filetypename="existing" + else + if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then + fatal "$e_path_abs" "$insrc" + fi + + if [[ ! -e "$insrc" ]]; then + log "$e_not_found" "$insrc" + fatal "$e_install_abort" + fi + + if [[ ! -r "$insrc" ]]; then + log "$e_not_readable" "$insrc" + fatal "$e_install_abort" + fi + + if [[ ! -d "$insrc" ]]; then + log "$e_not_dir" + fatal "$e_install_abort" + fi + + sanity_check $insrc + + filetype="directory" + filetypename="directory" + fi + + else + # Common code for both archive and stdin stream. + + if [[ "$intype" == "archive" ]]; then + if [[ ! -f "$insrc" ]]; then + log "$e_unknown_archive" + fatal "$e_install_abort" + fi + ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)" + else + # For intype == stdin, the insrc parameter specifies + # the stream format coming on stdin. + ftype="$insrc" + insrc="-" + fi + + # Setup vars for the archive type we have. + case "$ftype" in + *cpio*) filetype="cpio" + filetypename="cpio archive" + ;; + *bzip2*) filetype="bzip2" + filetypename="bzipped cpio archive" + ;; + *gzip*) filetype="gzip" + filetypename="gzipped cpio archive" + ;; + *ufsdump*) filetype="ufsdump" + filetypename="ufsdump archive" + ;; + "flar") + filetype="flar" + filetypename="flash archive" + ;; + "flash") + filetype="flar" + filetypename="flash archive" + ;; + *Flash\ Archive*) + filetype="flar" + filetypename="flash archive" + ;; + "tar") + filetype="tar" + filetypename="tar archive" + ;; + *USTAR\ tar\ archive) + filetype="tar" + filetypename="tar archive" + ;; + "pax") + filetype="xustar" + filetypename="pax (xustar) archive" + ;; + *USTAR\ tar\ archive\ extended\ format*) + filetype="xustar" + filetypename="pax (xustar) archive" + ;; + "zfs") + filetype="zfs" + filetypename="ZFS send stream" + ;; + *ZFS\ snapshot\ stream*) + filetype="zfs" + filetypename="ZFS send stream" + ;; + *) log "$e_unknown_archive" + fatal "$e_install_abort" + ;; + esac + fi + + vlog "$filetypename" + + # Check for a non-empty root if no '-d -' option. + if [[ "$filetype" != "existing" ]]; then + cnt=$(ls $ZONEROOT | wc -l) + if (( $cnt != 0 )); then + fatal "$e_root_full" "$ZONEROOT" + fi + fi + + fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp) + if [[ -z "$fstmpfile" ]]; then + fatal "$e_tmpfile" + fi + + # Make sure we always have the files holding the directories to filter + # out when extracting from a CPIO or PAX archive. We'll add the fs + # entries to these files in get_fs_info() (there may be no IPDs for + # some brands but thats ok). + ipdcpiofile=$(/usr/bin/mktemp -t -p /var/tmp ipd.cpio.XXXXXX) + if [[ -z "$ipdcpiofile" ]]; then + rm -f $fstmpfile + fatal "$e_tmpfile" + fi + + # In addition to the IPDs, also filter out these directories. + echo 'dev/*' >>$ipdcpiofile + echo 'devices/*' >>$ipdcpiofile + echo 'devices' >>$ipdcpiofile + echo 'proc/*' >>$ipdcpiofile + echo 'tmp/*' >>$ipdcpiofile + echo 'var/run/*' >>$ipdcpiofile + echo 'system/contract/*' >>$ipdcpiofile + echo 'system/object/*' >>$ipdcpiofile + + ipdpaxfile=$(/usr/bin/mktemp -t -p /var/tmp ipd.pax.XXXXXX) + if [[ -z "$ipdpaxfile" ]]; then + rm -f $fstmpfile $ipdcpiofile + fatal "$e_tmpfile" + fi + + printf "%s " \ + "dev devices proc tmp var/run system/contract system/object" \ + >>$ipdpaxfile + + # Set up any fs mounts so the archive will install into the correct + # locations. + get_fs_info + mnt_fs + if (( $? != 0 )); then + umnt_fs >/dev/null 2>&1 + rm -f $fstmpfile $ipdcpiofile $ipdpaxfile + fatal "$mount_failed" + fi + + if [[ "$filetype" == "existing" ]]; then + log "$no_installing" + else + log "$installing" + fi + + # + # Install the image into the zonepath. + # + unpack_result=0 + stage1="cat" + if [[ "$filetype" == "gzip" ]]; then + stage1="gzcat" + filetype="cpio" + elif [[ "$filetype" == "bzip2" ]]; then + stage1="bzcat" + filetype="cpio" + fi + + if [[ "$filetype" == "cpio" ]]; then + install_cpio "$stage1" "$insrc" + unpack_result=$? + + elif [[ "$filetype" == "flar" ]]; then + ( cd "$ZONEROOT" && $stage1 $insrc | install_flar ) + unpack_result=$? + + elif [[ "$filetype" == "xustar" ]]; then + install_pax "$insrc" + unpack_result=$? + + elif [[ "$filetype" = "tar" ]]; then + vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\"" + # Ignore errors from tar since we expect some errors depending + # on how the archive was made. + ( cd "$ZONEROOT" && tar -xf "$insrc" ) + unpack_result=0 + post_unpack + + elif [[ "$filetype" == "ufsdump" ]]; then + install_ufsdump "$insrc" + unpack_result=$? + + elif [[ "$filetype" == "directory" ]]; then + install_dir "$insrc" + unpack_result=$? + + elif [[ "$filetype" == "zfs" ]]; then + # + # Given a 'zfs send' stream file, receive the snapshot into + # the zone's dataset. We're getting the original system's + # zonepath dataset. Destroy the existing dataset created + # above since this recreates it. + # + if [[ -z "$DATASET" ]]; then + fatal "$f_nodataset" + fi + /usr/sbin/zfs destroy "$DATASET" + if (( $? != 0 )); then + log "$f_zfsdestroy" "$DATASET" + fi + + vlog "$stage1 $insrc | zfs receive -F $DATASET" + ( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET ) + unpack_result=$? + fi + + # Clean up any fs mounts used during unpacking. + umnt_fs + rm -f $fstmpfile $ipdcpiofile $ipdpaxfile + + chmod 700 $zonepath + + (( $unpack_result != 0 )) && fatal "$f_unpack_failed" + + # Verify this is a valid image. + sanity_check $ZONEROOT + + return 0 +} + +# Setup i18n output +TEXTDOMAIN="SUNW_OST_OSCMD" +export TEXTDOMAIN + +e_cannot_wrap=$(gettext "%s: error: wrapper file already exists") +e_baddir=$(gettext "Invalid '%s' directory within the zone") +e_badfile=$(gettext "Invalid '%s' file within the zone") +e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.") +e_not_found=$(gettext "%s: error: file or directory not found.") +e_install_abort=$(gettext "Installation aborted.") +e_not_readable=$(gettext "Cannot read directory '%s'") +e_not_dir=$(gettext "Error: must be a directory") +e_unknown_archive=$(gettext "Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.") +e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.") +e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).") +e_tmpfile=$(gettext "Unable to create temporary file") +e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.") +f_mkdir=$(gettext "Unable to create directory %s.") +f_chmod=$(gettext "Unable to chmod directory %s.") +f_chown=$(gettext "Unable to chown directory %s.") + + +m_analyse_archive=$(gettext "Analysing the archive") + +not_readable=$(gettext "Cannot read file '%s'") +not_flar=$(gettext "Input is not a flash archive") +bad_flar=$(gettext "Flash archive is a corrupt") +bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.") +f_unpack_failed=$(gettext "Unpacking the archive failed") +unknown_archiver=$(gettext "Archiver %s is not supported") +cmd_not_exec=$(gettext "Required command '%s' not executable!") + +# +# Exit values used by the script, as #defined in +# +# ZONE_SUBPROC_OK +# =============== +# Installation was successful +# +# ZONE_SUBPROC_USAGE +# ================== +# Improper arguments were passed, so print a usage message before exiting +# +# ZONE_SUBPROC_NOTCOMPLETE +# ======================== +# Installation did not complete, but another installation attempt can be +# made without an uninstall +# +# ZONE_SUBPROC_FATAL +# ================== +# Installation failed and an uninstall will be required before another +# install can be attempted +# +ZONE_SUBPROC_OK=0 +ZONE_SUBPROC_USAGE=253 +ZONE_SUBPROC_NOTCOMPLETE=254 +ZONE_SUBPROC_FATAL=255 + diff --git a/usr/src/lib/brand/shared/zone/query.ksh b/usr/src/lib/brand/shared/zone/query.ksh new file mode 100644 index 0000000000..480fbda955 --- /dev/null +++ b/usr/src/lib/brand/shared/zone/query.ksh @@ -0,0 +1,46 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +PATH=/usr/bin:/usr/sbin +export PATH + +. /usr/lib/brand/shared/common.ksh + +zonename=$1 +zonepath=$2 +cmd=$3 + +if [ $3 == "datasets" ]; then + get_zonepath_ds $zonepath + + DS=`/usr/sbin/zfs list -H -t filesystem -o name $ZONEPATH_DS/ROOT` + if [ ! -z "$DS" ]; then + echo "$DS\c" + else + fail_fatal "$f_no_ds" + fi +fi + +exit $ZONE_SUBPROC_OK diff --git a/usr/src/lib/brand/shared/zone/uninstall.ksh b/usr/src/lib/brand/shared/zone/uninstall.ksh new file mode 100644 index 0000000000..468a7ed92f --- /dev/null +++ b/usr/src/lib/brand/shared/zone/uninstall.ksh @@ -0,0 +1,720 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# get script name (bname) +# +bname=`basename $0` + +# +# common shell script functions +# +. /usr/lib/brand/shared/common.ksh + +# +# error messages +# +m_usage=$(gettext "Usage: %s: [-hFn]") + +m_1_zfs_promote=$(gettext "promoting '%s'.") +m_1_zfs_destroy=$(gettext "destroying '%s'.") +m_2_zfs_rename=$(gettext "renaming '%s' to '%s'.") +m_3_zfs_set=$(gettext "setting property %s='%s' for '%s'.") +m_rm_r=$(gettext "recursively deleting '%s'.") +m_rm=$(gettext "deleting '%s'.") + +w_no_ds=$(gettext "Warning: no zonepath dataset found.") + +f_usage_err=$(gettext "Error: invalid usage") +f_abort=$(gettext "Error: internal error detected, aborting.") +f_1_zfs_promote=$(gettext "Error: promoting ZFS dataset '%s'.") +f_2_zfs_rename=$(gettext "Error: renaming ZFS dataset '%s' to '%s'.") +f_3_zfs_set=$(gettext "Error: setting ZFS propery %s='%s' for '%s'.") +f_1_zfs_destroy=$(gettext "Error: destroying ZFS dataset.") +f_2_zfs_get=$(gettext "Error: reading ZFS dataset property '%s' from '%s'.") +f_user_snap=$(gettext "Error: user snapshot(s) detected.") +f_stray_snap=$(gettext "Error: uncloned snapshot(s) detected.") +f_stray_clone=$(gettext "Error: cloned zone datasets found outsize of zone.") +f_rm_snap=$(gettext "Error: please delete snapshot(s) and retry uninstall.") +f_rm_clone=$(gettext "Error: please delete clone(s) and retry uninstall.") +f_iu_clone=$(gettext "Error: cloned zone dataset(s) in use.") +f_dis_clone=$(gettext "Error: please stop using clone(s) and retry uninstall.") + +# +# functions +# +print_array() +{ + typeset -n pa_array=$1 + + (( pa_i = 0 )) + while (( $pa_i < ${#pa_array[@]} )); do + printf "\t${pa_array[$pa_i]}\n" + (( pa_i = $pa_i + 1 )) + done +} + +usage() +{ + printf "$m_usage\n" "$bname" + exit $ZONE_SUBPROC_USAGE +} + +usage_err() +{ + printf "$f_usage_err\n" >&2 + usage >&2 +} + +rm_zonepath() +{ + # cleanup stuff we know about and leave any user data alone + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_rm\n" "$zonepath/SUNWattached.xml" + $nop /bin/rm -f "$zonepath/SUNWattached.xml" + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_rm_r\n" "$zonepath/lu" + $nop /bin/rm -rf "$zonepath/lu" + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_rm_r\n" "$zonepath/dev" + $nop /bin/rm -rf "$zonepath/dev" + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_rm_r\n" "$zonepath/root" + $nop /bin/rm -rf "$zonepath/root" + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_rm\n" "$zonepath" + $nop /bin/rmdir "$zonepath" 2>/dev/null +} + +zfs_destroy() +{ + zd_fs1="$1" + + # first figure out if the target fs has an origin snapshot + zd_origin=`/sbin/zfs get -H -o value origin "$zd_fs1"` + if [[ $? != 0 ]]; then + printf "$f_2_zfs_get\n" origin "$zd_fs1" >&2 + exit $ZONE_SUBPROC_FATAL + fi + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_1_zfs_destroy\n" "$zd_fs1" + + # + # note that we specify the '-r' flag so that we destroy any + # descendants (filesystems and snapshot) of the specified + # filesystem. + # + $nop /sbin/zfs destroy -r "$zd_fs1" + if [[ $? != 0 ]]; then + printf "$f_1_zfs_destroy\n" "$zd_fs1" >&2 + exit $ZONE_SUBPROC_FATAL + fi + + [[ "$zd_origin" == "-" ]] && return + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_1_zfs_destroy\n" "$zd_origin" + + $nop /sbin/zfs destroy "$zd_origin" 2>/dev/null + # + # we ignore errors while trying to destroy the origin since + # the origin could have been used as the source for other + # clones + # +} + +zfs_promote() +{ + zp_fs1="$1" + + [[ -z "$opt_n" ]] && + printf "$m_1_zfs_promote\n" "$zp_fs1" + + $nop /sbin/zfs promote "$zp_fs1" + if [[ $? != 0 ]]; then + printf "$f_1_zfs_promote\n" "$zp_fs1" >&2 + exit $ZONE_SUBPROC_FATAL + fi +} + +zfs_rename() +{ + zr_fs1="$1" + zr_fs2="$2" + + [[ -z "$opt_n" ]] && + printf "$m_2_zfs_rename\n" "$zr_fs1" "$zr_fs2" + + $nop /sbin/zfs rename "$zr_fs1" "$zr_fs2" + if [[ $? != 0 ]]; then + printf "$f_2_zfs_rename\n" "$zr_fs1" "$zr_fs2" >&2 + return 1 + fi + return 0 +} + +zfs_set() +{ + zs_prop=$1 + zs_value=$2 + zs_fs1=$3 + + [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] && + printf "$m_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1" + + $nop /sbin/zfs set "$zs_prop"="$zs_value" "$zs_fs1" + if [[ $? != 0 ]]; then + printf "$f_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1" + return 1 + fi + return 0 +} + +zfs_set_array() +{ + zsa_prop=$1 + zsa_value=$2 + typeset -n zsa_array=$3 + zsa_ignore_errors=$4 + + (( zsa_i = 0 )) + while (( $zsa_i < ${#zsa_array[@]} )); do + zfs_set "$zsa_prop" "$zsa_value" "${zsa_array[$zsa_i]}" + [[ $? != 0 ]] && [[ -z "$zsa_ignore_errors" ]] && + return 1 + (( zsa_i = $zsa_i + 1 )) + done + return 0 +} + + +(( snap_rename_zbe_i = 1 )) +(( snap_rename_snap_i = 1 )) +snap_rename_init() +{ + (( snap_rename_zbe_i = 1 )) + (( snap_rename_snap_i = 1 )) +} + +snap_rename() +{ + eval sr_fs=\${$1} + eval sr_snap=\${$2} + + if [[ "$sr_snap" == ~(Elr)(zbe-[0-9][0-9]*) ]]; then + sr_snap="zbe-$snap_rename_zbe_i" + (( snap_rename_zbe_i = $snap_rename_zbe_i + 1 )) + elif [[ "$sr_snap" == ~(Er)(_snap[0-9]*) ]]; then + sr_snap=${sr_snap##~(Er)([0-9]*)} + sr_snap="${sr_snap}${snap_rename_snap_i}" + (( snap_rename_snap_i = $snap_rename_snap_i + 1 )) + else + printf "$f_user_snap\n" >&2 + printf "\t$sr_fs@$sr_snap\n" >&2 + printf "$f_rm_snap\n" >&2 + exit $ZONE_SUBPROC_FATAL + fi + + eval $2="$sr_snap" +} + +# find the dataset associated with $zonepath +uninstall_get_zonepath_ds() +{ + ZONEPATH_DS=`/sbin/zfs list -t filesystem -o name,mountpoint | \ + /bin/nawk -v zonepath=$zonepath '{ + if ($2 == zonepath) + print $1 + }'` + + if [ -z "$ZONEPATH_DS" ]; then + # there is no $zonepath dataset + rm_zonepath + exit $ZONE_SUBPROC_OK + fi +} + +# find the dataset associated with $ZONEPATH_DS/ROOT +uninstall_get_zonepath_root_ds() +{ + ZONEPATH_RDS=`/sbin/zfs list -H -t filesystem -o name \ + $ZONEPATH_DS/ROOT 2>/dev/null` + + if [ -z "$ZONEPATH_RDS" ]; then + # there is no $ZONEPATH_DS/ROOT dataset + c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l` + if [ $c = 1 ]; then + # $zonepath dataset has no descendents + zfs_destroy "$ZONEPATH_DS" + fi + rm_zonepath + exit $ZONE_SUBPROC_OK + fi +} + +destroy_zone_dataset() +{ + fs=$1 + + pool=${fs%%/*} + + # Fastpath. if there are no snapshots of $fs then just delete it. + c=`/sbin/zfs list -H -t snapshot -o name -r $fs | grep "^$fs@" | + LC_ALL=C LANG=C wc -l` + if (( $c == 0 )) ; then + zfs_destroy "$fs" + return + fi + + # + # This zone BE has snapshots. This can happen if a zone has + # multiple BEs (in which case we have snapshots named "zbe-XXX"), + # if this zone has been used as the source for a clone of + # another zone (in which case we have snapshots named + # "XXX_snap"), or if an administrator has been doing manual + # snapshotting. + # + # To be able to destroy this dataset (which we'll call the + # origin) we need to get rid of all it's snapshots. The "easiest" + # way to do this is to: + # + # - delete any uncloned origin snapshots + # - find the oldest clone of the youngest origin snapshot (which + # we'll call the oldest clone) + # - check if there are any snapshots naming conflicts between + # the origin and the oldest clone. + # - if so, find any clones of those conflicting origin snapshots + # - make sure that those clones are not zoned an in-use. + # - if any of those clones are zoned, unzone them. + # - rename origin snapshots to eliminate naming conflicts + # - for any clones that we unzoned, rezone them. + # - promote the oldest clone + # - destroy the origin and all it's descendants + # + + # + # Get a list of all the cloned datasets within the zpool + # containing the origin filesystem. Filter out any filesystems + # that are descendants of origin because we are planning to + # destroy them anyway. + # + unset clones clones_origin + (( clones_c = 0 )) + pool=${fs%%/*} + LANG=C LC_ALL=C /sbin/zfs list -H -t filesystem -s creation \ + -o name,origin -r "$pool" | + while IFS=" " read name origin; do + + # skip non-clone filesystems + [[ "$origin" == "-" ]] && + continue + + # skip desendents of the origin we plan to destroy + [[ "$name" == ~()(${fs}/*) ]] && + continue + + # record this clone and it's origin + clones[$clones_c]="$name" + clones_origin[$clones_c]="$origin" + (( clones_c = $clones_c + 1 )) + done + + # + # Now do a sanity check. Search for clones of a child datasets + # of the dataset we want to destroy, that are not themselves + # children of the dataset we're going to destroy). This should + # really never happen unless the global zone admin has cloned a + # snapshot of a zone filesystem to a location outside of that + # zone. bad admin... + # + unset stray_clones + (( stray_clones_c = 0 )) + (( j = 0 )) + while (( $j < $clones_c )); do + # is the clone origin a descendant of $fs? + if [[ "${clones_origin[$j]}" != ~()(${fs}/*) ]]; then + # we don't care. + (( j = $j + 1 )) + continue + fi + stray_clones[$stray_clones_c]=${clones[$j]} + (( stray_clones_c = $stray_clones_c + 1 )) + (( j = $j + 1 )) + done + if (( stray_clones_c > 0 )); then + # + # sigh. the admin has done something strange. + # tell them to clean it up and retry. + # + printf "$f_stray_clone\n" >&2 + print_array stray_clones >&2 + printf "$f_rm_clone\n" >&2 + exit $ZONE_SUBPROC_FATAL + fi + + # Find all the snapshots of the origin filesystem. + unset s_origin + (( s_origin_c = 0 )) + /sbin/zfs list -H -t snapshot -s creation -o name -r $fs | + grep "^$fs@" | while read name; do + s_origin[$s_origin_c]=$name + (( s_origin_c = $s_origin_c + 1 )) + done + + # + # Now go through the origin snapshots and find those which don't + # have clones. We're going to explicity delete these snapshots + # before we do the promotion. + # + unset s_delete + (( s_delete_c = 0 )) + (( j = 0 )) + while (( $j < $s_origin_c )); do + (( k = 0 )) + while (( $k < $clones_c )); do + # if we have a match then break out of this loop + [[ "${s_origin[$j]}" == "${clones_origin[$k]}" ]] && + break + (( k = $k + 1 )) + done + if (( $k != $clones_c )); then + # this snapshot has a clone, move on to the next one + (( j = $j + 1 )) + continue + fi + + # snapshot has no clones so add it to our delete list + s_delete[$s_delete_c]=${s_origin[$j]} + (( s_delete_c = $s_delete_c + 1 )) + # remove it from the origin snapshot list + (( k = $j + 1 )) + while (( $k < $s_origin_c )); do + s_origin[(( $k - 1 ))]=${s_origin[$k]} + (( k = $k + 1 )) + done + (( s_origin_c = $s_origin_c - 1 )) + done + + # + # Fastpath. If there are no remaining snapshots then just + # delete the origin filesystem (and all it's descendents) and + # move onto the next zone BE. + # + if (( $s_origin_c == 0 )); then + zfs_destroy "$fs" + return + fi + + # find the youngest snapshot of $fs + s_youngest=${s_origin[(( $s_origin_c - 1 ))]} + + # Find the oldest clone of the youngest snapshot of $fs + unset s_clone + (( j = $clones_c - 1 )) + while (( $j >= 0 )); do + if [[ "$s_youngest" == "${clones_origin[$j]}" ]]; then + s_clone=${clones[$j]} + break + fi + (( j = $j - 1 )) + done + if [[ -z "$s_clone" ]]; then + # uh oh. something has gone wrong. bail. + printf "$f_stray_snap\n" >&2 + printf "\t$s_youngest\n" >&2 + printf "$f_rm_snap\n" >&2 + exit $ZONE_SUBPROC_FATAL + fi + + # create an array of clone snapshot names + unset s_clone_s + (( s_clone_s_c = 0 )) + /sbin/zfs list -H -t snapshot -s creation -o name -r $s_clone | + grep "^$s_clone@" | while read name; do + s_clone_s[$s_clone_s_c]=${name##*@} + (( s_clone_s_c = $s_clone_s_c + 1 )) + done + + # create an arrays of possible origin snapshot renames + unset s_origin_snap + unset s_rename + (( j = 0 )) + while (( $j < $s_origin_c )); do + s_origin_snap[$j]=${s_origin[$j]##*@} + s_rename[$j]=${s_origin[$j]##*@} + (( j = $j + 1 )) + done + + # + # Search for snapshot name collisions between the origin and + # oldest clone. If we find one, generate a new name for the + # origin snapshot and re-do the collision check. + # + snap_rename_init + (( j = 0 )) + while (( $j < $s_origin_c )); do + (( k = 0 )) + while (( $k < $s_clone_s_c )); do + + # if there's no naming conflict continue + if [[ "${s_rename[$j]}" != "${s_clone_s[$k]}" ]]; then + (( k = $k + 1 )) + continue + fi + + # + # The origin snapshot conflicts with a clone + # snapshot. Choose a new name and then restart + # then check that against clone snapshot names. + # + snap_rename fs "s_rename[$j]" + (( k = 0 )) + continue; + done + + # if we didn't rename this snapshot then continue + if [[ "${s_rename[$j]}" == "${s_origin_snap[$j]}" ]]; then + (( j = $j + 1 )) + continue + fi + + # + # We need to rename this origin snapshot because it + # conflicts with a clone snapshot name. So above we + # chose a name that didn't conflict with any other clone + # snapshot names. But we also have to avoid naming + # conflicts with any other origin snapshot names. So + # check for that now. + # + (( k = 0 )) + while (( $k < $s_origin_c )); do + + # don't compare against ourself + if (( $j == $k )); then + (( k = $k + 1 )) + continue + fi + + # if there's no naming conflict continue + if [[ "${s_rename[$j]}" != "${s_rename[$k]}" ]]; then + (( k = $k + 1 )) + continue + fi + + # + # The new origin snapshot name conflicts with + # another origin snapshot name. Choose a new + # name and then go back to check the new name + # for uniqueness against all the clone snapshot + # names. + # + snap_rename fs "s_rename[$j]" + continue 2; + done + + # + # A new unique name has been chosen. Move on to the + # next origin snapshot. + # + (( j = $j + 1 )) + snap_rename_init + done + + # + # So now we know what snapshots need to be renamed before the + # promotion. But there's an additional problem. If any of the + # filesystems cloned from these snapshots have the "zoned" + # attribute set (which is highly likely) or if they are in use + # (and can't be unmounted and re-mounted) then the snapshot + # rename will fail. So now we'll search for all the clones of + # snapshots we plan to rename and look for ones that are zoned. + # + # We'll ignore any snapshot clones that may be in use but are + # not zoned. If these clones are in-use, the rename will fail + # and we'll abort, there's not much else we can do about it. + # But if they are not in use the snapshot rename will unmount + # and remount the clone. This is ok because when the zoned + # attribute is off, we know that the clone was originally + # mounted from the global zone. (So unmounting and remounting + # it from the global zone is ok.) + # + # But we'll abort this whole operation if we find any clones + # that that are zoned and in use. (This can happen if another + # zone has been cloned from this one and is now booted.) The + # reason we do this is because those zoned filesystems could + # have originally mounted from within the zone. So if we + # cleared the zone attribute and did the rename, we'd be + # remounting the filesystem from the global zone. This would + # result in the zone losing the ability to unmount the + # filesystem, which would be bad. + # + unset zoned_clones zoned_iu_clones + (( zoned_clones_c = 0 )) + (( zoned_iu_clones_c = 0 )) + (( j = 0 )) + # walk through all the clones + while (( $j < $clones_c )); do + # walk through all the origin snapshots + (( k = 0 )) + while (( $k < $s_origin_c )); do + # + # check if this clone originated from a snapshot that + # we need to rename. + # + [[ "${clones_origin[$j]}" == "${s_origin[$k]}" ]] && + [[ "${s_origin_snap[$k]}" != "${s_rename[$k]}" ]] && + break + (( k = $k + 1 )) + continue + done + if (( $k == $s_origin_c )); then + # This isn't a clone of a snapshot we want to rename. + (( j = $j + 1 )) + continue; + fi + + # get the zoned attr for this clone. + zoned=`LC_ALL=C LANG=C \ + /sbin/zfs get -H -o value zoned ${clones[$j]}` + if [[ "$zoned" != on ]]; then + # This clone isn't zoned so ignore it. + (( j = $j + 1 )) + continue + fi + + # remember this clone so we can muck with it's zoned attr. + zoned_clones[$zoned_clones_c]=${clones[$j]} + (( zoned_clones_c = $zoned_clones_c + 1 )) + + # check if it's in use + mounted=`LC_ALL=C LANG=C \ + /sbin/zfs get -H -o value mounted ${clones[$j]}` + if [[ "$mounted" != yes ]]; then + # Good news. This clone isn't in use. + (( j = $j + 1 )) + continue + fi + + # Sigh. This clone is in use so we're destined to fail. + zoned_iu_clones[$zoned_iu_clones_c]=${clones[$j]} + (( zoned_iu_clones_c = $zoned_iu_clones_c + 1 )) + + # keep looking for errors so we can report them all at once. + (( j = $j + 1 )) + done + if (( zoned_iu_clones_c > 0 )); then + # + # Tell the admin + # + printf "$f_iu_clone\n" >&2 + print_array zoned_iu_clones >&2 + printf "$f_dis_clone\n" >&2 + exit $ZONE_SUBPROC_FATAL + fi + + # + # Ok. So we're finally done with planning and we can do some + # damage. We're going to: + # - destroy unused snapshots + # - unzone clones which originate from snapshots we need to rename + # - rename conflicting snapshots + # - rezone any clones which we unzoned + # - promote the oldest clone of the youngest snapshot + # - finally destroy the origin filesystem. + # + + # delete any unsed snapshot + (( j = 0 )) + while (( $j < $s_delete_c )); do + zfs_destroy "${s_delete[$j]}" + (( j = $j + 1 )) + done + + # unzone clones + zfs_set_array zoned off zoned_clones || + zfs_set_array zoned on zoned_clones 1 + + # rename conflicting snapshots + (( j = 0 )) + while (( $j < $s_origin_c )); do + if [[ "${s_origin_snap[$j]}" != "${s_rename[$j]}" ]]; then + zfs_rename "${s_origin[$j]}" "$fs@${s_rename[$j]}" + if [[ $? != 0 ]]; then + # re-zone the clones before aborting + zfs_set_array zoned on zoned_clones 1 + exit $ZONE_SUBPROC_FATAL + fi + fi + (( j = $j + 1 )) + done + + # re-zone the clones + zfs_set_array zoned on zoned_clones 1 + + # promote the youngest clone of the oldest snapshot + zfs_promote "$s_clone" + + # destroy the origin filesystem and it's descendants + zfs_destroy "$fs" +} + +# +# This function expects an array named fs_all to exist which is initialized +# with the zone's ZFS datasets that should be destroyed. fs_all_c is the +# count of the number of elements in the array. ZONEPATH_RDS is the +# zonepath/root dataset and ZONEPATH_DS is the zonepath dataset. +# +destroy_zone_datasets() +{ + # Destroy the zone BEs datasets one by one. + (( i = 0 )) + while (( $i < $fs_all_c )); do + fs=${fs_all[$i]} + + destroy_zone_dataset "$fs" + (( i = $i + 1 )) + done + + # + # Check if there are any other datasets left. There may be datasets + # associated with other GZ BEs, so we need to leave things alone in + # that case. + # + c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_RDS | wc -l` + if [ $c = 1 ]; then + zfs_destroy "$ZONEPATH_RDS" + fi + c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l` + if [ $c = 1 ]; then + zfs_destroy "$ZONEPATH_DS" + fi + + rm_zonepath +} diff --git a/usr/src/lib/brand/sn1/librtld_db/Makefile.com b/usr/src/lib/brand/sn1/librtld_db/Makefile.com index 171f23bb92..37c809c301 100644 --- a/usr/src/lib/brand/sn1/librtld_db/Makefile.com +++ b/usr/src/lib/brand/sn1/librtld_db/Makefile.com @@ -19,62 +19,11 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -LIBRARY = sn1_librtld_db.a -VERS = .1 -COBJS = sn1_librtld_db.o +COBJS = brand_librtld_db.o OBJECTS = $(COBJS) $(COBJS64) -include $(SRC)/lib/Makefile.lib include ../../Makefile.sn1 - -CSRCS = $(COBJS:%o=../common/%c) -SRCS = $(CSRCS) - -SRCDIR = ../common -UTSBASE = $(SRC)/uts - -# -# ATTENTION: -# Librtl_db brand plugin libraries should NOT directly invoke any -# libproc.so interfaces or be linked against libproc. If a librtl_db -# brand plugin library uses libproc.so interfaces then it may break -# any other librtld_db consumers (like mdb) that tries to attach -# to a branded process. The only safe interfaces that the a librtld_db -# brand plugin library can use to access a target process are the -# proc_service(3PROC) apis. -# -DYNFLAGS += $(VERSREF) -M../common/mapfile-vers -LIBS = $(DYNLIB) -LDLIBS += -lc -lrtld_db -CFLAGS += $(CCVERBOSE) -CPPFLAGS += -D_REENTRANT -I../ -I$(UTSBASE)/common/brand/sn1 \ - -I$(SRC)/cmd/sgs/librtld_db/common \ - -I$(SRC)/cmd/sgs/include \ - -I$(SRC)/cmd/sgs/include/$(MACH) - -ROOTLIBDIR = $(ROOT)/usr/lib/brand/sn1 -ROOTLIBDIR64 = $(ROOT)/usr/lib/brand/sn1/$(MACH64) - -# -# The top level Makefiles define define TEXT_DOMAIN. But librtld_db.so.1 -# isn't internationalized and this library won't be either. The only -# messages that this library can generate are messages used for debugging -# the operation of the library itself. -# -DTEXTDOM = - -.KEEP_STATE: - -all: $(LIBS) - -lint: lintcheck - -pics/%64.o: ../common/%.c - $(COMPILE.c) -D_ELF64 $(PICFLAGS) -o $@ $< - $(POST_PROCESS_O) - -include $(SRC)/lib/Makefile.targ +include $(BRAND_SHARED)/librtld_db/Makefile.com diff --git a/usr/src/lib/brand/sn1/librtld_db/amd64/Makefile b/usr/src/lib/brand/sn1/librtld_db/amd64/Makefile index d1b2579c29..2f81f1df30 100644 --- a/usr/src/lib/brand/sn1/librtld_db/amd64/Makefile +++ b/usr/src/lib/brand/sn1/librtld_db/amd64/Makefile @@ -19,16 +19,15 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -COBJS64 = sn1_librtld_db64.o +COBJS64 = brand_librtld_db64.o include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 CLOBBERFILES = $(ROOTLIBDIR64)/$(DYNLIB) -DYNFLAGS += -M../common/mapfile-vers.64 +DYNFLAGS += -M$(BRAND_SHARED)/librtld_db/common/mapfile-vers.64 install: all $(ROOTLIBS64) diff --git a/usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers b/usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers deleted file mode 100644 index 4f3ef01e3c..0000000000 --- a/usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers +++ /dev/null @@ -1,57 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# MAPFILE HEADER START -# -# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. -# Object versioning must comply with the rules detailed in -# -# usr/src/lib/README.mapfiles -# -# You should not be making modifications here until you've read the most current -# copy of that file. If you need help, contact a gatekeeper for guidance. -# -# MAPFILE HEADER END -# - -SUNWprivate_1.1 { - global: - rtld_db_brand_ops32; - local: - *; -}; - -#Externally defined symbols -{ - global: - ps_pauxv = NODIRECT PARENT; - ps_pdmodel = NODIRECT PARENT; - ps_pglobal_lookup = NODIRECT PARENT; - ps_pglobal_sym = NODIRECT PARENT; - ps_plog = NODIRECT PARENT; - ps_pread = NODIRECT PARENT; - ps_pwrite = NODIRECT PARENT; -}; diff --git a/usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers.64 b/usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers.64 deleted file mode 100644 index 51e0c2c3cc..0000000000 --- a/usr/src/lib/brand/sn1/librtld_db/common/mapfile-vers.64 +++ /dev/null @@ -1,43 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# MAPFILE HEADER START -# -# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. -# Object versioning must comply with the rules detailed in -# -# usr/src/lib/README.mapfiles -# -# You should not be making modifications here until you've read the most current -# copy of that file. If you need help, contact a gatekeeper for guidance. -# -# MAPFILE HEADER END -# - -SUNWprivate_1.1 { - global: - rtld_db_brand_ops64; -}; diff --git a/usr/src/lib/brand/sn1/librtld_db/common/sn1_librtld_db.c b/usr/src/lib/brand/sn1/librtld_db/common/sn1_librtld_db.c deleted file mode 100644 index c4678b78ab..0000000000 --- a/usr/src/lib/brand/sn1/librtld_db/common/sn1_librtld_db.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * ATTENTION: - * Librtl_db brand plugin libraries should NOT directly invoke any - * libproc.so interfaces or be linked against libproc. If a librtl_db - * brand plugin library uses libproc.so interfaces then it may break - * any other librtld_db consumers (like mdb) that tries to attach - * to a branded process. The only safe interfaces that the a librtld_db - * brand plugin library can use to access a target process are the - * proc_service(3PROC) apis. - */ - -/* - * M_DATA comes from some streams header file but is also redifined in - * _rtld_db.h, so nuke the old streams definition here. - */ -#ifdef M_DATA -#undef M_DATA -#endif /* M_DATA */ - -/* - * For 32-bit versions of this library, this file get's compiled once. - * For 64-bit versions of this library, this file get's compiled twice, - * once with _ELF64 defined and once without. The expectation is that - * the 64-bit version of the library can properly deal with both 32-bit - * and 64-bit elf files, hence in the 64-bit library there are two copies - * of all the interfaces in this file, one set named *32 and one named *64. - * - * This also means that we need to be careful when declaring local pointers - * that point to objects in another processes address space, since these - * pointers may not match the current processes pointer width. Basically, - * we should not use any objects that change size between 32 and 64 bit - * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc. - * Instead we should declare all pointers as uint32_t. Then when we - * are compiled to deal with 64-bit targets we'll re-define uing32_t - * to be a uint64_t. - */ -#ifdef _LP64 -#ifdef _ELF64 -#define uint32_t uint64_t -#define Elf32_Dyn Elf64_Dyn -#define validate_rdebug32 validate_rdebug64 -#define _rd_loadobj_iter32 _rd_loadobj_iter64 -#define _rd_get_dyns32 _rd_get_dyns64 -#define dummy_ldb32 dummy_ldb64 -#define dummy_ldb_init32 dummy_ldb_init64 -#define dummy_ldb_fini32 dummy_ldb_fini64 -#define dummy_ldb_loadobj_iter32 dummy_ldb_loadobj_iter64 -#define dummy_ldb_get_dyns32 dummy_ldb_get_dyns64 -#define sn1_ldb_init32 sn1_ldb_init64 -#define sn1_ldb_fini32 sn1_ldb_fini64 -#define sn1_ldb_loadobj_iter32 sn1_ldb_loadobj_iter64 -#define sn1_ldb_get_dyns32 sn1_ldb_get_dyns64 -#endif /* _ELF64 */ -#endif /* _LP64 */ - -/* Included from usr/src/cmd/sgs/librtld_db/common */ -#include <_rtld_db.h> - -/*ARGSUSED*/ -static rd_helper_data_t -dummy_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) -{ - return (NULL); -} - -/*ARGSUSED*/ -static void -dummy_ldb_fini32(rd_helper_data_t rhd) -{ -} - -/*ARGSUSED*/ -static int -dummy_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) -{ - return (RD_OK); -} - -/*ARGSUSED*/ -static rd_err_e -dummy_ldb_get_dyns32(rd_helper_data_t rhd, - psaddr_t addr, void **dynpp, size_t *dynpp_sz) -{ - *dynpp = NULL; - *dynpp_sz = 0; - return (RD_OK); -} - -static rd_helper_ops_t dummy_ldb32 = { - LM_ID_BRAND, - dummy_ldb_init32, - dummy_ldb_fini32, - dummy_ldb_loadobj_iter32, - dummy_ldb_get_dyns32 -}; - -static uint32_t -sn1_ldb_getauxval32(struct ps_prochandle *php, int type) -{ - const auxv_t *auxvp = NULL; - - if (ps_pauxv(php, &auxvp) != PS_OK) - return ((uint32_t)-1); - - while (auxvp->a_type != AT_NULL) { - if (auxvp->a_type == type) - return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr); - auxvp++; - } - return ((uint32_t)-1); -} - -/* - * Normally, the native Solaris librtldb_db plugin uses a bunch of different - * methods to try and find the rdebug structure associated with the target - * process we're debugging. For details on the different methods see - * _rd_reset32(). Thankfully our job is easier. We know that the brand - * library is always linked against the native linker, and when the - * process was first executed we saved off a pointer to the brand linkers - * rdebug structure in one of our brand specific aux vectors, - * AT_SUN_BRAND_SN1_LDDATA. So we'll just look that up here. - */ -/*ARGSUSED*/ -static rd_helper_data_t -sn1_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) -{ - struct rd_agent *rap_new; - uint32_t lddata_addr; - int rd_dmodel; - - if (ps_pdmodel(php, &rd_dmodel) != PS_OK) { - ps_plog("sn1_ldb_init: lookup of data model failed"); - return (NULL); - } -#ifdef _ELF64 - assert(rd_dmodel == PR_MODEL_LP64); -#else /* !_ELF64 */ - assert(rd_dmodel == PR_MODEL_ILP32); -#endif /* !_ELF64 */ - - lddata_addr = sn1_ldb_getauxval32(php, AT_SUN_BRAND_SN1_LDDATA); - if (lddata_addr == (uint32_t)-1) { - ps_plog("sn1_ldb_init: no LDDATA found in aux vector"); - return (NULL); - } - ps_plog("sn1_ldb_init: found LDDATA auxv ld.so.1 data seg " - "at: 0x%p", lddata_addr); - - /* - * Ok. So this is kinda ugly. Basically we know that we're going to - * be parsing data from link maps that are generated by a Solaris - * linker. As it turns out, that's exactly what the default - * Solaris librtld_db library is designed to do. So rather than - * duplicate all that link map parsing code here we'll simply - * invoke the native librtld_db that normally does this, and when - * we do we'll point them at our emulation libraries link map. - * - * Of course these interfacess aren't really public interfaces - * and they take a "struct rd_agent" as a parameter. So here - * we'll allocate and initialize a new "struct rd_agent", point - * it at our emulation libraries link map, and initialize just - * enough of the structure to make the librtld_db interfaces - * that we want to use happy. - */ - if ((rap_new = calloc(sizeof (*rap_new), 1)) == NULL) { - ps_plog("sn1_ldb_init: can't allocate memory"); - return (NULL); - } - rap_new->rd_dmodel = rd_dmodel; - rap_new->rd_psp = php; - rap_new->rd_rdebug = lddata_addr; - (void) mutex_init(&rap_new->rd_mutex, USYNC_THREAD, 0); - - /* - * When we get invoked from librtld_db, and we call back into it, - * librtld_db will once again check if there is a plugin and - * invoke it. Since we don't want to enter a recursive loop - * we're going to specify a different plugin interface for - * our linkmap, and these new plugin interfaces won't actually - * do anything other than return. - */ - rap_new->rd_helper.rh_ops = &dummy_ldb32; - - /* - * validate_rdebug32() requires the following "struct rd_agent" - * members to be initialized: - * rd_psp, rd_rdebug - * - * validate_rdebug32() initializes the following "struct rd_agent" - * members: - * rd_flags, rd_rdebugvers, rd_rtlddbpriv - */ - if (validate_rdebug32(rap_new) != RD_OK) { - ps_plog("sn1_ldb_init: can't find valid r_debug data"); - free(rap_new); - return (NULL); - } - - ps_plog("sn1_ldb_init: finished, helper_data=0x%p", rap_new); - return ((rd_helper_data_t)rap_new); -} - -static void -sn1_ldb_fini32(rd_helper_data_t rhd) -{ - struct rd_agent *rap = (struct rd_agent *)rhd; - ps_plog("lx_ldb_fini: cleaning up sn1 helper"); - free(rap); -} - -/*ARGSUSED*/ -static int -sn1_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) -{ - struct rd_agent *rap = (struct rd_agent *)rhd; - int err; - - ps_plog("sn1_ldb_loadobj_iter(helper_data=0x%p)", rhd); - assert(rap->rd_psp == php); - RDAGLOCK(rap); - /* - * _rd_loadobj_iter32() requires the following "struct rd_agent" - * members to be initialized: - * rd_rtlddbpriv, rd_rdebugvers, rd_flags, - * rd_helper.rh_ops, rd_dmodel - */ - err = _rd_loadobj_iter32(rap, cb, client_data); - RDAGUNLOCK(rap); - ps_plog("sn1_ldb_loadobj_iter: finished, err = %d", err); - return (err); -} - -/*ARGSUSED*/ -static rd_err_e -sn1_ldb_get_dyns32(rd_helper_data_t rhd, - psaddr_t addr, void **dynpp, size_t *dynpp_sz) -{ - struct rd_agent *rap = (struct rd_agent *)rhd; - int err; - - ps_plog("sn1_ldb_get_dyns(helper_data=0x%p)", rhd); - err = _rd_get_dyns32(rap, addr, (Elf32_Dyn **)dynpp, dynpp_sz); - ps_plog("sn1_ldb_get_dyns: finished, err = %d", err); - return (err); -} - -/* - * Librtld_db plugin linkage struct. - * - * When we get loaded by librtld_db, it will look for the symbol below - * to find our plugin entry points. - */ -rd_helper_ops_t RTLD_DB_BRAND_OPS = { - LM_ID_NONE, - sn1_ldb_init32, - sn1_ldb_fini32, - sn1_ldb_loadobj_iter32, - sn1_ldb_get_dyns32 -}; diff --git a/usr/src/lib/brand/sn1/librtld_db/sparcv9/Makefile b/usr/src/lib/brand/sn1/librtld_db/sparcv9/Makefile index d1b2579c29..2f81f1df30 100644 --- a/usr/src/lib/brand/sn1/librtld_db/sparcv9/Makefile +++ b/usr/src/lib/brand/sn1/librtld_db/sparcv9/Makefile @@ -19,16 +19,15 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -COBJS64 = sn1_librtld_db64.o +COBJS64 = brand_librtld_db64.o include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 CLOBBERFILES = $(ROOTLIBDIR64)/$(DYNLIB) -DYNFLAGS += -M../common/mapfile-vers.64 +DYNFLAGS += -M$(BRAND_SHARED)/librtld_db/common/mapfile-vers.64 install: all $(ROOTLIBS64) diff --git a/usr/src/lib/brand/sn1/sn1_brand/Makefile.com b/usr/src/lib/brand/sn1/sn1_brand/Makefile.com index 4059dff444..4d26a454b0 100644 --- a/usr/src/lib/brand/sn1/sn1_brand/Makefile.com +++ b/usr/src/lib/brand/sn1/sn1_brand/Makefile.com @@ -19,18 +19,14 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # LIBRARY = sn1_brand.a VERS = .1 COBJS = sn1_brand.o -ASOBJS = sn1_crt.o sn1_handler.o sn1_runexe.o -OFFSETS_SRC = ../common/offsets.in -OFFSETS_H = assym.h -OBJECTS = $(COBJS) $(ASOBJS) -CLOBBERFILES += $(OFFSETS_H) +ASOBJS = crt.o handler.o runexe.o brand_util.o +OBJECTS = $(COBJS) include ../../Makefile.sn1 include $(SRC)/lib/Makefile.lib @@ -40,19 +36,8 @@ UTSBASE = $(SRC)/uts LIBS = $(DYNLIB) CSRCS = $(COBJS:%o=../common/%c) -ASSRCS = $(ASOBJS:%o=$(ISASRCDIR)/%s) -SRCS = $(CSRCS) $(ASSRCS) - -# -# Ugh, this is a gross hack. Our assembly routines uses lots of defines -# to simplify variable access. All these defines work fine for amd64 -# compiles because when compiling for amd64 we use the GNU assembler, -# gas. For 32-bit code we use the Sun assembler, as. Unfortunatly -# as does not handle certian constructs that gas does. So rather than -# make our code less readable, we'll just use gas to compile our 32-bit -# code as well. -# -i386_AS = $(amd64_AS) +SHAREDOBJS = $(ASOBJS:%o=$(ISAOBJDIR)/%o) +SRCS = $(CSRCS) # # Note that the architecture specific makefiles MUST update DYNFLAGS to @@ -76,30 +61,20 @@ i386_AS = $(amd64_AS) # regular and suid binaries). # NATIVE_DIR = /.SUNWnative -CPPFLAGS += -D_REENTRANT -U_ASM -I. -I../sys -I$(UTSBASE)/common/brand/sn1 +CPPFLAGS += -D_REENTRANT -U_ASM \ + -I. -I$(BRAND_SHARED)/brand/sys -I$(UTSBASE)/common/brand/sn1 CFLAGS += $(CCVERBOSE) -ASFLAGS = -P $(ASFLAGS_$(CURTYPE)) -D_ASM -I. -I../sys DYNFLAGS += $(DYNFLAGS_$(CLASS)) DYNFLAGS += $(BLOCAL) $(ZNOVERSION) -Wl,-e_start #DYNFLAGS += -R$(NATIVE_DIR)/lib -R$(NATIVE_DIR)/usr/lib LDLIBS += -lc -lmapmalloc +$(LIBS):= PICS += $(SHAREDOBJS) + .KEEP_STATE: all: $(LIBS) lint: lintcheck -# -# build the offset header before trying to compile any files. (it's included -# by sn1_misc.h, so it's needed for all objects, not just assembly ones.) -# -$(OBJECTS:%=pics/%): $(OFFSETS_H) -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) $(CTF_FLAGS) < $(OFFSETS_SRC) >$@ - -pics/%.o: $(ISASRCDIR)/%.s - $(COMPILE.s) -o $@ $< - $(POST_PROCESS_O) - include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/brand/sn1/sn1_brand/amd64/Makefile b/usr/src/lib/brand/sn1/sn1_brand/amd64/Makefile index e82bb23093..5b3c3c0ba3 100644 --- a/usr/src/lib/brand/sn1/sn1_brand/amd64/Makefile +++ b/usr/src/lib/brand/sn1/sn1_brand/amd64/Makefile @@ -19,16 +19,17 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # lib/brand/sn1/amd64/Makefile -ISASRCDIR = . +ISAOBJDIR = $(BRAND_SHARED)/brand/amd64/pics/ include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 +CPPFLAGS += -I$(BRAND_SHARED)/brand/amd64 + # # see ../Makefile.com for why we MUST explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_crt.s b/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_crt.s deleted file mode 100644 index 48dbe8e104..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_crt.s +++ /dev/null @@ -1,73 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -#if defined(lint) - -void -_start(void) -{ -} - -#else /* lint */ - /* - * Initial entry point for the brand emulation library. - * - * This platform specific assembly entry point exists just to invoke - * the common brand library startup routine. That routine expects to - * be called with the following arguments: - * sn1_init(int argc, char *argv[], char *envp[]) - * - * There are no arguments explicitly passed to this entry point, - * routine, but we do know how our initial stack has been setup by - * the kernel. The stack format is documented in: - * usr/src/cmd/sgs/rtld/amd64/boot.s - * - * So this routine will troll through the stack to setup the argument - * values for the common brand library startup routine and then invoke - * it. This routine is modeled after the default crt1.s`_start() - * routines. - */ - ENTRY_NP(_start) - - /* Make stack traces look pretty, build a fake stack frame. */ - pushq $0 / Build a stack frame. retpc = NULL - pushq $0 / fp = NULL - movq %rsp, %rbp / first stack frame - - /* - * Calculate the location of the envp array by adding the size of - * the argv array to the start of the argv array. - */ - movq 16(%rbp), %rdi / argc in %rax (1st param) - leaq 24(%rbp), %rsi / &argv[0] in %rbx (2nd param) - leaq 32(%rbp,%rdi,8), %rdx / envp in %rcx (3rd param) - call sn1_init - - /*NOTREACHED*/ - SET_SIZE(_start) -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_handler.s b/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_handler.s deleted file mode 100644 index 1853801302..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_handler.s +++ /dev/null @@ -1,219 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -/* - * Each JMP must occupy 16 bytes - */ -#define JMP \ - pushq $_CONST(. - sn1_handler_table); \ - jmp sn1_handler; \ - .align 16; - -#define JMP4 JMP; JMP; JMP; JMP -#define JMP16 JMP4; JMP4; JMP4; JMP4 -#define JMP64 JMP16; JMP16; JMP16; JMP16 -#define JMP256 JMP64; JMP64; JMP64; JMP64 - -#if defined(lint) - -void -sn1_handler_table(void) -{} - -void -sn1_handler(void) -{ -} - -#else /* lint */ - - /* - * On entry to this table, %rax will hold the return address. The - * location where we enter the table is a function of the system - * call number. The table needs the same alignment as the individual - * entries. - */ - .align 16 - ENTRY_NP(sn1_handler_table) - JMP256 - SET_SIZE(sn1_handler_table) - - /* - * %rax - userland return address - * stack contains: - * | -------------------------------------- - * v 8 | syscall arguments | - * %rsp+0 | syscall number | - * -------------------------------------- - */ - ENTRY_NP(sn1_handler) - pushq %rbp /* allocate stack frame */ - movq %rsp, %rbp - - /* Save registers at the time of the syscall. */ - movq $0, EH_LOCALS_GREG(REG_TRAPNO)(%rbp) - movq $0, EH_LOCALS_GREG(REG_ERR)(%rbp) - movq %r15, EH_LOCALS_GREG(REG_R15)(%rbp) - movq %r14, EH_LOCALS_GREG(REG_R14)(%rbp) - movq %r13, EH_LOCALS_GREG(REG_R13)(%rbp) - movq %r12, EH_LOCALS_GREG(REG_R12)(%rbp) - movq %r11, EH_LOCALS_GREG(REG_R11)(%rbp) - movq %r10, EH_LOCALS_GREG(REG_R10)(%rbp) - movq %r9, EH_LOCALS_GREG(REG_R9)(%rbp) - movq %r8, EH_LOCALS_GREG(REG_R8)(%rbp) - movq %rdi, EH_LOCALS_GREG(REG_RDI)(%rbp) - movq %rsi, EH_LOCALS_GREG(REG_RSI)(%rbp) - movq %rbx, EH_LOCALS_GREG(REG_RBX)(%rbp) - movq %rcx, EH_LOCALS_GREG(REG_RCX)(%rbp) - movq %rdx, EH_LOCALS_GREG(REG_RDX)(%rbp) - xorq %rcx, %rcx - movw %cs, %cx - movq %rcx, EH_LOCALS_GREG(REG_CS)(%rbp) - movw %ds, %cx - movq %rcx, EH_LOCALS_GREG(REG_DS)(%rbp) - movw %es, %cx - movq %rcx, EH_LOCALS_GREG(REG_ES)(%rbp) - movw %fs, %cx - movq %rcx, EH_LOCALS_GREG(REG_FS)(%rbp) - movw %gs, %cx - movq %rcx, EH_LOCALS_GREG(REG_GS)(%rbp) - movw %ss, %cx - movq %rcx, EH_LOCALS_GREG(REG_SS)(%rbp) - pushfq /* save syscall flags */ - popq %r12 - movq %r12, EH_LOCALS_GREG(REG_RFL)(%rbp) - movq EH_ARGS_OFFSET(0)(%rbp), %r12 /* save syscall rbp */ - movq %r12, EH_LOCALS_GREG(REG_RBP)(%rbp) - movq %rbp, %r12 /* save syscall rsp */ - addq $CPTRSIZE, %r12 - movq %r12, EH_LOCALS_GREG(REG_RSP)(%rbp) - movq %fs:0, %r12 /* save syscall fsbase */ - movq %r12, EH_LOCALS_GREG(REG_FSBASE)(%rbp) - movq $0, EH_LOCALS_GREG(REG_GSBASE)(%rbp) - - /* - * The kernel drops us into the middle of the sn1_handle_table - * above that then pushes that table offset onto the stack, and calls - * into sn1_handler. That offset indicates the system call number while - * %rax holds the return address for the system call. We replace the - * value on the stack with the return address, and use the value to - * compute the system call number by dividing by the table entry size. - */ - xchgq CPTRSIZE(%rbp), %rax /* swap JMP table offset and ret addr */ - shrq $4, %rax /* table_offset/size = syscall num */ - movq %rax, EH_LOCALS_GREG(REG_RAX)(%rbp) /* save syscall num */ - - /* - * Finish setting up our stack frame. We would normally do this - * upon entry to this function, but in this case we delayed it - * because a "sub" operation can modify flags and we wanted to - * save the flags into the gregset_t above before they get modified. - * - * Our stack frame format is documented in sn1_misc.h. - */ - subq $EH_LOCALS_SIZE, %rsp - - /* Look up the system call's entry in the sysent table */ - movq sn1_sysent_table@GOTPCREL(%rip), %r11 /* %r11 = sysent_table */ - shlq $4, %rax /* each entry is 16 bytes */ - addq %rax, %r11 /* %r11 = sysent entry address */ - - /* - * Get the return value flag and the number of arguments from the - * sysent table. - */ - movq CPTRSIZE(%r11), %r12 /* number of args + rv flag */ - andq $RV_MASK, %r12 /* strip out number of args */ - movq %r12, EH_LOCALS_RVFLAG(%rbp) /* save rv flag */ - - /* - * Setup arguments for our emulation call. Our input arguments, - * 0 to N, will become emulation call arguments 1 to N+1. - * - * Note: Syscall argument passing is different from function call - * argument passing on amd64. For function calls, the fourth arg - * is passed via %rcx, but for system calls the 4th argument is - * passed via %r10. This is because in amd64, the syscall - * instruction puts lower 32 bit of %rflags in %r11 and puts the - * %rip value to %rcx. - */ - movq EH_ARGS_OFFSET(4)(%rbp), %r12 /* copy 8th arg */ - movq %r12, EH_ARGS_OFFSET(2)(%rsp) - movq EH_ARGS_OFFSET(3)(%rbp), %r12 /* copy 7th arg */ - movq %r12, EH_ARGS_OFFSET(1)(%rsp) - movq %r9, EH_ARGS_OFFSET(0)(%rsp) - movq %r8, %r9 - movq %r10, %r8 - movq %rdx, %rcx - movq %rsi, %rdx - movq %rdi, %rsi - - /* - * The first parameter to the emulation callback function is a - * pointer to a sysret_t structure. - */ - movq %rbp, %rdi - addq $EH_LOCALS_SYSRET, %rdi /* arg0 == sysret_t ptr */ - - /* invoke the emulation routine */ - ALTENTRY(sn1_handler_savepc) - call *(%r11) - - /* restore scratch and parameter registers */ - movq EH_LOCALS_GREG(REG_R12)(%rbp), %r12 /* restore %r12 */ - movq EH_LOCALS_GREG(REG_R11)(%rbp), %r11 /* restore %r11 */ - movq EH_LOCALS_GREG(REG_R10)(%rbp), %r10 /* restore %r10 */ - movq EH_LOCALS_GREG(REG_R9)(%rbp), %r9 /* restore %r9 */ - movq EH_LOCALS_GREG(REG_R8)(%rbp), %r8 /* restore %r8 */ - movq EH_LOCALS_GREG(REG_RCX)(%rbp), %rcx /* restore %rcx */ - movq EH_LOCALS_GREG(REG_RDX)(%rbp), %rdx /* restore %rdx */ - movq EH_LOCALS_GREG(REG_RSI)(%rbp), %rsi /* restore %rsi */ - movq EH_LOCALS_GREG(REG_RDI)(%rbp), %rdi /* restore %rdi */ - - /* Check for syscall emulation success or failure */ - cmpq $0, %rax - je success - stc /* failure, set carry flag */ - jmp return /* return, %rax == errno */ - -success: - /* There is always at least one return value. */ - movq EH_LOCALS_SYSRET1(%rbp), %rax /* %rax == sys_rval1 */ - cmpq $RV_DEFAULT, EH_LOCALS_RVFLAG(%rbp) /* check rv flag */ - je clear_carry - mov EH_LOCALS_SYSRET2(%rbp), %rdx /* %rdx == sys_rval2 */ -clear_carry: - clc /* success, clear carry flag */ - -return: - movq %rbp, %rsp /* restore stack */ - popq %rbp - ret /* ret to instr after syscall */ - SET_SIZE(sn1_handler) - - -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_runexe.s b/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_runexe.s deleted file mode 100644 index 4798d4fe87..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/amd64/sn1_runexe.s +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -/*ARGSUSED*/ -void -sn1_runexe(void *argv, ulong_t entry) -{ -} - -#else /* lint */ - /* - * Prepare to jump to the target program we actually want to run. - * If this program is dynamically linked then we'll be jumping to - * another copy of the linker. If it's a statically linked program - * we'll be jumping directy to it's main entry point. In any case, - * we need to reset our current state stack and register state to - * something similar to the initial process state setup by the kernel - * and documented at: - * usr/src/cmd/sgs/rtld/i386/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * Of course this is the same stack format as when this executable - * was first started, so here we'll just roll back the stack and - * frame pointers to their values when this processes first started - * execution. - */ - ENTRY_NP(sn1_runexe) - - movq %rdi, %rax / %rax = &argv[0] - movq %rsi, %rbx / Brand app entry point in %rbx - subq $8, %rax / Top of stack - must point at argc - movq %rax, %rsp / Set %rsp to what linkers expect - - /* - * We also have to make sure to clear %rdx since nornally ld.so.1 will - * set that to non-zero if there is an exit function that should be - * invoked when the process is terminating. This isn't actually - * necessary if the target program we're jumping to is a dynamically - * linked program since in that case we're actually jumping to another - * copy of ld.so.1 and it will just reset %rdx, but if the target - * program we're jumping to is a statically linked binary that uses - * the standard sun compiler supplied crt1.o`_start(), it will check - * to see if %g1 is set. - */ - movq $0, %rdx - - jmp *%rbx / And away we go... - /* - * target will never return. - */ - SET_SIZE(sn1_runexe) -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/common/offsets.in b/usr/src/lib/brand/sn1/sn1_brand/common/offsets.in deleted file mode 100644 index 2897555874..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/common/offsets.in +++ /dev/null @@ -1,35 +0,0 @@ -\ -\ Copyright 2008 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 (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 -\ - - -#include -#include -#include -#include - -greg_t SIZEOF_GREG_T - -gregset_t SIZEOF_GREGSET_T - -sysret_t SIZEOF_SYSRET_T diff --git a/usr/src/lib/brand/sn1/sn1_brand/common/sn1_brand.c b/usr/src/lib/brand/sn1/sn1_brand/common/sn1_brand.c index 45a3213987..e3941063d2 100644 --- a/usr/src/lib/brand/sn1/sn1_brand/common/sn1_brand.c +++ b/usr/src/lib/brand/sn1/sn1_brand/common/sn1_brand.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -40,115 +39,14 @@ #include #include -#include +#include /* - * Principles of emulation 101. - * - * - * *** Setting errno - * - * Just don't do it. This emulation library is loaded onto a - * seperate link map from the application who's address space we're - * running in. We have our own private copy of libc, so there for, - * the errno value accessible from here is is also private and changing - * it will not affect any errno value that the processes who's address - * space we are running in will see. To return an error condition we - * should return the negated errno value we'd like the system to return. - * For more information about this see the comment in sn1_handler(). - * Basically, when we return to the caller that initiated the system - * call it's their responsibility to set errno. - * - * - * *** Recursion Considerations - * - * When emulating system calls we need to be very careful about what - * library calls we invoke. Library calls should be kept to a minimum. - * One issue is that library calls can invoke system calls, so if we're - * emulating a system call and we invoke a library call that depends on - * that system call we will probably enter a recursive loop, which would - * be bad. - * - * - * *** Return Values. - * - * When declaring new syscall emulation functions, it is very important - * to to set the proper RV_* flags in the sn1_sysent_table. Upon failure, - * syscall emulation fuctions should return an errno value. Upon success - * syscall emulation functions should return 0 and set the sysret_t return - * value parameters accordingly. - * - * - * *** Agent lwp considerations - * - * It is currently impossible to do any emulation for these system call - * when they are being invoked on behalf of an agent lwp. To understand why - * it's impossible you have to understand how agent lwp syscalls work. - * - * The agent lwp syscall process works as follows: - * 1 The controlling process stops the target. - * 2 The controlling process injects an agent lwp which is also stopped. - * This agent lwp assumes the userland stack and register values - * of another stopped lwp in the current process. - * 3 The controlling process configures the agent lwp to start - * executing the requested system call. - * 4 The controlling process configure /proc to stop the agent lwp when - * it enters the requested system call. - * 5 The controlling processes allows the agent lwp to start executing. - * 6 The agent lwp traps into the kernel to perform the requested system - * call and immediately stop. - * 7 The controlling process copies all the arguments for the requested - * system call onto the agent lwp's stack. - * 8 The controlling process configures /proc to stop the agent lwp - * when it completes the requested system call. - * 9 The controlling processes allows the agent lwp to start executing. - * 10 The agent lwp executes the system call and then stop before returning - * to userland. - * 11 The controlling process copies the return value and return arguments - * back from the agent lwps stack. - * 12 The controlling process destroys the agent lwp and restarts - * the target process. - * - * The fundamental problem is that when the agent executes the request - * system call in step 5, if we're emulating that system call then the - * lwp is redirected back to our emulation layer without blocking - * in the kernel. But our emulation layer can't access the arguments - * for the system call because they haven't been copied to the stack - * yet and they still only exist in the controlling processes address - * space. This prevents us from being able to do any emulation of - * agent lwp system calls. Hence, currently our brand trap interposition - * callback (sn1_brand_syscall_callback_common) will detect if a system - * call is being made by an agent lwp, and if this is the case it will - * never redirect the system call to this emulation library. - * - * In the future, if this proves to be a problem the the easiest solution - * would probably be to replace the branded versions of these application - * with their native counterparts. Ie, truss, plimit, and pfiles could be - * replace with wrapper scripts that execute the native versions of these - * applications. In the case of plimit and pfiles this should be pretty - * strait forward. Truss would probably be more tricky since it can - * execute applications which would be branded applications, so in that - * case it might be necessary to create a loadable library which could - * be LD_PRELOADed into truss and this library would interpose on the - * exec() system call to allow truss to correctly execute branded - * processes. It should be pointed out that this solution could work - * because "native agent lwps" (ie, agent lwps created by native - * processes) can be treated differently from "branded aged lwps" (ie, - * agent lwps created by branded processes), since native agent lwps - * would presumably be making native system calls and hence not need - * any interposition. - * + * See usr/src/lib/brand/shared/brand/common/brand_util.c for general + * emulation notes. * * *** sn1 brand emulation scope considerations * - * One of the differences between the lx brand and the s8 and s9 - * brands, is that the s8 and s9 brands only interpose on syscalls - * that need some kind of emulation, where as the lx brand interposes - * on _all_ system calls. Lx branded system calls that don't need - * any emulation are then redirected back to the kernel from the - * userland library via the IN_KERNEL_SYSCALL macro. The lx-syscall - * dtrace provider depends on this behavior. - * * Given that the sn1 brand exists for testing purposes, it should * eventually be enhanced to redirect all system calls through the * brand emulation library. This will ensure the maximum testing @@ -157,126 +55,10 @@ * - Folding the sn1 brand into the native brand and only enabling * it on DEBUG builds. * - Modifying the zones test suite to use sn1 branded zones by default, - * any adapting functional test harnesses to use sn1 branded zones + * and adapting functional test harnesses to use sn1 branded zones * by default instead of native zones. */ -#define EMULATE(cb, args) { (sysent_cb_t)(cb), (args) } -#define NOSYS EMULATE(sn1_unimpl, (0 | RV_DEFAULT)) - -typedef long (*sysent_cb_t)(); -typedef struct sn1_sysent_table { - sysent_cb_t st_callc; - uintptr_t st_args; -} sn1_sysent_table_t; -sn1_sysent_table_t sn1_sysent_table[]; - -/*LINTED: static unused*/ -static volatile int sn1_abort_err; -/*LINTED: static unused*/ -static volatile const char *sn1_abort_msg; -/*LINTED: static unused*/ -static volatile const char *sn1_abort_file; -/*LINTED: static unused*/ -static volatile int sn1_abort_line; - -extern int errno; - -/*ARGSUSED*/ -void -_sn1_abort(int err, const char *msg, const char *file, int line) -{ - sysret_t rval; - - /* Save the error message into convenient globals */ - sn1_abort_err = err; - sn1_abort_msg = msg; - sn1_abort_file = file; - sn1_abort_line = line; - - /* kill ourselves */ - abort(); - - /* If abort() didn't work, try something stronger. */ - (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGKILL); -} - -/* - * This function is defined to be NOSYS but it won't be called from the - * the kernel since the NOSYS system calls are not enabled in the kernel. - * Thus, the only time this function is called is directly from within the - * indirect system call path. - */ -/*ARGSUSED*/ -static long -sn1_unimpl(sysret_t *rv, uintptr_t p1) -{ - sysret_t rval; - - /* - * We'd like to print out some kind of error message here like - * "unsupported syscall", but we can't because it's not safe to - * assume that stderr or STDERR_FILENO actually points to something - * that is a terminal, and if we wrote to those files we could - * inadvertantly write to some applications open files, which would - * be bad. - * - * Normally, if an application calls an invalid system call - * it get a SIGSYS sent to it. So we'll just go ahead and send - * ourselves a signal here. Note that this is far from ideal since - * if the application has registered a signal handler, that signal - * handler may recieve a ucontext_t as the third parameter to - * indicate the context of the process when the signal was - * generated, and in this case that context will not be what the - * application is expecting. Hence, we should probably create a - * brandsys() kernel function that can deliver the signal to us - * with the correct ucontext_t. - */ - (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGSYS); - return (ENOSYS); -} - -#if defined(__sparc) && !defined(__sparcv9) -/* - * Yuck. For 32-bit sparc applications, handle indirect system calls. - * Note that we declare this interface to use the maximum number of - * system call arguments. If we recieve a system call that uses less - * arguments, then the additional arguments will be garbage, but they - * will also be ignored so that should be ok. - */ -static long -sn1_indir(sysret_t *rv, int code, - uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, - uintptr_t a5, uintptr_t a6, uintptr_t a7) -{ - sn1_sysent_table_t *sst = &(sn1_sysent_table[code]); - - sn1_assert(code < NSYSCALL); - switch (sst->st_args & NARGS_MASK) { - case 0: - return ((sst->st_callc)(rv)); - case 1: - return ((sst->st_callc)(rv, a0)); - case 2: - return ((sst->st_callc)(rv, a0, a1)); - case 3: - return ((sst->st_callc)(rv, a0, a1, a2)); - case 4: - return ((sst->st_callc)(rv, a0, a1, a2, a3)); - case 5: - return ((sst->st_callc)(rv, a0, a1, a2, a3, a4)); - case 6: - return ((sst->st_callc)(rv, rv, a0, a1, a2, a3, a4, a5)); - case 7: - return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6)); - case 8: - return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6, a7)); - } - sn1_abort(0, "invalid entry in sn1_sysent_table"); - return (EINVAL); -} -#endif /* __sparc && !__sparcv9 */ - static long sn1_uname(sysret_t *rv, uintptr_t p1) { @@ -287,7 +69,7 @@ sn1_uname(sysret_t *rv, uintptr_t p1) return (err); rev = atoi(&un.release[2]); - sn1_assert(rev >= 10); + brand_assert(rev >= 10); (void) sprintf(un.release, "5.%d", rev - 1); if (uucopy(&un, unp, sizeof (un)) != 0) @@ -295,177 +77,18 @@ sn1_uname(sysret_t *rv, uintptr_t p1) return (0); } -/* - * Close a libc file handle, but don't actually close the underlying - * file descriptor. - */ -static void -sn1_close_fh(FILE *file) -{ - int fd, fd_new; - - if (file == NULL) - return; - - if ((fd = fileno(file)) < 0) - return; - - /* - * While we could use dup() since we're linked with the native libc, - * the dup() syscall itself no longer exists so this would be - * problematic for any brands built from sn1. - */ - fd_new = fcntl(fd, F_DUPFD, 0); - if (fd_new == -1) - return; - - (void) fclose(file); - (void) dup2(fd_new, fd); - (void) close(fd_new); -} - /*ARGSUSED*/ int -sn1_init(int argc, char *argv[], char *envp[]) +brand_init(int argc, char *argv[], char *envp[]) { - sysret_t rval; - sn1_brand_reg_t reg; - sn1_elf_data_t sed; - auxv_t *ap; - uintptr_t *p; - int i, err; - - /* Sanity check our translation table return value codes */ - for (i = 0; i < NSYSCALL; i++) { - sn1_sysent_table_t *est = &(sn1_sysent_table[i]); - sn1_assert(BIT_ONLYONESET(est->st_args & RV_MASK)); - } - - /* - * We need to shutdown all libc stdio. libc stdio normally goes to - * file descriptors, but since we're actually part of a another - * process we don't own these file descriptors and we can't make - * any assumptions about their state. - */ - sn1_close_fh(stdin); - sn1_close_fh(stdout); - sn1_close_fh(stderr); - - /* - * Register our syscall emulation table with the kernel. - * Note that we don't have to do invoke (syscall_number + 1024) - * until we've actually establised a syscall emulation callback - * handler address, which is what we're doing with this brand - * syscall. - */ - reg.sbr_version = SN1_VERSION; -#ifdef __x86 - reg.sbr_handler = (caddr_t)sn1_handler_table; -#else /* !__x86 */ - reg.sbr_handler = (caddr_t)sn1_handler; -#endif /* !__x86 */ - if ((err = __systemcall(&rval, SYS_brand, B_REGISTER, ®)) != 0) { - sn1_abort(err, "Failed to brand current process"); - /*NOTREACHED*/ - } - - /* Get data about the executable we're running from the kernel. */ - if ((err = __systemcall(&rval, SYS_brand + 1024, - B_ELFDATA, (void *)&sed)) != 0) { - sn1_abort(err, - "Failed to get required brand ELF data from the kernel"); - /*NOTREACHED*/ - } - - /* - * Find the aux vector on the stack. - */ - p = (uintptr_t *)envp; - while (*p != NULL) - p++; + ulong_t ldentry; - /* - * p is now pointing at the 0 word after the environ pointers. - * After that is the aux vectors. - * - * The aux vectors are currently pointing to the brand emulation - * library and associated linker. We're going to change them to - * point to the brand executable and associated linker (or to no - * linker for static binaries). This matches the process data - * stored within the kernel and visible from /proc, which was - * all setup in sn1_elfexec(). We do this so that when a debugger - * attaches to the process it sees the process as a normal solaris - * process, this brand emulation library and everything on it's - * link map will not be visible, unless our librtld_db plugin - * is used. Note that this is very different from how Linux - * branded processes are implemented within lx branded zones. - * In that situation, the primary linkmap of the process is the - * brand emulation libraries linkmap, not the Linux applications - * linkmap. - * - * We also need to clear the AF_SUN_NOPLM flag from the AT_SUN_AUXFLAGS - * aux vector. This flag told our linker that we don't have a - * primary link map. Now that our linker is done initializing, we - * want to clear this flag before we transfer control to the - * applications copy of the linker, since we want that linker to have - * a primary link map which will be the link map for the application - * we're running. - */ - p++; - for (ap = (auxv_t *)p; ap->a_type != AT_NULL; ap++) { - switch (ap->a_type) { - case AT_BASE: - /* Hide AT_BASE if static binary */ - if (sed.sed_base == NULL) { - ap->a_type = AT_IGNORE; - ap->a_un.a_val = NULL; - } else { - ap->a_un.a_val = sed.sed_base; - } - break; - case AT_ENTRY: - ap->a_un.a_val = sed.sed_entry; - break; - case AT_PHDR: - ap->a_un.a_val = sed.sed_phdr; - break; - case AT_PHENT: - ap->a_un.a_val = sed.sed_phent; - break; - case AT_PHNUM: - ap->a_un.a_val = sed.sed_phnum; - break; - case AT_SUN_AUXFLAGS: - ap->a_un.a_val &= ~AF_SUN_NOPLM; - break; - case AT_SUN_EMULATOR: - /* - * ld.so.1 inspects AT_SUN_EMULATOR to see if - * if it is the linker for the brand emulation - * library. Hide AT_SUN_EMULATOR, as the - * linker we are about to jump to is the linker - * for the binary. - */ - ap->a_type = AT_IGNORE; - ap->a_un.a_val = NULL; - break; - case AT_SUN_LDDATA: - /* Hide AT_SUN_LDDATA if static binary */ - if (sed.sed_lddata == NULL) { - ap->a_type = AT_IGNORE; - ap->a_un.a_val = NULL; - } else { - ap->a_un.a_val = sed.sed_lddata; - } - break; - default: - break; - } - } + brand_pre_init(); + ldentry = brand_post_init(SN1_VERSION, argc, argv, envp); - sn1_runexe(argv, sed.sed_ldentry); + brand_runexe(argv, ldentry); /*NOTREACHED*/ - sn1_abort(0, "sn1_runexe() returned"); + brand_abort(0, "brand_runexe() returned"); return (-1); } @@ -499,15 +122,15 @@ IN_KERNEL_SYSCALL(waitid, SYS_waitid) /* 107 */ /* * This table must have at least NSYSCALL entries in it. * - * The second parameter of each entry in the sn1_sysent_table + * The second parameter of each entry in the brand_sysent_table * contains the number of parameters and flags that describe the * syscall return value encoding. See the block comments at the * top of this file for more information about the syscall return * value flags and when they should be used. */ -sn1_sysent_table_t sn1_sysent_table[] = { +brand_sysent_table_t brand_sysent_table[] = { #if defined(__sparc) && !defined(__sparcv9) - EMULATE(sn1_indir, 9 | RV_64RVAL), /* 0 */ + EMULATE(brand_indir, 9 | RV_64RVAL), /* 0 */ #else /* !__sparc || __sparcv9 */ NOSYS, /* 0 */ #endif /* !__sparc || __sparcv9 */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/i386/Makefile b/usr/src/lib/brand/sn1/sn1_brand/i386/Makefile index e5f9fdb455..9175087c0b 100644 --- a/usr/src/lib/brand/sn1/sn1_brand/i386/Makefile +++ b/usr/src/lib/brand/sn1/sn1_brand/i386/Makefile @@ -19,15 +19,16 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # lib/brand/sn1/i386/Makefile -ISASRCDIR = . +ISAOBJDIR = $(BRAND_SHARED)/brand/i386/pics include ../Makefile.com +CPPFLAGS += -I$(BRAND_SHARED)/brand/i386 + # # see ../Makefile.com for why we explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_crt.s b/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_crt.s deleted file mode 100644 index f4c6e8d408..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_crt.s +++ /dev/null @@ -1,77 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -#if defined(lint) - -void -_start(void) -{ -} - -#else /* lint */ - /* - * Initial entry point for the brand emulation library. - * - * This platform specific assembly entry point exists just to invoke - * the common brand library startup routine. That routine expects to - * be called with the following arguments: - * sn1_init(int argc, char *argv[], char *envp[]) - * - * There are no arguments explicitly passed to this entry point, - * routine, but we do know how our initial stack has been setup by - * the kernel. The stack format is documented in: - * usr/src/cmd/sgs/rtld/i386/boot.s - * - * So this routine will troll through the stack to setup the argument - * values for the common brand library startup routine and then invoke - * it. This routine is modeled after the default crt1.s`_start() - * routines. - */ - ENTRY_NP(_start) - - /* Make stack traces look pretty, build a fake stack frame. */ - pushl $0 / retpc = NULL - pushl $0 / fp = NULL - movl %esp, %ebp / first stack frame - - /* - * Calculate the location of the envp array by adding the size of - * the argv array to the start of the argv array. - */ - movl 8(%ebp), %eax / argc in %eax - leal 12(%ebp), %ebx / &argv[0] in %ebx - leal 16(%ebp,%eax,4), %ecx / envp in %ecx - - pushl %ecx / push envp (3rd param) - pushl %ebx / push argv (2nd param) - pushl %eax / push argc (1st param) - call sn1_init - - /*NOTREACHED*/ - SET_SIZE(_start) -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_handler.s b/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_handler.s deleted file mode 100644 index 66bef79ad1..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_handler.s +++ /dev/null @@ -1,196 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -/* - * Each JMP must occupy 16 bytes - */ -#define JMP \ - pushl $_CONST(. - sn1_handler_table); \ - jmp sn1_handler; \ - .align 16; - -#define JMP4 JMP; JMP; JMP; JMP -#define JMP16 JMP4; JMP4; JMP4; JMP4 -#define JMP64 JMP16; JMP16; JMP16; JMP16 -#define JMP256 JMP64; JMP64; JMP64; JMP64 - -#if defined(lint) - -void -sn1_handler_table(void) -{} - -void -sn1_handler(void) -{ -} - -#else /* lint */ - - /* - * On entry to this table, %eax will hold the return address. The - * location where we enter the table is a function of the system - * call number. The table needs the same alignment as the individual - * entries. - */ - .align 16 - ENTRY_NP(sn1_handler_table) - JMP256 - SET_SIZE(sn1_handler_table) - -#define PIC_SETUP(r) \ - call 9f; \ -9: \ - popl r; \ - addl $_GLOBAL_OFFSET_TABLE_ + [. - 9b], r - - /* - * %eax - userland return address - * stack contains: - * | -------------------------------------- - * v 4 | syscall arguments | - * %esp+0 | syscall number | - * -------------------------------------- - */ - ENTRY_NP(sn1_handler) - pushl %ebp /* allocate a stack frame */ - movl %esp, %ebp - - /* Save registers at the time of the syscall. */ - movl $0, EH_LOCALS_GREG(TRAPNO)(%ebp) - movl $0, EH_LOCALS_GREG(ERR)(%ebp) - movl %ebx, EH_LOCALS_GREG(EBX)(%ebp) - movl %ecx, EH_LOCALS_GREG(ECX)(%ebp) - movl %edx, EH_LOCALS_GREG(EDX)(%ebp) - movl %edi, EH_LOCALS_GREG(EDI)(%ebp) - movl %esi, EH_LOCALS_GREG(ESI)(%ebp) - mov %cs, EH_LOCALS_GREG(CS)(%ebp) - mov %ds, EH_LOCALS_GREG(DS)(%ebp) - mov %es, EH_LOCALS_GREG(ES)(%ebp) - mov %fs, EH_LOCALS_GREG(FS)(%ebp) - mov %gs, EH_LOCALS_GREG(GS)(%ebp) - pushfl /* save syscall flags */ - popl %ecx - movl %ecx, EH_LOCALS_GREG(EFL)(%ebp) - movl EH_ARGS_OFFSET(0)(%ebp), %ecx /* save syscall ebp */ - movl %ecx, EH_LOCALS_GREG(EBP)(%ebp) - movl %ebp, %ecx /* save syscall esp */ - addl $CPTRSIZE, %ecx - movl %ecx, EH_LOCALS_GREG(ESP)(%ebp) - - /* - * The kernel drops us into the middle of the sn1_handle_table - * above that then pushes that table offset onto the stack, and calls - * into sn1_handler. That offset indicates the system call number while - * %eax holds the return address for the system call. We replace the - * value on the stack with the return address, and use the value to - * compute the system call number by dividing by the table entry size. - */ - xchgl CPTRSIZE(%ebp), %eax /* swap JMP table offset and ret addr */ - shrl $4, %eax /* table_offset/size = syscall num */ - movl %eax, EH_LOCALS_GREG(EAX)(%ebp) /* save syscall num */ - - /* - * Finish setting up our stack frame. We would normally do this - * upon entry to this function, but in this case we delayed it - * because a "sub" operation can modify flags and we wanted to - * save the flags into the gregset_t above before they get modified. - * - * Our stack frame format is documented in sn1_misc.h. - */ - subl $EH_LOCALS_SIZE, %esp - - /* Look up the system call's entry in the sysent table */ - PIC_SETUP(%ecx) - movl sn1_sysent_table@GOT(%ecx), %edx /* %edx = sysent_table */ - shll $3, %eax /* each entry is 8 bytes */ - add %eax, %edx /* %edx = sysent entry address */ - - /* - * Get the return value flag and the number of arguments from the - * sysent table. - */ - movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ - andl $RV_MASK, %ecx /* strip out number of args */ - movl %ecx, EH_LOCALS_RVFLAG(%ebp) /* save rv flag */ - movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ - andl $NARGS_MASK, %ecx /* strip out rv flag */ - - /* - * Setup arguments for our emulation call. Our input arguments, - * 0 to N, will become emulation call arguments 1 to N+1. - * %ecx == number of arguments. - */ - movl %ebp, %esi /* args are at 12(%ebp) */ - addl $EH_ARGS_OFFSET(3), %esi - movl %esp, %edi /* copy args to 4(%esp) */ - addl $EH_ARGS_OFFSET(1), %edi - rep; smovl /* copy: (%esi) -> (%edi) */ - /* copy: %ecx 32-bit words */ - movl EH_LOCALS_GREG(ESI)(%ebp), %esi /* restore %esi */ - movl EH_LOCALS_GREG(EDI)(%ebp), %edi /* restore %edi */ - - /* - * The first parameter to the emulation callback function is a - * pointer to a sysret_t structure. - */ - movl %ebp, %ecx - addl $EH_LOCALS_SYSRET, %ecx - movl %ecx, EH_ARGS_OFFSET(0)(%esp) /* arg0 == sysret_t ptr */ - - /* invoke the emulation routine */ - ALTENTRY(sn1_handler_savepc) - call *(%edx) /* call emulation routine */ - - /* restore scratch registers */ - movl EH_LOCALS_GREG(ECX)(%ebp), %ecx /* restore %ecx */ - movl EH_LOCALS_GREG(EDX)(%ebp), %edx /* restore %edx */ - - /* Check for syscall emulation success or failure */ - cmpl $0, %eax /* check for an error */ - je success - stc /* failure, set carry flag */ - jmp return /* return, %rax == errno */ - -success: - /* There is always at least one return value. */ - movl EH_LOCALS_SYSRET1(%ebp), %eax /* %eax == sys_rval1 */ - cmpl $RV_DEFAULT, EH_LOCALS_RVFLAG(%ebp) /* check rv flag */ - je clear_carry - mov EH_LOCALS_SYSRET2(%ebp), %edx /* %edx == sys_rval2 */ -clear_carry: - clc /* success, clear carry flag */ - -return: - movl %ebp, %esp /* restore stack */ - popl %ebp - ret /* ret to instr after syscall */ - SET_SIZE(sn1_handler) - - -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_runexe.s b/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_runexe.s deleted file mode 100644 index 8e9eec3f6d..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/i386/sn1_runexe.s +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -/*ARGSUSED*/ -void -sn1_runexe(void *argv, ulong_t entry) -{ -} - -#else /* lint */ - /* - * Prepare to jump to the target program we actually want to run. - * If this program is dynamically linked then we'll be jumping to - * another copy of the linker. If it's a statically linked program - * we'll be jumping directy to it's main entry point. In any case, - * we need to reset our current state stack and register state to - * something similar to the initial process state setup by the kernel - * and documented at: - * usr/src/cmd/sgs/rtld/i386/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * Of course this is the same stack format as when this executable - * was first started, so here we'll just roll back the stack and - * frame pointers to their values when this processes first started - * execution. - */ - ENTRY_NP(sn1_runexe) - - movl 4(%esp), %eax / %eax = &argv[0] - movl 8(%esp), %ebx / Brand app entry point in %ebx - subl $4, %eax / Top of stack - must point at argc - movl %eax, %esp / Set %esp to what linkers expect - - /* - * We also have to make sure to clear %edx since nornally ld.so.1 will - * set that to non-zero if there is an exit function that should be - * invoked when the process is terminating. This isn't actually - * necessary if the target program we're jumping to is a dynamically - * linked program since in that case we're actually jumping to another - * copy of ld.so.1 and it will just reset %edx, but if the target - * program we're jumping to is a statically linked binary that uses - * the standard sun compiler supplied crt1.o`_start(), it will check - * to see if %g1 is set. - */ - movl $0, %edx - - jmp *%ebx / And away we go... - /* - * target will never return. - */ - SET_SIZE(sn1_runexe) -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/sparc/Makefile b/usr/src/lib/brand/sn1/sn1_brand/sparc/Makefile index 1f2a6c7f89..0ee543b052 100644 --- a/usr/src/lib/brand/sn1/sn1_brand/sparc/Makefile +++ b/usr/src/lib/brand/sn1/sn1_brand/sparc/Makefile @@ -19,15 +19,16 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # lib/brand/sn1/sparc/Makefile -ISASRCDIR = . +ISAOBJDIR = $(BRAND_SHARED)/brand/sparc/pics include ../Makefile.com +CPPFLAGS += -I$(BRAND_SHARED)/brand/sparc + # # see ../Makefile.com for why we MUST explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_crt.s b/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_crt.s deleted file mode 100644 index e4931d67b3..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_crt.s +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -void -_start(void) -{ -} - -#else /* lint */ - .section ".text" - /* - * Initial entry point for the brand emulation library. - * - * This platform specific assembly entry point exists just to invoke - * the common brand library startup routine. That routine expects to - * be called with the following arguments: - * sn1_init(int argc, char *argv[], char *envp[]) - * - * There are no arguments explicitly passed to this entry point, - * routine, but we do know how our initial stack has been setup by - * the kernel. The stack format is documented in: - * usr/src/cmd/sgs/rtld/sparc/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * So this routine will troll through the stack to setup the argument - * values for the common brand library startup routine and then invoke - * it. - */ - ENTRY_NP(_start) -#if defined (__sparcv9) - save %sp, -SA(MINFRAME + EB_MAX_SIZE64), %sp -#else /* !__sparcv9 */ - save %sp, -SA(MINFRAME + EB_MAX_SIZE32), %sp -#endif /* !__sparcv9 */ - - /* get argc */ - ldn [%fp + WINDOWSIZE + STACK_BIAS], %o0 - - /* get argv */ - add %fp, + WINDOWSIZE + CPTRSIZE + STACK_BIAS, %o1 - - /* get envp */ - add %o0, 1, %l0 ! add 1 to argc for last element of 0 - sll %l0, CPTRSHIFT, %l0 ! multiply argc by pointer size - add %o1, %l0, %o2 ! and add to argv to get first env ptr - - call sn1_init - nop - - /*NOTREACHED*/ - SET_SIZE(_start) -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_handler.s b/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_handler.s deleted file mode 100644 index b96782c037..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_handler.s +++ /dev/null @@ -1,225 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -#if defined(lint) - -void -sn1_handler(void) -{ -} - -#else /* !lint */ - -#define PIC_SETUP(r) \ - mov %o7, %g1; \ -9: call 8f; \ - sethi %hi(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ -8: or r, %lo(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ - add r, %o7, r; \ - mov %g1, %o7 - -/* - * Translate a global symbol into an address. The resulting address - * is returned in the first register parameter. The second register - * is just for scratch space. - */ -#if defined(__sparcv9) -#define GET_SYM_ADDR(r1, r2, name) \ - PIC_SETUP(r1) ;\ - sethi %hi(name), r2 ;\ - or r2, %lo(name), r2 ;\ - ldn [r2 + r1], r1 -#else /* !__sparcv9 */ -#define GET_SYM_ADDR(r1, r2, name) \ - PIC_SETUP(r1); \ - ld [r1 + name], r1 -#endif /* !__sparcv9 */ - - .section ".text" - - /* - * When we get here, %g1 should contain the system call and - * %g5 should contain the address immediately after the trap - * instruction. - */ - ENTRY_NP(sn1_handler) - - /* - * 64-bit sparc may need to save 3 parameters on the stack. - * 32-bit sparc may need to save 4 parameters on the stack. - * - * Our stack frame format is documented in sn1_misc.h. - */ - save %sp, -SA(MINFRAME + EH_LOCALS_SIZE), %sp - - /* - * Save the current caller state into gregs and gwins. - * Note that this state isn't exact, %g1 and %g5 have been - * already been lost. Also, we've pushed a stack frame so - * the callers output registers are our input registers. - */ - stn %g0, [%sp + EH_LOCALS_GREG(REG_G1)] /* %g1 is lost */ - stn %g2, [%sp + EH_LOCALS_GREG(REG_G2)] - stn %g3, [%sp + EH_LOCALS_GREG(REG_G3)] - stn %g4, [%sp + EH_LOCALS_GREG(REG_G4)] - stn %g0, [%sp + EH_LOCALS_GREG(REG_G5)] /* %g5 is lost */ - stn %g6, [%sp + EH_LOCALS_GREG(REG_G6)] - stn %g7, [%sp + EH_LOCALS_GREG(REG_G7)] - stn %i0, [%sp + EH_LOCALS_GREG(REG_O0)] - stn %i1, [%sp + EH_LOCALS_GREG(REG_O1)] - stn %i2, [%sp + EH_LOCALS_GREG(REG_O2)] - stn %i3, [%sp + EH_LOCALS_GREG(REG_O3)] - stn %i4, [%sp + EH_LOCALS_GREG(REG_O4)] - stn %i5, [%sp + EH_LOCALS_GREG(REG_O5)] - stn %i6, [%sp + EH_LOCALS_GREG(REG_O6)] - stn %i7, [%sp + EH_LOCALS_GREG(REG_O7)] - sub %g5, 4, %o0 - stn %o0, [%sp + EH_LOCALS_GREG(REG_PC)] - stn %g5, [%sp + EH_LOCALS_GREG(REG_nPC)] - rd %y, %o0 - stn %o0, [%sp + EH_LOCALS_GREG(REG_Y)] -#if defined(__sparcv9) - stn %g0, [%sp + EH_LOCALS_GREG(REG_ASI)] - rd %fprs, %o0 - stn %o0, [%sp + EH_LOCALS_GREG(REG_FPRS)] -#endif /* __sparcv9 */ - - /* - * Look up the system call's entry in the sysent table - * and obtain the address of the proper emulation routine (%l2). - */ - mov %g1, %l5 /* save syscall number */ - GET_SYM_ADDR(%l1, %l2, sn1_sysent_table) - mov %l5, %g1 /* restore syscall number */ - sll %g1, (1 + CLONGSHIFT), %l2 /* Each entry has 2 longs */ - add %l2, %l1, %l2 /* index to proper entry */ - ldn [%l2], %l2 /* emulation func address */ - - /* - * Look up the system call's entry in the sysent table, - * taking into account the posibility of indirect system calls, and - * obtain the number of arguments (%l4) and return value flag (%l3). - */ -#if defined(__sparcv9) - mov %g1, %l3 /* %g1 == syscall number */ -#else /* !__sparcv9 */ - /* - * Check for indirect system calls, in which case the real syscall - * number is the first parameter to the indirect system call. - */ - cmp %g1, %g0 /* saved syscall number */ - bne,a,pt %icc, no_indir /* indirect syscall? */ - mov %g1, %l3 /* %g1 == syscall number */ - mov %i0, %l3 /* %i0 == syscall number */ -no_indir: -#endif /* !__sparcv9 */ - sll %l3, (1 + CLONGSHIFT), %l3 /* Each entry has 2 longs */ - add %l3, %l1, %l3 /* index to proper entry */ - ldn [%l3 + CPTRSIZE], %l4 /* number of args + rv flag */ - sethi %hi(RV_MASK), %l5 - or %l5, %lo(RV_MASK), %l5 - andcc %l4, %l5, %l3 /* strip out number of args*/ - andcc %l4, NARGS_MASK, %l4 /* strip out rv flag */ - - /* - * Setup arguments for our emulation call. Our input arguments, - * 0 to N, will become emulation call arguments 1 to N+1. - * %l4 == number of arguments. - */ - mov %i0, %o1 - mov %i1, %o2 - mov %i2, %o3 - mov %i3, %o4 - mov %i4, %o5 - - /* 7th argument and above get passed on the stack */ - cmp %l4, 0x6 - bl,pt %ncc, args_copied - nop - stn %i5, [%sp + EH_ARGS_OFFSET(0)] /* copy 6th syscall arg */ - cmp %l4, 0x7 - bl,pt %ncc, args_copied - nop - ldn [%fp + EH_ARGS_OFFSET(0)], %l5 /* copy 7th syscall arg */ - stn %l5, [%sp + EH_ARGS_OFFSET(1)] - cmp %l4, 0x8 - bl,pt %ncc, args_copied - nop - ldn [%fp + EH_ARGS_OFFSET(1)], %l5 - stn %l5, [%sp + EH_ARGS_OFFSET(2)] /* copy 8th syscall arg */ -#if !defined(__sparcv9) - cmp %l4, 0x9 - bl,pt %ncc, args_copied - nop - ldn [%fp + EH_ARGS_OFFSET(2)], %l5 - stn %l5, [%sp + EH_ARGS_OFFSET(3)] /* copy 9th syscall arg */ -#endif /* !__sparcv9 */ - -args_copied: - /* - * The first parameter to the emulation callback function is a - * pointer to a sysret_t structure. - * - * invoke the emulation routine. - */ - ALTENTRY(sn1_handler_savepc) - call %l2 - add %sp, EH_LOCALS_SYSRET, %o0 /* arg0 == sysret_t ptr */ - - /* Check for syscall emulation success or failure */ - cmp %g0, %o0 - be success - nop - subcc %g0, 1, %g0 /* failure, set carry flag */ - ba return - mov %o0, %i0 /* return, %o0 == errno */ - -success: - /* There is always at least one return value. */ - ldn [%sp + EH_LOCALS_SYSRET1], %i0 /* %i0 == sys_rval1 */ - cmp %l3, RV_DEFAULT /* check rv flag */ - be,a clear_carry - mov %g0, %i1 /* clear second rval */ - ldn [%sp + EH_LOCALS_SYSRET2], %i1 /* %i1 == sys_rval2 */ -clear_carry: - addcc %g0, %g0, %g0 /* success, clear carry flag */ - -return: - /* - * Our syscall emulation is complete. Return to the caller that - * originally invoked a system which needed emulation. Note that - * we have to load the return address that we saved earlier because - * it's possible that %g5 was overwritten by a nested call into - * this emulation library. - */ - ldn [%sp + EH_LOCALS_GREG(REG_nPC)], %g5 - jmp %g5 - restore /* delay slot */ - SET_SIZE(sn1_handler) - - -#endif /* !lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_runexe.s b/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_runexe.s deleted file mode 100644 index 67dcb8895d..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/sparc/sn1_runexe.s +++ /dev/null @@ -1,82 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -/*ARGSUSED*/ -void -sn1_runexe(void *argv, ulong_t entry) -{ -} - -#else /* lint */ - .section ".text" - ENTRY_NP(sn1_runexe) - /* - * Prepare to jump to the target program we actually want to run. - * If this program is dynamically linked then we'll be jumping to - * another copy of the linker. If it's a statically linked program - * we'll be jumping directy to it's main entry point. In any case, - * we need to reset our current state stack and register state to - * something similar to the initial process state setup by the kernel - * and documented at: - * usr/src/cmd/sgs/rtld/sparc/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * Of course this is the same stack format as when this executable - * was first started, so here we'll just roll back the stack and - * frame pointers to their values when this processes first started - * execution. - * - * Our input parameters are stored in the %o? registers since we - * don't bother to allocate a new stack frame. - */ - sub %o0, CPTRSIZE + WINDOWSIZE + STACK_BIAS, %sp - clr %fp - - /* - * We also have to make sure to clear %g1 since nornally ld.so.1 will - * set that to non-zero if there is an exit function that should be - * invoked when the process is terminating. This isn't actually - * necessary if the target program we're jumping to is a dynamically - * linked program since in that case we're actually jumping to another - * copy of ld.so.1 and it will just reset %g1, but if the target - * program we're jumping to is a statically linked binary that uses - * the standard sun compiler supplied crt1.o`_start(), it will check - * to see if %g1 is set. - */ - clr %g1 - - jmp %o1 ! jump to the target processes entry point - nop - /* - * target will never return. - */ - SET_SIZE(sn1_runexe) -#endif /* lint */ diff --git a/usr/src/lib/brand/sn1/sn1_brand/sparcv9/Makefile b/usr/src/lib/brand/sn1/sn1_brand/sparcv9/Makefile index 90c9270c00..1d9c1aa3b8 100644 --- a/usr/src/lib/brand/sn1/sn1_brand/sparcv9/Makefile +++ b/usr/src/lib/brand/sn1/sn1_brand/sparcv9/Makefile @@ -19,16 +19,17 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # lib/brand/sn1/sparcv9/Makefile -ISASRCDIR = ../sparc +ISAOBJDIR = $(BRAND_SHARED)/brand/sparcv9/pics include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 +CPPFLAGS += -I$(BRAND_SHARED)/brand/sparcv9 + # # see ../Makefile.com for why we explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/sn1/sn1_brand/sys/sn1_misc.h b/usr/src/lib/brand/sn1/sn1_brand/sys/sn1_misc.h deleted file mode 100644 index 7a420b168c..0000000000 --- a/usr/src/lib/brand/sn1/sn1_brand/sys/sn1_misc.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SN1_MISC_H -#define _SN1_MISC_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This header file must uses _ASM defines to allow it to be included - * in assmebly source files - */ -#include -#include -#include -#include "assym.h" - -/* - * Our syscall emulation callback handler adds one argument to each - * system call, so we'll need to allocate space for one more argument - * above the maximum number of arguments that a system call can normally - * take. Also, we assume that each syscall argument is a long, ie, we - * don't support long long syscall parameters. - */ -#if defined(__sparc) -/* - * 32-bit and 64-bit sparc syscalls can take up to 8 arguments. - * 32-bit sparc indirect syscalls can take up to 9 arguments. - * Arguments 1 - 6 are passed via %o0 - %o5. - * Additional arguments are passed on the stack. - * So make space for 4 arguments on the stack. - */ -#define EH_ARGS_COUNT 4 -#elif defined(__amd64) -/* - * amd64 syscalls can take up to 8 arguments. - * Arguments 1 - 6 are passed via: %rdi, %rsi, %rdx, %r10, %r8, %r9 - * Additional arguments are passed on the stack. - * So make space for 3 arguments on the stack. - */ -#define EH_ARGS_COUNT 3 -#else /* !__sparc && !__amd64 */ -/* - * ia32 syscalls can take up to 8 arguments. - * All arguments are passed on the stack. - * So make space for 9 arguments on the stack. - */ -#define EH_ARGS_COUNT 9 -#endif /* !__sparc && !__amd64 */ - - -#define EH_ARGS_SIZE (CPTRSIZE * EH_ARGS_COUNT) -#define EH_ARGS_OFFSET(x) (STACK_BIAS + MINFRAME + (CPTRSIZE * (x))) -#define EH_LOCALS_SIZE (EH_ARGS_SIZE + SIZEOF_GREGSET_T + \ - SIZEOF_SYSRET_T + CPTRSIZE) - -#if defined(__sparc) -/* - * On sparc, all emulation callback handler variable access is done - * relative to %sp, so access offsets are positive. - */ -#define EH_LOCALS_START (STACK_BIAS + MINFRAME + EH_ARGS_SIZE) -#define EH_LOCALS_END_TGT (STACK_BIAS + MINFRAME + EH_LOCALS_SIZE) -#else /* !__sparc */ -/* - * On x86, all emulation callback handler variable access is done - * relative to %ebp/%rbp, so access offsets are negative. - */ -#define EH_LOCALS_START (-(EH_LOCALS_SIZE - \ - (STACK_BIAS + MINFRAME + EH_ARGS_SIZE))) -#define EH_LOCALS_END_TGT 0 -#endif /* !__sparc */ - -/* - * In our emulation callback handler, our stack will look like: - * ------------------------------------------------- - * %bp | long rvflag | - * | | sysret_t sysret | - * v | gregset_t gregs | - * %sp | long callback args[EH_ARGS_COUNT] | - * ------------------------------------------------- - * For ia32, use %ebp and %esp instead of %bp and %sp. - * For amd64, use %rbp and %rsp instead of %bp and %sp. - * - * Our emulation callback handler always saves enough space to hold the - * maximum number of stack arguments to a system call. This is architecture - * specific and is defined via EH_ARGS_COUNT. - */ -#define EH_LOCALS_GREGS (EH_LOCALS_START) -#define EH_LOCALS_GREG(x) (EH_LOCALS_GREGS + (SIZEOF_GREG_T * (x))) -#define EH_LOCALS_SYSRET (EH_LOCALS_GREGS + SIZEOF_GREGSET_T) -#define EH_LOCALS_SYSRET1 (EH_LOCALS_SYSRET) -#define EH_LOCALS_SYSRET2 (EH_LOCALS_SYSRET + CPTRSIZE) -#define EH_LOCALS_RVFLAG (EH_LOCALS_SYSRET + SIZEOF_SYSRET_T) -#define EH_LOCALS_END (EH_LOCALS_RVFLAG + CPTRSIZE) - -#if (EH_LOCALS_END != EH_LOCALS_END_TGT) -#error "sn1_misc.h EH_LOCALS_* macros don't add up" -#endif /* (EH_LOCALS_END != EH_LOCALS_END_TGT) */ - -/* - * The second parameter of each entry in the sn1_sysent_table - * contains the number of parameters and flags that describe the - * syscall return value encoding. See the block comments at the - * top of ../common/sn1_brand.c for more information about the - * syscall return value flags and when they should be used. - */ -#define NARGS_MASK 0x000000FF /* Mask for syscalls argument count */ -#define RV_MASK 0x0000FF00 /* Mask for return value flags */ -#define RV_DEFAULT 0x00000100 /* syscall returns "default" values */ -#define RV_32RVAL2 0x00000200 /* syscall returns two 32-bit values */ -#define RV_64RVAL 0x00000400 /* syscall returns a 64-bit value */ - -#if !defined(_ASM) - -/* - * We define our own version of assert because the default one will - * try to emit a localized message. That is bad because first, we can't - * emit messages to random file descriptors, and second localizing a message - * requires allocating memory and we can't do that either. - */ -#define sn1_assert(ex) (void)((ex) || \ - (_sn1_abort(0, #ex, __FILE__, __LINE__), 0)) -#define sn1_abort(err, msg) _sn1_abort((err), (msg), __FILE__, __LINE__) - -/* - * From sn1_runexe.s - */ -extern void sn1_runexe(void *, ulong_t); - -/* - * From sn1_handler.s - */ -extern void sn1_handler_table(void); -extern void sn1_handler(void); -extern void sn1_error(void); -extern void sn1_success(void); - -/* - * From sn1_brand.c - */ -extern void _sn1_abort(int, const char *, const char *, int); - -#endif /* !_ASM */ - -#ifdef __cplusplus -} -#endif - -#endif /* _SN1_MISC_H */ diff --git a/usr/src/lib/brand/solaris10/librtld_db/Makefile.com b/usr/src/lib/brand/solaris10/librtld_db/Makefile.com index f03de8ab6b..9399d772a9 100644 --- a/usr/src/lib/brand/solaris10/librtld_db/Makefile.com +++ b/usr/src/lib/brand/solaris10/librtld_db/Makefile.com @@ -19,62 +19,11 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -LIBRARY = solaris10_librtld_db.a -VERS = .1 -COBJS = solaris10_librtld_db.o +COBJS = brand_librtld_db.o OBJECTS = $(COBJS) $(COBJS64) -include $(SRC)/lib/Makefile.lib include ../../Makefile.s10 - -CSRCS = $(COBJS:%o=../common/%c) -SRCS = $(CSRCS) - -SRCDIR = ../common -UTSBASE = $(SRC)/uts - -# -# ATTENTION: -# Librtl_db brand plugin libraries should NOT directly invoke any -# libproc.so interfaces or be linked against libproc. If a librtl_db -# brand plugin library uses libproc.so interfaces then it may break -# any other librtld_db consumers (like mdb) that tries to attach -# to a branded process. The only safe interfaces that the a librtld_db -# brand plugin library can use to access a target process are the -# proc_service(3PROC) apis. -# -DYNFLAGS += $(VERSREF) -M../common/mapfile-vers -LIBS = $(DYNLIB) -LDLIBS += -lc -lrtld_db -CFLAGS += $(CCVERBOSE) -CPPFLAGS += -D_REENTRANT -I../ -I$(UTSBASE)/common/brand/solaris10 \ - -I$(SRC)/cmd/sgs/librtld_db/common \ - -I$(SRC)/cmd/sgs/include \ - -I$(SRC)/cmd/sgs/include/$(MACH) - -ROOTLIBDIR = $(ROOT)/usr/lib/brand/solaris10 -ROOTLIBDIR64 = $(ROOT)/usr/lib/brand/solaris10/$(MACH64) - -# -# The top level Makefiles define define TEXT_DOMAIN. But librtld_db.so.1 -# isn't internationalized and this library won't be either. The only -# messages that this library can generate are messages used for debugging -# the operation of the library itself. -# -DTEXTDOM = - -.KEEP_STATE: - -all: $(LIBS) - -lint: lintcheck - -pics/%64.o: ../common/%.c - $(COMPILE.c) -D_ELF64 $(PICFLAGS) -o $@ $< - $(POST_PROCESS_O) - -include $(SRC)/lib/Makefile.targ +include $(BRAND_SHARED)/librtld_db/Makefile.com diff --git a/usr/src/lib/brand/solaris10/librtld_db/amd64/Makefile b/usr/src/lib/brand/solaris10/librtld_db/amd64/Makefile index de7282752c..5bae7648ff 100644 --- a/usr/src/lib/brand/solaris10/librtld_db/amd64/Makefile +++ b/usr/src/lib/brand/solaris10/librtld_db/amd64/Makefile @@ -19,16 +19,15 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -COBJS64 = solaris10_librtld_db64.o +COBJS64 = brand_librtld_db64.o include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 CLOBBERFILES = $(ROOTLIBDIR64)/$(DYNLIB) -DYNFLAGS += -M../common/mapfile-vers.64 +DYNFLAGS += -M$(BRAND_SHARED)/librtld_db/common/mapfile-vers.64 install: all $(ROOTLIBS64) diff --git a/usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers b/usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers deleted file mode 100644 index 4f3ef01e3c..0000000000 --- a/usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers +++ /dev/null @@ -1,57 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# MAPFILE HEADER START -# -# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. -# Object versioning must comply with the rules detailed in -# -# usr/src/lib/README.mapfiles -# -# You should not be making modifications here until you've read the most current -# copy of that file. If you need help, contact a gatekeeper for guidance. -# -# MAPFILE HEADER END -# - -SUNWprivate_1.1 { - global: - rtld_db_brand_ops32; - local: - *; -}; - -#Externally defined symbols -{ - global: - ps_pauxv = NODIRECT PARENT; - ps_pdmodel = NODIRECT PARENT; - ps_pglobal_lookup = NODIRECT PARENT; - ps_pglobal_sym = NODIRECT PARENT; - ps_plog = NODIRECT PARENT; - ps_pread = NODIRECT PARENT; - ps_pwrite = NODIRECT PARENT; -}; diff --git a/usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers.64 b/usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers.64 deleted file mode 100644 index 51e0c2c3cc..0000000000 --- a/usr/src/lib/brand/solaris10/librtld_db/common/mapfile-vers.64 +++ /dev/null @@ -1,43 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# MAPFILE HEADER START -# -# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. -# Object versioning must comply with the rules detailed in -# -# usr/src/lib/README.mapfiles -# -# You should not be making modifications here until you've read the most current -# copy of that file. If you need help, contact a gatekeeper for guidance. -# -# MAPFILE HEADER END -# - -SUNWprivate_1.1 { - global: - rtld_db_brand_ops64; -}; diff --git a/usr/src/lib/brand/solaris10/librtld_db/common/solaris10_librtld_db.c b/usr/src/lib/brand/solaris10/librtld_db/common/solaris10_librtld_db.c deleted file mode 100644 index e20a6ac142..0000000000 --- a/usr/src/lib/brand/solaris10/librtld_db/common/solaris10_librtld_db.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * ATTENTION: - * Librtl_db brand plugin libraries should NOT directly invoke any - * libproc.so interfaces or be linked against libproc. If a librtl_db - * brand plugin library uses libproc.so interfaces then it may break - * any other librtld_db consumers (like mdb) that tries to attach - * to a branded process. The only safe interfaces that the a librtld_db - * brand plugin library can use to access a target process are the - * proc_service(3PROC) apis. - */ - -/* - * M_DATA comes from some streams header file but is also redifined in - * _rtld_db.h, so nuke the old streams definition here. - */ -#ifdef M_DATA -#undef M_DATA -#endif /* M_DATA */ - -/* - * For 32-bit versions of this library, this file get's compiled once. - * For 64-bit versions of this library, this file get's compiled twice, - * once with _ELF64 defined and once without. The expectation is that - * the 64-bit version of the library can properly deal with both 32-bit - * and 64-bit elf files, hence in the 64-bit library there are two copies - * of all the interfaces in this file, one set named *32 and one named *64. - * - * This also means that we need to be careful when declaring local pointers - * that point to objects in another processes address space, since these - * pointers may not match the current processes pointer width. Basically, - * we should not use any objects that change size between 32 and 64 bit - * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc. - * Instead we should declare all pointers as uint32_t. Then when we - * are compiled to deal with 64-bit targets we'll re-define uing32_t - * to be a uint64_t. - */ -#ifdef _LP64 -#ifdef _ELF64 -#define uint32_t uint64_t -#define Elf32_Dyn Elf64_Dyn -#define validate_rdebug32 validate_rdebug64 -#define _rd_loadobj_iter32 _rd_loadobj_iter64 -#define _rd_get_dyns32 _rd_get_dyns64 -#define dummy_ldb32 dummy_ldb64 -#define dummy_ldb_init32 dummy_ldb_init64 -#define dummy_ldb_fini32 dummy_ldb_fini64 -#define dummy_ldb_loadobj_iter32 dummy_ldb_loadobj_iter64 -#define dummy_ldb_get_dyns32 dummy_ldb_get_dyns64 -#define s10_ldb_init32 s10_ldb_init64 -#define s10_ldb_fini32 s10_ldb_fini64 -#define s10_ldb_loadobj_iter32 s10_ldb_loadobj_iter64 -#define s10_ldb_get_dyns32 s10_ldb_get_dyns64 -#endif /* _ELF64 */ -#endif /* _LP64 */ - -/* Included from usr/src/cmd/sgs/librtld_db/common */ -#include <_rtld_db.h> - -/*ARGSUSED*/ -static rd_helper_data_t -dummy_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) -{ - return (NULL); -} - -/*ARGSUSED*/ -static void -dummy_ldb_fini32(rd_helper_data_t rhd) -{ -} - -/*ARGSUSED*/ -static int -dummy_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) -{ - return (RD_OK); -} - -/*ARGSUSED*/ -static rd_err_e -dummy_ldb_get_dyns32(rd_helper_data_t rhd, - psaddr_t addr, void **dynpp, size_t *dynpp_sz) -{ - *dynpp = NULL; - *dynpp_sz = 0; - return (RD_OK); -} - -static rd_helper_ops_t dummy_ldb32 = { - LM_ID_BRAND, - dummy_ldb_init32, - dummy_ldb_fini32, - dummy_ldb_loadobj_iter32, - dummy_ldb_get_dyns32 -}; - -static uint32_t -s10_ldb_getauxval32(struct ps_prochandle *php, int type) -{ - const auxv_t *auxvp = NULL; - - if (ps_pauxv(php, &auxvp) != PS_OK) - return ((uint32_t)-1); - - while (auxvp->a_type != AT_NULL) { - if (auxvp->a_type == type) - return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr); - auxvp++; - } - return ((uint32_t)-1); -} - -/* - * Normally, the native Solaris librtldb_db plugin uses a bunch of different - * methods to try and find the rdebug structure associated with the target - * process we're debugging. For details on the different methods see - * _rd_reset32(). Thankfully our job is easier. We know that the brand - * library is always linked against the native linker, and when the - * process was first executed we saved off a pointer to the brand linkers - * rdebug structure in one of our brand specific aux vectors, - * AT_SUN_BRAND_S10_LDDATA. So we'll just look that up here. - */ -/*ARGSUSED*/ -static rd_helper_data_t -s10_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) -{ - struct rd_agent *rap_new; - uint32_t lddata_addr; - int rd_dmodel; - - if (ps_pdmodel(php, &rd_dmodel) != PS_OK) { - ps_plog("s10_ldb_init: lookup of data model failed"); - return (NULL); - } -#ifdef _ELF64 - assert(rd_dmodel == PR_MODEL_LP64); -#else /* !_ELF64 */ - assert(rd_dmodel == PR_MODEL_ILP32); -#endif /* !_ELF64 */ - - lddata_addr = s10_ldb_getauxval32(php, AT_SUN_BRAND_S10_LDDATA); - if (lddata_addr == (uint32_t)-1) { - ps_plog("s10_ldb_init: no LDDATA found in aux vector"); - return (NULL); - } - ps_plog("s10_ldb_init: found LDDATA auxv ld.so.1 data seg " - "at: 0x%p", lddata_addr); - - /* - * Ok. So this is kinda ugly. Basically we know that we're going to - * be parsing data from link maps that are generated by a Solaris - * linker. As it turns out, that's exactly what the default - * Solaris librtld_db library is designed to do. So rather than - * duplicate all that link map parsing code here we'll simply - * invoke the native librtld_db that normally does this, and when - * we do we'll point them at our emulation libraries link map. - * - * Of course these interfacess aren't really public interfaces - * and they take a "struct rd_agent" as a parameter. So here - * we'll allocate and initialize a new "struct rd_agent", point - * it at our emulation libraries link map, and initialize just - * enough of the structure to make the librtld_db interfaces - * that we want to use happy. - */ - if ((rap_new = calloc(sizeof (*rap_new), 1)) == NULL) { - ps_plog("s10_ldb_init: can't allocate memory"); - return (NULL); - } - rap_new->rd_dmodel = rd_dmodel; - rap_new->rd_psp = php; - rap_new->rd_rdebug = lddata_addr; - (void) mutex_init(&rap_new->rd_mutex, USYNC_THREAD, 0); - - /* - * When we get invoked from librtld_db, and we call back into it, - * librtld_db will once again check if there is a plugin and - * invoke it. Since we don't want to enter a recursive loop - * we're going to specify a different plugin interface for - * our linkmap, and these new plugin interfaces won't actually - * do anything other than return. - */ - rap_new->rd_helper.rh_ops = &dummy_ldb32; - - /* - * validate_rdebug32() requires the following "struct rd_agent" - * members to be initialized: - * rd_psp, rd_rdebug - * - * validate_rdebug32() initializes the following "struct rd_agent" - * members: - * rd_flags, rd_rdebugvers, rd_rtlddbpriv - */ - if (validate_rdebug32(rap_new) != RD_OK) { - ps_plog("s10_ldb_init: can't find valid r_debug data"); - free(rap_new); - return (NULL); - } - - ps_plog("s10_ldb_init: finished, helper_data=0x%p", rap_new); - return ((rd_helper_data_t)rap_new); -} - -static void -s10_ldb_fini32(rd_helper_data_t rhd) -{ - struct rd_agent *rap = (struct rd_agent *)rhd; - ps_plog("s10_ldb_fini: cleaning up s10 helper"); - free(rap); -} - -/*ARGSUSED*/ -static int -s10_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) -{ - struct rd_agent *rap = (struct rd_agent *)rhd; - int err; - - ps_plog("s10_ldb_loadobj_iter(helper_data=0x%p)", rhd); - assert(rap->rd_psp == php); - RDAGLOCK(rap); - /* - * _rd_loadobj_iter32() requires the following "struct rd_agent" - * members to be initialized: - * rd_rtlddbpriv, rd_rdebugvers, rd_flags, - * rd_helper.rh_ops, rd_dmodel - */ - err = _rd_loadobj_iter32(rap, cb, client_data); - RDAGUNLOCK(rap); - ps_plog("s10_ldb_loadobj_iter: finished, err = %d", err); - return (err); -} - -/*ARGSUSED*/ -static rd_err_e -s10_ldb_get_dyns32(rd_helper_data_t rhd, - psaddr_t addr, void **dynpp, size_t *dynpp_sz) -{ - struct rd_agent *rap = (struct rd_agent *)rhd; - int err; - - ps_plog("s10_ldb_get_dyns(helper_data=0x%p)", rhd); - err = _rd_get_dyns32(rap, addr, (Elf32_Dyn **)dynpp, dynpp_sz); - ps_plog("s10_ldb_get_dyns: finished, err = %d", err); - return (err); -} - -/* - * Librtld_db plugin linkage struct. - * - * When we get loaded by librtld_db, it will look for the symbol below - * to find our plugin entry points. - */ -rd_helper_ops_t RTLD_DB_BRAND_OPS = { - LM_ID_NONE, - s10_ldb_init32, - s10_ldb_fini32, - s10_ldb_loadobj_iter32, - s10_ldb_get_dyns32 -}; diff --git a/usr/src/lib/brand/solaris10/librtld_db/sparcv9/Makefile b/usr/src/lib/brand/solaris10/librtld_db/sparcv9/Makefile index de7282752c..5bae7648ff 100644 --- a/usr/src/lib/brand/solaris10/librtld_db/sparcv9/Makefile +++ b/usr/src/lib/brand/solaris10/librtld_db/sparcv9/Makefile @@ -19,16 +19,15 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -COBJS64 = solaris10_librtld_db64.o +COBJS64 = brand_librtld_db64.o include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 CLOBBERFILES = $(ROOTLIBDIR64)/$(DYNLIB) -DYNFLAGS += -M../common/mapfile-vers.64 +DYNFLAGS += -M$(BRAND_SHARED)/librtld_db/common/mapfile-vers.64 install: all $(ROOTLIBS64) diff --git a/usr/src/lib/brand/solaris10/s10_brand/Makefile.com b/usr/src/lib/brand/solaris10/s10_brand/Makefile.com index a90d56d4cd..f031d769f0 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/Makefile.com +++ b/usr/src/lib/brand/solaris10/s10_brand/Makefile.com @@ -19,18 +19,14 @@ # CDDL HEADER END # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # LIBRARY = s10_brand.a VERS = .1 COBJS = s10_brand.o s10_deleted.o s10_signal.o -ASOBJS = s10_crt.o s10_handler.o s10_runexe.o -OFFSETS_SRC = ../common/offsets.in -OFFSETS_H = assym.h -OBJECTS = $(COBJS) $(ASOBJS) -CLOBBERFILES += $(OFFSETS_H) +ASOBJS = crt.o handler.o runexe.o brand_util.o +OBJECTS = $(COBJS) include ../../Makefile.s10 include $(SRC)/lib/Makefile.lib @@ -40,19 +36,8 @@ UTSBASE = $(SRC)/uts LIBS = $(DYNLIB) CSRCS = $(COBJS:%o=../common/%c) -ASSRCS = $(ASOBJS:%o=$(ISASRCDIR)/%s) -SRCS = $(CSRCS) $(ASSRCS) - -# -# Ugh, this is a gross hack. Our assembly routines uses lots of defines -# to simplify variable access. All these defines work fine for amd64 -# compiles because when compiling for amd64 we use the GNU assembler, -# gas. For 32-bit code we use the Sun assembler, as. Unfortunatly -# as does not handle certian constructs that gas does. So rather than -# make our code less readable, we'll just use gas to compile our 32-bit -# code as well. -# -i386_AS = $(amd64_AS) +SHAREDOBJS = $(ASOBJS:%o=$(ISAOBJDIR)/%o) +SRCS = $(CSRCS) # # Note that the architecture specific makefiles MUST update DYNFLAGS to @@ -87,33 +72,23 @@ i386_AS = $(amd64_AS) # via mmap() instead of brk(). # CPPFLAGS += -D_REENTRANT -U_ASM \ - -I. -I../sys -I$(UTSBASE)/common/brand/solaris10 \ + -I. -I$(BRAND_SHARED)/brand/sys -I../sys \ + -I$(UTSBASE)/common/brand/solaris10 \ -I$(SRC)/uts/common/fs/zfs CFLAGS += $(CCVERBOSE) # Needed to handle zfs include files C99MODE= -xc99=%all C99LMODE= -Xc99=%all -ASFLAGS = -P $(ASFLAGS_$(CURTYPE)) -D_ASM -I. -I../sys DYNFLAGS += $(DYNFLAGS_$(CLASS)) DYNFLAGS += $(BLOCAL) $(ZNOVERSION) -Wl,-e_start LDLIBS += -lc -lmapmalloc +$(LIBS):= PICS += $(SHAREDOBJS) + .KEEP_STATE: all: $(LIBS) lint: lintcheck -# -# build the offset header before trying to compile any files. (it's included -# by s10_misc.h, so it's needed for all objects, not just assembly ones.) -# -$(OBJECTS:%=pics/%): $(OFFSETS_H) -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) $(CTF_FLAGS) < $(OFFSETS_SRC) >$@ - -pics/%.o: $(ISASRCDIR)/%.s - $(COMPILE.s) -o $@ $< - $(POST_PROCESS_O) - include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/brand/solaris10/s10_brand/amd64/Makefile b/usr/src/lib/brand/solaris10/s10_brand/amd64/Makefile index 6d760f7e28..abb83be149 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/amd64/Makefile +++ b/usr/src/lib/brand/solaris10/s10_brand/amd64/Makefile @@ -19,15 +19,16 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -ISASRCDIR = . +ISAOBJDIR = $(BRAND_SHARED)/brand/amd64/pics/ include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 +CPPFLAGS += -I$(BRAND_SHARED)/brand/amd64 + # # see ../Makefile.com for why we MUST explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_crt.s b/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_crt.s deleted file mode 100644 index 059eb8fe53..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_crt.s +++ /dev/null @@ -1,73 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -#if defined(lint) - -void -_start(void) -{ -} - -#else /* lint */ - /* - * Initial entry point for the brand emulation library. - * - * This platform specific assembly entry point exists just to invoke - * the common brand library startup routine. That routine expects to - * be called with the following arguments: - * s10_init(int argc, char *argv[], char *envp[]) - * - * There are no arguments explicitly passed to this entry point, - * routine, but we do know how our initial stack has been setup by - * the kernel. The stack format is documented in: - * usr/src/cmd/sgs/rtld/amd64/boot.s - * - * So this routine will troll through the stack to setup the argument - * values for the common brand library startup routine and then invoke - * it. This routine is modeled after the default crt1.s`_start() - * routines. - */ - ENTRY_NP(_start) - - /* Make stack traces look pretty, build a fake stack frame. */ - pushq $0 / Build a stack frame. retpc = NULL - pushq $0 / fp = NULL - movq %rsp, %rbp / first stack frame - - /* - * Calculate the location of the envp array by adding the size of - * the argv array to the start of the argv array. - */ - movq 16(%rbp), %rdi / argc in %rax (1st param) - leaq 24(%rbp), %rsi / &argv[0] in %rbx (2nd param) - leaq 32(%rbp,%rdi,8), %rdx / envp in %rcx (3rd param) - call s10_init - - /*NOTREACHED*/ - SET_SIZE(_start) -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_handler.s b/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_handler.s deleted file mode 100644 index 76b2dcfe1e..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_handler.s +++ /dev/null @@ -1,219 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -/* - * Each JMP must occupy 16 bytes - */ -#define JMP \ - pushq $_CONST(. - s10_handler_table); \ - jmp s10_handler; \ - .align 16; - -#define JMP4 JMP; JMP; JMP; JMP -#define JMP16 JMP4; JMP4; JMP4; JMP4 -#define JMP64 JMP16; JMP16; JMP16; JMP16 -#define JMP256 JMP64; JMP64; JMP64; JMP64 - -#if defined(lint) - -void -s10_handler_table(void) -{} - -void -s10_handler(void) -{ -} - -#else /* lint */ - - /* - * On entry to this table, %rax will hold the return address. The - * location where we enter the table is a function of the system - * call number. The table needs the same alignment as the individual - * entries. - */ - .align 16 - ENTRY_NP(s10_handler_table) - JMP256 - SET_SIZE(s10_handler_table) - - /* - * %rax - userland return address - * stack contains: - * | -------------------------------------- - * v 8 | syscall arguments | - * %rsp+0 | syscall number | - * -------------------------------------- - */ - ENTRY_NP(s10_handler) - pushq %rbp /* allocate stack frame */ - movq %rsp, %rbp - - /* Save registers at the time of the syscall. */ - movq $0, EH_LOCALS_GREG(REG_TRAPNO)(%rbp) - movq $0, EH_LOCALS_GREG(REG_ERR)(%rbp) - movq %r15, EH_LOCALS_GREG(REG_R15)(%rbp) - movq %r14, EH_LOCALS_GREG(REG_R14)(%rbp) - movq %r13, EH_LOCALS_GREG(REG_R13)(%rbp) - movq %r12, EH_LOCALS_GREG(REG_R12)(%rbp) - movq %r11, EH_LOCALS_GREG(REG_R11)(%rbp) - movq %r10, EH_LOCALS_GREG(REG_R10)(%rbp) - movq %r9, EH_LOCALS_GREG(REG_R9)(%rbp) - movq %r8, EH_LOCALS_GREG(REG_R8)(%rbp) - movq %rdi, EH_LOCALS_GREG(REG_RDI)(%rbp) - movq %rsi, EH_LOCALS_GREG(REG_RSI)(%rbp) - movq %rbx, EH_LOCALS_GREG(REG_RBX)(%rbp) - movq %rcx, EH_LOCALS_GREG(REG_RCX)(%rbp) - movq %rdx, EH_LOCALS_GREG(REG_RDX)(%rbp) - xorq %rcx, %rcx - movw %cs, %cx - movq %rcx, EH_LOCALS_GREG(REG_CS)(%rbp) - movw %ds, %cx - movq %rcx, EH_LOCALS_GREG(REG_DS)(%rbp) - movw %es, %cx - movq %rcx, EH_LOCALS_GREG(REG_ES)(%rbp) - movw %fs, %cx - movq %rcx, EH_LOCALS_GREG(REG_FS)(%rbp) - movw %gs, %cx - movq %rcx, EH_LOCALS_GREG(REG_GS)(%rbp) - movw %ss, %cx - movq %rcx, EH_LOCALS_GREG(REG_SS)(%rbp) - pushfq /* save syscall flags */ - popq %r12 - movq %r12, EH_LOCALS_GREG(REG_RFL)(%rbp) - movq EH_ARGS_OFFSET(0)(%rbp), %r12 /* save syscall rbp */ - movq %r12, EH_LOCALS_GREG(REG_RBP)(%rbp) - movq %rbp, %r12 /* save syscall rsp */ - addq $CPTRSIZE, %r12 - movq %r12, EH_LOCALS_GREG(REG_RSP)(%rbp) - movq %fs:0, %r12 /* save syscall fsbase */ - movq %r12, EH_LOCALS_GREG(REG_FSBASE)(%rbp) - movq $0, EH_LOCALS_GREG(REG_GSBASE)(%rbp) - - /* - * The kernel drops us into the middle of the s10_handle_table - * above that then pushes that table offset onto the stack, and calls - * into s10_handler. That offset indicates the system call number while - * %rax holds the return address for the system call. We replace the - * value on the stack with the return address, and use the value to - * compute the system call number by dividing by the table entry size. - */ - xchgq CPTRSIZE(%rbp), %rax /* swap JMP table offset and ret addr */ - shrq $4, %rax /* table_offset/size = syscall num */ - movq %rax, EH_LOCALS_GREG(REG_RAX)(%rbp) /* save syscall num */ - - /* - * Finish setting up our stack frame. We would normally do this - * upon entry to this function, but in this case we delayed it - * because a "sub" operation can modify flags and we wanted to - * save the flags into the gregset_t above before they get modified. - * - * Our stack frame format is documented in s10_misc.h. - */ - subq $EH_LOCALS_SIZE, %rsp - - /* Look up the system call's entry in the sysent table */ - movq s10_sysent_table@GOTPCREL(%rip), %r11 /* %r11 = sysent_table */ - shlq $4, %rax /* each entry is 16 bytes */ - addq %rax, %r11 /* %r11 = sysent entry address */ - - /* - * Get the return value flag and the number of arguments from the - * sysent table. - */ - movq CPTRSIZE(%r11), %r12 /* number of args + rv flag */ - andq $RV_MASK, %r12 /* strip out number of args */ - movq %r12, EH_LOCALS_RVFLAG(%rbp) /* save rv flag */ - - /* - * Setup arguments for our emulation call. Our input arguments, - * 0 to N, will become emulation call arguments 1 to N+1. - * - * Note: Syscall argument passing is different from function call - * argument passing on amd64. For function calls, the fourth arg - * is passed via %rcx, but for system calls the 4th argument is - * passed via %r10. This is because in amd64, the syscall - * instruction puts lower 32 bit of %rflags in %r11 and puts the - * %rip value to %rcx. - */ - movq EH_ARGS_OFFSET(4)(%rbp), %r12 /* copy 8th arg */ - movq %r12, EH_ARGS_OFFSET(2)(%rsp) - movq EH_ARGS_OFFSET(3)(%rbp), %r12 /* copy 7th arg */ - movq %r12, EH_ARGS_OFFSET(1)(%rsp) - movq %r9, EH_ARGS_OFFSET(0)(%rsp) - movq %r8, %r9 - movq %r10, %r8 - movq %rdx, %rcx - movq %rsi, %rdx - movq %rdi, %rsi - - /* - * The first parameter to the emulation callback function is a - * pointer to a sysret_t structure. - */ - movq %rbp, %rdi - addq $EH_LOCALS_SYSRET, %rdi /* arg0 == sysret_t ptr */ - - /* invoke the emulation routine */ - ALTENTRY(s10_handler_savepc) - call *(%r11) - - /* restore scratch and parameter registers */ - movq EH_LOCALS_GREG(REG_R12)(%rbp), %r12 /* restore %r12 */ - movq EH_LOCALS_GREG(REG_R11)(%rbp), %r11 /* restore %r11 */ - movq EH_LOCALS_GREG(REG_R10)(%rbp), %r10 /* restore %r10 */ - movq EH_LOCALS_GREG(REG_R9)(%rbp), %r9 /* restore %r9 */ - movq EH_LOCALS_GREG(REG_R8)(%rbp), %r8 /* restore %r8 */ - movq EH_LOCALS_GREG(REG_RCX)(%rbp), %rcx /* restore %rcx */ - movq EH_LOCALS_GREG(REG_RDX)(%rbp), %rdx /* restore %rdx */ - movq EH_LOCALS_GREG(REG_RSI)(%rbp), %rsi /* restore %rsi */ - movq EH_LOCALS_GREG(REG_RDI)(%rbp), %rdi /* restore %rdi */ - - /* Check for syscall emulation success or failure */ - cmpq $0, %rax - je success - stc /* failure, set carry flag */ - jmp return /* return, %rax == errno */ - -success: - /* There is always at least one return value. */ - movq EH_LOCALS_SYSRET1(%rbp), %rax /* %rax == sys_rval1 */ - cmpq $RV_DEFAULT, EH_LOCALS_RVFLAG(%rbp) /* check rv flag */ - je clear_carry - mov EH_LOCALS_SYSRET2(%rbp), %rdx /* %rdx == sys_rval2 */ -clear_carry: - clc /* success, clear carry flag */ - -return: - movq %rbp, %rsp /* restore stack */ - popq %rbp - ret /* ret to instr after syscall */ - SET_SIZE(s10_handler) - - -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_runexe.s b/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_runexe.s deleted file mode 100644 index a8aad19ef2..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/amd64/s10_runexe.s +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -/*ARGSUSED*/ -void -s10_runexe(void *argv, ulong_t entry) -{ -} - -#else /* lint */ - /* - * Prepare to jump to the target program we actually want to run. - * If this program is dynamically linked then we'll be jumping to - * another copy of the linker. If it's a statically linked program - * we'll be jumping directy to it's main entry point. In any case, - * we need to reset our current state stack and register state to - * something similar to the initial process state setup by the kernel - * and documented at: - * usr/src/cmd/sgs/rtld/i386/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * Of course this is the same stack format as when this executable - * was first started, so here we'll just roll back the stack and - * frame pointers to their values when this processes first started - * execution. - */ - ENTRY_NP(s10_runexe) - - movq %rdi, %rax / %rax = &argv[0] - movq %rsi, %rbx / Brand app entry point in %rbx - subq $8, %rax / Top of stack - must point at argc - movq %rax, %rsp / Set %rsp to what linkers expect - - /* - * We also have to make sure to clear %rdx since nornally ld.so.1 will - * set that to non-zero if there is an exit function that should be - * invoked when the process is terminating. This isn't actually - * necessary if the target program we're jumping to is a dynamically - * linked program since in that case we're actually jumping to another - * copy of ld.so.1 and it will just reset %rdx, but if the target - * program we're jumping to is a statically linked binary that uses - * the standard sun compiler supplied crt1.o`_start(), it will check - * to see if %g1 is set. - */ - movq $0, %rdx - - jmp *%rbx / And away we go... - /* - * target will never return. - */ - SET_SIZE(s10_runexe) -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/common/offsets.in b/usr/src/lib/brand/solaris10/s10_brand/common/offsets.in deleted file mode 100644 index 50bd417af3..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/common/offsets.in +++ /dev/null @@ -1,35 +0,0 @@ -\ -\ Copyright 2009 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 (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 -\ - - -#include -#include -#include -#include - -greg_t SIZEOF_GREG_T - -gregset_t SIZEOF_GREGSET_T - -sysret_t SIZEOF_SYSRET_T diff --git a/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c b/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c index 105ffec277..34326099f2 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c +++ b/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -60,113 +59,13 @@ #include #include +#include #include #include /* - * Principles of emulation 101. - * - * - * *** Setting errno - * - * Just don't do it. This emulation library is loaded onto a - * seperate link map from the application who's address space we're - * running in. We have our own private copy of libc, so there for, - * the errno value accessible from here is is also private and changing - * it will not affect any errno value that the processes who's address - * space we are running in will see. To return an error condition we - * should return the negated errno value we'd like the system to return. - * For more information about this see the comment in s10_handler(). - * Basically, when we return to the caller that initiated the system - * call it's their responsibility to set errno. - * - * - * *** Recursion Considerations - * - * When emulating system calls we need to be very careful about what - * library calls we invoke. Library calls should be kept to a minimum. - * One issue is that library calls can invoke system calls, so if we're - * emulating a system call and we invoke a library call that depends on - * that system call we will probably enter a recursive loop, which would - * be bad. - * - * - * *** Return Values. - * - * When declaring new syscall emulation functions, it is very important - * to to set the proper RV_* flags in the s10_sysent_table. Upon failure, - * syscall emulation fuctions should return an errno value. Upon success - * syscall emulation functions should return 0 and set the sysret_t return - * value parameters accordingly. - * - * There are five possible syscall macro wrappers used in the kernel's system - * call sysent table. These turn into the following return values: - * SYSENT_CL -> SYSENT_C or SYSENT_CI - * SYSENT_C SE_64RVAL RV_DEFAULT - * SYSENT_CI SE_32RVAL1 RV_DEFAULT - * SYSENT_2CI SE_32RVAL1|SE_32RVAL2 RV_32RVAL2 - * SYSENT_AP SE_64RVAL RV_64RVAL - * - * - * *** Agent lwp considerations - * - * It is currently impossible to do any emulation for these system call - * when they are being invoked on behalf of an agent lwp. To understand why - * it's impossible you have to understand how agent lwp syscalls work. - * - * The agent lwp syscall process works as follows: - * 1 The controlling process stops the target. - * 2 The controlling process injects an agent lwp which is also stopped. - * This agent lwp assumes the userland stack and register values - * of another stopped lwp in the current process. - * 3 The controlling process configures the agent lwp to start - * executing the requested system call. - * 4 The controlling process configure /proc to stop the agent lwp when - * it enters the requested system call. - * 5 The controlling processes allows the agent lwp to start executing. - * 6 The agent lwp traps into the kernel to perform the requested system - * call and immediately stop. - * 7 The controlling process copies all the arguments for the requested - * system call onto the agent lwp's stack. - * 8 The controlling process configures /proc to stop the agent lwp - * when it completes the requested system call. - * 9 The controlling processes allows the agent lwp to start executing. - * 10 The agent lwp executes the system call and then stop before returning - * to userland. - * 11 The controlling process copies the return value and return arguments - * back from the agent lwps stack. - * 12 The controlling process destroys the agent lwp and restarts - * the target process. - * - * The fundamental problem is that when the agent executes the request - * system call in step 5, if we're emulating that system call then the - * lwp is redirected back to our emulation layer without blocking - * in the kernel. But our emulation layer can't access the arguments - * for the system call because they haven't been copied to the stack - * yet and they still only exist in the controlling processes address - * space. This prevents us from being able to do any emulation of - * agent lwp system calls. Hence, currently our brand trap interposition - * callback (s10_brand_syscall_callback_common) will detect if a system - * call is being made by an agent lwp, and if this is the case it will - * never redirect the system call to this emulation library. - * - * In the future, if this proves to be a problem the the easiest solution - * would probably be to replace the branded versions of these application - * with their native counterparts. Ie, truss, plimit, and pfiles could be - * replace with wrapper scripts that execute the native versions of these - * applications. In the case of plimit and pfiles this should be pretty - * strait forward. Truss would probably be more tricky since it can - * execute applications which would be branded applications, so in that - * case it might be necessary to create a loadable library which could - * be LD_PRELOADed into truss and this library would interpose on the - * exec() system call to allow truss to correctly execute branded - * processes. It should be pointed out that this solution could work - * because "native agent lwps" (ie, agent lwps created by native - * processes) can be treated differently from "branded aged lwps" (ie, - * agent lwps created by branded processes), since native agent lwps - * would presumably be making native system calls and hence not need - * any interposition. - * + * See usr/src/lib/brand/shared/brand/common/brand_util.c for general + * emulation notes. */ static zoneid_t zoneid; @@ -214,72 +113,11 @@ pid_t zone_init_pid; ((emul_bitmap[(s10_emulated_features_constant) >> 3] & \ (1 << ((s10_emulated_features_constant) & 0x7))) != 0) -#define EMULATE(cb, args) { (sysent_cb_t)(cb), (args) } -#define NOSYS EMULATE(s10_unimpl, (0 | RV_DEFAULT)) - -typedef long (*sysent_cb_t)(); -typedef struct s10_sysent_table { - sysent_cb_t st_callc; - uintptr_t st_args; -} s10_sysent_table_t; -s10_sysent_table_t s10_sysent_table[]; +brand_sysent_table_t brand_sysent_table[]; #define S10_UTS_RELEASE "5.10" #define S10_UTS_VERSION "Generic_Virtual" -/*LINTED: static unused*/ -static volatile int s10_abort_err; -/*LINTED: static unused*/ -static volatile const char *s10_abort_msg; -/*LINTED: static unused*/ -static volatile const char *s10_abort_file; -/*LINTED: static unused*/ -static volatile int s10_abort_line; - -extern int errno; - -/*ARGSUSED*/ -void -_s10_abort(int err, const char *msg, const char *file, int line) -{ - sysret_t rval; - - /* Save the error message into convenient globals */ - s10_abort_err = err; - s10_abort_msg = msg; - s10_abort_file = file; - s10_abort_line = line; - - /* kill ourselves */ - abort(); - - /* If abort() didn't work, try something stronger. */ - (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGKILL); -} - -int -s10_uucopy(const void *from, void *to, size_t size) -{ - sysret_t rval; - - if (__systemcall(&rval, SYS_uucopy + 1024, from, to, size) != 0) - return (EFAULT); - return (0); -} - -/* - * ATTENTION: uucopystr() does NOT ensure that string are null terminated! - */ -int -s10_uucopystr(const void *from, void *to, size_t size) -{ - sysret_t rval; - - if (__systemcall(&rval, SYS_uucopystr + 1024, from, to, size) != 0) - return (EFAULT); - return (0); -} - /* * Figures out the PID of init for the zone. Also returns a boolean * indicating whether this process currently has that pid: if so, @@ -301,7 +139,7 @@ get_initpid_info(void) */ if ((err = __systemcall(&rval, SYS_brand, B_S10_PIDINFO, &pid, &zone_init_pid)) != 0) { - s10_abort(err, "Failed to get init's pid"); + brand_abort(err, "Failed to get init's pid"); } /* @@ -316,82 +154,6 @@ get_initpid_info(void) return (B_FALSE); } -/* - * This function is defined to be NOSYS but it won't be called from the - * the kernel since the NOSYS system calls are not enabled in the kernel. - * Thus, the only time this function is called is directly from within the - * indirect system call path. - */ -/*ARGSUSED*/ -static long -s10_unimpl(sysret_t *rv, uintptr_t p1) -{ - sysret_t rval; - - /* - * We'd like to print out some kind of error message here like - * "unsupported syscall", but we can't because it's not safe to - * assume that stderr or STDERR_FILENO actually points to something - * that is a terminal, and if we wrote to those files we could - * inadvertantly write to some applications open files, which would - * be bad. - * - * Normally, if an application calls an invalid system call - * it get a SIGSYS sent to it. So we'll just go ahead and send - * ourselves a signal here. Note that this is far from ideal since - * if the application has registered a signal handler, that signal - * handler may recieve a ucontext_t as the third parameter to - * indicate the context of the process when the signal was - * generated, and in this case that context will not be what the - * application is expecting. Hence, we should probably create a - * brandsys() kernel function that can deliver the signal to us - * with the correct ucontext_t. - */ - (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGSYS); - return (ENOSYS); -} - -#if defined(__sparc) && !defined(__sparcv9) -/* - * Yuck. For 32-bit sparc applications, handle indirect system calls. - * Note that we declare this interface to use the maximum number of - * system call arguments. If we recieve a system call that uses less - * arguments, then the additional arguments will be garbage, but they - * will also be ignored so that should be ok. - */ -static long -s10_indir(sysret_t *rv, int code, - uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, - uintptr_t a5, uintptr_t a6, uintptr_t a7) -{ - s10_sysent_table_t *sst = &(s10_sysent_table[code]); - - s10_assert(code < NSYSCALL); - switch (sst->st_args & NARGS_MASK) { - case 0: - return ((sst->st_callc)(rv)); - case 1: - return ((sst->st_callc)(rv, a0)); - case 2: - return ((sst->st_callc)(rv, a0, a1)); - case 3: - return ((sst->st_callc)(rv, a0, a1, a2)); - case 4: - return ((sst->st_callc)(rv, a0, a1, a2, a3)); - case 5: - return ((sst->st_callc)(rv, a0, a1, a2, a3, a4)); - case 6: - return ((sst->st_callc)(rv, rv, a0, a1, a2, a3, a4, a5)); - case 7: - return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6)); - case 8: - return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6, a7)); - } - s10_abort(0, "invalid entry in s10_sysent_table"); - return (EINVAL); -} -#endif /* __sparc && !__sparcv9 */ - /* Free the thread-local storage provided by mntfs_get_mntentbuf(). */ static void mntfs_free_mntentbuf(void *arg) @@ -514,7 +276,7 @@ mntfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) * therefore need to check the user-supplied address now since the * one we'll be providing is guaranteed to work. */ - if (s10_uucopy(&embufp->mbuf_emp, (void *)arg, sizeof (void *)) != 0) + if (brand_uucopy(&embufp->mbuf_emp, (void *)arg, sizeof (void *)) != 0) return (EFAULT); /* @@ -537,7 +299,7 @@ mntfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) } } - if (s10_uucopy(&embufp->mbuf_emp, (void *)arg, sizeof (void *)) != 0) + if (brand_uucopy(&embufp->mbuf_emp, (void *)arg, sizeof (void *)) != 0) return (EFAULT); return (0); @@ -666,7 +428,8 @@ crypto_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) if (major(sbuf.st_rdev) != crypto_dev) goto nonemuioctl; - if (s10_uucopy((const void *)arg, &s10_param, sizeof (s10_param)) != 0) + if (brand_uucopy((const void *)arg, &s10_param, sizeof (s10_param)) + != 0) return (EFAULT); struct_assign(native_param, s10_param, fl_provider_id); if ((err = __systemcall(rval, SYS_ioctl + 1024, fdes, cmd, @@ -753,7 +516,7 @@ crypto_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) struct_assign(s10_param, native_param, fl_list.prov_hash_threshold); struct_assign(s10_param, native_param, fl_list.prov_hash_limit); - return (s10_uucopy(&s10_param, (void *)arg, sizeof (s10_param))); + return (brand_uucopy(&s10_param, (void *)arg, sizeof (s10_param))); nonemuioctl: return (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg)); @@ -795,7 +558,7 @@ ctfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) if (strcmp(statbuf.st_fstype, MNTTYPE_CTFS) != 0) return (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg)); - if (s10_uucopy((const void *)arg, &s10param, sizeof (s10param)) != 0) + if (brand_uucopy((const void *)arg, &s10param, sizeof (s10param)) != 0) return (EFAULT); param.ctpm_id = s10param.ctpm_id; param.ctpm_size = sizeof (uint64_t); @@ -805,7 +568,8 @@ ctfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) return (err); if (cmd == CT_TGET) - return (s10_uucopy(&s10param, (void *)arg, sizeof (s10param))); + return (brand_uucopy(&s10param, (void *)arg, + sizeof (s10param))); return (0); } @@ -938,7 +702,8 @@ zfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) * copy the individual fields to a Solaris Next ZFS ioctl * structure. */ - if (s10_uucopy((const void *)arg, &s10_param, sizeof (s10_param)) != 0) + if (brand_uucopy((const void *)arg, &s10_param, sizeof (s10_param)) + != 0) return (EFAULT); /* @@ -1037,7 +802,7 @@ zfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) * Copy the S10 structure from the stack to the location * specified by the S10 process. */ - (void) s10_uucopy(&s10_param, (void *)arg, sizeof (s10_param)); + (void) brand_uucopy(&s10_param, (void *)arg, sizeof (s10_param)); return (err); passthruioctl: @@ -1180,7 +945,7 @@ s10_getdents_common(sysret_t *rval, int fd, char *buf, size_t nbyte, * use ENOMEM even though getdents(2) doesn't use it because it * best describes the failure. */ - (void) S10_TRUSS_POINT_3(rval, getdents_syscall_id, ENOMEM, fd, + (void) B_TRUSS_POINT_3(rval, getdents_syscall_id, ENOMEM, fd, buf, nbyte); rval->sys_rval1 = -1; rval->sys_rval2 = 0; @@ -1240,7 +1005,7 @@ s10_getdents_common(sysret_t *rval, int fd, char *buf, size_t nbyte, * Copy local_buf into buf so that the calling process can see * the results. */ - if ((err = s10_uucopy(local_buf, buf, buf_size)) != 0) { + if ((err = brand_uucopy(local_buf, buf, buf_size)) != 0) { free(local_buf); rval->sys_rval1 = -1; rval->sys_rval2 = 0; @@ -1326,7 +1091,7 @@ s10_acctctl(sysret_t *rval, int cmd, void *buf, size_t bufsz) mode = AC_FLOW; break; default: - return (S10_TRUSS_POINT_3(rval, SYS_acctctl, EINVAL, cmd, buf, + return (B_TRUSS_POINT_3(rval, SYS_acctctl, EINVAL, cmd, buf, bufsz)); } @@ -1383,12 +1148,12 @@ s10_auditsys(sysret_t *rval, int bsmcmd, intptr_t a0, intptr_t a1, intptr_t a2) &m, a2)) != 0) return (err); m = ((m & S10_AUDIT_HMASK) << 1) | (m & S10_AUDIT_LMASK); - if (s10_uucopy(&m, (void *)a1, sizeof (m)) != 0) + if (brand_uucopy(&m, (void *)a1, sizeof (m)) != 0) return (EFAULT); return (0); } else if ((int)a0 == A_SETPOLICY) { - if (s10_uucopy((const void *)a1, &m, sizeof (m)) != 0) + if (brand_uucopy((const void *)a1, &m, sizeof (m)) != 0) return (EFAULT); m = ((m >> 1) & S10_AUDIT_HMASK) | (m & S10_AUDIT_LMASK); return (__systemcall(rval, SYS_auditsys + 1024, bsmcmd, a0, &m, @@ -1399,11 +1164,11 @@ s10_auditsys(sysret_t *rval, int bsmcmd, intptr_t a0, intptr_t a1, intptr_t a2) return (err); if (m == AUC_NOSPACE) m = S10_AUC_NOSPACE; - if (s10_uucopy(&m, (void *)a1, sizeof (m)) != 0) + if (brand_uucopy(&m, (void *)a1, sizeof (m)) != 0) return (EFAULT); return (0); } else if ((int)a0 == A_SETCOND) { - if (s10_uucopy((const void *)a1, &m, sizeof (m)) != 0) + if (brand_uucopy((const void *)a1, &m, sizeof (m)) != 0) return (EFAULT); if (m == S10_AUC_NOSPACE) m = AUC_NOSPACE; @@ -1431,7 +1196,7 @@ s10_exec_native(sysret_t *rval, const char *fname, const char **argp, /* Get a copy of the executable we're trying to run */ path[0] = '\0'; - (void) s10_uucopystr(filename, path, sizeof (path)); + (void) brand_uucopystr(filename, path, sizeof (path)); /* Check if we're trying to run a native binary */ if (strncmp(path, "/.SUNWnative/usr/lib/brand/solaris10/s10_native", @@ -1445,13 +1210,13 @@ s10_exec_native(sysret_t *rval, const char *fname, const char **argp, * The the path of the dynamic linker is the second parameter * of s10_native_exec(). */ - if (s10_uucopy(argp, &filename, sizeof (char *)) != 0) + if (brand_uucopy(argp, &filename, sizeof (char *)) != 0) return (EFAULT); /* If an exec call succeeds, it never returns */ err = __systemcall(rval, SYS_brand + 1024, B_EXEC_NATIVE, filename, argp, envp, NULL, NULL, NULL); - s10_assert(err != 0); + brand_assert(err != 0); return (err); } @@ -1468,7 +1233,7 @@ s10_exec(sysret_t *rval, const char *fname, const char **argp) /* If an exec call succeeds, it never returns */ err = __systemcall(rval, SYS_execve + 1024, fname, argp, NULL); - s10_assert(err != 0); + brand_assert(err != 0); return (err); } @@ -1486,7 +1251,7 @@ s10_execve(sysret_t *rval, const char *fname, const char **argp, /* If an exec call succeeds, it never returns */ err = __systemcall(rval, SYS_execve + 1024, fname, argp, envp); - s10_assert(err != 0); + brand_assert(err != 0); return (err); } @@ -1510,14 +1275,14 @@ s10_uname(sysret_t *rv, uintptr_t p1) return (err); rev = atoi(&un.release[2]); - s10_assert(rev >= 11); + brand_assert(rev >= 11); bzero(un.release, _SYS_NMLN); (void) strlcpy(un.release, S10_UTS_RELEASE, _SYS_NMLN); bzero(un.version, _SYS_NMLN); (void) strlcpy(un.version, S10_UTS_VERSION, _SYS_NMLN); /* copy out the modified uname info */ - return (s10_uucopy(&un, unp, sizeof (un))); + return (brand_uucopy(&un, unp, sizeof (un))); } int @@ -1544,7 +1309,7 @@ s10_sysconfig(sysret_t *rv, int which) return (__systemcall(rv, SYS_sysconfig + 1024, which)); } - (void) S10_TRUSS_POINT_1(rv, SYS_sysconfig, 0, which); + (void) B_TRUSS_POINT_1(rv, SYS_sysconfig, 0, which); rv->sys_rval1 = value; rv->sys_rval2 = 0; @@ -1582,11 +1347,14 @@ s10_sysinfo(sysret_t *rv, int command, char *buf, long count) len = strlen(value) + 1; if (count > 0) { - if (s10_uucopystr(value, buf, count) != 0) + if (brand_uucopystr(value, buf, count) != 0) return (EFAULT); - /* Assure NULL termination of buf as s10_uucopystr() doesn't. */ - if (len > count && s10_uucopy("\0", buf + (count - 1), 1) != 0) + /* + * Assure NULL termination of buf as brand_uucopystr() doesn't. + */ + if (len > count && brand_uucopy("\0", buf + (count - 1), 1) + != 0) return (EFAULT); } @@ -1594,7 +1362,7 @@ s10_sysinfo(sysret_t *rv, int command, char *buf, long count) * On success, sysinfo(2) returns the size of buffer required to hold * the complete value plus its terminating NULL byte. */ - (void) S10_TRUSS_POINT_3(rv, SYS_systeminfo, 0, command, buf, count); + (void) B_TRUSS_POINT_3(rv, SYS_systeminfo, 0, command, buf, count); rv->sys_rval1 = len; rv->sys_rval2 = 0; return (0); @@ -1700,7 +1468,7 @@ s10_lwp_create_correct_fs(sysret_t *rval, ucontext_t *ucp, int flags, * Then make s10_lwp_create_entry_point() the new LWP's entry * point. */ - if (s10_uucopy(ucp, &s10_uc, sizeof (s10_uc)) != 0) + if (brand_uucopy(ucp, &s10_uc, sizeof (s10_uc)) != 0) return (EFAULT); s10_uc.uc_mcontext.gregs[REG_R14] = s10_uc.uc_mcontext.gregs[REG_RIP]; @@ -1740,7 +1508,7 @@ s10_lwp_private(sysret_t *rval, int cmd, int which, uintptr_t base) * Solaris 10 libc with which we're working functions correctly when %fs * is zero by calling thr_main() after issuing the SYS_lwp_private * syscall. If thr_main() barfs (returns -1), then change the LWP's %fs - * register via SYS_brand and patch s10_sysent_table so that issuing + * register via SYS_brand and patch brand_sysent_table so that issuing * SYS_lwp_create executes s10_lwp_create_correct_fs() rather than the * default s10_lwp_create(). s10_lwp_create_correct_fs() will * guarantee that new LWPs will have correct %fs values. @@ -1754,14 +1522,14 @@ s10_lwp_private(sysret_t *rval, int cmd, int which, uintptr_t base) * executed when libc is first loaded by ld.so.1. Thus we * are guaranteed to be single-threaded at this point. Even * if we were multithreaded at this point, writing a 64-bit - * value to the st_callc field of a s10_sysent_table + * value to the st_callc field of a brand_sysent_table * entry is guaranteed to be atomic on 64-bit x86 chips * as long as the field is not split across cache lines * (It shouldn't be.). See chapter 8, section 1.1 of * "The Intel 64 and IA32 Architectures Software Developer's * Manual," Volume 3A for more details. */ - s10_sysent_table[SYS_lwp_create].st_callc = + brand_sysent_table[SYS_lwp_create].st_callc = (sysent_cb_t)s10_lwp_create_correct_fs; return (__systemcall(rval, SYS_brand + 1024, B_S10_FSREGCORRECTION)); @@ -1820,7 +1588,7 @@ s10_zone(sysret_t *rval, int cmd, void *arg1, void *arg2, void *arg3, switch (cmd) { case ZONE_LOOKUP: - (void) S10_TRUSS_POINT_1(rval, SYS_zone, 0, cmd); + (void) B_TRUSS_POINT_1(rval, SYS_zone, 0, cmd); rval->sys_rval1 = GLOBAL_ZONEID; rval->sys_rval2 = 0; return (0); @@ -1855,7 +1623,7 @@ s10_zone(sysret_t *rval, int cmd, void *arg1, void *arg2, void *arg3, goto passthru; } - (void) S10_TRUSS_POINT_5(rval, SYS_zone, 0, cmd, zid, attr, + (void) B_TRUSS_POINT_5(rval, SYS_zone, 0, cmd, zid, attr, buf, bufsize); len = strlen(aval) + 1; @@ -1864,17 +1632,17 @@ s10_zone(sysret_t *rval, int cmd, void *arg1, void *arg2, void *arg3, if (buf != NULL) { if (len == 1) { - if (s10_uucopy("\0", buf, 1) != 0) + if (brand_uucopy("\0", buf, 1) != 0) return (EFAULT); } else { - if (s10_uucopystr(aval, buf, len) != 0) + if (brand_uucopystr(aval, buf, len) != 0) return (EFAULT); /* * Assure NULL termination of "buf" as - * s10_uucopystr() does NOT. + * brand_uucopystr() does NOT. */ - if (s10_uucopy("\0", buf + (len - 1), 1) != 0) + if (brand_uucopy("\0", buf + (len - 1), 1) != 0) return (EFAULT); } } @@ -1892,61 +1660,16 @@ passthru: arg4)); } -/* - * Close a libc file handle, but don't actually close the underlying - * file descriptor. - */ -static void -s10_close_fh(FILE *file) -{ - int fd, fd_new; - - if (file == NULL) - return; - - if ((fd = fileno(file)) < 0) - return; - - /* - * We're a branded process but our handler isn't installed yet. We - * can't use the dup() syscall since it no longer exists. - */ - fd_new = fcntl(fd, F_DUPFD, 0); - if (fd_new == -1) - return; - - (void) fclose(file); - (void) dup2(fd_new, fd); - (void) close(fd_new); -} - /*ARGSUSED*/ int -s10_init(int argc, char *argv[], char *envp[]) +brand_init(int argc, char *argv[], char *envp[]) { sysret_t rval; - s10_brand_reg_t reg; - s10_elf_data_t sed; - auxv_t *ap; - uintptr_t *p; - int i, err; + ulong_t ldentry; + int err; char *bname; - /* Sanity check our translation table return value codes */ - for (i = 0; i < NSYSCALL; i++) { - s10_sysent_table_t *est = &(s10_sysent_table[i]); - s10_assert(BIT_ONLYONESET(est->st_args & RV_MASK)); - } - - /* - * We need to shutdown all libc stdio. libc stdio normally goes to - * file descriptors, but since we're actually part of a another - * process we don't own these file descriptors and we can't make - * any assumptions about their state. - */ - s10_close_fh(stdin); - s10_close_fh(stdout); - s10_close_fh(stderr); + brand_pre_init(); /* * Cache the pid of the zone's init process and determine if @@ -1957,13 +1680,13 @@ s10_init(int argc, char *argv[], char *envp[]) /* get the current zoneid */ err = __systemcall(&rval, SYS_zone, ZONE_LOOKUP, NULL); - s10_assert(err == 0); + brand_assert(err == 0); zoneid = (zoneid_t)rval.sys_rval1; /* Get the zone's emulation bitmap. */ if ((err = __systemcall(&rval, SYS_zone, ZONE_GETATTR, zoneid, S10_EMUL_BITMAP, emul_bitmap, sizeof (emul_bitmap))) != 0) { - s10_abort(err, "The zone's patch level is unsupported"); + brand_abort(err, "The zone's patch level is unsupported"); /*NOTREACHED*/ } @@ -1992,137 +1715,26 @@ s10_init(int argc, char *argv[], char *envp[]) strcmp("patchadd", bname) == 0 || strcmp("patchrm", bname) == 0) emul_global_zone = B_TRUE; - /* - * Register our syscall emulation table with the kernel. - * Note that we don't have to do invoke (syscall_number + 1024) - * until we've actually establised a syscall emulation callback - * handler address, which is what we're doing with this brand - * syscall. - */ - reg.sbr_version = S10_VERSION; -#ifdef __x86 - reg.sbr_handler = (caddr_t)s10_handler_table; -#else /* !__x86 */ - reg.sbr_handler = (caddr_t)s10_handler; -#endif /* !__x86 */ - - if ((err = __systemcall(&rval, SYS_brand, B_REGISTER, ®)) != 0) { - s10_abort(err, "Failed to brand current process"); - /*NOTREACHED*/ - } - - /* Get data about the executable we're running from the kernel. */ - if ((err = __systemcall(&rval, SYS_brand + 1024, - B_ELFDATA, (void *)&sed)) != 0) { - s10_abort(err, - "Failed to get required brand ELF data from the kernel"); - /*NOTREACHED*/ - } - - /* - * Find the aux vector on the stack. - */ - p = (uintptr_t *)envp; - while (*p != NULL) - p++; - - /* - * p is now pointing at the 0 word after the environ pointers. - * After that is the aux vectors. - * - * The aux vectors are currently pointing to the brand emulation - * library and associated linker. We're going to change them to - * point to the brand executable and associated linker (or to no - * linker for static binaries). This matches the process data - * stored within the kernel and visible from /proc, which was - * all setup in s10_elfexec(). We do this so that when a debugger - * attaches to the process it sees the process as a normal solaris - * process, this brand emulation library and everything on it's - * link map will not be visible, unless our librtld_db plugin - * is used. Note that this is very different from how Linux - * branded processes are implemented within lx branded zones. - * In that situation, the primary linkmap of the process is the - * brand emulation libraries linkmap, not the Linux applications - * linkmap. - * - * We also need to clear the AF_SUN_NOPLM flag from the AT_SUN_AUXFLAGS - * aux vector. This flag told our linker that we don't have a - * primary link map. Now that our linker is done initializing, we - * want to clear this flag before we transfer control to the - * applications copy of the linker, since we want that linker to have - * a primary link map which will be the link map for the application - * we're running. - */ - p++; - for (ap = (auxv_t *)p; ap->a_type != AT_NULL; ap++) { - switch (ap->a_type) { - case AT_BASE: - /* Hide AT_BASE if static binary */ - if (sed.sed_base == NULL) { - ap->a_type = AT_IGNORE; - ap->a_un.a_val = NULL; - } else { - ap->a_un.a_val = sed.sed_base; - } - break; - case AT_ENTRY: - ap->a_un.a_val = sed.sed_entry; - break; - case AT_PHDR: - ap->a_un.a_val = sed.sed_phdr; - break; - case AT_PHENT: - ap->a_un.a_val = sed.sed_phent; - break; - case AT_PHNUM: - ap->a_un.a_val = sed.sed_phnum; - break; - case AT_SUN_AUXFLAGS: - ap->a_un.a_val &= ~AF_SUN_NOPLM; - break; - case AT_SUN_EMULATOR: - /* - * ld.so.1 inspects AT_SUN_EMULATOR to see if - * if it is the linker for the brand emulation - * library. Hide AT_SUN_EMULATOR, as the - * linker we are about to jump to is the linker - * for the binary. - */ - ap->a_type = AT_IGNORE; - ap->a_un.a_val = NULL; - break; - case AT_SUN_LDDATA: - /* Hide AT_SUN_LDDATA if static binary */ - if (sed.sed_lddata == NULL) { - ap->a_type = AT_IGNORE; - ap->a_un.a_val = NULL; - } else { - ap->a_un.a_val = sed.sed_lddata; - } - break; - default: - break; - } - } + ldentry = brand_post_init(S10_VERSION, argc, argv, envp); - s10_runexe(argv, sed.sed_ldentry); + brand_runexe(argv, ldentry); /*NOTREACHED*/ - s10_abort(0, "s10_runexe() returned"); + brand_abort(0, "brand_runexe() returned"); return (-1); } /* * This table must have at least NSYSCALL entries in it. * - * The second parameter of each entry in the s10_sysent_table + * The second parameter of each entry in the brand_sysent_table * contains the number of parameters and flags that describe the * syscall return value encoding. See the block comments at the * top of this file for more information about the syscall return * value flags and when they should be used. */ -s10_sysent_table_t s10_sysent_table[] = { +brand_sysent_table_t brand_sysent_table[] = { #if defined(__sparc) && !defined(__sparcv9) - EMULATE(s10_indir, 9 | RV_64RVAL), /* 0 */ + EMULATE(brand_indir, 9 | RV_64RVAL), /* 0 */ #else NOSYS, /* 0 */ #endif diff --git a/usr/src/lib/brand/solaris10/s10_brand/common/s10_deleted.c b/usr/src/lib/brand/solaris10/s10_brand/common/s10_deleted.c index fbd9a4de6d..d75413a22f 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/common/s10_deleted.c +++ b/usr/src/lib/brand/solaris10/s10_brand/common/s10_deleted.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -38,6 +37,7 @@ #include #include +#include #include /* @@ -293,7 +293,7 @@ s10_utime(sysret_t *rval, const char *path, const struct utimbuf *times) if (times == NULL) { tsp = NULL; } else { - if (s10_uucopy(times, <imes, sizeof (ltimes)) != 0) + if (brand_uucopy(times, <imes, sizeof (ltimes)) != 0) return (EFAULT); ts[0].tv_sec = ltimes.actime; ts[0].tv_nsec = 0; @@ -316,7 +316,7 @@ s10_utimes(sysret_t *rval, const char *path, const struct timeval times[2]) if (times == NULL) { tsp = NULL; } else { - if (s10_uucopy(times, ltimes, sizeof (ltimes)) != 0) + if (brand_uucopy(times, ltimes, sizeof (ltimes)) != 0) return (EFAULT); ts[0].tv_sec = ltimes[0].tv_sec; ts[0].tv_nsec = ltimes[0].tv_usec * 1000; @@ -340,7 +340,7 @@ s10_futimesat(sysret_t *rval, if (times == NULL) { tsp = NULL; } else { - if (s10_uucopy(times, ltimes, sizeof (ltimes)) != 0) + if (brand_uucopy(times, ltimes, sizeof (ltimes)) != 0) return (EFAULT); ts[0].tv_sec = ltimes[0].tv_sec; ts[0].tv_nsec = ltimes[0].tv_usec * 1000; diff --git a/usr/src/lib/brand/solaris10/s10_brand/common/s10_signal.c b/usr/src/lib/brand/solaris10/s10_brand/common/s10_signal.c index ff012812d7..d5b337cc6c 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/common/s10_signal.c +++ b/usr/src/lib/brand/solaris10/s10_brand/common/s10_signal.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -35,6 +34,7 @@ #include #include +#include #include #include @@ -192,7 +192,7 @@ s10sigset_to_native(const sigset_t *s10_set, sigset_t *native_set) int nativesig; sigset_t srcset, newset; - if (s10_uucopy(s10_set, &srcset, sizeof (sigset_t)) != 0) + if (brand_uucopy(s10_set, &srcset, sizeof (sigset_t)) != 0) return (EFAULT); (void) sigemptyset(&newset); @@ -217,7 +217,7 @@ s10sigset_to_native(const sigset_t *s10_set, sigset_t *native_set) SIGADDSET(&newset, nativesig); } - if (s10_uucopy(&newset, native_set, sizeof (sigset_t)) != 0) + if (brand_uucopy(&newset, native_set, sizeof (sigset_t)) != 0) return (EFAULT); return (0); @@ -263,7 +263,7 @@ nativesigset_to_s10(const sigset_t *native_set, sigset_t *s10_set) int s10sig; sigset_t srcset, newset; - if (s10_uucopy(native_set, &srcset, sizeof (sigset_t)) != 0) + if (brand_uucopy(native_set, &srcset, sizeof (sigset_t)) != 0) return (EFAULT); (void) sigemptyset(&newset); @@ -288,7 +288,7 @@ nativesigset_to_s10(const sigset_t *native_set, sigset_t *s10_set) SIGADDSET(&newset, s10sig); } - if (s10_uucopy(&newset, s10_set, sizeof (sigset_t)) != 0) + if (brand_uucopy(&newset, s10_set, sizeof (sigset_t)) != 0) return (EFAULT); return (0); @@ -307,7 +307,7 @@ s10_sigacthandler(int sig, siginfo_t *sip, void *uvp) s10_sig = nativesig_to_s10(sig); if (s10_sig <= 0) /* can't happen? */ - s10_abort(sig, "Received an impossible signal"); + brand_abort(sig, "Received an impossible signal"); if (sip != NULL) { /* * All we really have to do is map the signal number, @@ -316,7 +316,7 @@ s10_sigacthandler(int sig, siginfo_t *sip, void *uvp) * same between s10 and native. */ if (sip->si_signo != sig) /* can't happen? */ - s10_abort(sig, "Received an impossible siginfo"); + brand_abort(sig, "Received an impossible siginfo"); sip->si_signo = s10_sig; } if ((ucp = uvp) != NULL && @@ -404,7 +404,7 @@ s10_sigsuspend(sysret_t *rval, const sigset_t *set) int err; if ((err = s10sigset_to_native(set, &sigset_set)) != 0) { - (void) S10_TRUSS_POINT_1(rval, SYS_sigsuspend, err, set); + (void) B_TRUSS_POINT_1(rval, SYS_sigsuspend, err, set); return (err); } @@ -439,7 +439,7 @@ s10_sigaction(sysret_t *rval, void (*handler)(); if ((nativesig = s10sig_to_native(sig)) < 0) { - (void) S10_TRUSS_POINT_3(rval, SYS_sigaction, EINVAL, + (void) B_TRUSS_POINT_3(rval, SYS_sigaction, EINVAL, sig, act, oact); return (EINVAL); } @@ -449,12 +449,12 @@ s10_sigaction(sysret_t *rval, } else { sigactp = &sigact; - if (s10_uucopy(act, sigactp, sizeof (struct sigaction)) != 0) + if (brand_uucopy(act, sigactp, sizeof (struct sigaction)) != 0) return (EFAULT); if ((err = s10sigset_to_native(&sigactp->sa_mask, &sigactp->sa_mask)) != 0) { - (void) S10_TRUSS_POINT_3(rval, SYS_sigaction, err, + (void) B_TRUSS_POINT_3(rval, SYS_sigaction, err, sig, act, oact); return (err); } @@ -488,8 +488,8 @@ s10_sigaction(sysret_t *rval, if (osigactp->sa_handler == s10_sigacthandler) osigactp->sa_handler = s10_handlers[sig - 1]; - if (err == 0 && - s10_uucopy(osigactp, oact, sizeof (struct sigaction)) != 0) + if (err == 0 && brand_uucopy(osigactp, oact, + sizeof (struct sigaction)) != 0) err = EFAULT; } @@ -541,7 +541,7 @@ s10_sigsendsys(sysret_t *rval, procset_t *psp, int sig) int nativesig; if ((nativesig = s10sig_to_native(sig)) < 0) { - (void) S10_TRUSS_POINT_2(rval, SYS_sigsendsys, EINVAL, + (void) B_TRUSS_POINT_2(rval, SYS_sigsendsys, EINVAL, psp, sig); return (EINVAL); } @@ -639,7 +639,7 @@ s10_sigtimedwait(sysret_t *rval, int err, sig; if ((err = s10sigset_to_native(set, &sigset_set)) != 0) { - (void) S10_TRUSS_POINT_3(rval, SYS_sigtimedwait, err, + (void) B_TRUSS_POINT_3(rval, SYS_sigtimedwait, err, set, info, timeout); return (err); } @@ -682,7 +682,7 @@ s10_sigqueue(sysret_t *rval, pid_t pid, int signo, void *value, int si_code) int nativesig; if ((nativesig = s10sig_to_native(signo)) < 0) { - (void) S10_TRUSS_POINT_4(rval, SYS_sigqueue, EINVAL, + (void) B_TRUSS_POINT_4(rval, SYS_sigqueue, EINVAL, pid, signo, value, si_code); return (EINVAL); } @@ -715,11 +715,11 @@ s10_signotify(sysret_t *rval, if (cmd == SN_PROC) { int nativesig; - if (s10_uucopy(infop, &info, sizeof (siginfo_t)) != 0) + if (brand_uucopy(infop, &info, sizeof (siginfo_t)) != 0) return (EFAULT); if ((nativesig = s10sig_to_native(info.si_signo)) < 0) { - (void) S10_TRUSS_POINT_3(rval, SYS_signotify, EINVAL, + (void) B_TRUSS_POINT_3(rval, SYS_signotify, EINVAL, cmd, siginfo, sn_id); return (EINVAL); } @@ -740,7 +740,7 @@ s10_kill(sysret_t *rval, pid_t pid, int sig) int nativesig; if ((nativesig = s10sig_to_native(sig)) < 0) { - (void) S10_TRUSS_POINT_2(rval, SYS_kill, EINVAL, pid, sig); + (void) B_TRUSS_POINT_2(rval, SYS_kill, EINVAL, pid, sig); return (EINVAL); } @@ -761,7 +761,7 @@ s10_lwp_create(sysret_t *rval, ucontext_t *ucp, int flags, id_t *new_lwp) { ucontext_t s10_uc; - if (s10_uucopy(ucp, &s10_uc, sizeof (ucontext_t)) != 0) + if (brand_uucopy(ucp, &s10_uc, sizeof (ucontext_t)) != 0) return (EFAULT); if (s10_uc.uc_flags & UC_SIGMASK) @@ -781,7 +781,7 @@ s10_lwp_kill(sysret_t *rval, id_t lwpid, int sig) int nativesig; if ((nativesig = s10sig_to_native(sig)) < 0) { - (void) S10_TRUSS_POINT_2(rval, SYS_lwp_kill, EINVAL, + (void) B_TRUSS_POINT_2(rval, SYS_lwp_kill, EINVAL, lwpid, sig); return (EINVAL); } diff --git a/usr/src/lib/brand/solaris10/s10_brand/i386/Makefile b/usr/src/lib/brand/solaris10/s10_brand/i386/Makefile index 2d41a3f455..8f6a505876 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/i386/Makefile +++ b/usr/src/lib/brand/solaris10/s10_brand/i386/Makefile @@ -19,14 +19,15 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -ISASRCDIR = . +ISAOBJDIR = $(BRAND_SHARED)/brand/i386/pics include ../Makefile.com +CPPFLAGS += -I$(BRAND_SHARED)/brand/i386 + # # see ../Makefile.com for why we explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/solaris10/s10_brand/i386/s10_crt.s b/usr/src/lib/brand/solaris10/s10_brand/i386/s10_crt.s deleted file mode 100644 index d237aed543..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/i386/s10_crt.s +++ /dev/null @@ -1,77 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -#if defined(lint) - -void -_start(void) -{ -} - -#else /* lint */ - /* - * Initial entry point for the brand emulation library. - * - * This platform specific assembly entry point exists just to invoke - * the common brand library startup routine. That routine expects to - * be called with the following arguments: - * s10_init(int argc, char *argv[], char *envp[]) - * - * There are no arguments explicitly passed to this entry point, - * routine, but we do know how our initial stack has been setup by - * the kernel. The stack format is documented in: - * usr/src/cmd/sgs/rtld/i386/boot.s - * - * So this routine will troll through the stack to setup the argument - * values for the common brand library startup routine and then invoke - * it. This routine is modeled after the default crt1.s`_start() - * routines. - */ - ENTRY_NP(_start) - - /* Make stack traces look pretty, build a fake stack frame. */ - pushl $0 / retpc = NULL - pushl $0 / fp = NULL - movl %esp, %ebp / first stack frame - - /* - * Calculate the location of the envp array by adding the size of - * the argv array to the start of the argv array. - */ - movl 8(%ebp), %eax / argc in %eax - leal 12(%ebp), %ebx / &argv[0] in %ebx - leal 16(%ebp,%eax,4), %ecx / envp in %ecx - - pushl %ecx / push envp (3rd param) - pushl %ebx / push argv (2nd param) - pushl %eax / push argc (1st param) - call s10_init - - /*NOTREACHED*/ - SET_SIZE(_start) -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/i386/s10_handler.s b/usr/src/lib/brand/solaris10/s10_brand/i386/s10_handler.s deleted file mode 100644 index 1b2f5e5313..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/i386/s10_handler.s +++ /dev/null @@ -1,195 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -/* - * Each JMP must occupy 16 bytes - */ -#define JMP \ - pushl $_CONST(. - s10_handler_table); \ - jmp s10_handler; \ - .align 16; - -#define JMP4 JMP; JMP; JMP; JMP -#define JMP16 JMP4; JMP4; JMP4; JMP4 -#define JMP64 JMP16; JMP16; JMP16; JMP16 -#define JMP256 JMP64; JMP64; JMP64; JMP64 - -#if defined(lint) - -void -s10_handler_table(void) -{} - -void -s10_handler(void) -{ -} - -#else /* lint */ - - /* - * On entry to this table, %eax will hold the return address. The - * location where we enter the table is a function of the system - * call number. The table needs the same alignment as the individual - * entries. - */ - .align 16 - ENTRY_NP(s10_handler_table) - JMP256 - SET_SIZE(s10_handler_table) - -#define PIC_SETUP(r) \ - call 9f; \ -9: \ - popl r; \ - addl $_GLOBAL_OFFSET_TABLE_ + [. - 9b], r - - /* - * %eax - userland return address - * stack contains: - * | -------------------------------------- - * v 4 | syscall arguments | - * %esp+0 | syscall number | - * -------------------------------------- - */ - ENTRY_NP(s10_handler) - pushl %ebp /* allocate a stack frame */ - movl %esp, %ebp - - /* Save registers at the time of the syscall. */ - movl $0, EH_LOCALS_GREG(TRAPNO)(%ebp) - movl $0, EH_LOCALS_GREG(ERR)(%ebp) - movl %ebx, EH_LOCALS_GREG(EBX)(%ebp) - movl %ecx, EH_LOCALS_GREG(ECX)(%ebp) - movl %edx, EH_LOCALS_GREG(EDX)(%ebp) - movl %edi, EH_LOCALS_GREG(EDI)(%ebp) - movl %esi, EH_LOCALS_GREG(ESI)(%ebp) - mov %cs, EH_LOCALS_GREG(CS)(%ebp) - mov %ds, EH_LOCALS_GREG(DS)(%ebp) - mov %es, EH_LOCALS_GREG(ES)(%ebp) - mov %fs, EH_LOCALS_GREG(FS)(%ebp) - mov %gs, EH_LOCALS_GREG(GS)(%ebp) - pushfl /* save syscall flags */ - popl %ecx - movl %ecx, EH_LOCALS_GREG(EFL)(%ebp) - movl EH_ARGS_OFFSET(0)(%ebp), %ecx /* save syscall ebp */ - movl %ecx, EH_LOCALS_GREG(EBP)(%ebp) - movl %ebp, %ecx /* save syscall esp */ - addl $CPTRSIZE, %ecx - movl %ecx, EH_LOCALS_GREG(ESP)(%ebp) - - /* - * The kernel drops us into the middle of the s10_handle_table - * above that then pushes that table offset onto the stack, and calls - * into s10_handler. That offset indicates the system call number while - * %eax holds the return address for the system call. We replace the - * value on the stack with the return address, and use the value to - * compute the system call number by dividing by the table entry size. - */ - xchgl CPTRSIZE(%ebp), %eax /* swap JMP table offset and ret addr */ - shrl $4, %eax /* table_offset/size = syscall num */ - movl %eax, EH_LOCALS_GREG(EAX)(%ebp) /* save syscall num */ - - /* - * Finish setting up our stack frame. We would normally do this - * upon entry to this function, but in this case we delayed it - * because a "sub" operation can modify flags and we wanted to - * save the flags into the gregset_t above before they get modified. - * - * Our stack frame format is documented in s10_misc.h. - */ - subl $EH_LOCALS_SIZE, %esp - - /* Look up the system call's entry in the sysent table */ - PIC_SETUP(%ecx) - movl s10_sysent_table@GOT(%ecx), %edx /* %edx = sysent_table */ - shll $3, %eax /* each entry is 8 bytes */ - add %eax, %edx /* %edx = sysent entry address */ - - /* - * Get the return value flag and the number of arguments from the - * sysent table. - */ - movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ - andl $RV_MASK, %ecx /* strip out number of args */ - movl %ecx, EH_LOCALS_RVFLAG(%ebp) /* save rv flag */ - movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ - andl $NARGS_MASK, %ecx /* strip out rv flag */ - - /* - * Setup arguments for our emulation call. Our input arguments, - * 0 to N, will become emulation call arguments 1 to N+1. - * %ecx == number of arguments. - */ - movl %ebp, %esi /* args are at 12(%ebp) */ - addl $EH_ARGS_OFFSET(3), %esi - movl %esp, %edi /* copy args to 4(%esp) */ - addl $EH_ARGS_OFFSET(1), %edi - rep; smovl /* copy: (%esi) -> (%edi) */ - /* copy: %ecx 32-bit words */ - movl EH_LOCALS_GREG(ESI)(%ebp), %esi /* restore %esi */ - movl EH_LOCALS_GREG(EDI)(%ebp), %edi /* restore %edi */ - - /* - * The first parameter to the emulation callback function is a - * pointer to a sysret_t structure. - */ - movl %ebp, %ecx - addl $EH_LOCALS_SYSRET, %ecx - movl %ecx, EH_ARGS_OFFSET(0)(%esp) /* arg0 == sysret_t ptr */ - - /* invoke the emulation routine */ - ALTENTRY(s10_handler_savepc) - call *(%edx) /* call emulation routine */ - - /* restore scratch registers */ - movl EH_LOCALS_GREG(ECX)(%ebp), %ecx /* restore %ecx */ - movl EH_LOCALS_GREG(EDX)(%ebp), %edx /* restore %edx */ - - /* Check for syscall emulation success or failure */ - cmpl $0, %eax /* check for an error */ - je success - stc /* failure, set carry flag */ - jmp return /* return, %rax == errno */ - -success: - /* There is always at least one return value. */ - movl EH_LOCALS_SYSRET1(%ebp), %eax /* %eax == sys_rval1 */ - cmpl $RV_DEFAULT, EH_LOCALS_RVFLAG(%ebp) /* check rv flag */ - je clear_carry - mov EH_LOCALS_SYSRET2(%ebp), %edx /* %edx == sys_rval2 */ -clear_carry: - clc /* success, clear carry flag */ - -return: - movl %ebp, %esp /* restore stack */ - popl %ebp - ret /* ret to instr after syscall */ - SET_SIZE(s10_handler) - - -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/i386/s10_runexe.s b/usr/src/lib/brand/solaris10/s10_brand/i386/s10_runexe.s deleted file mode 100644 index 13cfb9d4b8..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/i386/s10_runexe.s +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -/*ARGSUSED*/ -void -s10_runexe(void *argv, ulong_t entry) -{ -} - -#else /* lint */ - /* - * Prepare to jump to the target program we actually want to run. - * If this program is dynamically linked then we'll be jumping to - * another copy of the linker. If it's a statically linked program - * we'll be jumping directy to it's main entry point. In any case, - * we need to reset our current state stack and register state to - * something similar to the initial process state setup by the kernel - * and documented at: - * usr/src/cmd/sgs/rtld/i386/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * Of course this is the same stack format as when this executable - * was first started, so here we'll just roll back the stack and - * frame pointers to their values when this processes first started - * execution. - */ - ENTRY_NP(s10_runexe) - - movl 4(%esp), %eax / %eax = &argv[0] - movl 8(%esp), %ebx / Brand app entry point in %ebx - subl $4, %eax / Top of stack - must point at argc - movl %eax, %esp / Set %esp to what linkers expect - - /* - * We also have to make sure to clear %edx since nornally ld.so.1 will - * set that to non-zero if there is an exit function that should be - * invoked when the process is terminating. This isn't actually - * necessary if the target program we're jumping to is a dynamically - * linked program since in that case we're actually jumping to another - * copy of ld.so.1 and it will just reset %edx, but if the target - * program we're jumping to is a statically linked binary that uses - * the standard sun compiler supplied crt1.o`_start(), it will check - * to see if %g1 is set. - */ - movl $0, %edx - - jmp *%ebx / And away we go... - /* - * target will never return. - */ - SET_SIZE(s10_runexe) -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/sparc/Makefile b/usr/src/lib/brand/solaris10/s10_brand/sparc/Makefile index 3cfd1f8496..52a71ae1bc 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/sparc/Makefile +++ b/usr/src/lib/brand/solaris10/s10_brand/sparc/Makefile @@ -19,14 +19,15 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -ISASRCDIR = . +ISAOBJDIR = $(BRAND_SHARED)/brand/sparc/pics include ../Makefile.com +CPPFLAGS += -I$(BRAND_SHARED)/brand/sparc + # # see ../Makefile.com for why we MUST explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_crt.s b/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_crt.s deleted file mode 100644 index 7d44642286..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_crt.s +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -void -_start(void) -{ -} - -#else /* lint */ - .section ".text" - /* - * Initial entry point for the brand emulation library. - * - * This platform specific assembly entry point exists just to invoke - * the common brand library startup routine. That routine expects to - * be called with the following arguments: - * s10_init(int argc, char *argv[], char *envp[]) - * - * There are no arguments explicitly passed to this entry point, - * routine, but we do know how our initial stack has been setup by - * the kernel. The stack format is documented in: - * usr/src/cmd/sgs/rtld/sparc/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * So this routine will troll through the stack to setup the argument - * values for the common brand library startup routine and then invoke - * it. - */ - ENTRY_NP(_start) -#if defined (__sparcv9) - save %sp, -SA(MINFRAME + EB_MAX_SIZE64), %sp -#else /* !__sparcv9 */ - save %sp, -SA(MINFRAME + EB_MAX_SIZE32), %sp -#endif /* !__sparcv9 */ - - /* get argc */ - ldn [%fp + WINDOWSIZE + STACK_BIAS], %o0 - - /* get argv */ - add %fp, + WINDOWSIZE + CPTRSIZE + STACK_BIAS, %o1 - - /* get envp */ - add %o0, 1, %l0 ! add 1 to argc for last element of 0 - sll %l0, CPTRSHIFT, %l0 ! multiply argc by pointer size - add %o1, %l0, %o2 ! and add to argv to get first env ptr - - call s10_init - nop - - /*NOTREACHED*/ - SET_SIZE(_start) -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_handler.s b/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_handler.s deleted file mode 100644 index 4d70ed5e68..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_handler.s +++ /dev/null @@ -1,225 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include - -#if defined(lint) - -void -s10_handler(void) -{ -} - -#else /* !lint */ - -#define PIC_SETUP(r) \ - mov %o7, %g1; \ -9: call 8f; \ - sethi %hi(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ -8: or r, %lo(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ - add r, %o7, r; \ - mov %g1, %o7 - -/* - * Translate a global symbol into an address. The resulting address - * is returned in the first register parameter. The second register - * is just for scratch space. - */ -#if defined(__sparcv9) -#define GET_SYM_ADDR(r1, r2, name) \ - PIC_SETUP(r1) ;\ - sethi %hi(name), r2 ;\ - or r2, %lo(name), r2 ;\ - ldn [r2 + r1], r1 -#else /* !__sparcv9 */ -#define GET_SYM_ADDR(r1, r2, name) \ - PIC_SETUP(r1); \ - ld [r1 + name], r1 -#endif /* !__sparcv9 */ - - .section ".text" - - /* - * When we get here, %g1 should contain the system call and - * %g5 should contain the address immediately after the trap - * instruction. - */ - ENTRY_NP(s10_handler) - - /* - * 64-bit sparc may need to save 3 parameters on the stack. - * 32-bit sparc may need to save 4 parameters on the stack. - * - * Our stack frame format is documented in s10_misc.h. - */ - save %sp, -SA(MINFRAME + EH_LOCALS_SIZE), %sp - - /* - * Save the current caller state into gregs and gwins. - * Note that this state isn't exact, %g1 and %g5 have been - * already been lost. Also, we've pushed a stack frame so - * the callers output registers are our input registers. - */ - stn %g0, [%sp + EH_LOCALS_GREG(REG_G1)] /* %g1 is lost */ - stn %g2, [%sp + EH_LOCALS_GREG(REG_G2)] - stn %g3, [%sp + EH_LOCALS_GREG(REG_G3)] - stn %g4, [%sp + EH_LOCALS_GREG(REG_G4)] - stn %g0, [%sp + EH_LOCALS_GREG(REG_G5)] /* %g5 is lost */ - stn %g6, [%sp + EH_LOCALS_GREG(REG_G6)] - stn %g7, [%sp + EH_LOCALS_GREG(REG_G7)] - stn %i0, [%sp + EH_LOCALS_GREG(REG_O0)] - stn %i1, [%sp + EH_LOCALS_GREG(REG_O1)] - stn %i2, [%sp + EH_LOCALS_GREG(REG_O2)] - stn %i3, [%sp + EH_LOCALS_GREG(REG_O3)] - stn %i4, [%sp + EH_LOCALS_GREG(REG_O4)] - stn %i5, [%sp + EH_LOCALS_GREG(REG_O5)] - stn %i6, [%sp + EH_LOCALS_GREG(REG_O6)] - stn %i7, [%sp + EH_LOCALS_GREG(REG_O7)] - sub %g5, 4, %o0 - stn %o0, [%sp + EH_LOCALS_GREG(REG_PC)] - stn %g5, [%sp + EH_LOCALS_GREG(REG_nPC)] - rd %y, %o0 - stn %o0, [%sp + EH_LOCALS_GREG(REG_Y)] -#if defined(__sparcv9) - stn %g0, [%sp + EH_LOCALS_GREG(REG_ASI)] - rd %fprs, %o0 - stn %o0, [%sp + EH_LOCALS_GREG(REG_FPRS)] -#endif /* __sparcv9 */ - - /* - * Look up the system call's entry in the sysent table - * and obtain the address of the proper emulation routine (%l2). - */ - mov %g1, %l5 /* save syscall number */ - GET_SYM_ADDR(%l1, %l2, s10_sysent_table) - mov %l5, %g1 /* restore syscall number */ - sll %g1, (1 + CLONGSHIFT), %l2 /* Each entry has 2 longs */ - add %l2, %l1, %l2 /* index to proper entry */ - ldn [%l2], %l2 /* emulation func address */ - - /* - * Look up the system call's entry in the sysent table, - * taking into account the posibility of indirect system calls, and - * obtain the number of arguments (%l4) and return value flag (%l3). - */ -#if defined(__sparcv9) - mov %g1, %l3 /* %g1 == syscall number */ -#else /* !__sparcv9 */ - /* - * Check for indirect system calls, in which case the real syscall - * number is the first parameter to the indirect system call. - */ - cmp %g1, %g0 /* saved syscall number */ - bne,a,pt %icc, no_indir /* indirect syscall? */ - mov %g1, %l3 /* %g1 == syscall number */ - mov %i0, %l3 /* %i0 == syscall number */ -no_indir: -#endif /* !__sparcv9 */ - sll %l3, (1 + CLONGSHIFT), %l3 /* Each entry has 2 longs */ - add %l3, %l1, %l3 /* index to proper entry */ - ldn [%l3 + CPTRSIZE], %l4 /* number of args + rv flag */ - sethi %hi(RV_MASK), %l5 - or %l5, %lo(RV_MASK), %l5 - andcc %l4, %l5, %l3 /* strip out number of args*/ - andcc %l4, NARGS_MASK, %l4 /* strip out rv flag */ - - /* - * Setup arguments for our emulation call. Our input arguments, - * 0 to N, will become emulation call arguments 1 to N+1. - * %l4 == number of arguments. - */ - mov %i0, %o1 - mov %i1, %o2 - mov %i2, %o3 - mov %i3, %o4 - mov %i4, %o5 - - /* 7th argument and above get passed on the stack */ - cmp %l4, 0x6 - bl,pt %ncc, args_copied - nop - stn %i5, [%sp + EH_ARGS_OFFSET(0)] /* copy 6th syscall arg */ - cmp %l4, 0x7 - bl,pt %ncc, args_copied - nop - ldn [%fp + EH_ARGS_OFFSET(0)], %l5 /* copy 7th syscall arg */ - stn %l5, [%sp + EH_ARGS_OFFSET(1)] - cmp %l4, 0x8 - bl,pt %ncc, args_copied - nop - ldn [%fp + EH_ARGS_OFFSET(1)], %l5 - stn %l5, [%sp + EH_ARGS_OFFSET(2)] /* copy 8th syscall arg */ -#if !defined(__sparcv9) - cmp %l4, 0x9 - bl,pt %ncc, args_copied - nop - ldn [%fp + EH_ARGS_OFFSET(2)], %l5 - stn %l5, [%sp + EH_ARGS_OFFSET(3)] /* copy 9th syscall arg */ -#endif /* !__sparcv9 */ - -args_copied: - /* - * The first parameter to the emulation callback function is a - * pointer to a sysret_t structure. - * - * invoke the emulation routine. - */ - ALTENTRY(s10_handler_savepc) - call %l2 - add %sp, EH_LOCALS_SYSRET, %o0 /* arg0 == sysret_t ptr */ - - /* Check for syscall emulation success or failure */ - cmp %g0, %o0 - be success - nop - subcc %g0, 1, %g0 /* failure, set carry flag */ - ba return - mov %o0, %i0 /* return, %o0 == errno */ - -success: - /* There is always at least one return value. */ - ldn [%sp + EH_LOCALS_SYSRET1], %i0 /* %i0 == sys_rval1 */ - cmp %l3, RV_DEFAULT /* check rv flag */ - be,a clear_carry - mov %g0, %i1 /* clear second rval */ - ldn [%sp + EH_LOCALS_SYSRET2], %i1 /* %i1 == sys_rval2 */ -clear_carry: - addcc %g0, %g0, %g0 /* success, clear carry flag */ - -return: - /* - * Our syscall emulation is complete. Return to the caller that - * originally invoked a system which needed emulation. Note that - * we have to load the return address that we saved earlier because - * it's possible that %g5 was overwritten by a nested call into - * this emulation library. - */ - ldn [%sp + EH_LOCALS_GREG(REG_nPC)], %g5 - jmp %g5 - restore /* delay slot */ - SET_SIZE(s10_handler) - - -#endif /* !lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_runexe.s b/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_runexe.s deleted file mode 100644 index f18b441105..0000000000 --- a/usr/src/lib/brand/solaris10/s10_brand/sparc/s10_runexe.s +++ /dev/null @@ -1,82 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -#if defined(lint) - -/*ARGSUSED*/ -void -s10_runexe(void *argv, ulong_t entry) -{ -} - -#else /* lint */ - .section ".text" - ENTRY_NP(s10_runexe) - /* - * Prepare to jump to the target program we actually want to run. - * If this program is dynamically linked then we'll be jumping to - * another copy of the linker. If it's a statically linked program - * we'll be jumping directy to it's main entry point. In any case, - * we need to reset our current state stack and register state to - * something similar to the initial process state setup by the kernel - * and documented at: - * usr/src/cmd/sgs/rtld/sparc/boot.s - * usr/src/cmd/sgs/rtld/sparcv9/boot.s - * - * Of course this is the same stack format as when this executable - * was first started, so here we'll just roll back the stack and - * frame pointers to their values when this processes first started - * execution. - * - * Our input parameters are stored in the %o? registers since we - * don't bother to allocate a new stack frame. - */ - sub %o0, CPTRSIZE + WINDOWSIZE + STACK_BIAS, %sp - clr %fp - - /* - * We also have to make sure to clear %g1 since nornally ld.so.1 will - * set that to non-zero if there is an exit function that should be - * invoked when the process is terminating. This isn't actually - * necessary if the target program we're jumping to is a dynamically - * linked program since in that case we're actually jumping to another - * copy of ld.so.1 and it will just reset %g1, but if the target - * program we're jumping to is a statically linked binary that uses - * the standard sun compiler supplied crt1.o`_start(), it will check - * to see if %g1 is set. - */ - clr %g1 - - jmp %o1 ! jump to the target processes entry point - nop - /* - * target will never return. - */ - SET_SIZE(s10_runexe) -#endif /* lint */ diff --git a/usr/src/lib/brand/solaris10/s10_brand/sparcv9/Makefile b/usr/src/lib/brand/solaris10/s10_brand/sparcv9/Makefile index 5d62c05faa..a6d7c0b1b5 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/sparcv9/Makefile +++ b/usr/src/lib/brand/solaris10/s10_brand/sparcv9/Makefile @@ -19,15 +19,16 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -ISASRCDIR = ../sparc +ISAOBJDIR = $(BRAND_SHARED)/brand/sparcv9/pics include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 +CPPFLAGS += -I$(BRAND_SHARED)/brand/sparcv9 + # # see ../Makefile.com for why we explicity make ld.so.1 our interpreter # diff --git a/usr/src/lib/brand/solaris10/s10_brand/sys/s10_misc.h b/usr/src/lib/brand/solaris10/s10_brand/sys/s10_misc.h index 972fa03d4c..d68833060f 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/sys/s10_misc.h +++ b/usr/src/lib/brand/solaris10/s10_brand/sys/s10_misc.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _S10_MISC_H @@ -30,169 +29,8 @@ extern "C" { #endif -/* - * This header file must uses _ASM defines to allow it to be included - * in assmebly source files - */ -#include -#include -#include -#include "assym.h" - -/* - * Our syscall emulation callback handler adds one argument to each - * system call, so we'll need to allocate space for one more argument - * above the maximum number of arguments that a system call can normally - * take. Also, we assume that each syscall argument is a long, ie, we - * don't support long long syscall parameters. - */ -#if defined(__sparc) -/* - * 32-bit and 64-bit sparc syscalls can take up to 8 arguments. - * 32-bit sparc indirect syscalls can take up to 9 arguments. - * Arguments 1 - 6 are passed via %o0 - %o5. - * Additional arguments are passed on the stack. - * So make space for 4 arguments on the stack. - */ -#define EH_ARGS_COUNT 4 -#elif defined(__amd64) -/* - * amd64 syscalls can take up to 8 arguments. - * Arguments 1 - 6 are passed via: %rdi, %rsi, %rdx, %r10, %r8, %r9 - * Additional arguments are passed on the stack. - * So make space for 3 arguments on the stack. - */ -#define EH_ARGS_COUNT 3 -#else /* !__sparc && !__amd64 */ -/* - * ia32 syscalls can take up to 8 arguments. - * All arguments are passed on the stack. - * So make space for 9 arguments on the stack. - */ -#define EH_ARGS_COUNT 9 -#endif /* !__sparc && !__amd64 */ - - -#define EH_ARGS_SIZE (CPTRSIZE * EH_ARGS_COUNT) -#define EH_ARGS_OFFSET(x) (STACK_BIAS + MINFRAME + (CPTRSIZE * (x))) -#define EH_LOCALS_SIZE (EH_ARGS_SIZE + SIZEOF_GREGSET_T + \ - SIZEOF_SYSRET_T + CPTRSIZE) - -#if defined(__sparc) -/* - * On sparc, all emulation callback handler variable access is done - * relative to %sp, so access offsets are positive. - */ -#define EH_LOCALS_START (STACK_BIAS + MINFRAME + EH_ARGS_SIZE) -#define EH_LOCALS_END_TGT (STACK_BIAS + MINFRAME + EH_LOCALS_SIZE) -#else /* !__sparc */ -/* - * On x86, all emulation callback handler variable access is done - * relative to %ebp/%rbp, so access offsets are negative. - */ -#define EH_LOCALS_START (-(EH_LOCALS_SIZE - \ - (STACK_BIAS + MINFRAME + EH_ARGS_SIZE))) -#define EH_LOCALS_END_TGT 0 -#endif /* !__sparc */ - -/* - * In our emulation callback handler, our stack will look like: - * ------------------------------------------------- - * %bp | long rvflag | - * | | sysret_t sysret | - * v | gregset_t gregs | - * %sp | long callback args[EH_ARGS_COUNT] | - * ------------------------------------------------- - * For ia32, use %ebp and %esp instead of %bp and %sp. - * For amd64, use %rbp and %rsp instead of %bp and %sp. - * - * Our emulation callback handler always saves enough space to hold the - * maximum number of stack arguments to a system call. This is architecture - * specific and is defined via EH_ARGS_COUNT. - */ -#define EH_LOCALS_GREGS (EH_LOCALS_START) -#define EH_LOCALS_GREG(x) (EH_LOCALS_GREGS + (SIZEOF_GREG_T * (x))) -#define EH_LOCALS_SYSRET (EH_LOCALS_GREGS + SIZEOF_GREGSET_T) -#define EH_LOCALS_SYSRET1 (EH_LOCALS_SYSRET) -#define EH_LOCALS_SYSRET2 (EH_LOCALS_SYSRET + CPTRSIZE) -#define EH_LOCALS_RVFLAG (EH_LOCALS_SYSRET + SIZEOF_SYSRET_T) -#define EH_LOCALS_END (EH_LOCALS_RVFLAG + CPTRSIZE) - -#if (EH_LOCALS_END != EH_LOCALS_END_TGT) -#error "s10_misc.h EH_LOCALS_* macros don't add up" -#endif /* (EH_LOCALS_END != EH_LOCALS_END_TGT) */ - -/* - * The second parameter of each entry in the s10_sysent_table - * contains the number of parameters and flags that describe the - * syscall return value encoding. See the block comments at the - * top of ../common/s10_brand.c for more information about the - * syscall return value flags and when they should be used. - */ -#define NARGS_MASK 0x000000FF /* Mask for syscalls argument count */ -#define RV_MASK 0x0000FF00 /* Mask for return value flags */ -#define RV_DEFAULT 0x00000100 /* syscall returns "default" values */ -#define RV_32RVAL2 0x00000200 /* syscall returns two 32-bit values */ -#define RV_64RVAL 0x00000400 /* syscall returns a 64-bit value */ - #if !defined(_ASM) -/* - * We define our own version of assert because the default one will - * try to emit a localized message. That is bad because first, we can't - * emit messages to random file descriptors, and second localizing a message - * requires allocating memory and we can't do that either. - */ -#define s10_assert(ex) (void)((ex) || \ - (_s10_abort(0, #ex, __FILE__, __LINE__), 0)) -#define s10_abort(err, msg) _s10_abort((err), (msg), __FILE__, __LINE__) - -/* - * These macros invoke a brandsys subcommand, B_S10_TRUSS_POINT, used to expose - * a call to an interpositioned syscall that would have otherwise gone - * unnoticed by truss(1) because the interpositioned system call did not call - * any system calls before returning. - */ -#define S10_TRUSS_POINT_5(rval, syscall_num, err, a0, a1, a2, a3, a4) \ - __systemcall(rval, SYS_brand + 1024, \ - B_S10_TRUSS_POINT, (syscall_num), (err), (a0), (a1), (a2), (a3), \ - (a4)) - -#define S10_TRUSS_POINT_4(rval, syscall_num, err, a0, a1, a2, a3) \ - S10_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), (a2), (a3), 0) - -#define S10_TRUSS_POINT_3(rval, syscall_num, err, a0, a1, a2) \ - S10_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), (a2), 0, 0) - -#define S10_TRUSS_POINT_2(rval, syscall_num, err, a0, a1) \ - S10_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), 0, 0, 0) - -#define S10_TRUSS_POINT_1(rval, syscall_num, err, a0) \ - S10_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), 0, 0, 0, 0) - -#define S10_TRUSS_POINT_0(rval, syscall_num, err) \ - S10_TRUSS_POINT_5(rval, (syscall_num), (err), 0, 0, 0, 0, 0) - -/* - * From s10_runexe.s - */ -extern void s10_runexe(void *, ulong_t); - -/* - * From s10_handler.s - */ -extern void s10_handler_table(void); -extern void s10_handler(void); -extern void s10_error(void); -extern void s10_success(void); - -/* - * From s10_brand.c - */ -extern void _s10_abort(int, const char *, const char *, int); -extern int s10_uucopy(const void *, void *, size_t); -extern int s10_uucopystr(const void *, void *, size_t); - /* * From s10_deleted.c */ diff --git a/usr/src/uts/common/brand/sn1/sn1_brand.c b/usr/src/uts/common/brand/sn1/sn1_brand.c index afc3cf48f3..bcca361192 100644 --- a/usr/src/uts/common/brand/sn1/sn1_brand.c +++ b/usr/src/uts/common/brand/sn1/sn1_brand.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -135,17 +134,7 @@ static struct modlinkage modlinkage = { void sn1_setbrand(proc_t *p) { - ASSERT(p->p_brand == &sn1_brand); - ASSERT(p->p_brand_data == NULL); - - /* - * We should only be called from exec(), when we know the process - * is single-threaded. - */ - ASSERT(p->p_tlist == p->p_tlist->t_forw); - - p->p_brand_data = kmem_zalloc(sizeof (sn1_proc_data_t), KM_SLEEP); - (void) sn1_initlwp(p->p_tlist->t_lwp); + brand_solaris_setbrand(p, &sn1_brand); } /* ARGSUSED */ @@ -162,213 +151,62 @@ sn1_setattr(zone_t *zone, int attr, void *buf, size_t bufsize) return (EINVAL); } -/* - * Get the address of the user-space system call handler from the user - * process and attach it to the proc structure. - */ /*ARGSUSED*/ int sn1_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6) { - sn1_proc_data_t *spd; - sn1_brand_reg_t reg; - proc_t *p = curproc; - int err; + int res; *rval = 0; - /* - * There is one operation that is suppored for non-branded - * process. B_EXEC_BRAND. This brand operaion is redundant - * since the kernel assumes a native process doing an exec - * in a branded zone is going to run a branded processes. - * hence we don't support this operation. - */ - if (cmd == B_EXEC_BRAND) - return (ENOSYS); - - /* For all other operations this must be a branded process. */ - if (p->p_brand == &native_brand) - return (ENOSYS); - - ASSERT(p->p_brand == &sn1_brand); - ASSERT(p->p_brand_data != NULL); - - spd = (sn1_proc_data_t *)p->p_brand_data; - - switch (cmd) { - case B_EXEC_NATIVE: - err = exec_common( - (char *)arg1, (const char **)arg2, (const char **)arg3, - EBA_NATIVE); - return (err); - - case B_REGISTER: - if (p->p_model == DATAMODEL_NATIVE) { - if (copyin((void *)arg1, ®, sizeof (reg)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - sn1_brand_reg32_t reg32; - - if (copyin((void *)arg1, ®32, sizeof (reg32)) != 0) - return (EFAULT); - reg.sbr_version = reg32.sbr_version; - reg.sbr_handler = (caddr_t)(uintptr_t)reg32.sbr_handler; -#endif /* _LP64 */ - } - - if (reg.sbr_version != SN1_VERSION) - return (ENOTSUP); - spd->spd_handler = reg.sbr_handler; - return (0); - case B_ELFDATA: - if (p->p_model == DATAMODEL_NATIVE) { - if (copyout(&spd->spd_elf_data, (void *)arg1, - sizeof (sn1_elf_data_t)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - sn1_elf_data32_t sed32; - - sed32.sed_phdr = spd->spd_elf_data.sed_phdr; - sed32.sed_phent = spd->spd_elf_data.sed_phent; - sed32.sed_phnum = spd->spd_elf_data.sed_phnum; - sed32.sed_entry = spd->spd_elf_data.sed_entry; - sed32.sed_base = spd->spd_elf_data.sed_base; - sed32.sed_ldentry = spd->spd_elf_data.sed_ldentry; - sed32.sed_lddata = spd->spd_elf_data.sed_lddata; - if (copyout(&sed32, (void *)arg1, sizeof (sed32)) != 0) - return (EFAULT); -#endif /* _LP64 */ - } - return (0); - } + res = brand_solaris_cmd(cmd, arg1, arg2, arg3, &sn1_brand, SN1_VERSION); + if (res >= 0) + return (res); return (EINVAL); } -/* - * Copy the per-process brand data from a parent proc to a child. - */ void sn1_copy_procdata(proc_t *child, proc_t *parent) { - sn1_proc_data_t *spd; - - ASSERT(parent->p_brand == &sn1_brand); - ASSERT(child->p_brand == &sn1_brand); - ASSERT(parent->p_brand_data != NULL); - ASSERT(child->p_brand_data == NULL); - - /* Just duplicate all the proc data of the parent for the child */ - spd = kmem_alloc(sizeof (sn1_proc_data_t), KM_SLEEP); - bcopy(parent->p_brand_data, spd, sizeof (sn1_proc_data_t)); - child->p_brand_data = spd; + brand_solaris_copy_procdata(child, parent, &sn1_brand); } -/*ARGSUSED*/ void sn1_proc_exit(struct proc *p, klwp_t *l) { - ASSERT(p->p_brand == &sn1_brand); - ASSERT(p->p_brand_data != NULL); - - /* - * We should only be called from proc_exit(), when we know that - * process is single-threaded. - */ - ASSERT(p->p_tlist == p->p_tlist->t_forw); - - /* upon exit, free our lwp brand data */ - (void) sn1_freelwp(ttolwp(curthread)); - - /* upon exit, free our proc brand data */ - kmem_free(p->p_brand_data, sizeof (sn1_proc_data_t)); - p->p_brand_data = NULL; + brand_solaris_proc_exit(p, l, &sn1_brand); } void sn1_exec() { - sn1_proc_data_t *spd = curproc->p_brand_data; - - ASSERT(curproc->p_brand == &sn1_brand); - ASSERT(curproc->p_brand_data != NULL); - ASSERT(ttolwp(curthread)->lwp_brand != NULL); - - /* - * We should only be called from exec(), when we know the process - * is single-threaded. - */ - ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw); - - /* Upon exec, reset our lwp brand data. */ - (void) sn1_freelwp(ttolwp(curthread)); - (void) sn1_initlwp(ttolwp(curthread)); - - /* - * Upon exec, reset all the proc brand data, except for the elf - * data associated with the executable we are exec'ing. - */ - spd->spd_handler = NULL; + brand_solaris_exec(&sn1_brand); } -/*ARGSUSED*/ int sn1_initlwp(klwp_t *l) { - ASSERT(l->lwp_procp->p_brand == &sn1_brand); - ASSERT(l->lwp_procp->p_brand_data != NULL); - ASSERT(l->lwp_brand == NULL); - l->lwp_brand = (void *)-1; - return (0); + return (brand_solaris_initlwp(l, &sn1_brand)); } -/*ARGSUSED*/ void sn1_forklwp(klwp_t *p, klwp_t *c) { - ASSERT(p->lwp_procp->p_brand == &sn1_brand); - ASSERT(c->lwp_procp->p_brand == &sn1_brand); - - ASSERT(p->lwp_procp->p_brand_data != NULL); - ASSERT(c->lwp_procp->p_brand_data != NULL); - - /* Both LWPs have already had been initialized via sn1_initlwp() */ - ASSERT(p->lwp_brand != NULL); - ASSERT(c->lwp_brand != NULL); + brand_solaris_forklwp(p, c, &sn1_brand); } -/*ARGSUSED*/ void sn1_freelwp(klwp_t *l) { - ASSERT(l->lwp_procp->p_brand == &sn1_brand); - ASSERT(l->lwp_procp->p_brand_data != NULL); - ASSERT(l->lwp_brand != NULL); - l->lwp_brand = NULL; + brand_solaris_freelwp(l, &sn1_brand); } -/*ARGSUSED*/ void sn1_lwpexit(klwp_t *l) { - proc_t *p = l->lwp_procp; - - ASSERT(l->lwp_procp->p_brand == &sn1_brand); - ASSERT(l->lwp_procp->p_brand_data != NULL); - ASSERT(l->lwp_brand != NULL); - - /* - * We should never be called for the last thread in a process. - * (That case is handled by sn1_proc_exit().) There for this lwp - * must be exiting from a multi-threaded process. - */ - ASSERT(p->p_tlist != p->p_tlist->t_forw); - - l->lwp_brand = NULL; + brand_solaris_lwpexit(l, &sn1_brand); } /*ARGSUSED*/ @@ -383,384 +221,16 @@ sn1_init_brand_data(zone_t *zone) { } -#if defined(_LP64) -static void -Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst) -{ - bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident)); - dst->e_type = src->e_type; - dst->e_machine = src->e_machine; - dst->e_version = src->e_version; - dst->e_entry = src->e_entry; - dst->e_phoff = src->e_phoff; - dst->e_shoff = src->e_shoff; - dst->e_flags = src->e_flags; - dst->e_ehsize = src->e_ehsize; - dst->e_phentsize = src->e_phentsize; - dst->e_phnum = src->e_phnum; - dst->e_shentsize = src->e_shentsize; - dst->e_shnum = src->e_shnum; - dst->e_shstrndx = src->e_shstrndx; -} -#endif /* _LP64 */ - int sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred, int brand_action) { - vnode_t *nvp; - Ehdr ehdr; - Addr uphdr_vaddr; - intptr_t voffset; - int interp; - int i, err; - struct execenv env; - struct user *up = PTOU(curproc); - sn1_proc_data_t *spd; - sn1_elf_data_t sed, *sedp; - char *linker; - uintptr_t lddata; /* lddata of executable's linker */ - - ASSERT(curproc->p_brand == &sn1_brand); - ASSERT(curproc->p_brand_data != NULL); - - spd = (sn1_proc_data_t *)curproc->p_brand_data; - sedp = &spd->spd_elf_data; - - args->brandname = SN1_BRANDNAME; - - /* - * We will exec the brand library and then map in the target - * application and (optionally) the brand's default linker. - */ - if (args->to_model == DATAMODEL_NATIVE) { - args->emulator = SN1_LIB; - linker = SN1_LINKER; -#if defined(_LP64) - } else { - args->emulator = SN1_LIB32; - linker = SN1_LINKER32; -#endif /* _LP64 */ - } - - if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW, NULLVPP, - &nvp)) != 0) { - uprintf("%s: not found.", args->emulator); - return (err); - } - - if (args->to_model == DATAMODEL_NATIVE) { - err = elfexec(nvp, uap, args, idatap, level + 1, execsz, - setid, exec_file, cred, brand_action); -#if defined(_LP64) - } else { - err = elf32exec(nvp, uap, args, idatap, level + 1, execsz, - setid, exec_file, cred, brand_action); -#endif /* _LP64 */ - } - VN_RELE(nvp); - if (err != 0) - return (err); - - /* - * The u_auxv vectors are set up by elfexec to point to the brand - * emulation library and linker. Save these so they can be copied to - * the specific brand aux vectors. - */ - bzero(&sed, sizeof (sed)); - for (i = 0; i < __KERN_NAUXV_IMPL; i++) { - switch (up->u_auxv[i].a_type) { - case AT_SUN_LDDATA: - sed.sed_lddata = up->u_auxv[i].a_un.a_val; - break; - case AT_BASE: - sed.sed_base = up->u_auxv[i].a_un.a_val; - break; - case AT_ENTRY: - sed.sed_entry = up->u_auxv[i].a_un.a_val; - break; - case AT_PHDR: - sed.sed_phdr = up->u_auxv[i].a_un.a_val; - break; - case AT_PHENT: - sed.sed_phent = up->u_auxv[i].a_un.a_val; - break; - case AT_PHNUM: - sed.sed_phnum = up->u_auxv[i].a_un.a_val; - break; - default: - break; - } - } - /* Make sure the emulator has an entry point */ - ASSERT(sed.sed_entry != NULL); - ASSERT(sed.sed_phdr != NULL); - - bzero(&env, sizeof (env)); - if (args->to_model == DATAMODEL_NATIVE) { - err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr, &voffset, - exec_file, &interp, &env.ex_bssbase, &env.ex_brkbase, - &env.ex_brksize, NULL); -#if defined(_LP64) - } else { - Elf32_Ehdr ehdr32; - Elf32_Addr uphdr_vaddr32; - err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32, - &voffset, exec_file, &interp, &env.ex_bssbase, - &env.ex_brkbase, &env.ex_brksize, NULL); - Ehdr32to64(&ehdr32, &ehdr); - if (uphdr_vaddr32 == (Elf32_Addr)-1) - uphdr_vaddr = (Addr)-1; - else - uphdr_vaddr = uphdr_vaddr32; -#endif /* _LP64 */ - } - if (err != 0) - return (err); - - /* - * Save off the important properties of the executable. The brand - * library will ask us for this data later, when it is initializing - * and getting ready to transfer control to the brand application. - */ - if (uphdr_vaddr == (Addr)-1) - sedp->sed_phdr = voffset + ehdr.e_phoff; - else - sedp->sed_phdr = voffset + uphdr_vaddr; - sedp->sed_entry = voffset + ehdr.e_entry; - sedp->sed_phent = ehdr.e_phentsize; - sedp->sed_phnum = ehdr.e_phnum; - - if (interp) { - if (ehdr.e_type == ET_DYN) { - /* - * This is a shared object executable, so we need to - * pick a reasonable place to put the heap. Just don't - * use the first page. - */ - env.ex_brkbase = (caddr_t)PAGESIZE; - env.ex_bssbase = (caddr_t)PAGESIZE; - } - - /* - * If the program needs an interpreter (most do), map it in and - * store relevant information about it in the aux vector, where - * the brand library can find it. - */ - if ((err = lookupname(linker, UIO_SYSSPACE, - FOLLOW, NULLVPP, &nvp)) != 0) { - uprintf("%s: not found.", SN1_LINKER); - return (err); - } - if (args->to_model == DATAMODEL_NATIVE) { - err = mapexec_brand(nvp, args, &ehdr, - &uphdr_vaddr, &voffset, exec_file, &interp, - NULL, NULL, NULL, &lddata); -#if defined(_LP64) - } else { - Elf32_Ehdr ehdr32; - Elf32_Addr uphdr_vaddr32; - err = mapexec32_brand(nvp, args, &ehdr32, - &uphdr_vaddr32, &voffset, exec_file, &interp, - NULL, NULL, NULL, &lddata); - Ehdr32to64(&ehdr32, &ehdr); - if (uphdr_vaddr32 == (Elf32_Addr)-1) - uphdr_vaddr = (Addr)-1; - else - uphdr_vaddr = uphdr_vaddr32; -#endif /* _LP64 */ - } - VN_RELE(nvp); - if (err != 0) - return (err); - - /* - * Now that we know the base address of the brand's linker, - * place it in the aux vector. - */ - sedp->sed_base = voffset; - sedp->sed_ldentry = voffset + ehdr.e_entry; - sedp->sed_lddata = voffset + lddata; - } else { - /* - * This program has no interpreter. The brand library will - * jump to the address in the AT_SUN_BRAND_LDENTRY aux vector, - * so in this case, put the entry point of the main executable - * there. - */ - if (ehdr.e_type == ET_EXEC) { - /* - * An executable with no interpreter, this must be a - * statically linked executable, which means we loaded - * it at the address specified in the elf header, in - * which case the e_entry field of the elf header is an - * absolute address. - */ - sedp->sed_ldentry = ehdr.e_entry; - sedp->sed_entry = ehdr.e_entry; - sedp->sed_lddata = NULL; - sedp->sed_base = NULL; - } else { - /* - * A shared object with no interpreter, we use the - * calculated address from above. - */ - sedp->sed_ldentry = sedp->sed_entry; - sedp->sed_entry = NULL; - sedp->sed_phdr = NULL; - sedp->sed_phent = NULL; - sedp->sed_phnum = NULL; - sedp->sed_lddata = NULL; - sedp->sed_base = voffset; - - if (ehdr.e_type == ET_DYN) { - /* - * Delay setting the brkbase until the first - * call to brk(); see elfexec() for details. - */ - env.ex_bssbase = (caddr_t)0; - env.ex_brkbase = (caddr_t)0; - env.ex_brksize = 0; - } - } - } - - env.ex_magic = elfmagic; - env.ex_vp = vp; - setexecenv(&env); - - /* - * It's time to manipulate the process aux vectors. First - * we need to update the AT_SUN_AUXFLAGS aux vector to set - * the AF_SUN_NOPLM flag. - */ - if (args->to_model == DATAMODEL_NATIVE) { - auxv_t auxflags_auxv; - - if (copyin(args->auxp_auxflags, &auxflags_auxv, - sizeof (auxflags_auxv)) != 0) - return (EFAULT); - - ASSERT(auxflags_auxv.a_type == AT_SUN_AUXFLAGS); - auxflags_auxv.a_un.a_val |= AF_SUN_NOPLM; - if (copyout(&auxflags_auxv, args->auxp_auxflags, - sizeof (auxflags_auxv)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - auxv32_t auxflags_auxv32; - - if (copyin(args->auxp_auxflags, &auxflags_auxv32, - sizeof (auxflags_auxv32)) != 0) - return (EFAULT); - - ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS); - auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM; - if (copyout(&auxflags_auxv32, args->auxp_auxflags, - sizeof (auxflags_auxv32)) != 0) - return (EFAULT); -#endif /* _LP64 */ - } - - /* Second, copy out the brand specific aux vectors. */ - if (args->to_model == DATAMODEL_NATIVE) { - auxv_t sn1_auxv[] = { - { AT_SUN_BRAND_AUX1, 0 }, - { AT_SUN_BRAND_AUX2, 0 }, - { AT_SUN_BRAND_AUX3, 0 } - }; - - ASSERT(sn1_auxv[0].a_type == AT_SUN_BRAND_SN1_LDDATA); - sn1_auxv[0].a_un.a_val = sed.sed_lddata; - - if (copyout(&sn1_auxv, args->auxp_brand, - sizeof (sn1_auxv)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - auxv32_t sn1_auxv32[] = { - { AT_SUN_BRAND_AUX1, 0 }, - { AT_SUN_BRAND_AUX2, 0 }, - { AT_SUN_BRAND_AUX3, 0 } - }; - - ASSERT(sn1_auxv32[0].a_type == AT_SUN_BRAND_SN1_LDDATA); - sn1_auxv32[0].a_un.a_val = (uint32_t)sed.sed_lddata; - if (copyout(&sn1_auxv32, args->auxp_brand, - sizeof (sn1_auxv32)) != 0) - return (EFAULT); -#endif /* _LP64 */ - } - - /* - * Third, the the /proc aux vectors set up by elfexec() point to brand - * emulation library and it's linker. Copy these to the /proc brand - * specific aux vector, and update the regular /proc aux vectors to - * point to the executable (and it's linker). This will enable - * debuggers to access the executable via the usual /proc or elf notes - * aux vectors. - * - * The brand emulation library's linker will get it's aux vectors off - * the stack, and then update the stack with the executable's aux - * vectors before jumping to the executable's linker. - * - * Debugging the brand emulation library must be done from - * the global zone, where the librtld_db module knows how to fetch the - * brand specific aux vectors to access the brand emulation libraries - * linker. - */ - for (i = 0; i < __KERN_NAUXV_IMPL; i++) { - ulong_t val; - - switch (up->u_auxv[i].a_type) { - case AT_SUN_BRAND_SN1_LDDATA: - up->u_auxv[i].a_un.a_val = sed.sed_lddata; - continue; - case AT_BASE: - val = sedp->sed_base; - break; - case AT_ENTRY: - val = sedp->sed_entry; - break; - case AT_PHDR: - val = sedp->sed_phdr; - break; - case AT_PHENT: - val = sedp->sed_phent; - break; - case AT_PHNUM: - val = sedp->sed_phnum; - break; - case AT_SUN_LDDATA: - val = sedp->sed_lddata; - break; - default: - continue; - } - - up->u_auxv[i].a_un.a_val = val; - if (val == NULL) { - /* Hide the entry for static binaries */ - up->u_auxv[i].a_type = AT_IGNORE; - } - } - - /* - * The last thing we do here is clear spd->spd_handler. This is - * important because if we're already a branded process and if this - * exec succeeds, there is a window between when the exec() first - * returns to the userland of the new process and when our brand - * library get's initialized, during which we don't want system - * calls to be re-directed to our brand library since it hasn't - * been initialized yet. - */ - spd->spd_handler = NULL; - - return (0); + return (brand_solaris_elfexec(vp, uap, args, idatap, level, execsz, + setid, exec_file, cred, brand_action, &sn1_brand, SN1_BRANDNAME, + SN1_LIB, SN1_LIB32, SN1_LINKER, SN1_LINKER32)); } - int _init(void) { @@ -804,21 +274,6 @@ _info(struct modinfo *modinfop) int _fini(void) { - int err; - - /* - * If there are any zones using this brand, we can't allow it to be - * unloaded. - */ - if (brand_zone_count(&sn1_brand)) - return (EBUSY); - - kmem_free(sn1_emulation_table, NSYSCALL); - sn1_emulation_table = NULL; - - err = mod_remove(&modlinkage); - if (err) - cmn_err(CE_WARN, "Couldn't unload sn1 brand module"); - - return (err); + return (brand_solaris_fini(&sn1_emulation_table, &modlinkage, + &sn1_brand)); } diff --git a/usr/src/uts/common/brand/sn1/sn1_brand.h b/usr/src/uts/common/brand/sn1/sn1_brand.h index 01c3b6f401..b487745e21 100644 --- a/usr/src/uts/common/brand/sn1/sn1_brand.h +++ b/usr/src/uts/common/brand/sn1/sn1_brand.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SN1_BRAND_H @@ -30,21 +29,20 @@ extern "C" { #endif -#include +#include #define SN1_BRANDNAME "sn1" #define SN1_VERSION_1 1 #define SN1_VERSION SN1_VERSION_1 -#define SN1_NATIVE_DIR "/.SUNWnative/" #define SN1_LIB_NAME "sn1_brand.so.1" #define SN1_LINKER_NAME "ld.so.1" -#define SN1_LIB32 SN1_NATIVE_DIR "usr/lib/" SN1_LIB_NAME +#define SN1_LIB32 BRAND_NATIVE_DIR "usr/lib/" SN1_LIB_NAME #define SN1_LINKER32 "/lib/" SN1_LINKER_NAME -#define SN1_LIB64 SN1_NATIVE_DIR "usr/lib/64/" SN1_LIB_NAME +#define SN1_LIB64 BRAND_NATIVE_DIR "usr/lib/64/" SN1_LIB_NAME #define SN1_LINKER64 "/lib/64/" SN1_LINKER_NAME #if defined(_LP64) @@ -55,58 +53,7 @@ extern "C" { #define SN1_LINKER SN1_LINKER32 #endif /* !_LP64 */ -/* - * Aux vector containing lddata pointer of brand library linkmap. - * Used by lx_librtld_db. - */ -#define AT_SUN_BRAND_SN1_LDDATA AT_SUN_BRAND_AUX1 - -/* - * Information needed by the sn1 library to launch an executable. - */ -typedef struct sn1_elf_data { - ulong_t sed_phdr; - ulong_t sed_phent; - ulong_t sed_phnum; - ulong_t sed_entry; - ulong_t sed_base; - ulong_t sed_ldentry; - ulong_t sed_lddata; -} sn1_elf_data_t; - -/* - * Structure used to register a branded processes - */ -typedef struct sn1_brand_reg { - uint_t sbr_version; /* version number */ - caddr_t sbr_handler; /* base address of handler */ -} sn1_brand_reg_t; - #if defined(_KERNEL) -#if defined(_SYSCALL32) -typedef struct sn1_elf_data32 { - uint32_t sed_phdr; - uint32_t sed_phent; - uint32_t sed_phnum; - uint32_t sed_entry; - uint32_t sed_base; - uint32_t sed_ldentry; - uint32_t sed_lddata; -} sn1_elf_data32_t; - -typedef struct sn1_brand_reg32 { - uint32_t sbr_version; /* version number */ - caddr32_t sbr_handler; /* base address of handler */ -} sn1_brand_reg32_t; -#endif /* _SYSCALL32 */ - -/* - * Information associated with all sn1 branded processes - */ -typedef struct sn1_proc_data { - caddr_t spd_handler; /* address of user-space handler */ - sn1_elf_data_t spd_elf_data; /* ELF data for sn1 application */ -} sn1_proc_data_t; void sn1_brand_syscall_callback(void); void sn1_brand_syscall32_callback(void); diff --git a/usr/src/uts/common/brand/sn1/sn1_offsets.in b/usr/src/uts/common/brand/sn1/sn1_offsets.in deleted file mode 100644 index 0e531f26fd..0000000000 --- a/usr/src/uts/common/brand/sn1/sn1_offsets.in +++ /dev/null @@ -1,30 +0,0 @@ -\ -\ Copyright 2008 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 (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 -\ -\ Sn1 brand structure offset for use in assembly code. -\ - -#include - -sn1_proc_data_t - spd_handler diff --git a/usr/src/uts/common/brand/solaris10/s10_brand.c b/usr/src/uts/common/brand/solaris10/s10_brand.c index aace5abe3a..0e8b91f2dd 100644 --- a/usr/src/uts/common/brand/solaris10/s10_brand.c +++ b/usr/src/uts/common/brand/solaris10/s10_brand.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -140,17 +139,7 @@ static struct modlinkage modlinkage = { void s10_setbrand(proc_t *p) { - ASSERT(p->p_brand == &s10_brand); - ASSERT(p->p_brand_data == NULL); - - /* - * We should only be called from exec(), when we know the process - * is single-threaded. - */ - ASSERT(p->p_tlist == p->p_tlist->t_forw); - - p->p_brand_data = kmem_zalloc(sizeof (s10_proc_data_t), KM_SLEEP); - (void) s10_initlwp(p->p_tlist->t_lwp); + brand_solaris_setbrand(p, &s10_brand); } /*ARGSUSED*/ @@ -223,7 +212,7 @@ s10_native() char *args_new, *comm_new, *p; int len; - len = sizeof (S10_NATIVE_LINKER32 " ") - 1; + len = sizeof (BRAND_NATIVE_LINKER32 " ") - 1; /* * Make sure that the process' interpreter is the native dynamic linker. @@ -236,9 +225,10 @@ s10_native() */ if (strcmp(up->u_comm, S10_LINKER_NAME) != 0) return (0); - if (strncmp(up->u_psargs, S10_NATIVE_LINKER64 " /", len + 4) == 0) + if (strncmp(up->u_psargs, BRAND_NATIVE_LINKER64 " /", len + 4) == 0) len += 3; /* to account for "/64" in the path */ - else if (strncmp(up->u_psargs, S10_NATIVE_LINKER32 " /", len + 1) != 0) + else if (strncmp(up->u_psargs, BRAND_NATIVE_LINKER32 " /", len + 1) + != 0) return (0); args_new = strdup(&up->u_psargs[len]); @@ -263,92 +253,24 @@ s10_native() return (0); } -/* - * Get the address of the user-space system call handler from the user - * process and attach it to the proc structure. - */ /*ARGSUSED*/ int s10_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6) { - s10_proc_data_t *spd; - s10_brand_reg_t reg; - proc_t *p = curproc; - int err; + proc_t *p = curproc; + int res; *rval = 0; - /* - * B_EXEC_BRAND is redundant - * since the kernel assumes a native process doing an exec - * in a branded zone is going to run a branded processes. - * hence we don't support this operation. - */ - if (cmd == B_EXEC_BRAND) - return (ENOSYS); - if (cmd == B_S10_NATIVE) return (s10_native()); - /* For all other operations this must be a branded process. */ - if (p->p_brand == &native_brand) - return (ENOSYS); - - ASSERT(p->p_brand == &s10_brand); - ASSERT(p->p_brand_data != NULL); - - spd = (s10_proc_data_t *)p->p_brand_data; - - switch (cmd) { - case B_EXEC_NATIVE: - err = exec_common( - (char *)arg1, (const char **)arg2, (const char **)arg3, - EBA_NATIVE); - return (err); - - case B_REGISTER: - if (p->p_model == DATAMODEL_NATIVE) { - if (copyin((void *)arg1, ®, sizeof (reg)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - s10_brand_reg32_t reg32; - - if (copyin((void *)arg1, ®32, sizeof (reg32)) != 0) - return (EFAULT); - reg.sbr_version = reg32.sbr_version; - reg.sbr_handler = (caddr_t)(uintptr_t)reg32.sbr_handler; -#endif /* _LP64 */ - } - - if (reg.sbr_version != S10_VERSION) - return (ENOTSUP); - spd->spd_handler = reg.sbr_handler; - return (0); - - case B_ELFDATA: - if (p->p_model == DATAMODEL_NATIVE) { - if (copyout(&spd->spd_elf_data, (void *)arg1, - sizeof (s10_elf_data_t)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - s10_elf_data32_t sed32; - - sed32.sed_phdr = spd->spd_elf_data.sed_phdr; - sed32.sed_phent = spd->spd_elf_data.sed_phent; - sed32.sed_phnum = spd->spd_elf_data.sed_phnum; - sed32.sed_entry = spd->spd_elf_data.sed_entry; - sed32.sed_base = spd->spd_elf_data.sed_base; - sed32.sed_ldentry = spd->spd_elf_data.sed_ldentry; - sed32.sed_lddata = spd->spd_elf_data.sed_lddata; - if (copyout(&sed32, (void *)arg1, sizeof (sed32)) != 0) - return (EFAULT); -#endif /* _LP64 */ - } - return (0); + res = brand_solaris_cmd(cmd, arg1, arg2, arg3, &s10_brand, S10_VERSION); + if (res >= 0) + return (res); + switch ((cmd)) { case B_S10_PIDINFO: /* * The s10 brand needs to be able to get the pid of the @@ -367,23 +289,6 @@ s10_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2, return (EFAULT); return (0); - case B_S10_TRUSS_POINT: - /* - * This subcommand exists so that we can see truss output - * from interposed system calls that return without first - * calling any other system call, meaning they would be - * invisible to truss(1). - * - * If the second argument is set non-zero, set errno to that - * value as well. - * - * Arguments are: - * - * arg1: syscall number - * arg2: errno - */ - return ((arg2 == 0) ? 0 : set_errno((uint_t)arg2)); - case B_S10_ISFDXATTRDIR: { /* * This subcommand enables the userland brand emulation library @@ -418,96 +323,34 @@ s10_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2, return (EINVAL); } -/* - * Copy the per-process brand data from a parent proc to a child. - */ void s10_copy_procdata(proc_t *child, proc_t *parent) { - s10_proc_data_t *spd; - - ASSERT(parent->p_brand == &s10_brand); - ASSERT(child->p_brand == &s10_brand); - ASSERT(parent->p_brand_data != NULL); - ASSERT(child->p_brand_data == NULL); - - /* Just duplicate all the proc data of the parent for the child */ - spd = kmem_alloc(sizeof (s10_proc_data_t), KM_SLEEP); - bcopy(parent->p_brand_data, spd, sizeof (s10_proc_data_t)); - child->p_brand_data = spd; + brand_solaris_copy_procdata(child, parent, &s10_brand); } -/*ARGSUSED*/ void s10_proc_exit(struct proc *p, klwp_t *l) { - ASSERT(p->p_brand == &s10_brand); - ASSERT(p->p_brand_data != NULL); - - /* - * We should only be called from proc_exit(), when we know that - * process is single-threaded. - */ - ASSERT(p->p_tlist == p->p_tlist->t_forw); - - /* upon exit, free our lwp brand data */ - (void) s10_freelwp(ttolwp(curthread)); - - /* upon exit, free our proc brand data */ - kmem_free(p->p_brand_data, sizeof (s10_proc_data_t)); - p->p_brand_data = NULL; + brand_solaris_proc_exit(p, l, &s10_brand); } void s10_exec() { - s10_proc_data_t *spd = curproc->p_brand_data; - - ASSERT(curproc->p_brand == &s10_brand); - ASSERT(curproc->p_brand_data != NULL); - ASSERT(ttolwp(curthread)->lwp_brand != NULL); - - /* - * We should only be called from exec(), when we know the process - * is single-threaded. - */ - ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw); - - /* Upon exec, reset our lwp brand data. */ - (void) s10_freelwp(ttolwp(curthread)); - (void) s10_initlwp(ttolwp(curthread)); - - /* - * Upon exec, reset all the proc brand data, except for the elf - * data associated with the executable we are exec'ing. - */ - spd->spd_handler = NULL; + brand_solaris_exec(&s10_brand); } -/*ARGSUSED*/ int s10_initlwp(klwp_t *l) { - ASSERT(l->lwp_procp->p_brand == &s10_brand); - ASSERT(l->lwp_procp->p_brand_data != NULL); - ASSERT(l->lwp_brand == NULL); - l->lwp_brand = (void *)-1; - return (0); + return (brand_solaris_initlwp(l, &s10_brand)); } -/*ARGSUSED*/ void s10_forklwp(klwp_t *p, klwp_t *c) { - ASSERT(p->lwp_procp->p_brand == &s10_brand); - ASSERT(c->lwp_procp->p_brand == &s10_brand); - - ASSERT(p->lwp_procp->p_brand_data != NULL); - ASSERT(c->lwp_procp->p_brand_data != NULL); - - /* Both LWPs have already had been initialized via s10_initlwp() */ - ASSERT(p->lwp_brand != NULL); - ASSERT(c->lwp_brand != NULL); + brand_solaris_forklwp(p, c, &s10_brand); #ifdef __amd64 /* @@ -522,32 +365,16 @@ s10_forklwp(klwp_t *p, klwp_t *c) #endif /* __amd64 */ } -/*ARGSUSED*/ void s10_freelwp(klwp_t *l) { - ASSERT(l->lwp_procp->p_brand == &s10_brand); - ASSERT(l->lwp_procp->p_brand_data != NULL); - ASSERT(l->lwp_brand != NULL); - l->lwp_brand = NULL; + brand_solaris_freelwp(l, &s10_brand); } -/*ARGSUSED*/ void s10_lwpexit(klwp_t *l) { - ASSERT(l->lwp_procp->p_brand == &s10_brand); - ASSERT(l->lwp_procp->p_brand_data != NULL); - ASSERT(l->lwp_brand != NULL); - - /* - * We should never be called for the last thread in a process. - * (That case is handled by s10_proc_exit().) There for this lwp - * must be exiting from a multi-threaded process. - */ - ASSERT(l->lwp_procp->p_tlist != l->lwp_procp->p_tlist->t_forw); - - l->lwp_brand = NULL; + brand_solaris_lwpexit(l, &s10_brand); } void @@ -564,381 +391,14 @@ s10_init_brand_data(zone_t *zone) zone->zone_brand_data = kmem_zalloc(sizeof (s10_zone_data_t), KM_SLEEP); } -#if defined(_LP64) -static void -Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst) -{ - bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident)); - dst->e_type = src->e_type; - dst->e_machine = src->e_machine; - dst->e_version = src->e_version; - dst->e_entry = src->e_entry; - dst->e_phoff = src->e_phoff; - dst->e_shoff = src->e_shoff; - dst->e_flags = src->e_flags; - dst->e_ehsize = src->e_ehsize; - dst->e_phentsize = src->e_phentsize; - dst->e_phnum = src->e_phnum; - dst->e_shentsize = src->e_shentsize; - dst->e_shnum = src->e_shnum; - dst->e_shstrndx = src->e_shstrndx; -} -#endif /* _LP64 */ - int s10_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred, int brand_action) { - vnode_t *nvp; - Ehdr ehdr; - Addr uphdr_vaddr; - intptr_t voffset; - int interp; - int i, err; - struct execenv env; - struct user *up = PTOU(curproc); - s10_proc_data_t *spd; - s10_elf_data_t sed, *sedp; - char *linker; - uintptr_t lddata; /* lddata of executable's linker */ - - ASSERT(curproc->p_brand == &s10_brand); - ASSERT(curproc->p_brand_data != NULL); - - spd = (s10_proc_data_t *)curproc->p_brand_data; - sedp = &spd->spd_elf_data; - - args->brandname = S10_BRANDNAME; - - /* - * We will exec the brand library and then map in the target - * application and (optionally) the brand's default linker. - */ - if (args->to_model == DATAMODEL_NATIVE) { - args->emulator = S10_LIB; - linker = S10_LINKER; -#if defined(_LP64) - } else { - args->emulator = S10_LIB32; - linker = S10_LINKER32; -#endif /* _LP64 */ - } - - if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW, NULLVPP, - &nvp)) != 0) { - uprintf("%s: not found.", args->emulator); - return (err); - } - - if (args->to_model == DATAMODEL_NATIVE) { - err = elfexec(nvp, uap, args, idatap, level + 1, execsz, - setid, exec_file, cred, brand_action); -#if defined(_LP64) - } else { - err = elf32exec(nvp, uap, args, idatap, level + 1, execsz, - setid, exec_file, cred, brand_action); -#endif /* _LP64 */ - } - VN_RELE(nvp); - if (err != 0) - return (err); - - /* - * The u_auxv vectors are set up by elfexec to point to the brand - * emulation library and linker. Save these so they can be copied to - * the specific brand aux vectors. - */ - bzero(&sed, sizeof (sed)); - for (i = 0; i < __KERN_NAUXV_IMPL; i++) { - switch (up->u_auxv[i].a_type) { - case AT_SUN_LDDATA: - sed.sed_lddata = up->u_auxv[i].a_un.a_val; - break; - case AT_BASE: - sed.sed_base = up->u_auxv[i].a_un.a_val; - break; - case AT_ENTRY: - sed.sed_entry = up->u_auxv[i].a_un.a_val; - break; - case AT_PHDR: - sed.sed_phdr = up->u_auxv[i].a_un.a_val; - break; - case AT_PHENT: - sed.sed_phent = up->u_auxv[i].a_un.a_val; - break; - case AT_PHNUM: - sed.sed_phnum = up->u_auxv[i].a_un.a_val; - break; - default: - break; - } - } - /* Make sure the emulator has an entry point */ - ASSERT(sed.sed_entry != NULL); - ASSERT(sed.sed_phdr != NULL); - - bzero(&env, sizeof (env)); - if (args->to_model == DATAMODEL_NATIVE) { - err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr, &voffset, - exec_file, &interp, &env.ex_bssbase, &env.ex_brkbase, - &env.ex_brksize, NULL); -#if defined(_LP64) - } else { - Elf32_Ehdr ehdr32; - Elf32_Addr uphdr_vaddr32; - err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32, - &voffset, exec_file, &interp, &env.ex_bssbase, - &env.ex_brkbase, &env.ex_brksize, NULL); - Ehdr32to64(&ehdr32, &ehdr); - if (uphdr_vaddr32 == (Elf32_Addr)-1) - uphdr_vaddr = (Addr)-1; - else - uphdr_vaddr = uphdr_vaddr32; -#endif /* _LP64 */ - } - if (err != 0) - return (err); - - /* - * Save off the important properties of the executable. The brand - * library will ask us for this data later, when it is initializing - * and getting ready to transfer control to the brand application. - */ - if (uphdr_vaddr == (Addr)-1) - sedp->sed_phdr = voffset + ehdr.e_phoff; - else - sedp->sed_phdr = voffset + uphdr_vaddr; - sedp->sed_entry = voffset + ehdr.e_entry; - sedp->sed_phent = ehdr.e_phentsize; - sedp->sed_phnum = ehdr.e_phnum; - - if (interp) { - if (ehdr.e_type == ET_DYN) { - /* - * This is a shared object executable, so we need to - * pick a reasonable place to put the heap. Just don't - * use the first page. - */ - env.ex_brkbase = (caddr_t)PAGESIZE; - env.ex_bssbase = (caddr_t)PAGESIZE; - } - - /* - * If the program needs an interpreter (most do), map it in and - * store relevant information about it in the aux vector, where - * the brand library can find it. - */ - if ((err = lookupname(linker, UIO_SYSSPACE, - FOLLOW, NULLVPP, &nvp)) != 0) { - uprintf("%s: not found.", S10_LINKER); - return (err); - } - if (args->to_model == DATAMODEL_NATIVE) { - err = mapexec_brand(nvp, args, &ehdr, - &uphdr_vaddr, &voffset, exec_file, &interp, - NULL, NULL, NULL, &lddata); -#if defined(_LP64) - } else { - Elf32_Ehdr ehdr32; - Elf32_Addr uphdr_vaddr32; - err = mapexec32_brand(nvp, args, &ehdr32, - &uphdr_vaddr32, &voffset, exec_file, &interp, - NULL, NULL, NULL, &lddata); - Ehdr32to64(&ehdr32, &ehdr); - if (uphdr_vaddr32 == (Elf32_Addr)-1) - uphdr_vaddr = (Addr)-1; - else - uphdr_vaddr = uphdr_vaddr32; -#endif /* _LP64 */ - } - VN_RELE(nvp); - if (err != 0) - return (err); - - /* - * Now that we know the base address of the brand's linker, - * place it in the aux vector. - */ - sedp->sed_base = voffset; - sedp->sed_ldentry = voffset + ehdr.e_entry; - sedp->sed_lddata = voffset + lddata; - } else { - /* - * This program has no interpreter. The brand library will - * jump to the address in the AT_SUN_BRAND_LDENTRY aux vector, - * so in this case, put the entry point of the main executable - * there. - */ - if (ehdr.e_type == ET_EXEC) { - /* - * An executable with no interpreter, this must be a - * statically linked executable, which means we loaded - * it at the address specified in the elf header, in - * which case the e_entry field of the elf header is an - * absolute address. - */ - sedp->sed_ldentry = ehdr.e_entry; - sedp->sed_entry = ehdr.e_entry; - sedp->sed_lddata = NULL; - sedp->sed_base = NULL; - } else { - /* - * A shared object with no interpreter, we use the - * calculated address from above. - */ - sedp->sed_ldentry = sedp->sed_entry; - sedp->sed_entry = NULL; - sedp->sed_phdr = NULL; - sedp->sed_phent = NULL; - sedp->sed_phnum = NULL; - sedp->sed_lddata = NULL; - sedp->sed_base = voffset; - - if (ehdr.e_type == ET_DYN) { - /* - * Delay setting the brkbase until the first - * call to brk(); see elfexec() for details. - */ - env.ex_bssbase = (caddr_t)0; - env.ex_brkbase = (caddr_t)0; - env.ex_brksize = 0; - } - } - } - - env.ex_magic = elfmagic; - env.ex_vp = vp; - setexecenv(&env); - - /* - * It's time to manipulate the process aux vectors. First - * we need to update the AT_SUN_AUXFLAGS aux vector to set - * the AF_SUN_NOPLM flag. - */ - if (args->to_model == DATAMODEL_NATIVE) { - auxv_t auxflags_auxv; - - if (copyin(args->auxp_auxflags, &auxflags_auxv, - sizeof (auxflags_auxv)) != 0) - return (EFAULT); - - ASSERT(auxflags_auxv.a_type == AT_SUN_AUXFLAGS); - auxflags_auxv.a_un.a_val |= AF_SUN_NOPLM; - if (copyout(&auxflags_auxv, args->auxp_auxflags, - sizeof (auxflags_auxv)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - auxv32_t auxflags_auxv32; - - if (copyin(args->auxp_auxflags, &auxflags_auxv32, - sizeof (auxflags_auxv32)) != 0) - return (EFAULT); - - ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS); - auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM; - if (copyout(&auxflags_auxv32, args->auxp_auxflags, - sizeof (auxflags_auxv32)) != 0) - return (EFAULT); -#endif /* _LP64 */ - } - - /* Second, copy out the brand specific aux vectors. */ - if (args->to_model == DATAMODEL_NATIVE) { - auxv_t s10_auxv[] = { - { AT_SUN_BRAND_AUX1, 0 }, - { AT_SUN_BRAND_AUX2, 0 }, - { AT_SUN_BRAND_AUX3, 0 } - }; - - ASSERT(s10_auxv[0].a_type == AT_SUN_BRAND_S10_LDDATA); - s10_auxv[0].a_un.a_val = sed.sed_lddata; - - if (copyout(&s10_auxv, args->auxp_brand, - sizeof (s10_auxv)) != 0) - return (EFAULT); -#if defined(_LP64) - } else { - auxv32_t s10_auxv32[] = { - { AT_SUN_BRAND_AUX1, 0 }, - { AT_SUN_BRAND_AUX2, 0 }, - { AT_SUN_BRAND_AUX3, 0 } - }; - - ASSERT(s10_auxv32[0].a_type == AT_SUN_BRAND_S10_LDDATA); - s10_auxv32[0].a_un.a_val = (uint32_t)sed.sed_lddata; - if (copyout(&s10_auxv32, args->auxp_brand, - sizeof (s10_auxv32)) != 0) - return (EFAULT); -#endif /* _LP64 */ - } - - /* - * Third, the the /proc aux vectors set up by elfexec() point to brand - * emulation library and it's linker. Copy these to the /proc brand - * specific aux vector, and update the regular /proc aux vectors to - * point to the executable (and it's linker). This will enable - * debuggers to access the executable via the usual /proc or elf notes - * aux vectors. - * - * The brand emulation library's linker will get it's aux vectors off - * the stack, and then update the stack with the executable's aux - * vectors before jumping to the executable's linker. - * - * Debugging the brand emulation library must be done from - * the global zone, where the librtld_db module knows how to fetch the - * brand specific aux vectors to access the brand emulation libraries - * linker. - */ - for (i = 0; i < __KERN_NAUXV_IMPL; i++) { - ulong_t val; - - switch (up->u_auxv[i].a_type) { - case AT_SUN_BRAND_S10_LDDATA: - up->u_auxv[i].a_un.a_val = sed.sed_lddata; - continue; - case AT_BASE: - val = sedp->sed_base; - break; - case AT_ENTRY: - val = sedp->sed_entry; - break; - case AT_PHDR: - val = sedp->sed_phdr; - break; - case AT_PHENT: - val = sedp->sed_phent; - break; - case AT_PHNUM: - val = sedp->sed_phnum; - break; - case AT_SUN_LDDATA: - val = sedp->sed_lddata; - break; - default: - continue; - } - - up->u_auxv[i].a_un.a_val = val; - if (val == NULL) { - /* Hide the entry for static binaries */ - up->u_auxv[i].a_type = AT_IGNORE; - } - } - - /* - * The last thing we do here is clear spd->spd_handler. This is - * important because if we're already a branded process and if this - * exec succeeds, there is a window between when the exec() first - * returns to the userland of the new process and when our brand - * library get's initialized, during which we don't want system - * calls to be re-directed to our brand library since it hasn't - * been initialized yet. - */ - spd->spd_handler = NULL; - - return (0); + return (brand_solaris_elfexec(vp, uap, args, idatap, level, execsz, + setid, exec_file, cred, brand_action, &s10_brand, S10_BRANDNAME, + S10_LIB, S10_LIB32, S10_LINKER, S10_LINKER32)); } void @@ -1110,21 +570,6 @@ _info(struct modinfo *modinfop) int _fini(void) { - int err; - - /* - * If there are any zones using this brand, we can't allow it to be - * unloaded. - */ - if (brand_zone_count(&s10_brand)) - return (EBUSY); - - kmem_free(s10_emulation_table, NSYSCALL); - s10_emulation_table = NULL; - - err = mod_remove(&modlinkage); - if (err) - cmn_err(CE_WARN, "Couldn't unload s10 brand module"); - - return (err); + return (brand_solaris_fini(&s10_emulation_table, &modlinkage, + &s10_brand)); } diff --git a/usr/src/uts/common/brand/solaris10/s10_brand.h b/usr/src/uts/common/brand/solaris10/s10_brand.h index 9559881e98..3686c3600e 100644 --- a/usr/src/uts/common/brand/solaris10/s10_brand.h +++ b/usr/src/uts/common/brand/solaris10/s10_brand.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _S10_BRAND_H @@ -30,24 +29,21 @@ extern "C" { #endif -#include +#include #define S10_BRANDNAME "solaris10" #define S10_VERSION_1 1 #define S10_VERSION S10_VERSION_1 -#define S10_NATIVE_DIR "/.SUNWnative/" #define S10_LIB_NAME "s10_brand.so.1" #define S10_LINKER_NAME "ld.so.1" -#define S10_LIB32 S10_NATIVE_DIR "usr/lib/" S10_LIB_NAME +#define S10_LIB32 BRAND_NATIVE_DIR "usr/lib/" S10_LIB_NAME #define S10_LINKER32 "/lib/" S10_LINKER_NAME -#define S10_NATIVE_LINKER32 S10_NATIVE_DIR "lib/" S10_LINKER_NAME -#define S10_LIB64 S10_NATIVE_DIR "usr/lib/64/" S10_LIB_NAME +#define S10_LIB64 BRAND_NATIVE_DIR "usr/lib/64/" S10_LIB_NAME #define S10_LINKER64 "/lib/64/" S10_LINKER_NAME -#define S10_NATIVE_LINKER64 S10_NATIVE_DIR "lib/64/" S10_LINKER_NAME #if defined(_LP64) #define S10_LIB S10_LIB64 @@ -69,7 +65,6 @@ extern "C" { * Brand system call subcodes. 0-127 are reserved for generic subcodes. */ #define B_S10_PIDINFO 128 -#define B_S10_TRUSS_POINT 129 #define B_S10_NATIVE 130 #define B_S10_FSREGCORRECTION 131 #define B_S10_ISFDXATTRDIR 132 @@ -102,12 +97,6 @@ enum s10_emulated_features { */ #define S10_CPU_REG_SAVE_SIZE (sizeof (ulong_t) * 4) -/* - * Aux vector containing lddata pointer of brand library linkmap. - * Used by s10_librtld_db. - */ -#define AT_SUN_BRAND_S10_LDDATA AT_SUN_BRAND_AUX1 - /* * S10 system call codes for S10 traps that have been removed or reassigned, * or that are to be removed or reassigned after the dtrace syscall provider @@ -154,27 +143,6 @@ enum s10_emulated_features { */ #define S10_EMUL_BITMAP ZONE_ATTR_BRAND_ATTRS -/* - * Information needed by the s10 library to launch an executable. - */ -typedef struct s10_elf_data { - ulong_t sed_phdr; - ulong_t sed_phent; - ulong_t sed_phnum; - ulong_t sed_entry; - ulong_t sed_base; - ulong_t sed_ldentry; - ulong_t sed_lddata; -} s10_elf_data_t; - -/* - * Structure used to register a branded processes - */ -typedef struct s10_brand_reg { - uint_t sbr_version; /* version number */ - caddr_t sbr_handler; /* base address of handler */ -} s10_brand_reg_t; - /* * s10_emul_bitmap represents an emulation feature bitmap. Each constant * in s10_emulated_features defines a bit index in this bitmap. If a bit is @@ -200,30 +168,6 @@ typedef struct s10_brand_reg { typedef uint8_t s10_emul_bitmap_t[(S10_NUM_EMUL_FEATURES >> 3) + 1]; #if defined(_KERNEL) -#if defined(_SYSCALL32) -typedef struct s10_elf_data32 { - uint32_t sed_phdr; - uint32_t sed_phent; - uint32_t sed_phnum; - uint32_t sed_entry; - uint32_t sed_base; - uint32_t sed_ldentry; - uint32_t sed_lddata; -} s10_elf_data32_t; - -typedef struct s10_brand_reg32 { - uint32_t sbr_version; /* version number */ - caddr32_t sbr_handler; /* base address of handler */ -} s10_brand_reg32_t; -#endif /* _SYSCALL32 */ - -/* - * Information associated with all s10 branded processes - */ -typedef struct s10_proc_data { - caddr_t spd_handler; /* address of user-space handler */ - s10_elf_data_t spd_elf_data; /* ELF data for s10 application */ -} s10_proc_data_t; /* brand specific data */ typedef struct s10_zone_data { diff --git a/usr/src/uts/common/brand/solaris10/s10_offsets.in b/usr/src/uts/common/brand/solaris10/s10_offsets.in deleted file mode 100644 index db5144d670..0000000000 --- a/usr/src/uts/common/brand/solaris10/s10_offsets.in +++ /dev/null @@ -1,30 +0,0 @@ -\ -\ Copyright 2009 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 (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 -\ -\ s10 brand structure offset for use in assembly code. -\ - -#include - -s10_proc_data_t - spd_handler diff --git a/usr/src/uts/common/os/brand.c b/usr/src/uts/common/os/brand.c index b2bc8cc7d0..32e5b32fcb 100644 --- a/usr/src/uts/common/os/brand.c +++ b/usr/src/uts/common/os/brand.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -32,6 +31,7 @@ #include #include #include +#include #define SUPPORTED_BRAND_VERSION BRAND_VER_1 @@ -425,3 +425,675 @@ brand_plat_interposition_disable(void) syscall_trap32_patch_instr_orig, 4); } #endif /* __sparcv9 */ + +/* + * The following functions can be shared among kernel brand modules which + * implement Solaris-derived brands, all of which need to do similar tasks + * to manage the brand. + */ + +#if defined(_LP64) +static void +Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst) +{ + bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident)); + dst->e_type = src->e_type; + dst->e_machine = src->e_machine; + dst->e_version = src->e_version; + dst->e_entry = src->e_entry; + dst->e_phoff = src->e_phoff; + dst->e_shoff = src->e_shoff; + dst->e_flags = src->e_flags; + dst->e_ehsize = src->e_ehsize; + dst->e_phentsize = src->e_phentsize; + dst->e_phnum = src->e_phnum; + dst->e_shentsize = src->e_shentsize; + dst->e_shnum = src->e_shnum; + dst->e_shstrndx = src->e_shstrndx; +} +#endif /* _LP64 */ + +/* + * Return -1 if the cmd was not handled by this function. + */ +/*ARGSUSED*/ +int +brand_solaris_cmd(int cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + struct brand *pbrand, int brandvers) +{ + brand_proc_data_t *spd; + brand_proc_reg_t reg; + proc_t *p = curproc; + int err; + + /* + * There is one operation that is supported for a native + * process; B_EXEC_BRAND. This brand operaion is redundant + * since the kernel assumes a native process doing an exec + * in a branded zone is going to run a branded processes. + * hence we don't support this operation. + */ + if (cmd == B_EXEC_BRAND) + return (ENOSYS); + + /* For all other operations this must be a branded process. */ + if (p->p_brand == &native_brand) + return (ENOSYS); + + ASSERT(p->p_brand == pbrand); + ASSERT(p->p_brand_data != NULL); + + spd = (brand_proc_data_t *)p->p_brand_data; + + switch ((cmd)) { + case B_EXEC_NATIVE: + err = exec_common((char *)arg1, (const char **)arg2, + (const char **)arg3, EBA_NATIVE); + return (err); + + /* + * Get the address of the user-space system call handler from + * the user process and attach it to the proc structure. + */ + case B_REGISTER: + if (p->p_model == DATAMODEL_NATIVE) { + if (copyin((void *)arg1, ®, sizeof (reg)) != 0) + return (EFAULT); + } +#if defined(_LP64) + else { + brand_common_reg32_t reg32; + + if (copyin((void *)arg1, ®32, sizeof (reg32)) != 0) + return (EFAULT); + reg.sbr_version = reg32.sbr_version; + reg.sbr_handler = (caddr_t)(uintptr_t)reg32.sbr_handler; + } +#endif /* _LP64 */ + + if (reg.sbr_version != brandvers) + return (ENOTSUP); + spd->spd_handler = reg.sbr_handler; + return (0); + + case B_ELFDATA: + if (p->p_model == DATAMODEL_NATIVE) { + if (copyout(&spd->spd_elf_data, (void *)arg1, + sizeof (brand_elf_data_t)) != 0) + return (EFAULT); + } +#if defined(_LP64) + else { + brand_elf_data32_t sed32; + + sed32.sed_phdr = spd->spd_elf_data.sed_phdr; + sed32.sed_phent = spd->spd_elf_data.sed_phent; + sed32.sed_phnum = spd->spd_elf_data.sed_phnum; + sed32.sed_entry = spd->spd_elf_data.sed_entry; + sed32.sed_base = spd->spd_elf_data.sed_base; + sed32.sed_ldentry = spd->spd_elf_data.sed_ldentry; + sed32.sed_lddata = spd->spd_elf_data.sed_lddata; + if (copyout(&sed32, (void *)arg1, sizeof (sed32)) + != 0) + return (EFAULT); + } +#endif /* _LP64 */ + return (0); + + /* + * The B_TRUSS_POINT subcommand exists so that we can see + * truss output from interposed system calls that return + * without first calling any other system call, meaning they + * would be invisible to truss(1). + * If the second argument is set non-zero, set errno to that + * value as well. + * + * Common arguments seen with truss are: + * + * arg1: syscall number + * arg2: errno + */ + case B_TRUSS_POINT: + return ((arg2 == 0) ? 0 : set_errno((uint_t)arg2)); + } + + return (-1); +} + +/*ARGSUSED*/ +void +brand_solaris_copy_procdata(proc_t *child, proc_t *parent, struct brand *pbrand) +{ + brand_proc_data_t *spd; + + ASSERT(parent->p_brand == pbrand); + ASSERT(child->p_brand == pbrand); + ASSERT(parent->p_brand_data != NULL); + ASSERT(child->p_brand_data == NULL); + + /* + * Just duplicate all the proc data of the parent for the + * child + */ + spd = kmem_alloc(sizeof (brand_proc_data_t), KM_SLEEP); + bcopy(parent->p_brand_data, spd, sizeof (brand_proc_data_t)); + child->p_brand_data = spd; +} + +/*ARGSUSED*/ +int +brand_solaris_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, + intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file, + cred_t *cred, int brand_action, struct brand *pbrand, char *bname, + char *brandlib, char *brandlib32, char *brandlinker, char *brandlinker32) +{ + + vnode_t *nvp; + Ehdr ehdr; + Addr uphdr_vaddr; + intptr_t voffset; + int interp; + int i, err; + struct execenv env; + struct user *up = PTOU(curproc); + brand_proc_data_t *spd; + brand_elf_data_t sed, *sedp; + char *linker; + uintptr_t lddata; /* lddata of executable's linker */ + + ASSERT(curproc->p_brand == pbrand); + ASSERT(curproc->p_brand_data != NULL); + + spd = (brand_proc_data_t *)curproc->p_brand_data; + sedp = &spd->spd_elf_data; + + args->brandname = bname; + + /* + * We will exec the brand library and then map in the target + * application and (optionally) the brand's default linker. + */ + if (args->to_model == DATAMODEL_NATIVE) { + args->emulator = brandlib; + linker = brandlinker; + } +#if defined(_LP64) + else { + args->emulator = brandlib32; + linker = brandlinker32; + } +#endif /* _LP64 */ + + if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW, + NULLVPP, &nvp)) != 0) { + uprintf("%s: not found.", args->emulator); + return (err); + } + + if (args->to_model == DATAMODEL_NATIVE) { + err = elfexec(nvp, uap, args, idatap, level + 1, execsz, + setid, exec_file, cred, brand_action); + } +#if defined(_LP64) + else { + err = elf32exec(nvp, uap, args, idatap, level + 1, execsz, + setid, exec_file, cred, brand_action); + } +#endif /* _LP64 */ + VN_RELE(nvp); + if (err != 0) + return (err); + + /* + * The u_auxv veCTors are set up by elfexec to point to the + * brand emulation library and linker. Save these so they can + * be copied to the specific brand aux vectors. + */ + bzero(&sed, sizeof (sed)); + for (i = 0; i < __KERN_NAUXV_IMPL; i++) { + switch (up->u_auxv[i].a_type) { + case AT_SUN_LDDATA: + sed.sed_lddata = up->u_auxv[i].a_un.a_val; + break; + case AT_BASE: + sed.sed_base = up->u_auxv[i].a_un.a_val; + break; + case AT_ENTRY: + sed.sed_entry = up->u_auxv[i].a_un.a_val; + break; + case AT_PHDR: + sed.sed_phdr = up->u_auxv[i].a_un.a_val; + break; + case AT_PHENT: + sed.sed_phent = up->u_auxv[i].a_un.a_val; + break; + case AT_PHNUM: + sed.sed_phnum = up->u_auxv[i].a_un.a_val; + break; + default: + break; + } + } + /* Make sure the emulator has an entry point */ + ASSERT(sed.sed_entry != NULL); + ASSERT(sed.sed_phdr != NULL); + + bzero(&env, sizeof (env)); + if (args->to_model == DATAMODEL_NATIVE) { + err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr, + &voffset, exec_file, &interp, &env.ex_bssbase, + &env.ex_brkbase, &env.ex_brksize, NULL); + } +#if defined(_LP64) + else { + Elf32_Ehdr ehdr32; + Elf32_Addr uphdr_vaddr32; + err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32, + &voffset, exec_file, &interp, &env.ex_bssbase, + &env.ex_brkbase, &env.ex_brksize, NULL); + Ehdr32to64(&ehdr32, &ehdr); + + if (uphdr_vaddr32 == (Elf32_Addr)-1) + uphdr_vaddr = (Addr)-1; + else + uphdr_vaddr = uphdr_vaddr32; + } +#endif /* _LP64 */ + if (err != 0) + return (err); + + /* + * Save off the important properties of the executable. The + * brand library will ask us for this data later, when it is + * initializing and getting ready to transfer control to the + * brand application. + */ + if (uphdr_vaddr == (Addr)-1) + sedp->sed_phdr = voffset + ehdr.e_phoff; + else + sedp->sed_phdr = voffset + uphdr_vaddr; + sedp->sed_entry = voffset + ehdr.e_entry; + sedp->sed_phent = ehdr.e_phentsize; + sedp->sed_phnum = ehdr.e_phnum; + + if (interp) { + if (ehdr.e_type == ET_DYN) { + /* + * This is a shared object executable, so we + * need to pick a reasonable place to put the + * heap. Just don't use the first page. + */ + env.ex_brkbase = (caddr_t)PAGESIZE; + env.ex_bssbase = (caddr_t)PAGESIZE; + } + + /* + * If the program needs an interpreter (most do), map + * it in and store relevant information about it in the + * aux vector, where the brand library can find it. + */ + if ((err = lookupname(linker, UIO_SYSSPACE, + FOLLOW, NULLVPP, &nvp)) != 0) { + uprintf("%s: not found.", brandlinker); + return (err); + } + if (args->to_model == DATAMODEL_NATIVE) { + err = mapexec_brand(nvp, args, &ehdr, + &uphdr_vaddr, &voffset, exec_file, &interp, + NULL, NULL, NULL, &lddata); + } +#if defined(_LP64) + else { + Elf32_Ehdr ehdr32; + Elf32_Addr uphdr_vaddr32; + err = mapexec32_brand(nvp, args, &ehdr32, + &uphdr_vaddr32, &voffset, exec_file, &interp, + NULL, NULL, NULL, &lddata); + Ehdr32to64(&ehdr32, &ehdr); + + if (uphdr_vaddr32 == (Elf32_Addr)-1) + uphdr_vaddr = (Addr)-1; + else + uphdr_vaddr = uphdr_vaddr32; + } +#endif /* _LP64 */ + VN_RELE(nvp); + if (err != 0) + return (err); + + /* + * Now that we know the base address of the brand's + * linker, place it in the aux vector. + */ + sedp->sed_base = voffset; + sedp->sed_ldentry = voffset + ehdr.e_entry; + sedp->sed_lddata = voffset + lddata; + } else { + /* + * This program has no interpreter. The brand library + * will jump to the address in the AT_SUN_BRAND_LDENTRY + * aux vector, so in this case, put the entry point of + * the main executable there. + */ + if (ehdr.e_type == ET_EXEC) { + /* + * An executable with no interpreter, this must + * be a statically linked executable, which + * means we loaded it at the address specified + * in the elf header, in which case the e_entry + * field of the elf header is an absolute + * address. + */ + sedp->sed_ldentry = ehdr.e_entry; + sedp->sed_entry = ehdr.e_entry; + sedp->sed_lddata = NULL; + sedp->sed_base = NULL; + } else { + /* + * A shared object with no interpreter, we use + * the calculated address from above. + */ + sedp->sed_ldentry = sedp->sed_entry; + sedp->sed_entry = NULL; + sedp->sed_phdr = NULL; + sedp->sed_phent = NULL; + sedp->sed_phnum = NULL; + sedp->sed_lddata = NULL; + sedp->sed_base = voffset; + + if (ehdr.e_type == ET_DYN) { + /* + * Delay setting the brkbase until the + * first call to brk(); see elfexec() + * for details. + */ + env.ex_bssbase = (caddr_t)0; + env.ex_brkbase = (caddr_t)0; + env.ex_brksize = 0; + } + } + } + + env.ex_magic = elfmagic; + env.ex_vp = vp; + setexecenv(&env); + + /* + * It's time to manipulate the process aux vectors. First + * we need to update the AT_SUN_AUXFLAGS aux vector to set + * the AF_SUN_NOPLM flag. + */ + if (args->to_model == DATAMODEL_NATIVE) { + auxv_t auxflags_auxv; + + if (copyin(args->auxp_auxflags, &auxflags_auxv, + sizeof (auxflags_auxv)) != 0) + return (EFAULT); + + ASSERT(auxflags_auxv.a_type == AT_SUN_AUXFLAGS); + auxflags_auxv.a_un.a_val |= AF_SUN_NOPLM; + if (copyout(&auxflags_auxv, args->auxp_auxflags, + sizeof (auxflags_auxv)) != 0) + return (EFAULT); + } +#if defined(_LP64) + else { + auxv32_t auxflags_auxv32; + + if (copyin(args->auxp_auxflags, &auxflags_auxv32, + sizeof (auxflags_auxv32)) != 0) + return (EFAULT); + + ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS); + auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM; + if (copyout(&auxflags_auxv32, args->auxp_auxflags, + sizeof (auxflags_auxv32)) != 0) + return (EFAULT); + } +#endif /* _LP64 */ + + /* Second, copy out the brand specific aux vectors. */ + if (args->to_model == DATAMODEL_NATIVE) { + auxv_t brand_auxv[] = { + { AT_SUN_BRAND_AUX1, 0 }, + { AT_SUN_BRAND_AUX2, 0 }, + { AT_SUN_BRAND_AUX3, 0 } + }; + + ASSERT(brand_auxv[0].a_type == + AT_SUN_BRAND_COMMON_LDDATA); + brand_auxv[0].a_un.a_val = sed.sed_lddata; + + if (copyout(&brand_auxv, args->auxp_brand, + sizeof (brand_auxv)) != 0) + return (EFAULT); + } +#if defined(_LP64) + else { + auxv32_t brand_auxv32[] = { + { AT_SUN_BRAND_AUX1, 0 }, + { AT_SUN_BRAND_AUX2, 0 }, + { AT_SUN_BRAND_AUX3, 0 } + }; + + ASSERT(brand_auxv32[0].a_type == AT_SUN_BRAND_COMMON_LDDATA); + brand_auxv32[0].a_un.a_val = (uint32_t)sed.sed_lddata; + if (copyout(&brand_auxv32, args->auxp_brand, + sizeof (brand_auxv32)) != 0) + return (EFAULT); + } +#endif /* _LP64 */ + + /* + * Third, the /proc aux vectors set up by elfexec() point to + * brand emulation library and it's linker. Copy these to the + * /proc brand specific aux vector, and update the regular + * /proc aux vectors to point to the executable (and it's + * linker). This will enable debuggers to access the + * executable via the usual /proc or elf notes aux vectors. + * + * The brand emulation library's linker will get it's aux + * vectors off the stack, and then update the stack with the + * executable's aux vectors before jumping to the executable's + * linker. + * + * Debugging the brand emulation library must be done from + * the global zone, where the librtld_db module knows how to + * fetch the brand specific aux vectors to access the brand + * emulation libraries linker. + */ + for (i = 0; i < __KERN_NAUXV_IMPL; i++) { + ulong_t val; + + switch (up->u_auxv[i].a_type) { + case AT_SUN_BRAND_COMMON_LDDATA: + up->u_auxv[i].a_un.a_val = sed.sed_lddata; + continue; + case AT_BASE: + val = sedp->sed_base; + break; + case AT_ENTRY: + val = sedp->sed_entry; + break; + case AT_PHDR: + val = sedp->sed_phdr; + break; + case AT_PHENT: + val = sedp->sed_phent; + break; + case AT_PHNUM: + val = sedp->sed_phnum; + break; + case AT_SUN_LDDATA: + val = sedp->sed_lddata; + break; + default: + continue; + } + + up->u_auxv[i].a_un.a_val = val; + if (val == NULL) { + /* Hide the entry for static binaries */ + up->u_auxv[i].a_type = AT_IGNORE; + } + } + + /* + * The last thing we do here is clear spd->spd_handler. This + * is important because if we're already a branded process and + * if this exec succeeds, there is a window between when the + * exec() first returns to the userland of the new process and + * when our brand library get's initialized, during which we + * don't want system calls to be re-directed to our brand + * library since it hasn't been initialized yet. + */ + spd->spd_handler = NULL; + + return (0); +} + +void +brand_solaris_exec(struct brand *pbrand) +{ + brand_proc_data_t *spd = curproc->p_brand_data; + + ASSERT(curproc->p_brand == pbrand); + ASSERT(curproc->p_brand_data != NULL); + ASSERT(ttolwp(curthread)->lwp_brand != NULL); + + /* + * We should only be called from exec(), when we know the process + * is single-threaded. + */ + ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw); + + /* Upon exec, reset our lwp brand data. */ + (void) brand_solaris_freelwp(ttolwp(curthread), pbrand); + (void) brand_solaris_initlwp(ttolwp(curthread), pbrand); + + /* + * Upon exec, reset all the proc brand data, except for the elf + * data associated with the executable we are exec'ing. + */ + spd->spd_handler = NULL; +} + +int +brand_solaris_fini(char **emul_table, struct modlinkage *modlinkage, + struct brand *pbrand) +{ + int err; + + /* + * If there are any zones using this brand, we can't allow it + * to be unloaded. + */ + if (brand_zone_count(pbrand)) + return (EBUSY); + + kmem_free(*emul_table, NSYSCALL); + *emul_table = NULL; + + err = mod_remove(modlinkage); + if (err) + cmn_err(CE_WARN, "Couldn't unload brand module"); + + return (err); +} + +/*ARGSUSED*/ +void +brand_solaris_forklwp(klwp_t *p, klwp_t *c, struct brand *pbrand) +{ + ASSERT(p->lwp_procp->p_brand == pbrand); + ASSERT(c->lwp_procp->p_brand == pbrand); + + ASSERT(p->lwp_procp->p_brand_data != NULL); + ASSERT(c->lwp_procp->p_brand_data != NULL); + + /* + * Both LWPs have already had been initialized via + * brand_solaris_initlwp(). + */ + ASSERT(p->lwp_brand != NULL); + ASSERT(c->lwp_brand != NULL); +} + +/*ARGSUSED*/ +void +brand_solaris_freelwp(klwp_t *l, struct brand *pbrand) +{ + ASSERT(l->lwp_procp->p_brand == pbrand); + ASSERT(l->lwp_procp->p_brand_data != NULL); + ASSERT(l->lwp_brand != NULL); + l->lwp_brand = NULL; +} + +/*ARGSUSED*/ +int +brand_solaris_initlwp(klwp_t *l, struct brand *pbrand) +{ + ASSERT(l->lwp_procp->p_brand == pbrand); + ASSERT(l->lwp_procp->p_brand_data != NULL); + ASSERT(l->lwp_brand == NULL); + l->lwp_brand = (void *)-1; + return (0); +} + +/*ARGSUSED*/ +void +brand_solaris_lwpexit(klwp_t *l, struct brand *pbrand) +{ + proc_t *p = l->lwp_procp; + + ASSERT(l->lwp_procp->p_brand == pbrand); + ASSERT(l->lwp_procp->p_brand_data != NULL); + ASSERT(l->lwp_brand != NULL); + + /* + * We should never be called for the last thread in a process. + * (That case is handled by brand_solaris_proc_exit().) + * Therefore this lwp must be exiting from a multi-threaded + * process. + */ + ASSERT(p->p_tlist != p->p_tlist->t_forw); + + l->lwp_brand = NULL; +} + +/*ARGSUSED*/ +void +brand_solaris_proc_exit(struct proc *p, klwp_t *l, struct brand *pbrand) +{ + ASSERT(p->p_brand == pbrand); + ASSERT(p->p_brand_data != NULL); + + /* + * We should only be called from proc_exit(), when we know that + * process is single-threaded. + */ + ASSERT(p->p_tlist == p->p_tlist->t_forw); + + /* upon exit, free our lwp brand data */ + (void) brand_solaris_freelwp(ttolwp(curthread), pbrand); + + /* upon exit, free our proc brand data */ + kmem_free(p->p_brand_data, sizeof (brand_proc_data_t)); + p->p_brand_data = NULL; +} + +void +brand_solaris_setbrand(proc_t *p, struct brand *pbrand) +{ + ASSERT(p->p_brand == pbrand); + ASSERT(p->p_brand_data == NULL); + + /* + * We should only be called from exec(), when we know the process + * is single-threaded. + */ + ASSERT(p->p_tlist == p->p_tlist->t_forw); + + p->p_brand_data = kmem_zalloc(sizeof (brand_proc_data_t), KM_SLEEP); + (void) brand_solaris_initlwp(p->p_tlist->t_lwp, pbrand); +} diff --git a/usr/src/uts/common/sys/brand.h b/usr/src/uts/common/sys/brand.h index ee56189df7..32e0f045e9 100644 --- a/usr/src/uts/common/sys/brand.h +++ b/usr/src/uts/common/sys/brand.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_BRAND_H @@ -33,6 +32,7 @@ extern "C" { #include #include +#include /* * All Brands supported by this kernel must use BRAND_VER_1. @@ -49,6 +49,7 @@ extern "C" { #define B_ELFDATA 3 #define B_EXEC_NATIVE 4 #define B_EXEC_BRAND 5 +#define B_TRUSS_POINT 6 /* * Structure used by zoneadmd to communicate the name of a brand and the @@ -65,10 +66,34 @@ struct brand_attr { /* What we call the labeled brand. */ #define LABELED_BRAND_NAME "labeled" -#ifdef _KERNEL +/* + * Aux vector containing lddata pointer of brand library linkmap. + * Used by common {brand}_librtld_db. + */ +#define AT_SUN_BRAND_COMMON_LDDATA AT_SUN_BRAND_AUX1 + +/* + * Information needed by the brand library to launch an executable. + */ +typedef struct brand_elf_data { + ulong_t sed_phdr; + ulong_t sed_phent; + ulong_t sed_phnum; + ulong_t sed_entry; + ulong_t sed_base; + ulong_t sed_ldentry; + ulong_t sed_lddata; +} brand_elf_data_t; + +/* + * Common structure used to register a branded processes + */ +typedef struct brand_proc_reg { + uint_t sbr_version; /* version number */ + caddr_t sbr_handler; /* base address of handler */ +} brand_proc_reg_t; -/* Root for branded zone's native binaries */ -#define NATIVE_ROOT "/native/" +#ifdef _KERNEL struct proc; struct uarg; @@ -141,6 +166,59 @@ extern void brand_unregister_zone(brand_t *); extern int brand_zone_count(brand_t *); extern void brand_setbrand(proc_t *); extern void brand_clearbrand(proc_t *); + +/* + * The following functions can be shared among kernel brand modules which + * implement Solaris-derived brands, all of which need to do similar tasks to + * manage the brand. + */ +extern int brand_solaris_cmd(int, uintptr_t, uintptr_t, uintptr_t, + struct brand *, int); +extern void brand_solaris_copy_procdata(proc_t *, proc_t *, + struct brand *); +extern int brand_solaris_elfexec(vnode_t *, execa_t *, uarg_t *, + intpdata_t *, int, long *, int, caddr_t, cred_t *, int, + struct brand *, char *, char *, char *, char *, char *); +extern void brand_solaris_exec(struct brand *); +extern int brand_solaris_fini(char **, struct modlinkage *, + struct brand *); +extern void brand_solaris_forklwp(klwp_t *, klwp_t *, struct brand *); +extern void brand_solaris_freelwp(klwp_t *, struct brand *); +extern int brand_solaris_initlwp(klwp_t *, struct brand *); +extern void brand_solaris_lwpexit(klwp_t *, struct brand *); +extern void brand_solaris_proc_exit(struct proc *, klwp_t *, + struct brand *); +extern void brand_solaris_setbrand(proc_t *, struct brand *); + +#if defined(_SYSCALL32) +typedef struct brand_elf_data32 { + uint32_t sed_phdr; + uint32_t sed_phent; + uint32_t sed_phnum; + uint32_t sed_entry; + uint32_t sed_base; + uint32_t sed_ldentry; + uint32_t sed_lddata; +} brand_elf_data32_t; + +typedef struct brand_common_reg32 { + uint32_t sbr_version; /* version number */ + caddr32_t sbr_handler; /* base address of handler */ +} brand_common_reg32_t; +#endif /* _SYSCALL32 */ + +/* + * Common information associated with all branded processes + */ +typedef struct brand_proc_data { + caddr_t spd_handler; /* address of user-space handler */ + brand_elf_data_t spd_elf_data; /* common ELF data for branded app. */ +} brand_proc_data_t; + +#define BRAND_NATIVE_DIR "/.SUNWnative/" +#define BRAND_NATIVE_LINKER32 BRAND_NATIVE_DIR "lib/ld.so.1" +#define BRAND_NATIVE_LINKER64 BRAND_NATIVE_DIR "lib/64/ld.so.1" + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/i86pc/ml/offsets.in b/usr/src/uts/i86pc/ml/offsets.in index 029193b35e..ceefce6d3c 100644 --- a/usr/src/uts/i86pc/ml/offsets.in +++ b/usr/src/uts/i86pc/ml/offsets.in @@ -1,6 +1,5 @@ \ -\ Copyright 2009 Sun Microsystems, Inc. All rights reserved. -\ Use is subject to license terms. +\ Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. \ \ CDDL HEADER START \ @@ -388,6 +387,9 @@ copyops brand b_machops +brand_proc_data_t + spd_handler + fastboot_file_t fb_va fb_pte_list_va diff --git a/usr/src/uts/intel/brand/common/brand_asm.h b/usr/src/uts/intel/brand/common/brand_asm.h index a6e5385f20..1d540db2a9 100644 --- a/usr/src/uts/intel/brand/common/brand_asm.h +++ b/usr/src/uts/intel/brand/common/brand_asm.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _COMMON_BRAND_ASM_H @@ -237,64 +236,6 @@ extern "C" { shl $4, SYSCALL_REG; /* syscall_num * 16 */ \ add SYSCALL_REG, scr /* leave return addr in scr reg. */ -#if defined(__amd64) - -/* - * To 'return' to our user-space handler, we just need to place its address - * into 'retreg'. The original return address is passed back in SYSCALL_REG. - */ -#define SYSCALL_EMUL(emul_table, handler, retreg) \ - CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ - CALC_TABLE_ADDR(SCR_REG, handler); \ - mov retreg, SYSCALL_REG; /* save orig return addr in syscall_reg */\ - mov SCR_REG, retreg; /* place new return addr in retreg */\ - mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */\ - mov V_SSP(SP_REG), SP_REG /* restore user stack pointer */ - -/* - * To 'return' to our user-space handler we need to update the user's %eip - * pointer in the saved interrupt state on the stack. The interrupt state was - * pushed onto our stack automatically when the interrupt occured; see the - * comments above. The original return address is passed back in SYSCALL_REG. - */ -#define INT_EMUL(emul_table, handler) \ - CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ - CALC_TABLE_ADDR(SCR_REG, handler); /* new return addr is in scratch */ \ - mov SCR_REG, SYSCALL_REG; /* place new ret addr in syscallreg */ \ - mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ \ - mov V_SSP(SP_REG), SP_REG; /* restore intr stack pointer */ \ - /*CSTYLED*/ \ - xchg (SP_REG), SYSCALL_REG /* swap new and orig. return addrs */ - -#else /* !__amd64 */ - -/* - * To 'return' to our user-space handler, we just need to place its address - * into 'retreg'. The original return address is passed back in SYSCALL_REG. - */ -#define SYSCALL_EMUL(emul_table, handler, retreg) \ - CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ - mov retreg, SCR_REG; /* save orig return addr in scr reg */ \ - CALC_TABLE_ADDR(retreg, handler); /* new return addr is in retreg */ \ - mov SCR_REG, SYSCALL_REG; /* save orig return addr in %eax */ \ - GET_V(SP_REG, 0, V_U_EBX, SCR_REG) /* restore scratch register */ - -/* - * To 'return' to our user-space handler, we need to replace the - * iret target address. - * The original return address is passed back in %eax. - */ -#define INT_EMUL(emul_table, handler) \ - CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ - CALC_TABLE_ADDR(SCR_REG, handler); /* new return addr is in scratch */ \ - mov SCR_REG, SYSCALL_REG; /* place new ret addr in syscallreg */ \ - GET_V(SP_REG, 0, V_U_EBX, SCR_REG); /* restore scratch register */ \ - add $V_END, SP_REG; /* restore intr stack pointer */ \ - /*CSTYLED*/ \ - xchg (SP_REG), SYSCALL_REG /* swap new and orig. return addrs */ - -#endif /* !__amd64 */ - #endif /* _ASM */ #ifdef __cplusplus diff --git a/usr/src/uts/intel/brand/common/brand_solaris.s b/usr/src/uts/intel/brand/common/brand_solaris.s new file mode 100644 index 0000000000..eb4c6b6844 --- /dev/null +++ b/usr/src/uts/intel/brand/common/brand_solaris.s @@ -0,0 +1,195 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * This is an assembly file that gets #include-ed into the brand-specific + * assembly files (e.g. sn1_brand_asm.s) for Solaris-derived brands. + * We can't make these into functions since in the trap context there's + * no easy place to save the extra parameters that would be required, so + * each brand module needs its own copy of this code. We #include this and + * use brand-specific #defines to replace the XXX_brand_... definitions. + */ + +#ifdef lint + +#include + +#else /* !lint */ + +#include +#include +#include +#include "assym.h" +#include "brand_asm.h" + +#endif /* !lint */ + +#ifdef lint + +void +XXX_brand_sysenter_callback(void) +{ +} + +void +XXX_brand_syscall_callback(void) +{ +} + +#if defined(__amd64) +void +XXX_brand_syscall32_callback(void) +{ +} +#endif /* amd64 */ + +void +XXX_brand_int91_callback(void) +{ +} + +#else /* !lint */ + +#ifdef _ASM /* The remainder of this file is only for assembly files */ + +#if defined(__amd64) + +/* + * syscall handler for 32-bit user processes: + * See "64-BIT INTERPOSITION STACK" in brand_asm.h. + * To 'return' to our user-space handler, we just need to place its address + * into %rcx. The original return address is passed back in SYSCALL_REG. + */ +ENTRY(XXX_brand_syscall32_callback) + CALLBACK_PROLOGUE(XXX_emulation_table, SPD_HANDLER, SYSCALL_REG, + SCR_REG, SCR_REGB); + CALC_TABLE_ADDR(SCR_REG, SPD_HANDLER); + mov %rcx, SYSCALL_REG; /* save orig return addr in syscall_reg */ + mov SCR_REG, %rcx; /* place new return addr in %rcx */ + mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ + mov V_SSP(SP_REG), SP_REG /* restore user stack pointer */ + jmp nopop_sys_syscall32_swapgs_sysretl +9: + retq +SET_SIZE(XXX_brand_syscall32_callback) + +/* + * syscall handler for 64-bit user processes: + * See "64-BIT INTERPOSITION STACK" in brand_asm.h. + * To 'return' to our user-space handler, we just need to place its address + * into %rcx. The original return address is passed back in SYSCALL_REG. + */ +ENTRY(XXX_brand_syscall_callback) + CALLBACK_PROLOGUE(XXX_emulation_table, SPD_HANDLER, SYSCALL_REG, + SCR_REG, SCR_REGB); + CALC_TABLE_ADDR(SCR_REG, SPD_HANDLER); + mov %rcx, SYSCALL_REG; /* save orig return addr in syscall_reg */ + mov SCR_REG, %rcx; /* place new return addr in %rcx */ + mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ + mov V_SSP(SP_REG), SP_REG /* restore user stack pointer */ + jmp nopop_sys_syscall_swapgs_sysretq +9: + retq +SET_SIZE(XXX_brand_syscall_callback) + +/* + * See "64-BIT INTERPOSITION STACK" in brand_asm.h. + * To 'return' to our user-space handler, we just need to place its address + * into %rdx. The original return address is passed back in SYSCALL_REG. + */ +ENTRY(XXX_brand_sysenter_callback) + CALLBACK_PROLOGUE(XXX_emulation_table, SPD_HANDLER, SYSCALL_REG, + SCR_REG, SCR_REGB); + CALC_TABLE_ADDR(SCR_REG, SPD_HANDLER); + mov %rdx, SYSCALL_REG; /* save orig return addr in syscall_reg */ + mov SCR_REG, %rdx; /* place new return addr in %rdx */ + mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ + mov V_SSP(SP_REG), SP_REG /* restore user stack pointer */ + jmp sys_sysenter_swapgs_sysexit +9: + ret +SET_SIZE(XXX_brand_sysenter_callback) + +/* + * To 'return' to our user-space handler we need to update the user's %eip + * pointer in the saved interrupt state on the stack. The interrupt state was + * pushed onto our stack automatically when the interrupt occured; see the + * comments above. The original return address is passed back in SYSCALL_REG. + * See "64-BIT INTERPOSITION STACK" and "64-BIT INT STACK" in brand_asm.h. + */ +ENTRY(XXX_brand_int91_callback) + CALLBACK_PROLOGUE(XXX_emulation_table, SPD_HANDLER, SYSCALL_REG, + SCR_REG, SCR_REGB); + CALC_TABLE_ADDR(SCR_REG, SPD_HANDLER); /* new ret addr is in scratch */ + mov SCR_REG, SYSCALL_REG; /* place new ret addr in syscallreg */ + mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ + mov V_SSP(SP_REG), SP_REG; /* restore intr stack pointer */ + /*CSTYLED*/ + xchg (SP_REG), SYSCALL_REG /* swap new and orig. return addrs */ + jmp sys_sysint_swapgs_iret +9: + retq +SET_SIZE(XXX_brand_int91_callback) + +#else /* !__amd64 */ + +/* + * To 'return' to our user-space handler, we need to replace the iret target + * address. The original return address is passed back in %eax. + * See "32-BIT INTERPOSITION STACK" and "32-BIT INT STACK" in brand_asm.h. + */ +ENTRY(XXX_brand_syscall_callback) + CALLBACK_PROLOGUE(XXX_emulation_table, SPD_HANDLER, SYSCALL_REG, + SCR_REG, SCR_REGB); + CALC_TABLE_ADDR(SCR_REG, SPD_HANDLER); /* new ret addr is in scratch */ + mov SCR_REG, SYSCALL_REG; /* place new ret addr in syscallreg */ + GET_V(SP_REG, 0, V_U_EBX, SCR_REG); /* restore scratch register */ + add $V_END, SP_REG; /* restore intr stack pointer */ + /*CSTYLED*/ + xchg (SP_REG), SYSCALL_REG /* swap new and orig. return addrs */ + jmp nopop_sys_rtt_syscall +9: + ret +SET_SIZE(XXX_brand_syscall_callback) + +/* + * To 'return' to our user-space handler, we just need to place its address + * into %edx. The original return address is passed back in SYSCALL_REG. + * See "32-BIT INTERPOSITION STACK" in brand_asm.h. + */ +ENTRY(XXX_brand_sysenter_callback) + CALLBACK_PROLOGUE(XXX_emulation_table, SPD_HANDLER, SYSCALL_REG, + SCR_REG, SCR_REGB); + mov %edx, SCR_REG; /* save orig return addr in scr reg */ + CALC_TABLE_ADDR(%edx, SPD_HANDLER); /* new return addr is in %edx */ + mov SCR_REG, SYSCALL_REG; /* save orig return addr in %eax */ + GET_V(SP_REG, 0, V_U_EBX, SCR_REG) /* restore scratch register */ + sysexit +9: + ret +SET_SIZE(XXX_brand_sysenter_callback) + +#endif /* !__amd64 */ +#endif /* _ASM */ +#endif /* !lint */ diff --git a/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s b/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s index 8432554132..a211a075b1 100644 --- a/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s +++ b/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s @@ -19,116 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ -#if defined(lint) +#define XXX_emulation_table sn1_emulation_table +#define XXX_brand_syscall32_callback sn1_brand_syscall32_callback +#define XXX_brand_syscall_callback sn1_brand_syscall_callback +#define XXX_brand_sysenter_callback sn1_brand_sysenter_callback +#define XXX_brand_int91_callback sn1_brand_int91_callback -#include - -#else /* lint */ - -#include -#include "../common/brand_asm.h" - -#endif /* lint */ - -#ifdef lint - -void -sn1_brand_sysenter_callback(void) -{ -} - -void -sn1_brand_syscall_callback(void) -{ -} - -#if defined(__amd64) -void -sn1_brand_syscall32_callback(void) -{ -} -#endif /* amd64 */ - -void -sn1_brand_int91_callback(void) -{ -} - -#else /* lint */ - -#if defined(__amd64) - -/* - * syscall handler for 32-bit user processes: - * %rcx - the address of the instruction after the syscall - * See "64-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(sn1_brand_syscall32_callback) - SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %rcx) - jmp nopop_sys_syscall32_swapgs_sysretl -9: - retq -SET_SIZE(sn1_brand_syscall32_callback) - -/* - * syscall handler for 64-bit user processes: - * %rcx - the address of the instruction after the syscall - * See "64-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(sn1_brand_syscall_callback) - SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %rcx) - jmp nopop_sys_syscall_swapgs_sysretq -9: - retq -SET_SIZE(sn1_brand_syscall_callback) - -/* - * %rdx - user space return address - * See "64-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(sn1_brand_sysenter_callback) - SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %rdx) - jmp sys_sysenter_swapgs_sysexit -9: - ret -SET_SIZE(sn1_brand_sysenter_callback) - -/* - * See "64-BIT INTERPOSITION STACK" and "64-BIT INT STACK" in brand_asm.h. - */ -ENTRY(sn1_brand_int91_callback) - INT_EMUL(sn1_emulation_table, SPD_HANDLER) - jmp sys_sysint_swapgs_iret -9: - retq -SET_SIZE(sn1_brand_int91_callback) - -#else /* !__amd64 */ - -/* - * See "32-BIT INTERPOSITION STACK" and "32-BIT INT STACK" in brand_asm.h. - */ -ENTRY(sn1_brand_syscall_callback) - INT_EMUL(sn1_emulation_table, SPD_HANDLER) - jmp nopop_sys_rtt_syscall -9: - ret -SET_SIZE(sn1_brand_syscall_callback) - -/* - * %edx - user space return address - * See "32-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(sn1_brand_sysenter_callback) - SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %edx) - sysexit -9: - ret -SET_SIZE(sn1_brand_sysenter_callback) - -#endif /* !__amd64 */ -#endif /* lint */ +#include "../common/brand_solaris.s" diff --git a/usr/src/uts/intel/brand/solaris10/s10_brand_asm.s b/usr/src/uts/intel/brand/solaris10/s10_brand_asm.s index d4a3b2eb5c..6fae877da2 100644 --- a/usr/src/uts/intel/brand/solaris10/s10_brand_asm.s +++ b/usr/src/uts/intel/brand/solaris10/s10_brand_asm.s @@ -19,116 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ -#if defined(lint) +#define XXX_emulation_table s10_emulation_table +#define XXX_brand_syscall32_callback s10_brand_syscall32_callback +#define XXX_brand_syscall_callback s10_brand_syscall_callback +#define XXX_brand_sysenter_callback s10_brand_sysenter_callback +#define XXX_brand_int91_callback s10_brand_int91_callback -#include - -#else /* lint */ - -#include -#include "../common/brand_asm.h" - -#endif /* lint */ - -#ifdef lint - -void -s10_brand_sysenter_callback(void) -{ -} - -void -s10_brand_syscall_callback(void) -{ -} - -#if defined(__amd64) -void -s10_brand_syscall32_callback(void) -{ -} -#endif /* amd64 */ - -void -s10_brand_int91_callback(void) -{ -} - -#else /* lint */ - -#if defined(__amd64) - -/* - * syscall handler for 32-bit user processes: - * %rcx - the address of the instruction after the syscall - * See "64-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(s10_brand_syscall32_callback) - SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %rcx) - jmp nopop_sys_syscall32_swapgs_sysretl -9: - retq -SET_SIZE(s10_brand_syscall32_callback) - -/* - * syscall handler for 64-bit user processes: - * %rcx - the address of the instruction after the syscall - * See "64-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(s10_brand_syscall_callback) - SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %rcx) - jmp nopop_sys_syscall_swapgs_sysretq -9: - retq -SET_SIZE(s10_brand_syscall_callback) - -/* - * %rdx - user space return address - * See "64-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(s10_brand_sysenter_callback) - SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %rdx) - jmp sys_sysenter_swapgs_sysexit -9: - ret -SET_SIZE(s10_brand_sysenter_callback) - -/* - * See "64-BIT INTERPOSITION STACK" and "64-BIT INT STACK" in brand_asm.h. - */ -ENTRY(s10_brand_int91_callback) - INT_EMUL(s10_emulation_table, SPD_HANDLER) - jmp sys_sysint_swapgs_iret -9: - retq -SET_SIZE(s10_brand_int91_callback) - -#else /* !__amd64 */ - -/* - * See "32-BIT INTERPOSITION STACK" and "32-BIT INT STACK" in brand_asm.h. - */ -ENTRY(s10_brand_syscall_callback) - INT_EMUL(s10_emulation_table, SPD_HANDLER) - jmp nopop_sys_rtt_syscall -9: - ret -SET_SIZE(s10_brand_syscall_callback) - -/* - * %edx - user space return address - * See "32-BIT INTERPOSITION STACK" in brand_asm.h. - */ -ENTRY(s10_brand_sysenter_callback) - SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %edx) - sysexit -9: - ret -SET_SIZE(s10_brand_sysenter_callback) - -#endif /* !__amd64 */ -#endif /* lint */ +#include "../common/brand_solaris.s" diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s index 807cb8f790..3151f3b4e3 100644 --- a/usr/src/uts/intel/ia32/ml/modstubs.s +++ b/usr/src/uts/intel/ia32/ml/modstubs.s @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -1423,6 +1422,18 @@ fcnname/**/_info: \ END_MODULE(ksocket); #endif +/* + * Stubs for elfexec + */ +#ifndef ELFEXEC_MODULE + MODULE(elfexec,exec); + STUB(elfexec, elfexec, nomod_einval); + STUB(elfexec, elf32exec, nomod_einval); + STUB(elfexec, mapexec_brand, nomod_einval); + STUB(elfexec, mapexec32_brand, nomod_einval); + END_MODULE(elfexec); +#endif + / this is just a marker for the area of text that contains stubs ENTRY_NP(stubs_end) diff --git a/usr/src/uts/intel/s10_brand/Makefile b/usr/src/uts/intel/s10_brand/Makefile index 7ed668ed74..ffda173a95 100644 --- a/usr/src/uts/intel/s10_brand/Makefile +++ b/usr/src/uts/intel/s10_brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # This makefile drives the production of the kernel component of # the Solaris 10 brand @@ -36,8 +35,6 @@ S10_BASE = $(UTSBASE)/common/brand/solaris10 # Define the module and object file sets. # MODULE = s10_brand -OFFSETS_H = $(OBJS_DIR)/s10_offsets.h -OFFSETS_SRC = $(S10_BASE)/s10_offsets.in OBJECTS = $(S10_BRAND_OBJS:%=$(OBJS_DIR)/%) LINTS = $(S10_BRAND_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(USR_BRAND_DIR)/$(MODULE) @@ -50,9 +47,9 @@ include $(UTSBASE)/intel/Makefile.intel # # Define targets # -ALL_TARGET = $(OFFSETS_H) $(BINARY) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(OFFSETS_H) $(BINARY) $(ROOTMODULE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # @@ -94,12 +91,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -# -# Create genassym.h -# -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@ - # # Include common targets. # diff --git a/usr/src/uts/intel/sn1_brand/Makefile b/usr/src/uts/intel/sn1_brand/Makefile index b7c9afab6e..b0b3ca2635 100644 --- a/usr/src/uts/intel/sn1_brand/Makefile +++ b/usr/src/uts/intel/sn1_brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # This makefile drives the production of the kernel component of # the N-1 Solaris brand @@ -36,8 +35,6 @@ SN1_BASE = $(UTSBASE)/common/brand/sn1 # Define the module and object file sets. # MODULE = sn1_brand -OFFSETS_H = $(OBJS_DIR)/sn1_offsets.h -OFFSETS_SRC = $(SN1_BASE)/sn1_offsets.in OBJECTS = $(SN1_BRAND_OBJS:%=$(OBJS_DIR)/%) LINTS = $(SN1_BRAND_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(USR_BRAND_DIR)/$(MODULE) @@ -50,9 +47,9 @@ include $(UTSBASE)/intel/Makefile.intel # # Define targets # -ALL_TARGET = $(OFFSETS_H) $(BINARY) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(OFFSETS_H) $(BINARY) $(ROOTMODULE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # @@ -94,12 +91,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -# -# Create genassym.h -# -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@ - # # Include common targets. # diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s index c04ceea2c9..8b63f25931 100644 --- a/usr/src/uts/sparc/ml/modstubs.s +++ b/usr/src/uts/sparc/ml/modstubs.s @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ #if !defined(lint) @@ -1296,6 +1295,18 @@ stubs_base: END_MODULE(ksocket); #endif +/* + * Stubs for elfexec + */ +#ifndef ELFEXEC_MODULE + MODULE(elfexec,exec); + STUB(elfexec, elfexec, nomod_einval); + STUB(elfexec, elf32exec, nomod_einval); + STUB(elfexec, mapexec_brand, nomod_einval); + STUB(elfexec, mapexec32_brand, nomod_einval); + END_MODULE(elfexec); +#endif + ! this is just a marker for the area of text that contains stubs .seg ".text" .global stubs_end diff --git a/usr/src/uts/sun4/brand/common/brand_solaris.s b/usr/src/uts/sun4/brand/common/brand_solaris.s new file mode 100644 index 0000000000..889218bc5f --- /dev/null +++ b/usr/src/uts/sun4/brand/common/brand_solaris.s @@ -0,0 +1,302 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * This is an assembly file that gets #include-ed into the brand-specific + * assembly files (e.g. sn1_brand_asm.s) for Solaris-derived brands. + * We can't make these into functions since in the trap context there's + * no easy place to save the extra parameters that would be required, so + * each brand module needs its own copy of this code. We #include this and + * use brand-specific #defines to replace the XXX_brand_... definitions. + */ + +#ifdef lint + +#include + +void +XXX_brand_syscall32_callback(void) +{ +} + +void +XXX_brand_syscall_callback(void) +{ +} + +#else /* !lint */ + +#include +#include +#include +#include "assym.h" + +#ifdef _ASM /* The remainder of this file is only for assembly files */ + +#if defined(sun4v) + +#define GLOBALS_SWAP(reg) \ + rdpr %gl, reg; \ + wrpr reg, 1, %gl + +/* + * The GLOBALS_RESTORE macro can only be one instruction since it's + * used in a delay slot. + */ +#define GLOBALS_RESTORE(reg) \ + wrpr reg, 0, %gl + +#else /* !sun4v */ + +#define GLOBALS_SWAP(reg) \ + rdpr %pstate, reg; \ + wrpr reg, PSTATE_AG, %pstate + +/* + * The GLOBALS_RESTORE macro can only be one instruction since it's + * used in a delay slot. + */ +#define GLOBALS_RESTORE(reg) \ + wrpr reg, %g0, %pstate + +#endif /* !sun4v */ + +/* + * Input parameters: + * %g1: return point + * %g2: pointer to our cpu structure + */ +ENTRY(XXX_brand_syscall32_callback) + /* + * If the trapping thread has the address mask bit clear, then it's + * a 64-bit process, and has no business calling 32-bit syscalls. + */ + rdpr %tstate, %g3; /* %tstate.am is the trapping */ + andcc %g3, TSTATE_AM, %g3; /* threads address mask bit */ + bne,pt %xcc, _entry; + nop; + jmp %g1; /* 64 bit process, bail out */ + nop; +SET_SIZE(XXX_brand_syscall32_callback) + +/* + * Input parameters: + * %g1: return point + * %g2: pointer to our cpu structure + */ +ENTRY(XXX_brand_syscall_callback) + /* + * If the trapping thread has the address mask bit set, then it's + * a 32-bit process, and has no business calling 64-bit syscalls. + */ + rdpr %tstate, %g3; /* %tstate.am is the trapping */ + andcc %g3, TSTATE_AM, %g3; /* threads address mask bit */ + be,pt %xcc, _entry; + nop; + jmp %g1; /* 32 bit process, bail out */ + nop; +SET_SIZE(XXX_brand_syscall_callback) + +ENTRY(XXX_brand_syscall_callback_common) +_entry: + /* + * Input parameters: + * %g1: return point + * %g2: pointer to our cpu structure + * + * Note that we're free to use any %g? registers as long as + * we are are executing with alternate globals. If we're + * executing with user globals we need to backup any registers + * that we want to use so that we can restore them when we're + * done. + * + * Save some locals in the CPU tmp area to give us a little + * room to work. + */ + stn %l0, [%g2 + CPU_TMP1]; + stn %l1, [%g2 + CPU_TMP2]; + +#if defined(sun4v) + /* + * On sun4v save our input parameters (which are stored in the + * alternate globals) since we'll need to switch between alternate + * globals and normal globals, and on sun4v the alternate globals + * are not preserved across these types of switches. + */ + stn %l2, [%g2 + CPU_TMP3]; + stn %l3, [%g2 + CPU_TMP4]; + + mov %g1, %l2; /* save %g1 in %l2 */ + mov %g2, %l3; /* save %g2 in %l3 */ +#endif /* sun4v */ + + /* + * Switch from the alternate to user globals to grab the syscall + * number. + */ + GLOBALS_SWAP(%l0); /* switch to normal globals */ + + /* + * If the system call number is >= 1024, then it is a native + * syscall that doesn't need emulation. + */ + cmp %g1, 1024; /* is this a native syscall? */ + bl,a _indirect_check; /* probably not, continue checking */ + mov %g1, %l1; /* delay slot - grab syscall number */ + + /* + * This is a native syscall, probably from the emulation library. + * Subtract 1024 from the syscall number and let it go through. + */ + sub %g1, 1024, %g1; /* convert magic num to real syscall */ + ba _exit; /* jump back into syscall path */ + GLOBALS_RESTORE(%l0); /* delay slot - */ + /* switch back to alternate globals */ + +_indirect_check: + /* + * If the system call number is 0 (SYS_syscall), then this might be + * an indirect syscall, in which case the actual syscall number + * would be stored in %o0, in which case we need to redo the + * the whole >= 1024 check. + */ + brnz,pt %g1, _emulation_check; /* is this an indirect syscall? */ + nop; /* if not, goto the emulation check */ + + /* + * Indirect syscalls are only supported for 32 bit processes so + * consult the tstate address mask again. + */ + rdpr %tstate, %l1; /* %tstate.am is the trapping */ + andcc %l1, TSTATE_AM, %l1; /* threads address mask bit */ + be,a,pn %xcc, _exit; + GLOBALS_RESTORE(%l0); /* delay slot - */ + /* switch back to alternate globals */ + + /* + * The caller is 32 bit and this an indirect system call. + */ + cmp %o0, 1024; /* is this a native syscall? */ + bl,a _emulation_check; /* no, goto the emulation check */ + mov %o0, %l1; /* delay slot - grab syscall number */ + + /* + * This is native indirect syscall, probably from the emulation + * library. Subtract 1024 from the syscall number and let it go + * through. + */ + sub %o0, 1024, %o0; /* convert magic num to real syscall */ + ba _exit; /* jump back into syscall path */ + GLOBALS_RESTORE(%l0); /* delay slot - */ + /* switch back to alternate globals */ + +_emulation_check: + GLOBALS_RESTORE(%l0); /* switch back to alternate globals */ + + /* + * Check to see if we want to interpose on this system call. If + * not, we jump back into the normal syscall path and pretend + * nothing happened. %l1 contains the syscall we're invoking. + */ + set XXX_emulation_table, %g3; + ldn [%g3], %g3; + add %g3, %l1, %g3; + ldub [%g3], %g3; + brz %g3, _exit; + nop; + + /* + * Find the address of the userspace handler. + * cpu->cpu_thread->t_procp->p_brand_data->spd_handler. + */ +#if defined(sun4v) + /* restore the alternate global registers after incrementing %gl */ + mov %l3, %g2; +#endif /* sun4v */ + ldn [%g2 + CPU_THREAD], %g3; /* get thread ptr */ + ldn [%g3 + T_PROCP], %g4; /* get proc ptr */ + ldn [%g4 + P_BRAND_DATA], %g5; /* get brand data ptr */ + ldn [%g5 + SPD_HANDLER], %g5; /* get userland brnd hdlr ptr */ + brz %g5, _exit; /* has it been set? */ + nop; + + /* + * Make sure this isn't an agent lwp. We can't do syscall + * interposition for system calls made by a agent lwp. See + * the block comments in the top of the brand emulation library + * for more information. + */ + ldn [%g4 + P_AGENTTP], %g4; /* get agent thread ptr */ + cmp %g3, %g4; /* is this an agent thread? */ + be,pn %xcc, _exit; /* if so don't emulate */ + nop; + + /* + * Now the magic happens. Grab the trap return address and then + * reset it to point to the user space handler. When we execute + * the 'done' instruction, we will jump into our handler instead of + * the user's code. We also stick the old return address in %g5, + * so we can return to the proper instruction in the user's code. + * Note: we also pass back the base address of the syscall + * emulation table. This is a performance hack to avoid having to + * look it up on every call. + */ + rdpr %tnpc, %l1; /* save old tnpc */ + wrpr %g0, %g5, %tnpc; /* setup tnpc */ + GLOBALS_SWAP(%l0); /* switch to normal globals */ + mov %l1, %g5; /* pass tnpc to user code in %g5 */ + GLOBALS_RESTORE(%l0); /* switch back to alternate globals */ + + /* Update the address we're going to return to */ +#if defined(sun4v) + set fast_trap_done_chk_intr, %l2; +#else /* !sun4v */ + set fast_trap_done_chk_intr, %g1; +#endif /* !sun4v */ + +_exit: + /* + * Restore registers before returning. + * + * Note that %g2 should be loaded with the CPU struct addr and + * %g1 should be loaded the address we're going to return to. + */ +#if defined(sun4v) + /* restore the alternate global registers after incrementing %gl */ + mov %l2, %g1; /* restore %g1 from %l2 */ + mov %l3, %g2; /* restore %g2 from %l3 */ + + ldn [%g2 + CPU_TMP4], %l3; /* restore locals */ + ldn [%g2 + CPU_TMP3], %l2; +#endif /* sun4v */ + + ldn [%g2 + CPU_TMP2], %l1; /* restore locals */ + ldn [%g2 + CPU_TMP1], %l0; + + jmp %g1; + nop; +SET_SIZE(XXX_brand_syscall_callback_common) + +#endif /* _ASM */ +#endif /* !lint */ diff --git a/usr/src/uts/sun4/brand/sn1/sn1_brand_asm.s b/usr/src/uts/sun4/brand/sn1/sn1_brand_asm.s index f1052a3332..b1af356944 100644 --- a/usr/src/uts/sun4/brand/sn1/sn1_brand_asm.s +++ b/usr/src/uts/sun4/brand/sn1/sn1_brand_asm.s @@ -19,272 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ -#if defined(lint) +#define XXX_emulation_table sn1_emulation_table +#define XXX_brand_syscall32_callback sn1_brand_syscall32_callback +#define XXX_brand_syscall_callback sn1_brand_syscall_callback +#define XXX_brand_syscall_callback_common sn1_brand_syscall_callback_common -#include - -void -sn1_brand_syscall32_callback(void) -{ -} - -void -sn1_brand_syscall_callback(void) -{ -} - -#else /* !lint */ - -#include -#include -#include -#include -#include "assym.h" - -#if defined(sun4v) - -#define GLOBALS_SWAP(reg) \ - rdpr %gl, reg ;\ - wrpr reg, 1, %gl - -/* - * The GLOBALS_RESTORE macro can only be one instruction since it's - * used in a delay slot. - */ -#define GLOBALS_RESTORE(reg) \ - wrpr reg, 0, %gl - -#else /* !sun4v */ - -#define GLOBALS_SWAP(reg) \ - rdpr %pstate, reg ;\ - wrpr reg, PSTATE_AG, %pstate - -/* - * The GLOBALS_RESTORE macro can only be one instruction since it's - * used in a delay slot. - */ -#define GLOBALS_RESTORE(reg) \ - wrpr reg, %g0, %pstate - -#endif /* !sun4v */ - - /* - * Input parameters: - * %g1: return point - * %g2: pointer to our cpu structure - */ - ENTRY(sn1_brand_syscall32_callback) - /* - * If the trapping thread has the address mask bit clear, then it's - * a 64-bit process, and has no business calling 32-bit syscalls. - */ - rdpr %tstate, %g3 ! %tstate.am is the trapping - andcc %g3, TSTATE_AM, %g3 ! threads address mask bit - bne,pt %xcc, _entry - nop - jmp %g1 ! 64 bit process, bail out - nop - SET_SIZE(sn1_brand_syscall32_callback) - - /* - * Input parameters: - * %g1: return point - * %g2: pointer to our cpu structure - */ - ENTRY(sn1_brand_syscall_callback) - /* - * If the trapping thread has the address mask bit set, then it's - * a 32-bit process, and has no business calling 64-bit syscalls. - */ - rdpr %tstate, %g3 ! %tstate.am is the trapping - andcc %g3, TSTATE_AM, %g3 ! threads address mask bit - be,pt %xcc, _entry - nop - jmp %g1 ! 32 bit process, bail out - nop - SET_SIZE(sn1_brand_syscall_callback) - - ENTRY(sn1_brand_syscall_callback_common) -_entry: - /* - * Input parameters: - * %g1: return point - * %g2: pointer to our cpu structure - * - * Note that we're free to use any %g? registers as long as - * we are are executing with alternate globals. If we're - * executing with user globals we need to backup any registers - * that we want to use so that we can restore them when we're - * done. - * - * Save some locals in the CPU tmp area to give us a little - * room to work. - */ - stn %l0, [%g2 + CPU_TMP1] - stn %l1, [%g2 + CPU_TMP2] - -#if defined(sun4v) - /* - * On sun4v save our input parameters (which are stored in the - * alternate globals) since we'll need to switch between alternate - * globals and normal globals, and on sun4v the alternate globals - * are not preserved across these types of switches. - */ - stn %l2, [%g2 + CPU_TMP3] - stn %l3, [%g2 + CPU_TMP4] - - mov %g1, %l2 ! save %g1 in %l2 - mov %g2, %l3 ! save %g2 in %l3 -#endif /* sun4v */ - - /* - * Switch from the alternate to user globals to grab the syscall - * number. - */ - GLOBALS_SWAP(%l0) ! switch to normal globals - - /* - * If the system call number is >= 1024, then it is a native - * syscall that doesn't need emulation. - */ - cmp %g1, 1024 ! is this a native syscall? - bl,a _indirect_check ! probably not, continue checking - mov %g1, %l1 ! delay slot - grab syscall number - - /* - * This is a native syscall, probably from the emulation library. - * Subtract 1024 from the syscall number and let it go through. - */ - sub %g1, 1024, %g1 ! convert magic num to real syscall - ba _exit ! jump back into syscall path - GLOBALS_RESTORE(%l0) ! delay slot - - ! switch back to alternate globals - -_indirect_check: - /* - * If the system call number is 0 (SYS_syscall), then this might be - * an indirect syscall, in which case the actual syscall number - * would be stored in %o0, in which case we need to redo the - * the whole >= 1024 check. - */ - brnz,pt %g1, _emulation_check ! is this an indirect syscall? - nop ! if not, goto the emulation check - - /* - * Indirect syscalls are only supported for 32 bit processes so - * consult the tstate address mask again. - */ - rdpr %tstate, %l1 ! %tstate.am is the trapping - andcc %l1, TSTATE_AM, %l1 ! threads address mask bit - be,a,pn %xcc, _exit - GLOBALS_RESTORE(%l0) ! delay slot - - ! switch back to alternate globals - - /* - * The caller is 32 bit and this an indirect system call. - */ - cmp %o0, 1024 ! is this a native syscall? - bl,a _emulation_check ! no, goto the emulation check - mov %o0, %l1 ! delay slot - grab syscall number - - /* - * This is native indirect syscall, probably from the emulation library. - * Subtract 1024 from the syscall number and let it go through. - */ - sub %o0, 1024, %o0 ! convert magic num to real syscall - ba _exit ! jump back into syscall path - GLOBALS_RESTORE(%l0) ! delay slot - - ! switch back to alternate globals - -_emulation_check: - GLOBALS_RESTORE(%l0) ! switch back to alternate globals - - /* - * Check to see if we want to interpose on this system call. If - * not, we jump back into the normal syscall path and pretend - * nothing happened. %l1 contains the syscall we're invoking. - */ - set sn1_emulation_table, %g3 - ldn [%g3], %g3 - add %g3, %l1, %g3 - ldub [%g3], %g3 - brz %g3, _exit - nop - - /* - * Find the address of the userspace handler. - * cpu->cpu_thread->t_procp->p_brand_data->spd_handler. - */ -#if defined(sun4v) - ! restore the alternate global registers after incrementing %gl - mov %l3, %g2 -#endif /* sun4v */ - ldn [%g2 + CPU_THREAD], %g3 ! get thread ptr - ldn [%g3 + T_PROCP], %g4 ! get proc ptr - ldn [%g4 + P_BRAND_DATA], %g5 ! get brand data ptr - ldn [%g5 + SPD_HANDLER], %g5 ! get userland brand handler ptr - brz %g5, _exit ! has it been set? - nop - - /* - * Make sure this isn't an agent lwp. We can't do syscall - * interposition for system calls made by a agent lwp. See - * the block comments in the top of the brand emulation library - * for more information. - */ - ldn [%g4 + P_AGENTTP], %g4 ! get agent thread ptr - cmp %g3, %g4 ! is this an agent thread? - be,pn %xcc, _exit ! if so don't emulate - nop - - /* - * Now the magic happens. Grab the trap return address and then - * reset it to point to the user space handler. When we execute - * the 'done' instruction, we will jump into our handler instead of - * the user's code. We also stick the old return address in %g5, - * so we can return to the proper instruction in the user's code. - * Note: we also pass back the base address of the syscall - * emulation table. This is a performance hack to avoid having to - * look it up on every call. - */ - rdpr %tnpc, %l1 ! save old tnpc - wrpr %g0, %g5, %tnpc ! setup tnpc - GLOBALS_SWAP(%l0) ! switch to normal globals - mov %l1, %g5 ! pass tnpc to user code in %g5 - GLOBALS_RESTORE(%l0) ! switch back to alternate globals - - /* Update the address we're going to return to */ -#if defined(sun4v) - set fast_trap_done_chk_intr, %l2 -#else /* !sun4v */ - set fast_trap_done_chk_intr, %g1 -#endif /* !sun4v */ - -_exit: - /* - * Restore registers before returning. - * - * Note that %g2 should be loaded with the CPU struct addr and - * %g1 should be loaded the address we're going to return to. - */ -#if defined(sun4v) - ! restore the alternate global registers after incrementing %gl - mov %l2, %g1 ! restore %g1 from %l2 - mov %l3, %g2 ! restore %g2 from %l3 - - ldn [%g2 + CPU_TMP4], %l3 ! restore locals - ldn [%g2 + CPU_TMP3], %l2 -#endif /* sun4v */ - - ldn [%g2 + CPU_TMP2], %l1 ! restore locals - ldn [%g2 + CPU_TMP1], %l0 - - jmp %g1 - nop - SET_SIZE(sn1_brand_syscall_callback_common) -#endif /* !lint */ +#include "../common/brand_solaris.s" diff --git a/usr/src/uts/sun4/brand/solaris10/s10_brand_asm.s b/usr/src/uts/sun4/brand/solaris10/s10_brand_asm.s index 9ab99b225c..7fd817bac6 100644 --- a/usr/src/uts/sun4/brand/solaris10/s10_brand_asm.s +++ b/usr/src/uts/sun4/brand/solaris10/s10_brand_asm.s @@ -19,272 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ -#if defined(lint) +#define XXX_emulation_table s10_emulation_table +#define XXX_brand_syscall32_callback s10_brand_syscall32_callback +#define XXX_brand_syscall_callback s10_brand_syscall_callback +#define XXX_brand_syscall_callback_common s10_brand_syscall_callback_common -#include - -void -s10_brand_syscall32_callback(void) -{ -} - -void -s10_brand_syscall_callback(void) -{ -} - -#else /* !lint */ - -#include -#include -#include -#include -#include "assym.h" - -#if defined(sun4v) - -#define GLOBALS_SWAP(reg) \ - rdpr %gl, reg ;\ - wrpr reg, 1, %gl - -/* - * The GLOBALS_RESTORE macro can only be one instruction since it's - * used in a delay slot. - */ -#define GLOBALS_RESTORE(reg) \ - wrpr reg, 0, %gl - -#else /* !sun4v */ - -#define GLOBALS_SWAP(reg) \ - rdpr %pstate, reg ;\ - wrpr reg, PSTATE_AG, %pstate - -/* - * The GLOBALS_RESTORE macro can only be one instruction since it's - * used in a delay slot. - */ -#define GLOBALS_RESTORE(reg) \ - wrpr reg, %g0, %pstate - -#endif /* !sun4v */ - - /* - * Input parameters: - * %g1: return point - * %g2: pointer to our cpu structure - */ - ENTRY(s10_brand_syscall32_callback) - /* - * If the trapping thread has the address mask bit clear, then it's - * a 64-bit process, and has no business calling 32-bit syscalls. - */ - rdpr %tstate, %g3 ! %tstate.am is the trapping - andcc %g3, TSTATE_AM, %g3 ! threads address mask bit - bne,pt %xcc, _entry - nop - jmp %g1 ! 64 bit process, bail out - nop - SET_SIZE(s10_brand_syscall32_callback) - - /* - * Input parameters: - * %g1: return point - * %g2: pointer to our cpu structure - */ - ENTRY(s10_brand_syscall_callback) - /* - * If the trapping thread has the address mask bit set, then it's - * a 32-bit process, and has no business calling 64-bit syscalls. - */ - rdpr %tstate, %g3 ! %tstate.am is the trapping - andcc %g3, TSTATE_AM, %g3 ! threads address mask bit - be,pt %xcc, _entry - nop - jmp %g1 ! 32 bit process, bail out - nop - SET_SIZE(s10_brand_syscall_callback) - - ENTRY(s10_brand_syscall_callback_common) -_entry: - /* - * Input parameters: - * %g1: return point - * %g2: pointer to our cpu structure - * - * Note that we're free to use any %g? registers as long as - * we are are executing with alternate globals. If we're - * executing with user globals we need to backup any registers - * that we want to use so that we can restore them when we're - * done. - * - * Save some locals in the CPU tmp area to give us a little - * room to work. - */ - stn %l0, [%g2 + CPU_TMP1] - stn %l1, [%g2 + CPU_TMP2] - -#if defined(sun4v) - /* - * On sun4v save our input parameters (which are stored in the - * alternate globals) since we'll need to switch between alternate - * globals and normal globals, and on sun4v the alternate globals - * are not preserved across these types of switches. - */ - stn %l2, [%g2 + CPU_TMP3] - stn %l3, [%g2 + CPU_TMP4] - - mov %g1, %l2 ! save %g1 in %l2 - mov %g2, %l3 ! save %g2 in %l3 -#endif /* sun4v */ - - /* - * Switch from the alternate to user globals to grab the syscall - * number. - */ - GLOBALS_SWAP(%l0) ! switch to normal globals - - /* - * If the system call number is >= 1024, then it is a native - * syscall that doesn't need emulation. - */ - cmp %g1, 1024 ! is this a native syscall? - bl,a _indirect_check ! probably not, continue checking - mov %g1, %l1 ! delay slot - grab syscall number - - /* - * This is a native syscall, probably from the emulation library. - * Subtract 1024 from the syscall number and let it go through. - */ - sub %g1, 1024, %g1 ! convert magic num to real syscall - ba _exit ! jump back into syscall path - GLOBALS_RESTORE(%l0) ! delay slot - - ! switch back to alternate globals - -_indirect_check: - /* - * If the system call number is 0 (SYS_syscall), then this might be - * an indirect syscall, in which case the actual syscall number - * would be stored in %o0, in which case we need to redo the - * the whole >= 1024 check. - */ - brnz,pt %g1, _emulation_check ! is this an indirect syscall? - nop ! if not, goto the emulation check - - /* - * Indirect syscalls are only supported for 32 bit processes so - * consult the tstate address mask again. - */ - rdpr %tstate, %l1 ! %tstate.am is the trapping - andcc %l1, TSTATE_AM, %l1 ! threads address mask bit - be,a,pn %xcc, _exit - GLOBALS_RESTORE(%l0) ! delay slot - - ! switch back to alternate globals - - /* - * The caller is 32 bit and this an indirect system call. - */ - cmp %o0, 1024 ! is this a native syscall? - bl,a _emulation_check ! no, goto the emulation check - mov %o0, %l1 ! delay slot - grab syscall number - - /* - * This is native indirect syscall, probably from the emulation library. - * Subtract 1024 from the syscall number and let it go through. - */ - sub %o0, 1024, %o0 ! convert magic num to real syscall - ba _exit ! jump back into syscall path - GLOBALS_RESTORE(%l0) ! delay slot - - ! switch back to alternate globals - -_emulation_check: - GLOBALS_RESTORE(%l0) ! switch back to alternate globals - - /* - * Check to see if we want to interpose on this system call. If - * not, we jump back into the normal syscall path and pretend - * nothing happened. %l1 contains the syscall we're invoking. - */ - set s10_emulation_table, %g3 - ldn [%g3], %g3 - add %g3, %l1, %g3 - ldub [%g3], %g3 - brz %g3, _exit - nop - - /* - * Find the address of the userspace handler. - * cpu->cpu_thread->t_procp->p_brand_data->spd_handler. - */ -#if defined(sun4v) - ! restore the alternate global registers after incrementing %gl - mov %l3, %g2 -#endif /* sun4v */ - ldn [%g2 + CPU_THREAD], %g3 ! get thread ptr - ldn [%g3 + T_PROCP], %g4 ! get proc ptr - ldn [%g4 + P_BRAND_DATA], %g5 ! get brand data ptr - ldn [%g5 + SPD_HANDLER], %g5 ! get userland brand handler ptr - brz %g5, _exit ! has it been set? - nop - - /* - * Make sure this isn't an agent lwp. We can't do syscall - * interposition for system calls made by a agent lwp. See - * the block comments in the top of the brand emulation library - * for more information. - */ - ldn [%g4 + P_AGENTTP], %g4 ! get agent thread ptr - cmp %g3, %g4 ! is this an agent thread? - be,pn %xcc, _exit ! if so don't emulate - nop - - /* - * Now the magic happens. Grab the trap return address and then - * reset it to point to the user space handler. When we execute - * the 'done' instruction, we will jump into our handler instead of - * the user's code. We also stick the old return address in %g5, - * so we can return to the proper instruction in the user's code. - * Note: we also pass back the base address of the syscall - * emulation table. This is a performance hack to avoid having to - * look it up on every call. - */ - rdpr %tnpc, %l1 ! save old tnpc - wrpr %g0, %g5, %tnpc ! setup tnpc - GLOBALS_SWAP(%l0) ! switch to normal globals - mov %l1, %g5 ! pass tnpc to user code in %g5 - GLOBALS_RESTORE(%l0) ! switch back to alternate globals - - /* Update the address we're going to return to */ -#if defined(sun4v) - set fast_trap_done_chk_intr, %l2 -#else /* !sun4v */ - set fast_trap_done_chk_intr, %g1 -#endif /* !sun4v */ - -_exit: - /* - * Restore registers before returning. - * - * Note that %g2 should be loaded with the CPU struct addr and - * %g1 should be loaded the address we're going to return to. - */ -#if defined(sun4v) - ! restore the alternate global registers after incrementing %gl - mov %l2, %g1 ! restore %g1 from %l2 - mov %l3, %g2 ! restore %g2 from %l3 - - ldn [%g2 + CPU_TMP4], %l3 ! restore locals - ldn [%g2 + CPU_TMP3], %l2 -#endif /* sun4v */ - - ldn [%g2 + CPU_TMP2], %l1 ! restore locals - ldn [%g2 + CPU_TMP1], %l0 - - jmp %g1 - nop - SET_SIZE(s10_brand_syscall_callback_common) -#endif /* !lint */ +#include "../common/brand_solaris.s" diff --git a/usr/src/uts/sun4/ml/offsets.in b/usr/src/uts/sun4/ml/offsets.in index c4ce99506e..974c48672e 100644 --- a/usr/src/uts/sun4/ml/offsets.in +++ b/usr/src/uts/sun4/ml/offsets.in @@ -1,6 +1,5 @@ \ offsets.in: input file to produce assym.h using the stabs program -\ Copyright 2009 Sun Microsystems, Inc. All rights reserved. -\ Use is subject to license terms. +\ Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. \ \ CDDL HEADER START \ @@ -555,3 +554,6 @@ copyops brand BRAND_SIZE b_machops + +brand_proc_data_t + spd_handler diff --git a/usr/src/uts/sun4u/s10_brand/Makefile b/usr/src/uts/sun4u/s10_brand/Makefile index 9d2c189970..6fdde88f6a 100644 --- a/usr/src/uts/sun4u/s10_brand/Makefile +++ b/usr/src/uts/sun4u/s10_brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # This makefile drives the production of the kernel component of # the Solaris 10 brand @@ -36,8 +35,6 @@ S10_BASE = $(UTSBASE)/common/brand/solaris10 # Define the module and object file sets. # MODULE = s10_brand -OFFSETS_H = $(OBJS_DIR)/s10_offsets.h -OFFSETS_SRC = $(S10_BASE)/s10_offsets.in OBJECTS = $(S10_BRAND_OBJS:%=$(OBJS_DIR)/%) LINTS = $(S10_BRAND_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_PSM_BRAND_DIR)/$(MODULE) @@ -50,9 +47,9 @@ include $(UTSBASE)/sun4u/Makefile.sun4u # # Define targets # -ALL_TARGET = $(OFFSETS_H) $(BINARY) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(OFFSETS_H) $(BINARY) $(ROOTMODULE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # # Update compiler variables. @@ -81,12 +78,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -# -# Create genassym.h -# -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@ - # # Include common targets. # diff --git a/usr/src/uts/sun4u/sn1_brand/Makefile b/usr/src/uts/sun4u/sn1_brand/Makefile index ad7b808e02..135ee8667b 100644 --- a/usr/src/uts/sun4u/sn1_brand/Makefile +++ b/usr/src/uts/sun4u/sn1_brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # This makefile drives the production of the kernel component of # the N-1 Solaris brand @@ -36,8 +35,6 @@ SN1_BASE = $(UTSBASE)/common/brand/sn1 # Define the module and object file sets. # MODULE = sn1_brand -OFFSETS_H = $(OBJS_DIR)/sn1_offsets.h -OFFSETS_SRC = $(SN1_BASE)/sn1_offsets.in OBJECTS = $(SN1_BRAND_OBJS:%=$(OBJS_DIR)/%) LINTS = $(SN1_BRAND_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_PSM_BRAND_DIR)/$(MODULE) @@ -50,9 +47,9 @@ include $(UTSBASE)/sun4u/Makefile.sun4u # # Define targets # -ALL_TARGET = $(OFFSETS_H) $(BINARY) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(OFFSETS_H) $(BINARY) $(ROOTMODULE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # # Update compiler variables. @@ -81,12 +78,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -# -# Create genassym.h -# -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@ - # # Include common targets. # diff --git a/usr/src/uts/sun4v/s10_brand/Makefile b/usr/src/uts/sun4v/s10_brand/Makefile index c034010201..acdd849a3f 100644 --- a/usr/src/uts/sun4v/s10_brand/Makefile +++ b/usr/src/uts/sun4v/s10_brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # This makefile drives the production of the kernel component of # the Solaris 10 brand @@ -36,8 +35,6 @@ S10_BASE = $(UTSBASE)/common/brand/solaris10 # Define the module and object file sets. # MODULE = s10_brand -OFFSETS_H = $(OBJS_DIR)/s10_offsets.h -OFFSETS_SRC = $(S10_BASE)/s10_offsets.in OBJECTS = $(S10_BRAND_OBJS:%=$(OBJS_DIR)/%) LINTS = $(S10_BRAND_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_PSM_BRAND_DIR)/$(MODULE) @@ -50,9 +47,9 @@ include $(UTSBASE)/sun4v/Makefile.sun4v # # Define targets # -ALL_TARGET = $(OFFSETS_H) $(BINARY) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(OFFSETS_H) $(BINARY) $(ROOTMODULE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # # Update compiler variables. @@ -81,12 +78,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -# -# Create genassym.h -# -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@ - # # Include common targets. # diff --git a/usr/src/uts/sun4v/sn1_brand/Makefile b/usr/src/uts/sun4v/sn1_brand/Makefile index 6a9dc5e1af..bea8c2527e 100644 --- a/usr/src/uts/sun4v/sn1_brand/Makefile +++ b/usr/src/uts/sun4v/sn1_brand/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # This makefile drives the production of the kernel component of # the N-1 Solaris brand @@ -36,8 +35,6 @@ SN1_BASE = $(UTSBASE)/common/brand/sn1 # Define the module and object file sets. # MODULE = sn1_brand -OFFSETS_H = $(OBJS_DIR)/sn1_offsets.h -OFFSETS_SRC = $(SN1_BASE)/sn1_offsets.in OBJECTS = $(SN1_BRAND_OBJS:%=$(OBJS_DIR)/%) LINTS = $(SN1_BRAND_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_PSM_BRAND_DIR)/$(MODULE) @@ -50,9 +47,9 @@ include $(UTSBASE)/sun4v/Makefile.sun4v # # Define targets # -ALL_TARGET = $(OFFSETS_H) $(BINARY) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(OFFSETS_H) $(BINARY) $(ROOTMODULE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # # Update compiler variables. @@ -81,12 +78,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -# -# Create genassym.h -# -$(OFFSETS_H): $(OFFSETS_SRC) - $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@ - # # Include common targets. # -- cgit v1.2.3