| 1 |
|
|---|
| 2 |
|
|---|
| 3 | /*******************************************************************************
|
|---|
| 4 | * Header Files *
|
|---|
| 5 | *******************************************************************************/
|
|---|
| 6 | #include <string.h>
|
|---|
| 7 | #include <locale.h>
|
|---|
| 8 | #include "shinstance.h"
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 | /*******************************************************************************
|
|---|
| 12 | * Global Variables *
|
|---|
| 13 | *******************************************************************************/
|
|---|
| 14 | static void *g_stack_base = 0;
|
|---|
| 15 | static void *g_stack_limit = 0;
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 | /*******************************************************************************
|
|---|
| 19 | * Internal Functions *
|
|---|
| 20 | *******************************************************************************/
|
|---|
| 21 | static void *shfork_string_to_ptr(const char *str, const char *argv0, const char *what);
|
|---|
| 22 |
|
|---|
| 23 | /* in shforkA-win.asm: */
|
|---|
| 24 | extern void shfork_resume(void *cur, void *base, void *limit);
|
|---|
| 25 |
|
|---|
| 26 | /* called by shforkA-win.asm: */
|
|---|
| 27 | void *shfork_maybe_forked(int argc, char **argv, char **envp);
|
|---|
| 28 | extern int shfork_body(uintptr_t stack_ptr);
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 | /***
|
|---|
| 32 | * Called by shforkA-win.asm to check whether we're a forked child
|
|---|
| 33 | * process or not.
|
|---|
| 34 | *
|
|---|
| 35 | * In the former case we will resume execution at the fork resume
|
|---|
| 36 | * point. In the latter we'll allocate a new stack of the forkable
|
|---|
| 37 | * heap and return it to the caller so real_main() in main.c can be
|
|---|
| 38 | * invoked on it.
|
|---|
| 39 | *
|
|---|
| 40 | * @returns Stack or not at all.
|
|---|
| 41 | * @param argc Argument count.
|
|---|
| 42 | * @param argv Argument vector.
|
|---|
| 43 | * @param envp Environment vector.
|
|---|
| 44 | */
|
|---|
| 45 | void *shfork_maybe_forked(int argc, char **argv, char **envp)
|
|---|
| 46 | {
|
|---|
| 47 | void *stack_ptr;
|
|---|
| 48 |
|
|---|
| 49 | /*
|
|---|
| 50 | * Are we actually forking?
|
|---|
| 51 | */
|
|---|
| 52 | if ( argc != 8
|
|---|
| 53 | || strcmp(argv[1], "--!forked!--")
|
|---|
| 54 | || strcmp(argv[2], "--stack-address")
|
|---|
| 55 | || strcmp(argv[4], "--stack-base")
|
|---|
| 56 | || strcmp(argv[6], "--stack-limit"))
|
|---|
| 57 | {
|
|---|
| 58 | shheap_init();
|
|---|
| 59 | return (char *)sh_malloc(NULL, 1*1024*1024) + 1*1024*1024;
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 | /*
|
|---|
| 63 | * Do any init that needs to be done before resuming the
|
|---|
| 64 | * fork() call.
|
|---|
| 65 | */
|
|---|
| 66 | setlocale(LC_ALL, "");
|
|---|
| 67 |
|
|---|
| 68 | /*
|
|---|
| 69 | * Convert the stack addresses.
|
|---|
| 70 | */
|
|---|
| 71 | stack_ptr = shfork_string_to_ptr(argv[3], argv[0], "--stack-address");
|
|---|
| 72 | g_stack_base = shfork_string_to_ptr(argv[5], argv[0], "--stack-base");
|
|---|
| 73 | g_stack_limit = shfork_string_to_ptr(argv[7], argv[0], "--stack-limit");
|
|---|
| 74 |
|
|---|
| 75 | /*
|
|---|
| 76 | * Switch stack and jump to the fork resume point.
|
|---|
| 77 | */
|
|---|
| 78 | shfork_resume(stack_ptr, g_stack_base, g_stack_limit);
|
|---|
| 79 | /* (won't get here) */
|
|---|
| 80 | return NULL;
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | /***
|
|---|
| 84 | * Converts a string into a pointer.
|
|---|
| 85 | *
|
|---|
| 86 | * @returns Pointer.
|
|---|
| 87 | * @param argv0 The program name in case of error.
|
|---|
| 88 | * @param str The string to convert.
|
|---|
| 89 | */
|
|---|
| 90 | static void *shfork_string_to_ptr(const char *str, const char *argv0, const char *what)
|
|---|
| 91 | {
|
|---|
| 92 | const char *start = str;
|
|---|
| 93 | intptr_t ptr = 0;
|
|---|
| 94 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
|
|---|
| 95 | str += 2;
|
|---|
| 96 | while (*str)
|
|---|
| 97 | {
|
|---|
| 98 | unsigned digit;
|
|---|
| 99 | switch (*str)
|
|---|
| 100 | {
|
|---|
| 101 | case '0': digit = 0; break;
|
|---|
| 102 | case '1': digit = 1; break;
|
|---|
| 103 | case '2': digit = 2; break;
|
|---|
| 104 | case '3': digit = 3; break;
|
|---|
| 105 | case '4': digit = 4; break;
|
|---|
| 106 | case '5': digit = 5; break;
|
|---|
| 107 | case '6': digit = 6; break;
|
|---|
| 108 | case '7': digit = 7; break;
|
|---|
| 109 | case '8': digit = 8; break;
|
|---|
| 110 | case '9': digit = 9; break;
|
|---|
| 111 | case 'a': case 'A': digit = 0xa; break;
|
|---|
| 112 | case 'b': case 'B': digit = 0xb; break;
|
|---|
| 113 | case 'c': case 'C': digit = 0xc; break;
|
|---|
| 114 | case 'd': case 'D': digit = 0xd; break;
|
|---|
| 115 | case 'e': case 'E': digit = 0xe; break;
|
|---|
| 116 | case 'f': case 'F': digit = 0xf; break;
|
|---|
| 117 | default:
|
|---|
| 118 | fprintf(stderr, "%s: fatal error: Invalid %s '%s'\n", argv0, what, start);
|
|---|
| 119 | exit(2);
|
|---|
| 120 | }
|
|---|
| 121 | ptr <<= 4;
|
|---|
| 122 | ptr |= digit;
|
|---|
| 123 | }
|
|---|
| 124 | return (void *)ptr;
|
|---|
| 125 | }
|
|---|
| 126 |
|
|---|
| 127 | /***
|
|---|
| 128 | * Create the child process making sure it inherits all our handles,
|
|---|
| 129 | * copy of the forkable heap and kick it off.
|
|---|
| 130 | *
|
|---|
| 131 | * Called by shfork_do_it() in shforkA-win.asm.
|
|---|
| 132 | *
|
|---|
| 133 | * @returns child pid on success, -1 and errno on failure.
|
|---|
| 134 | * @param stack_ptr The stack address at which the guest is suppost to resume.
|
|---|
| 135 | */
|
|---|
| 136 | int shfork_body(uintptr_t stack_ptr)
|
|---|
| 137 | {
|
|---|
| 138 | errno = ENOSYS;
|
|---|
| 139 | return -1;
|
|---|
| 140 | }
|
|---|