Skip to content

Commit

Permalink
Prepare poll support
Browse files Browse the repository at this point in the history
  • Loading branch information
momo5502 committed Nov 9, 2024
1 parent 9eb49c9 commit 5f94688
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 8 deletions.
127 changes: 123 additions & 4 deletions src/windows-emulator/devices/afd_endpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "afd_types.hpp"

#include "../windows_emulator.hpp"
#include "../syscall_utils.hpp"

#include <network/address.hpp>
#include <network/socket.hpp>
Expand Down Expand Up @@ -31,6 +32,35 @@ namespace
return win_emu.emu().read_memory<afd_creation_data>(data.buffer);
}

std::pair<AFD_POLL_INFO, std::vector<AFD_POLL_HANDLE_INFO>> get_poll_info(
windows_emulator& win_emu, const io_device_context& c)
{
constexpr auto info_size = offsetof(AFD_POLL_INFO, Handles);
if (!c.input_buffer || c.input_buffer_length < info_size)
{
throw std::runtime_error("Bad AFD poll data");
}

AFD_POLL_INFO poll_info{};
win_emu.emu().read_memory(c.input_buffer, &poll_info, info_size);

std::vector<AFD_POLL_HANDLE_INFO> handle_info{};

const emulator_object<AFD_POLL_HANDLE_INFO> handle_info_obj{win_emu.emu(), c.input_buffer + info_size};

if (c.input_buffer_length < (info_size + sizeof(AFD_POLL_HANDLE_INFO) * poll_info.NumberOfHandles))
{
throw std::runtime_error("Bad AFD poll handle data");
}

for (ULONG i = 0; i < poll_info.NumberOfHandles; ++i)
{
handle_info.emplace_back(handle_info_obj.read(i));
}

return {std::move(poll_info), std::move(handle_info)};
}

struct afd_endpoint : io_device
{
bool in_poll{};
Expand Down Expand Up @@ -122,14 +152,15 @@ namespace
return this->ioctl_send_datagram(win_emu, c);
case AFD_RECEIVE_DATAGRAM:
return this->ioctl_receive_datagram(win_emu, c);
case AFD_POLL:
return ioctl_poll(win_emu, c);
case AFD_SET_CONTEXT:
return STATUS_SUCCESS;
case AFD_GET_INFORMATION:
return STATUS_SUCCESS;
default:
win_emu.logger.print(color::gray, "Unsupported AFD IOCTL: %X\n", c.io_control_code);
return STATUS_NOT_SUPPORTED;
}

win_emu.logger.print(color::gray, "Unsupported AFD IOCTL: %X\n", c.io_control_code);
return STATUS_NOT_SUPPORTED;
}

NTSTATUS ioctl_bind(windows_emulator& win_emu, const io_device_context& c) const
Expand All @@ -156,6 +187,94 @@ namespace
return STATUS_SUCCESS;
}

static std::vector<afd_endpoint*> resolve_endpoints(windows_emulator& win_emu,
const std::span<const AFD_POLL_HANDLE_INFO> handles)
{
auto& proc = win_emu.process();

std::vector<afd_endpoint*> endpoints{};
endpoints.reserve(handles.size());

for (const auto& handle : handles)
{
auto* device = proc.devices.get(reinterpret_cast<uint64_t>(handle.Handle));
if (!device)
{
throw std::runtime_error("Bad device!");
}

auto* endpoint = device->get_internal_device<afd_endpoint>();
if (!endpoint)
{
throw std::runtime_error("Device is not an AFD endpoint!");
}

endpoints.push_back(endpoint);
}

return endpoints;
}

static bool is_poll_done(windows_emulator& win_emu, const io_device_context& c, emulator_thread& t,
const std::optional<std::chrono::steady_clock::time_point> timeout)
{
const auto [info, handles] = get_poll_info(win_emu, c);
const auto endpoints = resolve_endpoints(win_emu, handles);

std::vector<pollfd> poll_data{};
poll_data.resize(endpoints.size());

for (size_t i = 0; i < endpoints.size(); ++i)
{
auto& pfd = poll_data.at(i);
//auto& handle = handles.at(i);

pfd.fd = *endpoints.at(i)->s;
pfd.events = POLLIN;
pfd.revents = pfd.events;
}

const auto count = poll(poll_data.data(), static_cast<uint32_t>(poll_data.size()), 0);
if (count > 0)
{
emulator_object<AFD_POLL_INFO>{win_emu.emu(), c.input_buffer}.access([&](AFD_POLL_INFO& info)
{
info.NumberOfHandles = count;
});

t.pending_status = STATUS_SUCCESS;
return true;
}

if (timeout && *timeout < std::chrono::steady_clock::now())
{
t.pending_status = STATUS_TIMEOUT;
return true;
}

return false;
}

static NTSTATUS ioctl_poll(windows_emulator& win_emu, const io_device_context& c)
{
const auto [info, handles] = get_poll_info(win_emu, c);
(void)resolve_endpoints(win_emu, handles);

std::optional<std::chrono::steady_clock::time_point> timeout{};
if (info.Timeout.QuadPart)
{
timeout = convert_delay_interval_to_time_point(info.Timeout);
}

win_emu.process().active_thread->thread_blocker = [timeout, c](windows_emulator& emu, emulator_thread& t)
{
return is_poll_done(emu, c, t, timeout);
};

win_emu.yield_thread();
return STATUS_PENDING;
}

NTSTATUS ioctl_receive_datagram(windows_emulator& win_emu, const io_device_context& c)
{
auto& emu = win_emu.emu();
Expand Down
15 changes: 15 additions & 0 deletions src/windows-emulator/devices/afd_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,21 @@ typedef struct _AFD_RECV_DATAGRAM_INFO
PULONG AddressLength;
} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;

typedef struct _AFD_POLL_HANDLE_INFO
{
HANDLE Handle;
ULONG PollEvents;
NTSTATUS Status;
} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;

typedef struct _AFD_POLL_INFO
{
LARGE_INTEGER Timeout;
ULONG NumberOfHandles;
BOOLEAN Unique;
AFD_POLL_HANDLE_INFO Handles[1];
} AFD_POLL_INFO, *PAFD_POLL_INFO;

#define _AFD_REQUEST(ioctl) \
((((ULONG)(ioctl)) >> 2) & 0x03FF)
#define _AFD_BASE(ioctl) \
Expand Down
7 changes: 6 additions & 1 deletion src/windows-emulator/process_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#define GDT_LIMIT 0x1000
#define GDT_ENTRY_SIZE 0x8

class windows_emulator;

struct ref_counted_object
{
uint32_t ref_count{1};
Expand Down Expand Up @@ -220,6 +222,9 @@ class emulator_thread : ref_counted_object
bool alerted{false};
std::optional<std::chrono::steady_clock::time_point> await_time{};

// TODO: Get rid of that!
std::function<bool(windows_emulator&, emulator_thread&)> thread_blocker{};

std::optional<NTSTATUS> pending_status{};

std::optional<emulator_allocator> gs_segment;
Expand All @@ -234,7 +239,7 @@ class emulator_thread : ref_counted_object
return this->await_time.has_value() && this->await_time.value() < std::chrono::steady_clock::now();
}

bool is_thread_ready(process_context& context);
bool is_thread_ready(windows_emulator& win_emu);

void save(x64_emulator& emu)
{
Expand Down
18 changes: 15 additions & 3 deletions src/windows-emulator/windows_emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ namespace
auto& emu = win_emu.emu();
auto& context = win_emu.process();

if (!thread.is_thread_ready(context))
if (!thread.is_thread_ready(win_emu))
{
return false;
}
Expand Down Expand Up @@ -679,13 +679,25 @@ void emulator_thread::mark_as_ready(const NTSTATUS status)
this->waiting_for_alert = false;
}

bool emulator_thread::is_thread_ready(process_context& context)
bool emulator_thread::is_thread_ready(windows_emulator& win_emu)
{
if (this->exit_status.has_value())
{
return false;
}

if (this->thread_blocker)
{
const auto res = this->thread_blocker(win_emu, *this);
if (res)
{
this->thread_blocker = {};
return true;
}

return false;
}

if (this->waiting_for_alert)
{
if (this->alerted)
Expand All @@ -704,7 +716,7 @@ bool emulator_thread::is_thread_ready(process_context& context)

if (this->await_object.has_value())
{
if (is_object_signaled(context, *this->await_object))
if (is_object_signaled(win_emu.process(), *this->await_object))
{
this->mark_as_ready(STATUS_WAIT_0);
return true;
Expand Down

0 comments on commit 5f94688

Please sign in to comment.