Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / x86 / core / x86_string.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 /** @file
21  *
22  * Optimised string operations
23  *
24  */
25
26 FILE_LICENCE ( GPL2_OR_LATER );
27
28 #include <string.h>
29
30 /**
31  * Copy memory area
32  *
33  * @v dest              Destination address
34  * @v src               Source address
35  * @v len               Length
36  * @ret dest            Destination address
37  */
38 void * __attribute__ (( noinline )) __memcpy ( void *dest, const void *src,
39                                                size_t len ) {
40         void *edi = dest;
41         const void *esi = src;
42         int discard_ecx;
43
44         /* We often do large dword-aligned and dword-length block
45          * moves.  Using movsl rather than movsb speeds these up by
46          * around 32%.
47          */
48         __asm__ __volatile__ ( "rep movsl"
49                                : "=&D" ( edi ), "=&S" ( esi ),
50                                  "=&c" ( discard_ecx )
51                                : "0" ( edi ), "1" ( esi ), "2" ( len >> 2 )
52                                : "memory" );
53         __asm__ __volatile__ ( "rep movsb"
54                                : "=&D" ( edi ), "=&S" ( esi ),
55                                  "=&c" ( discard_ecx )
56                                : "0" ( edi ), "1" ( esi ), "2" ( len & 3 )
57                                : "memory" );
58         return dest;
59 }
60
61 /**
62  * Copy memory area backwards
63  *
64  * @v dest              Destination address
65  * @v src               Source address
66  * @v len               Length
67  * @ret dest            Destination address
68  */
69 void * __attribute__ (( noinline )) __memcpy_reverse ( void *dest,
70                                                        const void *src,
71                                                        size_t len ) {
72         void *edi = ( dest + len - 1 );
73         const void *esi = ( src + len - 1 );
74         int discard_ecx;
75
76         /* Assume memmove() is not performance-critical, and perform a
77          * bytewise copy for simplicity.
78          */
79         __asm__ __volatile__ ( "std\n\t"
80                                "rep movsb\n\t"
81                                "cld\n\t"
82                                : "=&D" ( edi ), "=&S" ( esi ),
83                                  "=&c" ( discard_ecx )
84                                : "0" ( edi ), "1" ( esi ),
85                                  "2" ( len )
86                                : "memory" );
87         return dest;
88 }
89
90
91 /**
92  * Copy (possibly overlapping) memory area
93  *
94  * @v dest              Destination address
95  * @v src               Source address
96  * @v len               Length
97  * @ret dest            Destination address
98  */
99 void * __memmove ( void *dest, const void *src, size_t len ) {
100
101         if ( dest <= src ) {
102                 return __memcpy ( dest, src, len );
103         } else {
104                 return __memcpy_reverse ( dest, src, len );
105         }
106 }
107
108 /**
109  * Swap memory areas
110  *
111  * @v dest              Destination address
112  * @v src               Source address
113  * @v len               Length
114  * @ret dest            Destination address
115  */
116 void * memswap ( void *dest, void *src, size_t len ) {
117         size_t discard_c;
118         int discard;
119
120         __asm__ __volatile__ ( "\n1:\n\t"
121                                "dec %2\n\t"
122                                "js 2f\n\t"
123                                "movb (%0,%2), %b3\n\t"
124                                "xchgb (%1,%2), %b3\n\t"
125                                "movb %b3, (%0,%2)\n\t"
126                                "jmp 1b\n\t"
127                                "2:\n\t"
128                                : "=r" ( src ), "=r" ( dest ),
129                                  "=&c" ( discard_c ), "=&q" ( discard )
130                                : "0" ( src ), "1" ( dest ), "2" ( len )
131                                : "memory" );
132
133         return dest;
134 }
135
136 /**
137  * Calculate length of string
138  *
139  * @v string            String
140  * @ret len             Length (excluding NUL)
141  */
142 size_t strlen ( const char *string ) {
143         const char *discard_D;
144         size_t len_plus_one;
145
146         __asm__ __volatile__ ( "repne scasb\n\t"
147                                "not %1\n\t"
148                                : "=&D" ( discard_D ), "=&c" ( len_plus_one )
149                                : "0" ( string ), "1" ( -1UL ), "a" ( 0 ) );
150
151         return ( len_plus_one - 1 );
152 }
153
154 /**
155  * Compare strings (up to a specified length)
156  *
157  * @v str1              First string
158  * @v str2              Second string
159  * @v len               Maximum length
160  * @ret diff            Difference
161  */
162 int strncmp ( const char *str1, const char *str2, size_t len ) {
163         const void *discard_S;
164         const void *discard_D;
165         size_t discard_c;
166         int diff;
167
168         __asm__ __volatile__ ( "\n1:\n\t"
169                                "dec %2\n\t"
170                                "js 2f\n\t"
171                                "lodsb\n\t"
172                                "scasb\n\t"
173                                "jne 3f\n\t"
174                                "testb %b3, %b3\n\t"
175                                "jnz 1b\n\t"
176                                /* Equal */
177                                "\n2:\n\t"
178                                "xor %3, %3\n\t"
179                                "jmp 4f\n\t"
180                                /* Not equal; CF indicates difference */
181                                "\n3:\n\t"
182                                "sbb %3, %3\n\t"
183                                "orb $1, %b3\n\t"
184                                "\n4:\n\t"
185                                : "=&S" ( discard_S ), "=&D" ( discard_D ),
186                                  "=&c" ( discard_c ), "=&a" ( diff )
187                                : "0" ( str1 ), "1" ( str2 ), "2" ( len ) );
188
189         return diff;
190 }