Index: /trunk/src/kash/Makefile.kmk
===================================================================
--- /trunk/src/kash/Makefile.kmk	(revision 2291)
+++ /trunk/src/kash/Makefile.kmk	(revision 2292)
@@ -32,4 +32,5 @@
 PROGRAMS += kash
 kash_TEMPLATE = BIN
+kash_ASTOOL = YASM
 kash_DEFS = lint SHELL SMALL
 kash_DEFS += SH_STUB_MODE # for the time being.
@@ -50,4 +51,7 @@
 	HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME
 kash_INCS = $(PATH_kash) . # (the last is because of error.h)
+kash_ASFLAGS.win = -g cv8
+kash_ASFLAGS.win.x86   = -f win32
+kash_ASFLAGS.win.amd64 = -f win64
 if "$(USER)" == "bird" && "$(KBUILD_TARGET)" != "win"
 kash_CFLAGS += -std=gnu99
@@ -96,5 +100,7 @@
 kash_SOURCES.win = \
 	sys_signame.c \
-	strlcpy.c
+	strlcpy.c \
+	shfork-win.c \
+	shforkA-win.asm
 kash_SOURCES.solaris = \
 	sys_signame.c \
Index: /trunk/src/kash/main.c
===================================================================
--- /trunk/src/kash/main.c	(revision 2291)
+++ /trunk/src/kash/main.c	(revision 2292)
@@ -101,5 +101,9 @@
 
 int
+#if K_OS == K_OS_WINDOWS
+real_main(int argc, char **argv, char **envp)
+#else
 main(int argc, char **argv, char **envp)
+#endif
 {
 	shinstance *psh;
Index: /trunk/src/kash/shfork-win.c
===================================================================
--- /trunk/src/kash/shfork-win.c	(revision 2292)
+++ /trunk/src/kash/shfork-win.c	(revision 2292)
@@ -0,0 +1,140 @@
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <string.h>
+#include <locale.h>
+#include "shinstance.h"
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static void *g_stack_base = 0;
+static void *g_stack_limit = 0;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void *shfork_string_to_ptr(const char *str, const char *argv0, const char *what);
+
+/* in shforkA-win.asm: */
+extern void shfork_resume(void *cur, void *base, void *limit);
+
+/* called by shforkA-win.asm: */
+void *shfork_maybe_forked(int argc, char **argv, char **envp);
+extern int shfork_body(uintptr_t stack_ptr);
+
+
+/***
+ * Called by shforkA-win.asm to check whether we're a forked child
+ * process or not.
+ *
+ * In the former case we will resume execution at the fork resume
+ * point. In the latter we'll allocate a new stack of the forkable
+ * heap and return it to the caller so real_main() in main.c can be
+ * invoked on it.
+ *
+ * @returns Stack or not at all.
+ * @param   argc    Argument count.
+ * @param   argv    Argument vector.
+ * @param   envp    Environment vector.
+ */
+void *shfork_maybe_forked(int argc, char **argv, char **envp)
+{
+    void *stack_ptr;
+
+    /*
+     * Are we actually forking?
+     */
+    if (    argc != 8
+        ||  strcmp(argv[1], "--!forked!--")
+        ||  strcmp(argv[2], "--stack-address")
+        ||  strcmp(argv[4], "--stack-base")
+        ||  strcmp(argv[6], "--stack-limit"))
+    {
+        shheap_init();
+        return (char *)sh_malloc(NULL, 1*1024*1024) + 1*1024*1024;
+    }
+
+    /*
+     * Do any init that needs to be done before resuming the
+     * fork() call.
+     */
+	setlocale(LC_ALL, "");
+
+    /*
+     * Convert the stack addresses.
+     */
+    stack_ptr     = shfork_string_to_ptr(argv[3], argv[0], "--stack-address");
+    g_stack_base  = shfork_string_to_ptr(argv[5], argv[0], "--stack-base");
+    g_stack_limit = shfork_string_to_ptr(argv[7], argv[0], "--stack-limit");
+
+    /*
+     * Switch stack and jump to the fork resume point.
+     */
+    shfork_resume(stack_ptr, g_stack_base, g_stack_limit);
+    /* (won't get here) */
+    return NULL;
+}
+
+/***
+ * Converts a string into a pointer.
+ *
+ * @returns Pointer.
+ * @param   argv0   The program name in case of error.
+ * @param   str     The string to convert.
+ */
+static void *shfork_string_to_ptr(const char *str, const char *argv0, const char *what)
+{
+    const char *start = str;
+    intptr_t ptr = 0;
+    if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+        str += 2;
+    while (*str)
+    {
+        unsigned digit;
+        switch (*str)
+        {
+            case '0':            digit =   0; break;
+            case '1':            digit =   1; break;
+            case '2':            digit =   2; break;
+            case '3':            digit =   3; break;
+            case '4':            digit =   4; break;
+            case '5':            digit =   5; break;
+            case '6':            digit =   6; break;
+            case '7':            digit =   7; break;
+            case '8':            digit =   8; break;
+            case '9':            digit =   9; break;
+            case 'a': case 'A':  digit = 0xa; break;
+            case 'b': case 'B':  digit = 0xb; break;
+            case 'c': case 'C':  digit = 0xc; break;
+            case 'd': case 'D':  digit = 0xd; break;
+            case 'e': case 'E':  digit = 0xe; break;
+            case 'f': case 'F':  digit = 0xf; break;
+            default:
+                fprintf(stderr, "%s: fatal error: Invalid %s '%s'\n", argv0, what, start);
+                exit(2);
+        }
+        ptr <<= 4;
+        ptr |= digit;
+    }
+    return (void *)ptr;
+}
+
+/***
+ * Create the child process making sure it inherits all our handles,
+ * copy of the forkable heap and kick it off.
+ *
+ * Called by shfork_do_it() in shforkA-win.asm.
+ *
+ * @returns child pid on success, -1 and errno on failure.
+ * @param   stack_ptr       The stack address at which the guest is suppost to resume.
+ */
+int shfork_body(uintptr_t stack_ptr)
+{
+    errno = ENOSYS;
+    return -1;
+}
Index: /trunk/src/kash/shforkA-win.asm
===================================================================
--- /trunk/src/kash/shforkA-win.asm	(revision 2292)
+++ /trunk/src/kash/shforkA-win.asm	(revision 2292)
@@ -0,0 +1,328 @@
+; $Id$
+;; @file
+; shforkA-win.asm - assembly routines used when forking on Windows.
+;
+
+;
+; Copyright (c) 2009 knut st. osmundsen <bird-kBuild-spamix@anduin.net>
+;
+; This file is part of kBuild.
+;
+; kBuild is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; kBuild is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+;
+;
+
+;*******************************************************************************
+;*      Defined Constants And Macros                                           *
+;*******************************************************************************
+%ifdef KBUILD_ARCH_AMD64
+ %define NAME(name) name
+%else
+ %define NAME(name) _ %+ name
+%endif
+
+
+;*******************************************************************************
+;*      External Symbols                                                       *
+;*******************************************************************************
+extern NAME(real_main)
+extern NAME(shfork_maybe_forked)
+extern NAME(shfork_body)
+
+
+[section .text]
+
+;;
+; C main() wrapper.
+;
+NAME(main):
+global NAME(main)
+%ifdef KBUILD_ARCH_AMD64
+[proc_frame main]
+%endif
+
+        ;
+        ; Prolog, spilling parameters from registers.
+        ;
+%ifdef KBUILD_ARCH_AMD64
+        [pushreg rbp]
+        push    rbp
+        [setframe rbp, 0]
+        mov     rbp, rsp
+        [allocstack 0x40]
+        sub     rsp, 40h
+        and     rsp, ~1fh
+        mov     [rsp    ], rcx          ; argc
+        mov     [rsp+ 8h], rdx          ; argv
+        mov     [rsp+10h], r8           ; envp
+        [endprolog]
+%else
+        push    ebp
+        mov     ebp, esp
+        sub     esp, 40h
+        and     esp, ~1fh
+%endif
+
+        ;
+        ; Call shfork_maybe_forked. This will not return if we're forking.
+        ;
+%ifndef KBUILD_ARCH_AMD64
+        mov     ecx, [ebp +  8h]        ; argc
+        mov     edx, [ebp + 0ch]        ; argv
+        mov     eax, [ebp + 10h]        ; envp
+        mov     [esp     ], ecx
+        mov     [esp + 4h], edx
+        mov     [esp + 8h], eax
+%endif
+        call    NAME(shfork_maybe_forked)
+
+        ;
+        ; Ok, it returned which means we're not forking.
+        ;
+        ; The accumulator register is now pointing to the top of the
+        ; stack we're going to call real_main on. Switch and call it.
+        ;
+        ; The TIB adjustments is required or we'll crash in longjmp/unwind.
+        ;
+%ifdef KBUILD_ARCH_AMD64
+        mov     [rsp + 18h], rax
+        mov     [rax -  8h], rsp
+
+        mov     r10, [gs:08h]           ; StackBase  (the higher value)
+        mov     r11, [gs:10h]           ; StackLimit (the lower value)
+        mov     [rax - 10h], r10
+        mov     [rax - 18h], r11
+        cmp     rax, r10
+        jb      .below
+        mov     [gs:08h], rax
+.below:
+        lea     r9, [rax - 1*1024*1024]
+        cmp     r9, r11
+        ja      .above
+        mov     [gs:10h], r9
+.above:
+
+        mov     rcx, [rsp      ]        ; argc
+        mov     rdx, [rsp + 08h]        ; argv
+        mov     r8,  [rsp + 10h]        ; envp
+
+        lea     rsp, [eax - 40h]        ; Switch!
+%else
+        mov     [esp + 18h], eax
+        mov     [eax - 4], esp
+        lea     esp, [eax - 40h]        ; Switch!
+
+        mov     edx, [fs:04h]           ; StackBase  (the higher value)
+        mov     ecx, [fs:08h]           ; StackLimit (the lower value)
+        mov     [eax - 10h], edx
+        mov     [eax - 18h], ecx
+        cmp     rax, edx
+        jb      .below
+        mov     [fs:04h], rax
+.below:
+        lea     edx, [eax - 1*1024*1024]
+        cmp     edx, ecx
+        ja      .above
+        mov     [fs:08h], edx
+.above:
+
+        mov     ecx, [ebp +  8h]        ; argc
+        mov     edx, [ebp + 0ch]        ; argv
+        mov     eax, [ebp + 10h]        ; envp
+
+        mov     [esp     ], ecx
+        mov     [esp + 4h], edx
+        mov     [esp + 8h], eax
+%endif
+        call    NAME(real_main)
+
+        ;
+        ; Switch back the stack, restore the TIB fields and we're done.
+        ;
+%ifdef KBUILD_ARCH_AMD64
+        lea     r11, [rsp + 40h]
+        mov     rsp, [rsp + 38h]
+        mov     r8, [r11 - 10h]
+        mov     r9, [r11 - 18h]
+        mov     [gs:08h], r8
+        mov     [gs:10h], r9
+%else
+        lea     edx, [esp + 40h]
+        mov     esp, [esp + 2ch]
+        mov     ecx, [edx - 10h]
+        mov     edx, [edx - 18h]
+        mov     [fs:04h], ecx
+        mov     [fs:08h], edx
+%endif
+        leave
+        ret
+%ifdef KBUILD_ARCH_AMD64
+[endproc_frame main]
+%endif
+
+
+;;
+; sh_fork() worker
+;
+NAME(shfork_do_it):
+global NAME(shfork_do_it)
+%ifdef KBUILD_ARCH_AMD64
+        [proc_frame shfork_do_it]
+        [pushreg rbp]
+        push    rbp
+        [setframe rbp, 0]
+        mov     rbp, rsp
+        [allocstack 0x400]
+        sub     rsp, 400h
+        and     rsp, ~1ffh
+[endprolog]
+%else
+        push    ebp
+        mov     ebp, esp
+        sub     esp, 400h
+        and     esp, ~1ffh
+%endif
+
+        ;
+        ; Save most registers so they can be restored in the child.
+        ;
+%ifdef KBUILD_ARCH_AMD64
+        fxsave  [rsp]
+        mov     [rsp + 200h], rbp
+        mov     [rsp + 208h], rax
+        mov     [rsp + 210h], rbx
+        mov     [rsp + 218h], rcx
+        mov     [rsp + 220h], rdx
+        mov     [rsp + 228h], rsi
+        mov     [rsp + 230h], rdi
+        mov     [rsp + 238h],  r8
+        mov     [rsp + 240h],  r9
+        mov     [rsp + 248h], r10
+        mov     [rsp + 250h], r11
+        mov     [rsp + 258h], r12
+        mov     [rsp + 260h], r13
+        mov     [rsp + 268h], r14
+        mov     [rsp + 270h], r15
+%else
+        fxsave  [esp]
+        mov     [esp + 200h], ebp
+        mov     [esp + 208h], eax
+        mov     [esp + 210h], ebx
+        mov     [esp + 218h], ecx
+        mov     [esp + 220h], edx
+        mov     [esp + 228h], esi
+        mov     [esp + 230h], edi
+%endif
+
+        ;
+        ; Call the shfork_body that will spawn the child and all that.
+        ;
+%ifdef KBUILD_ARCH_AMD64
+        mov     rcx, rsp
+%else
+        mov     ecx, esp
+        sub     esp, 20h
+        mov     [esp], ecx
+%endif
+        call    NAME(shfork_body)
+%ifdef KBUILD_ARCH_AMD64
+        lea     esp, [esp + 20h]
+%endif
+
+        ;
+        ; Just leave the function, no need to restore things.
+        ;
+        leave
+        ret
+%ifdef KBUILD_ARCH_AMD64
+[endproc_frame shfork_do_it]
+%endif
+
+
+;;
+; Switch the stack, restore the register and leave as if we'd called shfork_do_it.
+;
+; @param        cur     Current stack pointer.
+; @param        base    The stack base  (higher value).
+; @param        limit   The stack limit (lower value).
+;
+NAME(shfork_resume):
+global NAME(shfork_resume)
+%ifdef KBUILD_ARCH_AMD64
+        mov     rsp, rcx
+%else
+        mov     ecx, [esp + 4]
+        mov     edx, [esp + 8]
+        mov     eax, [esp + 12]
+        mov     esp, ecx
+%endif
+
+        ;
+        ; Adjust stack stuff in the TIB (longjmp/unwind).
+        ;
+%ifdef KBUILD_ARCH_AMD64
+        cmp     rdx, [gs:08h]           ; StackBase  (the higher value)
+        jb      .below
+        mov     [gs:08h], rdx
+.below:
+        cmp     r8,  [gs:10h]           ; StackLimit
+        ja      .above
+        mov     [gs:10h], r8
+.above:
+%else
+        cmp     edx, [fs:04h]           ; StackBase  (the higher value)
+        jb      .below
+        mov     [fs:04h], edx
+.below:
+        cmp     eax, [fs:08h]           ; StackLimit
+        ja      .above
+        mov     [fs:08h], eax
+.above:
+%endif
+
+        ;
+        ; Restore most of the registers.
+        ;
+        ;; @todo xmm registers may require explicit saving/restoring...
+%ifdef KBUILD_ARCH_AMD64
+        frstor  [rsp]
+        mov     rbp, [rsp + 200h]
+        mov     rax, [rsp + 208h]
+        mov     rbx, [rsp + 210h]
+        mov     rcx, [rsp + 218h]
+        mov     rdx, [rsp + 220h]
+        mov     rsi, [rsp + 228h]
+        mov     rdi, [rsp + 230h]
+        mov      r8, [rsp + 238h]
+        mov      r9, [rsp + 240h]
+        mov     r10, [rsp + 248h]
+        mov     r11, [rsp + 250h]
+        mov     r12, [rsp + 258h]
+        mov     r13, [rsp + 260h]
+        mov     r14, [rsp + 268h]
+        mov     r15, [rsp + 270h]
+%else
+        frstor  [esp]
+        mov     ebp, [esp + 200h]
+        mov     eax, [esp + 208h]
+        mov     ebx, [esp + 210h]
+        mov     ecx, [esp + 218h]
+        mov     edx, [esp + 220h]
+        mov     esi, [esp + 228h]
+        mov     edi, [esp + 230h]
+%endif
+        xor     eax, eax                ; the child returns 0.
+        leave
+        ret
+
Index: /trunk/src/kash/shheap.c
===================================================================
--- /trunk/src/kash/shheap.c	(revision 2291)
+++ /trunk/src/kash/shheap.c	(revision 2292)
@@ -29,4 +29,5 @@
 *   Header Files                                                               *
 *******************************************************************************/
+#include "shheap.h"
 #include <string.h>
 #include <stdlib.h>
Index: /trunk/src/kash/shheap.h
===================================================================
--- /trunk/src/kash/shheap.h	(revision 2291)
+++ /trunk/src/kash/shheap.h	(revision 2292)
@@ -1,5 +1,5 @@
 /* $Id$ */
 /** @file
- * The shell heap methods.
+ * The shell memory heap methods.
  */
 
@@ -32,4 +32,5 @@
 
 /* heap */
+int shheap_init(void);
 void *sh_malloc(shinstance *, size_t);
 void *sh_calloc(shinstance *, size_t, size_t);
Index: /trunk/src/kash/shinstance.c
===================================================================
--- /trunk/src/kash/shinstance.c	(revision 2291)
+++ /trunk/src/kash/shinstance.c	(revision 2292)
@@ -39,4 +39,8 @@
 #endif
 #include "shinstance.h"
+
+#if K_OS == K_OS_WINDOWS
+extern pid_t shfork_do_it(void); /* shforkA-win.asm */
+#endif
 
 
@@ -872,13 +876,11 @@
     pid = -1;
 
-#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
-#  ifdef SH_FORKED_MODE
-    /** @todo */
-    *(char *)1 = 0x1;
-#  else
+#elif K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
+    pid = shfork_do_it();
+
+#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
+# ifdef _MSC_VER
     pid = -1;
     errno = ENOSYS;
-#  endif
 # else
     pid = fork();
