Skip to content

Commit 7adeecf

Browse files
Privileged instructions can now be proxied by interrupt 13 (#66)
* Privileged instructions can now be proxied by int13 * Fix regular runlevel zero
1 parent 5efb2a5 commit 7adeecf

File tree

7 files changed

+121
-18
lines changed

7 files changed

+121
-18
lines changed

lua/entities/gmod_wire_gpu/cl_gpuvm.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,12 @@ function VM:Reset()
292292
self.INTR = 0 -- Handling an interrupt
293293
self.BlockStart = 0 -- Start of the block
294294
self.BlockSize = 0 -- Size of the block
295+
self.QUOTIMER = 0
296+
self.QUOCMP = 0
297+
self.PreqOperand1 = 0
298+
self.PreqOperand2 = 0
299+
self.PreqHandled = 0
300+
self.PreqReturn = 0
295301

296302
-- Reset internal GPU registers
297303
-- [131072]..[2097151] - Extended GPU memory (2MB GPU)

lua/entities/gmod_wire_spu/cl_spuvm.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ function VM:Reset()
137137
self.INTR = 0 -- Handling an interrupt
138138
self.BlockStart = 0 -- Start of the block
139139
self.BlockSize = 0 -- Size of the block
140+
self.QUOTIMER = 0
141+
self.QUOCMP = 0
142+
self.PreqOperand1 = 0
143+
self.PreqOperand2 = 0
144+
self.PreqHandled = 0
145+
self.PreqReturn = 0
140146

141147
self.EntryPoint0 = 0
142148
self.EntryPoint1 = 0

lua/wire/cpulib.lua

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ end
804804
-- TR: trigonometric syntax operand
805805
-- OL: old mnemonic for the instruction
806806
-- BL: instruction supports block prefix
807+
-- PR: privileged opcode but with custom handler(for example, if it needs to get a value to write to an operand)
807808
-- Op1 - operand 1 name
808809
-- Op2 - operand 2 name
809810

@@ -824,7 +825,7 @@ end
824825
-- INT: 48-bit signed integer
825826

826827
CPULib.InstructionTable = {}
827-
local W1,R0,OB,UB,CB,TR,OL,BL = 1,2,4,8,16,32,64,128
828+
local W1,R0,OB,UB,CB,TR,OL,BL,PR = 1,2,4,8,16,32,64,128,256
828829

829830
local function Bit(x,n) return (math.floor(x / n) % 2) == 1 end
830831
local function Entry(Set,Opc,Mnemonic,Ops,Version,Flags,Op1,Op2,Reference)
@@ -846,6 +847,7 @@ local function Entry(Set,Opc,Mnemonic,Ops,Version,Flags,Op1,Op2,Reference)
846847
Trigonometric = Bit(Flags,TR),
847848
Old = Bit(Flags,OL),
848849
BlockPrefix = Bit(Flags,BL),
850+
PrivilegedRequester = Bit(Flags,PR)
849851
})
850852
end
851853
local function CPU(...) Entry("CPU",...) end
@@ -880,7 +882,8 @@ CPULib.FlagLookup = {
880882
["CB"] = CB,
881883
["TR"] = TR,
882884
["OL"] = OL,
883-
["BL"] = BL
885+
["BL"] = BL,
886+
["PR"] = PR
884887
}
885888

886889
-- Parses an array of flags into a single number from a lookup table by name
@@ -1099,7 +1102,7 @@ CPU(012, "MUL", 2, 1.00, 0, "X", "Y", "X = X * Y"
10991102
CPU(013, "DIV", 2, 1.00, 0, "X", "Y", "X = X / Y")
11001103
CPU(014, "MOV", 2, 1.00, 0, "X", "Y", "X = Y")
11011104
CPU(015, "CMP", 2, 1.00, 0, "X", "Y", "Compare X and Y. Use with conditional branching instructions")
1102-
CPU(016, "RD", 2, 1.00, R0+OB, "X", "PTR", "Read value from memory by pointer PTR")
1105+
CPU(016, "RD", 2, 1.00, PR+OB, "X", "PTR", "Read value from memory by pointer PTR")
11031106
CPU(017, "WD", 2, 1.00, R0+OB, "PTR", "Y", "Write value to memory by pointer PTR")
11041107
CPU(018, "MIN", 2, 1.00, 0, "X", "Y", "Set X to smaller value out of X and Y")
11051108
CPU(019, "MAX", 2, 1.00, 0, "X", "Y", "Set X to bigger value out of X and Y")
@@ -1235,7 +1238,7 @@ CPU(117, "LEAVE", 0, 10.00, 0, "", "", "Leave subr
12351238
CPU(118, "STM", 0, 10.00, R0, "", "", "Enable extended memory mode")
12361239
CPU(119, "CLM", 0, 10.00, R0, "", "", "Disable extended memory mode")
12371240
---- Dec 12 -------------------------------------------------------------------------------------------------------------------------------------
1238-
CPU(120, "CPUGET", 2, 5.00, R0, "X", "IDX", "Read internal processor register IDX")
1241+
CPU(120, "CPUGET", 2, 5.00, PR, "X", "IDX", "Read internal processor register IDX")
12391242
CPU(121, "CPUSET", 2, 5.00, R0, "IDX", "Y", "Write internal processor register IDX")
12401243
CPU(122, "SPP", 2, 5.00, R0+BL, "PAGE", "IDX", "Set page flag IDX")
12411244
CPU(123, "CPP", 2, 5.00, R0+BL, "PAGE", "IDX", "Clear page flag IDX")
@@ -1248,7 +1251,7 @@ CPU(129, "CMPOR", 2, 6.00, 0, "X", "Y", "Compare X
12481251
---- Dec 13 -------------------------------------------------------------------------------------------------------------------------------------
12491252
CPU(130, "MSHIFT", 2, 7.00, 0, "COUNT", "OFFSET","Shift (and rotate) data pointed by ESI by OFFSET bytes")
12501253
CPU(131, "SMAP", 2, 8.00, R0+BL, "PAGE1", "PAGE2", "Remap PAGE1 to physical page PAGE2")
1251-
CPU(132, "GMAP", 2, 8.00, R0, "X", "PAGE", "Read what physical page PAGE is mapped to")
1254+
CPU(132, "GMAP", 2, 8.00, PR, "X", "PAGE", "Read what physical page PAGE is mapped to")
12521255
CPU(133, "RSTACK", 2, 9.00, 0, "X", "IDX", "Read value from stack at offset IDX (from address SS+IDX)")
12531256
CPU(134, "SSTACK", 2, 9.00, 0, "IDX", "Y", "Write value to stack at offset IDX (to address SS+IDX)")
12541257
CPU(135, "ENTER", 1, 10.00, 0, "SIZE", "", "Enter stack frame and allocate SIZE bytes on stack for local variables")

lua/wire/zvm/zvm_core.lua

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,31 @@ function ZVM:Dyn_EndQuotaInterrupt()
380380
self:Dyn_Emit("end")
381381
end
382382

383+
-- Allows you to set up code that runs if greater than this runlevel
384+
function ZVM:Dyn_BeginUnprivilegedCode(Runlevel)
385+
self:Emit("if (VM.PCAP == 1) and (VM.CurrentPage.RunLevel > %d) then",Runlevel)
386+
end
387+
388+
-- For readability to signify the end of an unprivileged block.
389+
function ZVM:Dyn_EndUnprivilegedCode()
390+
self:Emit("end")
391+
end
392+
393+
-- Set PreqOperands and an interrupt to return to just before this instruction, so it can be handled like a MEMRQ
394+
function ZVM:Dyn_EmitUnprivilegedRequestInterrupt(Opcode)
395+
self:Dyn_Emit("VM.PreqOperand1 = $1 or 0")
396+
self:Dyn_Emit("VM.PreqOperand2 = $2 or 0")
397+
self:Dyn_Emit("VM.PreqReturn = 0")
398+
-- Default PreqHandled to -1 (meaning unhandled, don't take return value, just skip the instruction)
399+
self:Dyn_Emit("VM.PreqHandled = -1")
400+
-- Return to just before instruction, to allow the instruction to get the return value if handled
401+
self:Dyn_EmitState()
402+
self:Dyn_Emit("VM.IP = %d",self.PrecompileIP-self.PrecompileCurInstructionSize)
403+
self:Dyn_Emit("VM.XEIP = %d",self.PrecompileXEIP-self.PrecompileCurInstructionSize)
404+
self:Dyn_Emit("VM:Interrupt(13,%d)",Opcode)
405+
self:Dyn_EmitBreak()
406+
end
407+
383408
--------------------------------------------------------------------------------
384409
function ZVM:Precompile_Initialize()
385410
self.PrecompileXEIP = self.XEIP
@@ -515,9 +540,14 @@ function ZVM:Precompile_Step()
515540

516541
-- Check opcode runlevel
517542
if self.OpcodeRunLevel[Opcode] then
518-
self:Emit("if (VM.PCAP == 1) and (VM.CurrentPage.RunLevel > %d) then",self.OpcodeRunLevel[Opcode])
519-
self:Dyn_EmitInterrupt("13",Opcode)
520-
self:Emit("end")
543+
self:Dyn_BeginUnprivilegedCode(self.OpcodeRunLevel[Opcode])
544+
self:Dyn_Emit("if VM.PreqHandled == 0 then")
545+
self:Dyn_EmitUnprivilegedRequestInterrupt(Opcode)
546+
self:Dyn_Emit("end")
547+
-- Skip running the privileged code if this was deemed "handled"
548+
self:Dyn_Emit("VM.PreqHandled = 0")
549+
self:Dyn_Emit("else")
550+
-- Privileged code will get wrapped in this block
521551
end
522552

523553
-- Calculate operand RM bytes
@@ -632,6 +662,10 @@ function ZVM:Precompile_Step()
632662
if self.EmitNeedInterruptCheck then
633663
self:Dyn_EmitInterruptCheck()
634664
end
665+
if self.OpcodeRunLevel[Opcode] then
666+
-- Wrap the privileged block up here.
667+
self:Dyn_EndUnprivilegedCode()
668+
end
635669
end
636670

637671
-- Do not repeat if opcode breaks the stream

lua/wire/zvm/zvm_data.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,13 @@ ZVM.InternalRegister[65] = "TimerRate"
8383
ZVM.InternalRegister[66] = "TimerPrevTime"
8484
ZVM.InternalRegister[67] = "TimerAddress"
8585
ZVM.InternalRegister[68] = "TimerPrevMode"
86+
----------------------------------
8687
ZVM.InternalRegister[69] = "LASTQUO"
8788
ZVM.InternalRegister[70] = "QUOFLAG"
89+
ZVM.InternalRegister[71] = "PreqOperand1"
90+
ZVM.InternalRegister[72] = "PreqOperand2"
91+
ZVM.InternalRegister[73] = "PreqReturn"
92+
ZVM.InternalRegister[74] = "PreqHandled"
8893
----------------------------------
8994
for reg=0,31 do ZVM.InternalRegister[96+reg] = "R"..reg end
9095

lua/wire/zvm/zvm_features.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ function ZVM:Reset()
111111
self.BlockSize = 0 -- Size of the block
112112
self.HaltPort = 0 -- Unused/obsolete
113113
self.TimerDT = 0 -- Timer deltastep within cached instructions block
114+
self.QUOTIMER = 0
115+
self.QUOCMP = 0
116+
self.PreqOperand1 = 0 -- Privileged Request Operands (used in interrupt 13 for opcodes requiring runlevel 0)
117+
self.PreqOperand2 = 0
118+
self.PreqHandled = 0
119+
self.PreqReturn = 0
114120

115121
-- Runlevel registers
116122
self.CRL = 0 -- Current runlevel

lua/wire/zvm/zvm_opcodes.lua

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,23 @@ end
156156
ZVM.OpcodeTable[16] = function(self) --RD
157157
self:Dyn_Emit("$L OP,ANS = $2,0")
158158
self:Dyn_EmitOperand("ANS")
159-
self:Dyn_Emit("if VM.Memory[OP] then")
160-
self:Dyn_Emit("ANS = VM.Memory[OP]")
161-
self:Dyn_Emit("end")
159+
self:Dyn_BeginUnprivilegedCode(0)
160+
self:Dyn_Emit("if VM.PreqHandled == 1 then")
161+
self:Dyn_Emit("ANS = VM.PreqReturn or 0")
162+
self:Dyn_Emit("VM.PreqReturn = 0")
163+
self:Dyn_Emit("VM.PreqHandled = 0")
164+
self:Dyn_Emit("elseif VM.PreqHandled == 0 then")
165+
-- 16 is the opcode to send to LADD for int 13
166+
self:Dyn_EmitUnprivilegedRequestInterrupt(16)
167+
self:Dyn_Emit("else")
168+
self:Dyn_Emit("VM.PreqHandled = 0")
169+
self:Dyn_Emit("end")
170+
self:Dyn_Emit("else")
171+
-- In this case we're privileged, so just handle it as usual
172+
self:Dyn_Emit("if VM.Memory[OP] then")
173+
self:Dyn_Emit("ANS = VM.Memory[OP]")
174+
self:Dyn_Emit("end")
175+
self:Dyn_EndUnprivilegedCode()
162176
end
163177
ZVM.OpcodeTable[17] = function(self) --WD
164178
self:Dyn_Emit("$L ADDR = math.floor($1)")
@@ -995,9 +1009,23 @@ ZVM.OpcodeTable[120] = function(self) --CPUGET
9951009
self:Dyn_Emit("$L OP = 0")
9961010
self:Dyn_EmitState()
9971011
self:Dyn_EmitOperand("OP")
998-
self:Dyn_Emit("if VM.InternalRegister[REG] then")
999-
self:Dyn_Emit("OP = VM[VM.InternalRegister[REG]]")
1000-
self:Dyn_Emit("end")
1012+
self:Dyn_BeginUnprivilegedCode(0)
1013+
self:Dyn_Emit("if VM.PreqHandled == 1 then")
1014+
self:Dyn_Emit("OP = VM.PreqReturn or 0")
1015+
self:Dyn_Emit("VM.PreqReturn = 0")
1016+
self:Dyn_Emit("VM.PreqHandled = 0")
1017+
self:Dyn_Emit("elseif VM.PreqHandled == 0 then")
1018+
-- 120 is the opcode to send to LADD for int 13
1019+
self:Dyn_EmitUnprivilegedRequestInterrupt(120)
1020+
self:Dyn_Emit("else")
1021+
self:Dyn_Emit("VM.PreqHandled = 0")
1022+
self:Dyn_Emit("end")
1023+
self:Dyn_Emit("else")
1024+
-- In this case we're privileged, so just handle it as usual
1025+
self:Dyn_Emit("if VM.InternalRegister[REG] then")
1026+
self:Dyn_Emit("OP = VM[VM.InternalRegister[REG]]")
1027+
self:Dyn_Emit("end")
1028+
self:Dyn_EndUnprivilegedCode()
10011029
end
10021030
ZVM.OpcodeTable[121] = function(self) --CPUSET
10031031
self:Dyn_Emit("$L REG = $1")
@@ -1215,10 +1243,25 @@ ZVM.OpcodeTable[131] = function(self) --SMAP
12151243
self:Dyn_Emit("end")
12161244
end
12171245
ZVM.OpcodeTable[132] = function(self) --GMAP
1218-
self:Dyn_Emit("$L IDX = math.floor(ADDR / 128)")
1219-
self:Dyn_Emit("$L PAGE = VM:GetPageByIndex(IDX)")
1220-
self:Dyn_EmitInterruptCheck()
1221-
self:Dyn_EmitOperand("PAGE.MappedIndex")
1246+
self:Dyn_EmitOperand("OP")
1247+
self:Dyn_BeginUnprivilegedCode(0)
1248+
self:Dyn_Emit("if VM.PreqHandled == 1 then")
1249+
self:Dyn_Emit("OP = VM.PreqReturn or 0")
1250+
self:Dyn_Emit("VM.PreqReturn = 0")
1251+
self:Dyn_Emit("VM.PreqHandled = 0")
1252+
self:Dyn_Emit("elseif VM.PreqHandled == 0 then")
1253+
-- 132 is the opcode to send to LADD for int 13
1254+
self:Dyn_EmitUnprivilegedRequestInterrupt(132)
1255+
self:Dyn_Emit("else")
1256+
self:Dyn_Emit("VM.PreqHandled = 0")
1257+
self:Dyn_Emit("end")
1258+
self:Dyn_Emit("else")
1259+
-- In this case we're privileged, so just handle it as usual
1260+
self:Dyn_Emit("$L IDX = math.floor($2 / 128)")
1261+
self:Dyn_Emit("$L PAGE = VM:GetPageByIndex(IDX)")
1262+
self:Dyn_EmitInterruptCheck()
1263+
self:Dyn_Emit("OP = (PAGE and PAGE.MappedIndex) or 0")
1264+
self:Dyn_EndUnprivilegedCode()
12221265
end
12231266
ZVM.OpcodeTable[133] = function(self) --RSTACK
12241267
self:Dyn_EmitForceRegisterGlobal("ESP")

0 commit comments

Comments
 (0)