290 lines
7.8 KiB
C
290 lines
7.8 KiB
C
//----------------------------------------------------------------------------//
|
|
// OS on Kaleid //
|
|
// //
|
|
// Desc: mem*() family //
|
|
// //
|
|
// //
|
|
// Copyright © 2018-2021 The OS/K Team //
|
|
// //
|
|
// This file is part of OS/K. //
|
|
// //
|
|
// OS/K is free software: you can redistribute it and/or modify //
|
|
// it under the terms of the GNU General Public License as published by //
|
|
// the Free Software Foundation, either version 3 of the License, or //
|
|
// any later version. //
|
|
// //
|
|
// OS/K is distributed in the hope that it will be useful, //
|
|
// but WITHOUT ANY WARRANTY//without even the implied warranty of //
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
// GNU General Public License for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with OS/K. If not, see <https://www.gnu.org/licenses/>. //
|
|
//----------------------------------------------------------------------------//
|
|
|
|
#include <libc.h>
|
|
#include <ex/malloc.h>
|
|
|
|
/* DO NOT compile with strict aliasing on */
|
|
|
|
//------------------------------------------//
|
|
// Memory allocation //
|
|
//------------------------------------------//
|
|
|
|
void *malloc(size_t n)
|
|
{
|
|
void *ptr;
|
|
error_t rc;
|
|
|
|
#ifndef _KALEID_KERNEL
|
|
rc = KalAllocMemory(&ptr, n);
|
|
#else
|
|
rc = KalAllocMemoryEx(&ptr, n, M_ZEROED, 0);
|
|
#endif
|
|
if (rc > 0) seterrno(rc);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void *memalign(size_t n, size_t align)
|
|
{
|
|
void *ptr;
|
|
error_t rc;
|
|
|
|
#ifndef _KALEID_KERNEL
|
|
rc = KalAllocMemoryEx(&ptr, n, 0, align);
|
|
#else
|
|
rc = KalAllocMemoryEx(&ptr, n, M_ZEROED, align);
|
|
#endif
|
|
if (rc > 0) seterrno(rc);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void *calloc(size_t n, size_t m)
|
|
{
|
|
void *ptr;
|
|
error_t rc;
|
|
|
|
rc = KalAllocMemoryEx(&ptr, n * m, M_ZEROED, 0);
|
|
if (rc > 0) seterrno(rc);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void free(void *ptr)
|
|
{
|
|
error_t rc = KalFreeMemory(ptr);
|
|
(void)rc;
|
|
}
|
|
|
|
//------------------------------------------//
|
|
// memset() family //
|
|
//------------------------------------------//
|
|
|
|
//
|
|
// Set "bytes"-many bytes starting from ptr to val
|
|
//
|
|
void *memset(void *ptr, int val, size_t bytes)
|
|
{
|
|
uchar *uptr = (uchar *)ptr;
|
|
|
|
// Deal with bytes before start of the first aligned qword
|
|
while (((ulong)uptr % alignof(QWORD)) > 0 && bytes--) {
|
|
*uptr++ = (uchar)val;
|
|
}
|
|
|
|
// At this point we're qword-aligned
|
|
if (bytes > sizeof(QWORD)) {
|
|
const ulong uval = ((ulong)val << 56) | ((ulong)val << 48)
|
|
| ((ulong)val << 40) | ((ulong)val << 32)
|
|
| ((ulong)val << 24) | ((ulong)val << 16)
|
|
| ((ulong)val << 8) | ((ulong)val);
|
|
|
|
ulong *uqptr = (ulong *)ptr;
|
|
|
|
// Moving fast, qword by qword
|
|
while (bytes > sizeof(QWORD)) {
|
|
bytes -= sizeof(QWORD);
|
|
*uqptr++ = uval;
|
|
}
|
|
|
|
uptr = (uchar *)(ulong)uqptr;
|
|
}
|
|
|
|
// Deal with the few remaining bytes
|
|
while (bytes--) *uptr++ = (uchar)val;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// Set "words"-many words starting from ptr to val
|
|
//
|
|
void *memsetw(void *ptr, int val, size_t words)
|
|
{
|
|
ushort *uptr = (ushort *)ptr;
|
|
|
|
// Check whether we can we do this a word-aligned way
|
|
if unlikely (((ulong)uptr % alignof(WORD)) > 0) {
|
|
// We can't, so we write word by word all the way up
|
|
while (words--) *uptr++ = (ushort)val;
|
|
return uptr;
|
|
}
|
|
|
|
while (((ulong)uptr % alignof(QWORD)) > 0 && words--) {
|
|
*uptr++ = (ushort)val;
|
|
}
|
|
|
|
if (words > QWORDS_TO_WORDS(1)) {
|
|
const ulong uval = ((ulong)val << 48) | ((ulong)val << 32)
|
|
| ((ulong)val << 16) | ((ulong)val);
|
|
|
|
ulong *uqptr = (ulong *)uptr;
|
|
|
|
while (words > QWORDS_TO_WORDS(1)) {
|
|
words -= QWORDS_TO_WORDS(1);
|
|
*uqptr++ = uval;
|
|
}
|
|
|
|
uptr = (ushort *)(ulong)uqptr;
|
|
}
|
|
|
|
while (words--) *uptr++ = (ushort)val;
|
|
|
|
return ptr;
|
|
}
|
|
#endif
|
|
|
|
// Set "dwords"-many dwords starting from ptr to val
|
|
// XXX unimplemented
|
|
void *memsetd(void *ptr, int val, size_t dwords)
|
|
{
|
|
(void)val;
|
|
(void)dwords;
|
|
seterrno(ENOSYS);
|
|
return ptr;
|
|
}
|
|
|
|
// Set "qwords"-many qwords starting from ptr to val
|
|
void *memsetq(void *ptr, long val, size_t qwords)
|
|
{
|
|
ulong *uptr = (ulong *)ptr;
|
|
|
|
// There's no need to check for alignment
|
|
while (qwords--) *uptr++ = (ulong)val;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
//------------------------------------------//
|
|
// Other mem*() functions //
|
|
//------------------------------------------//
|
|
|
|
//
|
|
// Set "bytes"-many bytes starting from ptr to 0
|
|
//
|
|
void *memzero(void *ptr, size_t bytes)
|
|
{
|
|
return memset(ptr, 0, bytes);
|
|
}
|
|
|
|
//
|
|
// Copy "bytes"-many bytes of src to dst
|
|
// Does not deal with overlapping blocks (memmove's job)
|
|
//
|
|
void *memcpy(void *restrict dst, const void *restrict src, size_t bytes)
|
|
{
|
|
const ulong *usrc = (const ulong *)src;
|
|
ulong *udst = (ulong *)dst;
|
|
|
|
assert(!"Don't use this, use memmove()");
|
|
assert((dst + bytes < src || src + bytes < dst) && "memcpy() overlap; use memmove()");
|
|
|
|
if unlikely (bytes == 0) return dst;
|
|
|
|
// Can align both src and dst at once at once?
|
|
if unlikely ((ulong)src % alignof(WORD) == 1
|
|
&& (ulong)dst % alignof(WORD) == 1) {
|
|
const uchar *ubsrc = (const uchar *)usrc;
|
|
uchar *ubdst = (uchar *)udst;
|
|
|
|
// Yes we can, we're guaranteed to be word-aligned after that
|
|
*ubdst++ = *ubsrc++;
|
|
bytes--;
|
|
|
|
udst = (ulong *)ubdst;
|
|
usrc = (ulong *)ubsrc;
|
|
}
|
|
|
|
const ushort *uwsrc = (const ushort *)usrc;
|
|
ushort *uwdst = (ushort *)udst;
|
|
|
|
// Align either dst or src for qword access
|
|
while ((ulong)dst % alignof(QWORD) > 0
|
|
&& (ulong)src % alignof(QWORD) > 0
|
|
&& bytes > sizeof(WORD)) {
|
|
|
|
bytes -= sizeof(WORD);
|
|
*uwdst++ = *uwsrc++;
|
|
}
|
|
|
|
udst = (ulong *)uwdst;
|
|
usrc = (ulong *)uwsrc;
|
|
|
|
// Copy fast
|
|
while (bytes > sizeof(QWORD)) {
|
|
bytes -= sizeof(QWORD);
|
|
*udst++ = *usrc++;
|
|
}
|
|
|
|
const uchar *ubsrc = (const uchar *)usrc;
|
|
ushort *ubdst = (ushort *)udst;
|
|
|
|
// Deal with the few bytes left
|
|
while (bytes--) *ubdst ++ = *ubsrc++;
|
|
|
|
return dst;
|
|
}
|
|
|
|
//
|
|
// Move memory from src to dest, even if they overlap
|
|
//
|
|
void *memmove(void *dst, const void *src, size_t bytes)
|
|
{
|
|
const uchar *usrc = src;
|
|
uchar *udst = dst;
|
|
|
|
// Can we safely go forward?
|
|
if (udst < usrc) {
|
|
while (bytes--) *udst++ = *usrc++;
|
|
}
|
|
|
|
// No, so we go backwards
|
|
else {
|
|
const uchar *usrc_end = usrc + bytes - 1;
|
|
uchar *udst_end = udst + bytes - 1;
|
|
while (bytes--) *udst_end-- = *usrc_end--;
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
//
|
|
// Compare memory areas
|
|
//
|
|
int memcmp(const void *ptr1, const void *ptr2, size_t bytes)
|
|
{
|
|
const uchar *uptr1 = ptr1;
|
|
const uchar *uptr2 = ptr2;
|
|
|
|
while (bytes--) {
|
|
if (*uptr1++ != *uptr2++) {
|
|
return uptr1[-1] < uptr2[-1] ? -1 : 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|