mirror of
https://github.com/AdvDebug/Brovan
synced 2026-08-09 11:57:17 +00:00
Sync XMM, fix bugs and add more Win32k syscalls
Adds backend-level XMM0-15 transfer APIs (KVM, Unicorn, WHP) and wires them into thread context save/restore so SIMD state survives scheduling. Introduces new Win32k syscall handlers for atom lookup, window message registration, hook register/unregister, class unregister, and related WinSyscallsHelper state management. Also improves wake scheduling behavior (yield slice after alert wake), tightens token syscall semantics/status codes, and adds DXVK/VK env passthrough plus BrovVulk issue-level diagnostics.
This commit is contained in:
@@ -142,6 +142,10 @@ namespace Brovan.Core.Emulation
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadXmmRegisters(ulong[] values) => false;
|
||||
|
||||
bool WriteXmmRegisters(ulong[] values) => false;
|
||||
|
||||
bool WriteRegisterBatch(int[] registers, ulong[] values, int count)
|
||||
{
|
||||
if (registers == null || values == null || count <= 0 || count > registers.Length || count > values.Length)
|
||||
|
||||
@@ -95,6 +95,10 @@ namespace Brovan.Core.Emulation
|
||||
=> Inner.ReadRegister(register);
|
||||
public ulong ReadRegister(int register)
|
||||
=> Inner.ReadRegister(register);
|
||||
public bool ReadXmmRegisters(ulong[] values)
|
||||
=> Inner.TransferXmmRegisters(values, false);
|
||||
public bool WriteXmmRegisters(ulong[] values)
|
||||
=> Inner.TransferXmmRegisters(values, true);
|
||||
public uint ReadRegister32(Registers register)
|
||||
=> Inner.ReadRegister32(register);
|
||||
public uint ReadRegister32(int register)
|
||||
|
||||
@@ -98,6 +98,10 @@ namespace Brovan.Core.Emulation
|
||||
=> Inner.ReadRegisterBatch(registers, values, count);
|
||||
public bool WriteRegisterBatch(int[] registers, ulong[] values, int count)
|
||||
=> Inner.WriteRegisterBatch(registers, values, count);
|
||||
public bool ReadXmmRegisters(ulong[] values)
|
||||
=> Inner.TransferXmmRegisters(values, false);
|
||||
public bool WriteXmmRegisters(ulong[] values)
|
||||
=> Inner.TransferXmmRegisters(values, true);
|
||||
|
||||
public CPUFlags GetCPUFlags() => Inner.GetCPUFlags();
|
||||
public bool SetCPUFlags(CPUFlags flags) => Inner.SetCPUFlags(flags);
|
||||
|
||||
@@ -112,6 +112,12 @@ namespace Brovan.Core.Emulation
|
||||
public IntPtr AddMemoryHook(ulong begin, ulong end, BackendHookType hookType, MemoryHookCallback callback)
|
||||
=> Inner.AddMemoryHook(begin, end, hookType, callback);
|
||||
|
||||
public bool ReadXmmRegisters(ulong[] values)
|
||||
=> Inner.TransferXmmRegisters(values, false);
|
||||
|
||||
public bool WriteXmmRegisters(ulong[] values)
|
||||
=> Inner.TransferXmmRegisters(values, true);
|
||||
|
||||
public IntPtr AddCodeHook(ulong begin, ulong end, CodeHookCallback callback)
|
||||
=> Inner.AddCodeHook(begin, end, callback);
|
||||
|
||||
|
||||
@@ -1525,6 +1525,22 @@ namespace Brovan.Core.Emulation
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends the running thread's slice after it made another thread runnable, leaving it Ready so it resumes
|
||||
/// where it left off. A wake only unblocks the target; without giving up the rest of the quantum the waker
|
||||
/// keeps running for up to a full MLFQ slice (1.6M instructions at the lowest queue) before the scheduler
|
||||
/// looks at the target again, and any handoff the waker then waits on costs that whole slice. Real hardware
|
||||
/// hides this by running the woken thread on another core.
|
||||
/// </summary>
|
||||
internal void YieldSliceAfterWake()
|
||||
{
|
||||
if (CurrentThread != null && CurrentThread.State == EmulatedThreadState.Running)
|
||||
CurrentThread.State = EmulatedThreadState.Ready;
|
||||
|
||||
SchedulerRefreshRequested = true;
|
||||
_emulator.StopEmulation();
|
||||
}
|
||||
|
||||
private void StopAfterSyntheticInstruction(ulong NextIp)
|
||||
{
|
||||
SchedulerRefreshRequested = true;
|
||||
@@ -1831,6 +1847,7 @@ namespace Brovan.Core.Emulation
|
||||
{
|
||||
if (t == null || t.Context == null) return;
|
||||
ReadGprBatch(t.Context);
|
||||
_emulator.ReadXmmRegisters(t.Context.Xmm);
|
||||
}
|
||||
|
||||
public bool ReadGprBatch(CpuContext c)
|
||||
@@ -1885,6 +1902,7 @@ namespace Brovan.Core.Emulation
|
||||
}
|
||||
|
||||
WriteGprBatch(t.Context);
|
||||
_emulator.WriteXmmRegisters(t.Context.Xmm);
|
||||
Guest.OnThreadContextLoaded(this, t);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -1128,6 +1129,19 @@ namespace Brovan.Core.Emulation.Guests
|
||||
{ "PATH", @"C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\" }
|
||||
};
|
||||
|
||||
// pass DXVK environment variables if available to the guest for debugging
|
||||
foreach (DictionaryEntry HostVariable in Environment.GetEnvironmentVariables())
|
||||
{
|
||||
string Name = HostVariable.Key as string;
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
continue;
|
||||
|
||||
if (!Name.StartsWith("DXVK_", StringComparison.OrdinalIgnoreCase) && !Name.StartsWith("VK_", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
Env[Name] = HostVariable.Value as string ?? string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder Builder = new StringBuilder(1024);
|
||||
foreach (var kv in Env)
|
||||
{
|
||||
|
||||
@@ -2332,6 +2332,41 @@ namespace Brovan.Core.Emulation
|
||||
}
|
||||
}
|
||||
|
||||
internal const int XmmRegisterCount = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Transfers XMM0-15 as 32 qwords, low half of each register first.
|
||||
/// </summary>
|
||||
public unsafe bool TransferXmmRegisters(ulong[] Values, bool Write)
|
||||
{
|
||||
if (Values == null || Values.Length < XmmRegisterCount * 2)
|
||||
return false;
|
||||
|
||||
LinuxKvmFpu Fpu = default;
|
||||
|
||||
lock (_vcpuLock)
|
||||
{
|
||||
if (KvmNative.ioctl(_vcpuFd, KvmConstants.KvmIoGetFpu, (IntPtr)(&Fpu)) < 0)
|
||||
return false;
|
||||
|
||||
if (Write)
|
||||
{
|
||||
for (int i = 0; i < XmmRegisterCount * 2; i++)
|
||||
((ulong*)Fpu.Xmm)[i] = Values[i];
|
||||
|
||||
if (KvmNative.ioctl(_vcpuFd, KvmConstants.KvmIoSetFpu, (IntPtr)(&Fpu)) < 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < XmmRegisterCount * 2; i++)
|
||||
Values[i] = ((ulong*)Fpu.Xmm)[i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe void SetFpu(ref LinuxKvmFpu fpu)
|
||||
{
|
||||
lock (_vcpuLock)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using Brovan.Core.Helpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows
|
||||
{
|
||||
@@ -29,6 +30,10 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
{
|
||||
if (Ioctl == IOCTL_BROVVULK_GEN)
|
||||
return HandleGenIoctl(ref Data, Instance);
|
||||
|
||||
if ((Instance.Settings.Flags & LogFlags.Issues) != 0)
|
||||
Instance.TriggerEventMessage($"[BrovVulk] unknown IOCTL 0x{Ioctl:X}.", LogFlags.Issues);
|
||||
|
||||
return NTSTATUS.STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
@@ -36,12 +41,22 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
{
|
||||
byte[] Input = Data.InputBuffer;
|
||||
if (Input == null || Input.Length < 8)
|
||||
{
|
||||
if ((Instance.Settings.Flags & LogFlags.Issues) != 0)
|
||||
Instance.TriggerEventMessage($"[BrovVulk] rejected IOCTL with a {(Input == null ? -1 : Input.Length)} byte input buffer.", LogFlags.Issues);
|
||||
|
||||
return NTSTATUS.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
uint Id = BinaryPrimitives.ReadUInt32LittleEndian(Input.AsSpan(0, 4));
|
||||
uint PayloadLen = BinaryPrimitives.ReadUInt32LittleEndian(Input.AsSpan(4, 4));
|
||||
if (PayloadLen > (uint)(Input.Length - 8) || PayloadLen > MaxGenPayload)
|
||||
{
|
||||
if ((Instance.Settings.Flags & LogFlags.Issues) != 0)
|
||||
Instance.TriggerEventMessage($"[BrovVulk] rejected command {Id} with payload length {PayloadLen} in a {Input.Length} byte input buffer.", LogFlags.Issues);
|
||||
|
||||
return NTSTATUS.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
byte[] OutBytes;
|
||||
lock (Lock)
|
||||
@@ -56,6 +71,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
uint Count = Reader.ReadU32();
|
||||
if (Count > MaxBatchCommands)
|
||||
throw new InvalidOperationException($"BrovVulk generic: batch count {Count} exceeds cap.");
|
||||
|
||||
Result = 0;
|
||||
for (uint k = 0; k < Count; k++)
|
||||
{
|
||||
@@ -72,8 +88,8 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
if ((Instance.Settings.Flags & LogFlags.Syscall) != 0)
|
||||
Instance.TriggerEventMessage($"[!] BrovVulk(gen): {Ex.Message}", LogFlags.Syscall);
|
||||
if ((Instance.Settings.Flags & LogFlags.Issues) != 0)
|
||||
Instance.TriggerEventMessage($"[!] BrovVulk(gen): {Ex.Message}", LogFlags.Issues);
|
||||
Writer.Reset();
|
||||
Result = VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows
|
||||
@@ -46,6 +46,10 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
Instance.WriteRegister(Registers.UC_X86_REG_RIP, TargetThread.Context.RIP);
|
||||
Instance.WriteRegister(Registers.UC_X86_REG_RAX, TargetThread.Context.RAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance.YieldSliceAfterWake();
|
||||
}
|
||||
}
|
||||
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
|
||||
ulong ThreadHandle = Instance.WinHelper.GetArg(0);
|
||||
ulong DesiredAccess = Instance.WinHelper.GetArg(1);
|
||||
ulong OpenAsSelf = Instance.WinHelper.GetArg(2);
|
||||
ulong TokenHandlePtr = Instance.WinHelper.GetArg(3);
|
||||
|
||||
if (TokenHandlePtr == 0)
|
||||
@@ -35,26 +34,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WinToken Token = WinEmulatedThread.GetState(Thread).ImpersonationToken;
|
||||
|
||||
if (Token == null)
|
||||
{
|
||||
if (OpenAsSelf == 0)
|
||||
return NTSTATUS.STATUS_NO_TOKEN;
|
||||
|
||||
WinProcess Process = Helper.WinProcesses.FirstOrDefault(Proc => Proc.PID == Helper.PID);
|
||||
if (Process == null || Process.PrimaryToken == null)
|
||||
return NTSTATUS.STATUS_NO_TOKEN;
|
||||
|
||||
Token = new WinToken
|
||||
{
|
||||
Type = TokenType.Impersonation,
|
||||
SessionId = Process.PrimaryToken.SessionId,
|
||||
IsElevated = Process.PrimaryToken.IsElevated,
|
||||
IsRestricted = Process.PrimaryToken.IsRestricted,
|
||||
EffectiveOnly = Process.PrimaryToken.EffectiveOnly,
|
||||
ImpersonationLevel = SecurityImpersonationLevel.SecurityImpersonation,
|
||||
OwningProcessId = Process.PrimaryToken.OwningProcessId,
|
||||
OwningThreadId = (ulong)Thread.ThreadId
|
||||
};
|
||||
}
|
||||
return NTSTATUS.STATUS_NO_TOKEN;
|
||||
|
||||
var Handle = Helper.HandleManager.AddHandle(Token, MapDesiredTokenAccess((AccessMask)(uint)DesiredAccess) | AccessMask.TokenDuplicate);
|
||||
Helper.WritePointer(TokenHandlePtr, Handle.Handle);
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
if (!Instance._emulator.WriteMemory(TokenInformation, Value))
|
||||
return NTSTATUS.STATUS_ACCESS_VIOLATION;
|
||||
@@ -168,7 +168,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
if (!Instance._emulator.WriteMemory(TokenInformation, 0u))
|
||||
return NTSTATUS.STATUS_ACCESS_VIOLATION;
|
||||
@@ -182,7 +182,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -201,7 +201,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -220,7 +220,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -257,7 +257,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -282,7 +282,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -326,7 +326,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uint Value = Token.Type == TokenType.Primary ? 1u : 2u;
|
||||
|
||||
@@ -342,7 +342,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uint Value = (uint)Token.ImpersonationLevel;
|
||||
|
||||
@@ -358,7 +358,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uint Value = 0;
|
||||
|
||||
@@ -374,7 +374,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
if (!Instance._emulator.WriteMemory(TokenInformation, Token.SessionId))
|
||||
return NTSTATUS.STATUS_ACCESS_VIOLATION;
|
||||
@@ -388,7 +388,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uint Value = Token.IsElevated ? 1u : 0u;
|
||||
|
||||
@@ -406,7 +406,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -423,7 +423,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
Buffer.Clear();
|
||||
@@ -455,7 +455,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> BufferData = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
BufferData.Clear();
|
||||
@@ -486,7 +486,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
WriteReturnLength(RequiredSize);
|
||||
|
||||
if (TokenInformationLength < RequiredSize)
|
||||
return NTSTATUS.STATUS_BUFFER_OVERFLOW;
|
||||
return NTSTATUS.STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Span<byte> BufferData = Instance.WinHelper.Shared.GetSpan(RequiredSize);
|
||||
BufferData.Clear();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows
|
||||
@@ -70,6 +70,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
return NTSTATUS.STATUS_UNSUCCESSFUL;
|
||||
|
||||
WindowsThreadState State = WinEmulatedThread.GetState(Thread);
|
||||
|
||||
if (State.WaitCompleted)
|
||||
{
|
||||
NTSTATUS Status = State.WaitStatus;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
{
|
||||
internal class NtUserGetAtomName : IWinSyscall
|
||||
{
|
||||
public NTSTATUS Handle(BinaryEmulator Instance)
|
||||
{
|
||||
ushort Atom = (ushort)Instance.WinHelper.GetArg(0);
|
||||
ulong StringPtr = Instance.WinHelper.GetArg(1);
|
||||
|
||||
uint BufferOffset = (uint)Instance.WinHelper.PointerSize;
|
||||
uint StructSize = BufferOffset * 2;
|
||||
|
||||
if (StringPtr == 0 || !Instance.IsRegionMapped(StringPtr, StructSize) ||
|
||||
!Instance.WinHelper.TryGetAtomName(Atom, out string Name))
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ushort MaximumLength = (ushort)(Instance.ReadMemoryUInt(StringPtr) >> 16);
|
||||
ulong Buffer = Instance.WinHelper.ReadPointer(StringPtr + BufferOffset);
|
||||
|
||||
int MaxChars = MaximumLength / sizeof(char);
|
||||
if (Buffer == 0 || MaxChars <= 0)
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (Name.Length >= MaxChars)
|
||||
Name = Name.Substring(0, MaxChars - 1);
|
||||
|
||||
uint NameBytes = (uint)((Name.Length + 1) * sizeof(char));
|
||||
if (!Instance.IsRegionMapped(Buffer, NameBytes))
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Span<byte> Bytes = Instance.WinHelper.Shared.GetSpan(NameBytes);
|
||||
Bytes.Clear();
|
||||
Encoding.Unicode.GetBytes(Name, Bytes);
|
||||
|
||||
if (!Instance.WriteMemory(Buffer, Bytes))
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Instance.SetRawSyscallReturn((uint)Name.Length);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
{
|
||||
internal class NtUserGetHDevName : IWinSyscall
|
||||
{
|
||||
private const int CchDeviceName = 32;
|
||||
private const string DeviceName = @"\\.\DISPLAY1";
|
||||
|
||||
public NTSTATUS Handle(BinaryEmulator Instance)
|
||||
{
|
||||
ulong Monitor = Instance.WinHelper.GetArg(0);
|
||||
ulong NamePtr = Instance.WinHelper.GetArg(1);
|
||||
|
||||
uint NameBytes = CchDeviceName * sizeof(char);
|
||||
|
||||
if (NamePtr == 0 || !Instance.IsRegionMapped(NamePtr, NameBytes) ||
|
||||
Monitor == 0 || Monitor != Instance.WinHelper.GetPrimaryMonitorHandle())
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Span<byte> Buffer = Instance.WinHelper.Shared.GetSpan(NameBytes);
|
||||
Buffer.Clear();
|
||||
Encoding.Unicode.GetBytes(DeviceName, Buffer);
|
||||
|
||||
if (!Instance.WriteMemory(NamePtr, Buffer))
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Instance.SetRawSyscallReturn(1);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
{
|
||||
internal class NtUserRegisterWindowMessage : IWinSyscall
|
||||
{
|
||||
public NTSTATUS Handle(BinaryEmulator Instance)
|
||||
{
|
||||
ulong NamePtr = Instance.WinHelper.GetArg(0);
|
||||
|
||||
bool Read = Instance.WinHelper.TryReadUnicodeString(NamePtr, out string Name, out _);
|
||||
|
||||
Instance.SetRawSyscallReturn(Read ? Instance.WinHelper.RegisterWindowMessageAtom(Name) : (ushort)0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
{
|
||||
internal class NtUserSetWindowsHookEx : IWinSyscall
|
||||
{
|
||||
public NTSTATUS Handle(BinaryEmulator Instance)
|
||||
{
|
||||
int HookId = (int)Instance.WinHelper.GetArg(3);
|
||||
ulong HookProc = Instance.WinHelper.GetArg(4);
|
||||
|
||||
if (HookProc == 0)
|
||||
{
|
||||
Instance.SetRawSyscallReturn(0);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Instance.SetRawSyscallReturn(Instance.WinHelper.RegisterWindowsHook(HookId, HookProc));
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
{
|
||||
internal class NtUserUnhookWindowsHookEx : IWinSyscall
|
||||
{
|
||||
public NTSTATUS Handle(BinaryEmulator Instance)
|
||||
{
|
||||
ulong Hook = Instance.WinHelper.GetArg(0);
|
||||
|
||||
Instance.SetRawSyscallReturn(Instance.WinHelper.UnregisterWindowsHook(Hook) ? 1u : 0u);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
{
|
||||
internal class NtUserUnregisterClass : IWinSyscall
|
||||
{
|
||||
public NTSTATUS Handle(BinaryEmulator Instance)
|
||||
{
|
||||
ulong ClassNamePtr = Instance.WinHelper.GetArg(0);
|
||||
ulong InstanceHandle = Instance.WinHelper.GetArg(1);
|
||||
|
||||
bool Read = Instance.WinHelper.TryReadUnicodeString(ClassNamePtr, out string ClassName, out _);
|
||||
|
||||
Instance.SetRawSyscallReturn(Read && Instance.WinHelper.UnregisterWindowClass(InstanceHandle, ClassName) ? 1u : 0u);
|
||||
return NTSTATUS.STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3961,6 +3961,67 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
Data[Offset + i] = (byte)(Value >> (i * 8));
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, ushort> RegisteredMessageAtoms = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<ushort, string> RegisteredMessageNames = new();
|
||||
private readonly Dictionary<ulong, (int HookId, ulong HookProc)> WindowsHooks = new();
|
||||
private ulong NextWindowsHook = 0x1F0000;
|
||||
|
||||
public ulong RegisterWindowsHook(int HookId, ulong HookProc)
|
||||
{
|
||||
ulong Hook = NextWindowsHook;
|
||||
NextWindowsHook += 4;
|
||||
WindowsHooks[Hook] = (HookId, HookProc);
|
||||
return Hook;
|
||||
}
|
||||
|
||||
public bool UnregisterWindowsHook(ulong Hook)
|
||||
{
|
||||
return WindowsHooks.Remove(Hook);
|
||||
}
|
||||
|
||||
public bool UnregisterWindowClass(ulong InstanceHandle, string Name)
|
||||
{
|
||||
WinWindowClass WindowClass = GetWindowClass(InstanceHandle, Name, null);
|
||||
if (WindowClass == null)
|
||||
return false;
|
||||
|
||||
WinWindowClassesByAtom.Remove(WindowClass.Atom);
|
||||
WinWindowClassAtomsByKey.Remove(BuildWindowClassKey(WindowClass.InstanceHandle, WindowClass.Name, WindowClass.Version));
|
||||
return true;
|
||||
}
|
||||
|
||||
public ushort RegisterWindowMessageAtom(string Name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
return 0;
|
||||
|
||||
if (RegisteredMessageAtoms.TryGetValue(Name, out ushort Existing))
|
||||
return Existing;
|
||||
|
||||
if (NextWindowClassAtom < 0xC000)
|
||||
NextWindowClassAtom = 0xC000;
|
||||
|
||||
ushort Atom = NextWindowClassAtom++;
|
||||
RegisteredMessageAtoms[Name] = Atom;
|
||||
RegisteredMessageNames[Atom] = Name;
|
||||
return Atom;
|
||||
}
|
||||
|
||||
public bool TryGetAtomName(ushort Atom, out string Name)
|
||||
{
|
||||
if (RegisteredMessageNames.TryGetValue(Atom, out Name))
|
||||
return true;
|
||||
|
||||
if (WinWindowClassesByAtom.TryGetValue(Atom, out WinWindowClass WindowClass) && !string.IsNullOrEmpty(WindowClass.Name))
|
||||
{
|
||||
Name = WindowClass.Name;
|
||||
return true;
|
||||
}
|
||||
|
||||
Name = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public WinWindowClass RegisterWindowClass(WinWindowClass WindowClass)
|
||||
{
|
||||
if (WindowClass == null || string.IsNullOrEmpty(WindowClass.Name))
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Brovan.Core.Emulation
|
||||
public ulong MXCSR;
|
||||
public ulong CS, DS, ES, FS, GS, SS;
|
||||
public ulong DR0, DR1, DR2, DR3, DR6, DR7;
|
||||
public readonly ulong[] Xmm = new ulong[32];
|
||||
}
|
||||
|
||||
public enum EmulatedThreadState
|
||||
|
||||
@@ -964,6 +964,53 @@ namespace Brovan.Core.Emulation
|
||||
}
|
||||
}
|
||||
|
||||
internal const int XmmRegisterCount = 16;
|
||||
|
||||
private static int[] _xmmBatchRegs;
|
||||
|
||||
private static int[] GetXmmBatchRegs()
|
||||
{
|
||||
int[] Regs = _xmmBatchRegs;
|
||||
if (Regs == null)
|
||||
{
|
||||
Regs = new int[XmmRegisterCount];
|
||||
for (int i = 0; i < XmmRegisterCount; i++)
|
||||
Regs[i] = (int)Registers.UC_X86_REG_XMM0 + i;
|
||||
_xmmBatchRegs = Regs;
|
||||
}
|
||||
return Regs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers XMM0-15 as 32 qwords, low half of each register first.
|
||||
/// </summary>
|
||||
public unsafe bool TransferXmmRegisters(ulong[] Values, bool Write)
|
||||
{
|
||||
if (DisposedCheck() || Values == null || Values.Length < XmmRegisterCount * 2)
|
||||
return false;
|
||||
|
||||
lock (_registerLock)
|
||||
{
|
||||
if (_uc == IntPtr.Zero)
|
||||
return false;
|
||||
|
||||
int[] Regs = GetXmmBatchRegs();
|
||||
|
||||
fixed (int* RegsPtr = Regs)
|
||||
fixed (ulong* ValsPtr = Values)
|
||||
{
|
||||
void** PtrArray = stackalloc void*[XmmRegisterCount];
|
||||
for (int i = 0; i < XmmRegisterCount; i++)
|
||||
PtrArray[i] = &ValsPtr[i * 2];
|
||||
|
||||
_error = Write
|
||||
? uc_reg_write_batch(_uc, RegsPtr, PtrArray, XmmRegisterCount)
|
||||
: uc_reg_read_batch(_uc, RegsPtr, PtrArray, XmmRegisterCount);
|
||||
return _error == UCErrors.UC_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the CPU Flags.
|
||||
/// </summary>
|
||||
|
||||
@@ -123,6 +123,8 @@ namespace Brovan.Core.Emulation
|
||||
Cr4 = 0x0000001F,
|
||||
Cr8 = 0x00000020,
|
||||
|
||||
Xmm0 = 0x00001000,
|
||||
|
||||
Dr0 = 0x00000021,
|
||||
Dr1 = 0x00000022,
|
||||
Dr2 = 0x00000023,
|
||||
|
||||
@@ -2299,6 +2299,62 @@ namespace Brovan.Core.Emulation
|
||||
return ref _regsCache;
|
||||
}
|
||||
|
||||
internal const int XmmRegisterCount = 16;
|
||||
|
||||
private static readonly uint[] XmmRegNames = BuildXmmRegNames();
|
||||
|
||||
private static uint[] BuildXmmRegNames()
|
||||
{
|
||||
uint[] Names = new uint[XmmRegisterCount];
|
||||
for (int i = 0; i < XmmRegisterCount; i++)
|
||||
Names[i] = (uint)WhvRegisterName.Xmm0 + (uint)i;
|
||||
return Names;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers XMM0-15 as 32 qwords, low half of each register first.
|
||||
/// </summary>
|
||||
public unsafe bool TransferXmmRegisters(ulong[] Values, bool Write)
|
||||
{
|
||||
if (Values == null || Values.Length < XmmRegisterCount * 2)
|
||||
return false;
|
||||
|
||||
Span<WhvRegisterValue> Regs = stackalloc WhvRegisterValue[XmmRegisterCount];
|
||||
|
||||
if (Write)
|
||||
{
|
||||
for (int i = 0; i < XmmRegisterCount; i++)
|
||||
{
|
||||
Regs[i].Low = Values[i * 2];
|
||||
Regs[i].High = Values[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
lock (_vcpuLock)
|
||||
{
|
||||
fixed (uint* Names = XmmRegNames)
|
||||
fixed (WhvRegisterValue* Vals = Regs)
|
||||
{
|
||||
int Hr = Write
|
||||
? WhpNative.WHvSetVirtualProcessorRegisters(_partition, VpIndex, Names, XmmRegisterCount, Vals)
|
||||
: WhpNative.WHvGetVirtualProcessorRegisters(_partition, VpIndex, Names, XmmRegisterCount, Vals);
|
||||
if (WhpNative.Failed(Hr))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Write)
|
||||
{
|
||||
for (int i = 0; i < XmmRegisterCount; i++)
|
||||
{
|
||||
Values[i * 2] = Regs[i].Low;
|
||||
Values[i * 2 + 1] = Regs[i].High;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe void LoadRegisters()
|
||||
{
|
||||
Span<WhvRegisterValue> values = stackalloc WhvRegisterValue[GpRegNames.Length];
|
||||
|
||||
Reference in New Issue
Block a user