Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tools/lkl/Makefile.autoconf
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,12 @@ endef

define nt_host
$(call set_autoconf_var,NT,y)
$(call set_kernel_config,INIT_STACK_ALL_ZERO,n)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used to make my old Cygwin GCC 11 happy. We can remove it if we maintain our own newer Cygwin cross compiler.

KOPT = "KALLSYMS_EXTRA_PASS=1"
KOPT += "HOSTCFLAGS=-Wno-char-subscripts"
KOPT += "HOSTLDFLAGS=-s"
LDLIBS += -lws2_32
LDFLAGS += -Wl,--image-base,0x10000
EXESUF := .exe
SOSUF := .dll
CFLAGS += -Iinclude/mingw32
Expand Down
1 change: 1 addition & 0 deletions tools/lkl/bin/x86_64-w64-mingw32-cc
22 changes: 22 additions & 0 deletions tools/lkl/bin/x86_64-w64-mingw32-gcc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash
# Shim: routes kernel code to cygwin cross-gcc, user-space to mingw-gcc.
# Cygwin-gcc: LP64 (long=64-bit), direct PE/COFF output, no Wine needed.
# Mingw-gcc: LLP64 (long=32-bit), standard Win64 libraries.
# The LKL API header uses __lkl_long_t (always 64-bit) to bridge the difference.
REAL_MINGW_GCC="/usr/bin/x86_64-w64-mingw32-gcc"
CYGWIN_GCC="/usr/bin/x86_64-pc-cygwin-gcc"
LKL_BIN_DIR="$(cd "$(dirname "$0")" && pwd)"

# Kernel code → cygwin-gcc (LP64)
for arg in "$@"; do
if [[ "$arg" == "-D__KERNEL__" ]]; then
exec "$CYGWIN_GCC" "$@"
fi
done

# User-space: use mingw-gcc with patched ld via specs
SPECS="$LKL_BIN_DIR/.lkl-linker.specs"
if [[ ! -f "$SPECS" ]]; then
printf '*linker:\n%s/x86_64-w64-mingw32-ld\n' "$LKL_BIN_DIR" > "$SPECS"
fi
exec "$REAL_MINGW_GCC" -specs="$SPECS" "$@"
Binary file added tools/lkl/bin/x86_64-w64-mingw32-ld
Comment thread
xdqi marked this conversation as resolved.
Binary file not shown.
Binary file added tools/lkl/bin/x86_64-w64-mingw32-objcopy
Binary file not shown.
89 changes: 88 additions & 1 deletion tools/lkl/lib/jmp_buf.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,92 @@
#include <setjmp.h>
#include <lkl_host.h>

#if defined(__x86_64__) && defined(_WIN64)
/*
* Custom non-SEH setjmp/longjmp for x86_64 Windows.
*
* Windows x64 longjmp uses RtlUnwindEx which walks the stack frame-by-frame.
* LKL uses longjmp for cooperative context switching between different stacks
* (each kernel thread has its own malloc'd stack). RtlUnwindEx cannot handle
* cross-stack jumps, causing stack overflow during unwinding.
* We bypass SEH entirely by doing a raw register save/restore.
*
* jmp_buf layout (16 bytes aligned):
* [0] rbx
* [1] rbp
* [2] r12
* [3] r13
* [4] r14
* [5] r15
* [6] rsp (after return from setjmp)
* [7] rip (return address)
* [8] rdi
* [9] rsi
*/

static inline int lkl_setjmp(void *buf)
{
int ret;
__asm__ __volatile__ (
"movq %%rbx, 0(%[b])\n\t"
"movq %%rbp, 8(%[b])\n\t"
"movq %%r12, 16(%[b])\n\t"
"movq %%r13, 24(%[b])\n\t"
"movq %%r14, 32(%[b])\n\t"
"movq %%r15, 40(%[b])\n\t"
"leaq 8(%%rsp), %%rax\n\t"
"movq %%rax, 48(%[b])\n\t"
"movq (%%rsp), %%rax\n\t"
"movq %%rax, 56(%[b])\n\t"
"movq %%rdi, 64(%[b])\n\t"
"movq %%rsi, 72(%[b])\n\t"
"xorl %[ret], %[ret]\n\t"
: [ret] "=a" (ret)
: [b] "r" (buf)
: "memory"
);
return ret;
}

__attribute__((noreturn))
static void lkl_longjmp(void *buf, int val)
{
__asm__ __volatile__ (
"movq 0(%[b]), %%rbx\n\t"
"movq 8(%[b]), %%rbp\n\t"
"movq 16(%[b]), %%r12\n\t"
"movq 24(%[b]), %%r13\n\t"
"movq 32(%[b]), %%r14\n\t"
"movq 40(%[b]), %%r15\n\t"
"movq 48(%[b]), %%rsp\n\t"
"movq 64(%[b]), %%rdi\n\t"
"movq 72(%[b]), %%rsi\n\t"
"movl %[v], %%eax\n\t"
"testl %%eax, %%eax\n\t"
"jnz 1f\n\t"
"incl %%eax\n\t"
"1:\n\t"
"jmpq *56(%[b])\n\t"
:
: [b] "r" (buf), [v] "r" (val)
: "memory"
);
__builtin_unreachable();
}

void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void))
{
if (!lkl_setjmp(jmpb->buf))
f();
}

void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val)
{
lkl_longjmp(jmpb->buf, val);
}

#else
#include <setjmp.h>

void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void))
{
if (!setjmp(*((jmp_buf *)jmpb->buf)))
Expand All @@ -11,3 +97,4 @@ void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val)
{
longjmp(*((jmp_buf *)jmpb->buf), val);
}
#endif