-
Notifications
You must be signed in to change notification settings - Fork 11
/
ptlhwdef.h
1563 lines (1315 loc) · 39.7 KB
/
ptlhwdef.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// -*- c++ -*-
//
// PTLsim: Cycle Accurate x86-64 Simulator
// Hardware Definitions
//
// Copyright 1999-2008 Matt T. Yourst <[email protected]>
//
#ifndef _PTLHWDEF_H
#define _PTLHWDEF_H
//
// NOTE: The first part of this file is included by assembly code,
// so do not put any C/C++-specific things here until the label
// __ASM_ONLY__ found below.
//
//
// Flags format: OF - - - SF ZF - AF wait PF inv CF
// 11 10 9 8 7 6 4 3 2 1 0
// rc - - - ra ra - ra - ra - rb
//
#define FLAG_CF 0x001 // (1 << 0)
#define FLAG_INV 0x002 // (1 << 1)
#define FLAG_PF 0x004 // (1 << 2)
#define FLAG_WAIT 0x008 // (1 << 3)
#define FLAG_AF 0x010 // (1 << 4)
#define FLAG_ZF 0x040 // (1 << 6)
#define FLAG_SF 0x080 // (1 << 7)
#define FLAG_OF 0x800 // (1 << 11)
#define FLAG_BR_TK 0x8000 // (1 << 15)
#define FLAG_SF_ZF 0x0c0 // (1 << 7) | (1 << 6)
#define FLAG_ZAPS 0x0d4 // 000011010100
#define FLAG_NOT_WAIT_INV (FLAG_ZAPS|FLAG_CF|FLAG_OF) // 00000100011010101: exclude others not in ZAPS/CF/OF
#define COND_o 0
#define COND_no 1
#define COND_c 2
#define COND_nc 3
#define COND_e 4
#define COND_ne 5
#define COND_be 6
#define COND_nbe 7
#define COND_s 8
#define COND_ns 9
#define COND_p 10
#define COND_np 11
#define COND_l 12
#define COND_nl 13
#define COND_le 14
#define COND_nle 15
#define COND_z COND_e
#define COND_nz COND_ne
#define COND_ae COND_nc
#define COND_ge COND_nl
#define COND_b COND_c
#define ARCHREG_INT_BASE 0
#define ARCHREG_SSE_BASE 16
//
// Registers
//
#define ARCHREG_COUNT 64
#define REG_rax 0
#define REG_rcx 1
#define REG_rdx 2
#define REG_rbx 3
#define REG_rsp 4
#define REG_rbp 5
#define REG_rsi 6
#define REG_rdi 7
#define REG_r8 8
#define REG_r9 9
#define REG_r10 10
#define REG_r11 11
#define REG_r12 12
#define REG_r13 13
#define REG_r14 14
#define REG_r15 15
#define REG_xmml0 16
#define REG_xmmh0 17
#define REG_xmml1 18
#define REG_xmmh1 19
#define REG_xmml2 20
#define REG_xmmh2 21
#define REG_xmml3 22
#define REG_xmmh3 23
#define REG_xmml4 24
#define REG_xmmh4 25
#define REG_xmml5 26
#define REG_xmmh5 27
#define REG_xmml6 28
#define REG_xmmh6 29
#define REG_xmml7 30
#define REG_xmmh7 31
#define REG_xmml8 32
#define REG_xmmh8 33
#define REG_xmml9 34
#define REG_xmmh9 35
#define REG_xmml10 36
#define REG_xmmh10 37
#define REG_xmml11 38
#define REG_xmmh11 39
#define REG_xmml12 40
#define REG_xmmh12 41
#define REG_xmml13 42
#define REG_xmmh13 43
#define REG_xmml14 44
#define REG_xmmh14 45
#define REG_xmml15 46
#define REG_xmmh15 47
#define REG_fptos 48
#define REG_fpsw 49
#define REG_fptags 50
#define REG_fpstack 51
#define REG_msr 52
#define REG_dlptr 53
#define REG_trace 54
#define REG_ctx 55
#define REG_rip 56
#define REG_flags 57
#define REG_dlend 58
#define REG_selfrip 59
#define REG_nextrip 60
#define REG_ar1 61
#define REG_ar2 62
#define REG_zero 63
// For renaming only:
#define REG_temp0 64
#define REG_temp1 65
#define REG_temp2 66
#define REG_temp3 67
#define REG_temp4 68
#define REG_temp5 69
#define REG_temp6 70
#define REG_temp7 71
#define REG_zf 72
#define REG_cf 73
#define REG_of 74
#define REG_imm 75
#define REG_mem 76
#define REG_temp8 77
#define REG_temp9 78
#define REG_temp10 79
#define TRANSREG_COUNT (64+16)
#define ARCHREG_NULL REG_zero
#ifndef __ASM_ONLY__
//
// The following definitions are used by C++ code
//
#include <globals.h>
extern W64 sim_cycle;
#include <logic.h>
#include <config.h>
//
// Exceptions:
// These are PTL internal exceptions, NOT x86 exceptions:
//
enum {
EXCEPTION_NoException = 0,
EXCEPTION_Propagate,
EXCEPTION_BranchMispredict,
EXCEPTION_UnalignedAccess,
EXCEPTION_PageFaultOnRead,
EXCEPTION_PageFaultOnWrite,
EXCEPTION_PageFaultOnExec,
EXCEPTION_StoreStoreAliasing,
EXCEPTION_LoadStoreAliasing,
EXCEPTION_CheckFailed,
EXCEPTION_SkipBlock,
EXCEPTION_LFRQFull,
EXCEPTION_FloatingPoint,
EXCEPTION_FloatingPointNotAvailable,
EXCEPTION_DivideOverflow,
EXCEPTION_COUNT
};
static const int MAX_BB_BYTES = 127;
static const int MAX_BB_X86_INSNS = 60;
static const int MAX_BB_UOPS = 63;
static const int MAX_BB_PER_PAGE = 4096;
static const int MAX_TRANSOPS_PER_USER_INSN = 16;
extern const char* exception_names[EXCEPTION_COUNT];
static inline const char* exception_name(W64 exception) {
return (exception < EXCEPTION_COUNT) ? exception_names[exception] : "Unknown";
}
//
// Uniquely identifies any translation or basic block, including
// the context in which it was translated: x86-64 instruction set,
// kernel vs user mode, flag values, segmentation assumptions, etc.
//
// Most of this information is only relevant for full system PTLsim/X.
// The userspace PTLsim only needs the RIP, use64, df, etc.
//
struct Context;
struct RIPVirtPhysBase {
W64 rip;
W64 mfnlo:28, use64:1, kernel:1, padlo:2, mfnhi:28, df:1, padhi:3;
// 28 bits + 12 page offset bits = 40 bit physical addresses
static const Waddr INVALID = 0xfffffff;
ostream& print(ostream& os) const;
};
struct RIPVirtPhys: public RIPVirtPhysBase {
operator W64() const { return rip; }
RIPVirtPhys() { }
RIPVirtPhys(W64 rip) { this->rip = rip; }
RIPVirtPhys(Waddr rip, Waddr mfnlo, Waddr mfnhi, bool use64, bool kernelmode);
// Update use64, kernelmode, mfnlo and mfnhi by translating rip and (rip + 4095), respectively:
RIPVirtPhys& update(Context& ctx, int bytes = PAGE_SIZE);
// Make sure we don't accidentally cast to W64 for comparisons
bool operator ==(const RIPVirtPhys& b) const {
#ifdef PTLSIM_HYPERVISOR
const W64* ap = (const W64*)this;
const W64* bp = (const W64*)&b;
return ((ap[0] == bp[0]) & (ap[1] == bp[1]));
#else
return (rip == b.rip);
#endif
}
};
static inline ostream& operator <<(ostream& os, const RIPVirtPhysBase& rvp) { return rvp.print(os); }
static inline ostream& operator <<(ostream& os, const RIPVirtPhys& rvp) { return rvp.print(os); }
//
// Store Forwarding Register definition
//
// Cleverness alert: FLAG_INV is bit 1 in both regular ALU flags
// AND bit 1 in the lowest byte of SFR.physaddr. This is critical
// to making the synthesized simulator code work efficiently.
//
// REMEMBER: sfr.physaddr is >> 3 so it fits in 45 bits (vs 48).
//
struct SFR {
W64 data;
W64 addrvalid:1, invalid:1, datavalid:1, physaddr:45, bytemask:8, tag:8;
};
stringbuf& operator <<(stringbuf& sb, const SFR& sfr);
inline ostream& operator <<(ostream& os, const SFR& sfr) {
stringbuf sb;
sb << sfr;
return os << sb;
}
struct IssueState {
union {
struct {
W64 rddata;
W64 addr:48, rdflags:16;
} reg;
struct {
W64 rddata;
W64 physaddr:48, flags:8, lfrqslot:8;
} ldreg;
struct {
W64 riptaken;
W64 ripseq;
} brreg;
SFR st;
};
};
ostream& operator <<(ostream& os, const IssueState& ctx);
struct IssueInput {
W64 ra;
W64 rb;
W64 rc;
W16 raflags;
W16 rbflags;
W16 rcflags;
};
typedef W64 UserContext[ARCHREG_COUNT];
ostream& operator <<(ostream& os, const UserContext& ctx);
typedef byte X87Reg[10];
struct X87StatusWord {
W16 ie:1, de:1, ze:1, oe:1, ue:1, pe:1, sf:1, es:1, c0:1, c1:1, c2:1, tos:3, c3:1, b:1;
X87StatusWord() { }
X87StatusWord(const W16& w) { *((W16*)this) = w; }
operator W16() const { return *((W16*)this); }
};
struct X87ControlWord {
W16 im:1, dm:1, zm:1, om:1, um:1, pm:1, res1:2, pc:2, rc:2, y:1, res2:3;
X87ControlWord() { }
X87ControlWord(const W16& w) { *((W16*)this) = w; }
operator W16() const { return *((W16*)this); }
};
struct X87State {
X87ControlWord cw;
W16 reserved1;
X87StatusWord sw;
W16 reserved2;
W16 tw;
W16 reserved3;
W32 eip;
W16 cs;
W16 opcode;
W32 dataoffs;
W16 ds;
W16 reserved4;
X87Reg stack[8];
};
union SSEType {
double d;
struct { float lo, hi; } f;
W64 w64;
struct { W32 lo, hi; } w32;
SSEType() { }
SSEType(W64 w) { w64 = w; }
operator W64() const { return w64; }
};
struct X87RegPadded {
X87Reg reg;
byte pad[6];
} packedstruct;
struct XMMReg {
W64 lo, hi;
};
struct FXSAVEStruct {
X87ControlWord cw;
X87StatusWord sw;
W16 tw;
W16 fop;
union {
struct {
W32 eip;
W16 cs;
W16 reserved1;
W32 dp;
W16 ds;
W16 reserved2;
} use32;
struct {
W64 rip;
W64 rdp;
} use64;
};
W32 mxcsr;
W32 mxcsr_mask;
X87RegPadded fpregs[8];
XMMReg xmmregs[16];
};
inline W64 x87_fp_80bit_to_64bit(const X87Reg* x87reg) {
W64 reg64;
asm("fldt (%[mem80])\n"
"fstpl %[mem64]\n"
: : [mem64] "m" (reg64), [mem80] "r" (x87reg));
return reg64;
}
inline void x87_fp_64bit_to_80bit(X87Reg* x87reg, W64 reg64) {
asm("fldl %[mem64]\n"
"fstpt (%[mem80])\n"
: : [mem80] "r" (*x87reg), [mem64] "m" (reg64) : "memory");
}
inline void cpu_fsave(X87State& state) {
asm volatile("fsave %[state]" : [state] "=m" (*&state));
}
inline void cpu_frstor(X87State& state) {
asm volatile("frstor %[state]" : : [state] "m" (*&state));
}
inline W16 cpu_get_fpcw() {
W16 fpcw;
asm volatile("fstcw %[fpcw]" : [fpcw] "=m" (fpcw));
return fpcw;
}
inline void cpu_set_fpcw(W16 fpcw) {
asm volatile("fldcw %[fpcw]" : : [fpcw] "m" (fpcw));
}
struct SegmentDescriptor {
W16 limit0;
W16 base0;
W16 base1:8, type:4, s:1, dpl:2, p:1;
W16 limit:4, avl:1, l:1, d:1, g:1, base2:8;
SegmentDescriptor() { }
SegmentDescriptor(W64 rawbits) { *((W64*)this) = rawbits; }
operator W64() const { return *((W64*)this); }
void setbase(W64 addr) {
assert((addr >> 32) == 0); // must use FSBASE and GSBASE MSRs for 64-bit addresses
base0 = lowbits(addr, 16);
base1 = bits(addr, 16, 8);
base2 = bits(addr, 24, 8);
}
W64 getbase() const {
return base0 + (base1 << 16) + (base2 << 24);
}
void setlimit(W64 size) {
g = (size >= (1 << 20));
if likely (g) size = ceil(size, 4096) >> 12;
limit0 = lowbits(size, 16);
limit = bits(size, 16, 4);
}
W64 getlimit() const {
W64 size = limit0 + (limit << 16);
if likely (g) size <<= 12;
return size;
}
} packedstruct;
// Encoding of segment numbers:
enum { SEGID_ES = 0, SEGID_CS = 1, SEGID_SS = 2, SEGID_DS = 3, SEGID_FS = 4, SEGID_GS = 5, SEGID_COUNT = 6 };
ostream& operator <<(ostream& os, const SegmentDescriptor& seg);
struct SegmentDescriptorCache {
W32 selector;
W32 present:1, use64:1, use32:1, supervisor:1, dpl:2;
W64 base;
W64 limit;
SegmentDescriptorCache() { }
// NOTE: selector field must be valid already; it is not updated!
SegmentDescriptorCache& operator =(const SegmentDescriptor& desc) {
present = desc.p;
use64 = desc.l;
use32 = desc.d;
supervisor = desc.s;
dpl = desc.dpl;
base = desc.getbase();
limit = desc.getlimit();
return *this;
}
// Make 64-bit flat
void flatten() {
present = 1;
use64 = 1;
use32 = 0;
supervisor = 0;
dpl = 3;
base = 0;
limit = 0xffffffffffffffffULL;
}
};
ostream& operator <<(ostream& os, const SegmentDescriptorCache& seg);
//
// These are x86 exceptions, not PTLsim internal exceptions
//
enum {
EXCEPTION_x86_divide = 0,
EXCEPTION_x86_debug = 1,
EXCEPTION_x86_nmi = 2,
EXCEPTION_x86_breakpoint = 3,
EXCEPTION_x86_overflow = 4,
EXCEPTION_x86_bounds = 5,
EXCEPTION_x86_invalid_opcode = 6,
EXCEPTION_x86_fpu_not_avail = 7,
EXCEPTION_x86_double_fault = 8,
EXCEPTION_x86_coproc_overrun = 9,
EXCEPTION_x86_invalid_tss = 10,
EXCEPTION_x86_seg_not_present = 11,
EXCEPTION_x86_stack_fault = 12,
EXCEPTION_x86_gp_fault = 13,
EXCEPTION_x86_page_fault = 14,
EXCEPTION_x86_spurious_int = 15,
EXCEPTION_x86_fpu = 16,
EXCEPTION_x86_unaligned = 17,
EXCEPTION_x86_machine_check = 18,
EXCEPTION_x86_sse = 19,
EXCEPTION_x86_count = 20,
};
extern const char* x86_exception_names[256];
struct PageFaultErrorCode {
byte p:1, rw:1, us:1, rsv:1, nx:1, pad:3;
RawDataAccessors(PageFaultErrorCode, byte);
};
ostream& operator <<(ostream& os, const PageFaultErrorCode& pfec);
//
// Information needed to update a PTE on commit.
//
// There is also a ptwrite bit that is set whenever a page
// table page is technically read only, but the user code
// may attempt to store to it anyway under the assumption
// that the hypervisor will trap the store, validate the
// written PTE value and emulate the store as if it was
// to a normal read-write page.
//
struct PTEUpdateBase {
byte a:1, d:1, ptwrite:1, pad:5;
};
struct PTEUpdate: public PTEUpdateBase {
RawDataAccessors(PTEUpdate, byte);
};
#ifdef PTLSIM_HYPERVISOR
struct TrapTarget {
#ifdef __x86_64__
W64 rip:48, cpl:2, maskevents:1, cs:13;
#else
W32 rip;
W16 pad;
W16 cs;
#endif
};
union VirtAddr {
struct { W64 offset:12, level1:9, level2:9, level3:9, level4:9, signext:16; } lm;
struct { W64 offset:12, level1:9, level2:9, level3:9, level4:9, signext:16; } pae;
struct { W32 offset:12, level1:10, level2:10; } x86;
RawDataAccessors(VirtAddr, W64);
};
#define DefinePTESetField(T, func, field) inline T func(W64 val) const { T pte(*this); pte.field = val; return pte; }
typedef struct Level4PTE {
W64 p:1, rw:1, us:1, pwt:1, pcd:1, a:1, ign:1, mbz:2, avl:3, mfn:40, avlhi:11, nx:1;
RawDataAccessors(Level4PTE, W64);
DefinePTESetField(Level4PTE, P, p);
DefinePTESetField(Level4PTE, W, rw);
DefinePTESetField(Level4PTE, U, us);
DefinePTESetField(Level4PTE, WT, pwt);
DefinePTESetField(Level4PTE, CD, pcd);
DefinePTESetField(Level4PTE, A, a);
DefinePTESetField(Level4PTE, NX, nx);
DefinePTESetField(Level4PTE, AVL, avl);
DefinePTESetField(Level4PTE, MFN, mfn);
};
struct Level3PTE {
W64 p:1, rw:1, us:1, pwt:1, pcd:1, a:1, ign:1, mbz:2, avl:3, mfn:40, avlhi:11, nx:1;
RawDataAccessors(Level3PTE, W64);
DefinePTESetField(Level3PTE, P, p);
DefinePTESetField(Level3PTE, W, rw);
DefinePTESetField(Level3PTE, U, us);
DefinePTESetField(Level3PTE, WT, pwt);
DefinePTESetField(Level3PTE, CD, pcd);
DefinePTESetField(Level3PTE, A, a);
DefinePTESetField(Level3PTE, NX, nx);
DefinePTESetField(Level3PTE, AVL, avl);
DefinePTESetField(Level3PTE, MFN, mfn);
};
struct Level2PTE {
W64 p:1, rw:1, us:1, pwt:1, pcd:1, a:1, d:1, psz:1, mbz:1, avl:3, mfn:40, avlhi:11, nx:1;
RawDataAccessors(Level2PTE, W64);
DefinePTESetField(Level2PTE, P, p);
DefinePTESetField(Level2PTE, W, rw);
DefinePTESetField(Level2PTE, U, us);
DefinePTESetField(Level2PTE, WT, pwt);
DefinePTESetField(Level2PTE, CD, pcd);
DefinePTESetField(Level2PTE, A, a);
DefinePTESetField(Level2PTE, D, d);
DefinePTESetField(Level2PTE, PSZ, psz);
DefinePTESetField(Level2PTE, NX, nx);
DefinePTESetField(Level2PTE, AVL, avl);
DefinePTESetField(Level2PTE, MFN, mfn);
};
struct Level1PTE {
W64 p:1, rw:1, us:1, pwt:1, pcd:1, a:1, d:1, pat:1, g:1, avl:3, mfn:40, avlhi:11, nx:1;
RawDataAccessors(Level1PTE, W64);
void accum(const Level1PTE& l) { p &= l.p; rw &= l.rw; us &= l.us; nx |= l.nx; }
void accum(const Level2PTE& l) { p &= l.p; rw &= l.rw; us &= l.us; nx |= l.nx; }
void accum(const Level3PTE& l) { p &= l.p; rw &= l.rw; us &= l.us; nx |= l.nx; }
void accum(const Level4PTE& l) { p &= l.p; rw &= l.rw; us &= l.us; nx |= l.nx; }
DefinePTESetField(Level1PTE, P, p);
DefinePTESetField(Level1PTE, W, rw);
DefinePTESetField(Level1PTE, U, us);
DefinePTESetField(Level1PTE, WT, pwt);
DefinePTESetField(Level1PTE, CD, pcd);
DefinePTESetField(Level1PTE, A, a);
DefinePTESetField(Level1PTE, D, d);
DefinePTESetField(Level1PTE, G, g);
DefinePTESetField(Level1PTE, NX, nx);
DefinePTESetField(Level1PTE, AVL, avl);
DefinePTESetField(Level1PTE, MFN, mfn);
};
ostream& operator <<(ostream& os, const Level1PTE& pte);
ostream& operator <<(ostream& os, const Level2PTE& pte);
ostream& operator <<(ostream& os, const Level3PTE& pte);
ostream& operator <<(ostream& os, const Level4PTE& pte);
#define X86_CR0_PE 0x00000001 // Enable Protected Mode (RW)
#define X86_CR0_MP 0x00000002 // Monitor Coprocessor (RW)
#define X86_CR0_EM 0x00000004 // Require FPU Emulation (RO)
#define X86_CR0_TS 0x00000008 // Task Switched (RW)
#define X86_CR0_ET 0x00000010 // Extension type (RO)
#define X86_CR0_NE 0x00000020 // Numeric Error Reporting (RW)
#define X86_CR0_WP 0x00010000 // Supervisor Write Protect (RW)
#define X86_CR0_AM 0x00040000 // Alignment Checking (RW)
#define X86_CR0_NW 0x20000000 // Not Write-Through (RW)
#define X86_CR0_CD 0x40000000 // Cache Disable (RW)
#define X86_CR0_PG 0x80000000 // Paging (RW)
struct CR0 {
W64 pe:1, mp:1, em:1, ts:1, et:1, ne:1, res6:10, wp:1, res17:1, am:1, res19:10, nw:1, cd:1, pg:1, res32:32;
RawDataAccessors(CR0, W64);
};
ostream& operator <<(ostream& os, const CR0& cr0);
// CR2 is page fault linear address
// CR3 is page table physical base
#define X86_CR4_VME 0x0001 // enable vm86 extensions
#define X86_CR4_PVI 0x0002 // virtual interrupts flag enable
#define X86_CR4_TSD 0x0004 // disable time stamp at ipl 3
#define X86_CR4_DE 0x0008 // enable debugging extensions
#define X86_CR4_PSE 0x0010 // enable page size extensions
#define X86_CR4_PAE 0x0020 // enable physical address extensions
#define X86_CR4_MCE 0x0040 // Machine check enable
#define X86_CR4_PGE 0x0080 // enable global pages
#define X86_CR4_PCE 0x0100 // enable performance counters at ipl 3
#define X86_CR4_OSFXSR 0x0200 // enable fast FPU save and restore
#define X86_CR4_OSXMMEXCPT 0x0400 // enable unmasked SSE exceptions
#define X86_CR4_VMXE 0x2000 // enable VMX
struct CR4 {
W64 vme:1, pvi:1, tsd:1, de:1, pse:1, pae:1, mce:1, pge:1, pce:1, osfxsr:1, osxmmexcpt:1, res11:53;
RawDataAccessors(CR4, W64);
};
ostream& operator <<(ostream& os, const CR4& cr4);
struct DebugReg {
W64 l0:1, g0:1, l1:1, g1:1, l2:1, g2:1, l3:1, g3:1, le:1, ge:1, res1:3, gd:1, res2:2,
t0:2, s0:2, t1:2, s1:2, t2:2, s2:2, t3:2, s3:2;
RawDataAccessors(DebugReg, W64);
};
enum {
DEBUGREG_TYPE_EXEC = 0,
DEBUGREG_TYPE_WRITE = 1,
DEBUGREG_TYPE_IO = 2,
DEBUGREG_TYPE_RW = 3,
};
enum {
DEBUGREG_SIZE_1 = 0,
DEBUGREG_SIZE_2 = 1,
DEBUGREG_SIZE_8 = 2,
DEBUGREG_SIZE_4 = 3,
};
// Extended Feature Enable Register
struct EFER {
W32 sce:1, pad1:7, lme:1, pad2:1, lma:1, nxe:1, svme:1, pad3:1, ffxsr:1, pad4:17;
RawDataAccessors(EFER, W32);
};
struct vcpu_guest_context;
struct vcpu_extended_context;
Level1PTE page_table_walk(W64 rawvirt, W64 toplevel_mfn, bool do_special_translations = true);
void page_table_acc_dirty_update(W64 rawvirt, W64 toplevel_mfn, const PTEUpdate& update);
W64 host_mfn_to_sim_mfn(W64 hostmfn);
W64 sim_mfn_to_host_mfn(W64 simmfn);
//
// This is the same format as Xen's vcpu_runstate_info_t
// but solves some header file problems by placing it here.
//
struct RunstateInfo {
// VCPU's current state (RUNSTATE_*).
int state;
// When was current state entered (system time, ns)?
W64 state_entry_time;
//
// Time spent in each RUNSTATE_* (ns). The sum of these times is
// guaranteed not to drift from system time.
//
W64 time[4];
};
#else
// Dummy type for usermode
typedef W64 Level1PTE;
#endif
//
// This is the complete x86 user-visible context for a single VCPU.
// It includes both the renamable registers (commitarf) as well as
// all relevant control registers, MSRs, x87 FP state, exception
// and interrupt vectors, Xen-specific data and so forth.
//
// The ContextBase structure must be less than 4096 bytes (1 page);
// the actual Context structure rounds the size up to a page
//
// PTLsim cores will need to define other per-VCPU structures to
// hold their internal state.
//
struct ContextBase {
W64 commitarf[64];
int vcpuid;
SegmentDescriptorCache seg[SEGID_COUNT];
W64 swapgs_base;
W64 fpstack[8];
X87ControlWord fpcw;
MXCSR mxcsr;
byte use32; // depends on active CS descriptor
byte use64; // depends on active CS descriptor
Waddr virt_addr_mask;
W64 exception;
Waddr error_code;
W32 internal_eflags; // parts of EFLAGS that are infrequently updated
#ifdef PTLSIM_HYPERVISOR
Waddr x86_exception;
byte kernel_mode; // VGCF_IN_KERNEL
byte kernel_in_syscall; // VGCF_IN_SYSCALL
byte i387_valid; // VGCF_I387_VALID
byte failsafe_disables_events;
byte syscall_disables_events;
byte saved_upcall_mask;
byte running;
byte dirty; // VCPU was just brought online
CR0 cr0;
Waddr cr1, cr2, cr3;
CR4 cr4;
Waddr cr5, cr6, cr7;
Waddr kernel_ptbase_mfn, user_ptbase_mfn;
DebugReg dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7;
Waddr kernel_ss, kernel_sp;
Waddr event_callback_rip;
Waddr failsafe_callback_rip;
Waddr syscall_rip;
Waddr fs_base;
Waddr gs_base_kernel;
Waddr gs_base_user;
EFER efer;
struct TrapTarget idt[256]; // Virtual IDT
Waddr ldtvirt;
Waddr gdtpages[16];
W16 ldtsize;
W16 gdtsize;
Waddr vm_assist;
W64 base_tsc;
W64 base_system_time;
W64 core_freq_hz;
double sys_time_cycles_to_nsec_coeff;
W16s virq_to_port[32];
W64 timer_cycle;
W64 poll_timer_cycle;
RunstateInfo runstate;
RunstateInfo* user_runstate;
static const int PTE_CACHE_SIZE = 16;
W64 cached_pte_virt[PTE_CACHE_SIZE];
Level1PTE cached_pte[PTE_CACHE_SIZE];
#else
// Always running in userspace version:
byte running;
#endif
inline void reset() {
setzero(commitarf);
#ifdef PTLSIM_HYPERVISOR
setzero(cached_pte_virt);
setzero(cached_pte);
#endif
exception = 0;
}
};
// Round up to a full page:
struct Context: public ContextBase {
byte padding[PAGE_SIZE - sizeof(ContextBase)];
void propagate_x86_exception(byte exception, W32 errorcode = 0, Waddr virtaddr = 0);
Waddr check_and_translate(Waddr virtaddr, int sizeshift, bool store, bool internal, int& exception, PageFaultErrorCode& pfec, PTEUpdate& pteupdate, Level1PTE& pteused);
Waddr check_and_translate(Waddr virtaddr, int sizeshift, bool store, bool internal, int& exception, PageFaultErrorCode& pfec, PTEUpdate& pteupdate) {
Level1PTE dummy;
return check_and_translate(virtaddr, sizeshift, store, internal, exception, pfec, pteupdate, dummy);
}
int copy_to_user(Waddr target, void* source, int bytes, PageFaultErrorCode& pfec, Waddr& faultaddr);
int copy_from_user(void* target, Waddr source, int bytes, PageFaultErrorCode& pfec, Waddr& faultaddr, bool forexec, Level1PTE& ptelo, Level1PTE& ptehi);
int copy_from_user(void* target, Waddr source, int bytes, PageFaultErrorCode& pfec, Waddr& faultaddr, bool forexec = false) {
Level1PTE ptelo;
Level1PTE ptehi;
return copy_from_user(target, source, bytes, pfec, faultaddr, forexec, ptelo, ptehi);
}
int copy_from_user(void* target, Waddr source, int bytes) {
PageFaultErrorCode pfec;
Waddr faultaddr;
return copy_from_user(target, source, bytes, pfec, faultaddr, false);
}
int copy_to_user(Waddr target, void* source, int bytes) {
PageFaultErrorCode pfec;
Waddr faultaddr;
return copy_to_user(target, source, bytes, pfec, faultaddr);
}
int write_segreg(unsigned int segid, W16 selector);
void reload_segment_descriptor(unsigned int segid, W16 selector);
void swapgs();
void init();
void fxsave(FXSAVEStruct& state);
void fxrstor(const FXSAVEStruct& state);
Context() { }
#ifdef PTLSIM_HYPERVISOR
void restorefrom(const vcpu_guest_context& ctx);
void restorefrom(const vcpu_extended_context& ctx);
void saveto(vcpu_guest_context& ctx);
void saveto(vcpu_extended_context& ctx);
bool gdt_entry_valid(W16 idx);
SegmentDescriptor get_gdt_entry(W16 idx);
#ifndef PTLSIM_PUBLIC_ONLY
Level1PTE virt_to_host_pte(W64 rawvirt);
Level1PTE virt_to_pte(W64 rawvirt);
#endif
W64 virt_to_pte_phys_addr(Waddr virtaddr, int level = 0);
int virt_to_pte_span(Level1PTE* ptes, W64 virtaddr, int pagecount);
// Flush the context mini-TLB and propagate flush to any core-specific TLBs
void flush_tlb(bool propagate_flush_to_model = true);
void flush_tlb_virt(Waddr virtaddr, bool propagate_flush_to_model = true);
void print_tlb(ostream& os);
void update_pte_acc_dirty(W64 rawvirt, const PTEUpdate& update) {
return page_table_acc_dirty_update(rawvirt, cr3 >> 12, update);
}
bool create_bounce_frame(W16 target_cs, Waddr target_rip, int action);
bool check_events() const;
bool event_upcall();
bool change_runstate(int newstate);
int page_table_level_count() const { return 4; }
#else
void update_pte_acc_dirty(W64 rawvirt, const PTEUpdate& update) { }
void update_shadow_segment_descriptors();
#endif
};
ostream& operator <<(ostream& os, const Context& ctx);
#ifndef PTLSIM_HYPERVISOR
extern Context ctx;
#endif
// Other flags not defined above
enum {
FLAG_TF = (1 << 8),
FLAG_IF = (1 << 9),
FLAG_DF = (1 << 10),
FLAG_IOPL = (1 << 12) | (1 << 13),
FLAG_NT = (1 << 14),
FLAG_RF = (1 << 16),
FLAG_VM = (1 << 17),
FLAG_AC = (1 << 18),
FLAG_VIF = (1 << 19),
FLAG_VIP = (1 << 20),
FLAG_ID = (1 << 21),
FLAG_COUNT = 22,
};
//
// Operation Classes
//
#define OPCLASS_LOGIC (1 << 0)
#define OPCLASS_ADDSUB (1 << 1)
#define OPCLASS_ADDSUBC (1 << 2)
#define OPCLASS_ADDSHIFT (1 << 3)
#define OPCLASS_ADD (OPCLASS_ADDSUB|OPCLASS_ADDSUBC|OPCLASS_ADDSHIFT)
#define OPCLASS_SELECT (1 << 4)
#define OPCLASS_COMPARE (1 << 5)
#define OPCLASS_COND_BRANCH (1 << 6)
#define OPCLASS_INDIR_BRANCH (1 << 7)
#define OPCLASS_UNCOND_BRANCH (1 << 8)
#define OPCLASS_ASSIST (1 << 9)
#define OPCLASS_BARRIER (OPCLASS_ASSIST)
#define OPCLASS_BRANCH (OPCLASS_COND_BRANCH|OPCLASS_INDIR_BRANCH|OPCLASS_UNCOND_BRANCH|OPCLASS_ASSIST)
#define OPCLASS_LOAD (1 << 11)
#define OPCLASS_STORE (1 << 12)
#define OPCLASS_PREFETCH (1 << 13)
#define OPCLASS_FENCE ((1 << 10) | OPCLASS_STORE)
#define OPCLASS_MEM (OPCLASS_LOAD|OPCLASS_STORE|OPCLASS_PREFETCH|OPCLASS_FENCE)
#define OPCLASS_SIMPLE_SHIFT (1 << 14)
#define OPCLASS_SHIFTROT (1 << 15)
#define OPCLASS_MULTIPLY (1 << 16)
#define OPCLASS_BITSCAN (1 << 17)
#define OPCLASS_FLAGS (1 << 18)
#define OPCLASS_CHECK (1 << 19)
#define OPCLASS_CONDITIONAL (OPCLASS_SELECT|OPCLASS_COND_BRANCH|OPCLASS_CHECK)
#define OPCLASS_ALU_SIZE_MERGING (OPCLASS_LOGIC|OPCLASS_ADD|OPCLASS_SELECT|OPCLASS_SIMPLE_SHIFT|OPCLASS_SHIFTROT|OPCLASS_MULTIPLY|OPCLASS_BITSCAN)
#define OPCLASS_FP_ALU (1 << 20)
#define OPCLASS_FP_DIVSQRT (1 << 21)
#define OPCLASS_FP_COMPARE (1 << 22)
#define OPCLASS_FP_PERMUTE (1 << 23)
#define OPCLASS_FP_CONVERTI2F (1 << 24)
#define OPCLASS_FP_CONVERTF2I (1 << 25)
#define OPCLASS_FP_CONVERTFP (1 << 26)