1/*
2 * Copyright (c) 2009 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Gabe Black
29 */
30
31#include "arch/x86/isa.hh"
32
33#include "arch/x86/decoder.hh"
34#include "arch/x86/tlb.hh"
35#include "cpu/base.hh"
36#include "cpu/thread_context.hh"
37#include "params/X86ISA.hh"
38#include "sim/serialize.hh"
39
40namespace X86ISA
41{
42
43void
44ISA::updateHandyM5Reg(Efer efer, CR0 cr0,
45                      SegAttr csAttr, SegAttr ssAttr, RFLAGS rflags,
46                      ThreadContext *tc)
47{
48    HandyM5Reg m5reg = 0;
49    if (efer.lma) {
50        m5reg.mode = LongMode;
51        if (csAttr.longMode)
52            m5reg.submode = SixtyFourBitMode;
53        else
54            m5reg.submode = CompatabilityMode;
55    } else {
56        m5reg.mode = LegacyMode;
57        if (cr0.pe) {
58            if (rflags.vm)
59                m5reg.submode = Virtual8086Mode;
60            else
61                m5reg.submode = ProtectedMode;
62        } else {
63            m5reg.submode = RealMode;
64        }
65    }
66    m5reg.cpl = csAttr.dpl;
67    m5reg.paging = cr0.pg;
68    m5reg.prot = cr0.pe;
69
70    // Compute the default and alternate operand size.
71    if (m5reg.submode == SixtyFourBitMode || csAttr.defaultSize) {
72        m5reg.defOp = 2;
73        m5reg.altOp = 1;
74    } else {
75        m5reg.defOp = 1;
76        m5reg.altOp = 2;
77    }
78
79    // Compute the default and alternate address size.
80    if (m5reg.submode == SixtyFourBitMode) {
81        m5reg.defAddr = 3;
82        m5reg.altAddr = 2;
83    } else if (csAttr.defaultSize) {
84        m5reg.defAddr = 2;
85        m5reg.altAddr = 1;
86    } else {
87        m5reg.defAddr = 1;
88        m5reg.altAddr = 2;
89    }
90
91    // Compute the stack size
92    if (m5reg.submode == SixtyFourBitMode) {
93        m5reg.stack = 3;
94    } else if (ssAttr.defaultSize) {
95        m5reg.stack = 2;
96    } else {
97        m5reg.stack = 1;
98    }
99
100    regVal[MISCREG_M5_REG] = m5reg;
101    if (tc)
102        tc->getDecoderPtr()->setM5Reg(m5reg);
103}
104
105void
106ISA::clear()
107{
108    // Blank everything. 0 might not be an appropriate value for some things,
109    // but it is for most.
110    memset(regVal, 0, NumMiscRegs * sizeof(RegVal));
111    regVal[MISCREG_DR6] = (mask(8) << 4) | (mask(16) << 16);
112    regVal[MISCREG_DR7] = 1 << 10;
113}
114
115ISA::ISA(Params *p)
116    : SimObject(p)
117{
118    clear();
119}
120
121const X86ISAParams *
122ISA::params() const
123{
124    return dynamic_cast<const Params *>(_params);
125}
126
127RegVal
128ISA::readMiscRegNoEffect(int miscReg) const
129{
130    // Make sure we're not dealing with an illegal control register.
131    // Instructions should filter out these indexes, and nothing else should
132    // attempt to read them directly.
133    assert(isValidMiscReg(miscReg));
134
135    return regVal[miscReg];
136}
137
138RegVal
139ISA::readMiscReg(int miscReg, ThreadContext * tc)
140{
141    if (miscReg == MISCREG_TSC) {
142        return regVal[MISCREG_TSC] + tc->getCpuPtr()->curCycle();
143    }
144
145    if (miscReg == MISCREG_FSW) {
146        RegVal fsw = regVal[MISCREG_FSW];
147        RegVal top = regVal[MISCREG_X87_TOP];
148        return insertBits(fsw, 13, 11, top);
149    }
150
151    return readMiscRegNoEffect(miscReg);
152}
153
154void
155ISA::setMiscRegNoEffect(int miscReg, RegVal val)
156{
157    // Make sure we're not dealing with an illegal control register.
158    // Instructions should filter out these indexes, and nothing else should
159    // attempt to write to them directly.
160    assert(isValidMiscReg(miscReg));
161
162    HandyM5Reg m5Reg = regVal[MISCREG_M5_REG];
163    int reg_width = 64;
164    switch (miscReg) {
165      case MISCREG_X87_TOP:
166        reg_width = 3;
167        break;
168      case MISCREG_FTW:
169        reg_width = 8;
170        break;
171      case MISCREG_FSW:
172      case MISCREG_FCW:
173      case MISCREG_FOP:
174        reg_width = 16;
175        break;
176      case MISCREG_MXCSR:
177        reg_width = 32;
178        break;
179      case MISCREG_FISEG:
180      case MISCREG_FOSEG:
181        if (m5Reg.submode != SixtyFourBitMode)
182            reg_width = 16;
183        break;
184      case MISCREG_FIOFF:
185      case MISCREG_FOOFF:
186        if (m5Reg.submode != SixtyFourBitMode)
187            reg_width = 32;
188        break;
189      default:
190        break;
191    }
192
193    regVal[miscReg] = val & mask(reg_width);
194}
195
196void
197ISA::setMiscReg(int miscReg, RegVal val, ThreadContext * tc)
198{
199    RegVal newVal = val;
200    switch(miscReg)
201    {
202      case MISCREG_CR0:
203        {
204            CR0 toggled = regVal[miscReg] ^ val;
205            CR0 newCR0 = val;
206            Efer efer = regVal[MISCREG_EFER];
207            if (toggled.pg && efer.lme) {
208                if (newCR0.pg) {
209                    //Turning on long mode
210                    efer.lma = 1;
211                    regVal[MISCREG_EFER] = efer;
212                } else {
213                    //Turning off long mode
214                    efer.lma = 0;
215                    regVal[MISCREG_EFER] = efer;
216                }
217            }
218            if (toggled.pg) {
219                dynamic_cast<TLB *>(tc->getITBPtr())->flushAll();
220                dynamic_cast<TLB *>(tc->getDTBPtr())->flushAll();
221            }
222            //This must always be 1.
223            newCR0.et = 1;
224            newVal = newCR0;
225            updateHandyM5Reg(regVal[MISCREG_EFER],
226                             newCR0,
227                             regVal[MISCREG_CS_ATTR],
228                             regVal[MISCREG_SS_ATTR],
229                             regVal[MISCREG_RFLAGS],
230                             tc);
231        }
232        break;
233      case MISCREG_CR2:
234        break;
235      case MISCREG_CR3:
236        dynamic_cast<TLB *>(tc->getITBPtr())->flushNonGlobal();
237        dynamic_cast<TLB *>(tc->getDTBPtr())->flushNonGlobal();
238        break;
239      case MISCREG_CR4:
240        {
241            CR4 toggled = regVal[miscReg] ^ val;
242            if (toggled.pae || toggled.pse || toggled.pge) {
243                dynamic_cast<TLB *>(tc->getITBPtr())->flushAll();
244                dynamic_cast<TLB *>(tc->getDTBPtr())->flushAll();
245            }
246        }
247        break;
248      case MISCREG_CR8:
249        break;
250      case MISCREG_CS_ATTR:
251        {
252            SegAttr toggled = regVal[miscReg] ^ val;
253            SegAttr newCSAttr = val;
254            if (toggled.longMode) {
255                if (newCSAttr.longMode) {
256                    regVal[MISCREG_ES_EFF_BASE] = 0;
257                    regVal[MISCREG_CS_EFF_BASE] = 0;
258                    regVal[MISCREG_SS_EFF_BASE] = 0;
259                    regVal[MISCREG_DS_EFF_BASE] = 0;
260                } else {
261                    regVal[MISCREG_ES_EFF_BASE] = regVal[MISCREG_ES_BASE];
262                    regVal[MISCREG_CS_EFF_BASE] = regVal[MISCREG_CS_BASE];
263                    regVal[MISCREG_SS_EFF_BASE] = regVal[MISCREG_SS_BASE];
264                    regVal[MISCREG_DS_EFF_BASE] = regVal[MISCREG_DS_BASE];
265                }
266            }
267            updateHandyM5Reg(regVal[MISCREG_EFER],
268                             regVal[MISCREG_CR0],
269                             newCSAttr,
270                             regVal[MISCREG_SS_ATTR],
271                             regVal[MISCREG_RFLAGS],
272                             tc);
273        }
274        break;
275      case MISCREG_SS_ATTR:
276        updateHandyM5Reg(regVal[MISCREG_EFER],
277                         regVal[MISCREG_CR0],
278                         regVal[MISCREG_CS_ATTR],
279                         val,
280                         regVal[MISCREG_RFLAGS],
281                         tc);
282        break;
283      // These segments always actually use their bases, or in other words
284      // their effective bases must stay equal to their actual bases.
285      case MISCREG_FS_BASE:
286      case MISCREG_GS_BASE:
287      case MISCREG_HS_BASE:
288      case MISCREG_TSL_BASE:
289      case MISCREG_TSG_BASE:
290      case MISCREG_TR_BASE:
291      case MISCREG_IDTR_BASE:
292        regVal[MISCREG_SEG_EFF_BASE(miscReg - MISCREG_SEG_BASE_BASE)] = val;
293        break;
294      // These segments ignore their bases in 64 bit mode.
295      // their effective bases must stay equal to their actual bases.
296      case MISCREG_ES_BASE:
297      case MISCREG_CS_BASE:
298      case MISCREG_SS_BASE:
299      case MISCREG_DS_BASE:
300        {
301            Efer efer = regVal[MISCREG_EFER];
302            SegAttr csAttr = regVal[MISCREG_CS_ATTR];
303            if (!efer.lma || !csAttr.longMode) // Check for non 64 bit mode.
304                regVal[MISCREG_SEG_EFF_BASE(miscReg -
305                        MISCREG_SEG_BASE_BASE)] = val;
306        }
307        break;
308      case MISCREG_TSC:
309        regVal[MISCREG_TSC] = val - tc->getCpuPtr()->curCycle();
310        return;
311      case MISCREG_DR0:
312      case MISCREG_DR1:
313      case MISCREG_DR2:
314      case MISCREG_DR3:
315        /* These should eventually set up breakpoints. */
316        break;
317      case MISCREG_DR4:
318        miscReg = MISCREG_DR6;
319        M5_FALLTHROUGH;
320      case MISCREG_DR6:
321        {
322            DR6 dr6 = regVal[MISCREG_DR6];
323            DR6 newDR6 = val;
324            dr6.b0 = newDR6.b0;
325            dr6.b1 = newDR6.b1;
326            dr6.b2 = newDR6.b2;
327            dr6.b3 = newDR6.b3;
328            dr6.bd = newDR6.bd;
329            dr6.bs = newDR6.bs;
330            dr6.bt = newDR6.bt;
331            newVal = dr6;
332        }
333        break;
334      case MISCREG_DR5:
335        miscReg = MISCREG_DR7;
336        M5_FALLTHROUGH;
337      case MISCREG_DR7:
338        {
339            DR7 dr7 = regVal[MISCREG_DR7];
340            DR7 newDR7 = val;
341            dr7.l0 = newDR7.l0;
342            dr7.g0 = newDR7.g0;
343            if (dr7.l0 || dr7.g0) {
344                panic("Debug register breakpoints not implemented.\n");
345            } else {
346                /* Disable breakpoint 0. */
347            }
348            dr7.l1 = newDR7.l1;
349            dr7.g1 = newDR7.g1;
350            if (dr7.l1 || dr7.g1) {
351                panic("Debug register breakpoints not implemented.\n");
352            } else {
353                /* Disable breakpoint 1. */
354            }
355            dr7.l2 = newDR7.l2;
356            dr7.g2 = newDR7.g2;
357            if (dr7.l2 || dr7.g2) {
358                panic("Debug register breakpoints not implemented.\n");
359            } else {
360                /* Disable breakpoint 2. */
361            }
362            dr7.l3 = newDR7.l3;
363            dr7.g3 = newDR7.g3;
364            if (dr7.l3 || dr7.g3) {
365                panic("Debug register breakpoints not implemented.\n");
366            } else {
367                /* Disable breakpoint 3. */
368            }
369            dr7.gd = newDR7.gd;
370            dr7.rw0 = newDR7.rw0;
371            dr7.len0 = newDR7.len0;
372            dr7.rw1 = newDR7.rw1;
373            dr7.len1 = newDR7.len1;
374            dr7.rw2 = newDR7.rw2;
375            dr7.len2 = newDR7.len2;
376            dr7.rw3 = newDR7.rw3;
377            dr7.len3 = newDR7.len3;
378        }
379        break;
380      case MISCREG_M5_REG:
381        // Writing anything to the m5reg with side effects makes it update
382        // based on the current values of the relevant registers. The actual
383        // value written is discarded.
384        updateHandyM5Reg(regVal[MISCREG_EFER],
385                         regVal[MISCREG_CR0],
386                         regVal[MISCREG_CS_ATTR],
387                         regVal[MISCREG_SS_ATTR],
388                         regVal[MISCREG_RFLAGS],
389                         tc);
390        return;
391      default:
392        break;
393    }
394    setMiscRegNoEffect(miscReg, newVal);
395}
396
397void
398ISA::serialize(CheckpointOut &cp) const
399{
400    SERIALIZE_ARRAY(regVal, NumMiscRegs);
401}
402
403void
404ISA::unserialize(CheckpointIn &cp)
405{
406    UNSERIALIZE_ARRAY(regVal, NumMiscRegs);
407    updateHandyM5Reg(regVal[MISCREG_EFER],
408                     regVal[MISCREG_CR0],
409                     regVal[MISCREG_CS_ATTR],
410                     regVal[MISCREG_SS_ATTR],
411                     regVal[MISCREG_RFLAGS],
412                     NULL);
413}
414
415void
416ISA::startup(ThreadContext *tc)
417{
418    tc->getDecoderPtr()->setM5Reg(regVal[MISCREG_M5_REG]);
419}
420
421}
422
423X86ISA::ISA *
424X86ISAParams::create()
425{
426    return new X86ISA::ISA(this);
427}
428