1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/klib/x86/cumem.cia Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,532 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\klib\x86\cumem.cia
1.18 +//
1.19 +//
1.20 +
1.21 +#include <x86.h>
1.22 +
1.23 +extern "C" {
1.24 +
1.25 +__NAKED__ void CopyInterSeg()
1.26 +//
1.27 +// Copy ECX bytes from DS:ESI to ES:EDI
1.28 +// Modifies EAX, EBX, ECX, EDX, ESI, EDI
1.29 +//
1.30 + {
1.31 + asm("pushfd");
1.32 + asm("cld"); // assume forward copy initially
1.33 + asm("test ecx,ecx"); //
1.34 + asm("jz short memcopy0");// if length=0, nothing to do
1.35 + asm("xor edx,edx"); //
1.36 + asm("cmp edi,esi"); // compare source and dest addresses
1.37 + asm("jc short memcopy1");// if dest<source, must go forwards
1.38 + asm("std"); // else go backwards
1.39 + asm("add esi,ecx"); // and start at end of block
1.40 + asm("add edi,ecx"); //
1.41 + asm("inc edx"); // edx=1 if backwards, 0 if forwards
1.42 + asm("memcopy1:");
1.43 + asm("cmp ecx,16"); // if length<16 don't bother with alignment check
1.44 + asm("jc short memcopy2");//
1.45 + asm("mov ebx,edi"); // ebx = destination address
1.46 + asm("and ebx,3"); // ebx bottom 2 bits = alignment of destination wrt hardware bus
1.47 + asm("jz short memcopy3");// if aligned, proceed with block move
1.48 + asm("or edx,edx"); // check direction of move
1.49 + asm("jnz short memcopy4");// if backwards, ebx = number of byte moves to align destination
1.50 + asm("neg ebx"); // else number of byte moves = 4-ebx
1.51 + asm("add ebx,4"); //
1.52 + asm("memcopy4:");
1.53 + asm("sub ecx,ebx"); // subtract number of bytes from length
1.54 + asm("xchg ecx,ebx"); // temporarily put length in ebx
1.55 + asm("sub edi,edx"); // adjust if backwards move
1.56 + asm("sub esi,edx"); //
1.57 + asm("rep movsb"); // move bytes to align destination
1.58 + asm("add edi,edx"); // adjust if backwards move
1.59 + asm("add esi,edx"); //
1.60 + asm("mov ecx,ebx"); // length back into ecx
1.61 + asm("memcopy3:");
1.62 + asm("mov ebx,ecx"); // save length in ebx
1.63 + asm("shl edx,2"); // adjustment 4 for backwards move
1.64 + asm("shr ecx,2"); // number of dwords to move into ecx
1.65 + asm("sub edi,edx"); // adjust if backwards move
1.66 + asm("sub esi,edx"); //
1.67 + asm("rep movsd"); // perform DWORD block move
1.68 + asm("add edi,edx"); // adjust if backwards move
1.69 + asm("add esi,edx"); //
1.70 + asm("mov ecx,ebx"); // length back into ecx
1.71 + asm("and ecx,3"); // number of remaining bytes to move
1.72 + asm("jz short memcopy0");// if zero, we are finished
1.73 + asm("shr edx,2"); // adjustment 1 for backwards move
1.74 + asm("memcopy2:"); // *** come here for small move
1.75 + asm("sub edi,edx"); // adjust if backwards move
1.76 + asm("sub esi,edx"); //
1.77 + asm("rep movsb"); // move remaining bytes
1.78 + asm("memcopy0:");
1.79 + asm("popfd");
1.80 + asm("ret"); // finished - return value in EAX
1.81 + }
1.82 +
1.83 +__NAKED__ void CopyInterSeg32()
1.84 +//
1.85 +// Copy ECX bytes from DS:ESI to ES:EDI
1.86 +// ECX, ESI and EDI are all multiples of 4
1.87 +// Modifies EAX, EBX, ECX, EDX, ESI, EDI
1.88 +//
1.89 + {
1.90 + asm("pushfd");
1.91 + asm("cld"); //
1.92 + asm("test ecx,ecx"); //
1.93 + asm("jz short memmove0");// if length=0, nothing to do
1.94 + asm("cmp edi,esi"); // compare source and dest addresses
1.95 + asm("jc short memmove1");// if dest<source, must go forwards
1.96 + asm("std"); // else go backwards
1.97 + asm("lea esi,[esi+ecx-4]"); // and start at end of block - 4
1.98 + asm("lea edi,[edi+ecx-4]"); //
1.99 + asm("memmove1:");
1.100 + asm("shr ecx,2"); // ecx now contains number of dwords to move
1.101 + asm("rep movsd"); // do dword block move
1.102 + asm("memmove0:");
1.103 + asm("popfd");
1.104 + asm("ret"); // finished - return value in EAX
1.105 + }
1.106 +
1.107 +__NAKED__ void FillInterSeg()
1.108 +//
1.109 +// Fill ECX bytes at ES:EDI with AL
1.110 +// Modifies EAX, ECX, EDX, EDI
1.111 +//
1.112 + {
1.113 + asm("pushfd");
1.114 + asm("cld"); // go forwards through array
1.115 + asm("test ecx,ecx"); //
1.116 + asm("jz short memfill0");// if length zero, nothing to do
1.117 + asm("cmp ecx,8"); // if array very small, just do byte fills
1.118 + asm("jb short memfill1");
1.119 +
1.120 + asm("mov ah,al"); // repeat al in all bytes of eax
1.121 + asm("movzx edx,ax"); //
1.122 + asm("shl eax,16"); //
1.123 + asm("or eax,edx"); //
1.124 + asm("mov edx,ecx"); // length into edx
1.125 + // ecx = number of byte fills to align = 4-(edi mod 4)
1.126 + asm("mov ecx,4");
1.127 + asm("sub ecx,edi"); //
1.128 + asm("and ecx,3"); //
1.129 + asm("jz short memfill2");// if already aligned, proceed to dword fill
1.130 + asm("sub edx,ecx"); // subtract alignment bytes from length
1.131 + asm("rep stosb"); // do byte fills to align
1.132 + asm("memfill2:");
1.133 + asm("mov ecx,edx"); // length remaining into ecx
1.134 + asm("shr ecx,2"); // number of dwords to fill into ecx
1.135 + asm("rep stosd"); // perform dword fill
1.136 + asm("mov ecx,edx"); // calculate number of leftover bytes
1.137 + asm("and ecx,3"); // in ecx
1.138 + asm("jz short memfill0");// if none left, exit
1.139 + asm("memfill1:");
1.140 + asm("rep stosb"); // do byte fills to make up correct length
1.141 + asm("memfill0:");
1.142 + asm("popfd");
1.143 + asm("ret");
1.144 + }
1.145 +
1.146 +
1.147 +/** Reads the current thread's memory space with appropriate permissions.
1.148 +
1.149 +Performs a memcpy(aKernAddr, aAddr, aLength).
1.150 +The reads are performed using requestor privilege level from GS, ie equal
1.151 +to the privilege level of the caller of the Exec:: function.
1.152 +Note that source and destination areas may not overlap.
1.153 +
1.154 +@param aKernAddr Destination address in kernel memory.
1.155 +@param aAddr Source address in kernel or user memory.
1.156 +@param aLength Number of bytes to copy.
1.157 +
1.158 +@pre Call in a thread context.
1.159 +@pre Kernel must be unlocked.
1.160 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.161 +in a critical section.
1.162 +*/
1.163 +EXPORT_C __NAKED__ void kumemget(TAny* /*aKernAddr*/, const TAny* /*aAddr*/, TInt /*aLength*/)
1.164 + {
1.165 + asm("push edi");
1.166 + asm("push esi");
1.167 + asm("push ebx");
1.168 + asm("push ds");
1.169 + asm("mov edi, [esp+20]");
1.170 + asm("mov esi, [esp+24]");
1.171 + asm("mov ecx, [esp+28]");
1.172 + asm("mov ax, gs");
1.173 + asm("mov ds, ax");
1.174 + asm("call %a0": : "i"(&CopyInterSeg));
1.175 + asm("pop ds");
1.176 + asm("pop ebx");
1.177 + asm("pop esi");
1.178 + asm("pop edi");
1.179 + asm("ret");
1.180 + }
1.181 +
1.182 +
1.183 +/** Reads the current thread's memory space with user permissions.
1.184 +
1.185 +Performs a memcpy(aKernAddr, aUserAddr, aLength).
1.186 +The reads are performed with ring 3 RPL.
1.187 +Note that source and destination areas may not overlap.
1.188 +
1.189 +@param aKernAddr Destination address in kernel memory.
1.190 +@param aUserAddr Source address in user memory.
1.191 +@param aLength Number of bytes to copy.
1.192 +
1.193 +@pre Call in a thread context.
1.194 +@pre Kernel must be unlocked.
1.195 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.196 +in a critical section.
1.197 +*/
1.198 +EXPORT_C __NAKED__ void umemget(TAny* /*aKernAddr*/, const TAny* /*aUserAddr*/, TInt /*aLength*/)
1.199 + {
1.200 + asm("push edi");
1.201 + asm("push esi");
1.202 + asm("push ebx");
1.203 + asm("push ds");
1.204 + asm("mov edi, [esp+20]");
1.205 + asm("mov esi, [esp+24]");
1.206 + asm("mov ecx, [esp+28]");
1.207 + asm("mov eax, %0": : "i"(RING3_DS));
1.208 + asm("mov ds, ax");
1.209 + asm("call %a0": : "i"(&CopyInterSeg));
1.210 + asm("pop ds");
1.211 + asm("pop ebx");
1.212 + asm("pop esi");
1.213 + asm("pop edi");
1.214 + asm("ret");
1.215 + }
1.216 +
1.217 +
1.218 +/** Does a word-aligned read of the current thread's memory space with appropriate permissions.
1.219 +
1.220 +Performs a memcpy(aKernAddr, aAddr, aLength).
1.221 +The reads are performed using requestor privilege level from GS, ie equal
1.222 +to the privilege level of the caller of the Exec:: function.
1.223 +Note that source and destination areas may not overlap.
1.224 +
1.225 +@param aKernAddr Destination address in kernel memory, must be 4-byte aligned.
1.226 +@param aAddr Source address in kernel or user memory, must be 4-byte aligned.
1.227 +@param aLength Number of bytes to copy, must be a multiple of 4.
1.228 +
1.229 +@pre Call in a thread context.
1.230 +@pre Kernel must be unlocked.
1.231 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.232 +in a critical section.
1.233 +*/
1.234 +EXPORT_C __NAKED__ void kumemget32(TAny* /*aKernAddr*/, const TAny* /*aAddr*/, TInt /*aLength*/)
1.235 + {
1.236 + asm("push edi");
1.237 + asm("push esi");
1.238 + asm("push ebx");
1.239 + asm("push ds");
1.240 + asm("mov edi, [esp+20]");
1.241 + asm("mov esi, [esp+24]");
1.242 + asm("mov ecx, [esp+28]");
1.243 + asm("mov ax, gs");
1.244 + asm("mov ds, ax");
1.245 + asm("call %a0": : "i"(&CopyInterSeg32));
1.246 + asm("pop ds");
1.247 + asm("pop ebx");
1.248 + asm("pop esi");
1.249 + asm("pop edi");
1.250 + asm("ret");
1.251 + }
1.252 +
1.253 +
1.254 +/** Does a word-aligned read of the current thread's memory space with user permissions.
1.255 +
1.256 +Performs a memcpy(aKernAddr, aUserAddr, aLength).
1.257 +The reads are performed with ring 3 RPL.
1.258 +Note that source and destination areas may not overlap.
1.259 +
1.260 +@param aKernAddr Destination address in kernel memory, must be 4-byte aligned.
1.261 +@param aUserAddr Source address in user memory, must be 4-byte aligned.
1.262 +@param aLength Number of bytes to copy, must be a multiple of 4.
1.263 +
1.264 +@pre Call in a thread context.
1.265 +@pre Kernel must be unlocked.
1.266 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.267 +in a critical section.
1.268 +*/
1.269 +EXPORT_C __NAKED__ void umemget32(TAny* /*aKernAddr*/, const TAny* /*aUserAddr*/, TInt /*aLength*/)
1.270 + {
1.271 + asm("push edi");
1.272 + asm("push esi");
1.273 + asm("push ebx");
1.274 + asm("push ds");
1.275 + asm("mov edi, [esp+20]");
1.276 + asm("mov esi, [esp+24]");
1.277 + asm("mov ecx, [esp+28]");
1.278 + asm("mov eax, %0": : "i"(RING3_DS));
1.279 + asm("mov ds, ax");
1.280 + asm("call %a0": : "i"(&CopyInterSeg32));
1.281 + asm("pop ds");
1.282 + asm("pop ebx");
1.283 + asm("pop esi");
1.284 + asm("pop edi");
1.285 + asm("ret");
1.286 + }
1.287 +
1.288 +
1.289 +/** Writes to the current thread's memory space with appropriate permissions.
1.290 +
1.291 +Performs a memcpy(aAddr, aKernAddr, aLength).
1.292 +The writes are performed using requestor privilege level from GS, ie equal
1.293 +to the privilege level of the caller of the Exec:: function.
1.294 +Note that source and destination areas may not overlap.
1.295 +
1.296 +@param aAddr Destination address in kernel or user memory.
1.297 +@param aKernAddr Source address in kernel memory.
1.298 +@param aLength Number of bytes to copy.
1.299 +
1.300 +@pre Call in a thread context.
1.301 +@pre Kernel must be unlocked.
1.302 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.303 +in a critical section.
1.304 +*/
1.305 +EXPORT_C __NAKED__ void kumemput(TAny* /*aAddr*/, const TAny* /*aKernAddr*/, TInt /*aLength*/)
1.306 + {
1.307 + asm("push edi");
1.308 + asm("push esi");
1.309 + asm("push ebx");
1.310 + asm("push es");
1.311 + asm("mov edi, [esp+20]");
1.312 + asm("mov esi, [esp+24]");
1.313 + asm("mov ecx, [esp+28]");
1.314 + asm("mov ax, gs");
1.315 + asm("mov es, ax");
1.316 + asm("call %a0": : "i"(&CopyInterSeg));
1.317 + asm("pop es");
1.318 + asm("pop ebx");
1.319 + asm("pop esi");
1.320 + asm("pop edi");
1.321 + asm("ret");
1.322 + }
1.323 +
1.324 +
1.325 +/** Writes to the current thread's memory space with user permissions.
1.326 +
1.327 +Performs a memcpy(aAddr, aKernAddr, aLength).
1.328 +The writes are performed with ring 3 RPL.
1.329 +Note that source and destination areas may not overlap.
1.330 +
1.331 +@param aUserAddr Destination address in user memory.
1.332 +@param aKernAddr Source address in kernel memory.
1.333 +@param aLength Number of bytes to copy.
1.334 +
1.335 +@pre Call in a thread context.
1.336 +@pre Kernel must be unlocked.
1.337 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.338 +in a critical section.
1.339 +*/
1.340 +EXPORT_C __NAKED__ void umemput(TAny* /*aUserAddr*/, const TAny* /*aKernAddr*/, TInt /*aLength*/)
1.341 + {
1.342 + asm("push edi");
1.343 + asm("push esi");
1.344 + asm("push ebx");
1.345 + asm("push es");
1.346 + asm("mov edi, [esp+20]");
1.347 + asm("mov esi, [esp+24]");
1.348 + asm("mov ecx, [esp+28]");
1.349 + asm("mov eax, %0": : "i"(RING3_DS));
1.350 + asm("mov es, ax");
1.351 + asm("call %a0": : "i"(&CopyInterSeg));
1.352 + asm("pop es");
1.353 + asm("pop ebx");
1.354 + asm("pop esi");
1.355 + asm("pop edi");
1.356 + asm("ret");
1.357 + }
1.358 +
1.359 +
1.360 +/** Does a word-aligned write to the current thread's memory space with appropriate permissions.
1.361 +
1.362 +Performs a memcpy(aAddr, aKernAddr, aLength).
1.363 +The writes are performed using requestor privilege level from GS, ie equal
1.364 +to the privilege level of the caller of the Exec:: function.
1.365 +Note that source and destination areas may not overlap.
1.366 +
1.367 +@param aAddr Destination address in kernel or user memory, must be 4-byte aligned.
1.368 +@param aKernAddr Source address in kernel memory, must be 4-byte aligned.
1.369 +@param aLength Number of bytes to copy, must be a multiple of 4.
1.370 +
1.371 +@pre Call in a thread context.
1.372 +@pre Kernel must be unlocked.
1.373 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.374 +in a critical section.
1.375 +*/
1.376 +EXPORT_C __NAKED__ void kumemput32(TAny* /*aAddr*/, const TAny* /*aKernAddr*/, TInt /*aLength*/)
1.377 + {
1.378 + asm("push edi");
1.379 + asm("push esi");
1.380 + asm("push ebx");
1.381 + asm("push es");
1.382 + asm("mov edi, [esp+20]");
1.383 + asm("mov esi, [esp+24]");
1.384 + asm("mov ecx, [esp+28]");
1.385 + asm("mov ax, gs");
1.386 + asm("mov es, ax");
1.387 + asm("call %a0": : "i"(&CopyInterSeg32));
1.388 + asm("pop es");
1.389 + asm("pop ebx");
1.390 + asm("pop esi");
1.391 + asm("pop edi");
1.392 + asm("ret");
1.393 + }
1.394 +
1.395 +
1.396 +/** Does a word-aligned write to the current thread's memory space with user permissions.
1.397 +
1.398 +Performs a memcpy(aAddr, aKernAddr, aLength).
1.399 +The writes are performed with ring 3 RPL.
1.400 +Note that source and destination areas may not overlap.
1.401 +
1.402 +@param aUserAddr Destination address in user memory, must be 4-byte aligned.
1.403 +@param aKernAddr Source address in kernel memory, must be 4-byte aligned.
1.404 +@param aLength Number of bytes to copy, must be a multiple of 4.
1.405 +
1.406 +@pre Call in a thread context.
1.407 +@pre Kernel must be unlocked.
1.408 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.409 +in a critical section.
1.410 +*/
1.411 +EXPORT_C __NAKED__ void umemput32(TAny* /*aUserAddr*/, const TAny* /*aKernAddr*/, TInt /*aLength*/)
1.412 + {
1.413 + asm("push edi");
1.414 + asm("push esi");
1.415 + asm("push ebx");
1.416 + asm("push es");
1.417 + asm("mov edi, [esp+20]");
1.418 + asm("mov esi, [esp+24]");
1.419 + asm("mov ecx, [esp+28]");
1.420 + asm("mov eax, %0": : "i"(RING3_DS));
1.421 + asm("mov es, ax");
1.422 + asm("call %a0": : "i"(&CopyInterSeg32));
1.423 + asm("pop es");
1.424 + asm("pop ebx");
1.425 + asm("pop esi");
1.426 + asm("pop edi");
1.427 + asm("ret");
1.428 + }
1.429 +
1.430 +
1.431 +/** Fills the current thread's memory space with appropriate permissions.
1.432 +
1.433 +Performs a memset(aAddr, aValue, aLength).
1.434 +The writes are performed using requestor privilege level from GS, ie equal
1.435 +to the privilege level of the caller of the Exec:: function.
1.436 +
1.437 +@param aAddr Destination address in kernel or user memory.
1.438 +@param aValue Value to write to each byte.
1.439 +@param aLength Number of bytes to fill.
1.440 +
1.441 +@pre Call in a thread context.
1.442 +@pre Kernel must be unlocked.
1.443 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.444 +in a critical section.
1.445 +*/
1.446 +EXPORT_C __NAKED__ void kumemset(TAny* /*aAddr*/, const TUint8 /*aValue*/, TInt /*aLength*/)
1.447 + {
1.448 + asm("push edi");
1.449 + asm("push es");
1.450 + asm("mov edi, [esp+12]");
1.451 + asm("mov eax, [esp+16]");
1.452 + asm("mov ecx, [esp+20]");
1.453 + asm("mov dx, gs");
1.454 + asm("mov es, dx");
1.455 + asm("call %a0": :"i"(&FillInterSeg));
1.456 + asm("pop es");
1.457 + asm("pop edi");
1.458 + asm("ret");
1.459 + }
1.460 +
1.461 +
1.462 +/** Fills the current thread's memory space with user permissions.
1.463 +
1.464 +Performs a memset(aUserAddr, aValue, aLength).
1.465 +The writes are performed with ring 3 RPL.
1.466 +
1.467 +@param aUserAddr Destination address in user memory.
1.468 +@param aValue Value to write to each byte.
1.469 +@param aLength Number of bytes to fill.
1.470 +
1.471 +@pre Call in a thread context.
1.472 +@pre Kernel must be unlocked.
1.473 +@pre Must be called under an XTRAP harness, or calling thread must not be
1.474 +in a critical section.
1.475 +*/
1.476 +EXPORT_C __NAKED__ void umemset(TAny* /*aUserAddr*/, const TUint8 /*aValue*/, TInt /*aLength*/)
1.477 + {
1.478 + asm("push edi");
1.479 + asm("push es");
1.480 + asm("mov edi, [esp+12]");
1.481 + asm("mov eax, [esp+16]");
1.482 + asm("mov ecx, [esp+20]");
1.483 + asm("mov edx, %0": : "i"(RING3_DS));
1.484 + asm("mov es, dx");
1.485 + asm("call %a0": :"i"(&FillInterSeg));
1.486 + asm("pop es");
1.487 + asm("pop edi");
1.488 + asm("ret");
1.489 + }
1.490 +
1.491 +__NAKED__ void uumemcpy32(TAny* /*aUserDst*/, const TAny* /*aUserSrc*/, TInt /*aLength*/)
1.492 + {
1.493 + asm("push edi");
1.494 + asm("push esi");
1.495 + asm("push ebx");
1.496 + asm("push ds");
1.497 + asm("push es");
1.498 + asm("mov edi, [esp+24]");
1.499 + asm("mov esi, [esp+28]");
1.500 + asm("mov ecx, [esp+32]");
1.501 + asm("mov ax, gs");
1.502 + asm("mov ds, ax");
1.503 + asm("mov es, ax");
1.504 + asm("call %a0": : "i"(&CopyInterSeg32));
1.505 + asm("pop es");
1.506 + asm("pop ds");
1.507 + asm("pop ebx");
1.508 + asm("pop esi");
1.509 + asm("pop edi");
1.510 + asm("ret");
1.511 + }
1.512 +
1.513 +__NAKED__ void uumemcpy(TAny* /*aUserDst*/, const TAny* /*aUserSrc*/, TInt /*aLength*/)
1.514 + {
1.515 + asm("push edi");
1.516 + asm("push esi");
1.517 + asm("push ebx");
1.518 + asm("push ds");
1.519 + asm("push es");
1.520 + asm("mov edi, [esp+24]");
1.521 + asm("mov esi, [esp+28]");
1.522 + asm("mov ecx, [esp+32]");
1.523 + asm("mov ax, gs");
1.524 + asm("mov ds, ax");
1.525 + asm("mov es, ax");
1.526 + asm("call %a0": : "i"(&CopyInterSeg));
1.527 + asm("pop es");
1.528 + asm("pop ds");
1.529 + asm("pop ebx");
1.530 + asm("pop esi");
1.531 + asm("pop edi");
1.532 + asm("ret");
1.533 + }
1.534 +
1.535 +}