Binary packages for various distributions will be available from:
https://www.winehq.org/download
Summary since last release
* Rebased to current wine 9.0-rc5 (500 patches are applied to wine vanilla)
Upstreamed (Either directly from staging or fixed with a similar patch).
* None
Added:
* None
Updated:
* vkd3d-latest
Where can you help
* Run Steam/Battle.net/GOG/UPlay/Epic
* Test your favorite game.
* Test your favorite applications.
* Improve staging patches and get them accepted upstream.
* Suggest patches to be included in staging.
As always, if you find a bug, please report it via
https://bugs.winehq.org
Best Regards
Alistair.
Hi All,
Now that vkd3d 1.10 is out, I have a request for developers.
Would it be possible to include a file of all games/applications that
have fixes when they are committed. It's too hard to track unless you
really doing serious work with it.
The whole concept of including the latest vk3d3d in staging was to help
with testing but if people don't know what to test, they wont.
This would also, give a nice section in the ANNOUNCE as to what now
works. :)
Best Regards
Alistair
Binary packages for various distributions will be available from:
https://www.winehq.org/download
Summary since last release
* Rebased to current wine 9.0-rc4 (500 patches are applied to wine vanilla)
Upstreamed (Either directly from staging or fixed with a similar patch).
* None
Added:
* None
Updated:
* vkd3d-latest
Where can you help
* Run Steam/Battle.net/GOG/UPlay/Epic
* Test your favorite game.
* Test your favorite applications.
* Improve staging patches and get them accepted upstream.
* Suggest patches to be included in staging.
As always, if you find a bug, please report it via
https://bugs.winehq.org
Best Regards
Alistair.
On January 4, 2024 6:47:04 PM PST, Andrew Cooper <andrew.cooper3(a)citrix.com> wrote:
>On 05/01/2024 1:02 am, H. Peter Anvin wrote:
>> Note that there is no fundamental reason you cannot run the Unix user space code inside the VM container, too; you only need to vmexit on an actual system call.
>
>I know this is going on a tangent, but getting a VMExit on the SYSCALL
>instruction is surprisingly difficult.
>
>The "easy" way is to hide EFER.SCE behind the guests back, intercept #UD
>and emulate both the SYSCALL and SYSRET instructions. It's slow, but it
>works.
>
>However, FRED completely prohibits tricks like this, because what you
>cannot reasonably do is clear CR4.FRED behind the back of a guest
>kernel. You'd have to intercept and emulate all event sources in order
>to catch SYSCALL.
>
>I raised this as a concern during early review, but Intel has no
>official feature to take a VMExit on privilege change, and FRED
>(rightly) wasn't an appropriate vehicle to add such a feature, so it was
>deemed not an issue that the FRED design would break the unofficial ways
>that people were using to intercept/monitor/etc system calls.
>
>~Andrew
>
>P.S. Yes, there are more adventurous tricks like injecting a thunk into
>the guest kernel and editing MSR_LSTAR behind the guest's back. In
>principle a similar trick works with FRED, but in order to do this to
>Windows, you also need to hook checkpatch to blind it to the thunk, and
>this is horribly invasive.
*In this case* it shouldn't be a problem, since the "guest operating system" would be virtually nonexistent and entirely puppeted by Wine.
On January 3, 2024 7:19:02 AM PST, Sean Christopherson <seanjc(a)google.com> wrote:
>On Tue, Jan 02, 2024, Elizabeth Figura wrote:
>> On Wednesday, December 27, 2023 5:58:19 PM CST H. Peter Anvin wrote:
>> > On December 27, 2023 2:20:37 PM PST, Elizabeth Figura <zfigura(a)codeweavers.com> wrote:
>> > >Hello all,
>> > >
>> > >There is a Windows 98 program, a game called Nuclear Strike, which wants to
>> > >do some amount of direct VGA access. Part of this is port I/O, which
>> > >naturally throws SIGILL that we can trivially catch and emulate in Wine.
>> > >The other part is direct access to the video memory at 0xa0000, which in
>> > >general isn't a problem to catch and virtualize as well.
>> > >
>> > >However, this program is a bit creative about how it accesses that memory;
>> > >instead of just writing to 0xa0000 directly, it looks up a segment
>> > >descriptor whose base is at 0xa0000 and then uses the %es override to
>> > >write bytes. In pseudo-C, what it does is:
>
>...
>
>> > A prctl() to set the UMIP-emulated return values or disable it (giving
>> > SIGILL) would be easy enough.
>> >
>> > For the non-UMIP case, and probably for a lot of other corner cases like
>> > relying on certain magic selector values and what not, the best option
>> > really would be to wrap the code in a lightweight KVM container. I do *not*
>> > mean running the Qemu user space part of KVM; instead have Wine interface
>> > with /dev/kvm directly.
>> >
>> > Non-KVM-capable hardware is basically historic at this point.
>>
>> Sorry for the late response—I've been trying to do research on what would be
>> necessary to use KVM (plus I made the poor choice of sending this during the
>> holiday season...)
>>
>> I'm concerned that KVM is going to be difficult or even intractable. Here are
>> some of the problems that I (perhaps incorrectly) understand:
>>
>> * As I am led to understand, there can only be one hypervisor on the machine
>> at a time,
>
>No. Only one instance of KVM-the-module is allowed, but there is no arbitrary
>limit on the number of VMs that userspace can create. The only meaningful
>limitation is memory, and while struct kvm isn't tiny, it's not _that_ big.
>
>> and KVM has a hard limit on the number of vCPUs.
>>
>> The obvious way to use KVM for Wine is to make each (guest) thread a vCPU.
>> That will, at the very least, run into the thread limit. In order to avoid
>> that we'd need to ship a whole scheduler, which is concerning. That's a huge
>> component to ship and a huge burden to keep updated. It also means we need to
>> hoist *all* of the ipc and sync code into the guest, which will take an
>> enormous amount of work.
>>
>> Moreover, because there can only be one hypervisor, and Wine is a multi-
>> process beast, that means that we suddenly need to throw every process into
>> the same VM.
>
>As above, this is wildly inaccurate. The only KVM restriction with respect to
>processes is that a VM is bound to the process (address space) that created the
>VM. There are no restrictions on the number of VMs that can be created, e.g. a
>single process can create multiple VMs.
>
>> That has unfortunate implications regarding isolation (it's been a dream for
>> years that we'd be able to share a single wine "VM" between multiple users),
>> it complicates memory management (though perhaps not terribly?). And it means
>> you can only have one Wine VM at a time, and can't use Wine at the same time
>> as a "real" VM, neither of which are restrictions that currently exist.
>>
>> And it's not even like we can refactor—we'd have to rewrite tons of code to
>> work inside a VM, but also keep the old code around for the cases where we
>> don't have a VM and want to delegate scheduling to the host OS.
>>
>> * Besides scheduling, we need to exit the VM every time we would normally call
>> into Unix code, which in practice is every time that the application does an
>> NT syscall, or uses a library which we delegate to the host (including e.g.
>> GPU, multimedia, audio...)
>
>Maybe I misinterpreted Peter's suggestion, but at least in my mind I wasn't thinking
>that the entire Wine process would run in a VM, but rather Wine would run just
>the "problematic" code in a VM.
>
Yes, the idea would be that you would run the "problematic" code inside a VM *mapped 1:1 with the external address space*, i.e. use KVM simply as a special execution mode to give you more control of the fine grained machine state like the GDT. The code that you don't want executed in the VM context simply leave unmapped in the VM page tables and set up #PF to always exit the VM context.
Hello all,
There is a Windows 98 program, a game called Nuclear Strike, which wants to do
some amount of direct VGA access. Part of this is port I/O, which naturally
throws SIGILL that we can trivially catch and emulate in Wine. The other part
is direct access to the video memory at 0xa0000, which in general isn't a
problem to catch and virtualize as well.
However, this program is a bit creative about how it accesses that memory;
instead of just writing to 0xa0000 directly, it looks up a segment descriptor
whose base is at 0xa0000 and then uses the %es override to write bytes. In
pseudo-C, what it does is:
int get_vga_selector()
{
sgdt(&gdt_size, &gdt_ptr);
sldt(&ldt_segment);
++gdt_size;
descriptor = gdt_ptr;
while (descriptor->base != 0xa0000)
{
++descriptor;
gdt_size -= sizeof(*descriptor);
if (!gdt_size)
break;
}
if (gdt_size)
return (descriptor - gdt_ptr) << 3;
descriptor = gdt_ptr[ldt_segment >> 3]->base;
ldt_size = gdt_ptr[ldt_segment >> 3]->limit + 1;
while (descriptor->base != 0xa0000)
{
++descriptor;
ldt_size -= sizeof(*descriptor);
if (!ldt_size)
break;
}
if (ldt_size)
return (descriptor - ldt_ptr) << 3;
return 0;
}
Currently we emulate IDT access. On a read fault, we execute sidt ourselves,
check if the read address falls within the IDT, and return some dummy data
from the exception handler if it does [1]. We can easily enough implement GDT
access as well this way, and there is even an out-of-tree patch written some
years ago that does this, and helps the game run.
However, there are two problems that I have observed or anticipated:
(1) On systems with UMIP, the kernel emulates sgdt instructions and returns a
consistent address which we can guarantee is invalid. However, it also returns
a size of zero. The program doesn't expect this (cf. the way the loop is
written above) and I believe will effectively loop forever in that case, or
until it finds the VGA selector or hits invalid memory.
I see two obvious ways to fix this: either adjust the size of the fake
kernel GDT, or provide a switch to stop emulating and let Wine handle it. The
latter may very well a more sustainable option in the long term (although I'll
admit I can't immediately come up with a reason why, other than "we might need
to raise the size yet again".)
Does anyone have opinions on this particular topic? I can look into
writing a patch but I'm not sure what the best approach is.
(2) On 64-bit systems without UMIP, sgdt returns a truncated address when in
32-bit mode. This truncated address in practice might point anywhere in the
address space, including to valid memory.
In order to fix this, we would need the kernel to guarantee that the GDT
base points to an address whose bottom 32 bits we can guarantee are
inaccessible. This is relatively easy to achieve ourselves by simply mapping
those pages as noaccess, but it also means that those pages can't overlap
something we need; we already go to pains to make sure that certain parts of
the address space are free. Broadly anything above the 2G boundary *should* be
okay though. Is this feasible?
We could also just decide we don't care about systems without UMIP, but
that seems a bit unfortunate; it's not that old of a feature. But I also have
no idea how hard it would be to make this kind of a guarantee on the kernel
side.
This is also, theoretically, a problem for the IDT, except that on the
machines I've tested, the IDT is always at 0xfffffe0000000000. That's not
great either (it's certainly caused some weirdness and confusion when
debugging, when we unexpectedly catch an unrelated null pointer access) but it
seems to work in practice.
--Zeb
[1] https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/krnl386.exe16/
instr.c#l702
Hi,
I've been looking to get League of Legends work in Wine.
The issue is that their Anti-Cheat hooks bunch of functions in
ntdll.dll directly by prepending `jmp their_code` before the real
function and it seems it messes something up.
Anyway, topic of this email is about handling of stack overflow.
When their exception handler gets messed up it is invoked recursively
until stack overflow.
And because it happened while it was in critical section it causes
other threads to deadlock.
My question is how such case should be handled?
When thread is killed should lock be released so other threads can
still proceed?
Or maybe just whole process should be killed if any thread has stack overflow?
To me it looks like in Windows when exception handler goes too deep
then Just in Time debugger is invoked or if that's not enabled then
process is killed with EXCEPTION_ACCESS_VIOLATION (maybe because it
tried to access beyond end of stack?)
Log looks like:
[...]
0120:trace:seh:call_handler calling handler 00006FFFFFC97030
(rec=00007F3214C54360, frame=00007F3214D4E710
context=00007F3214C538D0, dispatch=00007F3214C537A0)
0120:trace:seh:call_handler handler at 00006FFFFFC97030 returned 2
0120:trace:seh:call_stack_handlers nested exception
0120:trace:seh:call_handler calling handler 00000001413B347C
(rec=00007F3214C54360, frame=00007F3214D4F570
context=00007F3214C538D0, dispatch=00007F3214C537A0)
0120:err:virtual:virtual_setup_exception stack overflow 2576 bytes
addr 0x6ffff9e66327 stack 0x7f3214c505f0
(0x7f3214c50000-0x7f3214c51000-0x7f3214d50000)
0124:err:sync:RtlpWaitForCriticalSection section 00006FFFFFCAE4C0
"../wine/dlls/ntdll/loader.c: loader_section" wait timed out in thread
0124, blocked by 0120, retrying (60 sec)
011c:err:sync:RtlpWaitForCriticalSection section 00006FFFFFCAE4C0
"../wine/dlls/ntdll/loader.c: loader_section" wait timed out in thread
011c, blocked by 0120, retrying (60 sec)
[...]
// stuck like this
And several threads stuck like this
Thread 8 (Thread 472 "011c"):
#0 0x00006fffffc966d4 in NtWaitForAlertByThreadId () from
/opt/wine-lol-staging/lib/wine/x86_64-windows/ntdll.dll
#1 0x00006fffffc9db68 in RtlWaitOnAddress
(addr=addr@entry=0x6fffffcae4d8 <loader_section+24>,
cmp=cmp@entry=0x6fffffcbda90 <zero>, size=size@entry=4,
timeout=timeout@entry=0x7fc37b38f700) at ../wine/dlls/ntdll/sync.c:912
#2 0x00006fffffc9dd06 in wait_semaphore (timeout=<optimized out>,
crit=0x6fffffcae4c0 <loader_section>) at ../wine/dlls/ntdll/sync.c:196
#3 RtlpWaitForCriticalSection (crit=crit@entry=0x6fffffcae4c0
<loader_section>) at ../wine/dlls/ntdll/sync.c:314
#4 0x00006fffffc9df71 in RtlEnterCriticalSection
(crit=crit@entry=0x6fffffcae4c0 <loader_section>) at
../wine/dlls/ntdll/sync.c:383
#5 0x00006fffffc7667b in loader_init
(context=context@entry=0x7fc37b38fb00,
entry=entry@entry=0x7fc37b38fb80) at ../wine/dlls/ntdll/loader.c:4405
#6 0x00006fffffc9a444 in LdrInitializeThunk (context=0x7fc37b38fb00,
unk2=<optimized out>, unk3=<optimized out>, unk4=<optimized out>) at
../wine/dlls/ntdll/signal_x86_64.c:1716
#7 0x00006ffff88f7954 in ?? () from /mnt/Riot Games/League of
Legends/wine/dosdevices/s:/Riot Games/League of Legends/Game/stub.dll
Best regards,
Dāvis