From 4fd2b7f90cb6d3d9340624155aefb0c108360457 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Fri, 8 Nov 2013 22:06:07 +0100 Subject: [PATCH] add highly tuned assmbler functions for basic string operations --- arch/x86/include/asm/stddef.h | 125 ++++++++++++++++++++++++-- arch/x86/include/asm/string.h | 154 +++++++++++++++++++++++++++------ arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/string32.asm | 63 ++++++++++++++ include/eduos/config.h.example | 6 ++ libkern/string.c | 27 ++---- 6 files changed, 318 insertions(+), 59 deletions(-) create mode 100644 arch/x86/kernel/string32.asm diff --git a/arch/x86/include/asm/stddef.h b/arch/x86/include/asm/stddef.h index 1a78d7d..441f89a 100644 --- a/arch/x86/include/asm/stddef.h +++ b/arch/x86/include/asm/stddef.h @@ -25,6 +25,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * @author Stefan Lankes + * @file arch/x86/include/asm/stddef.h + * @brief Standard datatypes + * + * This file contains typedefs for standard datatypes for numerical and character values. + */ + #ifndef __ARCH_STDDEF_H__ #define __ARCH_STDDEF_H__ @@ -32,21 +40,47 @@ extern "C" { #endif +#if __SIZEOF_POINTER__ == 4 +#define CONFIG_X86_32 +/// A popular type for addresses typedef unsigned long size_t; +/// Pointer differences typedef long ptrdiff_t; #ifdef __KERNEL__ typedef long ssize_t; typedef long off_t; #endif +#elif __SIZEOF_POINTER__ == 8 +#define CONFIG_X86_64 +// A popular type for addresses +typedef unsigned long long size_t; +/// Pointer differences +typedef long long ptrdiff_t; +#ifdef __KERNEL__ +typedef long long ssize_t; +typedef long long off_t; +#endif +#else +#error unsupported architecture +#endif +/// Unsigned 64 bit integer typedef unsigned long long uint64_t; +/// Signed 64 bit integer typedef long long int64_t; +/// Unsigned 32 bit integer typedef unsigned int uint32_t; +/// Signed 32 bit integer typedef int int32_t; +/// Unsigned 16 bit integer typedef unsigned short uint16_t; +/// Signed 16 bit integer typedef short int16_t; +/// Unsigned 8 bit integer (/char) typedef unsigned char uint8_t; +/// Signed 8 bit integer (/char) typedef char int8_t; +/// 16 bit wide char type typedef unsigned short wchar_t; #ifndef _WINT_T @@ -54,16 +88,89 @@ typedef unsigned short wchar_t; typedef unsigned int wint_t; #endif -/* This defines what the stack looks like after an ISR was running */ +/** @brief This defines what the stack looks like after an ISR was called. + * + * All the interrupt handler routines use this type for their only parameter. + * Note: Our kernel doesn't use the GS and FS registers. + */ struct state { - /* - * We switched from software- to hardwaree-based multitasking - * Therefore, we do not longer save the registers by hand. - */ - /*unsigned int gs, fs, es, ds; */ /* pushed the segs last */ - unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */ - unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */ - /*unsigned int eip, cs, eflags, useresp, ss;*/ /* pushed by the processor automatically */ +#ifdef CONFIG_X86_32 + // ds register + uint32_t ds; + // es register + uint32_t es; + /// EDI register + uint32_t edi; + /// ESI register + uint32_t esi; + /// EBP register + uint32_t ebp; + /// ESP register + uint32_t esp; + /// EBX register + uint32_t ebx; + /// EDX register + uint32_t edx; + /// ECX register + uint32_t ecx; + /// EAX register + uint32_t eax; /* pushed by 'pusha' */ + + /// Interrupt number + uint32_t int_no; + + // pushed by the processor automatically + uint32_t error; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t useresp; + uint32_t ss; +#elif defined(CONFIG_X86_64) + /// R15 register + uint64_t r15; + /// R14 register + uint64_t r14; + /// R13 register + uint64_t r13; + /// R12 register + uint64_t r12; + /// R11 register + uint64_t r11; + /// R10 register + uint64_t r10; + /// R9 register + uint64_t r9; + /// R8 register + uint64_t r8; + /// RDI register + uint64_t rdi; + /// RSI register + uint64_t rsi; + /// RBP register + uint64_t rbp; + /// (pseudo) RSP register + uint64_t rsp; + /// RBX register + uint64_t rbx; + /// RDX register + uint64_t rdx; + /// RCX register + uint64_t rcx; + /// RAX register + uint64_t rax; + + /// Interrupt number + uint64_t int_no; + + // pushed by the processor automatically + uint64_t error; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t userrsp; + uint64_t ss; +#endif }; #ifdef __cplusplus diff --git a/arch/x86/include/asm/string.h b/arch/x86/include/asm/string.h index d5c2e4e..571a7b0 100644 --- a/arch/x86/include/asm/string.h +++ b/arch/x86/include/asm/string.h @@ -1,28 +1,20 @@ -/* - * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University - * All rights reserved. +/* + * Written by the Chair for Operating Systems, RWTH Aachen University + * + * NO Copyright (C) 2010-2011, Stefan Lankes + * consider these trivial functions to be public domain. + * + * These functions are distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +/** + * @author Stefan Lankes + * @file arch/x86/include/asm/string.h + * @brief Functions related to memcpy and strings. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This file deals with memcpy, memset, string functions and everything related to + * continuous byte fields. */ #ifndef __ARCH_STRING_H__ @@ -34,11 +26,119 @@ extern "C" { #endif -/* - * TODO: add architecture optimized versions of standard functions like memcpy +#ifdef HAVE_ARCH_MEMCPY +/** @brief Copy a byte range from source to dest * - * Perhapy you could use your experiences from GI4! + * @param dest Destination address + * @param src Source address + * @param count Range of the byte field in bytes */ +inline static void *memcpy(void* dest, const void *src, size_t count) +{ + size_t i, j, k; + + if (BUILTIN_EXPECT(!dest || !src, 0)) + return dest; + +#ifdef CONFIG_X86_32 + asm volatile ( + "cld; rep movsl\n\t" + "movl %4, %%ecx\n\t" + "andl $3, %%ecx\n\t" + "rep movsb\n\t" + : "=&c"(i), "=&D"(j), "=&S"(k) + : "0"(count/4), "g"(count), "1"(dest), "2"(src) : "memory","cc"); +#elif defined(CONFIG_X86_64) + asm volatile ( + "cld; rep movsq\n\t" + "movq %4, %%rcx\n\t" + "andq $7, %%rcx\n\t" + "rep movsb\n\t" + : "=&c"(i), "=&D"(j), "=&S"(k) + : "0"(count/8), "g"(count), "1"(dest), "2"(src) : "memory","cc"); +#endif + + return dest; +} +#endif + +#ifdef HAVE_ARCH_MEMSET +/** @brief Repeated write of a value to a whole range of bytes + * + * @param dest Destination address + * @param val Value to flood the range with + * @param count Size of target range in bytes + */ +inline static void *memset(void* dest, int val, size_t count) +{ + size_t i, j; + + if (BUILTIN_EXPECT(!dest, 0)) + return dest; + + asm volatile ("cld; rep stosb" + : "=&c"(i), "=&D"(j) + : "a"(val), "1"(dest), "0"(count) : "memory","cc"); + + return dest; +} +#endif + +#ifdef HAVE_ARCH_STRLEN +/** @brief Standard string length + * + * This function computed the length of the given null terminated string + * just like the strlen functions you are used to. + * + * @return + * - The length of the string + * - 0 if str is a NULL pointer + */ +inline static size_t strlen(const char* str) +{ + size_t len = 0; + size_t i, j; + + if (BUILTIN_EXPECT(!str, 0)) + return len; + +#ifdef CONFIG_X86_32 + asm volatile("not %%ecx; cld; repne scasb; not %%ecx; dec %%ecx" + : "=&c"(len), "=&D"(i), "=&a"(j) + : "2"(0), "1"(str), "0"(len) + : "memory","cc"); +#elif defined(CONFIG_X86_64) + asm volatile("not %%rcx; cld; repne scasb; not %%rcx; dec %%rcx" + : "=&c"(len), "=&D"(i), "=&a"(j) + : "2"(0), "1"(str), "0"(len) + : "memory","cc"); +#endif + + return len; +} +#endif + +#ifdef HAVE_ARCH_STRNCPY +/** @brief Copy string with maximum of n byte length + * + * @param dest Destination string pointer + * @param src Source string pointer + * @param n maximum number of bytes to copy + */ +char* strncpy(char* dest, const char* src, size_t n); +#endif + +#ifdef HAVE_ARCH_STRCPY +/** @brief Copy string + * + * Note that there is another safer variant of this function: strncpy.\n + * That one could save you from accidents with buffer overruns. + * + * @param dest Destination string pointer + * @param src Source string pointer + */ +char* strcpy(char* dest, const char* src); +#endif #ifdef __cplusplus } diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 57d96ec..3a59e1d 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -1,5 +1,5 @@ C_source := multiboot.c vga.c -ASM_source := entry.asm +ASM_source := entry.asm string32.asm MODULE := arch_x86_kernel include $(TOPDIR)/Makefile.inc diff --git a/arch/x86/kernel/string32.asm b/arch/x86/kernel/string32.asm new file mode 100644 index 0000000..7ccded6 --- /dev/null +++ b/arch/x86/kernel/string32.asm @@ -0,0 +1,63 @@ +; +; Written by the Chair for Operating Systems, RWTH Aachen University +; +; NO Copyright (C) 2010-2011, Stefan Lankes +; consider these trivial functions to be public domain. +; +; These functions are distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; + +[BITS 32] +SECTION .text +global strcpy +strcpy: + push ebp + mov ebp, esp + push edi + push esi + + mov esi, [ebp+12] + mov edi, [ebp+8] + +L1: + lodsb + stosb + test al, al + jne L1 + + mov eax, [ebp+8] + pop esi + pop edi + pop ebp + ret + +global strncpy +strncpy: + push ebp + mov ebp, esp + push edi + push esi + + mov ecx, [ebp+16] + mov esi, [ebp+12] + mov edi, [ebp+8] + +L2: + dec ecx + js L3 + lodsb + stosb + test al, al + jne L1 + rep + stosb + +L3: + mov eax, [ebp+8] + pop esi + pop edi + pop ebp + ret + +SECTION .note.GNU-stack noalloc noexec nowrite progbits diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index ad796f3..5db58b3 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -42,6 +42,12 @@ extern "C" { #define NORETURN __attribute__((noreturn)) #define STDCALL __attribute__((stdcall)) +#define HAVE_ARCH_MEMSET +#define HAVE_ARCH_MEMCPY +#define HAVE_ARCH_STRLEN +#define HAVE_ARCH_STRCPY +#define HAVE_ARCH_STRNCPY + #ifdef __cplusplus } #endif diff --git a/libkern/string.c b/libkern/string.c index 972afc2..7b5d633 100644 --- a/libkern/string.c +++ b/libkern/string.c @@ -1,28 +1,11 @@ /* - * Copyright (c) 2010, Stefan Lankes - * All rights reserved. + * Written by the Chair for Operating Systems, RWTH Aachen University * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. + * NO Copyright (C) 2010-2011, Stefan Lankes + * consider these trivial functions to be public domain. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * These functions are distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include