1/*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7*/
8
9#if !_BOOT_MODE
10#	include "asm_offsets.h"
11#endif
12
13#include <asm_defs.h>
14
15
16// We don't need the indirection in the boot loader.
17#if _BOOT_MODE
18#	define memcpy_generic	memcpy
19#	define memset_generic	memset
20#endif
21
22
23.align 4
24FUNCTION(memcpy_generic):
25	pushl	%esi
26	pushl	%edi
27	movl	12(%esp),%edi	/* dest */
28	movl	%edi,%eax	/* save dest ptr as return address */
29	movl	16(%esp),%esi	/* source */
30	movl	20(%esp),%ecx	/* count */
31
32	/* move by words */
33	// TODO: The addresses might not be aligned!
34	cld
35	shrl	$2,%ecx
36	rep
37	movsl
38
39	/* move any remaining data by bytes */
40	movl	20(%esp),%ecx
41	andl	$3,%ecx
42	rep
43	movsb
44
45	popl	%edi
46	popl	%esi
47	ret
48FUNCTION_END(memcpy_generic)
49SYMBOL(memcpy_generic_end):
50
51
52/* void *memset(void *dest, int value, size_t length); */
53.align 4
54FUNCTION(memset_generic):
55	push	%ebp
56	mov		%esp, %ebp
57
58	// %eax, %ecx, and %edx are scratch registers -- we only have to save %edi
59	push	%edi
60
61	// get the parameters
62	mov		16(%ebp), %ecx
63	mov		12(%ebp), %eax
64	mov		8(%ebp), %edi
65
66	// When touching less than 12 bytes, we just do it bytewise. We might be
67	// able to process one or two lwords lwordwise, but the additional overhead
68	// isn't worth it.
69	cmp		$12, %ecx
70	jl		2f
71
72	// buffer address lword-aligned?
73	mov		%edi, %edx
74	and		$0x3, %edx
75	jz		1f
76
77	// the buffer is unaligned -- copy the first bytes bytewise
78	mov		$4, %ecx
79	sub		%edx, %ecx
80	rep 	stosb
81
82	mov		16(%ebp), %ecx
83	sub		$4, %ecx
84	add		%edx, %ecx
85
861:	// lwordwise
87	// prepare %eax -- the low byte must be copied to the other bytes
88	mov		%al, %ah
89	mov		%eax, %edx
90	shl		$16, %eax
91	mov		%dx, %ax
92
93	// get the unaligned remainder into %edx
94	mov		%ecx, %edx
95	and		$0x3, %edx
96
97	// write words
98	shr		$2, %ecx
99	rep		stosl
100
101	mov		%edx, %ecx
102
1032:	// bytewise (remaining bytes)
104	rep 	stosb
105
106	pop		%edi
107
108	// return value is the value passed in
109	mov		8(%ebp), %eax
110
111	mov		%ebp, %esp
112	pop		%ebp
113	ret
114FUNCTION_END(memset_generic)
115SYMBOL(memset_generic_end):
116
117
118#if !_BOOT_MODE
119
120.align 4
121FUNCTION(memcpy):
122	jmp		*(gOptimizedFunctions + X86_OPTIMIZED_FUNCTIONS_memcpy)
123FUNCTION_END(memcpy)
124
125FUNCTION(memset):
126	jmp		*(gOptimizedFunctions + X86_OPTIMIZED_FUNCTIONS_memset)
127FUNCTION_END(memset)
128
129#endif	// !_BOOT_MODE
130