diff options
Diffstat (limited to 'src/arch/x86')
126 files changed, 8165 insertions, 2146 deletions
diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index 674cd54c2..4c0460e28 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -86,6 +86,7 @@ Import('*') if env['TARGET_ISA'] == 'x86': + Source('cpuid.cc') Source('emulenv.cc') Source('floatregfile.cc') Source('faults.cc') @@ -105,16 +106,22 @@ if env['TARGET_ISA'] == 'x86': Source('utility.cc') SimObject('X86TLB.py') - TraceFlag('Predecoder') - TraceFlag('X86') + TraceFlag('Predecoder', "Predecoder debug output") + TraceFlag('X86', "Generic X86 ISA debugging") if env['FULL_SYSTEM']: + TraceFlag('LocalApic', "Local APIC debugging") + TraceFlag('PageTableWalker', \ + "Page table walker state machine debugging") + TraceFlag('Faults', "Trace all faults/exceptions/traps") + + SimObject('X86LocalApic.py') SimObject('X86System.py') # Full-system sources + Source('interrupts.cc') Source('linux/system.cc') Source('pagetable_walker.cc') - Source('smbios.cc') Source('system.cc') Source('stacktrace.cc') Source('vtophys.cc') @@ -170,7 +177,6 @@ if env['TARGET_ISA'] == 'x86': 'general_purpose/load_segment_registers.py', 'general_purpose/logical.py', 'general_purpose/no_operation.py', - 'general_purpose/processor_information.py', 'general_purpose/rotate_and_shift/__init__.py', 'general_purpose/rotate_and_shift/rotate.py', 'general_purpose/rotate_and_shift/shift.py', @@ -182,7 +188,9 @@ if env['TARGET_ISA'] == 'x86': 'general_purpose/string/scan_string.py', 'general_purpose/string/store_string.py', 'general_purpose/system_calls.py', + 'romutil.py', 'system/__init__.py', + 'system/control_registers.py', 'system/halt.py', 'system/invlpg.py', 'system/undefined_operation.py', diff --git a/src/arch/x86/SConsopts b/src/arch/x86/SConsopts index d8b7cbed1..f8b700271 100644 --- a/src/arch/x86/SConsopts +++ b/src/arch/x86/SConsopts @@ -3,43 +3,16 @@ # Copyright (c) 2007 The Hewlett-Packard Development Company # All rights reserved. # -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the -# following conditions are met: -# -# The software must be used only for Non-Commercial Use which means any -# use which is NOT directed to receiving any direct monetary -# compensation for, or commercial advantage from such use. Illustrative -# examples of non-commercial use are academic research, personal study, -# teaching, education and corporate research & development. -# Illustrative examples of commercial use are distributing products for -# commercial advantage and providing services using the software for -# commercial advantage. -# -# If you wish to use this software or functionality therein that may be -# covered by patents for commercial use, please contact: -# Director of Intellectual Property Licensing -# Office of Strategy and Technology -# Hewlett-Packard Company -# 1501 Page Mill Road -# Palo Alto, California 94304 -# -# Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. Redistributions -# in binary form must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. Neither the name of -# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. No right of -# sublicense is granted herewith. Derivatives of the software and -# output created using the software may be prepared, but only for -# Non-Commercial Uses. Derivatives of the software may be shared with -# others provided: (i) the others agree to abide by the list of -# conditions herein which includes the Non-Commercial Use restrictions; -# and (ii) such Derivatives of the software include the above copyright -# notice to acknowledge the contribution from this software where -# applicable, this list of conditions and the disclaimer below. +# this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT diff --git a/src/arch/x86/X86LocalApic.py b/src/arch/x86/X86LocalApic.py new file mode 100644 index 000000000..483c65ef8 --- /dev/null +++ b/src/arch/x86/X86LocalApic.py @@ -0,0 +1,36 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from Device import BasicPioDevice + +class X86LocalApic(BasicPioDevice): + type = 'X86LocalApic' + cxx_class = 'X86ISA::Interrupts' + pio_latency = Param.Latency('1ns', 'Programmed IO latency in simticks') + int_port = Port("Port for sending and receiving interrupt messages") diff --git a/src/arch/x86/X86System.py b/src/arch/x86/X86System.py index f73764540..527831205 100644 --- a/src/arch/x86/X86System.py +++ b/src/arch/x86/X86System.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -54,10 +54,27 @@ # Authors: Gabe Black from m5.params import * +from E820 import X86E820Table, X86E820Entry +from SMBios import X86SMBiosSMBiosTable +from IntelMP import X86IntelMPFloatingPointer, X86IntelMPConfigTable +from ACPI import X86ACPIRSDP from System import System class X86System(System): type = 'X86System' + smbios_table = Param.X86SMBiosSMBiosTable( + X86SMBiosSMBiosTable(), 'table of smbios/dmi information') + intel_mp_pointer = Param.X86IntelMPFloatingPointer( + X86IntelMPFloatingPointer(), + 'intel mp spec floating pointer structure') + intel_mp_table = Param.X86IntelMPConfigTable( + X86IntelMPConfigTable(), + 'intel mp spec configuration table') + acpi_description_table_pointer = Param.X86ACPIRSDP( + X86ACPIRSDP(), 'ACPI root description pointer structure') class LinuxX86System(X86System): type = 'LinuxX86System' + + e820_table = Param.X86E820Table( + X86E820Table(), 'E820 map of physical memory') diff --git a/src/arch/x86/X86TLB.py b/src/arch/x86/X86TLB.py index dc080f37e..d5ae95372 100644 --- a/src/arch/x86/X86TLB.py +++ b/src/arch/x86/X86TLB.py @@ -54,23 +54,20 @@ # Authors: Gabe Black from MemObject import MemObject -from m5.SimObject import SimObject from m5.params import * from m5.proxy import * from m5 import build_env +from BaseTLB import BaseTLB if build_env['FULL_SYSTEM']: class X86PagetableWalker(MemObject): type = 'X86PagetableWalker' - cxx_namespace = 'X86ISA' - cxx_class = 'Walker' + cxx_class = 'X86ISA::Walker' port = Port("Port for the hardware table walker") system = Param.System(Parent.any, "system object") -class X86TLB(SimObject): +class X86TLB(BaseTLB): type = 'X86TLB' - cxx_namespace = 'X86ISA' - cxx_class = 'TLB' abstract = True size = Param.Int("TLB size") if build_env['FULL_SYSTEM']: @@ -79,14 +76,10 @@ class X86TLB(SimObject): class X86DTB(X86TLB): type = 'X86DTB' - cxx_namespace = 'X86ISA' - cxx_class = 'DTB' - + cxx_class = 'X86ISA::DTB' size = 64 class X86ITB(X86TLB): type = 'X86ITB' - cxx_namespace = 'X86ISA' - cxx_class = 'ITB' - + cxx_class = 'X86ISA::ITB' size = 64 diff --git a/src/arch/x86/apicregs.hh b/src/arch/x86/apicregs.hh new file mode 100644 index 000000000..464c3af2d --- /dev/null +++ b/src/arch/x86/apicregs.hh @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_APICREGS_HH__ +#define __ARCH_X86_APICREGS_HH__ + +namespace X86ISA +{ + enum ApicRegIndex + { + APIC_ID, + APIC_VERSION, + APIC_TASK_PRIORITY, + APIC_ARBITRATION_PRIORITY, + APIC_PROCESSOR_PRIORITY, + APIC_EOI, + APIC_LOGICAL_DESTINATION, + APIC_DESTINATION_FORMAT, + APIC_SPURIOUS_INTERRUPT_VECTOR, + + APIC_IN_SERVICE_BASE, + + APIC_TRIGGER_MODE_BASE = APIC_IN_SERVICE_BASE + 16, + + APIC_INTERRUPT_REQUEST_BASE = APIC_TRIGGER_MODE_BASE + 16, + + APIC_ERROR_STATUS = APIC_INTERRUPT_REQUEST_BASE + 16, + APIC_INTERRUPT_COMMAND_LOW, + APIC_INTERRUPT_COMMAND_HIGH, + APIC_LVT_TIMER, + APIC_LVT_THERMAL_SENSOR, + APIC_LVT_PERFORMANCE_MONITORING_COUNTERS, + APIC_LVT_LINT0, + APIC_LVT_LINT1, + APIC_LVT_ERROR, + APIC_INITIAL_COUNT, + APIC_CURRENT_COUNT, + APIC_DIVIDE_CONFIGURATION, + + APIC_INTERNAL_STATE, + + NUM_APIC_REGS + }; + + static inline ApicRegIndex + APIC_IN_SERVICE(int index) + { + return (ApicRegIndex)(APIC_IN_SERVICE_BASE + index); + } + + static inline ApicRegIndex + APIC_TRIGGER_MODE(int index) + { + return (ApicRegIndex)(APIC_TRIGGER_MODE_BASE + index); + } + + static inline ApicRegIndex + APIC_INTERRUPT_REQUEST(int index) + { + return (ApicRegIndex)(APIC_INTERRUPT_REQUEST_BASE + index); + } +} + +#endif diff --git a/src/arch/x86/bios/ACPI.py b/src/arch/x86/bios/ACPI.py new file mode 100644 index 000000000..6f7cae946 --- /dev/null +++ b/src/arch/x86/bios/ACPI.py @@ -0,0 +1,99 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +# ACPI description table header. Subclasses contain and handle the actual +# contents as appropriate for that type of table. +class X86ACPISysDescTable(SimObject): + type = 'X86ACPISysDescTable' + cxx_class = 'X86ISA::ACPI::SysDescTable' + abstract = True + + oem_id = Param.String('', 'string identifying the oem') + oem_table_id = Param.String('', 'oem table ID') + oem_revision = Param.UInt32(0, 'oem revision number for the table') + + creator_id = Param.String('', + 'string identifying the generator of the table') + creator_revision = Param.UInt32(0, + 'revision number for the creator of the table') + +class X86ACPIRSDT(X86ACPISysDescTable): + type = 'X86ACPIRSDT' + cxx_class = 'X86ISA::ACPI::RSDT' + + entries = VectorParam.X86ACPISysDescTable([], 'system description tables') + +class X86ACPIXSDT(X86ACPISysDescTable): + type = 'X86ACPIXSDT' + cxx_class = 'X86ISA::ACPI::XSDT' + + entries = VectorParam.X86ACPISysDescTable([], 'system description tables') + +# Root System Description Pointer Structure +class X86ACPIRSDP(SimObject): + type = 'X86ACPIRSDP' + cxx_class = 'X86ISA::ACPI::RSDP' + + oem_id = Param.String('', 'string identifying the oem') + # Because 0 encodes ACPI 1.0, 2 encodes ACPI 3.0, the version implemented + # here. + revision = Param.UInt8(2, 'revision of ACPI being used, zero indexed') + + rsdt = Param.X86ACPIRSDT(NULL, 'root system description table') + xsdt = Param.X86ACPIXSDT(X86ACPIXSDT(), + 'extended system description table') diff --git a/src/arch/x86/bios/E820.py b/src/arch/x86/bios/E820.py new file mode 100644 index 000000000..288c253fb --- /dev/null +++ b/src/arch/x86/bios/E820.py @@ -0,0 +1,71 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +class X86E820Entry(SimObject): + type = 'X86E820Entry' + cxx_class = 'X86ISA::E820Entry' + + addr = Param.Addr(0, 'address of the beginning of the region') + size = Param.MemorySize('0B', 'size of the region') + range_type = Param.UInt64('type of the region') + +class X86E820Table(SimObject): + type = 'X86E820Table' + cxx_class = 'X86ISA::E820Table' + + entries = VectorParam.X86E820Entry([], 'entries for the e820 table') diff --git a/src/arch/x86/bios/IntelMP.py b/src/arch/x86/bios/IntelMP.py new file mode 100644 index 000000000..04e79b6ac --- /dev/null +++ b/src/arch/x86/bios/IntelMP.py @@ -0,0 +1,242 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +class X86IntelMPFloatingPointer(SimObject): + type = 'X86IntelMPFloatingPointer' + cxx_class = 'X86ISA::IntelMP::FloatingPointer' + + # The minor revision of the spec to support. The major version is assumed + # to be 1 in accordance with the spec. + spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported') + # If no default configuration is used, set this to 0. + default_config = Param.UInt8(0, 'which default configuration to use') + imcr_present = Param.Bool(True, + 'whether the IMCR register is present in the APIC') + +class X86IntelMPConfigTable(SimObject): + type = 'X86IntelMPConfigTable' + cxx_class = 'X86ISA::IntelMP::ConfigTable' + + spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported') + oem_id = Param.String("", 'system manufacturer') + product_id = Param.String("", 'product family') + oem_table_addr = Param.UInt32(0, + 'pointer to the optional oem configuration table') + oem_table_size = Param.UInt16(0, 'size of the oem configuration table') + local_apic = Param.UInt32(0xFEE00000, 'address of the local APIC') + + base_entries = VectorParam.X86IntelMPBaseConfigEntry([], + 'base configuration table entries') + + ext_entries = VectorParam.X86IntelMPExtConfigEntry([], + 'extended configuration table entries') + + def add_entry(self, entry): + if isinstance(entry, X86IntelMPBaseConfigEntry): + self.base_entries.append(entry) + elif isinstance(entry, X86IntelMPExtConfigEntry): + self.ext_entries.append(entry) + else: + panic("Don't know what type of Intel MP entry %s is." \ + % entry.__class__.__name__) + +class X86IntelMPBaseConfigEntry(SimObject): + type = 'X86IntelMPBaseConfigEntry' + cxx_class = 'X86ISA::IntelMP::BaseConfigEntry' + abstract = True + +class X86IntelMPExtConfigEntry(SimObject): + type = 'X86IntelMPExtConfigEntry' + cxx_class = 'X86ISA::IntelMP::ExtConfigEntry' + abstract = True + +class X86IntelMPProcessor(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPProcessor' + cxx_class = 'X86ISA::IntelMP::Processor' + + local_apic_id = Param.UInt8(0, 'local APIC id') + local_apic_version = Param.UInt8(0, + 'bits 0-7 of the local APIC version register') + enable = Param.Bool(True, 'if this processor is usable') + bootstrap = Param.Bool(False, 'if this is the bootstrap processor') + + stepping = Param.UInt8(0, 'Processor stepping') + model = Param.UInt8(0, 'Processor model') + family = Param.UInt8(0, 'Processor family') + + feature_flags = Param.UInt32(0, 'flags returned by the CPUID instruction') + +class X86IntelMPBus(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPBus' + cxx_class = 'X86ISA::IntelMP::Bus' + + bus_id = Param.UInt8(0, 'bus id assigned by the bios') + bus_type = Param.String("", 'string that identify the bus type') + # Legal values for bus_type are: + # + # "CBUS", "CBUSII", "EISA", "FUTURE", "INTERN", "ISA", "MBI", "MBII", + # "MCA", "MPI", "MPSA", "NUBUS", "PCI", "PCMCIA", "TC", "VL", "VME", + # "XPRESS" + +class X86IntelMPIOAPIC(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPIOAPIC' + cxx_class = 'X86ISA::IntelMP::IOAPIC' + + id = Param.UInt8(0, 'id of this APIC') + version = Param.UInt8(0, 'bits 0-7 of the version register') + + enable = Param.Bool(True, 'if this APIC is usable') + + address = Param.UInt32(0xfec00000, 'address of this APIC') + +class X86IntelMPInterruptType(Enum): + map = {'INT' : 0, + 'NMI' : 1, + 'SMI' : 2, + 'ExtInt' : 3 + } + +class X86IntelMPPolarity(Enum): + map = {'ConformPolarity' : 0, + 'ActiveHigh' : 1, + 'ActiveLow' : 3 + } + +class X86IntelMPTriggerMode(Enum): + map = {'ConformTrigger' : 0, + 'EdgeTrigger' : 1, + 'LevelTrigger' : 3 + } + +class X86IntelMPIOIntAssignment(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPIOIntAssignment' + cxx_class = 'X86ISA::IntelMP::IOIntAssignment' + + interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt') + + polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity') + trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode') + + source_bus_id = Param.UInt8(0, + 'id of the bus from which the interrupt signal comes') + source_bus_irq = Param.UInt8(0, + 'which interrupt signal from the source bus') + + dest_io_apic_id = Param.UInt8(0, + 'id of the IO APIC the interrupt is going to') + dest_io_apic_intin = Param.UInt8(0, + 'the INTIN pin on the IO APIC the interrupt is connected to') + +class X86IntelMPLocalIntAssignment(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPLocalIntAssignment' + cxx_class = 'X86ISA::IntelMP::LocalIntAssignment' + + interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt') + + polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity') + trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode') + + source_bus_id = Param.UInt8(0, + 'id of the bus from which the interrupt signal comes') + source_bus_irq = Param.UInt8(0, + 'which interrupt signal from the source bus') + + dest_local_apic_id = Param.UInt8(0, + 'id of the local APIC the interrupt is going to') + dest_local_apic_intin = Param.UInt8(0, + 'the INTIN pin on the local APIC the interrupt is connected to') + +class X86IntelMPAddressType(Enum): + map = {"IOAddress" : 0, + "MemoryAddress" : 1, + "PrefetchAddress" : 2 + } + +class X86IntelMPAddrSpaceMapping(X86IntelMPExtConfigEntry): + type = 'X86IntelMPAddrSpaceMapping' + cxx_class = 'X86ISA::IntelMP::AddrSpaceMapping' + + bus_id = Param.UInt8(0, 'id of the bus the address space is mapped to') + address_type = Param.X86IntelMPAddressType('IOAddress', + 'address type used to access bus') + address = Param.Addr(0, 'starting address of the mapping') + length = Param.UInt64(0, 'length of mapping in bytes') + +class X86IntelMPBusHierarchy(X86IntelMPExtConfigEntry): + type = 'X86IntelMPBusHierarchy' + cxx_class = 'X86ISA::IntelMP::BusHierarchy' + + bus_id = Param.UInt8(0, 'id of the bus being described') + subtractive_decode = Param.Bool(False, + 'whether this bus contains all addresses not used by its children') + parent_bus = Param.UInt8(0, 'bus id of this busses parent') + +class X86IntelMPRangeList(Enum): + map = {"ISACompatible" : 0, + "VGACompatible" : 1 + } + +class X86IntelMPCompatAddrSpaceMod(X86IntelMPExtConfigEntry): + type = 'X86IntelMPCompatAddrSpaceMod' + cxx_class = 'X86ISA::IntelMP::CompatAddrSpaceMod' + + bus_id = Param.UInt8(0, 'id of the bus being described') + add = Param.Bool(False, + 'if the range should be added to the original mapping') + range_list = Param.X86IntelMPRangeList('ISACompatible', + 'which predefined range of addresses to use') diff --git a/src/arch/x86/bios/SConscript b/src/arch/x86/bios/SConscript new file mode 100644 index 000000000..912d6599c --- /dev/null +++ b/src/arch/x86/bios/SConscript @@ -0,0 +1,77 @@ +# -*- mode:python -*- + +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +Import('*') + +if env['TARGET_ISA'] == 'x86': + if env['FULL_SYSTEM']: + # The table generated by the bootloader using the BIOS and passed to + # the operating system which maps out physical memory. + SimObject('E820.py') + Source('e820.cc') + + # The DMI tables. + SimObject('SMBios.py') + Source('smbios.cc') + + # Intel Multiprocessor Specification Configuration Table + SimObject('IntelMP.py') + Source('intelmp.cc') + + # ACPI system description tables + SimObject('ACPI.py') + Source('acpi.cc') diff --git a/src/arch/x86/bios/SMBios.py b/src/arch/x86/bios/SMBios.py new file mode 100644 index 000000000..4947b2854 --- /dev/null +++ b/src/arch/x86/bios/SMBios.py @@ -0,0 +1,140 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +class X86SMBiosSMBiosStructure(SimObject): + type = 'X86SMBiosSMBiosStructure' + cxx_class = 'X86ISA::SMBios::SMBiosStructure' + abstract = True + +class Characteristic(Enum): + map = {'Unknown' : 2, + 'Unsupported' : 3, + 'ISA' : 4, + 'MCA' : 5, + 'EISA' : 6, + 'PCI' : 7, + 'PCMCIA' : 8, + 'PnP' : 9, + 'APM' : 10, + 'Flash' : 11, + 'Shadow' : 12, + 'VL_Vesa' : 13, + 'ESCD' : 14, + 'CDBoot' : 15, + 'SelectBoot' : 16, + 'Socketed' : 17, + 'PCMCIABoot' : 18, + 'EDD' : 19, + 'NEC9800' : 20, + 'Toshiba' : 21, + 'Floppy_5_25_360KB' : 22, + 'Floppy_5_25_1_2MB' : 23, + 'Floppy_3_5_720KB' : 24, + 'Floppy_3_5_2_88MB' : 25, + 'PrintScreen' : 26, + 'Keyboard8024' : 27, + 'Serial' : 28, + 'Printer' : 29, + 'CGA_Mono' : 30, + 'NEC_PC_98' : 31 + } + +class ExtCharacteristic(Enum): + map = {'ACPI' : 0, + 'USBLegacy' : 1, + 'AGP' : 2, + 'I20Boot' : 3, + 'LS_120Boot' : 4, + 'ZIPBoot' : 5, + 'FirewireBoot' : 6, + 'SmartBattery' : 7, + 'BootSpec' : 8, + 'NetServiceBoot' : 9, + 'TargetContent' : 10 + } + +class X86SMBiosBiosInformation(X86SMBiosSMBiosStructure): + type = 'X86SMBiosBiosInformation' + cxx_class = 'X86ISA::SMBios::BiosInformation' + + vendor = Param.String("", "vendor name string") + version = Param.String("", "version string") + starting_addr_segment = \ + Param.UInt16(0, "segment location of bios starting address") + release_date = Param.String("06/08/2008", "release date") + rom_size = Param.UInt8(0, "rom size") + characteristics = VectorParam.Characteristic([], + "bios characteristic bit vector") + characteristic_ext_bytes = VectorParam.ExtCharacteristic([], + "extended bios characteristic bit vector") + major = Param.UInt8(0, "major version number") + minor = Param.UInt8(0, "minor version number") + emb_cont_firmware_major = Param.UInt8(0, + "embedded controller firmware major version number") + + emb_cont_firmware_minor = Param.UInt8(0, + "embedded controller firmware minor version number") + +class X86SMBiosSMBiosTable(SimObject): + type = 'X86SMBiosSMBiosTable' + cxx_class = 'X86ISA::SMBios::SMBiosTable' + + major_version = Param.UInt8(2, "major version number") + minor_version = Param.UInt8(5, "minor version number") + + structures = VectorParam.X86SMBiosSMBiosStructure([], "smbios structures") diff --git a/src/arch/x86/bios/acpi.cc b/src/arch/x86/bios/acpi.cc new file mode 100644 index 000000000..15b3901eb --- /dev/null +++ b/src/arch/x86/bios/acpi.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/bios/acpi.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" +#include "sim/sim_object.hh" + +#include "params/X86ACPIRSDP.hh" + +#include "params/X86ACPISysDescTable.hh" +#include "params/X86ACPIRSDT.hh" +#include "params/X86ACPIXSDT.hh" + +using namespace std; + +const char X86ISA::ACPI::RSDP::signature[] = "RSD PTR "; + +X86ISA::ACPI::RSDP::RSDP(Params *p) : SimObject(p), oemID(p->oem_id), + revision(p->revision), rsdt(p->rsdt), xsdt(p->xsdt) +{} + +X86ISA::ACPI::SysDescTable::SysDescTable(Params *p, + const char * _signature, uint8_t _revision) : SimObject(p), + signature(_signature), revision(_revision), + oemID(p->oem_id), oemTableID(p->oem_table_id), + oemRevision(p->oem_revision), + creatorID(p->creator_id), creatorRevision(p->creator_revision) +{} + +X86ISA::ACPI::RSDT::RSDT(Params *p) : + SysDescTable(p, "RSDT", 1), entries(p->entries) +{} + +X86ISA::ACPI::XSDT::XSDT(Params *p) : + SysDescTable(p, "XSDT", 1), entries(p->entries) +{} + +X86ISA::ACPI::RSDP * +X86ACPIRSDPParams::create() +{ + return new X86ISA::ACPI::RSDP(this); +} + +X86ISA::ACPI::RSDT * +X86ACPIRSDTParams::create() +{ + return new X86ISA::ACPI::RSDT(this); +} + +X86ISA::ACPI::XSDT * +X86ACPIXSDTParams::create() +{ + return new X86ISA::ACPI::XSDT(this); +} diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh new file mode 100644 index 000000000..7bca17790 --- /dev/null +++ b/src/arch/x86/bios/acpi.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_BIOS_ACPI_HH__ +#define __ARCH_X86_BIOS_ACPI_HH__ + +#include "sim/host.hh" +#include "sim/sim_object.hh" + +#include <vector> +#include <string> + +class Port; + +class X86ACPIRSDPParams; + +class X86ACPISysDescTableParams; +class X86ACPIRSDTParams; +class X86ACPIXSDTParams; + +namespace X86ISA +{ + +namespace ACPI +{ + +class RSDT; +class XSDT; +class SysDescTable; + +class RSDP : public SimObject +{ + protected: + typedef X86ACPIRSDPParams Params; + + static const char signature[]; + + std::string oemID; + uint8_t revision; + + RSDT * rsdt; + XSDT * xsdt; + + public: + RSDP(Params *p); +}; + +class SysDescTable : public SimObject +{ + protected: + typedef X86ACPISysDescTableParams Params; + + const char * signature; + uint8_t revision; + + std::string oemID; + std::string oemTableID; + uint32_t oemRevision; + + std::string creatorID; + uint32_t creatorRevision; + + public: + SysDescTable(Params *p, const char * _signature, uint8_t _revision); +}; + +class RSDT : public SysDescTable +{ + protected: + typedef X86ACPIRSDTParams Params; + + std::vector<SysDescTable *> entries; + + public: + RSDT(Params *p); +}; + +class XSDT : public SysDescTable +{ + protected: + typedef X86ACPIXSDTParams Params; + + std::vector<SysDescTable *> entries; + + public: + XSDT(Params *p); +}; + +} // namespace ACPI + +} // namespace X86ISA + +#endif // __ARCH_X86_BIOS_E820_HH__ diff --git a/src/arch/x86/bios/e820.cc b/src/arch/x86/bios/e820.cc new file mode 100644 index 000000000..47adb703a --- /dev/null +++ b/src/arch/x86/bios/e820.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/bios/e820.hh" +#include "arch/x86/isa_traits.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" + +using namespace std; +using namespace X86ISA; + +template<class T> +void writeVal(T val, Port * port, Addr &addr) +{ + T guestVal = htog(val); + port->writeBlob(addr, (uint8_t *)&guestVal, sizeof(T)); + addr += sizeof(T); +} + +void X86ISA::E820Table::writeTo(Port * port, Addr countAddr, Addr addr) +{ + uint8_t e820Nr = entries.size(); + + // Make sure the number of entries isn't bigger than what the kernel + // would be capable of handling. + assert(e820Nr <= 128); + + uint8_t guestE820Nr = htog(e820Nr); + + port->writeBlob(countAddr, (uint8_t *)&guestE820Nr, sizeof(guestE820Nr)); + + for (int i = 0; i < e820Nr; i++) { + writeVal(entries[i]->addr, port, addr); + writeVal(entries[i]->size, port, addr); + writeVal(entries[i]->type, port, addr); + } +} + +E820Table * +X86E820TableParams::create() +{ + return new E820Table(this); +} + +E820Entry * +X86E820EntryParams::create() +{ + return new E820Entry(this); +} diff --git a/src/arch/x86/syscallreturn.hh b/src/arch/x86/bios/e820.hh index 6a7fdba58..da738343b 100644 --- a/src/arch/x86/syscallreturn.hh +++ b/src/arch/x86/bios/e820.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -55,20 +55,46 @@ * Authors: Gabe Black */ -#ifndef __ARCH_X86_SYSCALLRETURN_HH__ -#define __ARCH_X86_SYSCALLRETURN_HH__ +#ifndef __ARCH_X86_BIOS_E820_HH__ +#define __ARCH_X86_BIOS_E820_HH__ -#include "base/misc.hh" -#include "cpu/thread_context.hh" -#include "sim/syscallreturn.hh" +#include "params/X86E820Entry.hh" +#include "params/X86E820Table.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +#include <vector> + +class Port; namespace X86ISA { - static inline void setSyscallReturn(SyscallReturn return_value, - ThreadContext * tc) + class E820Entry : public SimObject { - tc->setIntReg(INTREG_RAX, return_value.value()); - } + public: + Addr addr; + Addr size; + uint32_t type; + + public: + typedef X86E820EntryParams Params; + E820Entry(Params *p) : + SimObject(p), addr(p->addr), size(p->size), type(p->range_type) + {} + }; + + class E820Table : public SimObject + { + public: + std::vector<E820Entry *> entries; + + public: + typedef X86E820TableParams Params; + E820Table(Params *p) : SimObject(p), entries(p->entries) + {} + + void writeTo(Port * port, Addr countAddr, Addr addr); + }; }; -#endif // __ARCH_X86_SYSCALLRETURN_HH__ +#endif // __ARCH_X86_BIOS_E820_HH__ diff --git a/src/arch/x86/bios/intelmp.cc b/src/arch/x86/bios/intelmp.cc new file mode 100644 index 000000000..2332e7a5c --- /dev/null +++ b/src/arch/x86/bios/intelmp.cc @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/bios/intelmp.hh" +#include "arch/x86/isa_traits.hh" +#include "base/misc.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" +#include "sim/host.hh" + +// Config entry types +#include "params/X86IntelMPBaseConfigEntry.hh" +#include "params/X86IntelMPExtConfigEntry.hh" + +// General table structures +#include "params/X86IntelMPConfigTable.hh" +#include "params/X86IntelMPFloatingPointer.hh" + +// Base entry types +#include "params/X86IntelMPBus.hh" +#include "params/X86IntelMPIOAPIC.hh" +#include "params/X86IntelMPIOIntAssignment.hh" +#include "params/X86IntelMPLocalIntAssignment.hh" +#include "params/X86IntelMPProcessor.hh" + +// Extended entry types +#include "params/X86IntelMPAddrSpaceMapping.hh" +#include "params/X86IntelMPBusHierarchy.hh" +#include "params/X86IntelMPCompatAddrSpaceMod.hh" + +using namespace std; + +const char X86ISA::IntelMP::FloatingPointer::signature[] = "_MP_"; + +template<class T> +uint8_t +writeOutField(FunctionalPort * port, Addr addr, T val) +{ + T guestVal = X86ISA::htog(val); + port->writeBlob(addr, (uint8_t *)(&guestVal), sizeof(T)); + + uint8_t checkSum = 0; + while(guestVal) { + checkSum += guestVal; + guestVal >>= 8; + } + return checkSum; +} + +uint8_t +writeOutString(FunctionalPort * port, Addr addr, string str, int length) +{ + char cleanedString[length + 1]; + cleanedString[length] = 0; + + if (str.length() > length) { + memcpy(cleanedString, str.c_str(), length); + warn("Intel MP configuration table string \"%s\" " + "will be truncated to \"%s\".\n", str, cleanedString); + } else { + memcpy(cleanedString, str.c_str(), str.length()); + memset(cleanedString + str.length(), 0, length - str.length()); + } + port->writeBlob(addr, (uint8_t *)(&cleanedString), length); + + uint8_t checkSum = 0; + for (int i = 0; i < length; i++) + checkSum += cleanedString[i]; + + return checkSum; +} + +Addr +X86ISA::IntelMP::FloatingPointer::writeOut(FunctionalPort * port, Addr addr) +{ + // Make sure that either a config table is present or a default + // configuration was found but not both. + if (!tableAddr && !defaultConfig) + fatal("Either an MP configuration table or a default configuration " + "must be used."); + if (tableAddr && defaultConfig) + fatal("Both an MP configuration table and a default configuration " + "were set."); + + uint8_t checkSum = 0; + + port->writeBlob(addr, (uint8_t *)signature, 4); + for (int i = 0; i < 4; i++) + checkSum += signature[i]; + + checkSum += writeOutField(port, addr + 4, tableAddr); + + // The length of the structure in paragraphs, aka 16 byte chunks. + uint8_t length = 1; + port->writeBlob(addr + 8, &length, 1); + checkSum += length; + + port->writeBlob(addr + 9, &specRev, 1); + checkSum += specRev; + + port->writeBlob(addr + 11, &defaultConfig, 1); + checkSum += defaultConfig; + + uint32_t features2_5 = imcrPresent ? (1 << 7) : 0; + checkSum += writeOutField(port, addr + 12, features2_5); + + checkSum = -checkSum; + port->writeBlob(addr + 10, &checkSum, 1); + + return 16; +} + +X86ISA::IntelMP::FloatingPointer::FloatingPointer(Params * p) : + SimObject(p), tableAddr(0), specRev(p->spec_rev), + defaultConfig(p->default_config), imcrPresent(p->imcr_present) +{} + +X86ISA::IntelMP::FloatingPointer * +X86IntelMPFloatingPointerParams::create() +{ + return new X86ISA::IntelMP::FloatingPointer(this); +} + +Addr +X86ISA::IntelMP::BaseConfigEntry::writeOut(FunctionalPort * port, + Addr addr, uint8_t &checkSum) +{ + port->writeBlob(addr, &type, 1); + checkSum += type; + return 1; +} + +X86ISA::IntelMP::BaseConfigEntry::BaseConfigEntry(Params * p, uint8_t _type) : + SimObject(p), type(_type) +{} + +Addr +X86ISA::IntelMP::ExtConfigEntry::writeOut(FunctionalPort * port, + Addr addr, uint8_t &checkSum) +{ + port->writeBlob(addr, &type, 1); + checkSum += type; + port->writeBlob(addr + 1, &length, 1); + checkSum += length; + return 1; +} + +X86ISA::IntelMP::ExtConfigEntry::ExtConfigEntry(Params * p, + uint8_t _type, uint8_t _length) : + SimObject(p), type(_type), length(_length) +{} + +const char X86ISA::IntelMP::ConfigTable::signature[] = "PCMP"; + +Addr +X86ISA::IntelMP::ConfigTable::writeOut(FunctionalPort * port, Addr addr) +{ + uint8_t checkSum = 0; + + port->writeBlob(addr, (uint8_t *)signature, 4); + for (int i = 0; i < 4; i++) + checkSum += signature[i]; + + // Base table length goes here but will be calculated later. + + port->writeBlob(addr + 6, (uint8_t *)(&specRev), 1); + checkSum += specRev; + + // The checksum goes here but is still being calculated. + + checkSum += writeOutString(port, addr + 8, oemID, 8); + checkSum += writeOutString(port, addr + 16, productID, 12); + + checkSum += writeOutField(port, addr + 28, oemTableAddr); + checkSum += writeOutField(port, addr + 32, oemTableSize); + checkSum += writeOutField(port, addr + 34, (uint16_t)baseEntries.size()); + checkSum += writeOutField(port, addr + 36, localApic); + + uint8_t reserved = 0; + port->writeBlob(addr + 43, &reserved, 1); + checkSum += reserved; + + vector<BaseConfigEntry *>::iterator baseEnt; + uint16_t offset = 44; + for (baseEnt = baseEntries.begin(); + baseEnt != baseEntries.end(); baseEnt++) { + offset += (*baseEnt)->writeOut(port, addr + offset, checkSum); + } + + // We've found the end of the base table this point. + checkSum += writeOutField(port, addr + 4, offset); + + vector<ExtConfigEntry *>::iterator extEnt; + uint16_t extOffset = 0; + uint8_t extCheckSum = 0; + for (extEnt = extEntries.begin(); + extEnt != extEntries.end(); extEnt++) { + extOffset += (*extEnt)->writeOut(port, + addr + offset + extOffset, extCheckSum); + } + + checkSum += writeOutField(port, addr + 40, extOffset); + extCheckSum = -extCheckSum; + checkSum += writeOutField(port, addr + 42, extCheckSum); + + // And now, we finally have the whole check sum completed. + checkSum = -checkSum; + writeOutField(port, addr + 7, checkSum); + + return offset + extOffset; +}; + +X86ISA::IntelMP::ConfigTable::ConfigTable(Params * p) : SimObject(p), + specRev(p->spec_rev), oemID(p->oem_id), productID(p->product_id), + oemTableAddr(p->oem_table_addr), oemTableSize(p->oem_table_size), + localApic(p->local_apic), + baseEntries(p->base_entries), extEntries(p->ext_entries) +{} + +X86ISA::IntelMP::ConfigTable * +X86IntelMPConfigTableParams::create() +{ + return new X86ISA::IntelMP::ConfigTable(this); +} + +Addr +X86ISA::IntelMP::Processor::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, localApicID); + checkSum += writeOutField(port, addr + 2, localApicVersion); + checkSum += writeOutField(port, addr + 3, cpuFlags); + checkSum += writeOutField(port, addr + 4, cpuSignature); + checkSum += writeOutField(port, addr + 8, featureFlags); + + uint32_t reserved = 0; + port->writeBlob(addr + 12, (uint8_t *)(&reserved), 4); + port->writeBlob(addr + 16, (uint8_t *)(&reserved), 4); + return 20; +} + +X86ISA::IntelMP::Processor::Processor(Params * p) : BaseConfigEntry(p, 0), + localApicID(p->local_apic_id), localApicVersion(p->local_apic_version), + cpuFlags(0), cpuSignature(0), featureFlags(p->feature_flags) +{ + if (p->enable) + cpuFlags |= (1 << 0); + if (p->bootstrap) + cpuFlags |= (1 << 1); + + replaceBits(cpuSignature, 0, 3, p->stepping); + replaceBits(cpuSignature, 4, 7, p->model); + replaceBits(cpuSignature, 8, 11, p->family); +} + +X86ISA::IntelMP::Processor * +X86IntelMPProcessorParams::create() +{ + return new X86ISA::IntelMP::Processor(this); +} + +Addr +X86ISA::IntelMP::Bus::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, busID); + checkSum += writeOutString(port, addr + 2, busType, 6); + return 8; +} + +X86ISA::IntelMP::Bus::Bus(Params * p) : BaseConfigEntry(p, 1), + busID(p->bus_id), busType(p->bus_type) +{} + +X86ISA::IntelMP::Bus * +X86IntelMPBusParams::create() +{ + return new X86ISA::IntelMP::Bus(this); +} + +Addr +X86ISA::IntelMP::IOAPIC::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, id); + checkSum += writeOutField(port, addr + 2, version); + checkSum += writeOutField(port, addr + 3, flags); + checkSum += writeOutField(port, addr + 4, address); + return 8; +} + +X86ISA::IntelMP::IOAPIC::IOAPIC(Params * p) : BaseConfigEntry(p, 2), + id(p->id), version(p->version), flags(0), address(p->address) +{ + if (p->enable) + flags |= 1; +} + +X86ISA::IntelMP::IOAPIC * +X86IntelMPIOAPICParams::create() +{ + return new X86ISA::IntelMP::IOAPIC(this); +} + +Addr +X86ISA::IntelMP::IntAssignment::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, interruptType); + checkSum += writeOutField(port, addr + 2, flags); + checkSum += writeOutField(port, addr + 4, sourceBusID); + checkSum += writeOutField(port, addr + 5, sourceBusIRQ); + checkSum += writeOutField(port, addr + 6, destApicID); + checkSum += writeOutField(port, addr + 7, destApicIntIn); + return 8; +} + +X86ISA::IntelMP::IOIntAssignment::IOIntAssignment(Params * p) : + IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 3, + p->source_bus_id, p->source_bus_irq, + p->dest_io_apic_id, p->dest_io_apic_intin) +{} + +X86ISA::IntelMP::IOIntAssignment * +X86IntelMPIOIntAssignmentParams::create() +{ + return new X86ISA::IntelMP::IOIntAssignment(this); +} + +X86ISA::IntelMP::LocalIntAssignment::LocalIntAssignment(Params * p) : + IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 4, + p->source_bus_id, p->source_bus_irq, + p->dest_local_apic_id, p->dest_local_apic_intin) +{} + +X86ISA::IntelMP::LocalIntAssignment * +X86IntelMPLocalIntAssignmentParams::create() +{ + return new X86ISA::IntelMP::LocalIntAssignment(this); +} + +Addr +X86ISA::IntelMP::AddrSpaceMapping::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, addrType); + checkSum += writeOutField(port, addr + 4, addr); + checkSum += writeOutField(port, addr + 12, addrLength); + return length; +} + +X86ISA::IntelMP::AddrSpaceMapping::AddrSpaceMapping(Params * p) : + ExtConfigEntry(p, 128, 20), + busID(p->bus_id), addrType(p->address_type), + addr(p->address), addrLength(p->length) +{} + +X86ISA::IntelMP::AddrSpaceMapping * +X86IntelMPAddrSpaceMappingParams::create() +{ + return new X86ISA::IntelMP::AddrSpaceMapping(this); +} + +Addr +X86ISA::IntelMP::BusHierarchy::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, info); + checkSum += writeOutField(port, addr + 4, parentBus); + + uint32_t reserved = 0; + port->writeBlob(addr + 5, (uint8_t *)(&reserved), 3); + + return length; +} + +X86ISA::IntelMP::BusHierarchy::BusHierarchy(Params * p) : + ExtConfigEntry(p, 129, 8), + busID(p->bus_id), info(0), parentBus(p->parent_bus) +{ + if (p->subtractive_decode) + info |= 1; +} + +X86ISA::IntelMP::BusHierarchy * +X86IntelMPBusHierarchyParams::create() +{ + return new X86ISA::IntelMP::BusHierarchy(this); +} + +Addr +X86ISA::IntelMP::CompatAddrSpaceMod::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, mod); + checkSum += writeOutField(port, addr + 4, rangeList); + return length; +} + +X86ISA::IntelMP::CompatAddrSpaceMod::CompatAddrSpaceMod(Params * p) : + ExtConfigEntry(p, 130, 8), + busID(p->bus_id), mod(0), rangeList(p->range_list) +{ + if (p->add) + mod |= 1; +} + +X86ISA::IntelMP::CompatAddrSpaceMod * +X86IntelMPCompatAddrSpaceModParams::create() +{ + return new X86ISA::IntelMP::CompatAddrSpaceMod(this); +} diff --git a/src/arch/x86/bios/intelmp.hh b/src/arch/x86/bios/intelmp.hh new file mode 100644 index 000000000..e8d1d656e --- /dev/null +++ b/src/arch/x86/bios/intelmp.hh @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_BIOS_INTELMP_HH__ +#define __ARCH_X86_BIOS_INTELMP_HH__ + +#include <string> +#include <vector> + +#include "base/bitfield.hh" +#include "sim/sim_object.hh" + +#include "enums/X86IntelMPAddressType.hh" +#include "enums/X86IntelMPInterruptType.hh" +#include "enums/X86IntelMPPolarity.hh" +#include "enums/X86IntelMPRangeList.hh" +#include "enums/X86IntelMPTriggerMode.hh" + +class FunctionalPort; + +// Config entry types +class X86IntelMPBaseConfigEntryParams; +class X86IntelMPExtConfigEntryParams; + +// General table structures +class X86IntelMPConfigTableParams; +class X86IntelMPFloatingPointerParams; + +// Base entry types +class X86IntelMPBusParams; +class X86IntelMPIOAPICParams; +class X86IntelMPIOIntAssignmentParams; +class X86IntelMPLocalIntAssignmentParams; +class X86IntelMPProcessorParams; + +// Extended entry types +class X86IntelMPAddrSpaceMappingParams; +class X86IntelMPBusHierarchyParams; +class X86IntelMPCompatAddrSpaceModParams; + +namespace X86ISA +{ + +namespace IntelMP +{ + +class FloatingPointer : public SimObject +{ + protected: + typedef X86IntelMPFloatingPointerParams Params; + + uint32_t tableAddr; + uint8_t specRev; + uint8_t defaultConfig; + bool imcrPresent; + + static const char signature[]; + + public: + + Addr writeOut(FunctionalPort * port, Addr addr); + + Addr getTableAddr() + { + return tableAddr; + } + + void setTableAddr(Addr addr) + { + tableAddr = addr; + } + + FloatingPointer(Params * p); +}; + +class BaseConfigEntry : public SimObject +{ + protected: + typedef X86IntelMPBaseConfigEntryParams Params; + + uint8_t type; + + public: + + virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + BaseConfigEntry(Params * p, uint8_t _type); +}; + +class ExtConfigEntry : public SimObject +{ + protected: + typedef X86IntelMPExtConfigEntryParams Params; + + uint8_t type; + uint8_t length; + + public: + + virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + ExtConfigEntry(Params * p, uint8_t _type, uint8_t _length); +}; + +class ConfigTable : public SimObject +{ + protected: + typedef X86IntelMPConfigTableParams Params; + + static const char signature[]; + + uint8_t specRev; + std::string oemID; + std::string productID; + uint32_t oemTableAddr; + uint16_t oemTableSize; + uint32_t localApic; + + std::vector<BaseConfigEntry *> baseEntries; + std::vector<ExtConfigEntry *> extEntries; + + public: + Addr writeOut(FunctionalPort * port, Addr addr); + + ConfigTable(Params * p); +}; + +class Processor : public BaseConfigEntry +{ + protected: + typedef X86IntelMPProcessorParams Params; + + uint8_t localApicID; + uint8_t localApicVersion; + uint8_t cpuFlags; + uint32_t cpuSignature; + uint32_t featureFlags; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + Processor(Params * p); +}; + +class Bus : public BaseConfigEntry +{ + protected: + typedef X86IntelMPBusParams Params; + + uint8_t busID; + std::string busType; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + Bus(Params * p); +}; + +class IOAPIC : public BaseConfigEntry +{ + protected: + typedef X86IntelMPIOAPICParams Params; + + uint8_t id; + uint8_t version; + uint8_t flags; + uint32_t address; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + IOAPIC(Params * p); +}; + +class IntAssignment : public BaseConfigEntry +{ + protected: + uint8_t interruptType; + + uint16_t flags; + + uint8_t sourceBusID; + uint8_t sourceBusIRQ; + + uint8_t destApicID; + uint8_t destApicIntIn; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + IntAssignment(X86IntelMPBaseConfigEntryParams * p, + Enums::X86IntelMPInterruptType _interruptType, + Enums::X86IntelMPPolarity polarity, + Enums::X86IntelMPTriggerMode trigger, + uint8_t _type, + uint8_t _sourceBusID, uint8_t _sourceBusIRQ, + uint8_t _destApicID, uint8_t _destApicIntIn) : + BaseConfigEntry(p, _type), + interruptType(_interruptType), flags(0), + sourceBusID(_sourceBusID), sourceBusIRQ(_sourceBusIRQ), + destApicID(_destApicID), destApicIntIn(_destApicIntIn) + { + replaceBits(flags, 0, 1, polarity); + replaceBits(flags, 2, 3, trigger); + } +}; + +class IOIntAssignment : public IntAssignment +{ + protected: + typedef X86IntelMPIOIntAssignmentParams Params; + + public: + IOIntAssignment(Params * p); +}; + +class LocalIntAssignment : public IntAssignment +{ + protected: + typedef X86IntelMPLocalIntAssignmentParams Params; + + public: + LocalIntAssignment(Params * p); +}; + +class AddrSpaceMapping : public ExtConfigEntry +{ + protected: + typedef X86IntelMPAddrSpaceMappingParams Params; + + uint8_t busID; + uint8_t addrType; + uint64_t addr; + uint64_t addrLength; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + AddrSpaceMapping(Params * p); +}; + +class BusHierarchy : public ExtConfigEntry +{ + protected: + typedef X86IntelMPBusHierarchyParams Params; + + uint8_t busID; + uint8_t info; + uint8_t parentBus; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + BusHierarchy(Params * p); +}; + +class CompatAddrSpaceMod : public ExtConfigEntry +{ + protected: + typedef X86IntelMPCompatAddrSpaceModParams Params; + + uint8_t busID; + uint8_t mod; + uint32_t rangeList; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + CompatAddrSpaceMod(Params * p); +}; + +} //IntelMP + +} //X86ISA + +#endif diff --git a/src/arch/x86/smbios.cc b/src/arch/x86/bios/smbios.cc index 319650c1f..95ade1e4d 100644 --- a/src/arch/x86/smbios.cc +++ b/src/arch/x86/bios/smbios.cc @@ -85,12 +85,17 @@ * Authors: Gabe Black */ -#include "arch/x86/smbios.hh" +#include "arch/x86/bios/smbios.hh" #include "arch/x86/isa_traits.hh" #include "mem/port.hh" +#include "params/X86SMBiosBiosInformation.hh" +#include "params/X86SMBiosSMBiosStructure.hh" +#include "params/X86SMBiosSMBiosTable.hh" #include "sim/byteswap.hh" #include "sim/host.hh" +using namespace std; + const char X86ISA::SMBios::SMBiosTable::SMBiosHeader::anchorString[] = "_SM_"; const uint8_t X86ISA::SMBios::SMBiosTable:: SMBiosHeader::formattedArea[] = {0,0,0,0,0}; @@ -101,6 +106,116 @@ const uint8_t X86ISA::SMBios::SMBiosTable:: const char X86ISA::SMBios::SMBiosTable:: SMBiosHeader::IntermediateHeader::anchorString[] = "_DMI_"; +template <class T> +uint64_t +composeBitVector(T vec) +{ + uint64_t val = 0; + typename T::iterator vecIt; + for (vecIt = vec.begin(); vecIt != vec.end(); vecIt++) { + val |= (1 << (*vecIt)); + } + return val; +} + +uint16_t +X86ISA::SMBios::SMBiosStructure::writeOut(FunctionalPort * port, Addr addr) +{ + port->writeBlob(addr, (uint8_t *)(&type), 1); + + uint8_t length = getLength(); + port->writeBlob(addr + 1, (uint8_t *)(&length), 1); + + uint16_t handleGuest = X86ISA::htog(handle); + port->writeBlob(addr + 2, (uint8_t *)(&handleGuest), 2); + + return length + getStringLength(); +} + +X86ISA::SMBios::SMBiosStructure::SMBiosStructure(Params * p, uint8_t _type) : + SimObject(p), type(_type), handle(0), stringFields(false) +{} + +void +X86ISA::SMBios::SMBiosStructure::writeOutStrings( + FunctionalPort * port, Addr addr) +{ + std::vector<std::string>::iterator it; + Addr offset = 0; + + const uint8_t nullTerminator = 0; + + // If there are string fields but none of them are used, that's a + // special case which is handled by this if. + if (strings.size() == 0 && stringFields) { + port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1); + offset++; + } else { + for (it = strings.begin(); it != strings.end(); it++) { + port->writeBlob(addr + offset, + (uint8_t *)it->c_str(), it->length() + 1); + offset += it->length() + 1; + } + } + port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1); +} + +int +X86ISA::SMBios::SMBiosStructure::getStringLength() +{ + int size = 0; + std::vector<std::string>::iterator it; + + for (it = strings.begin(); it != strings.end(); it++) { + size += it->length() + 1; + } + + return size + 1; +} + +int +X86ISA::SMBios::SMBiosStructure::addString(string & newString) +{ + stringFields = true; + // If a string is empty, treat it as not existing. The index for empty + // strings is 0. + if (newString.length() == 0) + return 0; + strings.push_back(newString); + return strings.size(); +} + +string +X86ISA::SMBios::SMBiosStructure::readString(int n) +{ + assert(n > 0 && n <= strings.size()); + return strings[n - 1]; +} + +void +X86ISA::SMBios::SMBiosStructure::setString(int n, std::string & newString) +{ + assert(n > 0 && n <= strings.size()); + strings[n - 1] = newString; +} + +X86ISA::SMBios::BiosInformation::BiosInformation(Params * p) : + SMBiosStructure(p, Type), + startingAddrSegment(p->starting_addr_segment), + romSize(p->rom_size), + majorVer(p->major), minorVer(p->minor), + embContFirmwareMajor(p->emb_cont_firmware_major), + embContFirmwareMinor(p->emb_cont_firmware_minor) + { + vendor = addString(p->vendor); + version = addString(p->version); + releaseDate = addString(p->release_date); + + characteristics = composeBitVector(p->characteristics); + characteristicExtBytes = + composeBitVector(p->characteristic_ext_bytes); + } + uint16_t X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr) { @@ -122,8 +237,8 @@ X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr) X86ISA::htog(characteristicExtBytes); port->writeBlob(addr + 0x12, (uint8_t *)(&characteristicExtBytesGuest), 2); - port->writeBlob(addr + 0x14, (uint8_t *)(&major), 1); - port->writeBlob(addr + 0x15, (uint8_t *)(&minor), 1); + port->writeBlob(addr + 0x14, (uint8_t *)(&majorVer), 1); + port->writeBlob(addr + 0x15, (uint8_t *)(&minorVer), 1); port->writeBlob(addr + 0x16, (uint8_t *)(&embContFirmwareMajor), 1); port->writeBlob(addr + 0x17, (uint8_t *)(&embContFirmwareMinor), 1); @@ -132,9 +247,22 @@ X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr) return size; } +X86ISA::SMBios::SMBiosTable::SMBiosTable(Params * p) : + SimObject(p), structures(p->structures) +{ + smbiosHeader.majorVersion = p->major_version; + smbiosHeader.minorVersion = p->minor_version; + assert(p->major_version <= 9); + assert(p->minor_version <= 9); + smbiosHeader.intermediateHeader.smbiosBCDRevision = + (p->major_version << 4) | p->minor_version; +} + void -X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr) +X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr, + Addr &headerSize, Addr &structSize) { + headerSize = 0x1F; /* * The main header @@ -205,14 +333,16 @@ X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr) Addr base = smbiosHeader.intermediateHeader.tableAddr; Addr offset = 0; uint16_t maxSize = 0; - std::vector<SMBiosStructure>::iterator it; + std::vector<SMBiosStructure *>::iterator it; for (it = structures.begin(); it != structures.end(); it++) { - uint16_t size = it->writeOut(port, base + offset); + uint16_t size = (*it)->writeOut(port, base + offset); if (size > maxSize) maxSize = size; offset += size; } + structSize = offset; + /* * Header */ @@ -243,3 +373,15 @@ X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr) intChecksum = -intChecksum; port->writeBlob(addr + 0x15, (uint8_t *)(&intChecksum), 1); } + +X86ISA::SMBios::BiosInformation * +X86SMBiosBiosInformationParams::create() +{ + return new X86ISA::SMBios::BiosInformation(this); +} + +X86ISA::SMBios::SMBiosTable * +X86SMBiosSMBiosTableParams::create() +{ + return new X86ISA::SMBios::SMBiosTable(this); +} diff --git a/src/arch/x86/smbios.hh b/src/arch/x86/bios/smbios.hh index c126de220..1c50d0b48 100644 --- a/src/arch/x86/smbios.hh +++ b/src/arch/x86/bios/smbios.hh @@ -85,16 +85,21 @@ * Authors: Gabe Black */ -#ifndef __ARCH_X86_SMBIOS_HH__ -#define __ARCH_X86_SMBIOS_HH__ +#ifndef __ARCH_X86_BIOS_SMBIOS_HH__ +#define __ARCH_X86_BIOS_SMBIOS_HH__ #include <string> #include <vector> -#include "arch/x86/isa_traits.hh" -#include "mem/port.hh" -#include "sim/byteswap.hh" +#include "enums/Characteristic.hh" +#include "enums/ExtCharacteristic.hh" #include "sim/host.hh" +#include "sim/sim_object.hh" + +class FunctionalPort; +class X86SMBiosBiosInformationParams; +class X86SMBiosSMBiosStructureParams; +class X86SMBiosSMBiosTableParams; namespace X86ISA { @@ -102,8 +107,11 @@ namespace X86ISA namespace SMBios { -class SMBiosStructure +class SMBiosStructure : public SimObject { + protected: + typedef X86SMBiosSMBiosStructureParams Params; + public: virtual @@ -126,73 +134,33 @@ class SMBiosStructure return 4; } - virtual uint16_t - writeOut(FunctionalPort * port, Addr addr) - { - port->writeBlob(addr, (uint8_t *)(&type), 1); - - uint8_t length = getLength(); - port->writeBlob(addr + 1, (uint8_t *)(&length), 1); - - uint16_t handleGuest = X86ISA::htog(handle); - port->writeBlob(addr + 2, (uint8_t *)(&handleGuest), 2); - - return length + getStringLength(); - } + virtual uint16_t writeOut(FunctionalPort * port, Addr addr); protected: - std::vector<std::string> strings; - - void writeOutStrings(FunctionalPort * port, Addr addr) - { - std::vector<std::string>::iterator it; - Addr offset = 0; - - for (it = strings.begin(); it != strings.end(); it++) { - port->writeBlob(addr + offset, - (uint8_t *)it->c_str(), it->length() + 1); - offset += it->length() + 1; - } + bool stringFields; - const uint8_t nullTerminator = 0; - port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1); - } + SMBiosStructure(Params * p, uint8_t _type); - int getStringLength() - { - int size = 0; - std::vector<std::string>::iterator it; + std::vector<std::string> strings; - for (it = strings.begin(); it != strings.end(); it++) { - size += it->length() + 1; - } + void writeOutStrings(FunctionalPort * port, Addr addr); - return size + 1; - } + int getStringLength(); public: - int addString(std::string & newString) - { - strings.push_back(newString); - return strings.size(); - } - - std::string readString(int n) - { - assert(n > 0 && n <= strings.size()); - return strings[n - 1]; - } - - void setString(int n, std::string & newString) - { - assert(n > 0 && n <= strings.size()); - strings[n - 1] = newString; - } + int addString(std::string & newString); + std::string readString(int n); + void setString(int n, std::string & newString); }; class BiosInformation : public SMBiosStructure { + protected: + const static uint8_t Type = 0; + + typedef X86SMBiosBiosInformationParams Params; + public: // Offset 04h, 1 byte uint8_t vendor; @@ -211,21 +179,25 @@ class BiosInformation : public SMBiosStructure // Offset 12h, 2 bytes uint16_t characteristicExtBytes; // Offset 14h, 1 byte - uint8_t major; + uint8_t majorVer; // Offset 15h, 1 byte - uint8_t minor; + uint8_t minorVer; // Offset 16h, 1 byte uint8_t embContFirmwareMajor; // Offset 17h, 1 byte uint8_t embContFirmwareMinor; + BiosInformation(Params * p); + uint8_t getLength() { return 0x18; } uint16_t writeOut(FunctionalPort * port, Addr addr); }; -class SMBiosTable +class SMBiosTable : public SimObject { - public: + protected: + typedef X86SMBiosSMBiosTableParams Params; + struct SMBiosHeader { SMBiosHeader() @@ -281,9 +253,23 @@ class SMBiosTable } intermediateHeader; } smbiosHeader; - void writeOut(FunctionalPort * port, Addr addr); + std::vector<SMBiosStructure *> structures; + + public: + SMBiosTable(Params * p); + + Addr getTableAddr() + { + return smbiosHeader.intermediateHeader.tableAddr; + } + + void setTableAddr(Addr addr) + { + smbiosHeader.intermediateHeader.tableAddr = addr; + } - std::vector<SMBiosStructure> structures; + void writeOut(FunctionalPort * port, Addr addr, + Addr &headerSize, Addr &structSize); }; } //SMBios diff --git a/src/arch/x86/cpuid.cc b/src/arch/x86/cpuid.cc new file mode 100644 index 000000000..247965df4 --- /dev/null +++ b/src/arch/x86/cpuid.cc @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/cpuid.hh" +#include "base/bitfield.hh" +#include "cpu/thread_context.hh" + +namespace X86ISA { + enum StandardCpuidFunction { + VendorAndLargestStdFunc, + FamilyModelStepping, + NumStandardCpuidFuncs + }; + + enum ExtendedCpuidFunctions { + VendorAndLargestExtFunc, + FamilyModelSteppingBrandFeatures, + NameString1, + NameString2, + NameString3, + L1CacheAndTLB, + L2L3CacheAndL2TLB, + APMInfo, + + /* + * The following are defined by the spec but not yet implemented + */ +/* LongModeAddressSize, + // Function 9 is reserved + SVMInfo = 10, + // Functions 11-24 are reserved + TLB1GBPageInfo = 25, + PerformanceInfo,*/ + + NumExtendedCpuidFuncs + }; + + static const int vendorStringSize = 13; + static const char vendorString[vendorStringSize] = "AuthenticAMD"; + static const int nameStringSize = 48; + static const char nameString[nameStringSize] = "Fake M5 x86_64 CPU"; + + uint64_t + stringToRegister(const char *str) + { + uint64_t reg = 0; + for (int pos = 3; pos >=0; pos--) { + reg <<= 8; + reg |= str[pos]; + } + return reg; + } + + bool + doCpuid(ThreadContext * tc, uint32_t function, CpuidResult &result) + { + uint16_t family = bits(function, 31, 16); + uint16_t funcNum = bits(function, 15, 0); + if (family == 0x8000) { + // The extended functions + switch (funcNum) { + case VendorAndLargestExtFunc: + assert(vendorStringSize >= 12); + result = CpuidResult( + NumExtendedCpuidFuncs - 1, + stringToRegister(vendorString), + stringToRegister(vendorString + 4), + stringToRegister(vendorString + 8)); + break; + case FamilyModelSteppingBrandFeatures: + result = CpuidResult(0x00020f51, 0x00000405, + 0xe3d3fbff, 0x00000001); + break; + case NameString1: + case NameString2: + case NameString3: + { + // Zero fill anything beyond the end of the string. This + // should go away once the string is a vetted parameter. + char cleanName[nameStringSize]; + memset(cleanName, '\0', nameStringSize); + strncpy(cleanName, nameString, nameStringSize); + + int offset = (funcNum - NameString1) * 16; + assert(nameStringSize >= offset + 16); + result = CpuidResult( + stringToRegister(cleanName + offset + 0), + stringToRegister(cleanName + offset + 4), + stringToRegister(cleanName + offset + 8), + stringToRegister(cleanName + offset + 12)); + } + break; + case L1CacheAndTLB: + result = CpuidResult(0xff08ff08, 0xff20ff20, + 0x40020140, 0x40020140); + break; + case L2L3CacheAndL2TLB: + result = CpuidResult(0x00000000, 0x42004200, + 0x00000000, 0x04008140); + break; + case APMInfo: + result = CpuidResult(0x80000018, 0x68747541, + 0x69746e65, 0x444d4163); + break; +/* case LongModeAddressSize: + case SVMInfo: + case TLB1GBPageInfo: + case PerformanceInfo:*/ + default: + return false; + } + } else if(family == 0x0000) { + // The standard functions + switch (funcNum) { + case VendorAndLargestStdFunc: + assert(vendorStringSize >= 12); + result = CpuidResult( + NumStandardCpuidFuncs - 1, + stringToRegister(vendorString), + stringToRegister(vendorString + 4), + stringToRegister(vendorString + 8)); + break; + case FamilyModelStepping: + result = CpuidResult(0x00020f51, 0000000405, + 0xe3d3fbff, 0x00000001); + break; + default: + return false; + } + } + return true; + } +} //namespace X86ISA diff --git a/src/arch/x86/cpuid.hh b/src/arch/x86/cpuid.hh new file mode 100644 index 000000000..5cb4c7972 --- /dev/null +++ b/src/arch/x86/cpuid.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_CPUID_HH__ +#define __ARCH_X86_CPUID_HH__ + +#include <inttypes.h> + +class ThreadContext; + +namespace X86ISA +{ + struct CpuidResult + { + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + + // These are not in alphebetical order on purpose. The order reflects + // how the CPUID orders the registers when it returns results. + CpuidResult(uint64_t _rax, uint64_t _rbx, + uint64_t _rdx, uint64_t _rcx) : + rax(_rax), rbx(_rbx), rcx(_rcx), rdx(_rdx) + {} + + CpuidResult() + {} + }; + + bool doCpuid(ThreadContext * tc, uint32_t function, CpuidResult &result); +} // namespace X86ISA + +#endif diff --git a/src/arch/x86/emulenv.cc b/src/arch/x86/emulenv.cc index 31b705d79..0d7b32130 100644 --- a/src/arch/x86/emulenv.cc +++ b/src/arch/x86/emulenv.cc @@ -55,6 +55,8 @@ * Authors: Gabe Black */ +#include <cassert> + #include "arch/x86/emulenv.hh" #include "base/misc.hh" @@ -91,7 +93,7 @@ void EmulEnv::doModRM(const ExtMachInst & machInst) //Figure out what segment to use. This won't be entirely accurate since //the presence of a displacement is supposed to make the instruction //default to the data segment. - if (base != INTREG_RBP && base != INTREG_RSP || + if ((base != INTREG_RBP && base != INTREG_RSP) || 0/*Has an immediate offset*/) { seg = SEGMENT_REG_DS; //Handle any segment override that might have been in the instruction @@ -103,3 +105,11 @@ void EmulEnv::doModRM(const ExtMachInst & machInst) } } +void EmulEnv::setSeg(const ExtMachInst & machInst) +{ + seg = SEGMENT_REG_DS; + //Handle any segment override that might have been in the instruction + int segFromInst = machInst.legacy.seg; + if (segFromInst) + seg = (SegmentRegIndex)(segFromInst - 1); +} diff --git a/src/arch/x86/emulenv.hh b/src/arch/x86/emulenv.hh index 1044dbdf9..cdb1bf863 100644 --- a/src/arch/x86/emulenv.hh +++ b/src/arch/x86/emulenv.hh @@ -86,6 +86,7 @@ namespace X86ISA {;} void doModRM(const ExtMachInst & machInst); + void setSeg(const ExtMachInst & machInst); }; }; diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc index 1c94a1251..b81400cc3 100644 --- a/src/arch/x86/faults.cc +++ b/src/arch/x86/faults.cc @@ -85,6 +85,7 @@ * Authors: Gabe Black */ +#include "arch/x86/decoder.hh" #include "arch/x86/faults.hh" #include "base/trace.hh" #include "config/full_system.hh" @@ -100,71 +101,90 @@ namespace X86ISA { #if FULL_SYSTEM - void X86Trap::invoke(ThreadContext * tc) + void X86FaultBase::invoke(ThreadContext * tc) { - panic("X86 faults are not implemented!"); + Addr pc = tc->readPC(); + DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc, vector, describe()); + using namespace X86ISAInst::RomLabels; + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + MicroPC entry; + if (m5reg.mode == LongMode) { + if (isSoft()) { + entry = extern_label_longModeSoftInterrupt; + } else { + entry = extern_label_longModeInterrupt; + } + } else { + entry = extern_label_legacyModeInterrupt; + } + tc->setIntReg(INTREG_MICRO(1), vector); + tc->setIntReg(INTREG_MICRO(7), pc); + if (errorCode != (uint64_t)(-1)) { + if (m5reg.mode == LongMode) { + entry = extern_label_longModeInterruptWithError; + } else { + panic("Legacy mode interrupts with error codes " + "aren't implementde.\n"); + } + // Software interrupts shouldn't have error codes. If one does, + // there would need to be microcode to set it up. + assert(!isSoft()); + tc->setIntReg(INTREG_MICRO(15), errorCode); + } + tc->setMicroPC(romMicroPC(entry)); + tc->setNextMicroPC(romMicroPC(entry) + 1); } - void X86Abort::invoke(ThreadContext * tc) + std::string + X86FaultBase::describe() const { - panic("X86 faults are not implemented!"); - } + std::stringstream ss; + ccprintf(ss, "%s", mnemonic()); + if (errorCode != (uint64_t)(-1)) { + ccprintf(ss, "(%#x)", errorCode); + } - void X86Interrupt::invoke(ThreadContext * tc) - { - panic("X86 faults are not implemented!"); + return ss.str(); } - - void FakeITLBFault::invoke(ThreadContext * tc) + + void X86Trap::invoke(ThreadContext * tc) { - // Start the page table walker. - tc->getITBPtr()->walk(tc, vaddr); + X86FaultBase::invoke(tc); + // This is the same as a fault, but it happens -after- the instruction. + tc->setPC(tc->readNextPC()); + tc->setNextPC(tc->readNextNPC()); + tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst)); } - void FakeDTLBFault::invoke(ThreadContext * tc) + void X86Abort::invoke(ThreadContext * tc) { - // Start the page table walker. - tc->getDTBPtr()->walk(tc, vaddr); + panic("Abort exception!"); } -#else // !FULL_SYSTEM - void FakeITLBFault::invoke(ThreadContext * tc) + void PageFault::invoke(ThreadContext * tc) { - DPRINTF(TLB, "Invoking an ITLB fault for address %#x at pc %#x.\n", - vaddr, tc->readPC()); - Process *p = tc->getProcessPtr(); - TlbEntry entry; - bool success = p->pTable->lookup(vaddr, entry); - if(!success) { - panic("Tried to execute unmapped address %#x.\n", vaddr); + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + X86FaultBase::invoke(tc); + /* + * If something bad happens while trying to enter the page fault + * handler, I'm pretty sure that's a double fault and then all bets are + * off. That means it should be safe to update this state now. + */ + if (m5reg.mode == LongMode) { + tc->setMiscReg(MISCREG_CR2, addr); } else { - Addr alignedVaddr = p->pTable->pageAlign(vaddr); - DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, - entry.pageStart()); - tc->getITBPtr()->insert(alignedVaddr, entry); + tc->setMiscReg(MISCREG_CR2, (uint32_t)addr); } } - void FakeDTLBFault::invoke(ThreadContext * tc) + std::string + PageFault::describe() const { - DPRINTF(TLB, "Invoking an DTLB fault for address %#x at pc %#x.\n", - vaddr, tc->readPC()); - Process *p = tc->getProcessPtr(); - TlbEntry entry; - bool success = p->pTable->lookup(vaddr, entry); - if(!success) { - p->checkAndAllocNextPage(vaddr); - success = p->pTable->lookup(vaddr, entry); - } - if(!success) { - panic("Tried to access unmapped address %#x.\n", vaddr); - } else { - Addr alignedVaddr = p->pTable->pageAlign(vaddr); - DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, - entry.pageStart()); - tc->getDTBPtr()->insert(alignedVaddr, entry); - } + std::stringstream ss; + ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr); + return ss.str(); } + #endif } // namespace X86ISA diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh index 78a55d0e1..fe5132994 100644 --- a/src/arch/x86/faults.hh +++ b/src/arch/x86/faults.hh @@ -58,9 +58,12 @@ #ifndef __ARCH_X86_FAULTS_HH__ #define __ARCH_X86_FAULTS_HH__ +#include "base/bitunion.hh" #include "base/misc.hh" #include "sim/faults.hh" +#include <string> + namespace X86ISA { // Base class for all x86 "faults" where faults is in the m5 sense @@ -69,11 +72,13 @@ namespace X86ISA protected: const char * faultName; const char * mnem; + uint8_t vector; uint64_t errorCode; X86FaultBase(const char * _faultName, const char * _mnem, - uint64_t _errorCode = 0) : - faultName(_faultName), mnem(_mnem), errorCode(_errorCode) + const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1) + : faultName(_faultName), mnem(_mnem), + vector(_vector), errorCode(_errorCode) { } @@ -91,6 +96,17 @@ namespace X86ISA { return mnem; } + + virtual bool isSoft() + { + return false; + } + +#if FULL_SYSTEM + void invoke(ThreadContext * tc); + + virtual std::string describe() const; +#endif }; // Base class for x86 faults which behave as if the underlying instruction @@ -99,8 +115,8 @@ namespace X86ISA { protected: X86Fault(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, vector, _errorCode) {} }; @@ -110,8 +126,8 @@ namespace X86ISA { protected: X86Trap(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, vector, _errorCode) {} #if FULL_SYSTEM @@ -124,8 +140,8 @@ namespace X86ISA { protected: X86Abort(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, vector, _errorCode) {} #if FULL_SYSTEM @@ -138,13 +154,9 @@ namespace X86ISA { protected: X86Interrupt(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, _vector, _errorCode) {} - -#if FULL_SYSTEM - void invoke(ThreadContext * tc); -#endif }; class UnimpInstFault : public FaultBase @@ -201,7 +213,7 @@ namespace X86ISA { public: DivideByZero() : - X86Fault("Divide-by-Zero-Error", "#DE") + X86Fault("Divide-by-Zero-Error", "#DE", 0) {} }; @@ -209,15 +221,15 @@ namespace X86ISA { public: DebugException() : - X86FaultBase("Debug", "#DB") + X86FaultBase("Debug", "#DB", 1) {} }; class NonMaskableInterrupt : public X86Interrupt { public: - NonMaskableInterrupt() : - X86Interrupt("Non-Maskable-Interrupt", "#NMI") + NonMaskableInterrupt(uint8_t _vector) : + X86Interrupt("Non Maskable Interrupt", "#NMI", 2, _vector) {} }; @@ -225,7 +237,7 @@ namespace X86ISA { public: Breakpoint() : - X86Trap("Breakpoint", "#BP") + X86Trap("Breakpoint", "#BP", 3) {} }; @@ -233,7 +245,7 @@ namespace X86ISA { public: OverflowTrap() : - X86Trap("Overflow", "#OF") + X86Trap("Overflow", "#OF", 4) {} }; @@ -241,7 +253,7 @@ namespace X86ISA { public: BoundRange() : - X86Fault("Bound-Range", "#BR") + X86Fault("Bound-Range", "#BR", 5) {} }; @@ -249,7 +261,7 @@ namespace X86ISA { public: InvalidOpcode() : - X86Fault("Invalid-Opcode", "#UD") + X86Fault("Invalid-Opcode", "#UD", 6) {} }; @@ -257,7 +269,7 @@ namespace X86ISA { public: DeviceNotAvailable() : - X86Fault("Device-Not-Available", "#NM") + X86Fault("Device-Not-Available", "#NM", 7) {} }; @@ -265,132 +277,156 @@ namespace X86ISA { public: DoubleFault() : - X86Abort("Double-Fault", "#DF") + X86Abort("Double-Fault", "#DF", 8, 0) {} }; class InvalidTSS : public X86Fault { public: - InvalidTSS() : - X86Fault("Invalid-TSS", "#TS") + InvalidTSS(uint32_t _errorCode) : + X86Fault("Invalid-TSS", "#TS", 10, _errorCode) {} }; class SegmentNotPresent : public X86Fault { public: - SegmentNotPresent() : - X86Fault("Segment-Not-Present", "#NP") + SegmentNotPresent(uint32_t _errorCode) : + X86Fault("Segment-Not-Present", "#NP", 11, _errorCode) {} }; class StackFault : public X86Fault { public: - StackFault() : - X86Fault("Stack", "#SS") + StackFault(uint32_t _errorCode) : + X86Fault("Stack", "#SS", 12, _errorCode) {} }; class GeneralProtection : public X86Fault { public: - GeneralProtection(uint64_t _errorCode) : - X86Fault("General-Protection", "#GP", _errorCode) + GeneralProtection(uint32_t _errorCode) : + X86Fault("General-Protection", "#GP", 13, _errorCode) {} }; class PageFault : public X86Fault { + protected: + BitUnion32(PageFaultErrorCode) + Bitfield<0> present; + Bitfield<1> write; + Bitfield<2> user; + Bitfield<3> reserved; + Bitfield<4> fetch; + EndBitUnion(PageFaultErrorCode) + + Addr addr; + public: - PageFault() : - X86Fault("Page-Fault", "#PF") + PageFault(Addr _addr, uint32_t _errorCode) : + X86Fault("Page-Fault", "#PF", 14, _errorCode), addr(_addr) {} + + PageFault(Addr _addr, bool present, bool write, + bool user, bool reserved, bool fetch) : + X86Fault("Page-Fault", "#PF", 14, 0), addr(_addr) + { + PageFaultErrorCode code = 0; + code.present = present; + code.write = write; + code.user = user; + code.reserved = reserved; + code.fetch = fetch; + errorCode = code; + } + +#if FULL_SYSTEM + void invoke(ThreadContext * tc); + + virtual std::string describe() const; +#endif }; class X87FpExceptionPending : public X86Fault { public: X87FpExceptionPending() : - X86Fault("x87 Floating-Point Exception Pending", "#MF") + X86Fault("x87 Floating-Point Exception Pending", "#MF", 16) {} }; - class AlignmentCheck : X86Fault + class AlignmentCheck : public X86Fault { public: AlignmentCheck() : - X86Fault("Alignment-Check", "#AC") + X86Fault("Alignment-Check", "#AC", 17, 0) {} }; - class MachineCheck : X86Abort + class MachineCheck : public X86Abort { public: MachineCheck() : - X86Abort("Machine-Check", "#MC") + X86Abort("Machine-Check", "#MC", 18) {} }; - class SIMDFloatingPointFault : X86Fault + class SIMDFloatingPointFault : public X86Fault { public: SIMDFloatingPointFault() : - X86Fault("SIMD Floating-Point", "#XF") + X86Fault("SIMD Floating-Point", "#XF", 19) {} }; - class SecurityException : X86FaultBase + class SecurityException : public X86FaultBase { public: SecurityException() : - X86FaultBase("Security Exception", "#SX") + X86FaultBase("Security Exception", "#SX", 30) {} }; - class ExternalInterrupt : X86Interrupt + class ExternalInterrupt : public X86Interrupt { public: - ExternalInterrupt() : - X86Interrupt("External Interrupt", "#INTR") + ExternalInterrupt(uint8_t _vector) : + X86Interrupt("External Interrupt", "#INTR", _vector) {} }; - class SoftwareInterrupt : X86Interrupt + class SystemManagementInterrupt : public X86Interrupt { public: - SoftwareInterrupt() : - X86Interrupt("Software Interrupt", "INTn") + SystemManagementInterrupt() : + X86Interrupt("System Management Interrupt", "#SMI", 0) {} }; - // These faults aren't part of the ISA definition. They trigger filling - // the tlb on a miss and are to take the place of a hardware table walker. - class FakeITLBFault : public X86Fault + class InitInterrupt : public X86Interrupt { - protected: - Addr vaddr; + uint8_t vector; public: - FakeITLBFault(Addr _vaddr) : - X86Fault("fake instruction tlb fault", "itlb"), - vaddr(_vaddr) + InitInterrupt(uint8_t _vector) : + X86Interrupt("INIT Interrupt", "#INIT", _vector) {} - - void invoke(ThreadContext * tc); }; - class FakeDTLBFault : public X86Fault + class SoftwareInterrupt : public X86Interrupt { - protected: - Addr vaddr; public: - FakeDTLBFault(Addr _vaddr) : - X86Fault("fake data tlb fault", "dtlb"), - vaddr(_vaddr) + SoftwareInterrupt(uint8_t _vector) : + X86Interrupt("Software Interrupt", "#INTR", _vector) {} - void invoke(ThreadContext * tc); + bool isSoft() + { + return true; + } }; }; diff --git a/src/arch/x86/floatregfile.cc b/src/arch/x86/floatregfile.cc index 1c49ea9c6..fce7f4868 100644 --- a/src/arch/x86/floatregfile.cc +++ b/src/arch/x86/floatregfile.cc @@ -96,15 +96,6 @@ using namespace std; class Checkpoint; -string X86ISA::getFloatRegName(RegIndex index) -{ - static std::string floatRegName[NumFloatRegs] = - {"mmx0", "mmx1", "mmx2", "mmx3", "mmx4", "mmx5", "mmx6", "mmx7", - "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", - "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}; - return floatRegName[index]; -} - void FloatRegFile::clear() { memset(q, 0, sizeof(FloatReg) * NumFloatRegs); @@ -113,27 +104,27 @@ void FloatRegFile::clear() FloatReg FloatRegFile::readReg(int floatReg, int width) { FloatReg reg = d[floatReg]; - DPRINTF(X86, "Reading %f from register %d.\n", reg, floatReg); + DPRINTF(FloatRegs, "Reading %f from register %d.\n", reg, floatReg); return reg; } FloatRegBits FloatRegFile::readRegBits(int floatReg, int width) { FloatRegBits reg = q[floatReg]; - DPRINTF(X86, "Reading %#x from register %d.\n", reg, floatReg); + DPRINTF(FloatRegs, "Reading %#x from register %d.\n", reg, floatReg); return reg; } Fault FloatRegFile::setReg(int floatReg, const FloatReg &val, int width) { - DPRINTF(X86, "Writing %f to register %d.\n", val, floatReg); + DPRINTF(FloatRegs, "Writing %f to register %d.\n", val, floatReg); d[floatReg] = val; return NoFault; } Fault FloatRegFile::setRegBits(int floatReg, const FloatRegBits &val, int width) { - DPRINTF(X86, "Writing bits %#x to register %d.\n", val, floatReg); + DPRINTF(FloatRegs, "Writing bits %#x to register %d.\n", val, floatReg); q[floatReg] = val; return NoFault; } diff --git a/src/arch/x86/floatregfile.hh b/src/arch/x86/floatregfile.hh index b77ddb0eb..ab239dd7d 100644 --- a/src/arch/x86/floatregfile.hh +++ b/src/arch/x86/floatregfile.hh @@ -98,8 +98,6 @@ class Checkpoint; namespace X86ISA { - std::string getFloatRegName(RegIndex); - //Each 128 bit xmm register is broken into two effective 64 bit registers. const int NumFloatRegs = NumMMXRegs + 2 * NumXMMRegs + NumMicroFpRegs; diff --git a/src/arch/x86/insts/macroop.hh b/src/arch/x86/insts/macroop.hh new file mode 100644 index 000000000..d6925a1a5 --- /dev/null +++ b/src/arch/x86/insts/macroop.hh @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_INSTS_MACROOP_HH__ +#define __ARCH_X86_INSTS_MACROOP_HH__ + +#include "arch/x86/emulenv.hh" +#include "arch/x86/types.hh" +#include "arch/x86/insts/static_inst.hh" + +namespace X86ISA +{ +// Base class for combinationally generated macroops +class MacroopBase : public X86StaticInst +{ + protected: + const char *macrocodeBlock; + + const uint32_t numMicroops; + X86ISA::EmulEnv env; + + //Constructor. + MacroopBase(const char *mnem, ExtMachInst _machInst, + uint32_t _numMicroops, X86ISA::EmulEnv _env) : + X86StaticInst(mnem, _machInst, No_OpClass), + numMicroops(_numMicroops), env(_env) + { + assert(numMicroops); + microops = new StaticInstPtr[numMicroops]; + flags[IsMacroop] = true; + } + + ~MacroopBase() + { + delete [] microops; + } + + StaticInstPtr * microops; + + StaticInstPtr fetchMicroop(MicroPC microPC) + { + assert(microPC < numMicroops); + return microops[microPC]; + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return mnemonic; + } + + public: + ExtMachInst + getExtMachInst() + { + return machInst; + } + + X86ISA::EmulEnv + getEmulEnv() + { + return env; + } +}; +} + +#endif //__ARCH_X86_INSTS_MACROOP_HH__ diff --git a/src/arch/x86/insts/microldstop.cc b/src/arch/x86/insts/microldstop.cc index 9638a2ae3..7cc6a330f 100644 --- a/src/arch/x86/insts/microldstop.cc +++ b/src/arch/x86/insts/microldstop.cc @@ -64,7 +64,6 @@ namespace X86ISA const SymbolTable *symtab) const { std::stringstream response; - bool someAddr = false; printMnemonic(response, instMnem, mnemonic); if(flags[IsLoad]) @@ -72,32 +71,8 @@ namespace X86ISA else printSrcReg(response, 2, dataSize); response << ", "; - printSegment(response, segment); - response << ":["; - if(scale != 0 && _srcRegIdx[0] != ZeroReg) - { - if(scale != 1) - ccprintf(response, "%d*", scale); - printSrcReg(response, 0, addressSize); - someAddr = true; - } - if(_srcRegIdx[1] != ZeroReg) - { - if(someAddr) - response << " + "; - printSrcReg(response, 1, addressSize); - someAddr = true; - } - if(disp != 0) - { - if(someAddr) - response << " + "; - ccprintf(response, "%#x", disp); - someAddr = true; - } - if(!someAddr) - response << "0"; - response << "]"; + printMem(response, segment, scale, index, base, disp, + addressSize, false); return response.str(); } } diff --git a/src/arch/x86/insts/microldstop.hh b/src/arch/x86/insts/microldstop.hh index 5b1210d69..1774454c3 100644 --- a/src/arch/x86/insts/microldstop.hh +++ b/src/arch/x86/insts/microldstop.hh @@ -59,9 +59,18 @@ #define __ARCH_X86_INSTS_MICROLDSTOP_HH__ #include "arch/x86/insts/microop.hh" +#include "mem/packet.hh" +#include "mem/request.hh" namespace X86ISA { + static const Request::FlagsType SegmentFlagMask = mask(4); + static const int FlagShift = 4; + enum FlagBit { + CPL0FlagBit = 1, + AddrSizeFlagBit = 2 + }; + /** * Base class for load and store ops */ @@ -76,6 +85,7 @@ namespace X86ISA const RegIndex data; const uint8_t dataSize; const uint8_t addressSize; + const Request::FlagsType memFlags; RegIndex foldOBit, foldABit; //Constructor @@ -86,13 +96,15 @@ namespace X86ISA uint64_t _disp, uint8_t _segment, RegIndex _data, uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags, OpClass __opClass) : X86MicroopBase(machInst, mnem, _instMnem, isMicro, isDelayed, isFirst, isLast, __opClass), scale(_scale), index(_index), base(_base), disp(_disp), segment(_segment), data(_data), - dataSize(_dataSize), addressSize(_addressSize) + dataSize(_dataSize), addressSize(_addressSize), + memFlags(_memFlags | _segment) { foldOBit = (dataSize == 1 && !_machInst.rex.present) ? 1 << 6 : 0; foldABit = @@ -149,6 +161,25 @@ namespace X86ISA } return fault; } + + uint64_t + get(PacketPtr pkt) const + { + switch(dataSize) + { + case 1: + return pkt->get<uint8_t>(); + case 2: + return pkt->get<uint16_t>(); + case 4: + return pkt->get<uint32_t>(); + case 8: + return pkt->get<uint64_t>(); + default: + panic("Bad operand size %d for read at %#x.\n", + dataSize, pkt->getAddr()); + } + } }; } diff --git a/src/arch/x86/insts/microop.cc b/src/arch/x86/insts/microop.cc index 494c0b303..c7bfc3703 100644 --- a/src/arch/x86/insts/microop.cc +++ b/src/arch/x86/insts/microop.cc @@ -98,7 +98,7 @@ namespace X86ISA case ConditionTests::SxOF: return ccflags.sf ^ ccflags.of; case ConditionTests::SxOvZF: - return ccflags.sf ^ ccflags.of | ccflags.zf; + return (ccflags.sf ^ ccflags.of) | ccflags.zf; case ConditionTests::False: return false; case ConditionTests::NotECF: @@ -131,7 +131,7 @@ namespace X86ISA case ConditionTests::NotSxOF: return !(ccflags.sf ^ ccflags.of); case ConditionTests::NotSxOvZF: - return !(ccflags.sf ^ ccflags.of | ccflags.zf); + return !((ccflags.sf ^ ccflags.of) | ccflags.zf); } panic("Unknown condition: %d\n", condition); return true; diff --git a/src/arch/x86/insts/microregop.cc b/src/arch/x86/insts/microregop.cc index 080926627..2ea975746 100644 --- a/src/arch/x86/insts/microregop.cc +++ b/src/arch/x86/insts/microregop.cc @@ -67,6 +67,9 @@ namespace X86ISA bool subtract) const { DPRINTF(X86, "flagMask = %#x\n", flagMask); + if (_destRegIdx[0] & (1 << 6)) { + _dest >>= 8; + } uint64_t flags = oldFlags & ~flagMask; if(flagMask & (ECFBit | CFBit)) { diff --git a/src/arch/x86/insts/static_inst.cc b/src/arch/x86/insts/static_inst.cc index 0c1508d5a..f4ed44603 100644 --- a/src/arch/x86/insts/static_inst.cc +++ b/src/arch/x86/insts/static_inst.cc @@ -63,13 +63,13 @@ namespace X86ISA void X86StaticInst::printMnemonic(std::ostream &os, const char * mnemonic) const { - ccprintf(os, "\t%s ", mnemonic); + ccprintf(os, " %s ", mnemonic); } void X86StaticInst::printMnemonic(std::ostream &os, const char * instMnemonic, const char * mnemonic) const { - ccprintf(os, "\t%s : %s ", instMnemonic, mnemonic); + ccprintf(os, " %s : %s ", instMnemonic, mnemonic); } void X86StaticInst::printSegment(std::ostream &os, int segment) const @@ -240,6 +240,44 @@ namespace X86ISA } } + void X86StaticInst::printMem(std::ostream &os, uint8_t segment, + uint8_t scale, RegIndex index, RegIndex base, + uint64_t disp, uint8_t addressSize, bool rip) const + { + bool someAddr = false; + printSegment(os, segment); + os << ":["; + if (rip) { + os << "rip"; + someAddr = true; + } else { + if (scale != 0 && index != ZeroReg) + { + if(scale != 1) + ccprintf(os, "%d*", scale); + printReg(os, index, addressSize); + someAddr = true; + } + if (base != ZeroReg) + { + if(someAddr) + os << " + "; + printReg(os, base, addressSize); + someAddr = true; + } + } + if (disp != 0) + { + if(someAddr) + os << " + "; + ccprintf(os, "%#x", disp); + someAddr = true; + } + if (!someAddr) + os << "0"; + os << "]"; + } + std::string X86StaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const { diff --git a/src/arch/x86/insts/static_inst.hh b/src/arch/x86/insts/static_inst.hh index e5c333e75..8480f2713 100644 --- a/src/arch/x86/insts/static_inst.hh +++ b/src/arch/x86/insts/static_inst.hh @@ -89,6 +89,9 @@ namespace X86ISA void printReg(std::ostream &os, int reg, int size) const; void printSrcReg(std::ostream &os, int reg, int size) const; void printDestReg(std::ostream &os, int reg, int size) const; + void printMem(std::ostream &os, uint8_t segment, + uint8_t scale, RegIndex index, RegIndex base, + uint64_t disp, uint8_t addressSize, bool rip) const; inline uint64_t merge(uint64_t into, uint64_t val, int size) const { diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc new file mode 100644 index 000000000..30c532c2b --- /dev/null +++ b/src/arch/x86/interrupts.cc @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/apicregs.hh" +#include "arch/x86/interrupts.hh" +#include "arch/x86/intmessage.hh" +#include "cpu/base.hh" +#include "mem/packet_access.hh" + +int +divideFromConf(uint32_t conf) +{ + // This figures out what division we want from the division configuration + // register in the local APIC. The encoding is a little odd but it can + // be deciphered fairly easily. + int shift = ((conf & 0x8) >> 1) | (conf & 0x3); + shift = (shift + 1) % 8; + return 1 << shift; +} + +namespace X86ISA +{ + +ApicRegIndex +decodeAddr(Addr paddr) +{ + ApicRegIndex regNum; + paddr &= ~mask(3); + switch (paddr) + { + case 0x20: + regNum = APIC_ID; + break; + case 0x30: + regNum = APIC_VERSION; + break; + case 0x80: + regNum = APIC_TASK_PRIORITY; + break; + case 0x90: + regNum = APIC_ARBITRATION_PRIORITY; + break; + case 0xA0: + regNum = APIC_PROCESSOR_PRIORITY; + break; + case 0xB0: + regNum = APIC_EOI; + break; + case 0xD0: + regNum = APIC_LOGICAL_DESTINATION; + break; + case 0xE0: + regNum = APIC_DESTINATION_FORMAT; + break; + case 0xF0: + regNum = APIC_SPURIOUS_INTERRUPT_VECTOR; + break; + case 0x100: + case 0x108: + case 0x110: + case 0x118: + case 0x120: + case 0x128: + case 0x130: + case 0x138: + case 0x140: + case 0x148: + case 0x150: + case 0x158: + case 0x160: + case 0x168: + case 0x170: + case 0x178: + regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8); + break; + case 0x180: + case 0x188: + case 0x190: + case 0x198: + case 0x1A0: + case 0x1A8: + case 0x1B0: + case 0x1B8: + case 0x1C0: + case 0x1C8: + case 0x1D0: + case 0x1D8: + case 0x1E0: + case 0x1E8: + case 0x1F0: + case 0x1F8: + regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8); + break; + case 0x200: + case 0x208: + case 0x210: + case 0x218: + case 0x220: + case 0x228: + case 0x230: + case 0x238: + case 0x240: + case 0x248: + case 0x250: + case 0x258: + case 0x260: + case 0x268: + case 0x270: + case 0x278: + regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8); + break; + case 0x280: + regNum = APIC_ERROR_STATUS; + break; + case 0x300: + regNum = APIC_INTERRUPT_COMMAND_LOW; + break; + case 0x310: + regNum = APIC_INTERRUPT_COMMAND_HIGH; + break; + case 0x320: + regNum = APIC_LVT_TIMER; + break; + case 0x330: + regNum = APIC_LVT_THERMAL_SENSOR; + break; + case 0x340: + regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; + break; + case 0x350: + regNum = APIC_LVT_LINT0; + break; + case 0x360: + regNum = APIC_LVT_LINT1; + break; + case 0x370: + regNum = APIC_LVT_ERROR; + break; + case 0x380: + regNum = APIC_INITIAL_COUNT; + break; + case 0x390: + regNum = APIC_CURRENT_COUNT; + break; + case 0x3E0: + regNum = APIC_DIVIDE_CONFIGURATION; + break; + default: + // A reserved register field. + panic("Accessed reserved register field %#x.\n", paddr); + break; + } + return regNum; +} +} + +Tick +X86ISA::Interrupts::read(PacketPtr pkt) +{ + Addr offset = pkt->getAddr() - pioAddr; + //Make sure we're at least only accessing one register. + if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) + panic("Accessed more than one register at a time in the APIC!\n"); + ApicRegIndex reg = decodeAddr(offset); + uint32_t val = htog(readReg(reg)); + DPRINTF(LocalApic, + "Reading Local APIC register %d at offset %#x as %#x.\n", + reg, offset, val); + pkt->setData(((uint8_t *)&val) + (offset & mask(3))); + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::Interrupts::write(PacketPtr pkt) +{ + Addr offset = pkt->getAddr() - pioAddr; + //Make sure we're at least only accessing one register. + if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) + panic("Accessed more than one register at a time in the APIC!\n"); + ApicRegIndex reg = decodeAddr(offset); + uint32_t val = regs[reg]; + pkt->writeData(((uint8_t *)&val) + (offset & mask(3))); + DPRINTF(LocalApic, + "Writing Local APIC register %d at offset %#x as %#x.\n", + reg, offset, gtoh(val)); + setReg(reg, gtoh(val)); + pkt->makeAtomicResponse(); + return latency; +} +void +X86ISA::Interrupts::requestInterrupt(uint8_t vector, + uint8_t deliveryMode, bool level) +{ + /* + * Fixed and lowest-priority delivery mode interrupts are handled + * using the IRR/ISR registers, checking against the TPR, etc. + * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through. + */ + if (deliveryMode == DeliveryMode::Fixed || + deliveryMode == DeliveryMode::LowestPriority) { + DPRINTF(LocalApic, "Interrupt is an %s.\n", + DeliveryMode::names[deliveryMode]); + // Queue up the interrupt in the IRR. + if (vector > IRRV) + IRRV = vector; + if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) { + setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector); + if (level) { + setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); + } else { + clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); + } + } + } else if (!DeliveryMode::isReserved(deliveryMode)) { + DPRINTF(LocalApic, "Interrupt is an %s.\n", + DeliveryMode::names[deliveryMode]); + if (deliveryMode == DeliveryMode::SMI && !pendingSmi) { + pendingUnmaskableInt = pendingSmi = true; + smiVector = vector; + } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) { + pendingUnmaskableInt = pendingNmi = true; + nmiVector = vector; + } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) { + pendingExtInt = true; + extIntVector = vector; + } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) { + pendingUnmaskableInt = pendingInit = true; + initVector = vector; + } + } + cpu->wakeup(); +} + +Tick +X86ISA::Interrupts::recvMessage(PacketPtr pkt) +{ + uint8_t id = 0; + Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0); + assert(pkt->cmd == MemCmd::MessageReq); + switch(offset) + { + case 0: + { + TriggerIntMessage message = pkt->get<TriggerIntMessage>(); + DPRINTF(LocalApic, + "Got Trigger Interrupt message with vector %#x.\n", + message.vector); + // Make sure we're really supposed to get this. + assert((message.destMode == 0 && message.destination == id) || + (bits((int)message.destination, id))); + + requestInterrupt(message.vector, + message.deliveryMode, message.trigger); + } + break; + default: + panic("Local apic got unknown interrupt message at offset %#x.\n", + offset); + break; + } + delete pkt->req; + delete pkt; + return latency; +} + + +uint32_t +X86ISA::Interrupts::readReg(ApicRegIndex reg) +{ + if (reg >= APIC_TRIGGER_MODE(0) && + reg <= APIC_TRIGGER_MODE(15)) { + panic("Local APIC Trigger Mode registers are unimplemented.\n"); + } + switch (reg) { + case APIC_ARBITRATION_PRIORITY: + panic("Local APIC Arbitration Priority register unimplemented.\n"); + break; + case APIC_PROCESSOR_PRIORITY: + panic("Local APIC Processor Priority register unimplemented.\n"); + break; + case APIC_ERROR_STATUS: + regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); + break; + case APIC_INTERRUPT_COMMAND_LOW: + panic("Local APIC Interrupt Command low" + " register unimplemented.\n"); + break; + case APIC_INTERRUPT_COMMAND_HIGH: + panic("Local APIC Interrupt Command high" + " register unimplemented.\n"); + break; + case APIC_CURRENT_COUNT: + { + if (apicTimerEvent.scheduled()) { + assert(clock); + // Compute how many m5 ticks happen per count. + uint64_t ticksPerCount = clock * + divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]); + // Compute how many m5 ticks are left. + uint64_t val = apicTimerEvent.when() - curTick; + // Turn that into a count. + val = (val + ticksPerCount - 1) / ticksPerCount; + return val; + } else { + return 0; + } + } + default: + break; + } + return regs[reg]; +} + +void +X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) +{ + uint32_t newVal = val; + if (reg >= APIC_IN_SERVICE(0) && + reg <= APIC_IN_SERVICE(15)) { + panic("Local APIC In-Service registers are unimplemented.\n"); + } + if (reg >= APIC_TRIGGER_MODE(0) && + reg <= APIC_TRIGGER_MODE(15)) { + panic("Local APIC Trigger Mode registers are unimplemented.\n"); + } + if (reg >= APIC_INTERRUPT_REQUEST(0) && + reg <= APIC_INTERRUPT_REQUEST(15)) { + panic("Local APIC Interrupt Request registers " + "are unimplemented.\n"); + } + switch (reg) { + case APIC_ID: + newVal = val & 0xFF; + break; + case APIC_VERSION: + // The Local APIC Version register is read only. + return; + case APIC_TASK_PRIORITY: + newVal = val & 0xFF; + break; + case APIC_ARBITRATION_PRIORITY: + panic("Local APIC Arbitration Priority register unimplemented.\n"); + break; + case APIC_PROCESSOR_PRIORITY: + panic("Local APIC Processor Priority register unimplemented.\n"); + break; + case APIC_EOI: + // Remove the interrupt that just completed from the local apic state. + clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); + updateISRV(); + return; + case APIC_LOGICAL_DESTINATION: + newVal = val & 0xFF000000; + break; + case APIC_DESTINATION_FORMAT: + newVal = val | 0x0FFFFFFF; + break; + case APIC_SPURIOUS_INTERRUPT_VECTOR: + regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1); + regs[APIC_INTERNAL_STATE] |= val & (1 << 8); + if (val & (1 << 9)) + warn("Focus processor checking not implemented.\n"); + break; + case APIC_ERROR_STATUS: + { + if (regs[APIC_INTERNAL_STATE] & 0x1) { + regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); + newVal = 0; + } else { + regs[APIC_INTERNAL_STATE] |= ULL(0x1); + return; + } + + } + break; + case APIC_INTERRUPT_COMMAND_LOW: + panic("Local APIC Interrupt Command low" + " register unimplemented.\n"); + break; + case APIC_INTERRUPT_COMMAND_HIGH: + panic("Local APIC Interrupt Command high" + " register unimplemented.\n"); + break; + case APIC_LVT_TIMER: + case APIC_LVT_THERMAL_SENSOR: + case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: + case APIC_LVT_LINT0: + case APIC_LVT_LINT1: + case APIC_LVT_ERROR: + { + uint64_t readOnlyMask = (1 << 12) | (1 << 14); + newVal = (val & ~readOnlyMask) | + (regs[reg] & readOnlyMask); + } + break; + case APIC_INITIAL_COUNT: + { + assert(clock); + newVal = bits(val, 31, 0); + // Compute how many timer ticks we're being programmed for. + uint64_t newCount = newVal * + (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); + // Schedule on the edge of the next tick plus the new count. + Tick offset = curTick % clock; + if (offset) { + reschedule(apicTimerEvent, + curTick + (newCount + 1) * clock - offset, true); + } else { + reschedule(apicTimerEvent, + curTick + newCount * clock, true); + } + } + break; + case APIC_CURRENT_COUNT: + //Local APIC Current Count register is read only. + return; + case APIC_DIVIDE_CONFIGURATION: + newVal = val & 0xB; + break; + default: + break; + } + regs[reg] = newVal; + return; +} + +bool +X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const +{ + RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS); + if (pendingUnmaskableInt) { + DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n"); + return true; + } + if (rflags.intf) { + if (pendingExtInt) { + DPRINTF(LocalApic, "Reported pending external interrupt.\n"); + return true; + } + if (IRRV > ISRV && bits(IRRV, 7, 4) > + bits(regs[APIC_TASK_PRIORITY], 7, 4)) { + DPRINTF(LocalApic, "Reported pending regular interrupt.\n"); + return true; + } + } + return false; +} + +Fault +X86ISA::Interrupts::getInterrupt(ThreadContext *tc) +{ + assert(checkInterrupts(tc)); + // These are all probably fairly uncommon, so we'll make them easier to + // check for. + if (pendingUnmaskableInt) { + if (pendingSmi) { + DPRINTF(LocalApic, "Generated SMI fault object.\n"); + return new SystemManagementInterrupt(); + } else if (pendingNmi) { + DPRINTF(LocalApic, "Generated NMI fault object.\n"); + return new NonMaskableInterrupt(nmiVector); + } else if (pendingInit) { + DPRINTF(LocalApic, "Generated INIT fault object.\n"); + return new InitInterrupt(initVector); + } else { + panic("pendingUnmaskableInt set, but no unmaskable " + "ints were pending.\n"); + return NoFault; + } + } else if (pendingExtInt) { + DPRINTF(LocalApic, "Generated external interrupt fault object.\n"); + return new ExternalInterrupt(extIntVector); + } else { + DPRINTF(LocalApic, "Generated regular interrupt fault object.\n"); + // The only thing left are fixed and lowest priority interrupts. + return new ExternalInterrupt(IRRV); + } +} + +void +X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc) +{ + assert(checkInterrupts(tc)); + if (pendingUnmaskableInt) { + if (pendingSmi) { + DPRINTF(LocalApic, "SMI sent to core.\n"); + pendingSmi = false; + } else if (pendingNmi) { + DPRINTF(LocalApic, "NMI sent to core.\n"); + pendingNmi = false; + } else if (pendingInit) { + DPRINTF(LocalApic, "Init sent to core.\n"); + pendingInit = false; + } + if (!(pendingSmi || pendingNmi || pendingInit)) + pendingUnmaskableInt = false; + } else if (pendingExtInt) { + pendingExtInt = false; + } else { + DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV); + // Mark the interrupt as "in service". + ISRV = IRRV; + setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); + // Clear it out of the IRR. + clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV); + updateIRRV(); + } +} + +X86ISA::Interrupts * +X86LocalApicParams::create() +{ + return new X86ISA::Interrupts(this); +} diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh index cf9109e22..c5e3bde0d 100644 --- a/src/arch/x86/interrupts.hh +++ b/src/arch/x86/interrupts.hh @@ -58,73 +58,274 @@ #ifndef __ARCH_X86_INTERRUPTS_HH__ #define __ARCH_X86_INTERRUPTS_HH__ +#include "arch/x86/apicregs.hh" #include "arch/x86/faults.hh" +#include "arch/x86/intmessage.hh" +#include "base/bitfield.hh" #include "cpu/thread_context.hh" +#include "dev/io_device.hh" +#include "dev/x86/intdev.hh" +#include "params/X86LocalApic.hh" +#include "sim/eventq.hh" -namespace X86ISA -{ +class ThreadContext; +class BaseCPU; + +namespace X86ISA { -class Interrupts +class Interrupts : public BasicPioDevice, IntDev { + protected: + // Storage for the APIC registers + uint32_t regs[NUM_APIC_REGS]; + + BitUnion32(LVTEntry) + Bitfield<7, 0> vector; + Bitfield<10, 8> deliveryMode; + Bitfield<12> status; + Bitfield<13> polarity; + Bitfield<14> remoteIRR; + Bitfield<15> trigger; + Bitfield<16> masked; + Bitfield<17> periodic; + EndBitUnion(LVTEntry) + + /* + * Timing related stuff. + */ + Tick latency; + Tick clock; + + class ApicTimerEvent : public Event + { + private: + Interrupts *localApic; + public: + ApicTimerEvent(Interrupts *_localApic) : + Event(), localApic(_localApic) + {} + + void process() + { + assert(localApic); + if (localApic->triggerTimerInterrupt()) { + localApic->setReg(APIC_INITIAL_COUNT, + localApic->readReg(APIC_INITIAL_COUNT)); + } + } + }; + + ApicTimerEvent apicTimerEvent; + + /* + * A set of variables to keep track of interrupts that don't go through + * the IRR. + */ + bool pendingSmi; + uint8_t smiVector; + bool pendingNmi; + uint8_t nmiVector; + bool pendingExtInt; + uint8_t extIntVector; + bool pendingInit; + uint8_t initVector; + + // This is a quick check whether any of the above (except ExtInt) are set. + bool pendingUnmaskableInt; + + /* + * IRR and ISR maintenance. + */ + uint8_t IRRV; + uint8_t ISRV; + + int + findRegArrayMSB(ApicRegIndex base) + { + int offset = 7; + do { + if (regs[base + offset] != 0) { + return offset * 32 + findMsbSet(regs[base + offset]); + } + } while (offset--); + return 0; + } + + void + updateIRRV() + { + IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE); + } + + void + updateISRV() + { + ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE); + } + + void + setRegArrayBit(ApicRegIndex base, uint8_t vector) + { + regs[base + (vector % 32)] |= (1 << (vector >> 5)); + } + + void + clearRegArrayBit(ApicRegIndex base, uint8_t vector) + { + regs[base + (vector % 32)] &= ~(1 << (vector >> 5)); + } + + bool + getRegArrayBit(ApicRegIndex base, uint8_t vector) + { + return bits(regs[base + (vector % 32)], vector >> 5); + } + + void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level); + + BaseCPU *cpu; + public: - Interrupts() + /* + * Params stuff. + */ + typedef X86LocalApicParams Params; + + void + setCPU(BaseCPU * newCPU) { - clear_all(); + cpu = newCPU; } - int InterruptLevel(uint64_t softint) + void + setClock(Tick newClock) { - panic("Interrupts::InterruptLevel unimplemented!\n"); - return 0; + clock = newClock; } - void post(int int_num, int index) + const Params * + params() const { - panic("Interrupts::post unimplemented!\n"); + return dynamic_cast<const Params *>(_params); } - void clear(int int_num, int index) + /* + * Functions to interact with the interrupt port from IntDev. + */ + Tick read(PacketPtr pkt); + Tick write(PacketPtr pkt); + Tick recvMessage(PacketPtr pkt); + + bool + triggerTimerInterrupt() { - warn("Interrupts::clear unimplemented!\n"); + LVTEntry entry = regs[APIC_LVT_TIMER]; + if (!entry.masked) + requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger); + return entry.periodic; } - void clear_all() + void addressRanges(AddrRangeList &range_list) { - warn("Interrupts::clear_all unimplemented!\n"); + range_list.clear(); + range_list.push_back(RangeEx(x86LocalAPICAddress(0, 0), + x86LocalAPICAddress(0, 0) + PageBytes)); } - bool check_interrupts(ThreadContext * tc) const + void getIntAddrRange(AddrRangeList &range_list) { - return false; + range_list.clear(); + range_list.push_back(RangeEx(x86InterruptAddress(0, 0), + x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize)); } - Fault getInterrupt(ThreadContext * tc) + Port *getPort(const std::string &if_name, int idx = -1) { - return NoFault; + if (if_name == "int_port") + return intPort; + return BasicPioDevice::getPort(if_name, idx); } - void updateIntrInfo(ThreadContext * tc) + /* + * Functions to access and manipulate the APIC's registers. + */ + + uint32_t readReg(ApicRegIndex miscReg); + void setReg(ApicRegIndex reg, uint32_t val); + void + setRegNoEffect(ApicRegIndex reg, uint32_t val) { - panic("Interrupts::updateIntrInfo unimplemented!\n"); + regs[reg] = val; } - uint64_t get_vec(int int_num) + /* + * Constructor. + */ + + Interrupts(Params * p) + : BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0), + apicTimerEvent(this), + pendingSmi(false), smiVector(0), + pendingNmi(false), nmiVector(0), + pendingExtInt(false), extIntVector(0), + pendingInit(false), initVector(0), + pendingUnmaskableInt(false) { - panic("Interrupts::get_vec unimplemented!\n"); - return 0; + pioSize = PageBytes; + memset(regs, 0, sizeof(regs)); + //Set the local apic DFR to the flat model. + regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1); + ISRV = 0; + IRRV = 0; } - void serialize(std::ostream & os) + /* + * Functions for retrieving interrupts for the CPU to handle. + */ + + bool checkInterrupts(ThreadContext *tc) const; + Fault getInterrupt(ThreadContext *tc); + void updateIntrInfo(ThreadContext *tc); + + /* + * Serialization. + */ + + void + serialize(std::ostream &os) { panic("Interrupts::serialize unimplemented!\n"); } - void unserialize(Checkpoint * cp, const std::string & section) + void + unserialize(Checkpoint *cp, const std::string §ion) { panic("Interrupts::unserialize unimplemented!\n"); } -}; + /* + * Old functions needed for compatability but which will be phased out + * eventually. + */ + void + post(int int_num, int index) + { + panic("Interrupts::post unimplemented!\n"); + } + + void + clear(int int_num, int index) + { + panic("Interrupts::clear unimplemented!\n"); + } + + void + clearAll() + { + panic("Interrupts::clearAll unimplemented!\n"); + } }; +} // namespace X86ISA + #endif // __ARCH_X86_INTERRUPTS_HH__ diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh new file mode 100644 index 000000000..f5f8519e2 --- /dev/null +++ b/src/arch/x86/intmessage.hh @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_INTMESSAGE_HH__ +#define __ARCH_X86_INTMESSAGE_HH__ + +#include "arch/x86/x86_traits.hh" +#include "base/bitunion.hh" +#include "mem/packet.hh" +#include "mem/request.hh" +#include "sim/host.hh" + +namespace X86ISA +{ + BitUnion32(TriggerIntMessage) + Bitfield<7, 0> destination; + Bitfield<15, 8> vector; + Bitfield<18, 16> deliveryMode; + Bitfield<19> destMode; + Bitfield<20> level; + Bitfield<21> trigger; + EndBitUnion(TriggerIntMessage) + + namespace DeliveryMode + { + enum IntDeliveryMode { + Fixed = 0, + LowestPriority = 1, + SMI = 2, + NMI = 4, + INIT = 5, + ExtInt = 7, + NumModes + }; + + static const char * const names[NumModes] = { + "Fixed", "LowestPriority", "SMI", "Reserved", + "NMI", "INIT", "Reserved", "ExtInt" + }; + + static inline bool + isReserved(int mode) + { + return mode == 3 || mode == 6; + } + } + + static const Addr TriggerIntOffset = 0; + + static inline PacketPtr + prepIntRequest(const uint8_t id, Addr offset, Addr size) + { + RequestPtr req = new Request(x86InterruptAddress(id, offset), + size, Request::UNCACHEABLE); + PacketPtr pkt = new Packet(req, MemCmd::MessageReq, Packet::Broadcast); + pkt->allocate(); + return pkt; + } + + template<class T> + PacketPtr + buildIntRequest(const uint8_t id, T payload, Addr offset, Addr size) + { + PacketPtr pkt = prepIntRequest(id, offset, size); + pkt->set<T>(payload); + return pkt; + } + + static inline PacketPtr + buildIntRequest(const uint8_t id, TriggerIntMessage payload) + { + return buildIntRequest(id, payload, TriggerIntOffset, + sizeof(TriggerIntMessage)); + } + + static inline PacketPtr + buildIntResponse() + { + panic("buildIntResponse not implemented.\n"); + } +} + +#endif diff --git a/src/arch/x86/intregfile.cc b/src/arch/x86/intregfile.cc index 9c9ea134e..58a37cb9e 100644 --- a/src/arch/x86/intregfile.cc +++ b/src/arch/x86/intregfile.cc @@ -97,17 +97,6 @@ using namespace std; class Checkpoint; -string X86ISA::getIntRegName(RegIndex index) -{ - //These might appear to be out of order, but they match - //the encoding for the registers. Who knows why the indexes - //are out of order - static std::string intRegName[NumIntArchRegs] = - {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; - return intRegName[index]; -} - int IntRegFile::flattenIndex(int reg) { return reg; @@ -120,13 +109,15 @@ void IntRegFile::clear() IntReg IntRegFile::readReg(int intReg) { - DPRINTF(X86, "Read int reg %d and got value %#x\n", intReg, regs[intReg]); + DPRINTF(IntRegs, "Read int reg %d and got value %#x\n", + intReg, regs[intReg]); return regs[intReg]; } void IntRegFile::setReg(int intReg, const IntReg &val) { - DPRINTF(X86, "Setting int reg %d to value %#x\n", intReg, val); + DPRINTF(IntRegs, "Setting int reg %d to value %#x\n", + intReg, val); regs[intReg] = val; } diff --git a/src/arch/x86/intregfile.hh b/src/arch/x86/intregfile.hh index b4d256a04..131245352 100644 --- a/src/arch/x86/intregfile.hh +++ b/src/arch/x86/intregfile.hh @@ -100,9 +100,6 @@ namespace X86ISA { class Regfile; - //This function translates integer register file indices into names - std::string getIntRegName(RegIndex); - const int NumIntArchRegs = NUM_INTREGS; const int NumIntRegs = NumIntArchRegs + NumMicroIntRegs + diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index 332ae1641..817986232 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -418,12 +418,27 @@ default: Inst::RET_FAR(); } 0x4: int3(); +#if FULL_SYSTEM 0x5: int_Ib(); +#else + // Really only the LSB matters, but the predecoder will sign + // extend it, and there's no easy way to specify only checking + // the first byte. + 0x5: decode IMMEDIATE { + 0xffffffffffffff80: + SyscallInst::int80('xc->syscall(Rax)', IsSyscall); + default: int_Ib(); + } +#endif 0x6: decode MODE_SUBMODE { 0x0: Inst::UD2(); default: into(); } - 0x7: iret(); + 0x7: decode MODE_SUBMODE { + 0x4: Inst::IRET_REAL(); + 0x3: Inst::IRET_VIRT(); + default: Inst::IRET_PROT(); + } } } 0x1A: decode OPCODE_OP_BOTTOM3 { @@ -549,8 +564,8 @@ 0x1F: decode OPCODE_OP_BOTTOM3 { 0x0: CLC(); 0x1: STC(); - 0x2: WarnUnimpl::cli(); - 0x3: WarnUnimpl::sti(); + 0x2: CLI(); + 0x3: STI(); 0x4: CLD(); 0x5: STD(); //0x6: group4(); diff --git a/src/arch/x86/isa/decoder/two_byte_opcodes.isa b/src/arch/x86/isa/decoder/two_byte_opcodes.isa index 8135a1fdb..1ee62142a 100644 --- a/src/arch/x86/isa/decoder/two_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/two_byte_opcodes.isa @@ -93,8 +93,8 @@ 0x00: decode MODRM_REG { 0x0: sldt_Mw_or_Rv(); 0x1: str_Mw_or_Rv(); - 0x2: lldt_Mw_or_Rv(); - 0x3: ltr_Mw_or_Rv(); + 0x2: Inst::LLDT(Ew); + 0x3: Inst::LTR(Ew); 0x4: verr_Mw_or_Rv(); 0x5: verw_Mw_or_Rv(); //0x6: jmpe_Ev(); // IA-64 @@ -128,7 +128,7 @@ 0x4: smsw_Rv(); 0x6: lmsw_Rv(); 0x7: decode MODRM_RM { - 0x0: swapgs(); + 0x0: Inst::SWAPGS(); 0x1: rdtscp(); default: Inst::UD2(); } @@ -163,17 +163,117 @@ } 0x02: lar_Gv_Ew(); 0x03: lsl_Gv_Ew(); - //sandpile.org doesn't seem to know what this is... ? - 0x04: loadall_or_reset_or_hang(); + // sandpile.org doesn't seem to know what this is...? We'll + // use it for pseudo instructions. We've got 16 bits of space + // to play with so there can be quite a few pseudo + // instructions. + //0x04: loadall_or_reset_or_hang(); + 0x4: decode IMMEDIATE { + format BasicOperate { #if FULL_SYSTEM - 0x05: syscall(); + 0x00: m5arm({{ + PseudoInst::arm(xc->tcBase()); + }}, IsNonSpeculative); + 0x01: m5quiesce({{ + PseudoInst::quiesce(xc->tcBase()); + }}, IsNonSpeculative); + 0x02: m5quiesceNs({{ + PseudoInst::quiesceNs(xc->tcBase(), Rdi); + }}, IsNonSpeculative); + 0x03: m5quiesceCycle({{ + PseudoInst::quiesceCycles(xc->tcBase(), Rdi); + }}, IsNonSpeculative); + 0x04: m5quiesceTime({{ + Rax = PseudoInst::quiesceTime(xc->tcBase()); + }}, IsNonSpeculative); +#endif + 0x07: m5rpns({{ + Rax = PseudoInst::rpns(xc->tcBase()); + }}, IsNonSpeculative); + 0x21: m5exit({{ + PseudoInst::m5exit(xc->tcBase(), Rdi); + }}, IsNonSpeculative); +#if FULL_SYSTEM + 0x30: m5initparam({{ + Rax = xc->tcBase()->getCpuPtr()-> + system->init_param; + }}, IsNonSpeculative); + 0x31: m5loadsymbol({{ + PseudoInst::loadsymbol(xc->tcBase()); + }}, IsNonSpeculative); +#endif + 0x40: m5resetstats({{ + PseudoInst::resetstats(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); + 0x41: m5dumpstats({{ + PseudoInst::dumpstats(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); + 0x42: m5dumpresetstats({{ + PseudoInst::dumpresetstats(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); + 0x43: m5checkpoint({{ + PseudoInst::m5checkpoint(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); +#if FULL_SYSTEM + 0x50: m5readfile({{ + Rax = PseudoInst::readfile( + xc->tcBase(), Rdi, Rsi, Rdx); + }}, IsNonSpeculative); +#endif + 0x51: m5debugbreak({{ + PseudoInst::debugbreak(xc->tcBase()); + }}, IsNonSpeculative); + 0x52: m5switchcpu({{ + PseudoInst::switchcpu(xc->tcBase()); + }}, IsNonSpeculative); +#if FULL_SYSTEM + 0x53: m5addsymbol({{ + PseudoInst::addsymbol(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); +#endif + 0x54: m5panic({{ + panic("M5 panic instruction called at pc=%#x.\n", + xc->readPC()); + }}, IsNonSpeculative); + 0x55: m5reserved1({{ + warn("M5 reserved opcode 1 ignored.\n"); + }}, IsNonSpeculative); + 0x56: m5reserved2({{ + warn("M5 reserved opcode 2 ignored.\n"); + }}, IsNonSpeculative); + 0x57: m5reserved3({{ + warn("M5 reserved opcode 3 ignored.\n"); + }}, IsNonSpeculative); + 0x58: m5reserved4({{ + warn("M5 reserved opcode 4 ignored.\n"); + }}, IsNonSpeculative); + 0x59: m5reserved5({{ + warn("M5 reserved opcode 5 ignored.\n"); + }}, IsNonSpeculative); + default: Inst::UD2(); + } + } +#if FULL_SYSTEM + 0x05: decode MODE_MODE { + 0x0: decode MODE_SUBMODE { + 0x0: Inst::SYSCALL_64(); + 0x1: Inst::SYSCALL_COMPAT(); + } + 0x1: Inst::SYSCALL_LEGACY(); + } #else - 0x05: SyscallInst::syscall('xc->syscall(rax)', IsSyscall); + 0x05: SyscallInst::syscall('xc->syscall(Rax)', IsSyscall); #endif - 0x06: clts(); - //sandpile.org says (AMD) after sysret, so I might want to check - //if that means amd64 or AMD machines - 0x07: loadall_or_sysret(); + 0x06: Inst::CLTS(); + 0x07: decode MODE_SUBMODE { + 0x0: decode OPSIZE { + // Return to 64 bit mode. + 0x8: Inst::SYSRET_TO_64(); + // Return to compatibility mode. + default: Inst::SYSRET_TO_COMPAT(); + } + default: Inst::SYSRET_NON_64(); + } } 0x01: decode OPCODE_OP_BOTTOM3 { 0x0: invd(); @@ -181,9 +281,9 @@ 0x2: Inst::UD2(); 0x3: Inst::UD2(); 0x4: Inst::UD2(); - 0x5: threednow(); - 0x6: threednow(); - 0x7: threednow(); + 0x5: Inst::PREFETCH(Mb); + 0x6: FailUnimpl::femms(); + 0x7: FailUnimpl::threednow(); } 0x02: decode LEGACY_DECODEVAL { // no prefix @@ -235,7 +335,7 @@ //group17(); 0x0: decode MODRM_REG { 0x0: prefetch_nta(); - 0x1: prefetch_t0(); + 0x1: Inst::PREFETCH_T0(Mb); 0x2: prefetch_t1(); 0x3: prefetch_t2(); default: Inst::HINT_NOP(); @@ -252,9 +352,9 @@ // no prefix 0x0: decode OPCODE_OP_BOTTOM3 { 0x0: Inst::MOV(Rd,Cd); - 0x1: mov_Rd_Dd(); + 0x1: Inst::MOV(Rd,Dd); 0x2: Inst::MOV(Cd,Rd); - 0x3: mov_Dd_Rd(); + 0x3: Inst::MOV(Dd,Rd); 0x4: mov_Rd_Td(); 0x6: mov_Td_Rd(); default: Inst::UD2(); @@ -317,10 +417,14 @@ } 0x06: decode OPCODE_OP_BOTTOM3 { 0x0: Inst::WRMSR(); - 0x1: rdtsc(); + 0x1: Inst::RDTSC(); 0x2: Inst::RDMSR(); 0x3: rdpmc(); +#if FULL_SYSTEM 0x4: sysenter(); +#else + 0x4: SyscallInst::sysenter('xc->syscall(Rax)', IsSyscall); +#endif 0x5: sysexit(); 0x6: Inst::UD2(); 0x7: getsec(); @@ -707,7 +811,14 @@ 0x14: decode OPCODE_OP_BOTTOM3 { 0x0: push_fs(); 0x1: pop_fs(); - 0x2: Inst::CPUID(rAd); + 0x2: CPUIDInst::CPUID({{ + CpuidResult result; + success = doCpuid(xc->tcBase(), Rax, result); + Rax = result.rax; + Rbx = result.rbx; + Rcx = result.rcx; + Rdx = result.rdx; + }}); 0x3: Inst::BT(Ev,Gv); 0x4: shld_Ev_Gv_Ib(); 0x5: shld_Ev_Gv_rCl(); @@ -719,20 +830,28 @@ 0x1: pop_gs(); 0x2: rsm_smm(); 0x3: Inst::BTS(Ev,Gv); - 0x4: shrd_Ev_Gv_Ib(); + 0x4: Inst::SHRD(Ev,Gv,Ib); 0x5: shrd_Ev_Gv_rCl(); //0x6: group16(); - 0x6: decode MODRM_MOD { - 0x3: decode MODRM_REG { - 0x5: lfence(); - 0x6: mfence(); - 0x7: sfence(); + 0x6: decode MODRM_REG { + 0x0: fxsave(); + 0x1: fxrstor(); + 0x2: ldmxcsr(); + 0x3: stmxcsr(); + 0x4: Inst::UD2(); + 0x5: decode MODRM_MOD { + 0x3: BasicOperate::LFENCE( + {{/*Nothing*/}}, IsReadBarrier); default: Inst::UD2(); } - default: decode MODRM_REG { - 0x0: fxsave(); - 0x1: fxrstor(); - 0x7: clflush(); + 0x6: decode MODRM_MOD { + 0x3: BasicOperate::MFENCE( + {{/*Nothing*/}}, IsMemBarrier); + default: Inst::UD2(); + } + 0x7: decode MODRM_MOD { + 0x3: BasicOperate::SFENCE( + {{/*Nothing*/}}, IsWriteBarrier); default: Inst::UD2(); } } @@ -775,8 +894,8 @@ 0x7: Inst::MOVSX_W(Gv,Ev); } 0x18: decode OPCODE_OP_BOTTOM3 { - 0x0: xadd_Eb_Gb(); - 0x1: xadd_Ev_Gv(); + 0x0: Inst::XADD(Eb,Gb); + 0x1: Inst::XADD(Ev,Gv); //0x7: group9(); 0x7: decode MODRM_REG { 0x1: cmpxchg_Mq(); @@ -820,7 +939,11 @@ default: Inst::UD2(); } } - 0x19: bswap_B(); + 0x19: decode OPSIZE { + 4: Inst::BSWAP_D(Bd); + 8: Inst::BSWAP_Q(Bq); + default: Inst::UD2(); + } 0x1A: decode LEGACY_DECODEVAL { // no prefix 0x0: decode OPCODE_OP_BOTTOM3 { diff --git a/src/arch/x86/isa/formats/basic.isa b/src/arch/x86/isa/formats/basic.isa index 7aea7085f..b96bae238 100644 --- a/src/arch/x86/isa/formats/basic.isa +++ b/src/arch/x86/isa/formats/basic.isa @@ -147,3 +147,11 @@ def template BasicDecode {{ def template BasicDecodeWithMnemonic {{ return new %(class_name)s("%(mnemonic)s", machInst); }}; + +def format BasicOperate(code, *flags) {{ + iop = InstObjParams(name, Name, 'X86ISA::X86StaticInst', code, flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/x86/isa/formats/cpuid.isa b/src/arch/x86/isa/formats/cpuid.isa new file mode 100644 index 000000000..204270556 --- /dev/null +++ b/src/arch/x86/isa/formats/cpuid.isa @@ -0,0 +1,110 @@ +// Copyright (c) 2008 The Hewlett-Packard Development Company +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the +// following conditions are met: +// +// The software must be used only for Non-Commercial Use which means any +// use which is NOT directed to receiving any direct monetary +// compensation for, or commercial advantage from such use. Illustrative +// examples of non-commercial use are academic research, personal study, +// teaching, education and corporate research & development. +// Illustrative examples of commercial use are distributing products for +// commercial advantage and providing services using the software for +// commercial advantage. +// +// If you wish to use this software or functionality therein that may be +// covered by patents for commercial use, please contact: +// Director of Intellectual Property Licensing +// Office of Strategy and Technology +// Hewlett-Packard Company +// 1501 Page Mill Road +// Palo Alto, California 94304 +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. Redistributions +// in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. Neither the name of +// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. No right of +// sublicense is granted herewith. Derivatives of the software and +// output created using the software may be prepared, but only for +// Non-Commercial Uses. Derivatives of the software may be shared with +// others provided: (i) the others agree to abide by the list of +// conditions herein which includes the Non-Commercial Use restrictions; +// and (ii) such Derivatives of the software include the above copyright +// notice to acknowledge the contribution from this software where +// applicable, this list of conditions and the disclaimer below. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +output header {{ + class CPUIDInst : public X86ISA::X86StaticInst + { + public: + static const RegIndex foldOBit = 0; + /// Constructor + CPUIDInst(const char *_mnemonic, ExtMachInst _machInst, + OpClass __opClass) : + X86ISA::X86StaticInst(_mnemonic, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string CPUIDInst::generateDisassembly(Addr PC, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + ccprintf(response, " "); + printReg(response, _srcRegIdx[0], machInst.opSize); + return response.str(); + } +}}; + +def template CPUIDExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + // If the CPUID instruction used a valid function number, this will + // be set to true. Otherwise, the instruction does nothing. + bool success; + %(op_decl)s; + %(op_rd)s; + %(code)s; + if (success) { + %(op_wb)s; + } + return NoFault; + } +}}; + +def format CPUIDInst(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'CPUIDInst', code, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = CPUIDExecute.subst(iop) +}}; + diff --git a/src/arch/x86/isa/formats/formats.isa b/src/arch/x86/isa/formats/formats.isa index 6906413c0..81179ab45 100644 --- a/src/arch/x86/isa/formats/formats.isa +++ b/src/arch/x86/isa/formats/formats.isa @@ -85,6 +85,9 @@ //Templates from this format are used later ##include "basic.isa" +//Include a format to generate a CPUID instruction. +##include "cpuid.isa" + //Include the "unknown" format ##include "unknown.isa" diff --git a/src/arch/x86/isa/includes.isa b/src/arch/x86/isa/includes.isa index 6724ea9b0..8626f117a 100644 --- a/src/arch/x86/isa/includes.isa +++ b/src/arch/x86/isa/includes.isa @@ -26,7 +26,7 @@ // // Authors: Gabe Black -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -97,6 +97,7 @@ output header {{ #include <iostream> #include "arch/x86/emulenv.hh" +#include "arch/x86/insts/macroop.hh" #include "arch/x86/insts/microfpop.hh" #include "arch/x86/insts/microldstop.hh" #include "arch/x86/insts/microregop.hh" @@ -113,10 +114,13 @@ output header {{ output decoder {{ #include "arch/x86/faults.hh" #include "arch/x86/floatregs.hh" +#include "arch/x86/microcode_rom.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/segmentregs.hh" +#include "arch/x86/tlb.hh" #include "base/cprintf.hh" #include "base/loader/symtab.hh" +#include "base/misc.hh" #include "cpu/thread_context.hh" // for Jump::branchTarget() #include "mem/packet.hh" @@ -144,6 +148,7 @@ output exec {{ #include <limits> #include <cmath> +#include "arch/x86/cpuid.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/tlb.hh" #include "base/bigint.hh" @@ -152,6 +157,8 @@ output exec {{ #include "sim/sim_exit.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" +#include "mem/request.hh" +#include "sim/pseudo_inst.hh" using namespace X86ISA; using namespace std; diff --git a/src/arch/x86/isa/insts/__init__.py b/src/arch/x86/isa/insts/__init__.py index 0ef617a87..d7a8bde19 100644 --- a/src/arch/x86/isa/insts/__init__.py +++ b/src/arch/x86/isa/insts/__init__.py @@ -53,7 +53,8 @@ # # Authors: Gabe Black -categories = ["general_purpose", +categories = ["romutil", + "general_purpose", "simd128", "simd64", "system", diff --git a/src/arch/x86/isa/insts/general_purpose/__init__.py b/src/arch/x86/isa/insts/general_purpose/__init__.py index 4f77cb233..23f955f08 100644 --- a/src/arch/x86/isa/insts/general_purpose/__init__.py +++ b/src/arch/x86/isa/insts/general_purpose/__init__.py @@ -65,7 +65,6 @@ categories = ["arithmetic", "load_segment_registers", "logical", "no_operation", - "processor_information", "rotate_and_shift", "semaphores", "string", diff --git a/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py b/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py index a9b53acac..19d1c7789 100644 --- a/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py +++ b/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py @@ -246,7 +246,7 @@ def macroop DIV_B_R divLoopTop: div2 t1, rax, t1, dataSize=1 div2 t1, rax, t1, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax, dataSize=1 @@ -269,7 +269,7 @@ def macroop DIV_B_M divLoopTop: div2 t1, rax, t1, dataSize=1 div2 t1, rax, t1, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax, dataSize=1 @@ -293,7 +293,7 @@ def macroop DIV_B_P divLoopTop: div2 t1, rax, t1, dataSize=1 div2 t1, rax, t1, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax, dataSize=1 @@ -321,7 +321,7 @@ divLoopTop: div2 t1, rax, t1 div2 t1, rax, t1 div2 t1, rax, t1, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax @@ -347,7 +347,7 @@ divLoopTop: div2 t1, rax, t1 div2 t1, rax, t1 div2 t1, rax, t1, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax @@ -374,7 +374,7 @@ divLoopTop: div2 t1, rax, t1 div2 t1, rax, t1 div2 t1, rax, t1, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax @@ -422,7 +422,7 @@ def macroop IDIV_B_R divLoopTop: div2 t4, t1, t4, dataSize=1 div2 t4, t1, t4, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5, dataSize=1 @@ -495,7 +495,7 @@ def macroop IDIV_B_M divLoopTop: div2 t4, t1, t4, dataSize=1 div2 t4, t1, t4, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5, dataSize=1 @@ -569,7 +569,7 @@ def macroop IDIV_B_P divLoopTop: div2 t4, t1, t4, dataSize=1 div2 t4, t1, t4, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5, dataSize=1 @@ -646,7 +646,7 @@ divLoopTop: div2 t4, t1, t4 div2 t4, t1, t4 div2 t4, t1, t4, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5 @@ -721,7 +721,7 @@ divLoopTop: div2 t4, t1, t4 div2 t4, t1, t4 div2 t4, t1, t4, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5 @@ -797,7 +797,7 @@ divLoopTop: div2 t4, t1, t4 div2 t4, t1, t4 div2 t4, t1, t4, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5 diff --git a/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py b/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py index b5fc43fcd..dbd2d8b84 100644 --- a/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py +++ b/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py @@ -53,20 +53,42 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop PREFETCH_M +{ + ld t0, seg, sib, disp, dataSize=1, prefetch=True +}; + +def macroop PREFETCH_P +{ + rdip t7 + ld t0, seg, riprel, disp, dataSize=1, prefetch=True +}; + +def macroop PREFETCH_T0_M +{ + ld t0, seg, sib, disp, dataSize=1, prefetch=True +}; + +def macroop PREFETCH_T0_P +{ + rdip t7 + ld t0, seg, riprel, disp, dataSize=1, prefetch=True +}; + +''' + #let {{ # class LFENCE(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class SFENCE(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MFENCE(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class PREFETCHlevel(Inst): -# "GenFault ${new UnimpInstFault}" -# class PREFETCH(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class PREFETCHW(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class CLFLUSH(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py b/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py index 71059e80d..22364e038 100644 --- a/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py +++ b/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py @@ -82,11 +82,11 @@ # Authors: Gabe Black microcode = ''' -def macroop BSF_R_R { +def macroop BSR_R_R { # Determine if the input was zero, and also move it to a temp reg. movi t1, t1, t0, dataSize=8 and t1, regm, regm, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0x0 @@ -125,20 +125,19 @@ def macroop BSF_R_R { srli t3, t1, 1, dataSize=8, flags=(EZF,) ori t4, reg, 0x1 mov reg, reg, t4, flags=(nCEZF,) - mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSF_R_M { +def macroop BSR_R_M { movi t1, t1, t0, dataSize=8 ld t1, seg, sib, disp # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0x0 @@ -177,13 +176,12 @@ def macroop BSF_R_M { srli t3, t1, 1, dataSize=8, flags=(EZF,) ori t4, reg, 0x1 mov reg, reg, t4, flags=(nCEZF,) - mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSF_R_P { +def macroop BSR_R_P { rdip t7 movi t1, t1, t0, dataSize=8 @@ -191,7 +189,7 @@ def macroop BSF_R_P { # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0x0 @@ -230,17 +228,16 @@ def macroop BSF_R_P { srli t3, t1, 1, dataSize=8, flags=(EZF,) ori t4, reg, 0x1 mov reg, reg, t4, flags=(nCEZF,) - mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSR_R_R { +def macroop BSF_R_R { # Determine if the input was zero, and also move it to a temp reg. mov t1, t1, t0, dataSize=8 and t1, regm, regm, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0 @@ -248,48 +245,54 @@ def macroop BSR_R_R { subi t2, t1, 1 xor t1, t2, t1 + # Bit 6 - srli t3, t1, 32, dataSize=8 - andi t3, t3, 32 - or reg, reg, t3 + srli t3, t1, 32, dataSize=8, flags=(EZF,) + ori t4, reg, 32 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 5 - srli t3, t1, 16, dataSize=8 - andi t3, t3, 16 - or reg, reg, t3 + srli t3, t1, 16, dataSize=8, flags=(EZF,) + ori t4, reg, 16 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 4 - srli t3, t1, 8, dataSize=8 - andi t3, t3, 8 - or reg, reg, t3 + srli t3, t1, 8, dataSize=8, flags=(EZF,) + ori t4, reg, 8 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 3 - srli t3, t1, 4, dataSize=8 - andi t3, t3, 4 - or reg, reg, t3 + srli t3, t1, 4, dataSize=8, flags=(EZF,) + ori t4, reg, 4 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 2 - srli t3, t1, 2, dataSize=8 - andi t3, t3, 2 - or reg, reg, t3 + srli t3, t1, 2, dataSize=8, flags=(EZF,) + ori t4, reg, 2 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 1 - srli t3, t1, 1, dataSize=8 - andi t3, t3, 1 - or reg, reg, t3 + srli t3, t1, 1, dataSize=8, flags=(EZF,) + ori t4, reg, 1 + mov reg, reg, t4, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSR_R_M { +def macroop BSF_R_M { mov t1, t1, t0, dataSize=8 ld t1, seg, sib, disp # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register mov reg, reg, t0 @@ -298,40 +301,46 @@ def macroop BSR_R_M { xor t1, t2, t1 # Bit 6 - srli t3, t1, 32, dataSize=8 - andi t3, t3, 32 - or reg, reg, t3 + srli t3, t1, 32, dataSize=8, flags=(EZF,) + ori t4, reg, 32 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 5 - srli t3, t1, 16, dataSize=8 - andi t3, t3, 16 - or reg, reg, t3 + srli t3, t1, 16, dataSize=8, flags=(EZF,) + ori t4, reg, 16 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 4 - srli t3, t1, 8, dataSize=8 - andi t3, t3, 8 - or reg, reg, t3 + srli t3, t1, 8, dataSize=8, flags=(EZF,) + ori t4, reg, 8 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 3 - srli t3, t1, 4, dataSize=8 - andi t3, t3, 4 - or reg, reg, t3 + srli t3, t1, 4, dataSize=8, flags=(EZF,) + ori t4, reg, 4 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 2 - srli t3, t1, 2, dataSize=8 - andi t3, t3, 2 - or reg, reg, t3 + srli t3, t1, 2, dataSize=8, flags=(EZF,) + ori t4, reg, 2 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 1 - srli t3, t1, 1, dataSize=8 - andi t3, t3, 1 - or reg, reg, t3 + srli t3, t1, 1, dataSize=8, flags=(EZF,) + ori t4, reg, 1 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSR_R_P { +def macroop BSF_R_P { rdip t7 mov t1, t1, t0, dataSize=8 @@ -339,7 +348,7 @@ def macroop BSR_R_P { # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register mov reg, reg, t0 @@ -348,34 +357,40 @@ def macroop BSR_R_P { xor t1, t2, t1 # Bit 6 - srli t3, t1, 32, dataSize=8 - andi t3, t3, 32 - or reg, reg, t3 + srli t3, t1, 32, dataSize=8, flags=(EZF,) + ori t4, reg, 32 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 5 - srli t3, t1, 16, dataSize=8 - andi t3, t3, 16 - or reg, reg, t3 + srli t3, t1, 16, dataSize=8, flags=(EZF,) + ori t4, reg, 16 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 4 - srli t3, t1, 8, dataSize=8 - andi t3, t3, 8 - or reg, reg, t3 + srli t3, t1, 8, dataSize=8, flags=(EZF,) + ori t4, reg, 8 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 3 - srli t3, t1, 4, dataSize=8 - andi t3, t3, 4 - or reg, reg, t3 + srli t3, t1, 4, dataSize=8, flags=(EZF,) + ori t4, reg, 4 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 2 - srli t3, t1, 2, dataSize=8 - andi t3, t3, 2 - or reg, reg, t3 + srli t3, t1, 2, dataSize=8, flags=(EZF,) + ori t4, reg, 2 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 1 - srli t3, t1, 1, dataSize=8 - andi t3, t3, 1 - or reg, reg, t3 + srli t3, t1, 1, dataSize=8, flags=(EZF,) + ori t4, reg, 1 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py index 45a7822fb..7abafe253 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py @@ -103,5 +103,5 @@ def macroop CALL_NEAR_P ''' #let {{ # class CALL(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py index 7039b4b5c..8203f7c2c 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -53,16 +53,194 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop IRET_REAL { + panic "Real mode iret isn't implemented!" +}; + +def macroop IRET_PROT { + .adjust_env oszIn64Override + + # Check for a nested task. This isn't supported at the moment. + rflag t1, NT + panic "Task switching with iret is unimplemented!", flags=(nCEZF,) + + #t1 = temp_RIP + #t2 = temp_CS + #t3 = temp_RFLAGS + #t4 = handy m5 register + + # Pop temp_RIP, temp_CS, and temp_RFLAGS + ld t1, ss, [1, t0, rsp], "0 * env.stackSize", dataSize=ssz + ld t2, ss, [1, t0, rsp], "1 * env.stackSize", dataSize=ssz + ld t3, ss, [1, t0, rsp], "2 * env.stackSize", dataSize=ssz + + # Read the handy m5 register for use later + rdm5reg t4 + + +### +### Handle if we're returning to virtual 8086 mode. +### + + #IF ((temp_RFLAGS.VM=1) && (CPL=0) && (LEGACY_MODE)) + # IRET_FROM_PROTECTED_TO_VIRTUAL + + #temp_RFLAGS.VM != 1 + rcri t0, t3, 18, flags=(ECF,) + br label("protToVirtFallThrough"), flags=(nCECF,) + + #CPL=0 + andi t0, t4, 0x30, flags=(EZF,) + br label("protToVirtFallThrough"), flags=(nCEZF,) + + #(LEGACY_MODE) + rcri t0, t4, 1, flags=(ECF,) + br label("protToVirtFallThrough"), flags=(nCECF,) + + panic "iret to virtual mode not supported" + +protToVirtFallThrough: + + + + #temp_CPL = temp_CS.rpl + andi t5, t2, 0x3 + + +### +### Read in the info for the new CS segment. +### + + #CS = READ_DESCRIPTOR (temp_CS, iret_chk) + andi t0, t2, 0xFC, flags=(EZF,), dataSize=2 + br label("processCSDescriptor"), flags=(CEZF,) + andi t6, t2, 0xF8, dataSize=8 + andi t0, t2, 0x4, flags=(EZF,), dataSize=2 + br label("globalCSDescriptor"), flags=(CEZF,) + ld t8, tsl, [1, t0, t6], dataSize=8 + br label("processCSDescriptor") +globalCSDescriptor: + ld t8, tsg, [1, t0, t6], dataSize=8 +processCSDescriptor: + chks t2, t6, dataSize=8 + + +### +### Get the new stack pointer and stack segment off the old stack if necessary, +### and piggyback on the logic to check the new RIP value. +### + #IF ((64BIT_MODE) || (temp_CPL!=CPL)) + #{ + + #(64BIT_MODE) + andi t0, t4, 0xE, flags=(EZF,) + # Since we just found out we're in 64 bit mode, take advantage and + # do the appropriate RIP checks. + br label("doPopStackStuffAndCheckRIP"), flags=(CEZF,) + + # Here, we know we're -not- in 64 bit mode, so we should do the + # appropriate/other RIP checks. + # if temp_RIP > CS.limit throw #GP(0) + rdlimit t6, cs, dataSize=8 + subi t0, t1, t6, flags=(ECF,) + fault "new GeneralProtection(0)", flags=(CECF,) + + #(temp_CPL!=CPL) + srli t7, t4, 4 + xor t7, t7, t5 + andi t0, t7, 0x3, flags=(EZF,) + br label("doPopStackStuff"), flags=(nCEZF,) + # We can modify user visible state here because we're know + # we're done with things that can fault. + addi rsp, rsp, "3 * env.stackSize" + br label("fallThroughPopStackStuff") + +doPopStackStuffAndCheckRIP: + # Check if the RIP is canonical. + sra t7, t1, 47, flags=(EZF,), dataSize=ssz + # if t7 isn't 0 or -1, it wasn't canonical. + br label("doPopStackStuff"), flags=(CEZF,) + addi t0, t7, 1, flags=(EZF,), dataSize=ssz + fault "new GeneralProtection(0)", flags=(nCEZF,) + +doPopStackStuff: + # POP.v temp_RSP + ld t6, ss, [1, t0, rsp], "3 * env.dataSize", dataSize=ssz + # POP.v temp_SS + ld t9, ss, [1, t0, rsp], "4 * env.dataSize", dataSize=ssz + # SS = READ_DESCRIPTOR (temp_SS, ss_chk) + andi t0, t9, 0xFC, flags=(EZF,), dataSize=2 + br label("processSSDescriptor"), flags=(CEZF,) + andi t7, t9, 0xF8, dataSize=8 + andi t0, t9, 0x4, flags=(EZF,), dataSize=2 + br label("globalSSDescriptor"), flags=(CEZF,) + ld t7, tsl, [1, t0, t7], dataSize=8 + br label("processSSDescriptor") +globalSSDescriptor: + ld t7, tsg, [1, t0, t7], dataSize=8 +processSSDescriptor: + chks t9, t7, dataSize=8 + + # This actually updates state which is wrong. It should wait until we know + # we're not going to fault. Unfortunately, that's hard to do. + wrdl ss, t7, t9 + wrsel ss, t9 + +### +### From this point downwards, we can't fault. We can update user visible state. +### + # RSP.s = temp_RSP + mov rsp, rsp, t6, dataSize=ssz + + #} + +fallThroughPopStackStuff: + + # Update CS + wrdl cs, t8, t2 + wrsel cs, t2 + + #CPL = temp_CPL + + #IF (changing CPL) + #{ + srli t7, t4, 4 + xor t7, t7, t5 + andi t0, t7, 0x3, flags=(EZF,) + br label("skipSegmentSquashing"), flags=(CEZF,) + + # The attribute register needs to keep track of more info before this will + # work the way it needs to. + # FOR (seg = ES, DS, FS, GS) + # IF ((seg.attr.dpl < cpl && ((seg.attr.type = 'data') + # || (seg.attr.type = 'non-conforming-code'))) + # { + # seg = NULL + # } + #} + +skipSegmentSquashing: + + # Ignore this for now. + #RFLAGS.v = temp_RFLAGS + wrflags t0, t3 + # VIF,VIP,IOPL only changed if (old_CPL = 0) + # IF only changed if (old_CPL <= old_RFLAGS.IOPL) + # VM unchanged + # RF cleared + + #RIP = temp_RIP + wrip t0, t1, dataSize=ssz +}; + +def macroop IRET_VIRT { + panic "Virtual mode iret isn't implemented!" +}; +''' #let {{ # class INT(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class INTO(Inst): -# "GenFault ${new UnimpInstFault}" -# class IRET(Inst): -# "GenFault ${new UnimpInstFault}" -# class IRETD(Inst): -# "GenFault ${new UnimpInstFault}" -# class IRETQ(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py index 0b2e81cbd..57ec9da26 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -85,7 +85,7 @@ def macroop RET_FAR { ld t1, ss, [1, t0, rsp] # Get the return CS - ld t2, ss, [1, t0, rsp], dsz + ld t2, ss, [1, t0, rsp], ssz # Get the rpl andi t3, t2, 0x3 @@ -96,14 +96,23 @@ def macroop RET_FAR { # that doesn't happen yet. # Do stuff if they're equal - chks t4, t2, flags=(EZF,) - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t3, flatseg, [1, t0, t4], addressSize=8, dataSize=8 - wrdl cs, t3, t2 + andi t0, t2, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t3, t2, 0xF8, dataSize=8 + andi t0, t2, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t3], dataSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t3], dataSize=8 +processDescriptor: + chks t2, t3, IretCheck, dataSize=8 # There should be validity checks on the RIP checks here, but I'll do # that later. + wrdl cs, t3, t2 + wrsel cs, t2 wrip t0, t1 - bri t0, label("end") + br label("end") # Do other stuff if they're not. end: diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py index a1e322e56..2cbdd1ad8 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py @@ -56,11 +56,11 @@ microcode = "" #let {{ # class AAA(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class AAD(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class AAM(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class AAS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py index 213724768..d220fdeb6 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py @@ -56,7 +56,7 @@ microcode = "" #let {{ # class DAA(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class DAS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py index b98d09816..ac2343462 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py @@ -53,8 +53,26 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop BSWAP_D_R +{ + roli reg, reg, 8, dataSize=2 + roli reg, reg, 16, dataSize=4 + roli reg, reg, 8, dataSize=2 +}; + +def macroop BSWAP_Q_R +{ + roli reg, reg, 8, dataSize=2 + roli reg, reg, 16, dataSize=4 + roli reg, reg, 8, dataSize=2 + roli reg, reg, 32, dataSize=8 + roli reg, reg, 8, dataSize=2 + roli reg, reg, 16, dataSize=4 + roli reg, reg, 8, dataSize=2 +}; +''' #let {{ # class BSWAP(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py index 1e0810594..01fa280fc 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py @@ -56,7 +56,7 @@ microcode = "" #let {{ # class MOVMSKPS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MOVMSKPD(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py index d6ae7885a..c334693e5 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py @@ -55,7 +55,7 @@ microcode = ''' def macroop XLAT { - zexti t1, rax, 7 + zexti t1, rax, 7, dataSize=8 # Here, t1 can be used directly. The value of al is supposed to be treated # as unsigned. Since we zero extended it from 8 bits above and the address # size has to be at least 16 bits, t1 will not be sign extended. diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py index 3b8608c48..60c046d04 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py +++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -126,18 +126,19 @@ def macroop MOVSXD_R_P { }; def macroop MOVSX_B_R_R { - sexti reg, regm, 7 + mov t1, t1, regm, dataSize=1 + sexti reg, t1, 7 }; def macroop MOVSX_B_R_M { - ld reg, seg, sib, disp, dataSize=1 - sexti reg, reg, 7 + ld t1, seg, sib, disp, dataSize=1 + sexti reg, t1, 7 }; def macroop MOVSX_B_R_P { rdip t7 - ld reg, seg, riprel, disp, dataSize=1 - sexti reg, reg, 7 + ld t1, seg, riprel, disp, dataSize=1 + sexti reg, t1, 7 }; def macroop MOVSX_W_R_R { @@ -160,7 +161,8 @@ def macroop MOVSX_W_R_P { # def macroop MOVZX_B_R_R { - zexti reg, regm, 7 + mov t1, t1, regm, dataSize=1 + zexti reg, t1, 7 }; def macroop MOVZX_B_R_M { @@ -190,13 +192,25 @@ def macroop MOVZX_W_R_P { }; def macroop MOV_C_R { + .adjust_env maxOsz wrcr reg, regm }; def macroop MOV_R_C { + .adjust_env maxOsz rdcr reg, regm }; +def macroop MOV_D_R { + .adjust_env maxOsz + wrdr reg, regm +}; + +def macroop MOV_R_D { + .adjust_env maxOsz + rddr reg, regm +}; + def macroop MOV_R_S { rdsel reg, regm }; @@ -213,7 +227,7 @@ def macroop MOV_P_S { }; def macroop MOV_REAL_S_R { - zext t2, regm, 15 + zexti t2, regm, 15, dataSize=8 slli t3, t2, 2, dataSize=8 wrsel reg, regm wrbase reg, t3 @@ -221,87 +235,121 @@ def macroop MOV_REAL_S_R { def macroop MOV_REAL_S_M { ld t1, seg, sib, disp, dataSize=2 - zext t2, t1, 15 + zexti t2, t1, 15, dataSize=8 slli t3, t2, 2, dataSize=8 wrsel reg, t1 wrbase reg, t3 }; def macroop MOV_REAL_S_P { - rdip t7 - ld t1, seg, riprel, disp, dataSize=2 - zext t2, t1, 15 - slli t3, t2, 2, dataSize=8 - wrsel reg, t1 - wrbase reg, t3 + panic "RIP relative addressing shouldn't happen in real mode" }; def macroop MOV_S_R { - chks t1, regm, flags=(EZF,), dataSize=8 - bri t0, label("end"), flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, regm -end: + andi t0, regm, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, regm, 0xF8, dataSize=8 + andi t0, regm, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks regm, t3, dataSize=8 + wrdl reg, t3, regm wrsel reg, regm }; def macroop MOV_S_M { ld t1, seg, sib, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - bri t0, label("end"), flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 -end: + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; def macroop MOV_S_P { rdip t7 ld t1, seg, riprel, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - bri t0, label("end"), flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 -end: + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; def macroop MOVSS_S_R { - chks t1, regm, flags=(EZF,), dataSize=8 - # This actually needs to use the selector as the error code, but it would - # be hard to get that information into the instruction at the moment. - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, regm + andi t0, regm, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, regm, 0xF8, dataSize=8 + andi t0, regm, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks regm, t3, SSCheck, dataSize=8 + wrdl reg, t3, regm wrsel reg, regm }; def macroop MOVSS_S_M { ld t1, seg, sib, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - # This actually needs to use the selector as the error code, but it would - # be hard to get that information into the instruction at the moment. - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, SSCheck, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; def macroop MOVSS_S_P { rdip t7 ld t1, seg, riprel, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - # This actually needs to use the selector as the error code, but it would - # be hard to get that information into the instruction at the moment. - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, SSCheck, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; ''' #let {{ # class MOVD(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MOVNTI(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py index 6c51f3171..82fdffc63 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py +++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -58,8 +58,8 @@ def macroop POP_R { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - ld t1, ss, [1, t0, rsp] - addi rsp, rsp, dsz + ld t1, ss, [1, t0, rsp], dataSize=ssz + addi rsp, rsp, ssz, dataSize=asz mov reg, reg, t1 }; @@ -67,10 +67,10 @@ def macroop POP_M { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - ld t1, ss, [1, t0, rsp] - cda seg, sib, disp - addi rsp, rsp, dsz - st t1, seg, sib, disp + ld t1, ss, [1, t0, rsp], dataSize=ssz + cda seg, sib, disp, dataSize=ssz + addi rsp, rsp, ssz, dataSize=asz + st t1, seg, sib, disp, dataSize=ssz }; def macroop POP_P { @@ -78,17 +78,17 @@ def macroop POP_P { .adjust_env oszIn64Override rdip t7 - ld t1, ss, [1, t0, rsp] - cda seg, sib, disp - addi rsp, rsp, dsz - st t1, seg, riprel, disp + ld t1, ss, [1, t0, rsp], dataSize=ssz + cda seg, sib, disp, dataSize=ssz + addi rsp, rsp, ssz, dataSize=asz + st t1, seg, riprel, disp, dataSize=ssz }; def macroop PUSH_R { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - stupd reg, ss, [1, t0, rsp], "-env.dataSize" + stupd reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSH_I { @@ -96,15 +96,15 @@ def macroop PUSH_I { .adjust_env oszIn64Override limm t1, imm - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSH_M { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - ld t1, seg, sib, disp - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + ld t1, seg, sib, disp, dataSize=ssz + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSH_P { @@ -112,48 +112,48 @@ def macroop PUSH_P { .adjust_env oszIn64Override rdip t7 - ld t1, seg, riprel, disp - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + ld t1, seg, riprel, disp, dataSize=ssz + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSHA { # Check all the stack addresses. We'll assume that if the beginning and # end are ok, then the stuff in the middle should be as well. - cda ss, [1, t0, rsp], "-env.dataSize" - cda ss, [1, t0, rsp], "-8 * env.dataSize" - stupd rax, ss, [1, t0, rsp], "-env.dataSize" - stupd rcx, ss, [1, t0, rsp], "-env.dataSize" - stupd rdx, ss, [1, t0, rsp], "-env.dataSize" - stupd rbx, ss, [1, t0, rsp], "-env.dataSize" - stupd rsp, ss, [1, t0, rsp], "-env.dataSize" - stupd rbp, ss, [1, t0, rsp], "-env.dataSize" - stupd rsi, ss, [1, t0, rsp], "-env.dataSize" - stupd rdi, ss, [1, t0, rsp], "-env.dataSize" + cda ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + cda ss, [1, t0, rsp], "-8 * env.stackSize", dataSize=ssz + stupd rax, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rcx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rdx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rbx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rsp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rbp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rsi, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rdi, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop POPA { # Check all the stack addresses. We'll assume that if the beginning and # end are ok, then the stuff in the middle should be as well. - ld t1, ss, [1, t0, rsp], "0 * env.dataSize" - ld t2, ss, [1, t0, rsp], "7 * env.dataSize" - mov rdi, rdi, t1 - ld rsi, ss, [1, t0, rsp], "1 * env.dataSize" - ld rbp, ss, [1, t0, rsp], "2 * env.dataSize" - ld rbx, ss, [1, t0, rsp], "4 * env.dataSize" - ld rdx, ss, [1, t0, rsp], "5 * env.dataSize" - ld rcx, ss, [1, t0, rsp], "6 * env.dataSize" - mov rax, rax, t2 - addi rsp, rsp, "8 * env.dataSize" + ld t1, ss, [1, t0, rsp], "0 * env.stackSize", dataSize=ssz + ld t2, ss, [1, t0, rsp], "7 * env.stackSize", dataSize=ssz + mov rdi, rdi, t1, dataSize=ssz + ld rsi, ss, [1, t0, rsp], "1 * env.stackSize", dataSize=ssz + ld rbp, ss, [1, t0, rsp], "2 * env.stackSize", dataSize=ssz + ld rbx, ss, [1, t0, rsp], "4 * env.stackSize", dataSize=ssz + ld rdx, ss, [1, t0, rsp], "5 * env.stackSize", dataSize=ssz + ld rcx, ss, [1, t0, rsp], "6 * env.stackSize", dataSize=ssz + mov rax, rax, t2, dataSize=ssz + addi rsp, rsp, "8 * env.stackSize", dataSize=asz }; def macroop LEAVE { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - mov t1, t1, rbp - ld rbp, ss, [1, t0, t1] - mov rsp, rsp, t1 - addi rsp, rsp, dsz + mov t1, t1, rbp, dataSize=asz + ld rbp, ss, [1, t0, t1], dataSize=ssz + mov rsp, rsp, t1, dataSize=asz + addi rsp, rsp, ssz, dataSize=asz }; def macroop ENTER_I_I { @@ -162,41 +162,41 @@ def macroop ENTER_I_I { # Pull the different components out of the immediate limm t1, imm - zexti t2, t1, 15, dataSize=2 + zexti t2, t1, 15, dataSize=8 srl t1, t1, 16 - zexti t1, t1, 5 + zexti t1, t1, 5, dataSize=8 # t1 is now the masked nesting level, and t2 is the amount of storage. # Push rbp. - stupd rbp, ss, [1, t0, rsp], "-env.dataSize" + stupd rbp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz # Save the stack pointer for later - mov t6, t6, rsp + mov t6, t6, rsp, dataSize=asz # If the nesting level is zero, skip all this stuff. subi t0, t1, t0, flags=(EZF,), dataSize=2 - bri t0, label("skipLoop"), flags=(CEZF,) + br label("skipLoop"), flags=(CEZF,) # If the level was 1, only push the saved rbp subi t0, t1, 1, flags=(EZF,) - bri t0, label("bottomOfLoop"), flags=(CEZF,) + br label("bottomOfLoop"), flags=(CEZF,) limm t4, "ULL(-1)", dataSize=8 topOfLoop: - ld t5, ss, [dsz, t4, rbp] - stupd t5, ss, [1, t0, rsp], "-env.dataSize" + ld t5, ss, [ssz, t4, rbp], dataSize=ssz + stupd t5, ss, [1, t0, rsp], "-env.stackSize" # If we're not done yet, loop subi t4, t4, 1, dataSize=8 add t0, t4, t1, flags=(EZF,) - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) bottomOfLoop: # Push the old rbp onto the stack - stupd t6, ss, [1, t0, rsp], "-env.dataSize" + stupd t6, ss, [1, t0, rsp], "-env.stackSize" skipLoop: - sub rsp, rsp, t2 - mov rbp, rbp, t6 + sub rsp, rsp, t2, dataSize=asz + mov rbp, rbp, t6, dataSize=asz }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py b/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py index fe60350c1..59f6aaec2 100644 --- a/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py +++ b/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -57,17 +57,15 @@ microcode = ''' def macroop PUSHF { .adjust_env oszIn64Override - # This should really read the whole flags register, not just user flags. - ruflags t1 - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + rflags t1 + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop POPF { .adjust_env oszIn64Override - ld t1, ss, [1, t0, rsp] - addi rsp, rsp, dsz - # This should really write the whole flags register, not just user flags. - wruflags t1, t0 + ld t1, ss, [1, t0, rsp], dataSize=ssz + addi rsp, rsp, ssz + wrflags t1, t0 }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py b/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py index 4c655e0b2..e151dc61d 100644 --- a/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py +++ b/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -84,10 +84,18 @@ def macroop CMC { ruflags t1 wruflagsi t1, "CFBit" }; + +def macroop STI { + rflags t1 + limm t2, "IFBit" + or t1, t1, t2 + wrflags t1, t0 +}; + +def macroop CLI { + rflags t1 + limm t2, "~IFBit" + and t1, t1, t2 + wrflags t1, t0 +}; ''' -#let {{ -# class CLI(Inst): -# "GenFault ${new UnimpInstFault}" -# class STI(Inst): -# "GenFault ${new UnimpInstFault}" -#}}; diff --git a/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py b/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py index 1986a322e..4e3c9b316 100644 --- a/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py +++ b/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py @@ -84,25 +84,23 @@ microcode = ''' def macroop IN_R_I { .adjust_imm trimImm(8) - limm t1, "IntAddrPrefixIO", dataSize=8 - ld reg, intseg, [1, t1, t0], imm, addressSize=8 + limm t1, imm, dataSize=asz + ld reg, intseg, [1, t1, t0], "IntAddrPrefixIO << 3", addressSize=8 }; def macroop IN_R_R { - limm t1, "IntAddrPrefixIO", dataSize=8 - zexti t2, regm, 15, dataSize=2 - ld reg, intseg, [1, t1, t2], addressSize=8 + zexti t2, regm, 15, dataSize=8 + ld reg, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 }; def macroop OUT_I_R { .adjust_imm trimImm(8) - limm t1, "IntAddrPrefixIO", dataSize=8 - st reg, intseg, [1, t1, t0], imm, addressSize=8 + limm t1, imm, dataSize=8 + st reg, intseg, [1, t1, t0], "IntAddrPrefixIO << 3", addressSize=8 }; def macroop OUT_R_R { - limm t1, "IntAddrPrefixIO", dataSize=8 - zexti t2, reg, 15, dataSize=2 - st regm, intseg, [1, t1, t2], addressSize=8 + zexti t2, reg, 15, dataSize=8 + st regm, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py b/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py index b44203d9c..b3bc5ab67 100644 --- a/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py +++ b/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -61,32 +61,33 @@ def macroop INS_M_R { subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 - ld t6, intseg, [1, t1, t2], addressSize=8 + ld t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 st t6, es, [1, t0, rdi] add rdi, rdi, t3, dataSize=asz }; def macroop INS_E_M_R { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 topOfLoop: - ld t6, intseg, [1, t1, t2], addressSize=8 + ld t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 st t6, es, [1, t0, rdi] subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; @@ -97,32 +98,33 @@ def macroop OUTS_R_M { subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 ld t6, ds, [1, t0, rsi] - st t6, intseg, [1, t1, t2], addressSize=8 + st t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 add rsi, rsi, t3, dataSize=asz }; def macroop OUTS_E_R_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 topOfLoop: ld t6, ds, [1, t0, rsi] - st t6, intseg, [1, t1, t2], addressSize=8 + st t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py b/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py index 8aec4b99e..e6633ee1a 100644 --- a/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py +++ b/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py @@ -56,17 +56,17 @@ microcode = "" #let {{ # class LDS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LES(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LFS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LGS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LSS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MOV_SEG(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class POP(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/processor_information.py b/src/arch/x86/isa/insts/general_purpose/processor_information.py deleted file mode 100644 index 6070169ac..000000000 --- a/src/arch/x86/isa/insts/general_purpose/processor_information.py +++ /dev/null @@ -1,405 +0,0 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company -# All rights reserved. -# -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the -# following conditions are met: -# -# The software must be used only for Non-Commercial Use which means any -# use which is NOT directed to receiving any direct monetary -# compensation for, or commercial advantage from such use. Illustrative -# examples of non-commercial use are academic research, personal study, -# teaching, education and corporate research & development. -# Illustrative examples of commercial use are distributing products for -# commercial advantage and providing services using the software for -# commercial advantage. -# -# If you wish to use this software or functionality therein that may be -# covered by patents for commercial use, please contact: -# Director of Intellectual Property Licensing -# Office of Strategy and Technology -# Hewlett-Packard Company -# 1501 Page Mill Road -# Palo Alto, California 94304 -# -# Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. Redistributions -# in binary form must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. Neither the name of -# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. No right of -# sublicense is granted herewith. Derivatives of the software and -# output created using the software may be prepared, but only for -# Non-Commercial Uses. Derivatives of the software may be shared with -# others provided: (i) the others agree to abide by the list of -# conditions herein which includes the Non-Commercial Use restrictions; -# and (ii) such Derivatives of the software include the above copyright -# notice to acknowledge the contribution from this software where -# applicable, this list of conditions and the disclaimer below. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Gabe Black - -microcode = ''' -def macroop CPUID_R { - -# -# Find which type of cpuid function it is by checking bit 31. Also clear that -# bit to form an offset into the functions of that type. -# - limm t1, 0x80000000, dataSize=4 - and t2, t1, rax, flags=(EZF,) - # clear the bit - xor t1, t2, rax - -# -# Do range checking on the offset -# - # If EZF is set, the function is standard and the max is 0x1. - movi t2, t2, 0x1, flags=(CEZF,) - # If EZF is cleared, the function is extended and the max is 0x18. - movi t2, t2, 0x18, flags=(nCEZF,) - subi t0, t1, t2, flags=(ECF,) - # ECF will be set if the offset is too large. - bri t0, label("end"), flags=(nCECF,) - - -# -# Jump to the right portion -# - movi t2, t2, label("standardStart"), flags=(CEZF,) - movi t2, t2, label("extendedStart"), flags=(nCEZF,) - # This gives each function 8 microops to use. It's wasteful because only - # 5 will be needed, but a multiply would be expensive. In the system - # described in the RISC86 patent, the fifth instruction would really be - # the sequencing field on an op quad, so each function would be implemented - # by -exactly- one op quad. Since we're approximating, this should be ok. - slli t1, t1, 3 - br t2, t1 - -############################################################################# -############################################################################# - -# -# Standard functions. -# - -standardStart: - -# 0x00000000 -- Processor Vendor and Largest Standard Function Number - limm rax, 0x00000001, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x00000001 -- Family, Model, Stepping Identifiers - limm rax, 0x00020f51, dataSize=4 - limm rbx, 0x00000405, dataSize=4 - limm rdx, 0xe3d3fbff, dataSize=4 - limm rcx, 0x00000001, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# -# Extended functions. -# - -extendedStart: - -# 0x80000000 -- Processor Vendor and Largest Extended Function Number - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000001 -- EAX: AMD Family, Model, Stepping -# EBX: BrandId Identifier -# ECX: Feature Identifiers -# EDX: Feature Identifiers - limm rax, 0x00020f51, dataSize=4 - limm rbx, 0x00000405, dataSize=4 - limm rdx, 0xe3d3fbff, dataSize=4 - limm rcx, 0x00000001, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000002 -- Processor Name String Identifier - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000003 -- Processor Name String Identifier - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000004 -- Processor Name String Identifier - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000005 -- L1 Cache and TLB Identifiers - limm rax, 0xff08ff08, dataSize=4 - limm rbx, 0xff20ff20, dataSize=4 - limm rdx, 0x40020140, dataSize=4 - limm rcx, 0x40020140, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000006 -- L2/L3 Cache and L2 TLB Identifiers - limm rax, 0x00000000, dataSize=4 - limm rbx, 0x42004200, dataSize=4 - limm rdx, 0x00000000, dataSize=4 - limm rcx, 0x04008140, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000007 -- Advanced Power Management Information - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000008 -- Long Mode Address Size Identification - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000009 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000A -- SVM Revision and Feature Identification - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000B -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000C -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000D -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000E -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000F -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000010 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000011 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000012 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000013 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000014 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000015 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000016 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000017 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000018 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -end: - fault "NoFault" -}; -''' diff --git a/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py b/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py index ed7d761b8..caaeca974 100644 --- a/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py +++ b/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py @@ -56,13 +56,13 @@ microcode = ''' def macroop SAL_R_I { - slli reg, reg, imm, flags=(SF,ZF,PF) + slli reg, reg, imm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAL_M_I { ldst t1, seg, sib, disp - slli t1, t1, imm, flags=(SF,ZF,PF) + slli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -70,19 +70,19 @@ def macroop SAL_P_I { rdip t7 ldst t1, seg, riprel, disp - slli t1, t1, imm, flags=(SF,ZF,PF) + slli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAL_1_R { - slli reg, reg, 1, flags=(SF,ZF,PF) + slli reg, reg, 1, flags=(CF,OF,SF,ZF,PF) }; def macroop SAL_1_M { ldst t1, seg, sib, disp - slli t1, t1, 1, flags=(SF,ZF,PF) + slli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -90,19 +90,19 @@ def macroop SAL_1_P { rdip t7 ldst t1, seg, riprel, disp - slli t1, t1, 1, flags=(SF,ZF,PF) + slli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAL_R_R { - sll reg, reg, regm, flags=(SF,ZF,PF) + sll reg, reg, regm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAL_M_R { ldst t1, seg, sib, disp - sll t1, t1, reg, flags=(SF,ZF,PF) + sll t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -110,19 +110,19 @@ def macroop SAL_P_R { rdip t7 ldst t1, seg, riprel, disp - sll t1, t1, reg, flags=(SF,ZF,PF) + sll t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SHR_R_I { - srli reg, reg, imm, flags=(SF,ZF,PF) + srli reg, reg, imm, flags=(CF,OF,SF,ZF,PF) }; def macroop SHR_M_I { ldst t1, seg, sib, disp - srli t1, t1, imm, flags=(SF,ZF,PF) + srli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -130,19 +130,19 @@ def macroop SHR_P_I { rdip t7 ldst t1, seg, riprel, disp - srli t1, t1, imm, flags=(SF,ZF,PF) + srli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SHR_1_R { - srli reg, reg, 1, flags=(SF,ZF,PF) + srli reg, reg, 1, flags=(CF,OF,SF,ZF,PF) }; def macroop SHR_1_M { ldst t1, seg, sib, disp - srli t1, t1, 1, flags=(SF,ZF,PF) + srli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -150,19 +150,19 @@ def macroop SHR_1_P { rdip t7 ldst t1, seg, riprel, disp - srli t1, t1, 1, flags=(SF,ZF,PF) + srli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SHR_R_R { - srl reg, reg, regm, flags=(SF,ZF,PF) + srl reg, reg, regm, flags=(CF,OF,SF,ZF,PF) }; def macroop SHR_M_R { ldst t1, seg, sib, disp - srl t1, t1, reg, flags=(SF,ZF,PF) + srl t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -170,19 +170,54 @@ def macroop SHR_P_R { rdip t7 ldst t1, seg, riprel, disp - srl t1, t1, reg, flags=(SF,ZF,PF) + srl t1, t1, reg, flags=(CF,OF,SF,ZF,PF) + st t1, seg, riprel, disp +}; + +# SHRD will not set OF correctly when the shift count is 1. +def macroop SHRD_R_R_I +{ + srli t1, reg, imm, flags=(CF,) + rori t2, regm, imm + srli t3, regm, imm + xor t2, t2, t3 + or reg, t1, t2 +}; + +# SHRD will not set OF correctly when the shift count is 1. +def macroop SHRD_M_R_I +{ + ldst t1, seg, sib, disp + srli t1, t1, imm, flags=(CF,) + rori t2, reg, imm + srli t3, reg, imm + xor t2, t2, t3 + or t1, t1, t2 + st t1, seg, sib, disp +}; + +# SHRD will not set OF correctly when the shift count is 1. +def macroop SHRD_P_R_I +{ + rdip t7 + ldst t1, seg, riprel, disp + srli t1, t1, imm, flags=(CF,) + rori t2, reg, imm + srli t3, reg, imm + xor t2, t2, t3 + or t1, t1, t2 st t1, seg, riprel, disp }; def macroop SAR_R_I { - srai reg, reg, imm, flags=(SF,ZF,PF) + srai reg, reg, imm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAR_M_I { ldst t1, seg, sib, disp - srai t1, t1, imm, flags=(SF,ZF,PF) + srai t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -190,19 +225,19 @@ def macroop SAR_P_I { rdip t7 ldst t1, seg, riprel, disp - srai t1, t1, imm, flags=(SF,ZF,PF) + srai t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAR_1_R { - srai reg, reg, 1, flags=(SF,ZF,PF) + srai reg, reg, 1, flags=(CF,OF,SF,ZF,PF) }; def macroop SAR_1_M { ldst t1, seg, sib, disp - srai t1, t1, 1, flags=(SF,ZF,PF) + srai t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -210,19 +245,19 @@ def macroop SAR_1_P { rdip t7 ldst t1, seg, riprel, disp - srai t1, t1, 1, flags=(SF,ZF,PF) + srai t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAR_R_R { - sra reg, reg, regm, flags=(SF,ZF,PF) + sra reg, reg, regm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAR_M_R { ldst t1, seg, sib, disp - sra t1, t1, reg, flags=(SF,ZF,PF) + sra t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -230,7 +265,7 @@ def macroop SAR_P_R { rdip t7 ldst t1, seg, riprel, disp - sra t1, t1, reg, flags=(SF,ZF,PF) + sra t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/semaphores.py b/src/arch/x86/isa/insts/general_purpose/semaphores.py index 27a31dbd9..f23241863 100644 --- a/src/arch/x86/isa/insts/general_purpose/semaphores.py +++ b/src/arch/x86/isa/insts/general_purpose/semaphores.py @@ -78,10 +78,30 @@ def macroop CMPXCHG_P_R { st t1, seg, riprel, disp mov rax, rax, t1, flags=(nCZF,) }; + +def macroop XADD_M_R { + ldst t1, seg, sib, disp + add t2, t1, reg, flags=(OF,SF,ZF,AF,PF,CF) + st t2, seg, sib, disp + mov reg, reg, t1 +}; + +def macroop XADD_P_R { + rdip t7 + ldst t1, seg, riprel, disp + add t2, t1, reg, flags=(OF,SF,ZF,AF,PF,CF) + st t2, seg, riprel, disp + mov reg, reg, t1 +}; + +def macroop XADD_R_R { + add t2, regm, reg, flags=(OF,SF,ZF,AF,PF,CF) + mov regm, regm, reg + mov reg, reg, t2 +}; + ''' #let {{ -# class XADD(Inst): -# "GenFault ${new UnimpInstFault}" # class XCHG(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py b/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py index 71b8511b4..561b8a415 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py +++ b/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -75,12 +75,16 @@ def macroop CMPS_M_M { # def macroop CMPS_E_M_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, seg, [1, t0, rsi] ld t2, es, [1, t0, rdi] sub t0, t1, t2, flags=(OF, SF, ZF, AF, PF, CF) @@ -88,17 +92,22 @@ def macroop CMPS_E_M_M { subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, 4, flags=(CSTRZnEZF,) + br label("topOfLoop"), flags=(CSTRZnEZF,) +end: fault "NoFault" }; def macroop CMPS_N_M_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, seg, [1, t0, rsi] ld t2, es, [1, t0, rdi] sub t0, t1, t2, flags=(OF, SF, ZF, AF, PF, CF) @@ -106,7 +115,8 @@ def macroop CMPS_N_M_M { subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, 4, flags=(CSTRnZnEZF,) + br label("topOfLoop"), flags=(CSTRnZnEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/string/load_string.py b/src/arch/x86/isa/insts/general_purpose/string/load_string.py index 61525c2f2..14198701a 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/load_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/load_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -61,12 +61,14 @@ def macroop LODS_M { subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - ld rax, seg, [1, t0, rdi] + ld rax, seg, [1, t0, rsi] - add rdi, rdi, t3, dataSize=asz + add rsi, rsi, t3, dataSize=asz }; def macroop LODS_E_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz @@ -74,11 +76,12 @@ def macroop LODS_E_M { mov t3, t3, t4, flags=(nCEZF,), dataSize=asz topOfLoop: - ld rax, seg, [1, t0, rdi] + ld rax, seg, [1, t0, rsi] subi rcx, rcx, 1, flags=(EZF,), dataSize=asz - add rdi, rdi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + add rsi, rsi, t3, dataSize=asz + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/string/move_string.py b/src/arch/x86/isa/insts/general_purpose/string/move_string.py index b64acfdc2..18faa38e2 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/move_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/move_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -69,6 +69,8 @@ def macroop MOVS_M_M { }; def macroop MOVS_E_M_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz @@ -82,7 +84,8 @@ topOfLoop: subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/string/scan_string.py b/src/arch/x86/isa/insts/general_purpose/string/scan_string.py index b038cc00a..5b0e74aad 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/scan_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/scan_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -73,34 +73,44 @@ def macroop SCAS_M { # def macroop SCAS_E_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t2, t2, dsz, flags=(CEZF,), dataSize=asz subi t3, t0, dsz, dataSize=asz mov t2, t2, t3, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, es, [1, t0, rdi] sub t0, t1, rax, flags=(OF, SF, ZF, AF, PF, CF) subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t2, dataSize=asz - bri t0, 4, flags=(CSTRZnEZF,) + br label("topOfLoop"), flags=(CSTRZnEZF,) +end: fault "NoFault" }; def macroop SCAS_N_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t2, t2, dsz, flags=(CEZF,), dataSize=asz subi t3, t0, dsz, dataSize=asz mov t2, t2, t3, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, es, [1, t0, rdi] sub t0, t1, rax, flags=(OF, SF, ZF, AF, PF, CF) subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t2, dataSize=asz - bri t0, 4, flags=(CSTRnZnEZF,) + br label("topOfLoop"), flags=(CSTRnZnEZF,) +end: fault "NoFault" }; diff --git a/src/arch/x86/isa/insts/general_purpose/string/store_string.py b/src/arch/x86/isa/insts/general_purpose/string/store_string.py index a8d558929..fe9917ce6 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/store_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/store_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -67,6 +67,8 @@ def macroop STOS_M { }; def macroop STOS_E_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz @@ -78,7 +80,8 @@ topOfLoop: subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/system_calls.py b/src/arch/x86/isa/insts/general_purpose/system_calls.py index e056bea84..67607d5f8 100644 --- a/src/arch/x86/isa/insts/general_purpose/system_calls.py +++ b/src/arch/x86/isa/insts/general_purpose/system_calls.py @@ -53,14 +53,183 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop SYSCALL_64 +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + # Save the next RIP. + rdip rcx + + # Stick rflags with RF masked into r11. + rflags t2 + limm t3, "~RFBit" + andi r11, t2, t3, dataSize=8 + + rdval t3, star + srli t3, t3, 32, dataSize=8 + andi t3, t3, 0xFC, dataSize=1 + + # Set up CS. + wrsel cs, t3 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=0, defaultSize=0, long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (1 << 6)) + wrattr cs, t4 + + # Set up SS. + addi t3, t3, 8 + wrsel ss, t3 + wrbase ss, t0, dataSize=8 + wrlimit ss, t1, dataSize=4 + # Writable, readable, not expandDown, + # dpl=0, defaultSize=0, not long mode + limm t4, ((1 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (0 << 6)) + wrattr ss, t4 + + # Set the new rip. + rdval t7, lstar + wrip t0, t7 + + # Mask the flags against sf_mask and leave RF turned off. + rdval t3, sf_mask, dataSize=8 + xor t3, t3, t1, dataSize=8 + and t3, t3, r11, dataSize=8 + wrflags t3, t0 +}; + +def macroop SYSCALL_COMPAT +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + # Save the next RIP. + rdip rcx + + # Stick rflags with RF masked into r11. + rflags t2 + limm t3, "~RFBit" + andi r11, t2, t3, dataSize=8 + + rdval t3, star + srli t3, t3, 32, dataSize=8 + andi t3, t3, 0xFC, dataSize=1 + + # Set up CS. + wrsel cs, t3 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=0, defaultSize=0, long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (1 << 6)) + wrattr cs, t4 + + # Set up SS. + addi t3, t3, 8 + wrsel ss, t3 + wrbase ss, t0, dataSize=8 + wrlimit ss, t1, dataSize=4 + # Writable, readable, not expandDown, + # dpl=0, defaultSize=0, not long mode + limm t4, ((1 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (0 << 6)) + wrattr ss, t4 + + # Set the new rip. + rdval t7, cstar + wrip t0, t7 + + # Mask the flags against sf_mask and leave RF turned off. + rdval t3, sf_mask, dataSize=8 + xor t3, t3, t1, dataSize=8 + and t3, t3, r11, dataSize=8 + wrflags t3, t0 +}; + +def macroop SYSCALL_LEGACY +{ + panic "The syscall instruction isn't implemented in legacy mode." +}; + +def macroop SYSRET_TO_64 +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + rdval t3, star + srli t3, t3, 48, dataSize=8 + ori t3, t3, 3, dataSize=1 + + # Set rflags to r11 with RF and VM cleared. + limm t4, "~(RFBit | VMBit)" + and t4, t4, r11, dataSize=8 + wrflags t4, t0 + + # Set up CS. + addi t4, t3, 16, dataSize=8 + wrsel cs, t4 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=3, defaultSize=0, long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (3 << 3) | (0 << 5) | (1 << 6)) + wrattr cs, t4 + + # Only the selector is changed for SS. + addi t4, t3, 8, dataSize=8 + wrsel ss, t4 + + # Set the RIP back. + wrip rcx, t0, dataSize=8 +}; + +def macroop SYSRET_TO_COMPAT +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + rdval t3, star + srli t3, t3, 48, dataSize=8 + ori t3, t3, 3, dataSize=1 + + # Set rflags to r11 with RF and VM cleared. + limm t4, "~(RFBit | VMBit)" + and t4, t4, r11, dataSize=8 + wrflags t4, t0 + + # Set up CS. + wrsel cs, t3 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=3, defaultSize=1, not long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (3 << 3) | (1 << 5) | (0 << 6)) + wrattr cs, t4 + + # Only the selector is changed for SS. + addi t4, t3, 8, dataSize=8 + wrsel ss, t4 + + # Set the RIP back. + wrip rcx, t0, dataSize=8 +}; + +def macroop SYSRET_NON_64 +{ + panic "The sysret instruction isn't implemented in legacy mode." +}; +''' #let {{ # class SYSENTER(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class SYSEXIT(Inst): -# "GenFault ${new UnimpInstFault}" -# class SYSCALL(Inst): -# "GenFault ${new UnimpInstFault}" -# class SYSRET(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/romutil.py b/src/arch/x86/isa/insts/romutil.py new file mode 100644 index 000000000..e47259eb3 --- /dev/null +++ b/src/arch/x86/isa/insts/romutil.py @@ -0,0 +1,212 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +intCodeTemplate = ''' +def rom +{ + # This vectors the CPU into an interrupt handler in long mode. + # On entry, t1 is set to the vector of the interrupt and t7 is the current + # ip. We need that because rdip returns the next ip. + extern %(startLabel)s: + + # + # Get the 64 bit interrupt or trap gate descriptor from the IDT + # + + # Load the gate descriptor from the IDT + slli t4, t1, 4, dataSize=8 + ld t2, idtr, [1, t0, t4], 8, dataSize=8, addressSize=8, atCPL0=True + ld t4, idtr, [1, t0, t4], dataSize=8, addressSize=8, atCPL0=True + + # Make sure the descriptor is a legal gate. + chks t1, t4, %(gateCheckType)s + + # + # Get the target CS descriptor using the selector in the gate + # descriptor. + # + srli t10, t4, 16, dataSize=8 + andi t5, t10, 0xF8, dataSize=8 + andi t0, t10, 0x4, flags=(EZF,), dataSize=2 + br rom_local_label("%(startLabel)s_globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True + br rom_local_label("%(startLabel)s_processDescriptor") +%(startLabel)s_globalDescriptor: + ld t3, tsg, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True +%(startLabel)s_processDescriptor: + chks t10, t3, IntCSCheck, dataSize=8 + wrdl hs, t3, t10, dataSize=8 + + # Stick the target offset in t9. + wrdh t9, t4, t2, dataSize=8 + + + # + # Figure out where the stack should be + # + + # Record what we might set the stack selector to. + rdsel t11, ss + + # Check if we're changing privelege level. At this point we can assume + # we're going to a DPL that's less than or equal to the CPL. + rdattr t10, hs, dataSize=8 + srli t10, t10, 3, dataSize=8 + andi t10, t10, 3, dataSize=8 + rdattr t5, cs, dataSize=8 + srli t5, t5, 3, dataSize=8 + andi t5, t5, 0x3, dataSize=8 + sub t0, t5, t10, flags=(EZF,), dataSize=8 + # We're going to change priviledge, so zero out the stack selector. We + # need to let the IST have priority so we don't branch yet. + wrsel t11, t0, flags=(nCEZF,) + + # Check the IST field of the gate descriptor + srli t12, t4, 32, dataSize=8 + andi t12, t12, 0x7, dataSize=8 + subi t0, t12, 1, flags=(ECF,), dataSize=8 + br rom_local_label("%(startLabel)s_istStackSwitch"), flags=(nCECF,) + br rom_local_label("%(startLabel)s_cplStackSwitch"), flags=(nCEZF,) + + # If we're here, it's because the stack isn't being switched. + # Set t6 to the new aligned rsp. + mov t6, t6, rsp, dataSize=8 + br rom_local_label("%(startLabel)s_stackSwitched") + +%(startLabel)s_istStackSwitch: + ld t6, tr, [8, t12, t0], 0x1c, dataSize=8, addressSize=8, atCPL0=True + br rom_local_label("%(startLabel)s_stackSwitched") + +%(startLabel)s_cplStackSwitch: + # Get the new rsp from the TSS + ld t6, tr, [8, t10, t0], 4, dataSize=8, addressSize=8, atCPL0=True + +%(startLabel)s_stackSwitched: + + andi t6, t6, 0xF0, dataSize=1 + subi t6, t6, 40 + %(errorCodeSize)d, dataSize=8 + + ## + ## Point of no return. + ## We're now going to irrevocably modify visible state. + ## Anything bad that's going to happen should have happened by now or will + ## happen right now. + ## + wrip t0, t9, dataSize=8 + + # + # Set up the target code segment. Do this now so we have the right + # permissions when setting up the stack frame. + # + srli t5, t4, 16, dataSize=8 + andi t5, t5, 0xFF, dataSize=8 + wrdl cs, t3, t5, dataSize=8 + # Tuck away the old CS for use below + limm t10, 0, dataSize=8 + rdsel t10, cs, dataSize=2 + wrsel cs, t5, dataSize=2 + + # Check that we can access everything we need to on the stack + ldst t0, hs, [1, t0, t6], dataSize=8, addressSize=8 + ldst t0, hs, [1, t0, t6], \ + 32 + %(errorCodeSize)d, dataSize=8, addressSize=8 + + + # + # Build up the interrupt stack frame + # + + + # Write out the contents of memory + %(errorCodeCode)s + st t7, hs, [1, t0, t6], %(errorCodeSize)d, dataSize=8, addressSize=8 + st t10, hs, [1, t0, t6], 8 + %(errorCodeSize)d, dataSize=8, addressSize=8 + rflags t10, dataSize=8 + st t10, hs, [1, t0, t6], 16 + %(errorCodeSize)d, dataSize=8, addressSize=8 + st rsp, hs, [1, t0, t6], 24 + %(errorCodeSize)d, dataSize=8, addressSize=8 + rdsel t5, ss, dataSize=2 + st t5, hs, [1, t0, t6], 32 + %(errorCodeSize)d, dataSize=8, addressSize=8 + + # Set the stack segment + mov rsp, rsp, t6, dataSize=8 + wrsel ss, t11, dataSize=2 + + # + # Adjust rflags which is still in t10 from above + # + + # Set IF to the lowest bit of the original gate type. + # The type field of the original gate starts at bit 40. + + # Set the TF, NT, and RF bits. We'll flip them at the end. + limm t6, (1 << 8) | (1 << 14) | (1 << 16) + or t10, t10, t6 + srli t5, t4, 40, dataSize=8 + srli t7, t10, 9, dataSize=8 + xor t5, t7, t5, dataSize=8 + andi t5, t5, 1, dataSize=8 + slli t5, t5, 9, dataSize=8 + or t6, t5, t6, dataSize=8 + + # Put the results into rflags + wrflags t6, t10 + + eret +}; +''' + +microcode = \ +intCodeTemplate % {\ + "startLabel" : "longModeInterrupt", + "gateCheckType" : "IntGateCheck", + "errorCodeSize" : 0, + "errorCodeCode" : "" +} + \ +intCodeTemplate % {\ + "startLabel" : "longModeSoftInterrupt", + "gateCheckType" : "SoftIntGateCheck", + "errorCodeSize" : 0, + "errorCodeCode" : "" +} + \ +intCodeTemplate % {\ + "startLabel" : "longModeInterruptWithError", + "gateCheckType" : "IntGateCheck", + "errorCodeSize" : 8, + "errorCodeCode" : ''' + st t15, hs, [1, t0, t6], dataSize=8, addressSize=8 + ''' +} + \ +''' +def rom +{ + # This vectors the CPU into an interrupt handler in legacy mode. + extern legacyModeInterrupt: + panic "Legacy mode interrupts not implemented (in microcode)" + eret +}; +''' diff --git a/src/arch/x86/isa/insts/system/__init__.py b/src/arch/x86/isa/insts/system/__init__.py index 409a929f5..0dec9ebda 100644 --- a/src/arch/x86/isa/insts/system/__init__.py +++ b/src/arch/x86/isa/insts/system/__init__.py @@ -81,7 +81,8 @@ # # Authors: Gabe Black -categories = ["halt", +categories = ["control_registers", + "halt", "invlpg", "undefined_operation", "msrs", diff --git a/src/arch/x86/isa/insts/system/control_registers.py b/src/arch/x86/isa/insts/system/control_registers.py new file mode 100644 index 000000000..902c01abb --- /dev/null +++ b/src/arch/x86/isa/insts/system/control_registers.py @@ -0,0 +1,35 @@ +# Copyright (c) 2009 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +microcode = ''' +def macroop CLTS { + rdcr t1, 0, dataSize=8 + andi t1, t1, 0xF7, dataSize=1 + wrcr 0, t1, dataSize=8 +}; +''' diff --git a/src/arch/x86/isa/insts/system/msrs.py b/src/arch/x86/isa/insts/system/msrs.py index 1acb4c792..7f283c8c1 100644 --- a/src/arch/x86/isa/insts/system/msrs.py +++ b/src/arch/x86/isa/insts/system/msrs.py @@ -84,8 +84,8 @@ microcode = ''' def macroop RDMSR { - limm t1, "IntAddrPrefixMSR >> 3" - ld t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4 + ld t2, intseg, [8, rcx, t0], "IntAddrPrefixMSR << 3", \ + dataSize=8, addressSize=8 mov rax, rax, t2, dataSize=4 srli t2, t2, 32, dataSize=8 mov rdx, rdx, t2, dataSize=4 @@ -93,10 +93,18 @@ def macroop RDMSR def macroop WRMSR { - limm t1, "IntAddrPrefixMSR >> 3" mov t2, t2, rax, dataSize=4 slli t3, rdx, 32, dataSize=8 or t2, t2, t3, dataSize=8 - st t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4 + st t2, intseg, [8, rcx, t0], "IntAddrPrefixMSR << 3", \ + dataSize=8, addressSize=8 +}; + +def macroop RDTSC +{ + rdtsc t1 + mov rax, rax, t1, dataSize=4 + srli t1, t1, 32, dataSize=8 + mov rdx, rdx, t1, dataSize=4 }; ''' diff --git a/src/arch/x86/isa/insts/system/segmentation.py b/src/arch/x86/isa/insts/system/segmentation.py index 97846f79c..acbca9f6e 100644 --- a/src/arch/x86/isa/insts/system/segmentation.py +++ b/src/arch/x86/isa/insts/system/segmentation.py @@ -56,7 +56,7 @@ microcode = ''' def macroop LGDT_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 @@ -68,7 +68,7 @@ def macroop LGDT_M def macroop LGDT_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit @@ -86,34 +86,34 @@ def macroop LGDT_P def macroop LGDT_16_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 # Get the base ld t2, seg, sib, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase tsg, t2 wrlimit tsg, t1 }; def macroop LGDT_16_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit ld t1, seg, riprel, disp, dataSize=2 # Get the base ld t2, seg, riprel, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase tsg, t2 wrlimit tsg, t1 }; def macroop LIDT_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 @@ -125,7 +125,7 @@ def macroop LIDT_M def macroop LIDT_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit @@ -143,28 +143,135 @@ def macroop LIDT_P def macroop LIDT_16_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 # Get the base ld t2, seg, sib, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase idtr, t2 wrlimit idtr, t1 }; def macroop LIDT_16_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit ld t1, seg, riprel, disp, dataSize=2 # Get the base ld t2, seg, riprel, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase idtr, t2 wrlimit idtr, t1 }; + +def macroop LTR_R +{ + chks reg, t0, TRCheck + limm t4, 0 + srli t4, reg, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks reg, t1, TSSCheck + wrdh t3, t1, t2 + wrdl tr, t1, reg + wrbase tr, t3, dataSize=8 + ori t1, t1, (1 << 9) + st t1, tsg, [8, t4, t0], dataSize=8 +}; + +def macroop LTR_M +{ + ld t5, seg, sib, disp, dataSize=2 + chks t5, t0, TRCheck + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, TSSCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 + ori t1, t1, (1 << 9) + st t1, tsg, [8, t4, t0], dataSize=8 +}; + +def macroop LTR_P +{ + rdip t7 + ld t5, seg, riprel, disp, dataSize=2 + chks t5, t0, TRCheck + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, TSSCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 + ori t1, t1, (1 << 9) + st t1, tsg, [8, t4, t0], dataSize=8 +}; + +def macroop LLDT_R +{ + chks reg, t0, InGDTCheck, flags=(EZF,) + br label("end"), flags=(CEZF,) + limm t4, 0 + srli t4, reg, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks reg, t1, LDTCheck + wrdh t3, t1, t2 + wrdl tr, t1, reg + wrbase tr, t3, dataSize=8 +end: + fault "NoFault" +}; + +def macroop LLDT_M +{ + ld t5, seg, sib, disp, dataSize=2 + chks t5, t0, InGDTCheck, flags=(EZF,) + br label("end"), flags=(CEZF,) + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, LDTCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 +end: + fault "NoFault" +}; + +def macroop LLDT_P +{ + rdip t7 + ld t5, seg, riprel, disp, dataSize=2 + chks t5, t0, InGDTCheck, flags=(EZF,) + br label("end"), flags=(CEZF,) + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, LDTCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 +end: + fault "NoFault" +}; + +def macroop SWAPGS +{ + rdval t1, kernel_gs_base, dataSize=8 + rdbase t2, gs, dataSize=8 + wrbase gs, t1, dataSize=8 + wrval kernel_gs_base, t2, dataSize=8 +}; ''' diff --git a/src/arch/x86/isa/macroop.isa b/src/arch/x86/isa/macroop.isa index 4818b926c..3a836ff68 100644 --- a/src/arch/x86/isa/macroop.isa +++ b/src/arch/x86/isa/macroop.isa @@ -72,41 +72,13 @@ def template MacroExecPanic {{ output header {{ // Base class for combinationally generated macroops - class Macroop : public StaticInst + class Macroop : public X86ISA::MacroopBase { - protected: - const uint32_t numMicroops; - - //Constructor. + public: Macroop(const char *mnem, ExtMachInst _machInst, - uint32_t _numMicroops) - : StaticInst(mnem, _machInst, No_OpClass), - numMicroops(_numMicroops) - { - assert(numMicroops); - microops = new StaticInstPtr[numMicroops]; - flags[IsMacroop] = true; - } - - ~Macroop() - { - delete [] microops; - } - - StaticInstPtr * microops; - - StaticInstPtr fetchMicroop(MicroPC microPC) - { - assert(microPC < numMicroops); - return microops[microPC]; - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return mnemonic; - } - + uint32_t _numMicroops, X86ISA::EmulEnv _env) + : MacroopBase(mnem, _machInst, _numMicroops, _env) + {} %(MacroExecPanic)s }; }}; @@ -130,22 +102,42 @@ def template MacroDeclare {{ %(declareLabels)s public: // Constructor. - %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv env); + %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv _env); + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; }; }}; +def template MacroDisassembly {{ + std::string + X86Macroop::%(class_name)s::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream out; + out << mnemonic << "\t"; + + int regSize = %(regSize)s; + %(disassembly)s + // Shut up gcc. + regSize = regSize; + return out.str(); + } +}}; + // Basic instruction class constructor template. def template MacroConstructor {{ inline X86Macroop::%(class_name)s::%(class_name)s( - ExtMachInst machInst, EmulEnv env) - : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s) + ExtMachInst machInst, EmulEnv _env) + : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, _env) { %(adjust_env)s; %(adjust_imm)s; %(adjust_disp)s; - %(do_modrm)s; + %(init_env)s; %(constructor)s; + const char *macrocodeBlock = "%(class_name)s"; //alloc_microops is the code that sets up the microops //array in the parent class. %(alloc_microops)s; @@ -174,7 +166,7 @@ let {{ } self.declared = False self.adjust_env = "" - self.doModRM = "" + self.init_env = "" self.adjust_imm = ''' uint64_t adjustedImm = IMMEDIATE; //This is to pacify gcc in case the immediate isn't used. @@ -186,7 +178,12 @@ let {{ adjustedDisp = adjustedDisp; ''' def getAllocator(self, env): - return "new X86Macroop::%s(machInst, %s)" % (self.name, env.getAllocator()) + return "new X86Macroop::%s(machInst, %s)" % \ + (self.name, env.getAllocator()) + def getMnemonic(self): + mnemonic = self.name.lower() + mnemonic = re.match(r'[^_]*', mnemonic).group(0) + return mnemonic def getDeclaration(self): #FIXME This first parameter should be the mnemonic. I need to #write some code which pulls that out @@ -194,32 +191,46 @@ let {{ for (label, microop) in self.labels.items(): declareLabels += "const static uint64_t label_%s = %d;\n" \ % (label, microop.micropc) - iop = InstObjParams(self.name, self.name, "Macroop", + iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", {"code" : "", "declareLabels" : declareLabels }) return MacroDeclare.subst(iop); - def getDefinition(self): + def getDefinition(self, env): #FIXME This first parameter should be the mnemonic. I need to #write some code which pulls that out numMicroops = len(self.microops) allocMicroops = '' micropc = 0 for op in self.microops: + isLast = (micropc == numMicroops - 1) allocMicroops += \ "microops[%d] = %s;\n" % \ - (micropc, op.getAllocator(True, False, - micropc == 0, - micropc == numMicroops - 1)) + (micropc, op.getAllocator(True, not isLast, + micropc == 0, isLast)) micropc += 1 - iop = InstObjParams(self.name, self.name, "Macroop", + if env.useStackSize: + useStackSize = "true" + else: + useStackSize = "false" + if env.memoryInst: + memoryInst = "true" + else: + memoryInst = "false" + regSize = '''(%s || (env.base == INTREG_RSP && %s) ? + env.stackSize : + env.dataSize)''' % (useStackSize, memoryInst) + iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", {"code" : "", "num_microops" : numMicroops, "alloc_microops" : allocMicroops, "adjust_env" : self.adjust_env, "adjust_imm" : self.adjust_imm, "adjust_disp" : self.adjust_disp, - "do_modrm" : self.doModRM}) - return MacroConstructor.subst(iop); + "disassembly" : env.disassembly, + "regSize" : regSize, + "init_env" : self.initEnv}) + return MacroConstructor.subst(iop) + \ + MacroDisassembly.subst(iop); }}; let {{ @@ -235,6 +246,16 @@ let {{ self.dataSize = "OPSIZE" self.stackSize = "STACKSIZE" self.doModRM = False + self.disassembly = "" + self.firstArgument = True + self.useStackSize = False + self.memoryInst = False + + def addToDisassembly(self, code): + if not self.firstArgument: + self.disassembly += "out << \", \";\n" + self.firstArgument = False + self.disassembly += code def getAllocator(self): if self.size == 'b': @@ -283,6 +304,7 @@ let {{ let {{ doModRMString = "env.doModRM(machInst);\n" + noModRMString = "env.setSeg(machInst);\n" def genMacroop(Name, env): blocks = OutputBlocks() if not macroopDict.has_key(Name): @@ -290,9 +312,11 @@ let {{ macroop = macroopDict[Name] if not macroop.declared: if env.doModRM: - macroop.doModRM = doModRMString + macroop.initEnv = doModRMString + else: + macroop.initEnv = noModRMString blocks.header_output = macroop.getDeclaration() - blocks.decoder_output = macroop.getDefinition() + blocks.decoder_output = macroop.getDefinition(env) macroop.declared = True blocks.decode_block = "return %s;\n" % macroop.getAllocator(env) return blocks diff --git a/src/arch/x86/isa/microasm.isa b/src/arch/x86/isa/microasm.isa index 78ae34f52..c7c6dae2e 100644 --- a/src/arch/x86/isa/microasm.isa +++ b/src/arch/x86/isa/microasm.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -64,23 +64,32 @@ //Include code to build macroops in both C++ and python. ##include "macroop.isa" +//Include code to fill out the microcode ROM in both C++ and python. +##include "rom.isa" + let {{ import sys sys.path[0:0] = ["src/arch/x86/isa/"] from insts import microcode # print microcode - from micro_asm import MicroAssembler, Rom_Macroop, Rom - mainRom = Rom('main ROM') + from micro_asm import MicroAssembler, Rom_Macroop + mainRom = X86MicrocodeRom('main ROM') assembler = MicroAssembler(X86Macroop, microopClasses, mainRom, Rom_Macroop) # Add in symbols for the microcode registers - for num in range(15): + for num in range(16): assembler.symbols["t%d" % num] = "NUM_INTREGS+%d" % num - for num in range(7): + for num in range(8): assembler.symbols["ufp%d" % num] = "FLOATREG_MICROFP(%d)" % num # Add in symbols for the segment descriptor registers - for letter in ("C", "D", "E", "F", "G", "S"): + for letter in ("C", "D", "E", "F", "G", "H", "S"): assembler.symbols["%ss" % letter.lower()] = "SEGMENT_REG_%sS" % letter + # Add in symbols for the various checks of segment selectors. + for check in ("NoCheck", "CSCheck", "CallGateCheck", "IntGateCheck", + "SoftIntGateCheck", "SSCheck", "IretCheck", "IntCSCheck", + "TRCheck", "TSSCheck", "InGDTCheck", "LDTCheck"): + assembler.symbols[check] = "Seg%s" % check + for reg in ("TR", "IDTR"): assembler.symbols[reg.lower()] = "SYS_SEGMENT_REG_%s" % reg @@ -129,13 +138,15 @@ let {{ # like the internal segment above assembler.symbols["flatseg"] = "SEGMENT_REG_LS" - for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di'): + for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di', \ + '8', '9', '10', '11', '12', '13', '14', '15'): assembler.symbols["r%s" % reg] = "INTREG_R%s" % reg.upper() - for reg in range(15): + for reg in range(16): assembler.symbols["cr%d" % reg] = "MISCREG_CR%d" % reg - for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF'): + for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF', \ + 'TF', 'IF', 'NT', 'RF', 'VM', 'AC', 'VIF', 'VIP', 'ID'): assembler.symbols[flag] = flag + "Bit" for cond in ('True', 'False', 'ECF', 'EZF', 'SZnZF', @@ -150,6 +161,11 @@ let {{ assembler.symbols["CTrue"] = "ConditionTests::True" assembler.symbols["CFalse"] = "ConditionTests::False" + for reg in ('sysenter_cs', 'sysenter_esp', 'sysenter_eip', + 'star', 'lstar', 'cstar', 'sf_mask', + 'kernel_gs_base'): + assembler.symbols[reg] = "MISCREG_%s" % reg.upper() + # Code literal which forces a default 64 bit operand size in 64 bit mode. assembler.symbols["oszIn64Override"] = ''' if (machInst.mode.submode == SixtyFourBitMode && @@ -157,7 +173,7 @@ let {{ env.dataSize = 8; ''' - assembler.symbols["oszForPseudoDesc"] = ''' + assembler.symbols["maxOsz"] = ''' if (machInst.mode.submode == SixtyFourBitMode) env.dataSize = 8; else @@ -174,10 +190,23 @@ let {{ assembler.symbols["label"] = labeler + def rom_labeler(labelStr): + return "romMicroPC(RomLabels::extern_label_%s)" % labelStr + + assembler.symbols["rom_label"] = rom_labeler + + def rom_local_labeler(labelStr): + return "romMicroPC(RomLabels::label_%s)" % labelStr + + assembler.symbols["rom_local_label"] = rom_local_labeler + def stack_index(index): return "(NUM_FLOATREGS + (((%s) + 8) %% 8))" % index assembler.symbols["st"] = stack_index macroopDict = assembler.assemble(microcode) + + decoder_output += mainRom.getDefinition() + header_output += mainRom.getDeclaration() }}; diff --git a/src/arch/x86/isa/microops/base.isa b/src/arch/x86/isa/microops/base.isa index 75658a26c..f1007bf71 100644 --- a/src/arch/x86/isa/microops/base.isa +++ b/src/arch/x86/isa/microops/base.isa @@ -69,6 +69,29 @@ let {{ let {{ class X86Microop(object): + + generatorNameTemplate = "generate_%s_%d" + + generatorTemplate = ''' + StaticInstPtr + ''' + generatorNameTemplate + '''(StaticInstPtr curMacroop) + { + static const char *macrocodeBlock = romMnemonic; + static const ExtMachInst dummyExtMachInst; + static const EmulEnv dummyEmulEnv(0, 0, 1, 1, 1); + + Macroop * macroop = dynamic_cast<Macroop *>(curMacroop.get()); + const ExtMachInst &machInst = + macroop ? macroop->getExtMachInst() : dummyExtMachInst; + const EmulEnv &env = + macroop ? macroop->getEmulEnv() : dummyEmulEnv; + // env may not be used in the microop's constructor. + RegIndex reg = env.reg; + reg = reg; + using namespace RomLabels; + return %s; + } + ''' def __init__(self, name): self.name = name @@ -91,4 +114,12 @@ let {{ def getAllocator(self, mnemonic, *microFlags): return 'new %s(machInst, %s)' % \ (self.className, mnemonic, self.microFlagsText(microFlags)) + + def getGeneratorDef(self, micropc): + return self.generatorTemplate % \ + (self.className, micropc, \ + self.getAllocator(True, True, False, False)) + + def getGenerator(self, micropc): + return self.generatorNameTemplate % (self.className, micropc) }}; diff --git a/src/arch/x86/isa/microops/debug.isa b/src/arch/x86/isa/microops/debug.isa new file mode 100644 index 000000000..38fee59bb --- /dev/null +++ b/src/arch/x86/isa/microops/debug.isa @@ -0,0 +1,229 @@ +// Copyright (c) 2008 The Hewlett-Packard Development Company +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the +// following conditions are met: +// +// The software must be used only for Non-Commercial Use which means any +// use which is NOT directed to receiving any direct monetary +// compensation for, or commercial advantage from such use. Illustrative +// examples of non-commercial use are academic research, personal study, +// teaching, education and corporate research & development. +// Illustrative examples of commercial use are distributing products for +// commercial advantage and providing services using the software for +// commercial advantage. +// +// If you wish to use this software or functionality therein that may be +// covered by patents for commercial use, please contact: +// Director of Intellectual Property Licensing +// Office of Strategy and Technology +// Hewlett-Packard Company +// 1501 Page Mill Road +// Palo Alto, California 94304 +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. Redistributions +// in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. Neither the name of +// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. No right of +// sublicense is granted herewith. Derivatives of the software and +// output created using the software may be prepared, but only for +// Non-Commercial Uses. Derivatives of the software may be shared with +// others provided: (i) the others agree to abide by the list of +// conditions herein which includes the Non-Commercial Use restrictions; +// and (ii) such Derivatives of the software include the above copyright +// notice to acknowledge the contribution from this software where +// applicable, this list of conditions and the disclaimer below. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +////////////////////////////////////////////////////////////////////////// +// +// Debug Microops +// +////////////////////////////////////////////////////////////////////////// + +output header {{ + class MicroDebugBase : public X86ISA::X86MicroopBase + { + protected: + std::string message; + uint8_t cc; + + public: + MicroDebugBase(ExtMachInst _machInst, const char * mnem, + const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc); + + MicroDebugBase(ExtMachInst _machInst, const char * mnem, + const char * instMnem, std::string _message, uint8_t _cc); + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +def template MicroDebugDeclare {{ + class %(class_name)s : public %(base_class)s + { + private: + void buildMe(); + public: + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc); + + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + std::string _message, uint8_t _cc); + + %(BasicExecDeclare)s + }; +}}; + +def template MicroDebugExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + %(op_decl)s + %(op_rd)s + if (%(cond_test)s) { + %(func)s("%s\n", message); + } + return NoFault; + } +}}; + +output decoder {{ + inline MicroDebugBase::MicroDebugBase( + ExtMachInst machInst, const char * mnem, const char * instMnem, + std::string _message, uint8_t _cc) : + X86MicroopBase(machInst, mnem, instMnem, + false, false, false, false, No_OpClass), + message(_message), cc(_cc) + { + } + + inline MicroDebugBase::MicroDebugBase( + ExtMachInst machInst, const char * mnem, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc) : + X86MicroopBase(machInst, mnem, instMnem, + isMicro, isDelayed, isFirst, isLast, No_OpClass), + message(_message), cc(_cc) + { + } +}}; + +def template MicroDebugConstructor {{ + + inline void %(class_name)s::buildMe() + { + %(constructor)s; + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + std::string _message, uint8_t _cc) : + %(base_class)s(machInst, "%(func)s", instMnem, _message, _cc) + { + buildMe(); + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc) : + %(base_class)s(machInst, "%(func)s", instMnem, + isMicro, isDelayed, isFirst, isLast, _message, _cc) + { + buildMe(); + } +}}; + +output decoder {{ + std::string MicroDebugBase::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + response << "\"" << message << "\""; + + return response.str(); + } +}}; + +let {{ + class MicroDebug(X86Microop): + def __init__(self, message, flags=None): + self.message = message + if flags: + if not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + self.cond = " | ".join(flags) + self.className += "Flags" + else: + self.cond = "0" + + def getAllocator(self, *microFlags): + allocator = '''new %(class_name)s(machInst, macrocodeBlock + %(flags)s, "%(message)s", %(cc)s)''' % { + "class_name" : self.className, + "flags" : self.microFlagsText(microFlags), + "message" : self.message, + "cc" : self.cond} + return allocator + + exec_output = "" + header_output = "" + decoder_output = "" + + def buildDebugMicro(func): + global exec_output, header_output, decoder_output + + iop = InstObjParams(func, "Micro%sFlags" % func.capitalize(), + "MicroDebugBase", + {"code": "", + "func": func, + "cond_test": "checkCondition(ccFlagBits, cc)"}) + exec_output += MicroDebugExecute.subst(iop) + header_output += MicroDebugDeclare.subst(iop) + decoder_output += MicroDebugConstructor.subst(iop) + + iop = InstObjParams(func, "Micro%s" % func.capitalize(), + "MicroDebugBase", + {"code": "", + "func": func, + "cond_test": "true"}) + exec_output += MicroDebugExecute.subst(iop) + header_output += MicroDebugDeclare.subst(iop) + decoder_output += MicroDebugConstructor.subst(iop) + + class MicroDebugChild(MicroDebug): + className = "Micro%s" % func.capitalize() + + global microopClasses + microopClasses[func] = MicroDebugChild + + buildDebugMicro("panic") + buildDebugMicro("fatal") + buildDebugMicro("warn") + buildDebugMicro("warn_once") +}}; diff --git a/src/arch/x86/isa/microops/fpop.isa b/src/arch/x86/isa/microops/fpop.isa index 2919aa277..d4acfdbf4 100644 --- a/src/arch/x86/isa/microops/fpop.isa +++ b/src/arch/x86/isa/microops/fpop.isa @@ -245,7 +245,7 @@ let {{ self.className += "Top" def getAllocator(self, *microFlags): - return '''new %(class_name)s(machInst, mnemonic + return '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(src1)s, %(src2)s, %(dest)s, %(dataSize)s, %(spm)d)''' % { "class_name" : self.className, diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa index cb63e7cd9..af94cf31e 100644 --- a/src/arch/x86/isa/microops/ldstop.isa +++ b/src/arch/x86/isa/microops/ldstop.isa @@ -124,14 +124,16 @@ def template MicroLeaDeclare {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(class_name)s(ExtMachInst _machInst, const char * instMnem, uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(BasicExecDeclare)s }; @@ -151,11 +153,13 @@ def template MicroLoadExecute {{ %(ea_code)s; DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); - fault = read(xc, EA, Mem, (%(mem_flags)s) | segment); + fault = read(xc, EA, Mem, memFlags); - if(fault == NoFault) - { + if (fault == NoFault) { %(code)s; + } else if (memFlags & Request::PF_EXCLUSIVE) { + // For prefetches, ignore any faults/exceptions. + return NoFault; } if(fault == NoFault) { @@ -178,7 +182,7 @@ def template MicroLoadInitiateAcc {{ %(ea_code)s; DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); - fault = read(xc, EA, Mem, (%(mem_flags)s) | segment); + fault = read(xc, EA, Mem, memFlags); return fault; } @@ -194,7 +198,7 @@ def template MicroLoadCompleteAcc {{ %(op_decl)s; %(op_rd)s; - Mem = pkt->get<typeof(Mem)>(); + Mem = get(pkt); %(code)s; @@ -225,9 +229,10 @@ def template MicroStoreExecute {{ if(fault == NoFault) { - fault = write(xc, Mem, EA, (%(mem_flags)s) | segment); + fault = write(xc, Mem, EA, memFlags); if(fault == NoFault) { + %(post_code)s; %(op_wb)s; } } @@ -252,20 +257,20 @@ def template MicroStoreInitiateAcc {{ if(fault == NoFault) { - fault = write(xc, Mem, EA, (%(mem_flags)s) | segment); - if(fault == NoFault) - { - %(op_wb)s; - } + write(xc, Mem, EA, memFlags); } return fault; } }}; def template MicroStoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc, - Trace::InstRecord * traceData) const + Fault %(class_name)s::completeAcc(PacketPtr pkt, + %(CPU_exec_context)s * xc, Trace::InstRecord * traceData) const { + %(op_decl)s; + %(op_rd)s; + %(complete_code)s; + %(op_wb)s; return NoFault; } }}; @@ -295,14 +300,16 @@ def template MicroLdStOpDeclare {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(class_name)s(ExtMachInst _machInst, const char * instMnem, uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(BasicExecDeclare)s @@ -324,12 +331,13 @@ def template MicroLdStOpConstructor {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize) : + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, false, false, false, false, _scale, _index, _base, _disp, _segment, _data, - _dataSize, _addressSize, %(op_class)s) + _dataSize, _addressSize, _memFlags, %(op_class)s) { buildMe(); } @@ -340,12 +348,13 @@ def template MicroLdStOpConstructor {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize) : + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, isMicro, isDelayed, isFirst, isLast, _scale, _index, _base, _disp, _segment, _data, - _dataSize, _addressSize, %(op_class)s) + _dataSize, _addressSize, _memFlags, %(op_class)s) { buildMe(); } @@ -353,26 +362,35 @@ def template MicroLdStOpConstructor {{ let {{ class LdStOp(X86Microop): - def __init__(self, data, segment, addr, disp, dataSize, addressSize): + def __init__(self, data, segment, addr, disp, + dataSize, addressSize, baseFlags, atCPL0, prefetch): self.data = data [self.scale, self.index, self.base] = addr self.disp = disp self.segment = segment self.dataSize = dataSize self.addressSize = addressSize + self.memFlags = baseFlags + if atCPL0: + self.memFlags += " | (CPL0FlagBit << FlagShift)" + if prefetch: + self.memFlags += " | Request::PF_EXCLUSIVE" + self.memFlags += " | (machInst.legacy.addr ? " + \ + "(AddrSizeFlagBit << FlagShift) : 0)" def getAllocator(self, *microFlags): - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(scale)s, %(index)s, %(base)s, %(disp)s, %(segment)s, %(data)s, - %(dataSize)s, %(addressSize)s)''' % { + %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % { "class_name" : self.className, "flags" : self.microFlagsText(microFlags), "scale" : self.scale, "index" : self.index, "base" : self.base, "disp" : self.disp, "segment" : self.segment, "data" : self.data, - "dataSize" : self.dataSize, "addressSize" : self.addressSize} + "dataSize" : self.dataSize, "addressSize" : self.addressSize, + "memFlags" : self.memFlags} return allocator }}; @@ -384,9 +402,11 @@ let {{ decoder_output = "" exec_output = "" - calculateEA = "EA = SegBase + scale * Index + Base + disp;" + calculateEA = ''' + EA = bits(SegBase + scale * Index + Base + disp, addressSize * 8 - 1, 0); + ''' - def defineMicroLoadOp(mnemonic, code, mem_flags=0): + def defineMicroLoadOp(mnemonic, code, mem_flags="0"): global header_output global decoder_output global exec_output @@ -397,8 +417,7 @@ let {{ # Build up the all register version of this micro op iop = InstObjParams(name, Name, 'X86ISA::LdStOp', {"code": code, - "ea_code": calculateEA, - "mem_flags": mem_flags}) + "ea_code": calculateEA}) header_output += MicroLdStOpDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroLoadExecute.subst(iop) @@ -407,19 +426,24 @@ let {{ class LoadOp(LdStOp): def __init__(self, data, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): - super(LoadOp, self).__init__(data, segment, - addr, disp, dataSize, addressSize) + dataSize="env.dataSize", + addressSize="env.addressSize", + atCPL0=False, prefetch=False): + super(LoadOp, self).__init__(data, segment, addr, + disp, dataSize, addressSize, mem_flags, + atCPL0, prefetch) self.className = Name self.mnemonic = name microopClasses[name] = LoadOp defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);') - defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', 'StoreCheck') + defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', + 'X86ISA::StoreCheck') defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;') - def defineMicroStoreOp(mnemonic, code, mem_flags=0): + def defineMicroStoreOp(mnemonic, code, \ + postCode="", completeCode="", mem_flags="0"): global header_output global decoder_output global exec_output @@ -430,8 +454,9 @@ let {{ # Build up the all register version of this micro op iop = InstObjParams(name, Name, 'X86ISA::LdStOp', {"code": code, - "ea_code": calculateEA, - "mem_flags": mem_flags}) + "post_code": postCode, + "complete_code": completeCode, + "ea_code": calculateEA}) header_output += MicroLdStOpDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroStoreExecute.subst(iop) @@ -440,26 +465,26 @@ let {{ class StoreOp(LdStOp): def __init__(self, data, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): - super(StoreOp, self).__init__(data, segment, - addr, disp, dataSize, addressSize) + dataSize="env.dataSize", + addressSize="env.addressSize", + atCPL0=False): + super(StoreOp, self).__init__(data, segment, addr, + disp, dataSize, addressSize, mem_flags, atCPL0, False) self.className = Name self.mnemonic = name microopClasses[name] = StoreOp - defineMicroStoreOp('St', 'Mem = Data;') + defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);') defineMicroStoreOp('Stfp', 'Mem = FpData.uqw;') - defineMicroStoreOp('Stupd', ''' - Mem = Data; - Base = merge(Base, EA - SegBase, addressSize); - '''); - + defineMicroStoreOp('Stupd', 'Mem = pick(Data, 2, dataSize);', + 'Base = merge(Base, EA - SegBase, addressSize);', + 'Base = merge(Base, pkt->req->getVaddr() - SegBase, addressSize);'); + defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS") iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp', {"code": "Data = merge(Data, EA, dataSize);", - "ea_code": calculateEA, - "mem_flags": 0}) + "ea_code": calculateEA}) header_output += MicroLeaDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroLeaExecute.subst(iop) @@ -468,7 +493,7 @@ let {{ def __init__(self, data, segment, addr, disp = 0, dataSize="env.dataSize", addressSize="env.addressSize"): super(LeaOp, self).__init__(data, segment, - addr, disp, dataSize, addressSize) + addr, disp, dataSize, addressSize, "0", False, False) self.className = "Lea" self.mnemonic = "lea" @@ -477,38 +502,28 @@ let {{ iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp', {"code": "xc->demapPage(EA, 0);", - "ea_code": calculateEA, - "mem_flags": 0}) + "ea_code": calculateEA}) header_output += MicroLeaDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroLeaExecute.subst(iop) class TiaOp(LdStOp): def __init__(self, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): + dataSize="env.dataSize", + addressSize="env.addressSize"): super(TiaOp, self).__init__("NUM_INTREGS", segment, - addr, disp, dataSize, addressSize) + addr, disp, dataSize, addressSize, "0", False, False) self.className = "Tia" self.mnemonic = "tia" microopClasses["tia"] = TiaOp - iop = InstObjParams("cda", "Cda", 'X86ISA::LdStOp', - {"code": ''' - Addr paddr; - fault = xc->translateDataWriteAddr(EA, paddr, - dataSize, (1 << segment)); - ''', - "ea_code": calculateEA}) - header_output += MicroLeaDeclare.subst(iop) - decoder_output += MicroLdStOpConstructor.subst(iop) - exec_output += MicroLeaExecute.subst(iop) - class CdaOp(LdStOp): def __init__(self, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): + dataSize="env.dataSize", + addressSize="env.addressSize", atCPL0=False): super(CdaOp, self).__init__("NUM_INTREGS", segment, - addr, disp, dataSize, addressSize) + addr, disp, dataSize, addressSize, "0", atCPL0, False) self.className = "Cda" self.mnemonic = "cda" diff --git a/src/arch/x86/isa/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa index 6686444fd..4e75ab8b0 100644 --- a/src/arch/x86/isa/microops/limmop.isa +++ b/src/arch/x86/isa/microops/limmop.isa @@ -154,7 +154,7 @@ let {{ self.dataSize = dataSize def getAllocator(self, *microFlags): - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(dest)s, %(imm)s, %(dataSize)s)''' % { "class_name" : self.className, "mnemonic" : self.mnemonic, diff --git a/src/arch/x86/isa/microops/microops.isa b/src/arch/x86/isa/microops/microops.isa index 53f34d3f2..19266f6d6 100644 --- a/src/arch/x86/isa/microops/microops.isa +++ b/src/arch/x86/isa/microops/microops.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -68,5 +68,11 @@ //Load/store microop definitions ##include "ldstop.isa" +//Control flow microop definitions +##include "seqop.isa" + //Miscellaneous microop definitions ##include "specop.isa" + +//Microops for printing out debug messages through M5 +##include "debug.isa" diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index e761f0034..f9bc82119 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -231,6 +231,21 @@ output header {{ void divide(uint64_t dividend, uint64_t divisor, uint64_t "ient, uint64_t &remainder); + + enum SegmentSelectorCheck { + SegNoCheck, SegCSCheck, SegCallGateCheck, SegIntGateCheck, + SegSoftIntGateCheck, SegSSCheck, SegIretCheck, SegIntCSCheck, + SegTRCheck, SegTSSCheck, SegInGDTCheck, SegLDTCheck + }; + + enum LongModeDescriptorType { + LDT64 = 2, + AvailableTSS64 = 9, + BusyTSS64 = 0xb, + CallGate64 = 0xc, + IntGate64 = 0xe, + TrapGate64 = 0xf + }; }}; output decoder {{ @@ -424,7 +439,7 @@ let {{ className = self.className if self.mnemonic == self.base_mnemonic + 'i': className += "Imm" - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(src1)s, %(op2)s, %(dest)s, %(dataSize)s, %(ext)s)''' % { "class_name" : className, @@ -838,19 +853,28 @@ let {{ code = 'RIP = psrc1 + sop2 + CSBase' else_code="RIP = RIP;" - class Br(WrRegOp, CondRegOp): - code = 'nuIP = psrc1 + op2;' - else_code='nuIP = nuIP;' - class Wruflags(WrRegOp): code = 'ccFlagBits = psrc1 ^ op2' + class Wrflags(WrRegOp): + code = ''' + MiscReg newFlags = psrc1 ^ op2; + MiscReg userFlagMask = 0xDD5; + // Get only the user flags + ccFlagBits = newFlags & userFlagMask; + // Get everything else + nccFlagBits = newFlags & ~userFlagMask; + ''' + class Rdip(RdRegOp): code = 'DestReg = RIP - CSBase' class Ruflags(RdRegOp): code = 'DestReg = ccFlagBits' + class Rflags(RdRegOp): + code = 'DestReg = ccFlagBits | nccFlagBits' + class Ruflag(RegOp): code = ''' int flag = bits(ccFlagBits, imm8); @@ -863,6 +887,20 @@ let {{ super(Ruflag, self).__init__(dest, \ "NUM_INTREGS", imm, flags, dataSize) + class Rflag(RegOp): + code = ''' + MiscReg flagMask = 0x3F7FDD5; + MiscReg flags = (nccFlagBits | ccFlagBits) & flagMask; + int flag = bits(flags, imm8); + DestReg = merge(DestReg, flag, dataSize); + ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : + (ccFlagBits & ~EZFBit); + ''' + def __init__(self, dest, imm, flags=None, \ + dataSize="env.dataSize"): + super(Rflag, self).__init__(dest, \ + "NUM_INTREGS", imm, flags, dataSize) + class Sext(RegOp): code = ''' IntReg val = psrc1; @@ -883,17 +921,53 @@ let {{ ''' class Zext(RegOp): - code = 'DestReg = bits(psrc1, op2, 0);' + code = 'DestReg = merge(DestReg, bits(psrc1, op2, 0), dataSize);' + + class Rddr(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Rddr, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) + code = ''' + CR4 cr4 = CR4Op; + DR7 dr7 = DR7Op; + if ((cr4.de == 1 && (src1 == 4 || src1 == 5)) || src1 >= 8) { + fault = new InvalidOpcode(); + } else if (dr7.gd) { + fault = new DebugException(); + } else { + DestReg = merge(DestReg, DebugSrc1, dataSize); + } + ''' + + class Wrdr(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Wrdr, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) + code = ''' + CR4 cr4 = CR4Op; + DR7 dr7 = DR7Op; + if ((cr4.de == 1 && (dest == 4 || dest == 5)) || dest >= 8) { + fault = new InvalidOpcode(); + } else if ((dest == 6 || dest == 7) && + bits(psrc1, 63, 32) && + machInst.mode.mode == LongMode) { + fault = new GeneralProtection(0); + } else if (dr7.gd) { + fault = new DebugException(); + } else { + DebugDest = psrc1; + } + ''' class Rdcr(RegOp): def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): super(Rdcr, self).__init__(dest, \ src1, "NUM_INTREGS", flags, dataSize) code = ''' - if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) { + if (src1 == 1 || (src1 > 4 && src1 < 8) || (src1 > 8)) { fault = new InvalidOpcode(); } else { - DestReg = ControlSrc1; + DestReg = merge(DestReg, ControlSrc1, dataSize); } ''' @@ -950,7 +1024,7 @@ let {{ ''' # Microops for manipulating segmentation registers - class SegOp(RegOp): + class SegOp(CondRegOp): abstract = True def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): super(SegOp, self).__init__(dest, \ @@ -971,74 +1045,223 @@ let {{ SegSelDest = psrc1; ''' + class WrAttr(SegOp): + code = ''' + SegAttrDest = psrc1; + ''' + class Rdbase(SegOp): code = ''' - DestReg = SegBaseDest; + DestReg = merge(DestReg, SegBaseSrc1, dataSize); ''' class Rdlimit(SegOp): code = ''' - DestReg = SegLimitSrc1; + DestReg = merge(DestReg, SegLimitSrc1, dataSize); + ''' + + class RdAttr(SegOp): + code = ''' + DestReg = merge(DestReg, SegAttrSrc1, dataSize); ''' class Rdsel(SegOp): code = ''' - DestReg = SegSelSrc1; + DestReg = merge(DestReg, SegSelSrc1, dataSize); ''' - class Chks(SegOp): + class Rdval(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Rdval, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) code = ''' - // The selector is in source 1. - SegSelector selector = psrc1; - - // Compute the address of the descriptor and set DestReg to it. - if (selector.ti) { - // A descriptor in the LDT - Addr target = (selector.esi << 3) + LDTRBase; - if (!LDTRSel || (selector.esi << 3) + dataSize > LDTRLimit) - fault = new GeneralProtection(selector & mask(16)); - DestReg = target; - } else { - // A descriptor in the GDT - Addr target = (selector.esi << 3) + GDTRBase; - if ((selector.esi << 3) + dataSize > GDTRLimit) - fault = new GeneralProtection(selector & mask(16)); - DestReg = target; + DestReg = MiscRegSrc1; + ''' + + class Wrval(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Wrval, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) + code = ''' + MiscRegDest = SrcReg1; + ''' + + class Chks(RegOp): + def __init__(self, dest, src1, src2=0, + flags=None, dataSize="env.dataSize"): + super(Chks, self).__init__(dest, + src1, src2, flags, dataSize) + code = ''' + // The selector is in source 1 and can be at most 16 bits. + SegSelector selector = DestReg; + SegDescriptor desc = SrcReg1; + HandyM5Reg m5reg = M5Reg; + + switch (imm8) + { + case SegNoCheck: + break; + case SegCSCheck: + panic("CS checks for far calls/jumps not implemented.\\n"); + break; + case SegCallGateCheck: + panic("CS checks for far calls/jumps through call gates" + "not implemented.\\n"); + break; + case SegSoftIntGateCheck: + // Check permissions. + if (desc.dpl < m5reg.cpl) { + fault = new GeneralProtection(selector); + } + // Fall through on purpose + case SegIntGateCheck: + // Make sure the gate's the right type. + if ((m5reg.mode == LongMode && (desc.type & 0xe) != 0xe) || + ((desc.type & 0x6) != 0x6)) { + fault = new GeneralProtection(0); + } + break; + case SegSSCheck: + if (selector.si || selector.ti) { + if (!desc.p) { + fault = new StackFault(selector); + } + } else { + if ((m5reg.submode != SixtyFourBitMode || + m5reg.cpl == 3) || + !(desc.s == 1 && + desc.type.codeOrData == 0 && desc.type.w) || + (desc.dpl != m5reg.cpl) || + (selector.rpl != m5reg.cpl)) { + fault = new GeneralProtection(selector); + } + } + break; + case SegIretCheck: + { + if ((!selector.si && !selector.ti) || + (selector.rpl < m5reg.cpl) || + !(desc.s == 1 && desc.type.codeOrData == 1) || + (!desc.type.c && desc.dpl != selector.rpl) || + (desc.type.c && desc.dpl > selector.rpl)) { + fault = new GeneralProtection(selector); + } else if (!desc.p) { + fault = new SegmentNotPresent(selector); + } + break; + } + case SegIntCSCheck: + if (m5reg.mode == LongMode) { + if (desc.l != 1 || desc.d != 0) { + fault = new GeneralProtection(selector); + } + } else { + panic("Interrupt CS checks not implemented " + "in legacy mode.\\n"); + } + break; + case SegTRCheck: + if (!selector.si || selector.ti) { + fault = new GeneralProtection(selector); + } + break; + case SegTSSCheck: + if (!desc.p) { + fault = new SegmentNotPresent(selector); + } else if (!(desc.type == 0x9 || + (desc.type == 1 && + m5reg.mode != LongMode))) { + fault = new GeneralProtection(selector); + } + break; + case SegInGDTCheck: + if (selector.ti) { + fault = new GeneralProtection(selector); + } + break; + case SegLDTCheck: + if (!desc.p) { + fault = new SegmentNotPresent(selector); + } else if (desc.type != 0x2) { + fault = new GeneralProtection(selector); + } + break; + default: + panic("Undefined segment check type.\\n"); } ''' flag_code = ''' // Check for a NULL selector and set ZF,EZF appropriately. ccFlagBits = ccFlagBits & ~(ext & (ZFBit | EZFBit)); - if (!selector.esi && !selector.ti) + if (!selector.si && !selector.ti) ccFlagBits = ccFlagBits | (ext & (ZFBit | EZFBit)); ''' class Wrdh(RegOp): code = ''' + SegDescriptor desc = SrcReg1; + + uint64_t target = bits(SrcReg2, 31, 0) << 32; + switch(desc.type) { + case LDT64: + case AvailableTSS64: + case BusyTSS64: + replaceBits(target, 23, 0, desc.baseLow); + replaceBits(target, 31, 24, desc.baseHigh); + break; + case CallGate64: + case IntGate64: + case TrapGate64: + replaceBits(target, 15, 0, bits(desc, 15, 0)); + replaceBits(target, 31, 16, bits(desc, 63, 48)); + break; + default: + panic("Wrdh used with wrong descriptor type!\\n"); + } + DestReg = target; + ''' + + class Wrtsc(WrRegOp): + code = ''' + TscOp = psrc1; + ''' + + class Rdtsc(RdRegOp): + code = ''' + DestReg = TscOp; + ''' + class Rdm5reg(RdRegOp): + code = ''' + DestReg = M5Reg; ''' class Wrdl(RegOp): code = ''' SegDescriptor desc = SrcReg1; - SegAttr attr = 0; - attr.dpl = desc.dpl; - attr.defaultSize = desc.d; - if (!desc.s) { - SegBaseDest = SegBaseDest; - SegLimitDest = SegLimitDest; - SegAttrDest = SegAttrDest; - panic("System segment encountered.\\n"); - } else { - if (!desc.p) - panic("Segment not present.\\n"); - if (desc.type.codeOrData) { - attr.readable = desc.type.r; - attr.longMode = desc.l; - } else { - attr.expandDown = desc.type.e; + SegSelector selector = SrcReg2; + if (selector.si || selector.ti) { + SegAttr attr = 0; + attr.dpl = desc.dpl; + attr.defaultSize = desc.d; + if (!desc.s) { + // The expand down bit happens to be set for gates. + if (desc.type.e) { + panic("Gate descriptor encountered.\\n"); + } attr.readable = 1; - attr.writable = desc.type.w; + attr.writable = 1; + } else { + if (!desc.p) + panic("Segment not present.\\n"); + if (desc.type.codeOrData) { + attr.readable = desc.type.r; + attr.longMode = desc.l; + } else { + attr.expandDown = desc.type.e; + attr.readable = 1; + attr.writable = desc.type.w; + } } Addr base = desc.baseLow | (desc.baseHigh << 24); Addr limit = desc.limitLow | (desc.limitHigh << 16); @@ -1047,6 +1270,10 @@ let {{ SegBaseDest = base; SegLimitDest = limit; SegAttrDest = attr; + } else { + SegBaseDest = SegBaseDest; + SegLimitDest = SegLimitDest; + SegAttrDest = SegAttrDest; } ''' }}; diff --git a/src/arch/x86/isa/microops/seqop.isa b/src/arch/x86/isa/microops/seqop.isa new file mode 100644 index 000000000..332519b87 --- /dev/null +++ b/src/arch/x86/isa/microops/seqop.isa @@ -0,0 +1,251 @@ +// Copyright (c) 2008 The Hewlett-Packard Development Company +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the +// following conditions are met: +// +// The software must be used only for Non-Commercial Use which means any +// use which is NOT directed to receiving any direct monetary +// compensation for, or commercial advantage from such use. Illustrative +// examples of non-commercial use are academic research, personal study, +// teaching, education and corporate research & development. +// Illustrative examples of commercial use are distributing products for +// commercial advantage and providing services using the software for +// commercial advantage. +// +// If you wish to use this software or functionality therein that may be +// covered by patents for commercial use, please contact: +// Director of Intellectual Property Licensing +// Office of Strategy and Technology +// Hewlett-Packard Company +// 1501 Page Mill Road +// Palo Alto, California 94304 +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. Redistributions +// in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. Neither the name of +// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. No right of +// sublicense is granted herewith. Derivatives of the software and +// output created using the software may be prepared, but only for +// Non-Commercial Uses. Derivatives of the software may be shared with +// others provided: (i) the others agree to abide by the list of +// conditions herein which includes the Non-Commercial Use restrictions; +// and (ii) such Derivatives of the software include the above copyright +// notice to acknowledge the contribution from this software where +// applicable, this list of conditions and the disclaimer below. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +output header {{ + class SeqOpBase : public X86ISA::X86MicroopBase + { + protected: + uint16_t target; + uint8_t cc; + + public: + SeqOpBase(ExtMachInst _machInst, const char * instMnem, + const char * mnemonic, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc); + + SeqOpBase(ExtMachInst _machInst, const char * instMnem, + const char * mnemonic, + uint16_t _target, uint8_t _cc); + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +def template SeqOpDeclare {{ + class %(class_name)s : public %(base_class)s + { + private: + void buildMe(); + public: + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc); + + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + uint16_t _target, uint8_t _cc); + + %(BasicExecDeclare)s + }; +}}; + +def template SeqOpExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + %(op_decl)s; + %(op_rd)s; + if (%(cond_test)s) { + %(code)s; + } else { + %(else_code)s; + } + %(op_wb)s; + return NoFault; + } +}}; + +output decoder {{ + inline SeqOpBase::SeqOpBase( + ExtMachInst machInst, const char * mnemonic, const char * instMnem, + uint16_t _target, uint8_t _cc) : + X86MicroopBase(machInst, mnemonic, instMnem, + false, false, false, false, No_OpClass), + target(_target), cc(_cc) + { + } + + inline SeqOpBase::SeqOpBase( + ExtMachInst machInst, const char * mnemonic, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc) : + X86MicroopBase(machInst, mnemonic, instMnem, + isMicro, isDelayed, isFirst, isLast, No_OpClass), + target(_target), cc(_cc) + { + } +}}; + +def template SeqOpConstructor {{ + + inline void %(class_name)s::buildMe() + { + %(constructor)s; + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + uint16_t _target, uint8_t _cc) : + %(base_class)s(machInst, "%(mnemonic)s", instMnem, _target, _cc) + { + buildMe(); + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc) : + %(base_class)s(machInst, "%(mnemonic)s", instMnem, + isMicro, isDelayed, isFirst, isLast, _target, _cc) + { + buildMe(); + } +}}; + +output decoder {{ + std::string SeqOpBase::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + ccprintf(response, "%#x", target); + + return response.str(); + } +}}; + +let {{ + class SeqOp(X86Microop): + def __init__(self, target, flags=None): + self.target = target + if flags: + if not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + self.cond = " | ".join(flags) + self.className += "Flags" + else: + self.cond = "0" + + def getAllocator(self, *microFlags): + allocator = '''new %(class_name)s(machInst, macrocodeBlock + %(flags)s, %(target)s, %(cc)s)''' % { + "class_name" : self.className, + "flags" : self.microFlagsText(microFlags), + "target" : self.target, + "cc" : self.cond} + return allocator + + class Br(SeqOp): + className = "MicroBranch" + + def getAllocator(self, *microFlags): + (is_micro, is_delayed, is_first, is_last) = microFlags + is_last = False + is_delayed = True + microFlags = (is_micro, is_delayed, is_first, is_last) + return super(Br, self).getAllocator(*microFlags) + + class Eret(SeqOp): + target = "normalMicroPC(0)" + className = "Eret" + + def __init__(self, flags=None): + if flags: + if not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + self.cond = " | ".join(flags) + self.className += "Flags" + else: + self.cond = "0" + + def getAllocator(self, *microFlags): + (is_micro, is_delayed, is_first, is_last) = microFlags + is_last = True + is_delayed = False + microFlags = (is_micro, is_delayed, is_first, is_last) + return super(Eret, self).getAllocator(*microFlags) + + iop = InstObjParams("br", "MicroBranchFlags", "SeqOpBase", + {"code": "nuIP = target", + "else_code": "nuIP = nuIP", + "cond_test": "checkCondition(ccFlagBits, cc)"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + iop = InstObjParams("br", "MicroBranch", "SeqOpBase", + {"code": "nuIP = target", + "else_code": "nuIP = nuIP", + "cond_test": "true"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + microopClasses["br"] = Br + + iop = InstObjParams("eret", "EretFlags", "SeqOpBase", + {"code": "", "else_code": "", + "cond_test": "checkCondition(ccFlagBits, cc)"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + iop = InstObjParams("eret", "Eret", "SeqOpBase", + {"code": "", "else_code": "", + "cond_test": "true"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + microopClasses["eret"] = Eret +}}; diff --git a/src/arch/x86/isa/microops/specop.isa b/src/arch/x86/isa/microops/specop.isa index 6bcc7ff91..c6e172ef1 100644 --- a/src/arch/x86/isa/microops/specop.isa +++ b/src/arch/x86/isa/microops/specop.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -95,6 +95,9 @@ output header {{ } %(BasicExecDeclare)s + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; }; }}; @@ -201,6 +204,16 @@ output decoder {{ return response.str(); } + + std::string MicroHalt::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + + return response.str(); + } }}; let {{ @@ -217,7 +230,7 @@ let {{ self.cond = "0" def getAllocator(self, *microFlags): - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(fault)s, %(cc)s)''' % { "class_name" : self.className, "flags" : self.microFlagsText(microFlags), @@ -244,7 +257,7 @@ let {{ pass def getAllocator(self, *microFlags): - return "new MicroHalt(machInst, mnemonic %s)" % \ + return "new MicroHalt(machInst, macrocodeBlock %s)" % \ self.microFlagsText(microFlags) microopClasses["halt"] = Halt diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa index 9345158e9..ab1e9a851 100644 --- a/src/arch/x86/isa/operands.isa +++ b/src/arch/x86/isa/operands.isa @@ -26,7 +26,7 @@ // // Authors: Gabe Black -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -109,7 +109,14 @@ def operands {{ 'Quotient': ('IntReg', 'uqw', 'INTREG_IMPLICIT(2)', 'IsInteger', 9), 'Remainder': ('IntReg', 'uqw', 'INTREG_IMPLICIT(3)', 'IsInteger', 10), 'Divisor': ('IntReg', 'uqw', 'INTREG_IMPLICIT(4)', 'IsInteger', 11), - 'rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12), + 'Rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12), + 'Rbx': ('IntReg', 'uqw', '(INTREG_RBX)', 'IsInteger', 13), + 'Rcx': ('IntReg', 'uqw', '(INTREG_RCX)', 'IsInteger', 14), + 'Rdx': ('IntReg', 'uqw', '(INTREG_RDX)', 'IsInteger', 15), + 'Rsp': ('IntReg', 'uqw', '(INTREG_RSP)', 'IsInteger', 16), + 'Rbp': ('IntReg', 'uqw', '(INTREG_RBP)', 'IsInteger', 17), + 'Rsi': ('IntReg', 'uqw', '(INTREG_RSI)', 'IsInteger', 18), + 'Rdi': ('IntReg', 'uqw', '(INTREG_RDI)', 'IsInteger', 19), 'FpSrcReg1': ('FloatReg', 'df', 'src1', 'IsFloating', 20), 'FpSrcReg2': ('FloatReg', 'df', 'src2', 'IsFloating', 21), 'FpDestReg': ('FloatReg', 'df', 'dest', 'IsFloating', 22), @@ -117,10 +124,13 @@ def operands {{ 'RIP': ('NPC', 'uqw', None, (None, None, 'IsControl'), 50), 'uIP': ('UPC', 'uqw', None, (None, None, 'IsControl'), 51), 'nuIP': ('NUPC', 'uqw', None, (None, None, 'IsControl'), 52), + # This holds the condition code portion of the flag register. The + # nccFlagBits version holds the rest. 'ccFlagBits': ('IntReg', 'uqw', 'INTREG_PSEUDO(0)', None, 60), - # The TOP register should needs to be more protected so that later + # These register should needs to be more protected so that later # instructions don't map their indexes with an old value. - 'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 61), + 'nccFlagBits': ('ControlReg', 'uqw', 'MISCREG_RFLAGS', None, 61), + 'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 62), # The segment base as used by memory instructions. 'SegBase': ('ControlReg', 'uqw', 'MISCREG_SEG_EFF_BASE(segment)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 70), @@ -128,23 +138,31 @@ def operands {{ # original instruction. 'ControlDest': ('ControlReg', 'uqw', 'MISCREG_CR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 100), 'ControlSrc1': ('ControlReg', 'uqw', 'MISCREG_CR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 101), - 'SegBaseDest': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 102), - 'SegBaseSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 103), - 'SegLimitDest': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 104), - 'SegLimitSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 105), - 'SegSelDest': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 106), - 'SegSelSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 107), - 'SegAttrDest': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 108), - 'SegAttrSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 109), + 'DebugDest': ('ControlReg', 'uqw', 'MISCREG_DR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 102), + 'DebugSrc1': ('ControlReg', 'uqw', 'MISCREG_DR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 103), + 'SegBaseDest': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 104), + 'SegBaseSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 105), + 'SegLimitDest': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 106), + 'SegLimitSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 107), + 'SegSelDest': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 108), + 'SegSelSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 109), + 'SegAttrDest': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 110), + 'SegAttrSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 111), # Operands to access specific control registers directly. 'EferOp': ('ControlReg', 'uqw', 'MISCREG_EFER', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 200), 'CR4Op': ('ControlReg', 'uqw', 'MISCREG_CR4', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 201), - 'LDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSL_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 202), - 'LDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSL_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 203), - 'LDTRSel': ('ControlReg', 'uqw', 'MISCREG_TSL', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 204), - 'GDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSG_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 205), - 'GDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSG_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 206), - 'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 207), + 'DR7Op': ('ControlReg', 'uqw', 'MISCREG_DR7', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 202), + 'LDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSL_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 203), + 'LDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSL_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 204), + 'LDTRSel': ('ControlReg', 'uqw', 'MISCREG_TSL', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 205), + 'GDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSG_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 206), + 'GDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSG_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 207), + 'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 208), + 'CSAttr': ('ControlReg', 'udw', 'MISCREG_CS_ATTR', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 209), + 'MiscRegDest': ('ControlReg', 'uqw', 'dest', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 210), + 'MiscRegSrc1': ('ControlReg', 'uqw', 'src1', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 211), + 'TscOp': ('ControlReg', 'uqw', 'MISCREG_TSC', (None, None, ['IsSerializeAfter', 'IsSerializing', 'IsNonSpeculative']), 212), + 'M5Reg': ('ControlReg', 'uqw', 'MISCREG_M5_REG', (None, None, None), 213), 'Mem': ('Mem', 'uqw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 300) }}; diff --git a/src/arch/x86/isa/rom.isa b/src/arch/x86/isa/rom.isa new file mode 100644 index 000000000..7d3eb8670 --- /dev/null +++ b/src/arch/x86/isa/rom.isa @@ -0,0 +1,90 @@ +// Copyright (c) 2008 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +def template MicroRomConstructor {{ + + %(define_generators)s + const MicroPC X86ISA::MicrocodeRom::numMicroops = %(num_microops)s; + + X86ISA::MicrocodeRom::MicrocodeRom() + { + using namespace RomLabels; + genFuncs = new GenFunc[numMicroops]; + %(alloc_generators)s; + } +}}; + +let {{ + from micro_asm import Rom + + class X86MicrocodeRom(Rom): + def __init__(self, name): + super(X86MicrocodeRom, self).__init__(name) + self.directives = {} + + def add_microop(self, mnemonic, microop): + microop.mnemonic = mnemonic + microop.micropc = len(self.microops) + self.microops.append(microop) + + + def getDeclaration(self): + declareLabels = "namespace RomLabels {\n" + for (label, microop) in self.labels.items(): + declareLabels += "const static uint64_t label_%s = %d;\n" \ + % (label, microop.micropc) + for (label, microop) in self.externs.items(): + declareLabels += \ + "const static MicroPC extern_label_%s = %d;\n" \ + % (label, microop.micropc) + declareLabels += "}\n" + return declareLabels; + + def getDefinition(self): + numMicroops = len(self.microops) + allocGenerators = '' + micropc = 0 + define_generators = ''' + namespace + { + static const char romMnemonic[] = "Microcode_ROM"; + ''' + for op in self.microops: + define_generators += op.getGeneratorDef(micropc) + allocGenerators += "genFuncs[%d] = %s;\n" % \ + (micropc, op.getGenerator(micropc)) + micropc += 1 + define_generators += "}\n" + iop = InstObjParams(self.name, self.name, "MicrocodeRom", + {"code" : "", + "define_generators" : define_generators, + "num_microops" : numMicroops, + "alloc_generators" : allocGenerators + }) + return MicroRomConstructor.subst(iop); +}}; diff --git a/src/arch/x86/isa/specialize.isa b/src/arch/x86/isa/specialize.isa index abf734307..b74363470 100644 --- a/src/arch/x86/isa/specialize.isa +++ b/src/arch/x86/isa/specialize.isa @@ -86,8 +86,17 @@ let {{ let {{ def doRipRelativeDecode(Name, opTypes, env): # print "RIPing %s with opTypes %s" % (Name, opTypes) - normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), copy.copy(env)) - ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), copy.copy(env)) + env.memoryInst = True + normEnv = copy.copy(env) + normEnv.addToDisassembly( + '''printMem(out, env.seg, env.scale, env.index, env.base, + machInst.displacement, env.addressSize, false);''') + normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv) + ripEnv = copy.copy(env) + ripEnv.addToDisassembly( + '''printMem(out, env.seg, 1, 0, 0, + machInst.displacement, env.addressSize, true);''') + ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv) blocks = OutputBlocks() blocks.append(normBlocks) @@ -138,12 +147,17 @@ let {{ #Figure out what to do with fixed register operands #This is the index to use, so we should stick it some place. if opType.reg in ("A", "B", "C", "D"): - env.addReg("INTREG_R%sX" % opType.reg) + regString = "INTREG_R%sX" % opType.reg else: - env.addReg("INTREG_R%s" % opType.reg) + regString = "INTREG_R%s" % opType.reg + env.addReg(regString) + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % regString) Name += "_R" elif opType.tag == "B": # This refers to registers whose index is encoded as part of the opcode + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % InstRegIndex) Name += "_R" env.addReg(InstRegIndex) elif opType.tag == "M": @@ -156,24 +170,34 @@ let {{ elif opType.tag == "C": # A control register indexed by the "reg" field env.addReg(ModRMRegIndex) + env.addToDisassembly( + "ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex) Name += "_C" elif opType.tag == "D": # A debug register indexed by the "reg" field env.addReg(ModRMRegIndex) + env.addToDisassembly( + "ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex) Name += "_D" elif opType.tag == "S": # A segment selector register indexed by the "reg" field env.addReg(ModRMRegIndex) + env.addToDisassembly( + "printSegment(out, %s);\n" % ModRMRegIndex) Name += "_S" elif opType.tag in ("G", "P", "T", "V"): # Use the "reg" field of the ModRM byte to select the register env.addReg(ModRMRegIndex) + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % ModRMRegIndex) Name += "_R" elif opType.tag in ("E", "Q", "W"): # This might refer to memory or to a register. We need to # divide it up farther. regEnv = copy.copy(env) regEnv.addReg(ModRMRMIndex) + regEnv.addToDisassembly( + "printReg(out, %s, regSize);\n" % ModRMRMIndex) # This refers to memory. The macroop constructor should set up # modrm addressing. memEnv = copy.copy(env) @@ -183,6 +207,8 @@ let {{ (doRipRelativeDecode, Name, copy.copy(opTypes), memEnv)) elif opType.tag in ("I", "J"): # Immediates + env.addToDisassembly( + "ccprintf(out, \"%#x\", machInst.immediate);\n") Name += "_I" elif opType.tag == "O": # Immediate containing a memory offset @@ -190,10 +216,22 @@ let {{ elif opType.tag in ("PR", "R", "VR"): # Non register modrm settings should cause an error env.addReg(ModRMRMIndex) + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % ModRMRMIndex) Name += "_R" elif opType.tag in ("X", "Y"): # This type of memory addressing is for string instructions. # They'll use the right index and segment internally. + if opType.tag == "X": + env.addToDisassembly( + '''printMem(out, env.seg, + 1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0, + env.addressSize, false);''') + else: + env.addToDisassembly( + '''printMem(out, SEGMENT_REG_ES, + 1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0, + env.addressSize, false);''') Name += "_M" else: raise Exception, "Unrecognized tag %s." % opType.tag diff --git a/src/arch/x86/isa_traits.hh b/src/arch/x86/isa_traits.hh index abb7694ed..d25e0eb70 100644 --- a/src/arch/x86/isa_traits.hh +++ b/src/arch/x86/isa_traits.hh @@ -106,19 +106,7 @@ namespace X86ISA const int StackPointerReg = INTREG_RSP; //X86 doesn't seem to have a link register const int ReturnAddressReg = 0; - const int ReturnValueReg = INTREG_RAX; const int FramePointerReg = INTREG_RBP; - const int ArgumentReg[] = { - INTREG_RDI, - INTREG_RSI, - INTREG_RDX, - //This argument register is r10 for syscalls and rcx for C. - INTREG_R10W, - //INTREG_RCX, - INTREG_R8W, - INTREG_R9W - }; - const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); // Some OS syscalls use a second register (rdx) to return a second // value diff --git a/src/arch/x86/linux/linux.cc b/src/arch/x86/linux/linux.cc index 5e8d2de16..41855da59 100644 --- a/src/arch/x86/linux/linux.cc +++ b/src/arch/x86/linux/linux.cc @@ -97,3 +97,42 @@ const int X86Linux64::NUM_OPEN_FLAGS = sizeof(X86Linux64::openFlagTable) / sizeof(X86Linux64::openFlagTable[0]); +// open(2) flags translation table +OpenFlagTransTable X86Linux32::openFlagTable[] = { +#ifdef _MSC_VER + { TGT_O_RDONLY, _O_RDONLY }, + { TGT_O_WRONLY, _O_WRONLY }, + { TGT_O_RDWR, _O_RDWR }, + { TGT_O_APPEND, _O_APPEND }, + { TGT_O_CREAT, _O_CREAT }, + { TGT_O_TRUNC, _O_TRUNC }, + { TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { TGT_O_RDONLY, O_RDONLY }, + { TGT_O_WRONLY, O_WRONLY }, + { TGT_O_RDWR, O_RDWR }, + { TGT_O_APPEND, O_APPEND }, + { TGT_O_CREAT, O_CREAT }, + { TGT_O_TRUNC, O_TRUNC }, + { TGT_O_EXCL, O_EXCL }, + { TGT_O_NONBLOCK, O_NONBLOCK }, + { TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int X86Linux32::NUM_OPEN_FLAGS = + sizeof(X86Linux32::openFlagTable) / + sizeof(X86Linux32::openFlagTable[0]); + diff --git a/src/arch/x86/linux/linux.hh b/src/arch/x86/linux/linux.hh index 8a78d5320..c2941c769 100644 --- a/src/arch/x86/linux/linux.hh +++ b/src/arch/x86/linux/linux.hh @@ -82,26 +82,26 @@ class X86Linux64 : public Linux uint64_t st_mtime_nsec; uint64_t st_ctimeX; uint64_t st_ctime_nsec; - int64_t __unused[3]; + int64_t unused0[3]; } tgt_stat64; static OpenFlagTransTable openFlagTable[]; - static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK - static const int TGT_O_APPEND = 00002000; //!< O_APPEND - static const int TGT_O_CREAT = 00000100; //!< O_CREAT - static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC - static const int TGT_O_EXCL = 00000200; //!< O_EXCL - static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY - static const int TGT_O_SYNC = 00010000; //!< O_SYNC -// static const int TGT_O_DRD = 0x00010000; //!< O_DRD -// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO -// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE -// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC -// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00002000; //!< O_APPEND + static const int TGT_O_CREAT = 00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC + static const int TGT_O_EXCL = 00000200; //!< O_EXCL + static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY + static const int TGT_O_SYNC = 00010000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC static const int NUM_OPEN_FLAGS; @@ -113,4 +113,53 @@ class X86Linux64 : public Linux } tgt_iovec; }; +class X86Linux32 : public Linux +{ + public: + + typedef struct { + uint64_t st_dev; + uint8_t __pad0[4]; + uint32_t __st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + int64_t st_size; + uint8_t __pad3[4]; + uint32_t st_blksize; + uint64_t st_blocks; + uint32_t st_atimeX; + uint32_t st_atime_nsec; + uint32_t st_mtimeX; + uint32_t st_mtime_nsec; + uint32_t st_ctimeX; + uint32_t st_ctime_nsec; + uint64_t st_ino; + } tgt_stat64; + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00002000; //!< O_APPEND + static const int TGT_O_CREAT = 00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC + static const int TGT_O_EXCL = 00000200; //!< O_EXCL + static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY + static const int TGT_O_SYNC = 00010000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x20; +}; + #endif diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc index 8beaf150b..da22d9851 100644 --- a/src/arch/x86/linux/process.cc +++ b/src/arch/x86/linux/process.cc @@ -64,34 +64,16 @@ #include "kern/linux/linux.hh" #include "sim/process.hh" -#include "sim/syscall_emul.hh" using namespace std; using namespace X86ISA; -SyscallDesc* -X86LinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} - -X86LinuxProcess::X86LinuxProcess(LiveProcessParams * params, +X86_64LinuxProcess::X86_64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile) - : X86LiveProcess(params, objFile), - Num_Syscall_Descs(273) + : X86_64LiveProcess(params, objFile, syscallDescs, 273) {} -void X86LinuxProcess::handleTrap(int trapNum, ThreadContext *tc) -{ - switch(trapNum) - { - //This implementation is from SPARC - case 0x10: //Linux 32 bit syscall trap - tc->syscall(tc->readIntReg(1)); - break; - default: - X86LiveProcess::handleTrap(trapNum, tc); - } -} +I386LinuxProcess::I386LinuxProcess(LiveProcessParams * params, + ObjectFile *objFile) + : I386LiveProcess(params, objFile, syscallDescs, 324) +{} diff --git a/src/arch/x86/linux/process.hh b/src/arch/x86/linux/process.hh index e224374d4..ca3606ef0 100644 --- a/src/arch/x86/linux/process.hh +++ b/src/arch/x86/linux/process.hh @@ -60,26 +60,30 @@ #include "sim/process.hh" #include "arch/x86/linux/linux.hh" -#include "arch/x86/syscallreturn.hh" #include "arch/x86/process.hh" namespace X86ISA { -/// A process with emulated x86/Linux syscalls. -class X86LinuxProcess : public X86LiveProcess +class X86_64LinuxProcess : public X86_64LiveProcess { + protected: + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + public: /// Constructor. - X86LinuxProcess(LiveProcessParams * params, ObjectFile *objFile); + X86_64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile); +}; +class I386LinuxProcess : public I386LiveProcess +{ + protected: /// Array of syscall descriptors, indexed by call number. static SyscallDesc syscallDescs[]; - SyscallDesc* getDesc(int callnum); - - const int Num_Syscall_Descs; - - void handleTrap(int trapNum, ThreadContext *tc); + public: + /// Constructor. + I386LinuxProcess(LiveProcessParams * params, ObjectFile *objFile); }; } // namespace X86ISA diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc index ae2ac243b..09235ec94 100644 --- a/src/arch/x86/linux/syscalls.cc +++ b/src/arch/x86/linux/syscalls.cc @@ -68,7 +68,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "Linux"); strcpy(name->nodename, "m5.eecs.umich.edu"); @@ -94,8 +94,8 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, }; //First argument is the code, second is the address - int code = tc->getSyscallArg(0); - uint64_t addr = tc->getSyscallArg(1); + int code = process->getSyscallArg(tc, 0); + uint64_t addr = process->getSyscallArg(tc, 1); uint64_t fsBase, gsBase; TranslatingPort *p = tc->getMemPort(); switch(code) @@ -122,7 +122,112 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, } } -SyscallDesc X86LinuxProcess::syscallDescs[] = { +BitUnion32(UserDescFlags) + Bitfield<0> seg_32bit; + Bitfield<2, 1> contents; + Bitfield<3> read_exec_only; + Bitfield<4> limit_in_pages; + Bitfield<5> seg_not_present; + Bitfield<6> useable; +EndBitUnion(UserDescFlags) + +struct UserDesc32 { + uint32_t entry_number; + uint32_t base_addr; + uint32_t limit; + uint32_t flags; +}; + +struct UserDesc64 { + uint32_t entry_number; + uint32_t __padding1; + uint64_t base_addr; + uint32_t limit; + uint32_t flags; +}; + +static SyscallReturn +setThreadArea32Func(SyscallDesc *desc, int callnum, + LiveProcess *process, ThreadContext *tc) +{ + const int minTLSEntry = 6; + const int numTLSEntries = 3; + const int maxTLSEntry = minTLSEntry + numTLSEntries - 1; + + X86LiveProcess *x86lp = dynamic_cast<X86LiveProcess *>(process); + assert(x86lp); + + assert((maxTLSEntry + 1) * sizeof(uint64_t) <= x86lp->gdtSize()); + + TypedBufferArg<UserDesc32> userDesc(process->getSyscallArg(tc, 0)); + TypedBufferArg<uint64_t> + gdt(x86lp->gdtStart() + minTLSEntry * sizeof(uint64_t), + numTLSEntries * sizeof(uint64_t)); + + if (!userDesc.copyIn(tc->getMemPort())) + return -EFAULT; + + if (!gdt.copyIn(tc->getMemPort())) + panic("Failed to copy in GDT for %s.\n", desc->name); + + if (userDesc->entry_number == (uint32_t)(-1)) { + // Find a free TLS entry. + for (int i = 0; i < numTLSEntries; i++) { + if (gdt[i] == 0) { + userDesc->entry_number = i + minTLSEntry; + break; + } + } + // We failed to find one. + if (userDesc->entry_number == (uint32_t)(-1)) + return -ESRCH; + } + + int index = userDesc->entry_number; + + if (index < minTLSEntry || index > maxTLSEntry) + return -EINVAL; + + index -= minTLSEntry; + + // Build the entry we're going to add. + SegDescriptor segDesc = 0; + UserDescFlags flags = userDesc->flags; + + segDesc.limitLow = bits(userDesc->limit, 15, 0); + segDesc.baseLow = bits(userDesc->base_addr, 23, 0); + segDesc.type.a = 1; + if (!flags.read_exec_only) + segDesc.type.w = 1; + if (bits((uint8_t)flags.contents, 0)) + segDesc.type.e = 1; + if (bits((uint8_t)flags.contents, 1)) + segDesc.type.codeOrData = 1; + segDesc.s = 1; + segDesc.dpl = 3; + if (!flags.seg_not_present) + segDesc.p = 1; + segDesc.limitHigh = bits(userDesc->limit, 19, 16); + if (flags.useable) + segDesc.avl = 1; + segDesc.l = 0; + if (flags.seg_32bit) + segDesc.d = 1; + if (flags.limit_in_pages) + segDesc.g = 1; + segDesc.baseHigh = bits(userDesc->base_addr, 31, 24); + + gdt[index] = (uint64_t)segDesc; + + if (!userDesc.copyOut(tc->getMemPort())) + return -EFAULT; + if (!gdt.copyOut(tc->getMemPort())) + panic("Failed to copy out GDT for %s.\n", desc->name); + + return 0; +} + +SyscallDesc X86_64LinuxProcess::syscallDescs[] = { /* 0 */ SyscallDesc("read", readFunc), /* 1 */ SyscallDesc("write", writeFunc), /* 2 */ SyscallDesc("open", openFunc<X86Linux64>), @@ -135,7 +240,7 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = { /* 9 */ SyscallDesc("mmap", mmapFunc<X86Linux64>), /* 10 */ SyscallDesc("mprotect", unimplementedFunc), /* 11 */ SyscallDesc("munmap", munmapFunc), - /* 12 */ SyscallDesc("brk", obreakFunc), + /* 12 */ SyscallDesc("brk", brkFunc), /* 13 */ SyscallDesc("rt_sigaction", unimplementedFunc), /* 14 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), /* 15 */ SyscallDesc("rt_sigreturn", unimplementedFunc), @@ -148,7 +253,7 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = { /* 22 */ SyscallDesc("pipe", unimplementedFunc), /* 23 */ SyscallDesc("select", unimplementedFunc), /* 24 */ SyscallDesc("sched_yield", unimplementedFunc), - /* 25 */ SyscallDesc("mremap", unimplementedFunc), + /* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>), /* 26 */ SyscallDesc("msync", unimplementedFunc), /* 27 */ SyscallDesc("mincore", unimplementedFunc), /* 28 */ SyscallDesc("madvise", unimplementedFunc), @@ -397,3 +502,330 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = { /* 271 */ SyscallDesc("ppoll", unimplementedFunc), /* 272 */ SyscallDesc("unshare", unimplementedFunc) }; + +SyscallDesc I386LinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", unimplementedFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", unimplementedFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<X86Linux64>), + /* 6 */ SyscallDesc("close", unimplementedFunc), + /* 7 */ SyscallDesc("waitpid", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unimplementedFunc), + /* 11 */ SyscallDesc("execve", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", unimplementedFunc), + /* 16 */ SyscallDesc("lchown", unimplementedFunc), + /* 17 */ SyscallDesc("break", unimplementedFunc), + /* 18 */ SyscallDesc("oldstat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", unimplementedFunc), + /* 20 */ SyscallDesc("getpid", unimplementedFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", unimplementedFunc), + /* 24 */ SyscallDesc("getuid", unimplementedFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("oldfstat", unimplementedFunc), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("ftime", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("rename", unimplementedFunc), + /* 39 */ SyscallDesc("mkdir", unimplementedFunc), + /* 40 */ SyscallDesc("rmdir", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("prof", unimplementedFunc), + /* 45 */ SyscallDesc("brk", brkFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", unimplementedFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("geteuid", unimplementedFunc), + /* 50 */ SyscallDesc("getegid", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("umount2", unimplementedFunc), + /* 53 */ SyscallDesc("lock", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("fcntl", unimplementedFunc), + /* 56 */ SyscallDesc("mpx", unimplementedFunc), + /* 57 */ SyscallDesc("setpgid", unimplementedFunc), + /* 58 */ SyscallDesc("ulimit", unimplementedFunc), + /* 59 */ SyscallDesc("oldolduname", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("ustat", unimplementedFunc), + /* 63 */ SyscallDesc("dup2", unimplementedFunc), + /* 64 */ SyscallDesc("getppid", unimplementedFunc), + /* 65 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 66 */ SyscallDesc("setsid", unimplementedFunc), + /* 67 */ SyscallDesc("sigaction", unimplementedFunc), + /* 68 */ SyscallDesc("sgetmask", unimplementedFunc), + /* 69 */ SyscallDesc("ssetmask", unimplementedFunc), + /* 70 */ SyscallDesc("setreuid", unimplementedFunc), + /* 71 */ SyscallDesc("setregid", unimplementedFunc), + /* 72 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 73 */ SyscallDesc("sigpending", unimplementedFunc), + /* 74 */ SyscallDesc("sethostname", unimplementedFunc), + /* 75 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 76 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 77 */ SyscallDesc("getrusage", unimplementedFunc), + /* 78 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 79 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 80 */ SyscallDesc("getgroups", unimplementedFunc), + /* 81 */ SyscallDesc("setgroups", unimplementedFunc), + /* 82 */ SyscallDesc("select", unimplementedFunc), + /* 83 */ SyscallDesc("symlink", unimplementedFunc), + /* 84 */ SyscallDesc("oldlstat", unimplementedFunc), + /* 85 */ SyscallDesc("readlink", unimplementedFunc), + /* 86 */ SyscallDesc("uselib", unimplementedFunc), + /* 87 */ SyscallDesc("swapon", unimplementedFunc), + /* 88 */ SyscallDesc("reboot", unimplementedFunc), + /* 89 */ SyscallDesc("readdir", unimplementedFunc), + /* 90 */ SyscallDesc("mmap", unimplementedFunc), + /* 91 */ SyscallDesc("munmap", unimplementedFunc), + /* 92 */ SyscallDesc("truncate", unimplementedFunc), + /* 93 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 94 */ SyscallDesc("fchmod", unimplementedFunc), + /* 95 */ SyscallDesc("fchown", unimplementedFunc), + /* 96 */ SyscallDesc("getpriority", unimplementedFunc), + /* 97 */ SyscallDesc("setpriority", unimplementedFunc), + /* 98 */ SyscallDesc("profil", unimplementedFunc), + /* 99 */ SyscallDesc("statfs", unimplementedFunc), + /* 100 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 101 */ SyscallDesc("ioperm", unimplementedFunc), + /* 102 */ SyscallDesc("socketcall", unimplementedFunc), + /* 103 */ SyscallDesc("syslog", unimplementedFunc), + /* 104 */ SyscallDesc("setitimer", unimplementedFunc), + /* 105 */ SyscallDesc("getitimer", unimplementedFunc), + /* 106 */ SyscallDesc("stat", unimplementedFunc), + /* 107 */ SyscallDesc("lstat", unimplementedFunc), + /* 108 */ SyscallDesc("fstat", unimplementedFunc), + /* 109 */ SyscallDesc("olduname", unimplementedFunc), + /* 110 */ SyscallDesc("iopl", unimplementedFunc), + /* 111 */ SyscallDesc("vhangup", unimplementedFunc), + /* 112 */ SyscallDesc("idle", unimplementedFunc), + /* 113 */ SyscallDesc("vm86old", unimplementedFunc), + /* 114 */ SyscallDesc("wait4", unimplementedFunc), + /* 115 */ SyscallDesc("swapoff", unimplementedFunc), + /* 116 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 117 */ SyscallDesc("ipc", unimplementedFunc), + /* 118 */ SyscallDesc("fsync", unimplementedFunc), + /* 119 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 120 */ SyscallDesc("clone", unimplementedFunc), + /* 121 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 122 */ SyscallDesc("uname", unameFunc), + /* 123 */ SyscallDesc("modify_ldt", unimplementedFunc), + /* 124 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 125 */ SyscallDesc("mprotect", unimplementedFunc), + /* 126 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 127 */ SyscallDesc("create_module", unimplementedFunc), + /* 128 */ SyscallDesc("init_module", unimplementedFunc), + /* 129 */ SyscallDesc("delete_module", unimplementedFunc), + /* 130 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 131 */ SyscallDesc("quotactl", unimplementedFunc), + /* 132 */ SyscallDesc("getpgid", unimplementedFunc), + /* 133 */ SyscallDesc("fchdir", unimplementedFunc), + /* 134 */ SyscallDesc("bdflush", unimplementedFunc), + /* 135 */ SyscallDesc("sysfs", unimplementedFunc), + /* 136 */ SyscallDesc("personality", unimplementedFunc), + /* 137 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 138 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 139 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 140 */ SyscallDesc("_llseek", unimplementedFunc), + /* 141 */ SyscallDesc("getdents", unimplementedFunc), + /* 142 */ SyscallDesc("_newselect", unimplementedFunc), + /* 143 */ SyscallDesc("flock", unimplementedFunc), + /* 144 */ SyscallDesc("msync", unimplementedFunc), + /* 145 */ SyscallDesc("readv", unimplementedFunc), + /* 146 */ SyscallDesc("writev", writevFunc<X86Linux32>), + /* 147 */ SyscallDesc("getsid", unimplementedFunc), + /* 148 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 149 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 150 */ SyscallDesc("mlock", unimplementedFunc), + /* 151 */ SyscallDesc("munlock", unimplementedFunc), + /* 152 */ SyscallDesc("mlockall", unimplementedFunc), + /* 153 */ SyscallDesc("munlockall", unimplementedFunc), + /* 154 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 155 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 156 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 157 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 158 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 159 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 160 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 161 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 162 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 163 */ SyscallDesc("mremap", unimplementedFunc), + /* 164 */ SyscallDesc("setresuid", unimplementedFunc), + /* 165 */ SyscallDesc("getresuid", unimplementedFunc), + /* 166 */ SyscallDesc("vm86", unimplementedFunc), + /* 167 */ SyscallDesc("query_module", unimplementedFunc), + /* 168 */ SyscallDesc("poll", unimplementedFunc), + /* 169 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 170 */ SyscallDesc("setresgid", unimplementedFunc), + /* 171 */ SyscallDesc("getresgid", unimplementedFunc), + /* 172 */ SyscallDesc("prctl", unimplementedFunc), + /* 173 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 174 */ SyscallDesc("rt_sigaction", unimplementedFunc), + /* 175 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), + /* 176 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 177 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 178 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), + /* 179 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 180 */ SyscallDesc("pread64", unimplementedFunc), + /* 181 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 182 */ SyscallDesc("chown", unimplementedFunc), + /* 183 */ SyscallDesc("getcwd", unimplementedFunc), + /* 184 */ SyscallDesc("capget", unimplementedFunc), + /* 185 */ SyscallDesc("capset", unimplementedFunc), + /* 186 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 187 */ SyscallDesc("sendfile", unimplementedFunc), + /* 188 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 189 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 190 */ SyscallDesc("vfork", unimplementedFunc), + /* 191 */ SyscallDesc("ugetrlimit", unimplementedFunc), + /* 192 */ SyscallDesc("mmap2", mmapFunc<X86Linux32>), + /* 193 */ SyscallDesc("truncate64", unimplementedFunc), + /* 194 */ SyscallDesc("ftruncate64", unimplementedFunc), + /* 195 */ SyscallDesc("stat64", unimplementedFunc), + /* 196 */ SyscallDesc("lstat64", unimplementedFunc), + /* 197 */ SyscallDesc("fstat64", fstat64Func<X86Linux32>), + /* 198 */ SyscallDesc("lchown32", unimplementedFunc), + /* 199 */ SyscallDesc("getuid32", unimplementedFunc), + /* 200 */ SyscallDesc("getgid32", unimplementedFunc), + /* 201 */ SyscallDesc("geteuid32", unimplementedFunc), + /* 202 */ SyscallDesc("getegid32", unimplementedFunc), + /* 203 */ SyscallDesc("setreuid32", unimplementedFunc), + /* 204 */ SyscallDesc("setregid32", unimplementedFunc), + /* 205 */ SyscallDesc("getgroups32", unimplementedFunc), + /* 206 */ SyscallDesc("setgroups32", unimplementedFunc), + /* 207 */ SyscallDesc("fchown32", unimplementedFunc), + /* 208 */ SyscallDesc("setresuid32", unimplementedFunc), + /* 209 */ SyscallDesc("getresuid32", unimplementedFunc), + /* 210 */ SyscallDesc("setresgid32", unimplementedFunc), + /* 211 */ SyscallDesc("getresgid32", unimplementedFunc), + /* 212 */ SyscallDesc("chown32", unimplementedFunc), + /* 213 */ SyscallDesc("setuid32", unimplementedFunc), + /* 214 */ SyscallDesc("setgid32", unimplementedFunc), + /* 215 */ SyscallDesc("setfsuid32", unimplementedFunc), + /* 216 */ SyscallDesc("setfsgid32", unimplementedFunc), + /* 217 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 218 */ SyscallDesc("mincore", unimplementedFunc), + /* 219 */ SyscallDesc("madvise", unimplementedFunc), + /* 220 */ SyscallDesc("madvise1", unimplementedFunc), + /* 221 */ SyscallDesc("getdents64", unimplementedFunc), + /* 222 */ SyscallDesc("fcntl64", unimplementedFunc), + /* 223 */ SyscallDesc("unused", unimplementedFunc), + /* 224 */ SyscallDesc("gettid", unimplementedFunc), + /* 225 */ SyscallDesc("readahead", unimplementedFunc), + /* 226 */ SyscallDesc("setxattr", unimplementedFunc), + /* 227 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 228 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 229 */ SyscallDesc("getxattr", unimplementedFunc), + /* 230 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 231 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 232 */ SyscallDesc("listxattr", unimplementedFunc), + /* 233 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 234 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 235 */ SyscallDesc("removexattr", unimplementedFunc), + /* 236 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 237 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 238 */ SyscallDesc("tkill", unimplementedFunc), + /* 239 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 240 */ SyscallDesc("futex", unimplementedFunc), + /* 241 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 242 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 243 */ SyscallDesc("set_thread_area", setThreadArea32Func), + /* 244 */ SyscallDesc("get_thread_area", unimplementedFunc), + /* 245 */ SyscallDesc("io_setup", unimplementedFunc), + /* 246 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 247 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 248 */ SyscallDesc("io_submit", unimplementedFunc), + /* 249 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 250 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 251 */ SyscallDesc("unused", unimplementedFunc), + /* 252 */ SyscallDesc("exit_group", exitFunc), + /* 253 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 254 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 255 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 256 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 257 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 258 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 259 */ SyscallDesc("timer_create", unimplementedFunc), + /* 260 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 261 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 262 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 263 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 264 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 265 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 266 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 267 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 268 */ SyscallDesc("statfs64", unimplementedFunc), + /* 269 */ SyscallDesc("fstatfs64", unimplementedFunc), + /* 270 */ SyscallDesc("tgkill", unimplementedFunc), + /* 271 */ SyscallDesc("utimes", unimplementedFunc), + /* 272 */ SyscallDesc("fadvise64_64", unimplementedFunc), + /* 273 */ SyscallDesc("vserver", unimplementedFunc), + /* 274 */ SyscallDesc("mbind", unimplementedFunc), + /* 275 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 276 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 277 */ SyscallDesc("mq_open", unimplementedFunc), + /* 278 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 279 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 280 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 281 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 282 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 283 */ SyscallDesc("kexec_load", unimplementedFunc), + /* 284 */ SyscallDesc("waitid", unimplementedFunc), + /* 285 */ SyscallDesc("sys_setaltroot", unimplementedFunc), + /* 286 */ SyscallDesc("add_key", unimplementedFunc), + /* 287 */ SyscallDesc("request_key", unimplementedFunc), + /* 288 */ SyscallDesc("keyctl", unimplementedFunc), + /* 289 */ SyscallDesc("ioprio_set", unimplementedFunc), + /* 290 */ SyscallDesc("ioprio_get", unimplementedFunc), + /* 291 */ SyscallDesc("inotify_init", unimplementedFunc), + /* 292 */ SyscallDesc("inotify_add_watch", unimplementedFunc), + /* 293 */ SyscallDesc("inotify_rm_watch", unimplementedFunc), + /* 294 */ SyscallDesc("migrate_pages", unimplementedFunc), + /* 295 */ SyscallDesc("openat", unimplementedFunc), + /* 296 */ SyscallDesc("mkdirat", unimplementedFunc), + /* 297 */ SyscallDesc("mknodat", unimplementedFunc), + /* 298 */ SyscallDesc("fchownat", unimplementedFunc), + /* 299 */ SyscallDesc("futimesat", unimplementedFunc), + /* 300 */ SyscallDesc("fstatat64", unimplementedFunc), + /* 301 */ SyscallDesc("unlinkat", unimplementedFunc), + /* 302 */ SyscallDesc("renameat", unimplementedFunc), + /* 303 */ SyscallDesc("linkat", unimplementedFunc), + /* 304 */ SyscallDesc("symlinkat", unimplementedFunc), + /* 305 */ SyscallDesc("readlinkat", unimplementedFunc), + /* 306 */ SyscallDesc("fchmodat", unimplementedFunc), + /* 307 */ SyscallDesc("faccessat", unimplementedFunc), + /* 308 */ SyscallDesc("pselect6", unimplementedFunc), + /* 309 */ SyscallDesc("ppoll", unimplementedFunc), + /* 310 */ SyscallDesc("unshare", unimplementedFunc), + /* 311 */ SyscallDesc("set_robust_list", unimplementedFunc), + /* 312 */ SyscallDesc("get_robust_list", unimplementedFunc), + /* 313 */ SyscallDesc("splice", unimplementedFunc), + /* 314 */ SyscallDesc("sync_file_range", unimplementedFunc), + /* 315 */ SyscallDesc("tee", unimplementedFunc), + /* 316 */ SyscallDesc("vmsplice", unimplementedFunc), + /* 317 */ SyscallDesc("move_pages", unimplementedFunc), + /* 318 */ SyscallDesc("getcpu", unimplementedFunc), + /* 319 */ SyscallDesc("epoll_pwait", unimplementedFunc), + /* 320 */ SyscallDesc("utimensat", unimplementedFunc), + /* 321 */ SyscallDesc("signalfd", unimplementedFunc), + /* 322 */ SyscallDesc("timerfd", unimplementedFunc), + /* 323 */ SyscallDesc("eventfd", unimplementedFunc) +}; diff --git a/src/arch/x86/linux/system.cc b/src/arch/x86/linux/system.cc index 944bb2930..c2d9cb35c 100644 --- a/src/arch/x86/linux/system.cc +++ b/src/arch/x86/linux/system.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -68,7 +68,7 @@ using namespace LittleEndianGuest; using namespace X86ISA; LinuxX86System::LinuxX86System(Params *p) - : X86System(p), commandLine(p->boot_osflags) + : X86System(p), commandLine(p->boot_osflags), e820Table(p->e820_table) { } @@ -144,62 +144,7 @@ LinuxX86System::startup() // A pointer to the buffer for E820 entries. const Addr e820MapPointer = realModeData + 0x2d0; - struct e820Entry - { - Addr addr; - Addr size; - uint32_t type; - }; - - // The size is computed this way to ensure no padding sneaks in. - int e820EntrySize = - sizeof(e820Entry().addr) + - sizeof(e820Entry().size) + - sizeof(e820Entry().type); - - // I'm not sure what these should actually be. On a real machine they - // would be generated by the BIOS, and they need to reflect the regions - // which are actually available/reserved. These values are copied from - // my development machine. - e820Entry e820Map[] = { - {ULL(0x0), ULL(0x9d400), 1}, - {ULL(0x9d400), ULL(0xa0000) - ULL(0x9d400), 2}, - {ULL(0xe8000), ULL(0x100000) - ULL(0xe8000), 2}, - {ULL(0x100000), ULL(0xcfff9300) - ULL(0x100000), 1}, - {ULL(0xcfff9300), ULL(0xd0000000) - ULL(0xcfff9300), 2}, - {ULL(0xfec00000), ULL(0x100000000) - ULL(0xfec00000), 2} - }; - - uint8_t e820Nr = sizeof(e820Map) / sizeof(e820Entry); - - // Make sure the number of entries isn't bigger than what the kernel - // would be capable of providing. - assert(e820Nr <= 128); - - uint8_t guestE820Nr = X86ISA::htog(e820Nr); - physPort->writeBlob(e820MapNrPointer, - (uint8_t *)&guestE820Nr, sizeof(guestE820Nr)); - - for (int i = 0; i < e820Nr; i++) { - e820Entry guestE820Entry; - guestE820Entry.addr = X86ISA::htog(e820Map[i].addr); - guestE820Entry.size = X86ISA::htog(e820Map[i].size); - guestE820Entry.type = X86ISA::htog(e820Map[i].type); - physPort->writeBlob(e820MapPointer + e820EntrySize * i, - (uint8_t *)&guestE820Entry.addr, - sizeof(guestE820Entry.addr)); - physPort->writeBlob( - e820MapPointer + e820EntrySize * i + - sizeof(guestE820Entry.addr), - (uint8_t *)&guestE820Entry.size, - sizeof(guestE820Entry.size)); - physPort->writeBlob( - e820MapPointer + e820EntrySize * i + - sizeof(guestE820Entry.addr) + - sizeof(guestE820Entry.size), - (uint8_t *)&guestE820Entry.type, - sizeof(guestE820Entry.type)); - } + e820Table->writeTo(physPort, e820MapNrPointer, e820MapPointer); /* * Pass the location of the real mode data structure to the kernel diff --git a/src/arch/x86/linux/system.hh b/src/arch/x86/linux/system.hh index fc725ad45..a9c5f4ca9 100644 --- a/src/arch/x86/linux/system.hh +++ b/src/arch/x86/linux/system.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -62,12 +62,14 @@ #include <vector> #include "params/LinuxX86System.hh" +#include "arch/x86/bios/e820.hh" #include "arch/x86/system.hh" class LinuxX86System : public X86System { protected: std::string commandLine; + X86ISA::E820Table * e820Table; public: typedef LinuxX86SystemParams Params; diff --git a/src/arch/x86/microcode_rom.hh b/src/arch/x86/microcode_rom.hh new file mode 100644 index 000000000..f8ad410ce --- /dev/null +++ b/src/arch/x86/microcode_rom.hh @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_MICROCODE_ROM_HH__ +#define __ARCH_X86_MICROCODE_ROM_HH__ + +#include "arch/x86/emulenv.hh" +#include "cpu/static_inst.hh" + +namespace X86ISAInst +{ + class MicrocodeRom + { + protected: + + typedef StaticInstPtr (*GenFunc)(StaticInstPtr); + + static const MicroPC numMicroops; + + GenFunc * genFuncs; + + public: + //Constructor. + MicrocodeRom(); + + //Destructor. + ~MicrocodeRom() + { + delete [] genFuncs; + } + + StaticInstPtr + fetchMicroop(MicroPC microPC, StaticInstPtr curMacroop) + { + microPC = normalMicroPC(microPC); + assert(microPC < numMicroops); + return genFuncs[microPC](curMacroop); + } + }; +} + +namespace X86ISA +{ + using X86ISAInst::MicrocodeRom; +} + +#endif // __ARCH_X86_MICROCODE_ROM_HH__ diff --git a/src/arch/x86/miscregfile.cc b/src/arch/x86/miscregfile.cc index 3b4dc3407..0316603e5 100644 --- a/src/arch/x86/miscregfile.cc +++ b/src/arch/x86/miscregfile.cc @@ -87,6 +87,7 @@ #include "arch/x86/miscregfile.hh" #include "arch/x86/tlb.hh" +#include "cpu/base.hh" #include "cpu/thread_context.hh" #include "sim/serialize.hh" @@ -95,19 +96,16 @@ using namespace std; class Checkpoint; -//These functions map register indices to names -string X86ISA::getMiscRegName(RegIndex index) -{ - panic("No misc registers in x86 yet!\n"); -} - void MiscRegFile::clear() { - // Blank everything. 0 might not be an appropriate value for some things. + // Blank everything. 0 might not be an appropriate value for some things, + // but it is for most. memset(regVal, 0, NumMiscRegs * sizeof(MiscReg)); + regVal[MISCREG_DR6] = (mask(8) << 4) | (mask(16) << 16); + regVal[MISCREG_DR7] = 1 << 10; } -MiscReg MiscRegFile::readRegNoEffect(int miscReg) +MiscReg MiscRegFile::readRegNoEffect(MiscRegIndex miscReg) { // Make sure we're not dealing with an illegal control register. // Instructions should filter out these indexes, and nothing else should @@ -121,90 +119,15 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg) return regVal[miscReg]; } -MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc) +MiscReg MiscRegFile::readReg(MiscRegIndex miscReg, ThreadContext * tc) { - if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) { - if (miscReg >= MISCREG_APIC_IN_SERVICE(0) && - miscReg <= MISCREG_APIC_IN_SERVICE(15)) { - panic("Local APIC In-Service registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) && - miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) { - panic("Local APIC Trigger Mode registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) && - miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) { - panic("Local APIC Interrupt Request registers " - "are unimplemented.\n"); - } - switch (miscReg) { - case MISCREG_APIC_TASK_PRIORITY: - panic("Local APIC Task Priority register unimplemented.\n"); - break; - case MISCREG_APIC_ARBITRATION_PRIORITY: - panic("Local APIC Arbitration Priority register unimplemented.\n"); - break; - case MISCREG_APIC_PROCESSOR_PRIORITY: - panic("Local APIC Processor Priority register unimplemented.\n"); - break; - case MISCREG_APIC_EOI: - panic("Local APIC EOI register unimplemented.\n"); - break; - case MISCREG_APIC_LOGICAL_DESTINATION: - panic("Local APIC Logical Destination register unimplemented.\n"); - break; - case MISCREG_APIC_DESTINATION_FORMAT: - panic("Local APIC Destination Format register unimplemented.\n"); - break; - case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR: - panic("Local APIC Spurious Interrupt Vector" - " register unimplemented.\n"); - break; - case MISCREG_APIC_ERROR_STATUS: - panic("Local APIC Error Status register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_LOW: - panic("Local APIC Interrupt Command low" - " register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_HIGH: - panic("Local APIC Interrupt Command high" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_TIMER: - panic("Local APIC LVT Timer register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_THERMAL_SENSOR: - panic("Local APIC LVT Thermal Sensor register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: - panic("Local APIC LVT Performance Monitoring Counters" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT0: - panic("Local APIC LVT LINT0 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT1: - panic("Local APIC LVT LINT1 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_ERROR: - panic("Local APIC LVT Error register unimplemented.\n"); - break; - case MISCREG_APIC_INITIAL_COUNT: - panic("Local APIC Initial Count register unimplemented.\n"); - break; - case MISCREG_APIC_CURRENT_COUNT: - panic("Local APIC Current Count register unimplemented.\n"); - break; - case MISCREG_APIC_DIVIDE_COUNT: - panic("Local APIC Divide Count register unimplemented.\n"); - break; - } + if (miscReg == MISCREG_TSC) { + return regVal[MISCREG_TSC] + tc->getCpuPtr()->curCycle(); } return readRegNoEffect(miscReg); } -void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val) +void MiscRegFile::setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val) { // Make sure we're not dealing with an illegal control register. // Instructions should filter out these indexes, and nothing else should @@ -217,96 +140,10 @@ void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val) regVal[miscReg] = val; } -void MiscRegFile::setReg(int miscReg, +void MiscRegFile::setReg(MiscRegIndex miscReg, const MiscReg &val, ThreadContext * tc) { MiscReg newVal = val; - if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) { - if (miscReg >= MISCREG_APIC_IN_SERVICE(0) && - miscReg <= MISCREG_APIC_IN_SERVICE(15)) { - panic("Local APIC In-Service registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) && - miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) { - panic("Local APIC Trigger Mode registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) && - miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) { - panic("Local APIC Interrupt Request registers " - "are unimplemented.\n"); - } - switch (miscReg) { - case MISCREG_APIC_ID: - panic("Local APIC ID register unimplemented.\n"); - break; - case MISCREG_APIC_VERSION: - panic("Local APIC Version register is read only.\n"); - break; - case MISCREG_APIC_TASK_PRIORITY: - panic("Local APIC Task Priority register unimplemented.\n"); - break; - case MISCREG_APIC_ARBITRATION_PRIORITY: - panic("Local APIC Arbitration Priority register unimplemented.\n"); - break; - case MISCREG_APIC_PROCESSOR_PRIORITY: - panic("Local APIC Processor Priority register unimplemented.\n"); - break; - case MISCREG_APIC_EOI: - panic("Local APIC EOI register unimplemented.\n"); - break; - case MISCREG_APIC_LOGICAL_DESTINATION: - panic("Local APIC Logical Destination register unimplemented.\n"); - break; - case MISCREG_APIC_DESTINATION_FORMAT: - panic("Local APIC Destination Format register unimplemented.\n"); - break; - case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR: - panic("Local APIC Spurious Interrupt Vector" - " register unimplemented.\n"); - break; - case MISCREG_APIC_ERROR_STATUS: - panic("Local APIC Error Status register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_LOW: - panic("Local APIC Interrupt Command low" - " register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_HIGH: - panic("Local APIC Interrupt Command high" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_TIMER: - panic("Local APIC LVT Timer register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_THERMAL_SENSOR: - panic("Local APIC LVT Thermal Sensor register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: - panic("Local APIC LVT Performance Monitoring Counters" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT0: - panic("Local APIC LVT LINT0 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT1: - panic("Local APIC LVT LINT1 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_ERROR: - panic("Local APIC LVT Error register unimplemented.\n"); - break; - case MISCREG_APIC_INITIAL_COUNT: - panic("Local APIC Initial Count register unimplemented.\n"); - break; - case MISCREG_APIC_CURRENT_COUNT: - panic("Local APIC Current Count register unimplemented.\n"); - break; - case MISCREG_APIC_DIVIDE_COUNT: - panic("Local APIC Divide Count register unimplemented.\n"); - break; - } - setRegNoEffect(miscReg, newVal); - return; - } switch(miscReg) { case MISCREG_CR0: @@ -314,17 +151,39 @@ void MiscRegFile::setReg(int miscReg, CR0 toggled = regVal[miscReg] ^ val; CR0 newCR0 = val; Efer efer = regVal[MISCREG_EFER]; + HandyM5Reg m5reg = regVal[MISCREG_M5_REG]; if (toggled.pg && efer.lme) { if (newCR0.pg) { //Turning on long mode efer.lma = 1; + m5reg.mode = LongMode; regVal[MISCREG_EFER] = efer; } else { //Turning off long mode efer.lma = 0; + m5reg.mode = LegacyMode; regVal[MISCREG_EFER] = efer; } } + // Figure out what submode we're in. + if (m5reg.mode == LongMode) { + SegAttr csAttr = regVal[MISCREG_CS_ATTR]; + if (csAttr.longMode) + m5reg.submode = SixtyFourBitMode; + else + m5reg.submode = CompatabilityMode; + } else { + if (newCR0.pe) { + RFLAGS rflags = regVal[MISCREG_RFLAGS]; + if (rflags.vm) + m5reg.submode = Virtual8086Mode; + else + m5reg.submode = ProtectedMode; + } else { + m5reg.submode = RealMode; + } + } + regVal[MISCREG_M5_REG] = m5reg; if (toggled.pg) { tc->getITBPtr()->invalidateAll(); tc->getDTBPtr()->invalidateAll(); @@ -355,20 +214,26 @@ void MiscRegFile::setReg(int miscReg, { SegAttr toggled = regVal[miscReg] ^ val; SegAttr newCSAttr = val; + HandyM5Reg m5reg = regVal[MISCREG_M5_REG]; if (toggled.longMode) { - SegAttr newCSAttr = val; if (newCSAttr.longMode) { + if (m5reg.mode == LongMode) + m5reg.submode = SixtyFourBitMode; regVal[MISCREG_ES_EFF_BASE] = 0; regVal[MISCREG_CS_EFF_BASE] = 0; regVal[MISCREG_SS_EFF_BASE] = 0; regVal[MISCREG_DS_EFF_BASE] = 0; } else { + if (m5reg.mode == LongMode) + m5reg.submode = CompatabilityMode; regVal[MISCREG_ES_EFF_BASE] = regVal[MISCREG_ES_BASE]; regVal[MISCREG_CS_EFF_BASE] = regVal[MISCREG_CS_BASE]; regVal[MISCREG_SS_EFF_BASE] = regVal[MISCREG_SS_BASE]; regVal[MISCREG_DS_EFF_BASE] = regVal[MISCREG_DS_BASE]; } } + m5reg.cpl = newCSAttr.dpl; + regVal[MISCREG_M5_REG] = m5reg; } break; // These segments always actually use their bases, or in other words @@ -396,6 +261,80 @@ void MiscRegFile::setReg(int miscReg, MISCREG_SEG_BASE_BASE)] = val; } break; + case MISCREG_TSC: + regVal[MISCREG_TSC] = val - tc->getCpuPtr()->curCycle(); + return; + case MISCREG_DR0: + case MISCREG_DR1: + case MISCREG_DR2: + case MISCREG_DR3: + /* These should eventually set up breakpoints. */ + break; + case MISCREG_DR4: + miscReg = MISCREG_DR6; + /* Fall through to have the same effects as DR6. */ + case MISCREG_DR6: + { + DR6 dr6 = regVal[MISCREG_DR6]; + DR6 newDR6 = val; + dr6.b0 = newDR6.b0; + dr6.b1 = newDR6.b1; + dr6.b2 = newDR6.b2; + dr6.b3 = newDR6.b3; + dr6.bd = newDR6.bd; + dr6.bs = newDR6.bs; + dr6.bt = newDR6.bt; + newVal = dr6; + } + break; + case MISCREG_DR5: + miscReg = MISCREG_DR7; + /* Fall through to have the same effects as DR7. */ + case MISCREG_DR7: + { + DR7 dr7 = regVal[MISCREG_DR7]; + DR7 newDR7 = val; + dr7.l0 = newDR7.l0; + dr7.g0 = newDR7.g0; + if (dr7.l0 || dr7.g0) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 0. */ + } + dr7.l1 = newDR7.l1; + dr7.g1 = newDR7.g1; + if (dr7.l1 || dr7.g1) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 1. */ + } + dr7.l2 = newDR7.l2; + dr7.g2 = newDR7.g2; + if (dr7.l2 || dr7.g2) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 2. */ + } + dr7.l3 = newDR7.l3; + dr7.g3 = newDR7.g3; + if (dr7.l3 || dr7.g3) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 3. */ + } + dr7.gd = newDR7.gd; + dr7.rw0 = newDR7.rw0; + dr7.len0 = newDR7.len0; + dr7.rw1 = newDR7.rw1; + dr7.len1 = newDR7.len1; + dr7.rw2 = newDR7.rw2; + dr7.len2 = newDR7.len2; + dr7.rw3 = newDR7.rw3; + dr7.len3 = newDR7.len3; + } + break; + default: + break; } setRegNoEffect(miscReg, newVal); } diff --git a/src/arch/x86/miscregfile.hh b/src/arch/x86/miscregfile.hh index e095e06e9..6d3ae4e92 100644 --- a/src/arch/x86/miscregfile.hh +++ b/src/arch/x86/miscregfile.hh @@ -29,7 +29,7 @@ */ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -91,6 +91,7 @@ #include "arch/x86/faults.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/types.hh" +#include "sim/host.hh" #include <string> @@ -98,8 +99,6 @@ class Checkpoint; namespace X86ISA { - std::string getMiscRegName(RegIndex); - //These will have to be updated in the future. const int NumMiscArchRegs = NUM_MISCREGS; const int NumMiscRegs = NUM_MISCREGS; @@ -117,13 +116,13 @@ namespace X86ISA clear(); } - MiscReg readRegNoEffect(int miscReg); + MiscReg readRegNoEffect(MiscRegIndex miscReg); - MiscReg readReg(int miscReg, ThreadContext *tc); + MiscReg readReg(MiscRegIndex miscReg, ThreadContext *tc); - void setRegNoEffect(int miscReg, const MiscReg &val); + void setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val); - void setReg(int miscReg, + void setReg(MiscRegIndex miscReg, const MiscReg &val, ThreadContext *tc); void serialize(std::ostream & os); diff --git a/src/arch/x86/miscregs.hh b/src/arch/x86/miscregs.hh index d1016d2a9..af02e9422 100644 --- a/src/arch/x86/miscregs.hh +++ b/src/arch/x86/miscregs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -82,6 +82,18 @@ namespace X86ISA OFBit = 1 << 11 }; + enum RFLAGBit { + TFBit = 1 << 8, + IFBit = 1 << 9, + NTBit = 1 << 14, + RFBit = 1 << 16, + VMBit = 1 << 17, + ACBit = 1 << 18, + VIFBit = 1 << 19, + VIPBit = 1 << 20, + IDBit = 1 << 21 + }; + enum MiscRegIndex { // Control registers @@ -118,6 +130,9 @@ namespace X86ISA // Flags register MISCREG_RFLAGS = MISCREG_DR_BASE + NumDRegs, + //Register to keep handy values like the CPU mode in. + MISCREG_M5_REG, + /* * Model Specific Registers */ @@ -183,6 +198,9 @@ namespace X86ISA MISCREG_MC2_CTL, MISCREG_MC3_CTL, MISCREG_MC4_CTL, + MISCREG_MC5_CTL, + MISCREG_MC6_CTL, + MISCREG_MC7_CTL, MISCREG_MC_STATUS_BASE, MISCREG_MC0_STATUS = MISCREG_MC_STATUS_BASE, @@ -190,6 +208,9 @@ namespace X86ISA MISCREG_MC2_STATUS, MISCREG_MC3_STATUS, MISCREG_MC4_STATUS, + MISCREG_MC5_STATUS, + MISCREG_MC6_STATUS, + MISCREG_MC7_STATUS, MISCREG_MC_ADDR_BASE, MISCREG_MC0_ADDR = MISCREG_MC_ADDR_BASE, @@ -197,6 +218,9 @@ namespace X86ISA MISCREG_MC2_ADDR, MISCREG_MC3_ADDR, MISCREG_MC4_ADDR, + MISCREG_MC5_ADDR, + MISCREG_MC6_ADDR, + MISCREG_MC7_ADDR, MISCREG_MC_MISC_BASE, MISCREG_MC0_MISC = MISCREG_MC_MISC_BASE, @@ -204,6 +228,9 @@ namespace X86ISA MISCREG_MC2_MISC, MISCREG_MC3_MISC, MISCREG_MC4_MISC, + MISCREG_MC5_MISC, + MISCREG_MC6_MISC, + MISCREG_MC7_MISC, // Extended feature enable register MISCREG_EFER, @@ -341,38 +368,6 @@ namespace X86ISA MISCREG_APIC_BASE, - MISCREG_APIC_START, - MISCREG_APIC_ID = MISCREG_APIC_START, - MISCREG_APIC_VERSION, - MISCREG_APIC_TASK_PRIORITY, - MISCREG_APIC_ARBITRATION_PRIORITY, - MISCREG_APIC_PROCESSOR_PRIORITY, - MISCREG_APIC_EOI, - MISCREG_APIC_LOGICAL_DESTINATION, - MISCREG_APIC_DESTINATION_FORMAT, - MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR, - - MISCREG_APIC_IN_SERVICE_BASE, - - MISCREG_APIC_TRIGGER_MODE_BASE = MISCREG_APIC_IN_SERVICE_BASE + 16, - - MISCREG_APIC_INTERRUPT_REQUEST_BASE = - MISCREG_APIC_TRIGGER_MODE_BASE + 16, - - MISCREG_APIC_ERROR_STATUS = MISCREG_APIC_INTERRUPT_REQUEST_BASE + 16, - MISCREG_APIC_INTERRUPT_COMMAND_LOW, - MISCREG_APIC_INTERRUPT_COMMAND_HIGH, - MISCREG_APIC_LVT_TIMER, - MISCREG_APIC_LVT_THERMAL_SENSOR, - MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS, - MISCREG_APIC_LVT_LINT0, - MISCREG_APIC_LVT_LINT1, - MISCREG_APIC_LVT_ERROR, - MISCREG_APIC_INITIAL_COUNT, - MISCREG_APIC_CURRENT_COUNT, - MISCREG_APIC_DIVIDE_COUNT, - MISCREG_APIC_END = MISCREG_APIC_DIVIDE_COUNT, - // "Fake" MSRs for internally implemented devices MISCREG_PCI_CONFIG_ADDRESS, @@ -481,24 +476,6 @@ namespace X86ISA return (MiscRegIndex)(MISCREG_SEG_ATTR_BASE + index); } - static inline MiscRegIndex - MISCREG_APIC_IN_SERVICE(int index) - { - return (MiscRegIndex)(MISCREG_APIC_IN_SERVICE_BASE + index); - } - - static inline MiscRegIndex - MISCREG_APIC_TRIGGER_MODE(int index) - { - return (MiscRegIndex)(MISCREG_APIC_TRIGGER_MODE_BASE + index); - } - - static inline MiscRegIndex - MISCREG_APIC_INTERRUPT_REQUEST(int index) - { - return (MiscRegIndex)(MISCREG_APIC_INTERRUPT_REQUEST_BASE + index); - } - /** * A type to describe the condition code bits of the RFLAGS register, * plus two flags, EZF and ECF, which are only visible to microcode. @@ -537,6 +514,12 @@ namespace X86ISA Bitfield<0> cf; // Carry Flag EndBitUnion(RFLAGS) + BitUnion64(HandyM5Reg) + Bitfield<0> mode; + Bitfield<3, 1> submode; + Bitfield<5, 4> cpl; + EndBitUnion(HandyM5Reg) + /** * Control registers */ @@ -589,6 +572,38 @@ namespace X86ISA Bitfield<3, 0> tpr; // Task Priority Register EndBitUnion(CR8) + BitUnion64(DR6) + Bitfield<0> b0; + Bitfield<1> b1; + Bitfield<2> b2; + Bitfield<3> b3; + Bitfield<13> bd; + Bitfield<14> bs; + Bitfield<15> bt; + EndBitUnion(DR6) + + BitUnion64(DR7) + Bitfield<0> l0; + Bitfield<1> g0; + Bitfield<2> l1; + Bitfield<3> g1; + Bitfield<4> l2; + Bitfield<5> g2; + Bitfield<6> l3; + Bitfield<7> g3; + Bitfield<8> le; + Bitfield<9> ge; + Bitfield<13> gd; + Bitfield<17, 16> rw0; + Bitfield<19, 18> len0; + Bitfield<21, 20> rw1; + Bitfield<23, 22> len1; + Bitfield<25, 24> rw2; + Bitfield<27, 26> len2; + Bitfield<29, 28> rw3; + Bitfield<31, 30> len3; + EndBitUnion(DR7) + // MTRR capabilities BitUnion64(MTRRcap) Bitfield<7, 0> vcnt; // Variable-Range Register Count diff --git a/src/arch/x86/mmaped_ipr.hh b/src/arch/x86/mmaped_ipr.hh index eda85c084..7056c0902 100644 --- a/src/arch/x86/mmaped_ipr.hh +++ b/src/arch/x86/mmaped_ipr.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -78,15 +78,12 @@ namespace X86ISA #if !FULL_SYSTEM panic("Shouldn't have a memory mapped register in SE\n"); #else + Addr offset = pkt->getAddr() & mask(3); MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg)); - if (index == MISCREG_PCI_CONFIG_ADDRESS || - (index >= MISCREG_APIC_START && - index <= MISCREG_APIC_END)) { - pkt->set((uint32_t)(xc->readMiscReg(pkt->getAddr() / - sizeof(MiscReg)))); - } else { - pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg))); - } + MiscReg data = htog(xc->readMiscReg(index)); + // Make sure we don't trot off the end of data. + assert(offset + pkt->getSize() <= sizeof(MiscReg)); + pkt->setData(((uint8_t *)&data) + offset); #endif return xc->getCpuPtr()->ticks(1); } @@ -97,15 +94,14 @@ namespace X86ISA #if !FULL_SYSTEM panic("Shouldn't have a memory mapped register in SE\n"); #else + Addr offset = pkt->getAddr() & mask(3); MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg)); - if (index == MISCREG_PCI_CONFIG_ADDRESS || - (index >= MISCREG_APIC_START && - index <= MISCREG_APIC_END)) { - xc->setMiscReg(index, gtoh(pkt->get<uint32_t>())); - } else { - xc->setMiscReg(pkt->getAddr() / sizeof(MiscReg), - gtoh(pkt->get<uint64_t>())); - } + MiscReg data; + data = htog(xc->readMiscRegNoEffect(index)); + // Make sure we don't trot off the end of data. + assert(offset + pkt->getSize() <= sizeof(MiscReg)); + pkt->writeData(((uint8_t *)&data) + offset); + xc->setMiscReg(index, gtoh(data)); #endif return xc->getCpuPtr()->ticks(1); } diff --git a/src/arch/x86/pagetable.hh b/src/arch/x86/pagetable.hh index e42693c03..1a7a945e4 100644 --- a/src/arch/x86/pagetable.hh +++ b/src/arch/x86/pagetable.hh @@ -113,6 +113,12 @@ namespace X86ISA TlbEntry(Addr asn, Addr _vaddr, Addr _paddr); TlbEntry() {} + void + updateVaddr(Addr new_vaddr) + { + vaddr = new_vaddr; + } + Addr pageStart() { return paddr; diff --git a/src/arch/x86/pagetable_walker.cc b/src/arch/x86/pagetable_walker.cc index e70c16b1d..f625cf4bd 100644 --- a/src/arch/x86/pagetable_walker.cc +++ b/src/arch/x86/pagetable_walker.cc @@ -84,8 +84,8 @@ BitUnion64(PageTableEntry) Bitfield<0> p; EndBitUnion(PageTableEntry) -void -Walker::doNext(PacketPtr &read, PacketPtr &write) +Fault +Walker::doNext(PacketPtr &write) { assert(state != Ready && state != Waiting); write = NULL; @@ -101,39 +101,45 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) bool badNX = pte.nx && (!tlb->allowNX() || !enableNX); switch(state) { case LongPML4: + DPRINTF(PageTableWalker, + "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size; doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (badNX) - panic("NX violation!\n"); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } entry.noExec = pte.nx; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); nextState = LongPDP; break; case LongPDP: + DPRINTF(PageTableWalker, + "Got long mode PDP entry %#016x.\n", (uint64_t)pte); nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size; doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } nextState = LongPD; break; case LongPD: + DPRINTF(PageTableWalker, + "Got long mode PD entry %#016x.\n", (uint64_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } if (!pte.ps) { // 4 KB page entry.size = 4 * (1 << 10); @@ -150,47 +156,49 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; } case LongPTE: + DPRINTF(PageTableWalker, + "Got long mode PTE entry %#016x.\n", (uint64_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } entry.paddr = (uint64_t)pte & (mask(40) << 12); entry.uncacheable = uncacheable; entry.global = pte.g; entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; case PAEPDP: + DPRINTF(PageTableWalker, + "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } nextState = PAEPD; break; case PAEPD: + DPRINTF(PageTableWalker, + "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } if (!pte.ps) { // 4 KB page entry.size = 4 * (1 << 10); @@ -206,39 +214,39 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; } case PAEPTE: + DPRINTF(PageTableWalker, + "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } entry.paddr = (uint64_t)pte & (mask(40) << 12); entry.uncacheable = uncacheable; entry.global = pte.g; entry.patBit = bits(pte, 7); entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; case PSEPD: + DPRINTF(PageTableWalker, + "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } if (!pte.ps) { // 4 KB page entry.size = 4 * (1 << 10); @@ -255,54 +263,51 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; } case PD: + DPRINTF(PageTableWalker, + "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } // 4 KB page entry.size = 4 * (1 << 10); nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; nextState = PTE; break; - nextState = PTE; - break; case PTE: + DPRINTF(PageTableWalker, + "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } entry.paddr = (uint64_t)pte & (mask(20) << 12); entry.uncacheable = uncacheable; entry.global = pte.g; entry.patBit = bits(pte, 7); entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; default: panic("Unknown page table walker state %d!\n"); } PacketPtr oldRead = read; //If we didn't return, we're setting up another read. - uint32_t flags = oldRead->req->getFlags(); - if (uncacheable) - flags |= UNCACHEABLE; - else - flags &= ~UNCACHEABLE; + Request::Flags flags = oldRead->req->getFlags(); + flags.set(Request::UNCACHEABLE, uncacheable); RequestPtr request = new Request(nextRead, oldRead->getSize(), flags); read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); @@ -319,14 +324,20 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) delete oldRead->req; delete oldRead; } + return NoFault; } -void -Walker::start(ThreadContext * _tc, Addr vaddr) +Fault +Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, + RequestPtr _req, bool _write, bool _execute) { assert(state == Ready); - assert(!tc); tc = _tc; + req = _req; + Addr vaddr = req->getVaddr(); + execute = _execute; + write = _write; + translation = _translation; VAddr addr = vaddr; @@ -340,6 +351,7 @@ Walker::start(ThreadContext * _tc, Addr vaddr) // Do long mode. state = LongPML4; top = (cr3.longPdtb << 12) + addr.longl4 * size; + enableNX = efer.nxe; } else { // We're in some flavor of legacy mode. CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); @@ -347,6 +359,7 @@ Walker::start(ThreadContext * _tc, Addr vaddr) // Do legacy PAE. state = PAEPDP; top = (cr3.paePdtb << 5) + addr.pael3 * size; + enableNX = efer.nxe; } else { size = 4; top = (cr3.pdtb << 12) + addr.norml2 * size; @@ -357,38 +370,44 @@ Walker::start(ThreadContext * _tc, Addr vaddr) // Do legacy non PSE. state = PD; } + enableNX = false; } } nextState = Ready; entry.vaddr = vaddr; - enableNX = efer.nxe; - - RequestPtr request = - new Request(top, size, PHYSICAL | cr3.pcd ? UNCACHEABLE : 0); + Request::Flags flags = Request::PHYSICAL; + if (cr3.pcd) + flags.set(Request::UNCACHEABLE); + RequestPtr request = new Request(top, size, flags); read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); read->allocate(); Enums::MemoryMode memMode = sys->getMemoryMode(); if (memMode == Enums::timing) { - tc->suspend(); - port.sendTiming(read); + nextState = state; + state = Waiting; + timingFault = NoFault; + sendPackets(); } else if (memMode == Enums::atomic) { + Fault fault; do { port.sendAtomic(read); PacketPtr write = NULL; - doNext(read, write); + fault = doNext(write); + assert(fault == NoFault || read == NULL); state = nextState; nextState = Ready; if (write) port.sendAtomic(write); } while(read); - tc = NULL; state = Ready; nextState = Waiting; + return fault; } else { panic("Unrecognized memory system mode.\n"); } + return NoFault; } bool @@ -400,18 +419,19 @@ Walker::WalkerPort::recvTiming(PacketPtr pkt) bool Walker::recvTiming(PacketPtr pkt) { - inflight--; if (pkt->isResponse() && !pkt->wasNacked()) { + assert(inflight); + assert(state == Waiting); + assert(!read); + inflight--; if (pkt->isRead()) { - assert(inflight); - assert(state == Waiting); - assert(!read); state = nextState; nextState = Ready; PacketPtr write = NULL; - doNext(pkt, write); - state = Waiting; read = pkt; + timingFault = doNext(write); + state = Waiting; + assert(timingFault == NoFault || read == NULL); if (write) { writes.push_back(write); } @@ -420,14 +440,31 @@ Walker::recvTiming(PacketPtr pkt) sendPackets(); } if (inflight == 0 && read == NULL && writes.size() == 0) { - tc->activate(0); - tc = NULL; state = Ready; nextState = Waiting; + if (timingFault == NoFault) { + /* + * Finish the translation. Now that we now the right entry is + * in the TLB, this should work with no memory accesses. + * There could be new faults unrelated to the table walk like + * permissions violations, so we'll need the return value as + * well. + */ + bool delayedResponse; + Fault fault = tlb->translate(req, tc, NULL, write, execute, + delayedResponse, true); + assert(!delayedResponse); + // Let the CPU continue. + translation->finish(fault, req, tc, write); + } else { + // There was a fault during the walk. Let the CPU know. + translation->finish(timingFault, req, tc, write); + } } } else if (pkt->wasNacked()) { pkt->reinitNacked(); if (!port.sendTiming(pkt)) { + inflight--; retrying = true; if (pkt->isWrite()) { writes.push_back(pkt); @@ -435,8 +472,6 @@ Walker::recvTiming(PacketPtr pkt) assert(!read); read = pkt; } - } else { - inflight++; } } return true; @@ -490,27 +525,26 @@ Walker::sendPackets() //Reads always have priority if (read) { - if (!port.sendTiming(read)) { + PacketPtr pkt = read; + read = NULL; + inflight++; + if (!port.sendTiming(pkt)) { retrying = true; + read = pkt; + inflight--; return; - } else { - inflight++; - delete read->req; - delete read; - read = NULL; } } //Send off as many of the writes as we can. while (writes.size()) { PacketPtr write = writes.back(); + writes.pop_back(); + inflight++; if (!port.sendTiming(write)) { retrying = true; + writes.push_back(write); + inflight--; return; - } else { - inflight++; - delete write->req; - delete write; - writes.pop_back(); } } } @@ -524,6 +558,15 @@ Walker::getPort(const std::string &if_name, int idx) panic("No page table walker port named %s!\n", if_name); } +Fault +Walker::pageFault(bool present) +{ + DPRINTF(PageTableWalker, "Raising page fault.\n"); + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + return new PageFault(entry.vaddr, present, write, + m5reg.cpl == 3, false, execute && enableNX); +} + } X86ISA::Walker * diff --git a/src/arch/x86/pagetable_walker.hh b/src/arch/x86/pagetable_walker.hh index 324f16f3c..f73774a45 100644 --- a/src/arch/x86/pagetable_walker.hh +++ b/src/arch/x86/pagetable_walker.hh @@ -85,17 +85,28 @@ namespace X86ISA PSEPD, PD, PTE }; - // Act on the current state and determine what to do next. read - // should be the packet that just came back from a read and write + // Act on the current state and determine what to do next. The global + // read should be the packet that just came back from a read and write // should be NULL. When the function returns, read is either NULL // if the machine is finished, or points to a packet to initiate // the next read. If any write is required to update an "accessed" // bit, write will point to a packet to do the write. Otherwise it - // will be NULL. - void doNext(PacketPtr &read, PacketPtr &write); + // will be NULL. The return value is whatever fault was incurred + // during this stage of the lookup. + Fault doNext(PacketPtr &write); // Kick off the state machine. - void start(ThreadContext * _tc, Addr vaddr); + Fault start(ThreadContext * _tc, BaseTLB::Translation *translation, + RequestPtr req, bool write, bool execute); + // Clean up after the state machine. + void + stop() + { + nextState = Ready; + delete read->req; + delete read; + read = NULL; + } protected: @@ -111,6 +122,11 @@ namespace X86ISA bool retrying; /* + * The fault, if any, that's waiting to be delivered in timing mode. + */ + Fault timingFault; + + /* * Functions for dealing with packets. */ bool recvTiming(PacketPtr pkt); @@ -156,16 +172,21 @@ namespace X86ISA // The TLB we're supposed to load. TLB * tlb; System * sys; + BaseTLB::Translation * translation; /* * State machine state. */ ThreadContext * tc; + RequestPtr req; State state; State nextState; int size; bool enableNX; + bool write, execute, user; TlbEntry entry; + + Fault pageFault(bool present); public: diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc index 407a09ec0..620ab89ea 100644 --- a/src/arch/x86/predecoder.cc +++ b/src/arch/x86/predecoder.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -55,9 +55,11 @@ * Authors: Gabe Black */ +#include "arch/x86/miscregs.hh" #include "arch/x86/predecoder.hh" #include "base/misc.hh" #include "base/trace.hh" +#include "cpu/thread_context.hh" #include "sim/host.hh" namespace X86ISA @@ -78,7 +80,9 @@ namespace X86ISA emi.modRM = 0; emi.sib = 0; - emi.mode = 0; + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + emi.mode.mode = m5reg.mode; + emi.mode.submode = m5reg.submode; } void Predecoder::process() @@ -132,7 +136,10 @@ namespace X86ISA { uint8_t prefix = Prefixes[nextByte]; State nextState = PrefixState; - if(prefix) + // REX prefixes are only recognized in 64 bit mode. + if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode) + prefix = 0; + if (prefix) consumeByte(); switch(prefix) { @@ -209,10 +216,12 @@ namespace X86ISA DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte); emi.opcode.op = nextByte; + SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR); + //Figure out the effective operand size. This can be overriden to //a fixed value at the decoder level. int logOpSize; - if(/*FIXME long mode*/1) + if (emi.mode.submode == SixtyFourBitMode) { if(emi.rex.w) logOpSize = 3; // 64 bit operand size @@ -221,7 +230,7 @@ namespace X86ISA else logOpSize = 2; // 32 bit operand size } - else if(/*FIXME default 32*/1) + else if(csAttr.defaultSize) { if(emi.legacy.op) logOpSize = 1; // 16 bit operand size @@ -242,14 +251,14 @@ namespace X86ISA //Figure out the effective address size. This can be overriden to //a fixed value at the decoder level. int logAddrSize; - if(/*FIXME 64-bit mode*/1) + if(emi.mode.submode == SixtyFourBitMode) { if(emi.legacy.addr) logAddrSize = 2; // 32 bit address size else logAddrSize = 3; // 64 bit address size } - else if(/*FIXME default 32*/1) + else if(csAttr.defaultSize) { if(emi.legacy.addr) logAddrSize = 1; // 16 bit address size @@ -264,6 +273,16 @@ namespace X86ISA logAddrSize = 1; // 16 bit address size } + SegAttr ssAttr = tc->readMiscRegNoEffect(MISCREG_SS_ATTR); + //Figure out the effective stack width. This can be overriden to + //a fixed value at the decoder level. + if(emi.mode.submode == SixtyFourBitMode) + emi.stackSize = 8; // 64 bit stack width + else if(ssAttr.defaultSize) + emi.stackSize = 4; // 32 bit stack width + else + emi.stackSize = 2; // 16 bit stack width + //Set the actual address size emi.addrSize = 1 << logAddrSize; @@ -299,19 +318,21 @@ namespace X86ISA ModRM modRM; modRM = nextByte; DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte); - if (0) {//FIXME in 16 bit mode + SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR); + if (emi.mode.submode != SixtyFourBitMode && + !csAttr.defaultSize) { //figure out 16 bit displacement size - if(modRM.mod == 0 && modRM.rm == 6 || modRM.mod == 2) + if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2) displacementSize = 2; - else if(modRM.mod == 1) + else if (modRM.mod == 1) displacementSize = 1; else displacementSize = 0; } else { //figure out 32/64 bit displacement size - if(modRM.mod == 0 && modRM.rm == 5 || modRM.mod == 2) + if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2) displacementSize = 4; - else if(modRM.mod == 1) + else if (modRM.mod == 1) displacementSize = 1; else displacementSize = 0; diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh index 6e41e8134..a16ce6fb8 100644 --- a/src/arch/x86/predecoder.hh +++ b/src/arch/x86/predecoder.hh @@ -58,6 +58,8 @@ #ifndef __ARCH_X86_PREDECODER_HH__ #define __ARCH_X86_PREDECODER_HH__ +#include <cassert> + #include "arch/x86/types.hh" #include "base/bitfield.hh" #include "base/misc.hh" diff --git a/src/arch/x86/predecoder_tables.cc b/src/arch/x86/predecoder_tables.cc index a8c719054..5f2b5c421 100644 --- a/src/arch/x86/predecoder_tables.cc +++ b/src/arch/x86/predecoder_tables.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -123,7 +123,7 @@ namespace X86ISA { //LSB // MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F /* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1, -/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, /* 2 */ 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, /* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, /* 4 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, @@ -201,7 +201,7 @@ namespace X86ISA //For two byte instructions { //LSB // MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F -/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 0 */ 0 , 0 , 0 , 0 , WO, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , BY , /* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* 2 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 76f0b5d04..4a61ed168 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -98,56 +98,115 @@ #include "mem/page_table.hh" #include "mem/translating_port.hh" #include "sim/process_impl.hh" +#include "sim/syscall_emul.hh" #include "sim/system.hh" using namespace std; using namespace X86ISA; -M5_64_auxv_t::M5_64_auxv_t(int64_t type, int64_t val) -{ - a_type = TheISA::htog(type); - a_val = TheISA::htog(val); -} - -X86LiveProcess::X86LiveProcess(LiveProcessParams * params, - ObjectFile *objFile) - : LiveProcess(params, objFile) +static const int ReturnValueReg = INTREG_RAX; +static const int ArgumentReg[] = { + INTREG_RDI, + INTREG_RSI, + INTREG_RDX, + //This argument register is r10 for syscalls and rcx for C. + INTREG_R10W, + //INTREG_RCX, + INTREG_R8W, + INTREG_R9W +}; +static const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); +static const int ArgumentReg32[] = { + INTREG_EBX, + INTREG_ECX, + INTREG_EDX, + INTREG_ESI, + INTREG_EDI, +}; +static const int NumArgumentRegs32 = sizeof(ArgumentReg) / sizeof(const int); + +X86LiveProcess::X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs) : + LiveProcess(params, objFile), syscallDescs(_syscallDescs), + numSyscallDescs(_numSyscallDescs) { brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); brk_point = roundUp(brk_point, VMPageSize); +} - // Set pointer for next thread stack. Reserve 8M for main stack. - next_thread_stack_base = stack_base - (8 * 1024 * 1024); - +X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params, + ObjectFile *objFile, SyscallDesc *_syscallDescs, + int _numSyscallDescs) : + X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs) +{ // Set up stack. On X86_64 Linux, stack goes from the top of memory // downward, less the hole for the kernel address space plus one page // for undertermined purposes. stack_base = (Addr)0x7FFFFFFFF000ULL; + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + // Set up region for mmaps. This was determined empirically and may not // always be correct. mmap_start = mmap_end = (Addr)0x2aaaaaaab000ULL; } -void X86LiveProcess::handleTrap(int trapNum, ThreadContext *tc) +void +I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc) { - switch(trapNum) - { - default: - panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum); + Addr eip = tc->readPC(); + if (eip >= vsyscallPage.base && + eip < vsyscallPage.base + vsyscallPage.size) { + tc->setNextPC(vsyscallPage.base + vsyscallPage.vsysexitOffset); } + X86LiveProcess::syscall(callnum, tc); +} + + +I386LiveProcess::I386LiveProcess(LiveProcessParams *params, + ObjectFile *objFile, SyscallDesc *_syscallDescs, + int _numSyscallDescs) : + X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs) +{ + _gdtStart = 0x100000000; + _gdtSize = VMPageSize; + + vsyscallPage.base = 0xffffe000ULL; + vsyscallPage.size = VMPageSize; + vsyscallPage.vsyscallOffset = 0x400; + vsyscallPage.vsysexitOffset = 0x410; + + stack_base = vsyscallPage.base; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + + // Set up region for mmaps. This was determined empirically and may not + // always be correct. + mmap_start = mmap_end = (Addr)0xf7ffd000ULL; +} + +SyscallDesc* +X86LiveProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum >= numSyscallDescs) + return NULL; + return &syscallDescs[callnum]; } void -X86LiveProcess::startup() +X86_64LiveProcess::startup() { + LiveProcess::startup(); + if (checkpointRestored) return; - argsInit(sizeof(IntReg), VMPageSize); + argsInit(sizeof(uint64_t), VMPageSize); - for (int i = 0; i < threadContexts.size(); i++) { - ThreadContext * tc = threadContexts[i]; + for (int i = 0; i < contextIds.size(); i++) { + ThreadContext * tc = system->getThreadContext(contextIds[i]); SegAttr dataAttr = 0; dataAttr.writable = 1; @@ -203,10 +262,122 @@ X86LiveProcess::startup() } void -X86LiveProcess::argsInit(int intSize, int pageSize) +I386LiveProcess::startup() +{ + LiveProcess::startup(); + + if (checkpointRestored) + return; + + argsInit(sizeof(uint32_t), VMPageSize); + + /* + * Set up a GDT for this process. The whole GDT wouldn't really be for + * this process, but the only parts we care about are. + */ + pTable->allocate(_gdtStart, _gdtSize); + uint64_t zero = 0; + assert(_gdtSize % sizeof(zero) == 0); + for (Addr gdtCurrent = _gdtStart; + gdtCurrent < _gdtStart + _gdtSize; gdtCurrent += sizeof(zero)) { + initVirtMem->write(gdtCurrent, zero); + } + + // Set up the vsyscall page for this process. + pTable->allocate(vsyscallPage.base, vsyscallPage.size); + uint8_t vsyscallBlob[] = { + 0x51, // push %ecx + 0x52, // push %edp + 0x55, // push %ebp + 0x89, 0xe5, // mov %esp, %ebp + 0x0f, 0x34 // sysenter + }; + initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsyscallOffset, + vsyscallBlob, sizeof(vsyscallBlob)); + + uint8_t vsysexitBlob[] = { + 0x5d, // pop %ebp + 0x5a, // pop %edx + 0x59, // pop %ecx + 0xc3 // ret + }; + initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsysexitOffset, + vsysexitBlob, sizeof(vsysexitBlob)); + + for (int i = 0; i < contextIds.size(); i++) { + ThreadContext * tc = system->getThreadContext(contextIds[i]); + + SegAttr dataAttr = 0; + dataAttr.writable = 1; + dataAttr.readable = 1; + dataAttr.expandDown = 0; + dataAttr.dpl = 3; + dataAttr.defaultSize = 1; + dataAttr.longMode = 0; + + //Initialize the segment registers. + for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) { + tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0); + tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0); + tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr); + tc->setMiscRegNoEffect(MISCREG_SEG_SEL(seg), 0xB); + tc->setMiscRegNoEffect(MISCREG_SEG_LIMIT(seg), (uint32_t)(-1)); + } + + SegAttr csAttr = 0; + csAttr.writable = 0; + csAttr.readable = 1; + csAttr.expandDown = 0; + csAttr.dpl = 3; + csAttr.defaultSize = 1; + csAttr.longMode = 0; + + tc->setMiscRegNoEffect(MISCREG_CS_ATTR, csAttr); + + tc->setMiscRegNoEffect(MISCREG_TSG_BASE, _gdtStart); + tc->setMiscRegNoEffect(MISCREG_TSG_EFF_BASE, _gdtStart); + tc->setMiscRegNoEffect(MISCREG_TSG_LIMIT, _gdtStart + _gdtSize - 1); + + // Set the LDT selector to 0 to deactivate it. + tc->setMiscRegNoEffect(MISCREG_TSL, 0); + + //Set up the registers that describe the operating mode. + CR0 cr0 = 0; + cr0.pg = 1; // Turn on paging. + cr0.cd = 0; // Don't disable caching. + cr0.nw = 0; // This is bit is defined to be ignored. + cr0.am = 0; // No alignment checking + cr0.wp = 0; // Supervisor mode can write read only pages + cr0.ne = 1; + cr0.et = 1; // This should always be 1 + cr0.ts = 0; // We don't do task switching, so causing fp exceptions + // would be pointless. + cr0.em = 0; // Allow x87 instructions to execute natively. + cr0.mp = 1; // This doesn't really matter, but the manual suggests + // setting it to one. + cr0.pe = 1; // We're definitely in protected mode. + tc->setMiscReg(MISCREG_CR0, cr0); + + Efer efer = 0; + efer.sce = 1; // Enable system call extensions. + efer.lme = 1; // Enable long mode. + efer.lma = 0; // Deactivate long mode. + efer.nxe = 1; // Enable nx support. + efer.svme = 0; // Disable svm support for now. It isn't implemented. + efer.ffxsr = 1; // Turn on fast fxsave and fxrstor. + tc->setMiscReg(MISCREG_EFER, efer); + } +} + +template<class IntType> +void +X86LiveProcess::argsInit(int pageSize, + std::vector<AuxVector<IntType> > extraAuxvs) { - typedef M5_64_auxv_t auxv_t; - Process::startup(); + int intSize = sizeof(IntType); + + typedef AuxVector<IntType> auxv_t; + std::vector<auxv_t> auxv = extraAuxvs; string filename; if(argv.size() < 1) @@ -399,35 +570,35 @@ X86LiveProcess::argsInit(int intSize, int pageSize) roundUp(stack_size, pageSize)); // map out initial stack contents - Addr sentry_base = stack_base - sentry_size; - Addr file_name_base = sentry_base - file_name_size; - Addr env_data_base = file_name_base - env_data_size; - Addr arg_data_base = env_data_base - arg_data_size; - Addr aux_data_base = arg_data_base - info_block_padding - aux_data_size; - Addr auxv_array_base = aux_data_base - aux_array_size - aux_padding; - Addr envp_array_base = auxv_array_base - envp_array_size; - Addr argv_array_base = envp_array_base - argv_array_size; - Addr argc_base = argv_array_base - argc_size; - - DPRINTF(X86, "The addresses of items on the initial stack:\n"); - DPRINTF(X86, "0x%x - file name\n", file_name_base); - DPRINTF(X86, "0x%x - env data\n", env_data_base); - DPRINTF(X86, "0x%x - arg data\n", arg_data_base); - DPRINTF(X86, "0x%x - aux data\n", aux_data_base); - DPRINTF(X86, "0x%x - auxv array\n", auxv_array_base); - DPRINTF(X86, "0x%x - envp array\n", envp_array_base); - DPRINTF(X86, "0x%x - argv array\n", argv_array_base); - DPRINTF(X86, "0x%x - argc \n", argc_base); - DPRINTF(X86, "0x%x - stack min\n", stack_min); + IntType sentry_base = stack_base - sentry_size; + IntType file_name_base = sentry_base - file_name_size; + IntType env_data_base = file_name_base - env_data_size; + IntType arg_data_base = env_data_base - arg_data_size; + IntType aux_data_base = arg_data_base - info_block_padding - aux_data_size; + IntType auxv_array_base = aux_data_base - aux_array_size - aux_padding; + IntType envp_array_base = auxv_array_base - envp_array_size; + IntType argv_array_base = envp_array_base - argv_array_size; + IntType argc_base = argv_array_base - argc_size; + + DPRINTF(Stack, "The addresses of items on the initial stack:\n"); + DPRINTF(Stack, "0x%x - file name\n", file_name_base); + DPRINTF(Stack, "0x%x - env data\n", env_data_base); + DPRINTF(Stack, "0x%x - arg data\n", arg_data_base); + DPRINTF(Stack, "0x%x - aux data\n", aux_data_base); + DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base); + DPRINTF(Stack, "0x%x - envp array\n", envp_array_base); + DPRINTF(Stack, "0x%x - argv array\n", argv_array_base); + DPRINTF(Stack, "0x%x - argc \n", argc_base); + DPRINTF(Stack, "0x%x - stack min\n", stack_min); // write contents to stack // figure out argc - uint64_t argc = argv.size(); - uint64_t guestArgc = TheISA::htog(argc); + IntType argc = argv.size(); + IntType guestArgc = X86ISA::htog(argc); //Write out the sentry void * - uint64_t sentry_NULL = 0; + IntType sentry_NULL = 0; initVirtMem->writeBlob(sentry_base, (uint8_t*)&sentry_NULL, sentry_size); @@ -458,17 +629,70 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); + ThreadContext *tc = system->getThreadContext(contextIds[0]); //Set the stack pointer register - threadContexts[0]->setIntReg(StackPointerReg, stack_min); + tc->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); // There doesn't need to be any segment base added in since we're dealing // with the flat segmentation model. - threadContexts[0]->setPC(prog_entry); - threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + tc->setPC(prog_entry); + tc->setNextPC(prog_entry + sizeof(MachInst)); //Align the "stack_min" to a page boundary. stack_min = roundDown(stack_min, pageSize); // num_processes++; } + +void +X86_64LiveProcess::argsInit(int intSize, int pageSize) +{ + std::vector<AuxVector<uint64_t> > extraAuxvs; + X86LiveProcess::argsInit<uint64_t>(pageSize, extraAuxvs); +} + +void +I386LiveProcess::argsInit(int intSize, int pageSize) +{ + std::vector<AuxVector<uint32_t> > extraAuxvs; + //Tell the binary where the vsyscall part of the vsyscall page is. + extraAuxvs.push_back(AuxVector<uint32_t>(0x20, + vsyscallPage.base + vsyscallPage.vsyscallOffset)); + extraAuxvs.push_back(AuxVector<uint32_t>(0x21, vsyscallPage.base)); + X86LiveProcess::argsInit<uint32_t>(pageSize, extraAuxvs); +} + +void +X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn return_value) +{ + tc->setIntReg(INTREG_RAX, return_value.value()); +} + +X86ISA::IntReg +X86_64LiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < NumArgumentRegs); + return tc->readIntReg(ArgumentReg[i]); +} + +void +X86_64LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val) +{ + assert(i < NumArgumentRegs); + return tc->setIntReg(ArgumentReg[i], val); +} + +X86ISA::IntReg +I386LiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < NumArgumentRegs32); + return tc->readIntReg(ArgumentReg32[i]); +} + +void +I386LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val) +{ + assert(i < NumArgumentRegs); + return tc->setIntReg(ArgumentReg[i], val); +} diff --git a/src/arch/x86/process.hh b/src/arch/x86/process.hh index 5def9e13d..cd6d99e66 100644 --- a/src/arch/x86/process.hh +++ b/src/arch/x86/process.hh @@ -62,38 +62,76 @@ #include <vector> #include "sim/process.hh" +class SyscallDesc; + namespace X86ISA { - struct M5_64_auxv_t + + class X86LiveProcess : public LiveProcess { - int64_t a_type; - union { - int64_t a_val; - int64_t a_ptr; - int64_t a_fcn; - }; + protected: + Addr _gdtStart; + Addr _gdtSize; + + SyscallDesc *syscallDescs; + const int numSyscallDescs; - M5_64_auxv_t() - {} + X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs); - M5_64_auxv_t(int64_t type, int64_t val); + template<class IntType> + void argsInit(int pageSize, + std::vector<AuxVector<IntType> > extraAuxvs); + + public: + Addr gdtStart() + { return _gdtStart; } + + Addr gdtSize() + { return _gdtSize; } + + SyscallDesc* getDesc(int callnum); + + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); }; - class X86LiveProcess : public LiveProcess + class X86_64LiveProcess : public X86LiveProcess { protected: - std::vector<M5_64_auxv_t> auxv; - - X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile); + X86_64LiveProcess(LiveProcessParams *params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs); + public: + void argsInit(int intSize, int pageSize); void startup(); - public: + X86ISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val); + }; - //Handles traps which request services from the operating system - virtual void handleTrap(int trapNum, ThreadContext *tc); + class I386LiveProcess : public X86LiveProcess + { + protected: + I386LiveProcess(LiveProcessParams *params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs); + class VSyscallPage + { + public: + Addr base; + Addr size; + Addr vsyscallOffset; + Addr vsysexitOffset; + }; + VSyscallPage vsyscallPage; + + public: void argsInit(int intSize, int pageSize); + void startup(); + + void syscall(int64_t callnum, ThreadContext *tc); + X86ISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val); }; } diff --git a/src/arch/x86/regfile.cc b/src/arch/x86/regfile.cc index c27ab08ba..7d01c4bb4 100644 --- a/src/arch/x86/regfile.cc +++ b/src/arch/x86/regfile.cc @@ -135,23 +135,23 @@ void RegFile::clear() MiscReg RegFile::readMiscRegNoEffect(int miscReg) { - return miscRegFile.readRegNoEffect(miscReg); + return miscRegFile.readRegNoEffect((MiscRegIndex)miscReg); } MiscReg RegFile::readMiscReg(int miscReg, ThreadContext *tc) { - return miscRegFile.readReg(miscReg, tc); + return miscRegFile.readReg((MiscRegIndex)miscReg, tc); } void RegFile::setMiscRegNoEffect(int miscReg, const MiscReg &val) { - miscRegFile.setRegNoEffect(miscReg, val); + miscRegFile.setRegNoEffect((MiscRegIndex)miscReg, val); } void RegFile::setMiscReg(int miscReg, const MiscReg &val, ThreadContext * tc) { - miscRegFile.setReg(miscReg, val, tc); + miscRegFile.setReg((MiscRegIndex)miscReg, val, tc); } FloatReg RegFile::readFloatReg(int floatReg, int width) @@ -214,7 +214,7 @@ int X86ISA::flattenIntIndex(ThreadContext * tc, int reg) //If we need to fold over the index to match byte semantics, do that. //Otherwise, just strip off any extra bits and pass it through. if (reg & (1 << 6)) - return (reg & ~(1 << 6) - 0x4); + return (reg & (~(1 << 6) - 0x4)); else return (reg & ~(1 << 6)); } @@ -228,7 +228,8 @@ int X86ISA::flattenFloatIndex(ThreadContext * tc, int reg) return reg; } -void RegFile::serialize(std::ostream &os) +void +RegFile::serialize(EventManager *em, std::ostream &os) { intRegFile.serialize(os); floatRegFile.serialize(os); @@ -237,7 +238,8 @@ void RegFile::serialize(std::ostream &os) SERIALIZE_SCALAR(nextRip); } -void RegFile::unserialize(Checkpoint *cp, const std::string §ion) +void +RegFile::unserialize(EventManager *em, Checkpoint *cp, const string §ion) { intRegFile.unserialize(cp, section); floatRegFile.unserialize(cp, section); @@ -246,11 +248,6 @@ void RegFile::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(nextRip); } -void RegFile::changeContext(RegContextParam param, RegContextVal val) -{ - panic("changeContext not implemented for x86!\n"); -} - void X86ISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) { panic("copyMiscRegs not implemented for x86!\n"); diff --git a/src/arch/x86/regfile.hh b/src/arch/x86/regfile.hh index 650181aca..8938ab0bc 100644 --- a/src/arch/x86/regfile.hh +++ b/src/arch/x86/regfile.hh @@ -68,6 +68,7 @@ #include <string> class Checkpoint; +class EventManager; namespace X86ISA { @@ -96,8 +97,6 @@ namespace X86ISA void clear(); - int FlattenIntIndex(int reg); - MiscReg readMiscRegNoEffect(int miscReg); MiscReg readMiscReg(int miscReg, ThreadContext *tc); @@ -139,12 +138,11 @@ namespace X86ISA void setIntReg(int intReg, const IntReg &val); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(EventManager *em, std::ostream &os); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion); public: - - void changeContext(RegContextParam param, RegContextVal val); }; int flattenIntIndex(ThreadContext * tc, int reg); diff --git a/src/arch/x86/remote_gdb.cc b/src/arch/x86/remote_gdb.cc index 5ab0ec3fb..c416042c8 100644 --- a/src/arch/x86/remote_gdb.cc +++ b/src/arch/x86/remote_gdb.cc @@ -57,7 +57,7 @@ /* * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and @@ -65,8 +65,8 @@ * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -78,8 +78,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -96,7 +96,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 */ /*- @@ -116,8 +116,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. @@ -157,7 +157,7 @@ #include "cpu/thread_context.hh" using namespace std; -using namespace TheISA; +using namespace X86ISA; RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) : BaseRemoteGDB(_system, c, NumGDBRegs) diff --git a/src/arch/x86/stacktrace.cc b/src/arch/x86/stacktrace.cc index 300e8dcd0..87767583b 100644 --- a/src/arch/x86/stacktrace.cc +++ b/src/arch/x86/stacktrace.cc @@ -70,8 +70,6 @@ namespace X86ISA if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) panic("thread info not compiled into kernel\n"); name_off = vp->readGtoH<int32_t>(addr); - - tc->delVirtPort(vp); } Addr @@ -87,7 +85,6 @@ namespace X86ISA vp = tc->getVirtPort(); tsk = vp->readGtoH<Addr>(base + task_off); - tc->delVirtPort(vp); return tsk; } @@ -105,7 +102,6 @@ namespace X86ISA vp = tc->getVirtPort(); pd = vp->readGtoH<uint16_t>(task + pid_off); - tc->delVirtPort(vp); return pd; } diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc index 947a7793e..ed3dae4e6 100644 --- a/src/arch/x86/system.cc +++ b/src/arch/x86/system.cc @@ -55,13 +55,15 @@ * Authors: Gabe Black */ +#include "arch/x86/bios/smbios.hh" +#include "arch/x86/bios/intelmp.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/system.hh" -#include "arch/x86/smbios.hh" #include "arch/vtophys.hh" -#include "base/remote_gdb.hh" +#include "base/intmath.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" +#include "base/remote_gdb.hh" #include "base/trace.hh" #include "cpu/thread_context.hh" #include "mem/physical.hh" @@ -72,14 +74,12 @@ using namespace LittleEndianGuest; using namespace X86ISA; -X86System::X86System(Params *p) - : System(p) -{ - smbiosTable = new X86ISA::SMBios::SMBiosTable; - smbiosTable->smbiosHeader.majorVersion = 2; - smbiosTable->smbiosHeader.minorVersion = 5; - smbiosTable->smbiosHeader.intermediateHeader.smbiosBCDRevision = 0x25; -} +X86System::X86System(Params *p) : + System(p), smbiosTable(p->smbios_table), + mpFloatingPointer(p->intel_mp_pointer), + mpConfigTable(p->intel_mp_table), + rsdp(p->acpi_description_table_pointer) +{} void X86System::startup() @@ -236,27 +236,67 @@ X86System::startup() // We should now be in long mode. Yay! + Addr ebdaPos = 0xF0000; + Addr fixed, table; + //Write out the SMBios/DMI table - writeOutSMBiosTable(0xF0000); + writeOutSMBiosTable(ebdaPos, fixed, table); + ebdaPos += (fixed + table); + ebdaPos = roundUp(ebdaPos, 16); + + //Write out the Intel MP Specification configuration table + writeOutMPTable(ebdaPos, fixed, table); + ebdaPos += (fixed + table); } void -X86System::writeOutSMBiosTable(Addr header, Addr table) +X86System::writeOutSMBiosTable(Addr header, + Addr &headerSize, Addr &structSize, Addr table) { // Get a port to write the table and header to memory. FunctionalPort * physPort = threadContexts[0]->getPhysPort(); // If the table location isn't specified, just put it after the header. // The header size as of the 2.5 SMBios specification is 0x1F bytes - if (!table) { - if (!smbiosTable->smbiosHeader.intermediateHeader.tableAddr) - smbiosTable->smbiosHeader. - intermediateHeader.tableAddr = header + 0x1F; - } else { - smbiosTable->smbiosHeader.intermediateHeader.tableAddr = table; + if (!table) + table = header + 0x1F; + smbiosTable->setTableAddr(table); + + smbiosTable->writeOut(physPort, header, headerSize, structSize); + + // Do some bounds checking to make sure we at least didn't step on + // ourselves. + assert(header > table || header + headerSize <= table); + assert(table > header || table + structSize <= header); +} + +void +X86System::writeOutMPTable(Addr fp, + Addr &fpSize, Addr &tableSize, Addr table) +{ + // Get a port to write the table and header to memory. + FunctionalPort * physPort = threadContexts[0]->getPhysPort(); + + // If the table location isn't specified and it exists, just put + // it after the floating pointer. The fp size as of the 1.4 Intel MP + // specification is 0x10 bytes. + if (mpConfigTable) { + if (!table) + table = fp + 0x10; + mpFloatingPointer->setTableAddr(table); } - smbiosTable->writeOut(physPort, header); + fpSize = mpFloatingPointer->writeOut(physPort, fp); + if (mpConfigTable) + tableSize = mpConfigTable->writeOut(physPort, table); + else + tableSize = 0; + + // Do some bounds checking to make sure we at least didn't step on + // ourselves and the fp structure was the size we thought it was. + assert(fp > table || fp + fpSize <= table); + assert(table > fp || table + tableSize <= fp); + assert(fpSize == 0x10); } diff --git a/src/arch/x86/system.hh b/src/arch/x86/system.hh index 8a5483ebf..12a471f6f 100644 --- a/src/arch/x86/system.hh +++ b/src/arch/x86/system.hh @@ -74,6 +74,11 @@ namespace X86ISA { class SMBiosTable; } + namespace IntelMP + { + class FloatingPointer; + class ConfigTable; + } } class X86System : public System @@ -95,8 +100,15 @@ class X86System : public System protected: X86ISA::SMBios::SMBiosTable * smbiosTable; + X86ISA::IntelMP::FloatingPointer * mpFloatingPointer; + X86ISA::IntelMP::ConfigTable * mpConfigTable; + X86ISA::ACPI::RSDP * rsdp; + + void writeOutSMBiosTable(Addr header, + Addr &headerSize, Addr &tableSize, Addr table = 0); - void writeOutSMBiosTable(Addr header, Addr table = 0); + void writeOutMPTable(Addr fp, + Addr &fpSize, Addr &tableSize, Addr table = 0); const Params *params() const { return (const Params *)_params; } diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index a87abf212..3fec4c7da 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -59,6 +59,7 @@ #include "config/full_system.hh" +#include "arch/x86/insts/microldstop.hh" #include "arch/x86/pagetable.hh" #include "arch/x86/tlb.hh" #include "arch/x86/x86_traits.hh" @@ -72,6 +73,9 @@ #if FULL_SYSTEM #include "arch/x86/pagetable_walker.hh" +#else +#include "mem/page_table.hh" +#include "sim/process.hh" #endif namespace X86ISA { @@ -90,7 +94,7 @@ TLB::TLB(const Params *p) : BaseTLB(p), configAddress(0), size(p->size) #endif } -void +TlbEntry * TLB::insert(Addr vpn, TlbEntry &entry) { //TODO Deal with conflicting entries @@ -106,6 +110,7 @@ TLB::insert(Addr vpn, TlbEntry &entry) *newEntry = entry; newEntry->vaddr = vpn; entryList.push_front(newEntry); + return newEntry; } TLB::EntryList::iterator @@ -138,14 +143,6 @@ TLB::lookup(Addr va, bool update_lru) return *entry; } -#if FULL_SYSTEM -void -TLB::walk(ThreadContext * _tc, Addr vaddr) -{ - walker->start(_tc, vaddr); -} -#endif - void TLB::invalidateAll() { @@ -188,16 +185,18 @@ TLB::demapPage(Addr va, uint64_t asn) } } -template<class TlbFault> Fault -TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) +TLB::translate(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write, bool execute, + bool &delayedResponse, bool timing) { + delayedResponse = false; Addr vaddr = req->getVaddr(); DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr); uint32_t flags = req->getFlags(); bool storeCheck = flags & StoreCheck; - int seg = flags & mask(4); + int seg = flags & SegmentFlagMask; //XXX Junk code to surpress the warning if (storeCheck); @@ -206,10 +205,11 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) // value. if (seg == SEGMENT_REG_MS) { DPRINTF(TLB, "Addresses references internal memory.\n"); - Addr prefix = vaddr & IntAddrPrefixMask; + Addr prefix = (vaddr >> 3) & IntAddrPrefixMask; if (prefix == IntAddrPrefixCPUID) { panic("CPUID memory space not yet implemented!\n"); } else if (prefix == IntAddrPrefixMSR) { + vaddr = vaddr >> 3; req->setMmapedIpr(true); Addr regNum = 0; switch (vaddr & ~IntAddrPrefixMask) { @@ -357,6 +357,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x410: regNum = MISCREG_MC4_CTL; break; + case 0x414: + regNum = MISCREG_MC5_CTL; + break; + case 0x418: + regNum = MISCREG_MC6_CTL; + break; + case 0x41C: + regNum = MISCREG_MC7_CTL; + break; case 0x401: regNum = MISCREG_MC0_STATUS; break; @@ -372,6 +381,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x411: regNum = MISCREG_MC4_STATUS; break; + case 0x415: + regNum = MISCREG_MC5_STATUS; + break; + case 0x419: + regNum = MISCREG_MC6_STATUS; + break; + case 0x41D: + regNum = MISCREG_MC7_STATUS; + break; case 0x402: regNum = MISCREG_MC0_ADDR; break; @@ -387,6 +405,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x412: regNum = MISCREG_MC4_ADDR; break; + case 0x416: + regNum = MISCREG_MC5_ADDR; + break; + case 0x41A: + regNum = MISCREG_MC6_ADDR; + break; + case 0x41E: + regNum = MISCREG_MC7_ADDR; + break; case 0x403: regNum = MISCREG_MC0_MISC; break; @@ -402,6 +429,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x413: regNum = MISCREG_MC4_MISC; break; + case 0x417: + regNum = MISCREG_MC5_MISC; + break; + case 0x41B: + regNum = MISCREG_MC6_MISC; + break; + case 0x41F: + regNum = MISCREG_MC7_MISC; + break; case 0xC0000080: regNum = MISCREG_EFER; break; @@ -510,7 +546,8 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS); if (bits(configAddress, 31, 31)) { req->setPaddr(PhysAddrPrefixPciConfig | - bits(configAddress, 30, 0)); + mbits(configAddress, 30, 2) | + (IOPort & mask(2))); } } else { req->setPaddr(PhysAddrPrefixIO | IOPort); @@ -534,35 +571,38 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) // If we're not in 64-bit mode, do protection/limit checks if (!efer.lma || !csAttr.longMode) { DPRINTF(TLB, "Not in long mode. Checking segment protection.\n"); - SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg)); - if (!attr.writable && write) - return new GeneralProtection(0); - if (!attr.readable && !write && !execute) + // Check for a NULL segment selector. + if (!tc->readMiscRegNoEffect(MISCREG_SEG_SEL(seg))) return new GeneralProtection(0); + bool expandDown = false; + SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg)); + if (seg >= SEGMENT_REG_ES && seg <= SEGMENT_REG_HS) { + if (!attr.writable && write) + return new GeneralProtection(0); + if (!attr.readable && !write && !execute) + return new GeneralProtection(0); + expandDown = attr.expandDown; + + } Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg)); Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg)); - if (!attr.expandDown) { + // This assumes we're not in 64 bit mode. If we were, the default + // address size is 64 bits, overridable to 32. + int size = 32; + bool sizeOverride = (flags & (AddrSizeFlagBit << FlagShift)); + if ((csAttr.defaultSize && sizeOverride) || + (!csAttr.defaultSize && !sizeOverride)) + size = 16; + Addr offset = bits(vaddr - base, size-1, 0); + Addr endOffset = offset + req->getSize() - 1; + if (expandDown) { DPRINTF(TLB, "Checking an expand down segment.\n"); - // We don't have to worry about the access going around the - // end of memory because accesses will be broken up into - // pieces at boundaries aligned on sizes smaller than an - // entire address space. We do have to worry about the limit - // being less than the base. - if (limit < base) { - if (limit < vaddr + req->getSize() && vaddr < base) - return new GeneralProtection(0); - } else { - if (limit < vaddr + req->getSize()) - return new GeneralProtection(0); - } + warn_once("Expand down segments are untested.\n"); + if (offset <= limit || endOffset <= limit) + return new GeneralProtection(0); } else { - if (limit < base) { - if (vaddr <= limit || vaddr + req->getSize() >= base) - return new GeneralProtection(0); - } else { - if (vaddr <= limit && vaddr + req->getSize() >= base) - return new GeneralProtection(0); - } + if (offset > limit || endOffset > limit) + return new GeneralProtection(0); } } // If paging is enabled, do the translation. @@ -571,14 +611,57 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) // The vaddr already has the segment base applied. TlbEntry *entry = lookup(vaddr); if (!entry) { - return new TlbFault(vaddr); - } else { - // Do paging protection checks. - DPRINTF(TLB, "Entry found with paddr %#x, doing protection checks.\n", entry->paddr); - Addr paddr = entry->paddr | (vaddr & (entry->size-1)); - DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr); - req->setPaddr(paddr); +#if FULL_SYSTEM + Fault fault = walker->start(tc, translation, req, + write, execute); + if (timing || fault != NoFault) { + // This gets ignored in atomic mode. + delayedResponse = true; + return fault; + } + entry = lookup(vaddr); + assert(entry); +#else + DPRINTF(TLB, "Handling a TLB miss for " + "address %#x at pc %#x.\n", + vaddr, tc->readPC()); + + Process *p = tc->getProcessPtr(); + TlbEntry newEntry; + bool success = p->pTable->lookup(vaddr, newEntry); + if(!success && !execute) { + p->checkAndAllocNextPage(vaddr); + success = p->pTable->lookup(vaddr, newEntry); + } + if(!success) { + panic("Tried to execute unmapped address %#x.\n", vaddr); + } else { + Addr alignedVaddr = p->pTable->pageAlign(vaddr); + DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, + newEntry.pageStart()); + entry = insert(alignedVaddr, newEntry); + } + DPRINTF(TLB, "Miss was serviced.\n"); +#endif } + // Do paging protection checks. + bool inUser = (csAttr.dpl == 3 && + !(flags & (CPL0FlagBit << FlagShift))); + if ((inUser && !entry->user) || + (write && !entry->writable)) { + // The page must have been present to get into the TLB in + // the first place. We'll assume the reserved bits are + // fine even though we're not checking them. + return new PageFault(vaddr, true, write, + inUser, false, execute); + } + + + DPRINTF(TLB, "Entry found with paddr %#x, " + "doing protection checks.\n", entry->paddr); + Addr paddr = entry->paddr | (vaddr & (entry->size-1)); + DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr); + req->setPaddr(paddr); } else { //Use the address which already has segmentation applied. DPRINTF(TLB, "Paging disabled.\n"); @@ -592,160 +675,68 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) req->setPaddr(vaddr); } // Check for an access to the local APIC +#if FULL_SYSTEM LocalApicBase localApicBase = tc->readMiscRegNoEffect(MISCREG_APIC_BASE); - Addr baseAddr = localApicBase.base << 12; + Addr baseAddr = localApicBase.base * PageBytes; Addr paddr = req->getPaddr(); - if (baseAddr <= paddr && baseAddr + (1 << 12) > paddr) { - req->setMmapedIpr(true); + if (baseAddr <= paddr && baseAddr + PageBytes > paddr) { + // The Intel developer's manuals say the below restrictions apply, + // but the linux kernel, because of a compiler optimization, breaks + // them. + /* // Check alignment if (paddr & ((32/8) - 1)) return new GeneralProtection(0); // Check access size if (req->getSize() != (32/8)) return new GeneralProtection(0); - MiscReg regNum; - switch (paddr - baseAddr) - { - case 0x20: - regNum = MISCREG_APIC_ID; - break; - case 0x30: - regNum = MISCREG_APIC_VERSION; - break; - case 0x80: - regNum = MISCREG_APIC_TASK_PRIORITY; - break; - case 0x90: - regNum = MISCREG_APIC_ARBITRATION_PRIORITY; - break; - case 0xA0: - regNum = MISCREG_APIC_PROCESSOR_PRIORITY; - break; - case 0xB0: - regNum = MISCREG_APIC_EOI; - break; - case 0xD0: - regNum = MISCREG_APIC_LOGICAL_DESTINATION; - break; - case 0xE0: - regNum = MISCREG_APIC_DESTINATION_FORMAT; - break; - case 0xF0: - regNum = MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR; - break; - case 0x100: - case 0x108: - case 0x110: - case 0x118: - case 0x120: - case 0x128: - case 0x130: - case 0x138: - case 0x140: - case 0x148: - case 0x150: - case 0x158: - case 0x160: - case 0x168: - case 0x170: - case 0x178: - regNum = MISCREG_APIC_IN_SERVICE( - (paddr - baseAddr - 0x100) / 0x8); - break; - case 0x180: - case 0x188: - case 0x190: - case 0x198: - case 0x1A0: - case 0x1A8: - case 0x1B0: - case 0x1B8: - case 0x1C0: - case 0x1C8: - case 0x1D0: - case 0x1D8: - case 0x1E0: - case 0x1E8: - case 0x1F0: - case 0x1F8: - regNum = MISCREG_APIC_TRIGGER_MODE( - (paddr - baseAddr - 0x180) / 0x8); - break; - case 0x200: - case 0x208: - case 0x210: - case 0x218: - case 0x220: - case 0x228: - case 0x230: - case 0x238: - case 0x240: - case 0x248: - case 0x250: - case 0x258: - case 0x260: - case 0x268: - case 0x270: - case 0x278: - regNum = MISCREG_APIC_INTERRUPT_REQUEST( - (paddr - baseAddr - 0x200) / 0x8); - break; - case 0x280: - regNum = MISCREG_APIC_ERROR_STATUS; - break; - case 0x300: - regNum = MISCREG_APIC_INTERRUPT_COMMAND_LOW; - break; - case 0x310: - regNum = MISCREG_APIC_INTERRUPT_COMMAND_HIGH; - break; - case 0x320: - regNum = MISCREG_APIC_LVT_TIMER; - break; - case 0x330: - regNum = MISCREG_APIC_LVT_THERMAL_SENSOR; - break; - case 0x340: - regNum = MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; - break; - case 0x350: - regNum = MISCREG_APIC_LVT_LINT0; - break; - case 0x360: - regNum = MISCREG_APIC_LVT_LINT1; - break; - case 0x370: - regNum = MISCREG_APIC_LVT_ERROR; - break; - case 0x380: - regNum = MISCREG_APIC_INITIAL_COUNT; - break; - case 0x390: - regNum = MISCREG_APIC_CURRENT_COUNT; - break; - case 0x3E0: - regNum = MISCREG_APIC_DIVIDE_COUNT; - break; - default: - // A reserved register field. - return new GeneralProtection(0); - break; - } - req->setPaddr(regNum * sizeof(MiscReg)); + */ + // Force the access to be uncacheable. + req->setFlags(Request::UNCACHEABLE); + req->setPaddr(x86LocalAPICAddress(tc->contextId(), paddr - baseAddr)); } +#endif return NoFault; }; Fault -DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) +{ + bool delayedResponse; + return TLB::translate(req, tc, NULL, write, + false, delayedResponse, false); +} + +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) { - return TLB::translate<FakeDTLBFault>(req, tc, write, false); + bool delayedResponse; + assert(translation); + Fault fault = TLB::translate(req, tc, translation, + write, false, delayedResponse, true); + if (!delayedResponse) + translation->finish(fault, req, tc, write); } Fault -ITB::translate(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) +{ + bool delayedResponse; + return TLB::translate(req, tc, NULL, false, + true, delayedResponse, false); +} + +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) { - return TLB::translate<FakeITLBFault>(req, tc, false, true); + bool delayedResponse; + assert(translation); + Fault fault = TLB::translate(req, tc, translation, + false, true, delayedResponse, true); + if (!delayedResponse) + translation->finish(fault, req, tc, false); } #if FULL_SYSTEM diff --git a/src/arch/x86/tlb.hh b/src/arch/x86/tlb.hh index 89b965e97..2467bc472 100644 --- a/src/arch/x86/tlb.hh +++ b/src/arch/x86/tlb.hh @@ -87,8 +87,7 @@ namespace X86ISA class TLB : public BaseTLB { protected: - friend class FakeITLBFault; - friend class FakeDTLBFault; + friend class Walker; typedef std::list<TlbEntry *> EntryList; @@ -118,8 +117,6 @@ namespace X86ISA protected: Walker * walker; - - void walk(ThreadContext * _tc, Addr vaddr); #endif public: @@ -137,13 +134,13 @@ namespace X86ISA EntryList freeList; EntryList entryList; - template<class TlbFault> - Fault translate(RequestPtr &req, ThreadContext *tc, - bool write, bool execute); + Fault translate(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write, bool execute, + bool &delayedResponse, bool timing); public: - void insert(Addr vpn, TlbEntry &entry); + TlbEntry * insert(Addr vpn, TlbEntry &entry); // Checkpointing virtual void serialize(std::ostream &os); @@ -159,7 +156,9 @@ namespace X86ISA _allowNX = false; } - Fault translate(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); friend class DTB; }; @@ -172,7 +171,9 @@ namespace X86ISA { _allowNX = true; } - Fault translate(RequestPtr &req, ThreadContext *tc, bool write); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write); #if FULL_SYSTEM Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 90df38d13..29420352b 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -246,17 +246,6 @@ namespace X86ISA MiscReg ctrlReg; } AnyReg; - //XXX This is very hypothetical. X87 instructions would need to - //change their "context" constantly. It's also not clear how - //this would be handled as far as out of order execution. - //Maybe x87 instructions are in order? - enum RegContextParam - { - CONTEXT_X87_TOP - }; - - typedef int RegContextVal; - typedef uint16_t RegIndex; struct CoreSpecific { diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index 5fe5bf8c3..43a5ca1a9 100644 --- a/src/arch/x86/utility.cc +++ b/src/arch/x86/utility.cc @@ -55,11 +55,17 @@ * Authors: Gabe Black */ +#include "config/full_system.hh" + +#if FULL_SYSTEM +#include "arch/x86/interrupts.hh" +#endif #include "arch/x86/intregs.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/segmentregs.hh" #include "arch/x86/utility.hh" #include "arch/x86/x86_traits.hh" +#include "cpu/base.hh" #include "sim/system.hh" namespace X86ISA { @@ -254,9 +260,15 @@ void initCPU(ThreadContext *tc, int cpuId) lApicBase.bsp = (cpuId == 0); tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); - tc->setMiscRegNoEffect(MISCREG_APIC_ID, cpuId << 24); + Interrupts * interrupts = dynamic_cast<Interrupts *>( + tc->getCpuPtr()->getInterruptController()); + assert(interrupts); + + interrupts->setRegNoEffect(APIC_ID, cpuId << 24); - tc->setMiscRegNoEffect(MISCREG_APIC_VERSION, (5 << 16) | 0x14); + interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14); + + interrupts->setClock(tc->getCpuPtr()->ticks(16)); // TODO Set the SMRAM base address (SMBASE) to 0x00030000 diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh index 477a76e0b..6f0812a6a 100644 --- a/src/arch/x86/utility.hh +++ b/src/arch/x86/utility.hh @@ -93,7 +93,12 @@ namespace X86ISA static inline bool inUserMode(ThreadContext *tc) { - return false; +#if FULL_SYSTEM + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + return m5reg.cpl == 3; +#else + return true; +#endif } inline bool isCallerSaveIntegerRegister(unsigned int reg) { diff --git a/src/arch/x86/x86_traits.hh b/src/arch/x86/x86_traits.hh index d605ce218..0347a7099 100644 --- a/src/arch/x86/x86_traits.hh +++ b/src/arch/x86/x86_traits.hh @@ -55,11 +55,13 @@ * Authors: Gabe Black */ -#include "sim/host.hh" - #ifndef __ARCH_X86_X86TRAITS_HH__ #define __ARCH_X86_X86TRAITS_HH__ +#include <assert.h> + +#include "sim/host.hh" + namespace X86ISA { const int NumMicroIntRegs = 16; @@ -90,6 +92,37 @@ namespace X86ISA const Addr PhysAddrPrefixIO = ULL(0x8000000000000000); const Addr PhysAddrPrefixPciConfig = ULL(0xC000000000000000); + const Addr PhysAddrPrefixLocalAPIC = ULL(0x2000000000000000); + const Addr PhysAddrPrefixInterrupts = ULL(0xA000000000000000); + // Each APIC gets two pages. One page is used for local apics to field + // accesses from the CPU, and the other is for all APICs to communicate. + const Addr PhysAddrAPICRangeSize = 1 << 12; + + static inline Addr + x86IOAddress(const uint32_t port) + { + return PhysAddrPrefixIO | port; + } + + static inline Addr + x86PciConfigAddress(const uint32_t addr) + { + return PhysAddrPrefixPciConfig | addr; + } + + static inline Addr + x86LocalAPICAddress(const uint8_t id, const uint16_t addr) + { + assert(addr < (1 << 12)); + return PhysAddrPrefixLocalAPIC | (id * (1 << 12)) | addr; + } + + static inline Addr + x86InterruptAddress(const uint8_t id, const uint16_t addr) + { + assert(addr < PhysAddrAPICRangeSize); + return PhysAddrPrefixInterrupts | (id * PhysAddrAPICRangeSize) | addr; + } } #endif //__ARCH_X86_X86TRAITS_HH__ |