From 96cd0949b69398f5aa132105c81d7ce2d1f8682d Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Wed, 7 Oct 2009 19:17:24 +0300 Subject: [PATCH] Correct placement of arguments and environment on stack. int main(int argc, char *argv[]) style main function works now on Codezero/POSIX. --- conts/libc/src/getenv.c | 88 ----------------- conts/posix/SConstruct | 1 + .../posix/libposix/include/posix/posix_init.h | 3 +- conts/posix/libposix/init.c | 14 +++ conts/posix/mm0/mm/execve.c | 29 ++++-- conts/posix/mm0/mm/task.c | 99 ++++++++++++++----- conts/posix/test0/SConscript | 9 +- conts/posix/test0/container.c | 18 +++- conts/posix/test0/include/posix_init.h | 3 +- conts/posix/test0/main.c | 2 +- conts/posix/test0/src/crt0.S | 96 +++--------------- 11 files changed, 147 insertions(+), 215 deletions(-) delete mode 100644 conts/libc/src/getenv.c create mode 100644 conts/posix/libposix/init.c diff --git a/conts/libc/src/getenv.c b/conts/libc/src/getenv.c deleted file mode 100644 index 7a0c37e..0000000 --- a/conts/libc/src/getenv.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Australian Public Licence B (OZPLB) - * - * Version 1-0 - * - * Copyright (c) 2004 National ICT Australia - * - * All rights reserved. - * - * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS) - * National ICT Australia - * http://www.ertos.nicta.com.au - * - * Permission is granted by National ICT Australia, free of charge, to - * any person obtaining a copy of this software and any associated - * documentation files (the "Software") to deal with the Software without - * restriction, including (without limitation) the rights to use, copy, - * modify, adapt, merge, publish, distribute, communicate to the public, - * sublicense, and/or sell, lend or rent out copies of the Software, and - * to permit persons to whom the Software is furnished to do so, subject - * to the following conditions: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimers. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimers in the documentation and/or other materials provided - * with the distribution. - * - * * Neither the name of National ICT Australia, nor the names of its - * contributors, may be used to endorse or promote products derived - * from this Software without specific prior written permission. - * - * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT - * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND - * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS, - * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS - * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE, - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, - * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF - * ERRORS, WHETHER OR NOT DISCOVERABLE. - * - * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL - * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL - * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER - * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR - * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS - * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR - * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT, - * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN - * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER - * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS - * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS, - * DAMAGES OR OTHER LIABILITY. - * - * If applicable legislation implies representations, warranties, or - * conditions, or imposes obligations or liability on National ICT - * Australia or one of its contributors in respect of the Software that - * cannot be wholly or partly excluded, restricted or modified, the - * liability of National ICT Australia or the contributor is limited, to - * the full extent permitted by the applicable legislation, at its - * option, to: - * a. in the case of goods, any one or more of the following: - * i. the replacement of the goods or the supply of equivalent goods; - * ii. the repair of the goods; - * iii. the payment of the cost of replacing the goods or of acquiring - * equivalent goods; - * iv. the payment of the cost of having the goods repaired; or - * b. in the case of services: - * i. the supplying of the services again; or - * ii. the payment of the cost of having the services supplied again. - * - * The construction, validity and performance of this licence is governed - * by the laws in force in New South Wales, Australia. - */ - -#include -#include - -char * -getenv(const char *name) -{ - printf("WARNING: getenv not implemented\n"); - return NULL; -} diff --git a/conts/posix/SConstruct b/conts/posix/SConstruct index 4cf07e9..5e91654 100644 --- a/conts/posix/SConstruct +++ b/conts/posix/SConstruct @@ -74,6 +74,7 @@ rootfs = SConscript('rootfs/SConscript', \ exports = { 'config' : config, 'environment' : env, 'contid' : contid, 'previmage' : mm0 }, duplicate = 0, \ variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/rootfs')) +# No libposix reference because it conflicts with the compiler C library + the cluncky libc we have. test0_env = env.Clone() test0_env.Replace(CPPPATH = ['include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE]) test0 = SConscript('test0/SConscript', \ diff --git a/conts/posix/libposix/include/posix/posix_init.h b/conts/posix/libposix/include/posix/posix_init.h index 43a99b2..39307a2 100644 --- a/conts/posix/libposix/include/posix/posix_init.h +++ b/conts/posix/libposix/include/posix/posix_init.h @@ -1,7 +1,6 @@ #ifndef __LIBPOSIX_INIT_H__ #define __LIBPOSIX_INIT_H__ -void libposix_init(void); -void posix_service_init(void); +int __libposix_init(void *envp); #endif /* __LIBPOSIX_INIT_H__ */ diff --git a/conts/posix/libposix/init.c b/conts/posix/libposix/init.c new file mode 100644 index 0000000..2667183 --- /dev/null +++ b/conts/posix/libposix/init.c @@ -0,0 +1,14 @@ + + +#include +#include +#include +#include +#include + +int __libposix_init(void *envp) +{ + __environ = envp; + return 0; +} + diff --git a/conts/posix/mm0/mm/execve.c b/conts/posix/mm0/mm/execve.c index ec02123..cdb621e 100644 --- a/conts/posix/mm0/mm/execve.c +++ b/conts/posix/mm0/mm/execve.c @@ -1,4 +1,4 @@ -/* It is safe when argc = 0 *//* +/* * Program execution * * Copyright (C) 2008 Bahadir Balban @@ -21,6 +21,7 @@ #include #include #include +#include /* * Probes and parses the low-level executable file format and creates a @@ -40,16 +41,29 @@ int init_execve(char *filepath) struct vm_file *vmfile; struct exec_file_desc efd; struct tcb *new_task; + struct args_struct args, env; + char *env_string = "pagerid=0"; + int err; + struct task_ids ids = { .tid = TASK_ID_INVALID, .spid = TASK_ID_INVALID, - .tgid = TASK_ID_INVALID + .tgid = TASK_ID_INVALID, }; - struct args_struct args = { .argc = 0 }; /* It is safe when argc = 0 */ - struct args_struct env = { .argc = 0 }; /* It is safe when argc = 0 */ - //struct tcb *self = find_task(self_tid()); - // int fd; - int err; + + /* Set up args_struct */ + args.argc = 1; + args.argv = alloca(sizeof(args.argv)); + args.argv[0] = alloca(strlen(filepath) + 1); + strncpy(args.argv[0], filepath, strlen(filepath) + 1); + args.size = sizeof(args.argv) * args.argc + strlen(filepath) + 1; + + /* Set up environment */ + env.argc = 1; + env.argv = alloca(sizeof(env.argv)); + env.argv[0] = alloca(strlen(env_string) + 1); + strncpy(env.argv[0], env_string, strlen(env_string) + 1); + env.size = sizeof(env.argv) + strlen(env_string) + 1; /* Get file info from vfs */ if ((err = vfs_open_bypath(filepath, &vnum, &length)) < 0) @@ -95,6 +109,7 @@ int init_execve(char *filepath) new_task->args_start, new_task->pagerid); + /* Add new task to global list */ global_add_task(new_task); diff --git a/conts/posix/mm0/mm/task.c b/conts/posix/mm0/mm/task.c index 620af59..d4e199e 100644 --- a/conts/posix/mm0/mm/task.c +++ b/conts/posix/mm0/mm/task.c @@ -425,47 +425,96 @@ struct tcb *task_create(struct tcb *parent, struct task_ids *ids, return task; } + /* * Copy argument and environment strings into task's stack in a * format that is expected by the C runtime. * * e.g. uclibc expects stack state: * - * (low) |->argc|argv[0]|argv[1]|...|argv[argc] = 0|envp[0]|...|NULL| (high) + * (low) |->argc|argv[0]|argv[1]|...|argv[argc] = 0|envp[0]|envp[1]|...|NULL| (high) + * + * IOW: + * + * argc + * argv pointers + * null + * env pointers + * null + * + * After the final null, we place the strings, but this is unspecified. + * On setting new environment strings, instead of using this fixed + * space, heap seems to get used in uClibc. * */ -int task_args_to_user(char *user_stack, struct args_struct *args, - struct args_struct *env) +int task_copy_args_to_user(char *user_stack, unsigned long user_ptr, + struct args_struct *args, struct args_struct *env) { + char **argv_start, **envp_start; + BUG_ON((unsigned long)user_stack & 7); /* Copy argc */ *((int *)user_stack) = args->argc; user_stack += sizeof(int); - /* Copy argument strings one by one */ - for (int i = 0; i < args->argc; i++) { - strcpy(user_stack, args->argv[i]); - user_stack += strlen(args->argv[i]) + 1; - } + /* Set beginning of argv */ + argv_start = (char **)user_stack; + + /* Forward by number of argv ptrs */ + user_stack += sizeof(int) * args->argc; + /* Put the null terminator integer */ *((int *)user_stack) = 0; user_stack = user_stack + sizeof(int); + /* Set beginning of envp */ + envp_start = (char **)user_stack; + /* Forward by number of envp ptrs */ + user_stack += sizeof(int) * env->argc; + + /* Put the null terminator integer */ + *((int *)user_stack) = 0; + user_stack = user_stack + sizeof(int); + + /* Copy argument strings one by one */ + for (int i = 0; i < args->argc; i++) { + /* Copy string */ + strcpy(user_stack, args->argv[i]); + + /* Set its pointer on stack */ + argv_start[i] = (char *) + ((user_ptr & ~PAGE_MASK) + | ((unsigned long)user_stack & + PAGE_MASK)); + + /* Update location */ + user_stack += strlen(args->argv[i]) + 1; + } + /* Copy environment strings one by one */ for (int i = 0; i < env->argc; i++) { + /* Copy string */ strcpy(user_stack, env->argv[i]); + + /* Set its pointer on stack */ + envp_start[i] = (char *) + ((user_ptr & ~PAGE_MASK) + | ((unsigned long)user_stack & + PAGE_MASK)); + user_stack += strlen(env->argv[i]) + 1; } return 0; } -int task_map_stack(struct vm_file *f, struct exec_file_desc *efd, struct tcb *task, - struct args_struct *args, struct args_struct *env) +int task_map_stack(struct vm_file *f, struct exec_file_desc *efd, + struct tcb *task, struct args_struct *args, + struct args_struct *env) { /* First set up task's stack markers */ - unsigned long stack_used = align_up(args->size + env->size, 8); + unsigned long stack_used = align_up(args->size + env->size + 8, 8); unsigned long arg_pages = __pfn(page_align_up(stack_used)); char *args_on_stack; void *mapped; @@ -491,23 +540,21 @@ int task_map_stack(struct vm_file *f, struct exec_file_desc *efd, struct tcb *ta return (int)mapped; } - /* If args or env use any bytes */ - if (stack_used) { - /* Map the stack's part that will contain args and environment */ - if (IS_ERR(args_on_stack = - pager_validate_map_user_range2(task, - (void *)task->args_start, - stack_used, - VM_READ | VM_WRITE))) { - return (int)args_on_stack; - } + /* Map the stack's part that will contain args and environment */ + if (IS_ERR(args_on_stack = + pager_validate_map_user_range2(task, + (void *)task->args_start, + stack_used, + VM_READ | VM_WRITE))) + return (int)args_on_stack; - /* Copy arguments and env */ - task_args_to_user(args_on_stack, args, env); + /* Copy arguments and env */ + task_copy_args_to_user(args_on_stack, + task->args_start, + args, env); - /* Unmap task's those stack pages from pager */ - pager_unmap_pages(args_on_stack, arg_pages); - } + /* Unmap task's those stack pages from pager */ + pager_unmap_pages(args_on_stack, arg_pages); return 0; } diff --git a/conts/posix/test0/SConscript b/conts/posix/test0/SConscript index 070694c..4797bf1 100644 --- a/conts/posix/test0/SConscript +++ b/conts/posix/test0/SConscript @@ -9,7 +9,7 @@ sys.path.append('../../../../') from config.lib import * from tools.pyelf.lmanext import * -src = [Glob('*.c') + Glob('test_exec.S') + Glob('src/*.c') + Glob('src/arch/arm/*.c')] +src = [Glob('*.c') + Glob('test_exec.S') + Glob('src/*.[Sc]') + Glob('src/arch/arm/*.c')] asm_string = \ ''' @@ -34,7 +34,7 @@ env = environment.Clone() test_exec_env = environment.Clone() test_exec_env.Append(LIBS = ['posix', 'c-userspace']) -test_exec_env.Append(LINKFLAGS = ['-T' + "test0/include/test_exec_linker.lds", '-u_start']) +test_exec_env.Append(LINKFLAGS = '-T' + "test0/include/test_exec_linker.lds") test_exec_env.Append(CPPFLAGS = ' -D__USERSPACE__') test_exec_env.Replace(PROGSUFFIX = '') test_exec_src = Glob('src/test_exec/*.[cS]') @@ -44,7 +44,7 @@ test_exec_asm = Command('test_exec.S', test_exec, generate_incbin_asm) Depends(test_exec, test_exec_objs) env.Append(LIBS = ['posix', 'c-userspace']) -env.Append(LINKFLAGS = ['-T' + lma_lds[0].path, '-u_start']) +env.Append(LINKFLAGS = '-T' + lma_lds[0].path) env.Append(CPPFLAGS = ' -D__USERSPACE__') env.Replace(PROGSUFFIX = '') objs = env.Object(src + test_exec_asm) @@ -75,6 +75,9 @@ elf_wrap_env.Append(LINKFLAGS = '-T' + elf_wrapped_lds[0].path) elf_wrap_objs = elf_wrap_env.Object(elf_wrapped_asm) test0_elf_elf = elf_wrap_env.Program('test0_elf.elf', elf_wrap_objs) +# So that everytime test0 is built, elf_wrap_objs +# gets built (even though elf_wrapped_asm remains the same +Depends(elf_wrap_objs, test0) Depends(test0, lma_lds) Depends(test0, test_exec) Depends(lma_lds, previmage) diff --git a/conts/posix/test0/container.c b/conts/posix/test0/container.c index e6ab94b..f9734f1 100644 --- a/conts/posix/test0/container.c +++ b/conts/posix/test0/container.c @@ -8,15 +8,27 @@ #include #include #include /* Initialisers for posix library */ +#include -void main(void); +int main(int argc, char *argv[]); -void __container_init(void) +int __container_init(int argc, char **argv) { + void *envp = &argv[argc + 1]; + char *pagerval; + + if ((char *)envp == *argv) + envp = &argv[argc]; + + __libposix_init(envp); + + pagerval = getenv("pagerid"); + printf("Pager id: %s\n", pagerval); + /* Generic L4 thread initialisation */ __l4_init(); /* Entry to main */ - main(); + return main(argc, argv); } diff --git a/conts/posix/test0/include/posix_init.h b/conts/posix/test0/include/posix_init.h index 43a99b2..39307a2 100644 --- a/conts/posix/test0/include/posix_init.h +++ b/conts/posix/test0/include/posix_init.h @@ -1,7 +1,6 @@ #ifndef __LIBPOSIX_INIT_H__ #define __LIBPOSIX_INIT_H__ -void libposix_init(void); -void posix_service_init(void); +int __libposix_init(void *envp); #endif /* __LIBPOSIX_INIT_H__ */ diff --git a/conts/posix/test0/main.c b/conts/posix/test0/main.c index 34d7d35..af6d7c2 100644 --- a/conts/posix/test0/main.c +++ b/conts/posix/test0/main.c @@ -25,7 +25,7 @@ void wait_pager(l4id_t partner) pid_t parent_of_all; -void main(void) +int main(int argc, char *argv[]) { printf("\n%s: Started with thread id %d\n", __TASKNAME__, getpid()); diff --git a/conts/posix/test0/src/crt0.S b/conts/posix/test0/src/crt0.S index 9bcb3a8..b9aabb0 100644 --- a/conts/posix/test0/src/crt0.S +++ b/conts/posix/test0/src/crt0.S @@ -1,93 +1,23 @@ /* - * Australian Public Licence B (OZPLB) - * - * Version 1-0 - * - * Copyright (c) 2004 National ICT Australia - * - * All rights reserved. - * - * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS) - * National ICT Australia - * http://www.ertos.nicta.com.au - * - * Permission is granted by National ICT Australia, free of charge, to - * any person obtaining a copy of this software and any associated - * documentation files (the "Software") to deal with the Software without - * restriction, including (without limitation) the rights to use, copy, - * modify, adapt, merge, publish, distribute, communicate to the public, - * sublicense, and/or sell, lend or rent out copies of the Software, and - * to permit persons to whom the Software is furnished to do so, subject - * to the following conditions: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimers. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimers in the documentation and/or other materials provided - * with the distribution. - * - * * Neither the name of National ICT Australia, nor the names of its - * contributors, may be used to endorse or promote products derived - * from this Software without specific prior written permission. - * - * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT - * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND - * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS, - * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS - * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE, - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, - * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF - * ERRORS, WHETHER OR NOT DISCOVERABLE. - * - * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL - * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL - * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER - * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR - * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS - * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR - * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT, - * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN - * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER - * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS - * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS, - * DAMAGES OR OTHER LIABILITY. - * - * If applicable legislation implies representations, warranties, or - * conditions, or imposes obligations or liability on National ICT - * Australia or one of its contributors in respect of the Software that - * cannot be wholly or partly excluded, restricted or modified, the - * liability of National ICT Australia or the contributor is limited, to - * the full extent permitted by the applicable legislation, at its - * option, to: - * a. in the case of goods, any one or more of the following: - * i. the replacement of the goods or the supply of equivalent goods; - * ii. the repair of the goods; - * iii. the payment of the cost of replacing the goods or of acquiring - * equivalent goods; - * iv. the payment of the cost of having the goods repaired; or - * b. in the case of services: - * i. the supplying of the services again; or - * ii. the payment of the cost of having the services supplied again. - * - * The construction, validity and performance of this licence is governed - * by the laws in force in New South Wales, Australia. + * Copyright (C) 2009 Bahadir Balban */ -#ifdef __thumb__ -#define bl blx -#endif +/* + * We expect initial stack state: + * + * (low) |->argc|argv[0]|argv[1]|...|argv[argc] = 0|envp[0]|...|NULL| (high) + * + */ - .section .text.head - .code 32 +.section .text.head .global _start; .align; _start: - ldr sp, =__stack - bl platform_init + mov fp, #0 @ Clear frame pointer + mov lr, #0 @ Clear link register + ldmfd sp!, {r0} @ Argc value in r0 + mov r1, sp @ Ptr to argv in r1 + bl __container_init 1: b 1b