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 | }
|
---|