]>
Commit | Line | Data |
---|---|---|
2aa62f2b | 1 | /** @file\r |
2 | Definitions for memory allocation routines: calloc, malloc, realloc, free.\r | |
3 | \r | |
4 | The order and contiguity of storage allocated by successive calls to the\r | |
5 | calloc, malloc, and realloc functions is unspecified. The pointer returned\r | |
6 | if the allocation succeeds is suitably aligned so that it may be assigned to\r | |
7 | a pointer of any type of object and then used to access such an object or an\r | |
8 | array of such objects in the space allocated (until the space is explicitly\r | |
9 | freed or reallocated). Each such allocation shall yield a pointer to an\r | |
10 | object disjoint from any other object. The pointer returned points to the\r | |
11 | start (lowest byte address) of the allocated space. If the space can not be\r | |
12 | allocated, a null pointer is returned. If the size of the space requested\r | |
13 | is zero, the behavior is implementation-defined; the value returned shall be\r | |
14 | either a null pointer or a unique pointer. The value of a pointer that\r | |
15 | refers to freed space is indeterminate.\r | |
16 | \r | |
17 | Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r | |
18 | This program and the accompanying materials\r | |
19 | are licensed and made available under the terms and conditions of the BSD License\r | |
20 | which accompanies this distribution. The full text of the license may be found at\r | |
21 | http://opensource.org/licenses/bsd-license.php\r | |
22 | \r | |
23 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
24 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
25 | \r | |
26 | */\r | |
27 | #include <Base.h>\r | |
28 | #include <Uefi.h>\r | |
29 | #include <Library/MemoryAllocationLib.h>\r | |
30 | #include <Library/UefiBootServicesTableLib.h>\r | |
31 | #include <Library/BaseMemoryLib.h>\r | |
32 | #include <Library/DebugLib.h>\r | |
33 | \r | |
34 | #include <LibConfig.h>\r | |
35 | \r | |
36 | #include <assert.h>\r | |
37 | #include <stdlib.h>\r | |
38 | #include <errno.h>\r | |
39 | \r | |
40 | /** The UEFI functions do not provide a way to determine the size of an\r | |
41 | allocated region of memory given just a pointer to the start of that\r | |
42 | region. Since this is required for the implementation of realloc,\r | |
43 | the memory head structure from Core/Dxe/Mem/Pool.c has been reproduced\r | |
44 | here.\r | |
45 | \r | |
46 | NOTE: If the UEFI implementation is changed, the realloc function may cease\r | |
47 | to function properly.\r | |
48 | **/\r | |
49 | #define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r | |
50 | typedef struct {\r | |
51 | UINT32 Signature;\r | |
52 | UINT32 Size;\r | |
53 | EFI_MEMORY_TYPE Type;\r | |
54 | UINTN Reserved;\r | |
55 | CHAR8 Data[1];\r | |
56 | } POOL_HEAD;\r | |
57 | \r | |
58 | /****************************/\r | |
59 | \r | |
60 | /** The malloc function allocates space for an object whose size is specified\r | |
61 | by size and whose value is indeterminate.\r | |
62 | \r | |
63 | This implementation uses the UEFI memory allocation boot services to get a\r | |
64 | region of memory that is 8-byte aligned and of the specified size. The\r | |
65 | region is allocated with type EfiLoaderData.\r | |
66 | \r | |
67 | @param size Size, in bytes, of the region to allocate.\r | |
68 | \r | |
69 | @return NULL is returned if the space could not be allocated and errno\r | |
70 | contains the cause. Otherwise, a pointer to an 8-byte aligned\r | |
71 | region of the requested size is returned.<BR>\r | |
72 | If NULL is returned, errno may contain:\r | |
73 | - EINVAL: Requested Size is zero.\r | |
74 | - ENOMEM: Memory could not be allocated.\r | |
75 | **/\r | |
76 | void *\r | |
77 | malloc(size_t Size)\r | |
78 | {\r | |
79 | void *RetVal;\r | |
80 | EFI_STATUS Status;\r | |
81 | \r | |
82 | if( Size == 0) {\r | |
83 | errno = EINVAL; // Make errno diffenent, just in case of a lingering ENOMEM.\r | |
84 | return NULL;\r | |
85 | }\r | |
86 | \r | |
87 | Status = gBS->AllocatePool( EfiLoaderData, (UINTN)Size, &RetVal);\r | |
88 | if( Status != EFI_SUCCESS) {\r | |
89 | RetVal = NULL;\r | |
90 | errno = ENOMEM;\r | |
91 | }\r | |
92 | return RetVal;\r | |
93 | }\r | |
94 | \r | |
95 | /** The calloc function allocates space for an array of Num objects, each of\r | |
96 | whose size is Size. The space is initialized to all bits zero.\r | |
97 | \r | |
98 | This implementation uses the UEFI memory allocation boot services to get a\r | |
99 | region of memory that is 8-byte aligned and of the specified size. The\r | |
100 | region is allocated with type EfiLoaderData.\r | |
101 | \r | |
102 | @param Num Number of objects to allocate.\r | |
103 | @param Size Size, in bytes, of the objects to allocate space for.\r | |
104 | \r | |
105 | @return NULL is returned if the space could not be allocated and errno\r | |
106 | contains the cause. Otherwise, a pointer to an 8-byte aligned\r | |
107 | region of the requested size is returned.\r | |
108 | **/\r | |
109 | void *\r | |
110 | calloc(size_t Num, size_t Size)\r | |
111 | {\r | |
112 | void *RetVal;\r | |
113 | size_t NumSize;\r | |
114 | \r | |
115 | NumSize = Num * Size;\r | |
116 | if (NumSize == 0) {\r | |
117 | return NULL;\r | |
118 | }\r | |
119 | RetVal = malloc(NumSize);\r | |
120 | if( RetVal != NULL) {\r | |
121 | (VOID)ZeroMem( RetVal, NumSize);\r | |
122 | }\r | |
123 | return RetVal;\r | |
124 | }\r | |
125 | \r | |
126 | /** The free function causes the space pointed to by Ptr to be deallocated,\r | |
127 | that is, made available for further allocation.\r | |
128 | \r | |
129 | If Ptr is a null pointer, no action occurs. Otherwise, if the argument\r | |
130 | does not match a pointer earlier returned by the calloc, malloc, or realloc\r | |
131 | function, or if the space has been deallocated by a call to free or\r | |
132 | realloc, the behavior is undefined.\r | |
133 | \r | |
134 | @param Ptr Pointer to a previously allocated region of memory to be freed.\r | |
135 | \r | |
136 | **/\r | |
137 | void\r | |
138 | free(void *Ptr)\r | |
139 | {\r | |
140 | (void) gBS->FreePool (Ptr);\r | |
141 | }\r | |
142 | \r | |
143 | /** The realloc function changes the size of the object pointed to by Ptr to\r | |
144 | the size specified by NewSize.\r | |
145 | \r | |
146 | The contents of the object are unchanged up to the lesser of the new and\r | |
147 | old sizes. If the new size is larger, the value of the newly allocated\r | |
148 | portion of the object is indeterminate.\r | |
149 | \r | |
150 | If Ptr is a null pointer, the realloc function behaves like the malloc\r | |
151 | function for the specified size.\r | |
152 | \r | |
153 | If Ptr does not match a pointer earlier returned by the calloc, malloc, or\r | |
154 | realloc function, or if the space has been deallocated by a call to the free\r | |
155 | or realloc function, the behavior is undefined.\r | |
156 | \r | |
157 | If the space cannot be allocated, the object pointed to by Ptr is unchanged.\r | |
158 | \r | |
159 | If NewSize is zero and Ptr is not a null pointer, the object it points to\r | |
160 | is freed.\r | |
161 | \r | |
162 | This implementation uses the UEFI memory allocation boot services to get a\r | |
163 | region of memory that is 8-byte aligned and of the specified size. The\r | |
164 | region is allocated with type EfiLoaderData.\r | |
165 | \r | |
166 | The following combinations of Ptr and NewSize can occur:<BR>\r | |
167 | Ptr NewSize<BR>\r | |
168 | -------- -------------------<BR>\r | |
169 | - NULL 0 Returns NULL;\r | |
170 | - NULL > 0 Same as malloc(NewSize)\r | |
171 | - invalid X Returns NULL;\r | |
172 | - valid NewSize >= OldSize Returns malloc(NewSize) with Oldsize bytes copied from Ptr\r | |
173 | - valid NewSize < OldSize Returns new buffer with Oldsize bytes copied from Ptr\r | |
174 | - valid 0 Return NULL. Frees Ptr.\r | |
175 | \r | |
176 | \r | |
177 | @param Ptr Pointer to a previously allocated region of memory to be resized.\r | |
178 | @param NewSize Size, in bytes, of the new object to allocate space for.\r | |
179 | \r | |
180 | @return NULL is returned if the space could not be allocated and errno\r | |
181 | contains the cause. Otherwise, a pointer to an 8-byte aligned\r | |
182 | region of the requested size is returned. If NewSize is zero,\r | |
183 | NULL is returned and errno will be unchanged.\r | |
184 | **/\r | |
185 | void *\r | |
186 | realloc(void *Ptr, size_t NewSize)\r | |
187 | {\r | |
188 | void *RetVal = NULL;\r | |
189 | POOL_HEAD *Head;\r | |
190 | UINTN OldSize = 0;\r | |
191 | UINTN NumCpy;\r | |
192 | \r | |
193 | // Find out the size of the OLD memory region\r | |
194 | if( Ptr != NULL) {\r | |
195 | Head = BASE_CR (Ptr, POOL_HEAD, Data);\r | |
196 | assert(Head != NULL);\r | |
197 | if (Head->Signature != POOL_HEAD_SIGNATURE) {\r | |
198 | errno = EFAULT;\r | |
199 | return NULL;\r | |
200 | }\r | |
201 | OldSize = Head->Size;\r | |
202 | }\r | |
203 | \r | |
204 | // At this point, Ptr is either NULL or a valid pointer to an allocated space\r | |
205 | \r | |
206 | if( NewSize > 0) {\r | |
207 | RetVal = malloc(NewSize); // Get the NEW memory region\r | |
208 | if( Ptr != NULL) { // If there is an OLD region...\r | |
209 | if( RetVal != NULL) { // and the NEW region was successfully allocated\r | |
210 | NumCpy = OldSize;\r | |
211 | if( OldSize > NewSize) {\r | |
212 | NumCpy = NewSize;\r | |
213 | }\r | |
214 | (VOID)CopyMem( RetVal, Ptr, NumCpy); // Copy old data to the new region.\r | |
215 | free( Ptr); // and reclaim the old region.\r | |
216 | }\r | |
217 | }\r | |
218 | }\r | |
219 | else {\r | |
220 | if( Ptr != NULL) {\r | |
221 | free( Ptr); // Reclaim the old region.\r | |
222 | }\r | |
223 | }\r | |
224 | \r | |
225 | return RetVal;\r | |
226 | }\r |