summaryrefslogtreecommitdiff
path: root/aarch64/elfmain.sail
diff options
context:
space:
mode:
authorAlastair Reid2018-06-26 17:02:33 +0100
committerAlastair Reid2018-06-26 17:03:27 +0100
commit16c63bce08d1b7f99320cc669f69e195638e6a65 (patch)
treed81e1f69965d393d6dacaee895668ced4c8992bc /aarch64/elfmain.sail
parent91c0437a14f67953b6672d0633e2c68de174aa11 (diff)
Main: attempt to capture AArch64 execution cycle
Diffstat (limited to 'aarch64/elfmain.sail')
-rw-r--r--aarch64/elfmain.sail180
1 files changed, 180 insertions, 0 deletions
diff --git a/aarch64/elfmain.sail b/aarch64/elfmain.sail
new file mode 100644
index 00000000..7be920c3
--- /dev/null
+++ b/aarch64/elfmain.sail
@@ -0,0 +1,180 @@
+$include <elf.sail>
+
+val read_register = "reg_deref" : forall ('a : Type). register('a) -> 'a effect {rreg}
+
+// EL1 physical EL2 physical EL3 physical EL1 virtual, EL2 virtual
+let CNT_CVAL = [ref CNTP_CVAL_EL0, ref CNTHP_CVAL_EL2, ref CNTPS_CVAL_EL1, ref CNTV_CVAL_EL0, ref CNTHV_CVAL_EL2]
+let CNT_TVAL = [ref CNTP_TVAL_EL0, ref CNTHP_TVAL_EL2, ref CNTPS_TVAL_EL1, ref CNTV_TVAL_EL0, ref CNTHV_TVAL_EL2]
+let CNT_CTL = [ref CNTP_CTL_EL0, ref CNTHP_CTL_EL2, ref CNTPS_CTL_EL1, ref CNTV_CTL_EL0, ref CNTHV_CTL_EL2 ]
+let CNT_CTL = [ref CNTP_CTL_EL0, ref CNTHP_CTL_EL2, ref CNTPS_CTL_EL1, ref CNTV_CTL_EL0, ref CNTHV_CTL_EL2 ]
+let CNT_IRQ = [0x0000_000d, 0x0000_000a, 0x0000_03ff, 0x0000_000b, 0x0000_03ff ]
+// No IRQ No IRQ?
+
+// SGI Interrupts are 0-15, PPI interrupts are 16-31, so SPI interrupts have an offset of 32.
+let SPI_OFFSET = 32
+
+// Simple top level fetch and execute loop.
+val fetch_and_execute : unit -> unit effect {escape, undef, wreg, rreg, rmem, wmem}
+
+function fetch_and_execute () = {
+ var cycle_counter : int = 0;
+ while true do {
+ cycle_counter = cycle_counter + 1;
+ try {
+ // Increment the counter
+ CNTPCT_EL0 = CNTPCT_EL0 + 1;
+ CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2;
+
+ // Timer value view for each timer
+ foreach (timer from 0 to 4) {
+ let TVAL = CNT_TVAL[timer];
+ let nextTVAL = read_register(TVAL) - 1;
+ (*TVAL) = nextTVAL;
+
+ if nextTVAL == 0x0000_0000 then {
+ _IRQPending = true;
+ AArch64_TakePhysicalIRQException()
+ }
+ };
+
+ // Handle the Kernel event stream, if enabled by CNTKCTL_EL1[2].
+ if CNTKCTL_EL1[2] == bitone then {
+ let mask = LSL(ZeroExtend(0x1, 64), UInt(CNTKCTL_EL1[7 .. 4]));
+
+ // Trigger event stream on either rising bit (0-1, bitzero) or falling (1-0, bitone)
+ let trigger : bool = if CNTKCTL_EL1[3] == bitzero then {
+ ((CNTVCT_EL0 - 1) & mask) == Zeros() & (CNTVCT_EL0 & mask) != Zeros()
+ } else {
+ ((CNTVCT_EL0 - 1) & mask) != Zeros() & (CNTVCT_EL0 & mask) == Zeros()
+ };
+
+ if trigger & PSTATE.I == bitzero then {
+ _IRQPending = true;
+ AArch64_TakePhysicalIRQException()
+ }
+ };
+
+ // Handle the Hypervisor event stream, if enabled by CNTHCTL_EL2[2].
+ if CNTHCTL_EL2[2] == bitone then {
+ let mask = LSL(ZeroExtend(0x1, 64), UInt(CNTHCTL_EL2[7 .. 4]));
+
+ // Trigger event stream on either rising bit (0-1, bitzero) or falling (1-0, bitone)
+ let trigger : bool = if CNTHCTL_EL2[3] == bitzero then {
+ ((CNTPCT_EL0 - 1) & mask) == Zeros() & (CNTPCT_EL0 & mask) != Zeros()
+ } else {
+ ((CNTPCT_EL0 - 1) & mask) != Zeros() & (CNTPCT_EL0 & mask) == Zeros()
+ };
+
+ if trigger & PSTATE.I == bitzero then {
+ prerr("[Clock] Tick\n");
+ _IRQPending = true;
+ AArch64_TakePhysicalIRQException()
+ }
+ };
+
+ var prevEL = PSTATE.EL;
+ var prevI = PSTATE.I;
+
+ // Store the old values of the Counter-timer Kernel/Hypervisor Control
+ // registers, as we want to figure out when they changes.
+ var prevCNTKCTL_EL1 = CNTKCTL_EL1;
+ var prevCNTHCTL_EL2 = CNTHCTL_EL2;
+
+ if ~(__Sleeping()) then {
+ var ok = false;
+
+ // Check for pending interrupts
+ var interrupt_req : InterruptReq = undefined;
+ interrupt_req.take_SE = true; interrupt_req.take_vSE = true;
+ interrupt_req.take_IRQ = true; interrupt_req.take_vIRQ = true;
+ interrupt_req.take_FIQ = true; interrupt_req.take_vFIQ = true;
+ ok = ~(TakePendingInterrupts(interrupt_req));
+
+ try {
+ __currentInstr = __fetchA64();
+ ok = true;
+ } catch {
+ Error_ExceptionTaken() => {
+ print("Exception taken during IFetch\n")
+ },
+ _ => {
+ print("Exiting due to unhandled exception during fetch\n");
+ exit()
+ }
+ };
+ if ok then {
+ try {
+ ok = false;
+ __PC_changed = false;
+ ShouldAdvanceIT = (PSTATE.nRW == [bitone]) & (PSTATE.T == [bitone]);
+ decode(__currentInstr);
+ if ~(__PC_changed) then _PC = _PC + 4 else ();
+ if ShouldAdvanceIT then AArch32_ITAdvance() else ();
+ SSAdvance();
+ __UpdateSystemCounter(); // should this happen even if sleeping?
+ ok = true;
+ } catch {
+ Error_See(_) => UndefinedFault(),
+ Error_ReservedEncoding(_) => UndefinedFault(),
+ Error_Undefined() => UndefinedFault(),
+ Error_ExceptionTaken() => {
+ print("Exception taken during IFetch\n")
+ },
+ _ => {
+ print("Exiting due to unhandled exception during decode/execute\n");
+ exit()
+ }
+ }
+ };
+ if ~(ok) then {
+ print(concat_str("Yoiks: something went wrong at ", concat_str(DecStr(cycle_counter), "\n")));
+ }
+ };
+
+ // We want to keep track of what exception level we are in for debugging purposes.
+ if UInt(prevEL) > UInt(PSTATE.EL) then {
+ prerr_bits("[Sail] Exception level dropped to: ", PSTATE.EL)
+ };
+ if prevI != PSTATE.I then {
+ prerr_bits("[Sail] PSTATE.I changed to: ", PSTATE.I);
+ };
+ if prevCNTKCTL_EL1 != CNTKCTL_EL1 then {
+ prerr_bits("[Clock] CNTKCTL_EL1 changed to ", CNTKCTL_EL1);
+ };
+ if prevCNTHCTL_EL2 != CNTHCTL_EL2 then {
+ prerr_bits("[Clock] CNTHCTL_EL2 changed to ", CNTHCTL_EL2);
+ }
+
+ } catch {
+ Error_See(str) if str == "HINT" => (),
+ Error_ExceptionTaken(_) => {
+ // enable_tracing()
+ ()
+ },
+ _ => {
+ prerr("Exiting due to unhandled exception\n");
+ exit()
+ }
+ };
+ __EndCycle()
+ }
+}
+
+let COLD_RESET : bool = true
+
+val "load_raw" : (bits(64), string) -> unit
+
+val init : unit -> unit effect {escape, undef, rreg, wreg}
+
+function init() = {
+ __currentInstrLength = 4;
+ TakeReset(COLD_RESET);
+ _PC = CFG_RVBAR;
+}
+
+val main : unit -> unit effect {escape, undef, wreg, rreg, rmem, wmem}
+
+function main() = {
+ init();
+ fetch_and_execute()
+}