diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 1736686dfdc57731e0367a09944c8b1bd44f8139..23831146aa51867aec5c172ad2cb1e68a2c4a2fd 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -16,11 +16,12 @@ * @param m an ELF module * @param rel an ELF relocation entry * @param sym the address of the target symbol + * @param sec_name the name of the section to apply the relocation in * * return 0 on success */ -int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym) +int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym, const char *sec_name) { Elf_Addr rsym; @@ -40,9 +41,13 @@ int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym) if (!sym) return -EINVAL; + if (!sec_name) { + pr_err("\tsec_name empty!\n"); + return -EINVAL; + } - text = find_mod_sec(m, ".text"); + text = find_mod_sec(m, sec_name); loc8 = (uint8_t *) (text->addr + rel->r_offset); loc32 = (uint32_t *) loc8; diff --git a/arch/sparc/kernel/ttable.S b/arch/sparc/kernel/ttable.S index 9ee891551c42fcc89d772864865df66c3f80bc8c..8cd0e19ecebc72804f654b96841a6c1790db18ea 100644 --- a/arch/sparc/kernel/ttable.S +++ b/arch/sparc/kernel/ttable.S @@ -145,8 +145,6 @@ hw_div0_trap_handler: nmi_entry: .global reg_access_trap_handler reg_access_trap_handler: - .global strchr -strchr: .global syscall_tbl syscall_tbl: .global syscall_trap @@ -159,4 +157,4 @@ syscall_trap: unimpl_flush_trap_handler: .global watchpoint_det_trap_handler watchpoint_det_trap_handler: - ta 0 + ta 3 diff --git a/include/kernel/elf.h b/include/kernel/elf.h index 4797c137df8986f1d7515d7a5636ff7352fa3a01..79739dc17a5860b2105df7e144020265e3e68a0a 100644 --- a/include/kernel/elf.h +++ b/include/kernel/elf.h @@ -568,6 +568,9 @@ int elf_header_check(Elf_Ehdr *ehdr); Elf_Shdr *elf_get_shdr(const Elf_Ehdr *ehdr); size_t elf_find_shdr_alloc_idx(const Elf_Ehdr *ehdr, const size_t offset); +size_t elf_get_common_size(const Elf_Ehdr *ehdr); +size_t elf_get_common_objects(const Elf_Ehdr *ehdr, char **objname); + Elf_Shdr *elf_get_sec_by_idx(const Elf_Ehdr *ehdr, const size_t idx); Elf_Shdr *elf_get_sec_shstrtab(const Elf_Ehdr *ehdr); char *elf_get_shstrtab_str(const Elf_Ehdr *ehdr, size_t idx); @@ -586,6 +589,7 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr, const char *name, unsigned long *value); unsigned long elf_get_symbol_type(const Elf_Ehdr *ehdr, const char *name); +size_t elf_get_symbol_size(const Elf_Ehdr *ehdr, const char *name); size_t elf_find_sec_idx_by_type(const Elf_Ehdr *ehdr, const uint32_t sh_type, @@ -606,4 +610,6 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr); void elf_dump_sections(const Elf_Ehdr *ehdr); +unsigned short elf_get_symbol_shndx(const Elf_Ehdr *ehdr, + const char *name); #endif /* _KERNEL_ELF_H_ */ diff --git a/include/kernel/module.h b/include/kernel/module.h index e357eaff481c85521a2b49b71aa8778a5de4185b..dc3584dcfa22484926021594c3b8d11252bc1ec9 100644 --- a/include/kernel/module.h +++ b/include/kernel/module.h @@ -62,7 +62,8 @@ struct elf_module { /* implemented in architecture code */ -int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym); +int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym, + const char *sec_name); struct module_section *find_mod_sec(const struct elf_module *m, diff --git a/include/kernel/string.h b/include/kernel/string.h index b39f37523bffa2953d379057cc8afc830e2ef02e..532d0db8ac84ebde948b1ccf237090c8d2b49317 100644 --- a/include/kernel/string.h +++ b/include/kernel/string.h @@ -20,12 +20,16 @@ char *strpbrk(const char *s, const char *accept); char *strsep(char **stringp, const char *delim); char *strdup(const char *s); +char *strchr(const char *s, int c); + char *strstr(const char *haystack, const char *needle); size_t strlen(const char *s); int memcmp(const void *s1, const void *s2, size_t n); void *memset(void *s, int c, size_t n); void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); + char *strcpy(char *dest, const char *src); void bzero(void *s, size_t n); @@ -46,5 +50,7 @@ int vprintf(const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap); +int puts(const char *s); +int putchar(int c); #endif /* _KERNEL_STRING_H_ */ diff --git a/init/Kconfig b/init/Kconfig index a786cac7cdaa4d70deae7d609f7b41398986da98..63b9260acc7ad60188778b86f413db61e4e14120 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -105,6 +105,16 @@ config EMBED_MODULES_IMAGE generated modules into the final kernel binary. This is a convenience option, if unsure, say Y. +config EMBED_APPLICATION + string "Embed an application image" + depends on EMBED_MODULES_IMAGE + default "" + help + Specify a path to an executable to embed or leave it empty. + Note: in the current implementation, the executable is treated as a + kernel module, so it requires to be relocatible and have a init/exit + call. + endif # MODULES @@ -178,4 +188,5 @@ config DEBUG_INFO_REDUCED DEBUG_INFO build and compile times are reduced too. Only works with newer gcc versions. + endmenu diff --git a/init/main.c b/init/main.c index 063716fd7b80e03b762381008559668ef50a1aac..eb3bb2f86e414c7c92dc083d706fe86788ffd2c6 100644 --- a/init/main.c +++ b/init/main.c @@ -163,6 +163,27 @@ int kernel_main(void) modules_list_loaded(); #endif + +#ifdef CONFIG_EMBED_APPLICATION + /* dummy demonstrator */ +{ + void *addr; + struct elf_module m; + + addr = module_read_embedded("CrApp1"); + + pr_debug(MSG "test executable address is %p\n", addr); + if (addr) + module_load(&m, addr); + +#if 0 + modules_list_loaded(); +#endif +} +#endif + + + #ifdef CONFIG_MPPB /* The mppbv2 LEON's cache would really benefit from cache sniffing... * Interactions with DMA or Xentiums are a pain when using the lower diff --git a/kernel/module.c b/kernel/module.c index b15a5d7893e3b3e8c99ad0bbf4deb3884524b867..aab0150f8a7decccb0c20a88faedc25b4fe44b04 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -69,6 +69,28 @@ struct module_section *find_mod_sec(const struct elf_module *m, } +/** + * @brief find module section by index + * + * @param m a struct elf_module + * + * @param idx the index of the module section + * + * @return module section structure pointer or NULL if not found + */ + +struct module_section *find_mod_idx(const struct elf_module *m, + size_t idx) + +{ + if (idx >= m->num_sec) + return NULL; + + return &m->sec[idx]; +} + + + /** * @brief setup the module structure * @@ -178,8 +200,13 @@ static int module_load_mem(struct elf_module *m) sec = elf_get_sec_by_idx(m->ehdr, idx); +#if 0 if (!sec->sh_size) /* don't need those */ continue; +#else + if (!(sec->sh_flags & SHF_ALLOC)) + continue; +#endif s->size = sec->sh_size; @@ -193,24 +220,27 @@ static int module_load_mem(struct elf_module *m) goto error; strcpy(s->name, src); + + pr_err(MOD "section %s index %d max %d\n", s->name, s, m->num_sec); if (sec->sh_type & SHT_NOBITS) { - pr_debug(MOD "\tZero segment %10s at %p size %ld\n", + pr_info(MOD "\tZero segment %10s at %p size %ld\n", s->name, (char *) va_load, sec->sh_size); bzero((void *) va_load, s->size); } else { - pr_debug(MOD "\tCopy segment %10s from %p to %p size %ld\n", + pr_info(MOD "\tCopy segment %10s from %p to %p size %ld\n", s->name, (char *) m->ehdr + sec->sh_offset, (char *) va_load, sec->sh_size); - memcpy((void *) va_load, - (char *) m->ehdr + sec->sh_offset, - sec->sh_size); + if (sec->sh_size) + memcpy((void *) va_load, + (char *) m->ehdr + sec->sh_offset, + sec->sh_size); } s->addr = va_load; @@ -219,10 +249,84 @@ static int module_load_mem(struct elf_module *m) s++; if (s > &m->sec[m->num_sec]) { - pr_debug(MOD "Error out of section memory\n"); + pr_err(MOD "Error out of section memory\n"); + goto error; + } + } + +#if 0 + if (elf_get_common_size(m->ehdr)) { + + m->num_sec++; + m->sec = (struct module_section *) + krealloc(m->sec, sizeof(struct module_section) * m->num_sec); + + if (!m->sec) + goto error; + + s = &m->sec[m->num_sec - 1]; + + s->size = elf_get_common_size(m->ehdr); + s->addr = (unsigned long) kzalloc(s->size); + if (!s->addr) + goto error; + + pr_info(MOD "\tcreating .alloc section of %d bytes at %x\n", s->size, s->addr); + + s->name = kmalloc(strlen(".alloc")); + if (!s->name) + goto error; + + strcpy(s->name, ".alloc"); + + } +#else + /* yes, yes, fixup like everything else here */ + if (elf_get_common_objects(m->ehdr, NULL)) { + size_t cnt = elf_get_common_objects(m->ehdr, NULL); + char **obj; + + m->sec = (struct module_section *) + krealloc(m->sec, sizeof(struct module_section) * (m->num_sec + cnt)); + + if (!m->sec) goto error; + + + /* point to last */ + s = &m->sec[m->num_sec]; + /* and update */ + m->num_sec += cnt; + + obj = kmalloc(cnt * sizeof(char **)); + if (!obj) + goto error; + /* load names */ + elf_get_common_objects(m->ehdr, obj); + + + /* Allocate one section entry for each object, this is not + * that efficient, but what the heck. Better not to have + * uninitialised non-static globals at all! + */ + for (idx = 0; idx < cnt; idx++) { + s->size = elf_get_symbol_size(m->ehdr, obj[idx]); + s->addr = (unsigned long) kzalloc(s->size); + if (!s->addr) + goto error; + pr_debug(MOD "\tcreating \"%s\" section of %d bytes at %x\n", obj[idx], s->size, s->addr); + s->name = kmalloc(strlen(obj[idx])); + if (!s->name) + goto error; + strcpy(s->name, obj[idx]); + s++; } + + kfree(obj); } +#endif + + return 0; @@ -264,11 +368,12 @@ static int module_relocate(struct elf_module *m) if (m->ehdr->e_type != ET_DYN) return 0; - /* we only need RELA type relocations */ while (1) { + char *rel_sec; + idx = elf_find_sec_idx_by_type(m->ehdr, SHT_RELA, idx + 1); if (!idx) @@ -276,8 +381,16 @@ static int module_relocate(struct elf_module *m) sec = elf_get_sec_by_idx(m->ehdr, idx); - pr_debug(MOD "\n" - MOD "Section Header info: %ld\n", sec->sh_info); + pr_info(MOD "\n" + MOD "Section Header info: %ld %s\n", sec->sh_info, elf_get_shstrtab_str(m->ehdr, idx)); + + if (!strcmp(elf_get_shstrtab_str(m->ehdr, idx), ".rela.text")) + rel_sec = ".text"; + else if (!strcmp(elf_get_shstrtab_str(m->ehdr, idx), ".rela.data")) + rel_sec = ".data"; + else + BUG(); + if (sec) { @@ -295,8 +408,8 @@ static int module_relocate(struct elf_module *m) unsigned int symsec = ELF_R_SYM(relatab[i].r_info); char *symstr = elf_get_symbol_str(m->ehdr, symsec); struct module_section *s; - struct module_section *text = find_mod_sec(m, ".text"); - + struct module_section *text = find_mod_sec(m, ".text"); /* ?? rel_sec ?? */ + pr_debug(MOD "OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n", relatab[i].r_offset, relatab[i].r_info, @@ -308,23 +421,63 @@ static int module_relocate(struct elf_module *m) if (strlen(symstr)) { - Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr); + unsigned long symval; + Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr); - if (!sym) { + if (!sym) { + pr_debug(MOD "\tSymbol %s not found in library, trying to resolving in module\n", + symstr); - unsigned long symval; - pr_info(MOD "\tSymbol %s not found in library, trying to resolving in module\n", - symstr); + if ((elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) { + char *secstr; - if (!(elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) { - pr_debug(MOD "\tERROR, object data resolution not yet implemented, symbol %s may not function as intended. If it is a variable, declare it static as a workaround\n", symstr); - } + s = find_mod_sec(m, elf_get_shstrtab_str(m->ehdr, elf_get_symbol_shndx(m->ehdr, symstr))); + + switch (elf_get_symbol_shndx(m->ehdr, symstr)) { + case SHN_UNDEF: + pr_debug(MOD "\tundefined section index\n"); + break; + case SHN_ABS: + pr_debug(MOD "\tabsolute value section index\n"); + case SHN_COMMON: + pr_debug(MOD "\t %s common symbol index (must allocate) add: %d\n", symstr, + relatab[i].r_addend); + s = find_mod_sec(m, symstr); + if (!s) { + pr_err("no suitable section found"); + return -1; + } + break; + default: + break; + + } + + + if (!s) { + pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr); + continue; + } + secstr = s->name; + /* target address to insert at location */ + reladdr = (long) s->addr; + pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx, section %s\n", reladdr, s->addr, secstr); + + /* needed ?? */ + //elf_get_symbol_value(m->ehdr, symstr, (unsigned long *) &relatab[i].r_addend); + apply_relocate_add(m, &relatab[i], reladdr, rel_sec); + continue; + + } + +#if 0 if (!(elf_get_symbol_type(m->ehdr, symstr) & (STT_FUNC | STT_OBJECT))) { pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); return -1; } +#endif if (!elf_get_symbol_value(m->ehdr, symstr, &symval)) { pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); return -1; @@ -334,25 +487,26 @@ static int module_relocate(struct elf_module *m) } - pr_debug(MOD "\tSymbol %s at %lx\n", symstr, sym); + pr_debug(MOD "\tSymbol %s at %lx val %lx sec %d\n", symstr, sym, symval, symsec); - apply_relocate_add(m, &relatab[i], sym); + apply_relocate_add(m, &relatab[i], sym, rel_sec); } else { /* no string, symtab entry is probably a section, try to identify it */ char *secstr = elf_get_shstrtab_str(m->ehdr, symsec); - s = find_mod_sec(m, secstr); + s = find_mod_idx(m, symsec-1); if (!s) { pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr); continue; } + secstr = s->name; /* target address to insert at location */ reladdr = (long) s->addr; - pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx\n", reladdr, s->addr); + pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx, section %s\n", reladdr, s->addr, secstr); - apply_relocate_add(m, &relatab[i], reladdr); + apply_relocate_add(m, &relatab[i], reladdr, rel_sec); } pr_debug(MOD "\n"); diff --git a/lib/elf.c b/lib/elf.c index 89553fd1a52939164f1a9ea062d162c48b291eb0..df56bb6859a0b8f10b1b5f58484f1b1c86984e04 100644 --- a/lib/elf.c +++ b/lib/elf.c @@ -510,6 +510,102 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr, } +/** + * @brief get the value of a symbol + * + * @param ehdr an Elf_Ehdr + * + * @param name the name of the symbol + * + * @return the size of the symbol (0 if not found or simply size 0) + * -1 on error + */ + +size_t elf_get_symbol_size(const Elf_Ehdr *ehdr, const char *name) + +{ + unsigned int i; + size_t sym_cnt; + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return -1; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug(MSG "Error %d != %ld\n", + sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if(!strcmp(elf_get_symbol_str(ehdr, i), name)) + return (size_t) symbols[i].st_size; + } + + return 0; +} + + +/** + * @brief get the section index of a symbol + * + * @param ehdr an Elf_Ehdr + * + * @param name the name of the symbol + * + * @return the section index of the symbol or -1 if not found + */ + +unsigned short elf_get_symbol_shndx(const Elf_Ehdr *ehdr, + const char *name) + +{ + unsigned int i; + size_t sym_cnt; + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return -1; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug(MSG "Error %d != %ld\n", + sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if(!strcmp(elf_get_symbol_str(ehdr, i), name)) { + return symbols[i].st_shndx; + } + } + + return -1; +} + + + /** * @brief get the ELF type of a symbol * @@ -607,14 +703,114 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr) for (i = 0; i <ehdr->e_shnum; i++) { shdr = elf_get_sec_by_idx(ehdr, i); if ((shdr->sh_flags & SHF_ALLOC)) - if (shdr->sh_size) - cnt++; + cnt++; } return cnt; } + +/* @brief get the total byte size of unallocated uninitialised common objects + * + * @param ehdr an Elf_Ehdr + * + * @return the number of bytes to be occupied by common (unallocated) objects + */ + +size_t elf_get_common_size(const Elf_Ehdr *ehdr) +{ + unsigned int i; + size_t sym_cnt; + + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + size_t bytes = 0; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return 0; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return 0; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if (symbols[i].st_shndx == SHN_COMMON) + bytes += symbols[i].st_size; + } + + return bytes; +} + + +/* @brief get the total count of unallocated uninitialised common objects + * + * @param ehdr an Elf_Ehdr + * @param[out] an index array + * + * @note set idx to NULL to determine the number of elements needed for the + * array + * + * @return the number of common objects + */ + +size_t elf_get_common_objects(const Elf_Ehdr *ehdr, char **objname) +{ + unsigned int i; + size_t sym_cnt; + + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + size_t common = 0; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return 0; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return 0; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if (symbols[i].st_shndx == SHN_COMMON) { + if (objname) + objname[common] = elf_get_symbol_str(ehdr, i); + common++; + } + } + + return common; +} + + + + + + + /** * @brief get the number of entries in a dynamic section * @@ -727,7 +923,8 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr) printk(MSG "\n" MSG ".symtab contains %d entries\n" MSG "============================\n" - MSG "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\n", sym_cnt); + MSG "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\t\t[SHIDX]\n", + sym_cnt); for (i = 0; i < sym_cnt; i++) { @@ -756,7 +953,9 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr) printk("\tUNKNOWN"); break; } - printk("\t%-10s\n", elf_get_symbol_str(ehdr, i)); + printk("\t%-10s", elf_get_symbol_str(ehdr, i)); + + printk("\t%4ld\n", symbols[i].st_shndx); } } diff --git a/lib/string.c b/lib/string.c index 51a37bf7bd38099eaf22f0258f4a0488f5c4d023..2cf71210ef721e6d7a298b7dd0313c26ed77369d 100644 --- a/lib/string.c +++ b/lib/string.c @@ -173,6 +173,33 @@ char *strdup(const char *s) EXPORT_SYMBOL(strdup); +/** + * @brief locate a character in string + * + * @param s the string to search in + * @param c the character to search for + * + * @returns a pointer to the first matched character or NULL if not found + * + * @note the terminating null byte is considered part of the string, so that if + * c is given as '\0', the function returns a pointer to the terminator + */ + +char *strchr(const char *s, int c) +{ + while ((*s) != (char) c) { + + if ((*s) == '\0') + return NULL; + + s++; + } + + return (char *) s; +} +EXPORT_SYMBOL(strchr); + + /** * @brief calculate the length of a string * @@ -300,6 +327,53 @@ void *memcpy(void *dest, const void *src, size_t n) EXPORT_SYMBOL(memcpy); +/** + * @brief copy a memory area src that may overlap with area dest + * + * @param dest the destination memory area + * @param src the source memory area + * @param n the number of bytes to copy + * + * @returns a pointer to dest + */ + +void *memmove(void *dest, const void *src, size_t n) +{ + char *d; + + const char *s; + + if (dest <= src) { + + d = dest; + s = src; + + while (n--) { + (*d) = (*s); + d++; + s++; + } + + } else { + + d = dest; + d += n; + + s = src; + s += n; + + while (n--) { + d--; + s--; + (*d) = (*s); + } + + } + return dest; +} +EXPORT_SYMBOL(memmove); + + /** * @brief copy a '\0' terminated string * @@ -352,6 +426,58 @@ void bzero(void *s, size_t n) EXPORT_SYMBOL(bzero); +/** + * @brief writes the string s and a trailing newline to stdout + * + * @param str the destination buffer + * @param format the format string buffer + * @param ... arguments to the format string + * + * @return the number of characters written to buf + */ + +int puts(const char *s) +{ + int n; + + n = vsnprintf(NULL, INT_MAX, s, NULL); + n+= vsnprintf(NULL, INT_MAX, "\n", NULL); + + return n; +} +EXPORT_SYMBOL(puts); + + +/** + * @brief writes the character c, cast to an unsigned char, to stdout + * + * @param c the character to write + * + * @return the number of characters written to buf + * + * FIXME: this must be replaced by a different mechanic, e.g. provided + * by the architecture or a driver + */ + +int putchar(int c) +{ +#define TREADY 4 + static volatile int *console = (int *)0x80000100; + + while (!(console[1] & TREADY)); + + console[0] = 0x0ff & c; + + if (c == '\n') { + while (!(console[1] & TREADY)); + console[0] = (int) '\r'; + } + + return c; +} + + + /** * @brief print a string into a buffer diff --git a/scripts/link-leanos.sh b/scripts/link-leanos.sh index db0f57a1cb85898593977e34b47939a1766e1e76..b497a25c30ac9298500cba17018841860eb240b8 100755 --- a/scripts/link-leanos.sh +++ b/scripts/link-leanos.sh @@ -309,7 +309,9 @@ if [ "$1" = "embed" ]; then rm -f modules.image ${AR} rcs ${srctree}/modules.image \ $(tr '\n' ' ' < ${srctree}/modules.order) \ - $(find dsp/xentium -name *.xen) + $(find dsp/xentium -name *.xen) \ + "${CONFIG_EMBED_APPLICATION}" + leanos_link "${kallsymso}" leanos "${embedflags}" exit diff --git a/tools/testing/hwtests/application/Makefile b/tools/testing/hwtests/application/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..96e88ca4e78aaaca8032f33f6616a7165bda9fdd --- /dev/null +++ b/tools/testing/hwtests/application/Makefile @@ -0,0 +1,27 @@ +CC = sparc-elf-gcc +SOURCEDIR = ./ +INCLUDEDIR = ./ +BUILDDIR = ./ +PATH += +CPPFLAGS := +CFLAGS := -r -mv8 -mhard-float -mfix-gr712rc -O2 -std=gnu89 -W -Wall \ + -Wextra -Werror -pedantic -Wshadow -Wuninitialized \ + -fdiagnostics-show-option -Wcast-qual -Wformat=2 \ + -nostartfiles -nostdlib +LDFLAGS := +SOURCES := $(wildcard *.c) +OBJECTS := $(patsubst %.c, $(BUILDDIR)/%.o, $(subst $(SOURCEDIR)/,, $(SOURCES))) +TARGET := executable_demo + +DEBUG?=1 +ifeq "$(shell expr $(DEBUG) \> 1)" "1" + CFLAGS += -DDEBUGLEVEL=$(DEBUG) +else + CFLAGS += -DDEBUGLEVEL=1 +endif + + +all: $(SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) $^ -o $(TARGET) + + diff --git a/tools/testing/hwtests/application/README b/tools/testing/hwtests/application/README new file mode 100644 index 0000000000000000000000000000000000000000..3e3fe3cdac1b43b70b999dcae01828d214d8706a --- /dev/null +++ b/tools/testing/hwtests/application/README @@ -0,0 +1,26 @@ + +Description: +============ + +This test configures and executes an embedded application demonstrator. + +Press Ctrl+C to quit the demonstration. + +Pass/Fail Criterea: +=================== + + None + +Prerequisites: +============== + + * connected GR712 board + * grmon v2.x + + +Notes: +====== + +The current .config of LeanOS will be overwritten and the image will +be rebuilt. + diff --git a/tools/testing/hwtests/application/config b/tools/testing/hwtests/application/config new file mode 100644 index 0000000000000000000000000000000000000000..7dbd6f625f610046fd1b8997b3e50e8bd792da0d --- /dev/null +++ b/tools/testing/hwtests/application/config @@ -0,0 +1,72 @@ +# +# Automatically generated file; DO NOT EDIT. +# LeanOS Configuration +# + +# +# SPARC Configuration +# +# CONFIG_LEON2 is not set +CONFIG_LEON3=y +# CONFIG_MMU is not set +CONFIG_CPU_CLOCK_FREQ=80000000 +CONFIG_EXTRA_SPARC_PHYS_BANKS=0 +CONFIG_SPARC_CPU_REG_WINDOWS=8 +CONFIG_SPARC_TEXT_START=0x40000000 +CONFIG_SPARC_FP_START=0x40100000 + +# +# Memory Management Settings +# +CONFIG_SPARC_MM_BLOCK_ORDER_MAX=26 +CONFIG_SPARC_MM_BLOCK_ORDER_MIN=12 +CONFIG_SPARC_INIT_PAGE_MAP_MAX_ENTRIES=8 +CONFIG_SPARC_BOOTMEM_RESERVE_CHUNK_ORDER=20 +CONFIG_SPARC_BOOTMEM_REQUEST_NEW_ON_DEMAND=y +CONFIG_SPARC_NESTED_IRQ=y + +# +# General Setup +# +CONFIG_KALLSYMS=y +CONFIG_CROSS_PLATFORM_TARGET=y +CONFIG_CROSS_COMPILE="sparc-elf-" +# CONFIG_TARGET_COMPILER_BOOT_CODE is not set +CONFIG_ARCH_CUSTOM_BOOT_CODE=y +CONFIG_MODULES=y +CONFIG_EMBED_MODULES_IMAGE=y +# CONFIG_BUILD_XEN_KERNELS is not set + +# +# Compile-time checks and compiler options +# +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CC_OPTIMIZE_NONE is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_KERNEL_PRINTK=y +CONFIG_KERNEL_LEVEL=7 +# CONFIG_IRQ_STATS_COLLECT is not set +# CONFIG_TASK_PREEMPTION_DISABLE is not set +# CONFIG_SOC is not set + +# +# Core Components +# +CONFIG_SYSCTL=y +CONFIG_MM=y + +# +# Memory Management Debug Options +# +# CONFIG_MM_DEBUG_DUMP is not set +CONFIG_PAGE_MAP=y + +# +# Page Map Options +# +# CONFIG_PAGE_MAP_CHECK_PAGE_ALIGNMENT is not set +CONFIG_PAGE_MAP_MOVE_NODE_AVAIL_THRESH=1 +CONFIG_CHUNK=y +CONFIG_AR=y +# CONFIG_SAMPLES is not set diff --git a/tools/testing/hwtests/application/executable_demo.c b/tools/testing/hwtests/application/executable_demo.c new file mode 100644 index 0000000000000000000000000000000000000000..6ac004039967c5dde46472d2c9d7ae8fc2ec4bab --- /dev/null +++ b/tools/testing/hwtests/application/executable_demo.c @@ -0,0 +1,79 @@ +/* This demonstrates a basic configuration for and "embedded application" + * + * Note that at this point, we do not distinguish between an application + * payload and a module, this will be changed in the future. + */ + + +#include "glue.h" + + + + +/* some random function we use in our executable */ + +static void print0r(int i) +{ + printk("print0r %d\n", i); +} + +/* this is the equivalent of "main()" in our application + * (can actually be main I guess) + */ + +static int iasw(void *data) +{ + int i; + + (void) data; + + /* print a little */ + for (i = 0; i < 10; i++) + print0r(i); + + /* then print a single "z" in a loop and "pause" until the function + * is re-scheduled by issuing sched_yield() + */ + + while (1) { + printk("z"); + sched_yield(); + } + + return 0; +} + + + +/* + * This is our startup call, it will be executed once when the application is + * loaded. Here we create at thread in which our actual application code + * will run in. + */ + +int init_iasw(void) +{ + struct task_struct *t; + + t = kthread_create(iasw, (void *) 0, KTHREAD_CPU_AFFINITY_NONE, "IASW"); + kthread_wake_up(t); + + return 0; +} + + +/** + * this is our optional exit call, it will be called when the module/application + * is removed by the kernel + */ + +int exit_iasw(void) +{ + printk("%s leaving\n", __func__); + /* kthread_destroy() */ + return 0; +} + +/* here we declare our init and exit functions */ +module_init(init_iasw) +module_exit(exit_iasw) diff --git a/tools/testing/hwtests/application/glue.h b/tools/testing/hwtests/application/glue.h new file mode 100644 index 0000000000000000000000000000000000000000..8022d37ebc38cfee17eb5c0f1bc9adde5de9bdb8 --- /dev/null +++ b/tools/testing/hwtests/application/glue.h @@ -0,0 +1,29 @@ +#ifndef GLUE_H +#define GLUE_H + + +/* + * prototypes and declarations needed to build this demo + */ + +#define module_init(initfunc) \ + int _module_init(void) __attribute__((alias(#initfunc))); + +#define module_exit(exitfunc) \ + int _module_exit(void) __attribute__((alias(#exitfunc))); + +#define KTHREAD_CPU_AFFINITY_NONE (-1) + +int printk(const char *format, ...); + +struct task_struct *kthread_create(int (*thread_fn)(void *data), + void *data, int cpu, + const char *namefmt, + ...); +void kthread_wake_up(struct task_struct *task); + +void sched_yield(void); + + + +#endif /* GLUE_H */ diff --git a/tools/testing/hwtests/application/grmon_cmds b/tools/testing/hwtests/application/grmon_cmds new file mode 100644 index 0000000000000000000000000000000000000000..05f292df204472001cf6c0004ecce992d33dede4 --- /dev/null +++ b/tools/testing/hwtests/application/grmon_cmds @@ -0,0 +1,3 @@ +load leanos +run +quit diff --git a/tools/testing/hwtests/application/run_test.sh b/tools/testing/hwtests/application/run_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..9f4f0f44e5aba9b882ce61d27f94fbdc99dd6c32 --- /dev/null +++ b/tools/testing/hwtests/application/run_test.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# grmon must be in path! + + +#build application +make || exit 1 + + +mydir=$PWD +srcdir=../../../../ + +cp config ${srcdir}/.config || exit 1 + +echo -e "CONFIG_EMBED_APPLICATION=\"$PWD/executable_demo\"" >> ${srcdir}/.config + +cd ${srcdir} || exit 1 + +make clean || exit 1 + +make || exit 1 + +grmon -ftdi -u -ftdifreq 0 -jtagcable 3 -nb -c $mydir/grmon_cmds