split kernel lib sources into their own directory and handled the section

differences with a partial link and a special link script
This commit is contained in:
Eric J. Bowersox
2013-05-02 22:31:00 -06:00
parent 9c655d1fb0
commit 622b4cfe3c
18 changed files with 272 additions and 71 deletions

43
kernel/lib/Makefile Normal file
View File

@@ -0,0 +1,43 @@
#
# This file is part of the COMROGUE Operating System for Raspberry Pi
#
# Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
# All rights reserved.
#
# This program is free for commercial and non-commercial use as long as the following conditions are
# adhered to.
#
# Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
# in the code are not to be removed.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted
# provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this list of conditions and
# the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
MAKEFLAGS += -rR
CRBASEDIR := $(abspath ../..)
include $(CRBASEDIR)/armcompile.mk
LIB_OBJS = divide.o qdivrem.o intlib.o objhelp.o rbtree.o str.o strcopymem.o strcomparemem.o strsetmem.o lib_guids.o
all: kernel-lib.o
kernel-lib.o: $(LIB_OBJS) kernel-lib.lds
$(LD) -r -T kernel-lib.lds $(LIB_OBJS) -o kernel-lib.o
clean:
-rm *.o *.s *.lds

477
kernel/lib/divide.S Normal file
View File

@@ -0,0 +1,477 @@
/*
* Portions of this file are subject to the following notices:
*
* Copyright (C) 2012 Andrew Turner
* All rights reserved.
*
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas of 3am Software Foundry.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Derived from FreeBSD libkern divsi3.S, uldivmod.S, and ldivmod.S, munged by Erbo to COMROGUE standards */
.globl __aeabi_uidiv
.globl __aeabi_uidivmod
__aeabi_uidiv:
__aeabi_uidivmod:
eor r0, r1, r0 /* r0 = r0 / r1; r1 = r0 % r1 */
eor r1, r0, r1
eor r0, r1, r0 /* r0 = r1 / r0; r1 = r1 % r0 */
cmp r0, #1
bcc .L_overflow
beq .L_divide_l0
mov ip, #0
movs r1, r1
bpl .L_divide_l1
orr ip, ip, #0x20000000 /* indicates r1 is negative */
movs r1, r1, lsr #1
orrcs ip, ip, #0x10000000 /* indicates bit 0 of r1 */
b .L_divide_l1
.L_divide_l0:
mov r0, r1 /* r0 == 1 */
mov r1, #0
bx lr
.globl __aeabi_idiv
.globl __aeabi_idivmod
__aeabi_idiv:
__aeabi_idivmod:
eor r0, r1, r0 /* r0 = r0 / r1; r1 = r0 % r1 */
eor r1, r0, r1
eor r0, r1, r0 /* r0 = r1 / r0; r1 = r1 % r0 */
cmp r0, #1
bcc .L_overflow
beq .L_divide_l0
ands ip, r0, #0x80000000
rsbmi r0, r0, #0
ands r2, r1, #0x80000000
eor ip, ip, r2
rsbmi r1, r1, #0
orr ip, r2, ip, lsr #1 /* bit 0x40000000 = negative division, bit 0x80000000 = negative remainder */
.L_divide_l1:
mov r2, #1
mov r3, #0
/*
* If the highest bit of the dividend is set, we have to be
* careful when shifting the divisor. Test this.
*/
movs r1, r1
bpl .L_old_code
/*
* At this point, the highest bit of r1 is known to be set.
* We abuse this below in the tst instructions.
*/
tst r1, r0 /*, lsl #0 */
bmi .L_divide_b1
tst r1, r0, lsl #1
bmi .L_divide_b2
tst r1, r0, lsl #2
bmi .L_divide_b3
tst r1, r0, lsl #3
bmi .L_divide_b4
tst r1, r0, lsl #4
bmi .L_divide_b5
tst r1, r0, lsl #5
bmi .L_divide_b6
tst r1, r0, lsl #6
bmi .L_divide_b7
tst r1, r0, lsl #7
bmi .L_divide_b8
tst r1, r0, lsl #8
bmi .L_divide_b9
tst r1, r0, lsl #9
bmi .L_divide_b10
tst r1, r0, lsl #10
bmi .L_divide_b11
tst r1, r0, lsl #11
bmi .L_divide_b12
tst r1, r0, lsl #12
bmi .L_divide_b13
tst r1, r0, lsl #13
bmi .L_divide_b14
tst r1, r0, lsl #14
bmi .L_divide_b15
tst r1, r0, lsl #15
bmi .L_divide_b16
tst r1, r0, lsl #16
bmi .L_divide_b17
tst r1, r0, lsl #17
bmi .L_divide_b18
tst r1, r0, lsl #18
bmi .L_divide_b19
tst r1, r0, lsl #19
bmi .L_divide_b20
tst r1, r0, lsl #20
bmi .L_divide_b21
tst r1, r0, lsl #21
bmi .L_divide_b22
tst r1, r0, lsl #22
bmi .L_divide_b23
tst r1, r0, lsl #23
bmi .L_divide_b24
tst r1, r0, lsl #24
bmi .L_divide_b25
tst r1, r0, lsl #25
bmi .L_divide_b26
tst r1, r0, lsl #26
bmi .L_divide_b27
tst r1, r0, lsl #27
bmi .L_divide_b28
tst r1, r0, lsl #28
bmi .L_divide_b29
tst r1, r0, lsl #29
bmi .L_divide_b30
tst r1, r0, lsl #30
bmi .L_divide_b31
/*
* instead of:
* tst r1, r0, lsl #31
* bmi .L_divide_b32
*/
b .L_divide_b32
.L_old_code:
cmp r1, r0
bcc .L_divide_b0
cmp r1, r0, lsl #1
bcc .L_divide_b1
cmp r1, r0, lsl #2
bcc .L_divide_b2
cmp r1, r0, lsl #3
bcc .L_divide_b3
cmp r1, r0, lsl #4
bcc .L_divide_b4
cmp r1, r0, lsl #5
bcc .L_divide_b5
cmp r1, r0, lsl #6
bcc .L_divide_b6
cmp r1, r0, lsl #7
bcc .L_divide_b7
cmp r1, r0, lsl #8
bcc .L_divide_b8
cmp r1, r0, lsl #9
bcc .L_divide_b9
cmp r1, r0, lsl #10
bcc .L_divide_b10
cmp r1, r0, lsl #11
bcc .L_divide_b11
cmp r1, r0, lsl #12
bcc .L_divide_b12
cmp r1, r0, lsl #13
bcc .L_divide_b13
cmp r1, r0, lsl #14
bcc .L_divide_b14
cmp r1, r0, lsl #15
bcc .L_divide_b15
cmp r1, r0, lsl #16
bcc .L_divide_b16
cmp r1, r0, lsl #17
bcc .L_divide_b17
cmp r1, r0, lsl #18
bcc .L_divide_b18
cmp r1, r0, lsl #19
bcc .L_divide_b19
cmp r1, r0, lsl #20
bcc .L_divide_b20
cmp r1, r0, lsl #21
bcc .L_divide_b21
cmp r1, r0, lsl #22
bcc .L_divide_b22
cmp r1, r0, lsl #23
bcc .L_divide_b23
cmp r1, r0, lsl #24
bcc .L_divide_b24
cmp r1, r0, lsl #25
bcc .L_divide_b25
cmp r1, r0, lsl #26
bcc .L_divide_b26
cmp r1, r0, lsl #27
bcc .L_divide_b27
cmp r1, r0, lsl #28
bcc .L_divide_b28
cmp r1, r0, lsl #29
bcc .L_divide_b29
cmp r1, r0, lsl #30
bcc .L_divide_b30
.L_divide_b32:
cmp r1, r0, lsl #31
subhs r1, r1,r0, lsl #31
addhs r3, r3,r2, lsl #31
.L_divide_b31:
cmp r1, r0, lsl #30
subhs r1, r1,r0, lsl #30
addhs r3, r3,r2, lsl #30
.L_divide_b30:
cmp r1, r0, lsl #29
subhs r1, r1,r0, lsl #29
addhs r3, r3,r2, lsl #29
.L_divide_b29:
cmp r1, r0, lsl #28
subhs r1, r1,r0, lsl #28
addhs r3, r3,r2, lsl #28
.L_divide_b28:
cmp r1, r0, lsl #27
subhs r1, r1,r0, lsl #27
addhs r3, r3,r2, lsl #27
.L_divide_b27:
cmp r1, r0, lsl #26
subhs r1, r1,r0, lsl #26
addhs r3, r3,r2, lsl #26
.L_divide_b26:
cmp r1, r0, lsl #25
subhs r1, r1,r0, lsl #25
addhs r3, r3,r2, lsl #25
.L_divide_b25:
cmp r1, r0, lsl #24
subhs r1, r1,r0, lsl #24
addhs r3, r3,r2, lsl #24
.L_divide_b24:
cmp r1, r0, lsl #23
subhs r1, r1,r0, lsl #23
addhs r3, r3,r2, lsl #23
.L_divide_b23:
cmp r1, r0, lsl #22
subhs r1, r1,r0, lsl #22
addhs r3, r3,r2, lsl #22
.L_divide_b22:
cmp r1, r0, lsl #21
subhs r1, r1,r0, lsl #21
addhs r3, r3,r2, lsl #21
.L_divide_b21:
cmp r1, r0, lsl #20
subhs r1, r1,r0, lsl #20
addhs r3, r3,r2, lsl #20
.L_divide_b20:
cmp r1, r0, lsl #19
subhs r1, r1,r0, lsl #19
addhs r3, r3,r2, lsl #19
.L_divide_b19:
cmp r1, r0, lsl #18
subhs r1, r1,r0, lsl #18
addhs r3, r3,r2, lsl #18
.L_divide_b18:
cmp r1, r0, lsl #17
subhs r1, r1,r0, lsl #17
addhs r3, r3,r2, lsl #17
.L_divide_b17:
cmp r1, r0, lsl #16
subhs r1, r1,r0, lsl #16
addhs r3, r3,r2, lsl #16
.L_divide_b16:
cmp r1, r0, lsl #15
subhs r1, r1,r0, lsl #15
addhs r3, r3,r2, lsl #15
.L_divide_b15:
cmp r1, r0, lsl #14
subhs r1, r1,r0, lsl #14
addhs r3, r3,r2, lsl #14
.L_divide_b14:
cmp r1, r0, lsl #13
subhs r1, r1,r0, lsl #13
addhs r3, r3,r2, lsl #13
.L_divide_b13:
cmp r1, r0, lsl #12
subhs r1, r1,r0, lsl #12
addhs r3, r3,r2, lsl #12
.L_divide_b12:
cmp r1, r0, lsl #11
subhs r1, r1,r0, lsl #11
addhs r3, r3,r2, lsl #11
.L_divide_b11:
cmp r1, r0, lsl #10
subhs r1, r1,r0, lsl #10
addhs r3, r3,r2, lsl #10
.L_divide_b10:
cmp r1, r0, lsl #9
subhs r1, r1,r0, lsl #9
addhs r3, r3,r2, lsl #9
.L_divide_b9:
cmp r1, r0, lsl #8
subhs r1, r1,r0, lsl #8
addhs r3, r3,r2, lsl #8
.L_divide_b8:
cmp r1, r0, lsl #7
subhs r1, r1,r0, lsl #7
addhs r3, r3,r2, lsl #7
.L_divide_b7:
cmp r1, r0, lsl #6
subhs r1, r1,r0, lsl #6
addhs r3, r3,r2, lsl #6
.L_divide_b6:
cmp r1, r0, lsl #5
subhs r1, r1,r0, lsl #5
addhs r3, r3,r2, lsl #5
.L_divide_b5:
cmp r1, r0, lsl #4
subhs r1, r1,r0, lsl #4
addhs r3, r3,r2, lsl #4
.L_divide_b4:
cmp r1, r0, lsl #3
subhs r1, r1,r0, lsl #3
addhs r3, r3,r2, lsl #3
.L_divide_b3:
cmp r1, r0, lsl #2
subhs r1, r1,r0, lsl #2
addhs r3, r3,r2, lsl #2
.L_divide_b2:
cmp r1, r0, lsl #1
subhs r1, r1,r0, lsl #1
addhs r3, r3,r2, lsl #1
.L_divide_b1:
cmp r1, r0
subhs r1, r1, r0
addhs r3, r3, r2
.L_divide_b0:
tst ip, #0x20000000
bne .L_udivide_l1
mov r0, r3
cmp ip, #0
rsbmi r1, r1, #0
movs ip, ip, lsl #1
bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */
rsbmi r0, r0, #0
bx lr
.L_udivide_l1:
tst ip, #0x10000000
mov r1, r1, lsl #1
orrne r1, r1, #1
mov r3, r3, lsl #1
cmp r1, r0
subhs r1, r1, r0
addhs r3, r3, r2
mov r0, r3
bx lr
.L_overflow:
/* TODO: cause an exception or something? */
mvn r0, #0
bx lr
.globl __aeabi_uldivmod
__aeabi_uldivmod:
push {r4,lr}
sub sp, sp, #8
mov r4, sp
push {r4}
bl __qdivrem
pop {r4}
/*
* The remainder is already on the stack just waiting to be popped
* into r2/r3.
*/
pop {r2-r4,lr}
bx lr
.globl __aeabi_ldivmod
__aeabi_ldivmod:
push {r4-r5, sl, lr}
mov r5, #0 /* r5 = negative indicator */
cmp r3, #0
bge 2f
eor r5, r5, #1 /* flip quotient sign */
bl .Lnegate_b
bcs .Lmaxdenom
2:
cmp r1, #0
/* bge 3f */
eorlt r5, r5, #3 /* flip quotient sign, flip remainder sign */
bllt .Lnegate_a
3:
/*
* Arguments are setup, allocate some stack for the remainder
* and call __qdivrem for the heavy lifting.
*/
sub sp, sp, #8
mov r4, sp /* pointer to remainder */
push {r4}
bl __qdivrem
pop {r4}
teq r5, #0 /* any signs to flip? */
/*
* The quotient is already in the right place and neither value
* needs its sign flipped.
*/
popeq {r2-r5, sl, lr}
bxeq lr
pop {r2, r3}
tst r5, #2 /* does remainder need to be negative? */
bleq .Lnegate_b
tst r5, #1 /* does quotient need to be negative? */
bleq .Lnegate_a
pop {r4-r5, sl, lr}
bx lr
.Lnegate_a:
rsbs r0, r0, #0
rsc r1, r1, #0
bx lr
.Lnegate_b:
rsbs r2, r2, #0
rsc r3, r3, #0
bx lr
.Lmaxdenom:
/*
* We had a carry so the denominator must have INT64_MIN
* Also BLO and BHI never changed values so we can use
* them to see if the numerator has the same value. We
* don't have to worry about sign.
*/
teq r3, r1
teqeq r2, r0
bne 1f
/*
* They were equal, so we return a quotient of 1 and remainder of 0.
*/
mov r0, #1
mov r1, #0
mov r2, #0
mov r3, #0
pop {r4-r5, sl, lr}
bx lr
/*
* Our remainder must be the numerator and our quotient is 0.
*/
1: mov r2, r0
mov r3, r1
mov r0, #0
mov r1, #0
pop {r4-r5, sl, lr}
bx lr

80
kernel/lib/intlib.c Normal file
View File

@@ -0,0 +1,80 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/types.h>
#include <comrogue/intlib.h>
#include "quad.h"
/*---------------------------
* Integer library functions
*---------------------------
*/
/* Flags used internally to IntLDiv. */
#define FLIP_QUOTIENT 0x00000001
#define FLIP_REMAINDER 0x00000002
/*
* Divides two 64-bit integers and returns a quotient and a remainder in a structure.
*
* Parameters:
* - pResult = Pointer to an LDIV structure to contain the quotient and remainder.
* - num = The numerator (dividend) for the division.
* - demom = The demoninator (divisor) for the division.
*
* Returns:
* Standard SUCCEEDED/FAILED HRESULT.
*/
HRESULT IntLDiv(PLDIV pResult, INT64 num, INT64 denom)
{
UINT32 mode = 0;
if (denom == 0)
{
pResult->quot = pResult->rem = 0;
return E_INVALIDARG;
}
if (denom < 0)
{
mode ^= FLIP_QUOTIENT;
denom = -denom;
}
if (num < 0)
{
mode ^= (FLIP_QUOTIENT|FLIP_REMAINDER);
num = -num;
}
pResult->quot = __qdivrem(num, denom, (PUINT64)(&(pResult->rem)));
if (mode & FLIP_QUOTIENT)
pResult->quot = -(pResult->quot);
if (mode & FLIP_REMAINDER)
pResult->rem = -(pResult->rem);
return S_OK;
}

182
kernel/lib/kernel-lib.ldi Normal file
View File

@@ -0,0 +1,182 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
/* Copied from default linker script for relocatable linking under ARM & modified */
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SECTIONS
{
/* Read-only sections, merged into text segment: */
.interp 0 : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash 0 : { *(.hash) }
.gnu.hash 0 : { *(.gnu.hash) }
.dynsym 0 : { *(.dynsym) }
.dynstr 0 : { *(.dynstr) }
.gnu.version 0 : { *(.gnu.version) }
.gnu.version_d 0: { *(.gnu.version_d) }
.gnu.version_r 0: { *(.gnu.version_r) }
.rel.init 0 : { *(.rel.init) }
.rela.init 0 : { *(.rela.init) }
.rel.text 0 : { *(.rel.text) }
.rela.text 0 : { *(.rela.text) }
.rel.fini 0 : { *(.rel.fini) }
.rela.fini 0 : { *(.rela.fini) }
.rel.rodata 0 : { *(.rel.rodata) }
.rela.rodata 0 : { *(.rela.rodata) }
.rel.ctors 0 : { *(.rel.ctors) }
.rela.ctors 0 : { *(.rela.ctors) }
.rel.dtors 0 : { *(.rel.dtors) }
.rela.dtors 0 : { *(.rela.dtors) }
.rel.got 0 : { *(.rel.got) }
.rela.got 0 : { *(.rela.got) }
.rel.bss 0 : { *(.rel.bss) }
.rela.bss 0 : { *(.rela.bss) }
.rel.iplt 0 :
{
*(.rel.iplt)
}
.rela.iplt 0 :
{
*(.rela.iplt)
}
.rel.plt 0 :
{
*(.rel.plt)
}
.rela.plt 0 :
{
*(.rela.plt)
}
.init 0 :
{
KEEP (*(.init))
} =0
.plt 0 : { *(.plt) }
.iplt 0 : { *(.iplt) }
.lib.text 0 :
{
*(.text .stub)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0
.fini 0 :
{
KEEP (*(.fini))
} =0
.lib.rodata 0 : { *(.rodata) }
.lib.rodata1 0 : { *(.rodata1) }
.ARM.extab 0 : { *(.ARM.extab) }
.ARM.exidx 0 : { *(.ARM.exidx) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame 0 : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table 0 : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges 0 : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
/* Exception handling */
.eh_frame 0 : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table 0 : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges 0 : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.preinit_array 0 :
{
KEEP (*(.preinit_array))
}
.jcr 0 : { KEEP (*(.jcr)) }
.dynamic 0 : { *(.dynamic) }
.got 0 : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.stack 0 :
{
*(.stack)
}
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
/* we don't allow data in the library section, so discard all data segments */
/DISCARD/ : {
*(.rel.data.rel.ro)
*(.rela.data.rel.ro)
*(.rel.data)
*(.rela.data)
*(.data)
*(.data1)
*(.dynbss)
*(.bss)
*(COMMON)
*(.rel.tdata)
*(.rela.tdata)
*(.rel.tbss)
*(.rela.tbss)
*(.tdata)
*(.tbss)
}
}

50
kernel/lib/lib_guids.c Normal file
View File

@@ -0,0 +1,50 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
/*------------------------------------------------------------------------------------------------------
* This module defines all the GUIDs as static data that goes into the library segment (i.e. accessible
* from both supervisor and user modes). The following definitions MUST be first in this source file,
* AND in this order.
*------------------------------------------------------------------------------------------------------
*/
#include <comrogue/internals/seg.h>
#define GUIDATTR SEG_RODATA
#define INITGUID
#include <comrogue/object_definition_macros.h>
/*-------------------------------------------------------------------------------------------------
* Now include all the header files generated from IDL. Try to include them in the order in which
* interfaces are defined.
*-------------------------------------------------------------------------------------------------
*/
#include <comrogue/object_types.h>
#include <comrogue/objectbase.h>
#include <comrogue/allocator.h>

123
kernel/lib/objhelp.c Normal file
View File

@@ -0,0 +1,123 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/str.h>
#include <comrogue/object_types.h>
#include <comrogue/objectbase.h>
#include <comrogue/allocator.h>
#include <comrogue/stdobj.h>
#include <comrogue/objhelp.h>
/*--------------------------------------------
* Standard object functions (API-type calls)
*--------------------------------------------
*/
/*
* Determines whether two GUID references are equal.
*
* Parameters:
* - guid1 = First GUID to compare.
* - guid2 = Second GUID to compare.
*
* Returns:
* TRUE if the GUIDs are equal, FALSE otherwise.
*/
BOOL IsEqualGUID(REFGUID guid1, REFGUID guid2)
{
return MAKEBOOL(StrCompareMem(guid1, guid2, sizeof(GUID)) == 0);
}
/*-----------------------------------------------------------------
* Functions to be used in the construction of C interface vtables
*-----------------------------------------------------------------
*/
/*
* Retrieves pointers to the supported interfaces on an object. Any pointer returned by this method
* has AddRef called on it before it returns.
*
* Parameters:
* - pThis = Base interface pointer.
* - riid = The identifier of the interface being requested.
* - ppvObject = Address of a pointer variable that receives the interface pointer requested by riid.
* On return, *ppvObject contains the requested interface pointer, or NULL if the interface
* is not supported.
*
* Returns:
* - S_OK = If the interface is supported. *ppvObject contains the pointer to the interface.
* - E_NOINTERFACE = If the interface is not supported. *ppvObject contains NULL.
* - E_POINTER = If ppvObject is NULL.
*/
/* This macro makes a ObjHlpStandardQueryInterface_IXXX function for any interface directly derived from IUnknown */
#define MAKE_BASE_QI(iface) \
HRESULT ObjHlpStandardQueryInterface_ ## iface (IUnknown *pThis, REFIID riid, PPVOID ppvObject) \
{ \
if (!ppvObject) return E_POINTER; \
*ppvObject = NULL; \
if (!IsEqualIID(riid, &IID_ ## iface) && !IsEqualIID(riid, &IID_IUnknown)) \
return E_NOINTERFACE; \
IUnknown_AddRef(pThis); \
*ppvObject = (PVOID)pThis; \
return S_OK; \
}
MAKE_BASE_QI(IMalloc)
/*
* "Dummy" version of AddRef/Release used for static objects.
*
* Parameters:
* - pThis = Base interface pointer.
*
* Returns:
* 1.
*/
UINT32 ObjHlpStaticAddRefRelease(IUnknown *pThis)
{
return 1;
}
/*
* Method returning void that does nothing.
*
* Parameters:
* - pThis = Base interface pointer.
*
* Returns:
* Nothing.
*/
void ObjHlpDoNothingReturnVoid(IUnknown *pThis)
{
/* do nothing */
}

279
kernel/lib/qdivrem.c Normal file
View File

@@ -0,0 +1,279 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Derived from FreeBSD libkern qdivrem.c, munged by Erbo to COMROGUE standards */
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include "quad.h"
/*
* Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
* section 4.3.1, pp. 257--259.
*/
#define B (1 << HALF_BITS) /* digit base */
/* Combine two `digits' to make a single two-digit number. */
#define COMBINE(a, b) (((UINT32)(a) << HALF_BITS) | (b))
/* select a type for digits in base B: use unsigned short if they fit */
typedef UINT16 DIGIT;
/*
* Shift p[0]..p[len] left `sh' bits, ignoring any bits that
* `fall out' the left (there never will be any such anyway).
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
*/
static void __shl(register DIGIT *p, register INT32 len, register INT32 sh)
{
register INT32 i;
for (i = 0; i < len; i++)
p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
p[i] = LHALF(p[i] << sh);
}
/*
* __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
*
* We do this in base 2^HALF_BITS, so that all intermediate products
* fit within u_long. As a consequence, the maximum length dividend and
* divisor are 4 `digits' in this base (they are shorter if they have
* leading zeros).
*/
UINT64 __qdivrem(UINT64 uq, UINT64 vq, PUINT64 pRem)
{
UU tmp;
DIGIT *u, *v, *q;
register DIGIT v1, v2;
UINT32 qhat, rhat, t;
INT32 m, n, d, j, i;
DIGIT uspace[5], vspace[5], qspace[5];
/*
* Take care of special cases: divide by zero, and u < v.
*/
if (vq == 0)
{ /* divide by zero. */
SEG_RODATA static volatile const unsigned int zero = 0;
tmp.ul[H] = tmp.ul[L] = 1 / zero;
if (pRem)
*pRem = uq;
return tmp.q;
}
if (uq < vq)
{
if (pRem)
*pRem = uq;
return 0;
}
u = uspace;
v = vspace;
q = qspace;
/*
* Break dividend and divisor into digits in base B, then
* count leading zeros to determine m and n. When done, we
* will have:
* u = (u[1]u[2]...u[m+n]) sub B
* v = (v[1]v[2]...v[n]) sub B
* v[1] != 0
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
* m >= 0 (otherwise u < v, which we already checked)
* m + n = 4
* and thus
* m = 4 - n <= 2
*/
tmp.uq = uq;
u[0] = 0;
u[1] = HHALF(tmp.ul[H]);
u[2] = LHALF(tmp.ul[H]);
u[3] = HHALF(tmp.ul[L]);
u[4] = LHALF(tmp.ul[L]);
tmp.uq = vq;
v[1] = HHALF(tmp.ul[H]);
v[2] = LHALF(tmp.ul[H]);
v[3] = HHALF(tmp.ul[L]);
v[4] = LHALF(tmp.ul[L]);
for (n = 4; v[1] == 0; v++)
{
if (--n == 1)
{
UINT32 rbj; /* r*B+u[j] (not root boy jim) */
DIGIT q1, q2, q3, q4;
/*
* Change of plan, per exercise 16.
* r = 0;
* for j = 1..4:
* q[j] = floor((r*B + u[j]) / v),
* r = (r*B + u[j]) % v;
* We unroll this completely here.
*/
t = v[2]; /* nonzero, by definition */
q1 = u[1] / t;
rbj = COMBINE(u[1] % t, u[2]);
q2 = rbj / t;
rbj = COMBINE(rbj % t, u[3]);
q3 = rbj / t;
rbj = COMBINE(rbj % t, u[4]);
q4 = rbj / t;
if (pRem)
*pRem = rbj % t;
tmp.ul[H] = COMBINE(q1, q2);
tmp.ul[L] = COMBINE(q3, q4);
return tmp.q;
}
}
/*
* By adjusting q once we determine m, we can guarantee that
* there is a complete four-digit quotient at &qspace[1] when
* we finally stop.
*/
for (m = 4 - n; u[1] == 0; u++)
m--;
for (i = 4 - m; --i >= 0;)
q[i] = 0;
q += 4 - m;
/*
* Here we run Program D, translated from MIX to C and acquiring
* a few minor changes.
*
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
*/
d = 0;
for (t = v[1]; t < B / 2; t <<= 1)
d++;
if (d > 0)
{
__shl(u, m + n, d); /* u <<= d */
__shl(v + 1, n - 1, d); /* v <<= d */
}
/*
* D2: j = 0.
*/
j = 0;
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
v2 = v[2]; /* for D3 */
do
{
register DIGIT uj0, uj1, uj2;
/*
* D3: Calculate qhat (\^q, in TeX notation).
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
* let rhat = (u[j]*B + u[j+1]) mod v[1].
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
* decrement qhat and increase rhat correspondingly.
* Note that if rhat >= B, v[2]*qhat < rhat*B.
*/
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
uj1 = u[j + 1]; /* for D3 only */
uj2 = u[j + 2]; /* for D3 only */
if (uj0 == v1)
{
qhat = B;
rhat = uj1;
goto qhat_too_big;
}
else
{
UINT32 nn = COMBINE(uj0, uj1);
qhat = nn / v1;
rhat = nn % v1;
}
while (v2 * qhat > COMBINE(rhat, uj2))
{
qhat_too_big:
qhat--;
if ((rhat += v1) >= B)
break;
}
/*
* D4: Multiply and subtract.
* The variable `t' holds any borrows across the loop.
* We split this up so that we do not require v[0] = 0,
* and to eliminate a final special case.
*/
for (t = 0, i = n; i > 0; i--)
{
t = u[i + j] - v[i] * qhat - t;
u[i + j] = LHALF(t);
t = (B - HHALF(t)) & (B - 1);
}
t = u[j] - t;
u[j] = LHALF(t);
/*
* D5: test remainder.
* There is a borrow if and only if HHALF(t) is nonzero;
* in that (rare) case, qhat was too large (by exactly 1).
* Fix it by adding v[1..n] to u[j..j+n].
*/
if (HHALF(t))
{
qhat--;
for (t = 0, i = n; i > 0; i--)
{ /* D6: add back. */
t += u[i + j] + v[i];
u[i + j] = LHALF(t);
t = HHALF(t);
}
u[j] = LHALF(u[j] + t);
}
q[j] = qhat;
} while (++j <= m); /* D7: loop on j. */
/*
* If caller wants the remainder, we have to calculate it as
* u[m..m+n] >> d (this is at most n digits and thus fits in
* u[m+1..m+n], but we may need more source digits).
*/
if (pRem)
{
if (d)
{
for (i = m + n; i > m; --i)
u[i] = (u[i] >> d) | LHALF(u[i - 1] << (HALF_BITS - d));
u[i] = 0;
}
tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
*pRem = tmp.q;
}
tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
return tmp.q;
}

71
kernel/lib/quad.h Normal file
View File

@@ -0,0 +1,71 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)quad.h 8.1 (Berkeley) 6/4/93
* $FreeBSD$
*/
/* Derived from FreeBDS libkern quad.h, munged by Erbo to COMROGUE standards */
#ifndef QUAD_H_INCLUDED
#define QUAD_H_INCLUDED
#include <comrogue/types.h>
typedef union tagUU {
INT64 q; /* signed quad */
UINT64 uq; /* unsigned quad */
INT32 sl[2]; /* two signed longs */
UINT32 ul[2]; /* two unsigned longs */
} UU;
/* Low word/high word definitions. */
#define L 0
#define H 1
/* Number of bits in a halfword. */
#define HALF_BITS (INT32_BITS / 2)
/*
* Extract high and low shortwords from longword, and move low shortword of
* longword to upper half of long, i.e., produce the upper longword of
* ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
*
* These are used in the multiply code, to split a longword into upper
* and lower halves, and to reassemble a product as a quad_t, shifted left
* (sizeof(long)*CHAR_BIT/2).
*/
#define HHALF(x) ((x) >> HALF_BITS)
#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1))
#define LHUP(x) ((x) << HALF_BITS)
extern UINT64 __qdivrem(UINT64 u, UINT64 v, PUINT64 pRem);
#endif /* QUAD_H_INCLUDED */

519
kernel/lib/rbtree.c Normal file
View File

@@ -0,0 +1,519 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/types.h>
#include <comrogue/internals/rbtree.h>
#include <comrogue/internals/trace.h>
#ifdef THIS_FILE
#undef THIS_FILE
DECLARE_THIS_FILE
#endif
/*------------------------------------------------------------------------------------------------------
* An implementation of left-leaning red-black 2-3 trees as detailed in "Left-leaning Red-Black Trees,"
* Robert Sedgwick, Princeton University, 2008 (http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf).
* See also Java source at https://gist.github.com/741080.
*
* Note that we store the node color as a single bit in the low-order bit of the "right" node pointer.
* This is do-able since, for all cases, pointers to instances of RBTREENODE will be 4-byte aligned.
*------------------------------------------------------------------------------------------------------
*/
/*
* A standard compare-by-value function for tree keys, which compares the numeric values of the keys as
* unsigned integers.
*
* Parameters:
* - k1 = First key value to compare.
* - k2 = Second key value to compare.
*
* Returns:
* 0 if the keys are equal; an integer less than 0 if k1 is less than k2; an integer greater than 0 if
* k1 is greater than k2.
*/
INT32 RbtStdCompareByValue(TREEKEY k1, TREEKEY k2)
{
if (k1 == k2)
return 0;
if (((UINT_PTR)k1) < ((UINT_PTR)k2))
return -1;
return 1;
}
/*
* Rotates a subtree "leftward," so that the root node of the tree is the former root node's right child.
* The new root node inherits the former root node's color, and the former root node turns red.
*
* Parameters:
* - ptn = Pointer to the root node of the subtree.
*
* Returns:
* Pointer to the new root node of the subtree after the rotation.
*/
static PRBTREENODE rotate_left(PRBTREENODE ptn)
{
register PRBTREENODE ptnNewRoot = rbtNodeRight(ptn);
ASSERT(ptnNewRoot);
rbtSetNodeRight(ptn, ptnNewRoot->ptnLeft);
ptnNewRoot->ptnLeft = ptn;
rbtSetNodeColor(ptnNewRoot, rbtNodeColor(ptn));
rbtSetNodeColor(ptn, RED);
return ptnNewRoot;
}
/*
* Rotates a subtree "rightward," so that the root node of the tree is the former root node's left child.
* The new root node inherits the former root node's color, and the former root node turns red.
*
* Parameters:
* - ptn = Pointer to the root node of the subtree.
*
* Returns:
* Pointer to the new root node of the subtree after the rotation.
*/
static PRBTREENODE rotate_right(PRBTREENODE ptn)
{
register PRBTREENODE ptnNewRoot = ptn->ptnLeft;
ASSERT(ptnNewRoot);
ptn->ptnLeft = rbtNodeRight(ptnNewRoot);
rbtSetNodeRight(ptnNewRoot, ptn);
rbtSetNodeColor(ptnNewRoot, rbtNodeColor(ptn));
rbtSetNodeColor(ptn, RED);
return ptnNewRoot;
}
/*
* Flips the color of the specified node and both its immediate children.
*
* Parameters:
* - ptn = Pointer to the node to be color-flipped.
*
* Returns:
* Nothing.
*/
static void color_flip(PRBTREENODE ptn)
{
rbtToggleColor(ptn);
rbtToggleColor(ptn->ptnLeft);
rbtToggleColor(rbtNodeRight(ptn));
}
/*
* Fixes up the given subtree after an insertion or deletion, to ensure that it maintains the invariants
* that no two consecutive links in the tree may be red, and that all red links must lean left.
*
* Parameters:
* - ptn = Pointer to the root node of the subtree to be fixed up.
*
* Returns:
* Pointer to the new root node of the subtree after fixup is performed.
*/
static PRBTREENODE fix_up(PRBTREENODE ptn)
{
if (rbtIsRed(rbtNodeRight(ptn)) && !rbtIsRed(ptn->ptnLeft))
ptn = rotate_left(ptn);
if (rbtIsRed(ptn->ptnLeft) && rbtIsRed(ptn->ptnLeft->ptnLeft))
ptn = rotate_right(ptn);
if (rbtIsRed(ptn->ptnLeft) && rbtIsRed(rbtNodeRight(ptn)))
color_flip(ptn);
return ptn;
}
/*
* Inserts a new node under the current subtree. An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure, containing the compare function.
* - ptnCurrent = Pointer to the current subtree we're inserting into.
* - ptnNew = Pointer to the new tree node to be inserted. This node must have been initialized with
* the rbtInitNode macro to contain a key, NULL left and right pointers, and be red. It is
* assumed that the node's key does NOT already exist in the tree.
*
* Returns:
* The pointer to the new subtree after the insertion is performed.
*
* N.B.:
* This function is recursive; however, the nature of the tree guarantees that the stack space consumed
* by its stack frames will be O(log n).
*/
static PRBTREENODE insert_under(PRBTREE ptree, PRBTREENODE ptnCurrent, PRBTREENODE ptnNew)
{
register int cmp; /* compare result */
if (!ptnCurrent)
return ptnNew; /* degenerate case */
cmp = (*(ptree->pfnTreeCompare))(ptnNew->treekey, ptnCurrent->treekey);
ASSERT(cmp != 0);
if (cmp < 0)
ptnCurrent->ptnLeft = insert_under(ptree, ptnCurrent->ptnLeft, ptnNew);
else
rbtSetNodeRight(ptnCurrent, insert_under(ptree, rbtNodeRight(ptnCurrent), ptnNew));
return fix_up(ptnCurrent);
}
/*
* Inserts a new node into the tree. An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - ptnNew = Pointer to the new tree node to be inserted. This node must have been initialized with
* the rbtInitNode macro to contain a key, NULL left and right pointers, and be red. It is
* assumed that the node's key does NOT already exist in the tree.
*
* Returns:
* Nothing.
*/
void RbtInsert(PRBTREE ptree, PRBTREENODE ptnNew)
{
ptree->ptnRoot = insert_under(ptree, ptree->ptnRoot, ptnNew);
rbtSetNodeColor(ptree->ptnRoot, BLACK);
}
/*
* Locates a node in the tree by key. An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - key = Key value to be looked up.
*
* Returns:
* Pointer to the node where the key is found, or NULL if not found.
*/
PRBTREENODE RbtFind(PRBTREE ptree, TREEKEY key)
{
register PRBTREENODE ptn = ptree->ptnRoot; /* current node */
register int cmp; /* compare result */
while (ptn)
{
cmp = (*(ptree->pfnTreeCompare))(key, ptn->treekey);
if (cmp == 0)
break; /* found */
else if (cmp < 0)
ptn = ptn->ptnLeft;
else
ptn = rbtNodeRight(ptn);
}
return ptn;
}
/*
* Given a key, returns either the node that matches the key, if the key is in the tree, or the node
* that has a key that most immediately precedes the supplied key. An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - key = Key value to be looked up.
*
* Returns:
* Pointer to the node where the key is found, or pointer to the predecessor node, or NULL if the key
* is less than every key in the tree and hence has no predecessor.
*/
PRBTREENODE RbtFindPredecessor(PRBTREE ptree, TREEKEY key)
{
register PRBTREENODE ptn = ptree->ptnRoot; /* current node */
register int cmp; /* compare result */
while (ptn)
{
cmp = (*(ptree->pfnTreeCompare))(key, ptn->treekey);
if (cmp == 0)
break; /* found */
else if (cmp > 0)
{
if (rbtNodeRight(ptn))
ptn = rbtNodeRight(ptn);
else
break; /* found predecessor */
}
else
ptn = ptn->ptnLeft;
}
return ptn;
}
/*
* Given a key, returns either the node that matches the key, if the key is in the tree, or the node
* that has a key that most immediately succeeds the supplied key. An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - key = Key value to be looked up.
*
* Returns:
* Pointer to the node where the key is found, or pointer to the successor node, or NULL if the key
* is greater than every key in the tree and hence has no successor.
*/
PRBTREENODE RbtFindSuccessor(PRBTREE ptree, TREEKEY key)
{
register PRBTREENODE ptn = ptree->ptnRoot; /* current node */
register int cmp; /* compare result */
while (ptn)
{
cmp = (*(ptree->pfnTreeCompare))(key, ptn->treekey);
if (cmp == 0)
break; /* found */
else if (cmp < 0)
{
if (ptn->ptnLeft)
ptn = ptn->ptnLeft;
else
break; /* found successor */
}
else
ptn = rbtNodeRight(ptn);
}
return ptn;
}
/*
* Finds the "minimum" node in the subtree (the one at the bottom end of the left spine of the subtree).
*
* Parameters:
* - ptn = Pointer to the subtree to be searched.
*
* Returns:
* Pointer to the leftmost node in the subtree.
*/
static PRBTREENODE find_min(PRBTREENODE ptn)
{
while (ptn->ptnLeft)
ptn = ptn->ptnLeft;
return ptn;
}
/*
* Finds the "minimum" node in the tree (the one at the bottom end of the left spine of the tree).
*
* Parameters:
* - ptree = Pointer to the tree head structure.
*
* Returns:
* Pointer to the leftmost node in the tree. If the tree has no nodes, NULL is returned.
*/
PRBTREENODE RbtFindMin(PRBTREE ptree)
{
return ptree->ptnRoot ? find_min(ptree->ptnRoot) : NULL;
}
/*
* Fixup required to delete the leftmost node; we maintain the invariant that either the current node
* or its left child is red. After a color flip, we resolve any successive reds on the right with rotations
* and another color flip.
*
* Parameters:
* - ptn = Pointer to root of subtree to be fixed up.
*
* Returns:
* Pointer to root of subtree after fixup.
*/
static PRBTREENODE move_red_left(PRBTREENODE ptn)
{
color_flip(ptn);
if (rbtNodeRight(ptn) && rbtIsRed(rbtNodeRight(ptn)->ptnLeft))
{
rbtSetNodeRight(ptn, rotate_right(rbtNodeRight(ptn)));
ptn = rotate_left(ptn);
color_flip(ptn);
}
return ptn;
}
/*
* Fixup required to delete an internal node, rotating left-leaning red links to the right.
*
* Parameters:
* - ptn = Pointer to root of subtree to be fixed up.
*
* Returns:
* Pointer to root of subtree after fixup.
*/
static PRBTREENODE move_red_right(PRBTREENODE ptn)
{
color_flip(ptn);
if (ptn->ptnLeft && rbtIsRed(ptn->ptnLeft->ptnLeft))
{
ptn = rotate_right(ptn);
color_flip(ptn);
}
return ptn;
}
/*
* Deletes the leftmost node in the subtree. (Note that "deletes" means "removes from the tree." No memory
* delete operation is actually performed.)
*
* Parameters:
* - ptn = Pointer to root of subtree to have its leftmost node deleted.
*
* Returns:
* Pointer to root of subtree after having the leftmost node deleted.
*
* N.B.:
* This function is recursive; however, the nature of the tree guarantees that the stack space consumed
* by its stack frames will be O(log n).
*/
static PRBTREENODE delete_min(PRBTREENODE ptn)
{
if (!(ptn->ptnLeft))
return rbtNodeRight(ptn);
if (!rbtIsRed(ptn->ptnLeft) && !rbtIsRed(ptn->ptnLeft->ptnLeft))
ptn = move_red_left(ptn);
ptn->ptnLeft = delete_min(ptn->ptnLeft);
return fix_up(ptn);
}
/*
* Deletes the node in the subtree having an arbitrary key. (Note that "deletes" means "removes from the tree."
* No memory delete operation is actually performed.) An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure, containing the compare function.
* - ptnCurrent = Pointer to the root of the current subtree we're deleting from.
* - key = Key value we're deleting from the tree. It is assumed that this key value exists in the subtree.
*
* Returns:
* Pointer to the root of the subtree after the node has been deleted.
*
* N.B.:
* This function is recursive; however, the nature of the tree guarantees that the stack space consumed
* by its stack frames (and those of delete_min, where we call it) will be O(log n).
*/
static PRBTREENODE delete_from_under(PRBTREE ptree, PRBTREENODE ptnCurrent, TREEKEY key)
{
register int cmp = (*(ptree->pfnTreeCompare))(key, ptnCurrent->treekey);
if (cmp < 0)
{
/* hunt down the left subtree */
if (!rbtIsRed(ptnCurrent->ptnLeft) && !rbtIsRed(ptnCurrent->ptnLeft->ptnLeft))
ptnCurrent = move_red_left(ptnCurrent);
ptnCurrent->ptnLeft = delete_from_under(ptree, ptnCurrent->ptnLeft, key);
}
else
{
if (rbtIsRed(ptnCurrent->ptnLeft))
{
ptnCurrent = rotate_right(ptnCurrent);
cmp = (*(ptree->pfnTreeCompare))(key, ptnCurrent->treekey);
}
if ((cmp == 0) && !rbtNodeRight(ptnCurrent))
return ptnCurrent->ptnLeft; /* degenerate case */
if ( !rbtIsRed(rbtNodeRight(ptnCurrent))
&& (!rbtNodeRight(ptnCurrent) || !rbtIsRed(rbtNodeRight(ptnCurrent)->ptnLeft)))
{
ptnCurrent = move_red_right(ptnCurrent);
cmp = (*(ptree->pfnTreeCompare))(key, ptnCurrent->treekey);
}
if (cmp == 0)
{
/*
* Here we find the minimum node in the right subtree, unlink it, and link it into place in place of
* ptnCurrent (i.e. node pointed to by ptnCurrent should no longer be referenced). We inherit the
* child pointers and color of ptnCurrent (minus the reference from the right-hand tree where applicable).
*/
register PRBTREENODE ptnMin = find_min(rbtNodeRight(ptnCurrent));
rbtSetNodeRight(ptnMin, delete_min(rbtNodeRight(ptnCurrent)));
ptnMin->ptnLeft = ptnCurrent->ptnLeft;
rbtSetNodeColor(ptnMin, rbtNodeColor(ptnCurrent));
ptnCurrent = ptnMin;
}
else /* hunt down the right subtree */
rbtSetNodeRight(ptnCurrent, delete_from_under(ptree, rbtNodeRight(ptnCurrent), key));
}
return fix_up(ptnCurrent);
}
/*
* Deletes the node in the tree having an arbitrary key. (Note that "deletes" means "removes from the tree."
* No memory delete operation is actually performed.) An O(log n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - key = Key value we're deleting from the tree. It is assumed that this key value exists in the subtree.
*
* Returns:
* Nothing.
*/
void RbtDelete(PRBTREE ptree, TREEKEY key)
{
ptree->ptnRoot = delete_from_under(ptree, ptree->ptnRoot, key);
if (ptree->ptnRoot)
rbtSetNodeColor(ptree->ptnRoot, BLACK);
}
/*
* Performs an inorder traversal of the tree rooted at the specified node. An O(n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - ptn = Pointer to the root of the current tree node.
* - pfnWalk = Pointer to a function called for each tree node we encounter. This function returns TRUE
* to continue the traversal or FALSE to stop it.
* - pData = Arbitrary data pointer that gets passed to the pfnWalk function.
*
* Returns:
* TRUE if the tree was entirely traversed, FALSE if the tree walk was interrupted.
*
* N.B.:
* This function is recursive; however, the nature of the tree guarantees that the stack space consumed
* by its stack frames will be O(log n).
*/
static BOOL do_walk(PRBTREE ptree, PRBTREENODE ptn, PFNRBTWALK pfnWalk, PVOID pData)
{
register BOOL rc = TRUE;
if (ptn->ptnLeft)
rc = do_walk(ptree, ptn->ptnLeft, pfnWalk, pData);
if (rc)
rc = (*pfnWalk)(ptree, ptn, pData);
if (rc && rbtNodeRight(ptn))
rc = do_walk(ptree, rbtNodeRight(ptn), pfnWalk, pData);
return rc;
}
/*
* Performs an inorder traversal of the tree. An O(n) operation.
*
* Parameters:
* - ptree = Pointer to the tree head structure.
* - pfnWalk = Pointer to a function called for each tree node we encounter. This function returns TRUE
* to continue the traversal or FALSE to stop it.
* - pData = Arbitrary data pointer that gets passed to the pfnWalk function.
*
* Returns:
* TRUE if the tree was entirely traversed, FALSE if the tree walk was interrupted.
*/
BOOL RbtWalk(PRBTREE ptree, PFNRBTWALK pfnWalk, PVOID pData)
{
return (ptree->ptnRoot ? do_walk(ptree, ptree->ptnRoot, pfnWalk, pData) : TRUE);
}

422
kernel/lib/str.c Normal file
View File

@@ -0,0 +1,422 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/intlib.h>
#include <comrogue/str.h>
#include <comrogue/internals/seg.h>
/*-------------------------
* Basic string operations
*-------------------------
*/
/*
* Returns whether or not the character is a digit (0-9).
*
* Parameters:
* - ch = Character to be tested.
*
* Returns:
* TRUE if the character is a digit, FALSE otherwise.
*/
BOOL StrIsDigit8(CHAR ch)
{
/* TODO: replace with something nicer later */
return MAKEBOOL((ch >= '0') && (ch <= '9'));
}
/*
* Returns the length of a null-terminated string.
*
* Parameters:
* - psz = The string to get the length of.
*
* Returns:
* The length of the string in characters.
*/
INT32 StrLength8(PCSTR psz)
{
register PCSTR p = psz;
while (*p)
p++;
return (INT32)(p - psz);
}
/*
* Locates a character within a null-terminated string.
*
* Parameters:
* - psz = String to search through for character.
* - ch = Character to look for.
*
* Returns:
* NULL if character was not found, otherwise pointer to character within string.
*/
PCHAR StrChar8(PCSTR psz, INT32 ch)
{
const CHAR mych = ch;
for (; *psz; psz++)
if (*psz == mych)
return (PCHAR)psz;
return NULL;
}
/*-------------------------------
* Numeric-to-string conversions
*-------------------------------
*/
/*
* Formats an unsigned numeric value into a buffer. This function formats the value into the END of the
* buffer and returns a pointer to the first character of the number. Note that the string-converted number
* is NOT null-terminated!
*
* Parameters:
* - value = The value to be converted.
* - pchBuf = Pointer to the buffer in which to store the converted value.
* - nBytes = Number of characters in the buffer.
* - nBase = The numeric base to use to output the number. Valid values are in the interval [2,36].
* - fUppercase = TRUE to use upper-case letters as digits in output, FALSE to use lower-case letters.
*
* Returns:
* A pointer to the first digit of the converted value, which will be somewhere in the interval
* [pchBuf, pchBuf + nBytes).
*/
static PCHAR convert_number_engine8(UINT64 value, PCHAR pchBuf, INT32 nBytes, INT32 nBase, BOOL fUppercase)
{
static DECLARE_STRING8_CONST(szDigitsUppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
static DECLARE_STRING8_CONST(szDigitsLowercase, "0123456789abcdefghijklmnopqrstuvwxyz");
PCSTR pszDigits = (fUppercase ? szDigitsUppercase : szDigitsLowercase); /* digit set to use */
PCHAR p = pchBuf + nBytes; /* output pointer */
INT64 accumulator; /* accumulator of quotients */
LDIV ldiv; /* buffer for division */
/* do initial division to get rid of high-order bit & handle 0 */
*--p = pszDigits[value % nBase];
accumulator = (INT64)(value / nBase);
while ((p > pchBuf) && (accumulator > 0))
{ /* output digits */
IntLDiv(&ldiv, accumulator, nBase);
*--p = pszDigits[ldiv.rem];
accumulator = ldiv.quot;
}
return p;
}
/*-----------------------------------------
* StrFormatV8 and its support definitions
*-----------------------------------------
*/
/* Flag values for conversion characters */
#define FLAG_LEFTJUST 0x01 /* left-justify output field */
#define FLAG_PLUSSIGN 0x02 /* use a '+' for the sign if >= 0 */
#define FLAG_SPACESIGN 0x04 /* use a space for the sign if >= 0 */
#define FLAG_ALTMODE 0x08 /* alternate conversion mode */
#define FLAG_ZEROPAD 0x10 /* zero-pad to width */
/* Macro that calls the output function and either updates total output or exits */
#define do_output(pBuf, nChr) \
do { if ((nChr) > 0) { if (SUCCEEDED((*pfnFormat)(&pArg, (pBuf), (nChr)))) nTotalOutput += (nChr); \
else { errorFlag = SEVERITY_ERROR; goto error; } } } while (0)
/* Strings used for padding */
static DECLARE_STRING8_CONST(szPadSpace, " ");
static DECLARE_STRING8_CONST(szPadZero, "0000000000000000000000000000000000000000000000000000000000");
#define PAD_SIZE (sizeof(szPadSpace) - 1) /* number of characters available in pad string */
/* Macro that outputs characters for padding */
#define do_pad_output(szPad, nChr) \
do { int n, nt = (nChr); while (nt > 0) { n = intMin(nt, PAD_SIZE); do_output(szPad, n); nt -= n; } } while (0)
#define MAX_VAL 509 /* maximum field value for conversion */
#define BUFSIZE 64 /* buffer size on stack for conversion */
#define NUM_CONVERT_BYTES 32 /* maximum number of bytes for converting a numeric value */
/*
* Format a series of arguments like "printf," calling a function to perform the actual character output.
*
* Parameters:
* - pfnFormat = Pointer to the format function
* - pArg = Pointer argument passed to the format function, which may modify it
* - pszFormat = Format string, like a printf format string.
* - pargs = Pointer to varargs-style function arguments.
*
* Returns:
* A HRESULT as follows: Severity indicates whether the output function failed or succeeded, facility is always
* FACILITY_STRFORMAT, code indicates the number of characters output.
*
* Notes:
* Floating-point conversion formats are not supported at this time.
*/
HRESULT StrFormatV8(PFNFORMAT8 pfnFormat, PVOID pArg, PCSTR pszFormat, va_list pargs)
{
static DECLARE_STRING8_CONST(szFlagChars, "0+- #"); /* flag characters and values */
static const UINT32 SEG_RODATA auiFlagValues[] =
{ FLAG_ZEROPAD, FLAG_LEFTJUST, FLAG_PLUSSIGN, FLAG_SPACESIGN, FLAG_ALTMODE, 0 };
static DECLARE_STRING8_CONST(szConversionChars, "hl"); /* conversion characters */
PCSTR p; /* pointer used to walk the format string */
PCHAR pFlag; /* pointer to flag character/temp buffer pointer */
PCHAR pchOutput; /* pointer to characters actually output */
INT32 nchOutput; /* number of characters output */
PCHAR pchPrefix; /* pointer to prefix characters */
INT32 nchPrefix; /* number of prefix characters */
INT32 nchZeroPrefix; /* number of zeroes to write as a prefix */
INT32 nTotalOutput = 0; /* total number of characters output */
UINT32 errorFlag = SEVERITY_SUCCESS; /* error flag to return */
UINT32 flags; /* conversion flags seen */
INT32 ncWidth; /* width for field */
INT32 ncPrecision; /* precision for field */
INT32 nBase; /* numeric base for field */
INT64 input; /* input integer value */
CHAR chConvert; /* conversion character for field */
CHAR achBuffer[BUFSIZE]; /* buffer into which output is formatted */
while (*pszFormat)
{
/* locate all plain characters up to next % or end of string and output them */
p = pszFormat;
while (*p && (*p != '%'))
p++;
do_output(pszFormat, p - pszFormat);
if (*p == '%')
{
flags = 0; /* convert flags first */
for (p++; (pFlag = StrChar8(szFlagChars, *p)) != NULL; p++)
flags |= auiFlagValues[pFlag - szFlagChars];
ncWidth = 0; /* now convert width */
if (*p == '*')
{
ncWidth = va_arg(pargs, INT32); /* specified by arg */
p++;
if (ncWidth < 0)
{
flags |= FLAG_LEFTJUST; /* negative width is taken as use of - flag */
ncWidth = -ncWidth;
}
}
else
{
while (StrIsDigit8(*p))
ncWidth = ncWidth * 10 + (*p++ - '0');
}
if (ncWidth > MAX_VAL)
ncWidth = MAX_VAL;
ncPrecision = -1; /* now convert precision */
if (*p == '.')
{
p++;
if (*p == '*')
{
ncPrecision = va_arg(pargs, INT32); /* specified by arg */
p++;
/* N.B. ncPrecision < 0 = "omitted precision" */
}
else
{
ncPrecision = 0;
while (StrIsDigit8(*p))
ncPrecision = ncPrecision * 10 + (*p++ - '0');
}
if (ncPrecision > MAX_VAL)
ncPrecision = MAX_VAL;
}
chConvert = StrChar8(szConversionChars, *p) ? *p++ : '\0'; /* get conversion character */
/* based on field character, convert the field */
pchOutput = achBuffer;
nchOutput = 0;
pchPrefix = NULL;
nchPrefix = 0;
nchZeroPrefix = 0;
switch (*p)
{
case 'c': /* output a character */
achBuffer[nchOutput++] = (CHAR)va_arg(pargs, INT32);
break;
case 'd':
case 'i': /* output a decimal number */
if (ncPrecision < 0)
ncPrecision = 1; /* default precision is 1 */
if (chConvert == 'h')
input = va_arg(pargs, INT32);
else if (chConvert == '\0')
input = va_arg(pargs, INT32);
else
input = va_arg(pargs, INT64);
if ((input == 0) && (ncPrecision == 0))
break; /* no output */
if (input < 0)
{
achBuffer[nchPrefix++] = '-'; /* minus sign */
input = -input;
}
else
{
/* plus or space for sign if flags dictate */
if (flags & FLAG_PLUSSIGN)
achBuffer[nchPrefix++] = '+';
else if (flags & FLAG_SPACESIGN)
achBuffer[nchPrefix++] = ' ';
}
if (nchPrefix > 0)
{
pchPrefix = achBuffer; /* adjust output pointer and set prefix */
pchOutput = achBuffer + nchPrefix;
}
/* clamp input value and run it through number conversion engine */
if (chConvert == 'h')
input &= UINT16_MAX;
else if (chConvert == '\0')
input &= UINT32_MAX;
pFlag = pchOutput;
pchOutput = convert_number_engine8((UINT64)input, pFlag, NUM_CONVERT_BYTES, 10, FALSE);
nchOutput = (pFlag + NUM_CONVERT_BYTES) - pchOutput;
/* calculate zero prefix based on precision */
if ((flags & (FLAG_ZEROPAD|FLAG_LEFTJUST)) == FLAG_ZEROPAD)
nchZeroPrefix = intMax(0, ncWidth - (nchPrefix + nchOutput));
else if (ncPrecision > 0)
nchZeroPrefix = intMax(0, ncPrecision - nchOutput);
break;
case 'o':
case 'u':
case 'x':
case 'X': /* output an unsigned number */
if (ncPrecision < 0)
ncPrecision = 1; /* defualt precision is 1 */
if (chConvert == 'h')
input = va_arg(pargs, UINT32);
else if (chConvert == '\0')
input = va_arg(pargs, UINT32);
else
input = (INT64)va_arg(pargs, UINT64);
if ((input == 0) && (ncPrecision == 0))
break; /* no output */
/* select numeric base of output */
if (*p == 'o')
nBase = 8;
else if (*p == 'u')
nBase = 10;
else
nBase = 16;
if (flags & FLAG_ALTMODE)
{
if (*p == 'o')
{ /* forced octal notation */
achBuffer[nchPrefix++] = '0';
ncPrecision--;
}
else if (*p != 'u')
{ /* forced hexadecimal notation */
achBuffer[nchPrefix++] = '0';
achBuffer[nchPrefix++] = *p;
}
}
if (nchPrefix > 0)
{
pchPrefix = achBuffer; /* adjust output pointer and set prefix */
pchOutput = achBuffer + nchPrefix;
}
/* clamp input value and run it through number conversion engine */
if (chConvert == 'h')
input &= UINT16_MAX;
else if (chConvert == '\0')
input &= UINT32_MAX;
pFlag = pchOutput;
pchOutput = convert_number_engine8((UINT64)input, pFlag, NUM_CONVERT_BYTES, nBase, MAKEBOOL(*p == 'X'));
nchOutput = (pFlag + NUM_CONVERT_BYTES) - pchOutput;
/* calculate zero prefix based on precision */
if ((flags & (FLAG_ZEROPAD|FLAG_LEFTJUST)) == FLAG_ZEROPAD)
nchZeroPrefix = intMax(0, ncWidth - (nchPrefix + nchOutput));
else if (ncPrecision > 0)
nchZeroPrefix = intMax(0, ncPrecision - nchOutput);
break;
case 'p': /* output a pointer value - treated as unsigned hex with precision of 8 */
input = (INT_PTR)va_arg(pargs, PVOID);
input &= UINT_PTR_MAX;
pFlag = pchOutput;
pchOutput = convert_number_engine8((UINT64)input, pFlag, NUM_CONVERT_BYTES, 16, FALSE);
nchOutput = (pFlag + NUM_CONVERT_BYTES) - pchOutput;
nchZeroPrefix = intMax(0, (sizeof(UINT_PTR) / sizeof(CHAR) * 2) - nchOutput);
break;
case 's': /* output a string */
pchOutput = (PCHAR)va_arg(pargs, PCSTR);
nchOutput = StrLength8(pchOutput);
if ((ncPrecision >= 0) && (ncPrecision < nchOutput))
nchOutput = ncPrecision;
break;
case 'n': /* output nothing, just store number of characters output so far */
*(va_arg(pargs, PINT32)) = nTotalOutput;
goto no_output;
case '%': /* output a single % sign */
default: /* unrecognized format character, output it and continue */
achBuffer[nchOutput++] = *p;
break;
}
ncWidth -= (nchPrefix + nchZeroPrefix + nchOutput);
if (!(flags & FLAG_LEFTJUST))
do_pad_output(szPadSpace, ncWidth);
do_output(pchPrefix, nchPrefix);
do_pad_output(szPadZero, nchZeroPrefix);
do_output(pchOutput, nchOutput);
if (flags & FLAG_LEFTJUST)
do_pad_output(szPadSpace, ncWidth);
no_output:
p++;
}
pszFormat = p;
}
error:
return MAKE_SCODE(errorFlag, FACILITY_STRFORMAT, nTotalOutput);
}

185
kernel/lib/strcomparemem.S Normal file
View File

@@ -0,0 +1,185 @@
/*
* Copyright 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2002 ARM Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the company may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Taken from FreeBSD memcmp.S, munged by Erbo to COMROGUE standards */
/* Func: INT32 StrCompareMem(PCVOID pMem1, PCVOID pMem2, SSIZE_T cb); */
/*
* Compares two memory blocks as bytes, returning a value for comparison between the two.
*
* Parameters:
* - pMem1 = First block of memory to compare.
* - pMem2 = Second block of memory to compare.
* - cb = Size of the two memory blocks in bytes.
*
* Returns:
* 0 if the two memory blocks are the same; a value less than 0 if the memory block pointed to by pMem1 is
* less than the one pointed to by pMem2; a value greater than 0 if the memory block pointed to by pMem1 is
* greater than the one pointed to by pMem2.
*/
.globl StrCompareMem
StrCompareMem:
mov ip, r0
cmp r2, #0x06 /* optimized version for 6-byte compares */
beq .Lmemcmp_6bytes
mov r0, #0x00
/* Are both addresses aligned the same way? */
cmp r2, #0x00
eornes r3, ip, r1
bxeq lr /* len == 0, or same addresses! */
tst r3, #0x03
subne r2, r2, #0x01
bne .Lmemcmp_bytewise2 /* Badly aligned. Do it the slow way */
/* Word-align the addresses, if necessary */
sub r3, r1, #0x05
ands r3, r3, #0x03
add r3, r3, r3, lsl #1
addne pc, pc, r3, lsl #3
nop
/* Compare up to 3 bytes */
ldrb r0, [ip], #0x01
ldrb r3, [r1], #0x01
subs r0, r0, r3
bxne lr
subs r2, r2, #0x01
bxeq lr
/* Compare up to 2 bytes */
ldrb r0, [ip], #0x01
ldrb r3, [r1], #0x01
subs r0, r0, r3
bxne lr
subs r2, r2, #0x01
bxeq lr
/* Compare 1 byte */
ldrb r0, [ip], #0x01
ldrb r3, [r1], #0x01
subs r0, r0, r3
bxne lr
subs r2, r2, #0x01
bxeq lr
/* Compare 4 bytes at a time, if possible */
subs r2, r2, #0x04
bcc .Lmemcmp_bytewise
.Lmemcmp_word_aligned:
ldr r0, [ip], #0x04
ldr r3, [r1], #0x04
subs r2, r2, #0x04
cmpcs r0, r3
beq .Lmemcmp_word_aligned
sub r0, r0, r3
/* Correct for extra subtraction, and check if done */
adds r2, r2, #0x04
cmpeq r0, #0x00 /* If done, did all bytes match? */
bxeq lr /* Yup. Just return */
/* Re-do the final word byte-wise */
sub ip, ip, #0x04
sub r1, r1, #0x04
.Lmemcmp_bytewise:
add r2, r2, #0x03
.Lmemcmp_bytewise2:
ldrb r0, [ip], #0x01
ldrb r3, [r1], #0x01
subs r2, r2, #0x01
cmpcs r0, r3
beq .Lmemcmp_bytewise2
sub r0, r0, r3
bx lr
/*
* 6 byte compares are very common, thanks to the network stack.
* This code is hand-scheduled to reduce the number of stalls for
* load results. Everything else being equal, this will be ~32%
* faster than a byte-wise memcmp.
*/
.align 5
.Lmemcmp_6bytes:
ldrb r3, [r1, #0x00] /* r3 = b2#0 */
ldrb r0, [ip, #0x00] /* r0 = b1#0 */
ldrb r2, [r1, #0x01] /* r2 = b2#1 */
subs r0, r0, r3 /* r0 = b1#0 - b2#0 */
ldreqb r3, [ip, #0x01] /* r3 = b1#1 */
bxne lr /* Return if mismatch on #0 */
subs r0, r3, r2 /* r0 = b1#1 - b2#1 */
ldreqb r3, [r1, #0x02] /* r3 = b2#2 */
ldreqb r0, [ip, #0x02] /* r0 = b1#2 */
bxne lr /* Return if mismatch on #1 */
ldrb r2, [r1, #0x03] /* r2 = b2#3 */
subs r0, r0, r3 /* r0 = b1#2 - b2#2 */
ldreqb r3, [ip, #0x03] /* r3 = b1#3 */
bxne lr /* Return if mismatch on #2 */
subs r0, r3, r2 /* r0 = b1#3 - b2#3 */
ldreqb r3, [r1, #0x04] /* r3 = b2#4 */
ldreqb r0, [ip, #0x04] /* r0 = b1#4 */
bxne lr /* Return if mismatch on #3 */
ldrb r2, [r1, #0x05] /* r2 = b2#5 */
subs r0, r0, r3 /* r0 = b1#4 - b2#4 */
ldreqb r3, [ip, #0x05] /* r3 = b1#5 */
bxne lr /* Return if mismatch on #4 */
sub r0, r3, r2 /* r0 = b1#5 - b2#5 */
bx lr

271
kernel/lib/strcopymem.S Normal file
View File

@@ -0,0 +1,271 @@
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Taken from FreeBSD memcpy_arm.S, munged by Erbo to COMROGUE standards */
/*
* This is one fun bit of code ...
* Some easy listening music is suggested while trying to understand this
* code e.g. Iron Maiden
*
* For anyone attempting to understand it :
*
* The core code is implemented here with simple stubs for memcpy().
*
* All local labels are prefixed with Lmemcpy_
* Following the prefix a label starting f is used in the forward copy code
* while a label using b is used in the backwards copy code
* The source and destination addresses determine whether a forward or
* backward copy is performed.
* Separate bits of code are used to deal with the following situations
* for both the forward and backwards copy.
* unaligned source address
* unaligned destination address
* Separate copy routines are used to produce an optimised result for each
* of these cases.
* The copy code will use LDM/STM instructions to copy up to 32 bytes at
* a time where possible.
*
* Note: r12 (aka ip) can be trashed during the function along with
* r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
* Additional registers are preserved prior to use i.e. r4, r5 & lr
*
* Apologies for the state of the comments ;-)
*/
/* Func: PVOID StrCopyMem(PVOID pDest, PCVOID pSrc, SSIZE_T cb); */
/*
* Copies memory data from one block of memory to another. Assumes the memory blocks do NOT overlap.
*
* Parameters:
* - pDest = Destination for the copy operation.
* - pSrc = Source for the copy operation.
* - cb = Number of bytes to be copied.
*
* Returns:
* pDest.
*/
.globl StrCopyMem
StrCopyMem:
/* save leaf functions having to store this away */
stmdb sp!, {r0, lr} /* memcpy() returns dest addr */
subs r2, r2, #4
blt .Lmemcpy_l4 /* less than 4 bytes */
ands r12, r0, #3
bne .Lmemcpy_destul /* oh unaligned destination addr */
ands r12, r1, #3
bne .Lmemcpy_srcul /* oh unaligned source addr */
.Lmemcpy_t8:
/* We have aligned source and destination */
subs r2, r2, #8
blt .Lmemcpy_l12 /* less than 12 bytes (4 from above) */
subs r2, r2, #0x14
blt .Lmemcpy_l32 /* less than 32 bytes (12 from above) */
stmdb sp!, {r4} /* borrow r4 */
/* blat 32 bytes at a time */
/* XXX for really big copies perhaps we should use more registers */
.Lmemcpy_loop32:
ldmia r1!, {r3, r4, r12, lr}
stmia r0!, {r3, r4, r12, lr}
ldmia r1!, {r3, r4, r12, lr}
stmia r0!, {r3, r4, r12, lr}
subs r2, r2, #0x20
bge .Lmemcpy_loop32
cmn r2, #0x10
ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
stmgeia r0!, {r3, r4, r12, lr}
subge r2, r2, #0x10
ldmia sp!, {r4} /* return r4 */
.Lmemcpy_l32:
adds r2, r2, #0x14
/* blat 12 bytes at a time */
.Lmemcpy_loop12:
ldmgeia r1!, {r3, r12, lr}
stmgeia r0!, {r3, r12, lr}
subges r2, r2, #0x0c
bge .Lmemcpy_loop12
.Lmemcpy_l12:
adds r2, r2, #8
blt .Lmemcpy_l4
subs r2, r2, #4
ldrlt r3, [r1], #4
strlt r3, [r0], #4
ldmgeia r1!, {r3, r12}
stmgeia r0!, {r3, r12}
subge r2, r2, #4
.Lmemcpy_l4:
/* less than 4 bytes to go */
adds r2, r2, #4
ldmeqia sp!, {r0, pc} /* done */
/* copy the crud byte at a time */
cmp r2, #2
ldrb r3, [r1], #1
strb r3, [r0], #1
ldrgeb r3, [r1], #1
strgeb r3, [r0], #1
ldrgtb r3, [r1], #1
strgtb r3, [r0], #1
ldmia sp!, {r0, pc}
/* erg - unaligned destination */
.Lmemcpy_destul:
rsb r12, r12, #4
cmp r12, #2
/* align destination with byte copies */
ldrb r3, [r1], #1
strb r3, [r0], #1
ldrgeb r3, [r1], #1
strgeb r3, [r0], #1
ldrgtb r3, [r1], #1
strgtb r3, [r0], #1
subs r2, r2, r12
blt .Lmemcpy_l4 /* less the 4 bytes */
ands r12, r1, #3
beq .Lmemcpy_t8 /* we have an aligned source */
/* erg - unaligned source */
/* This is where it gets nasty ... */
.Lmemcpy_srcul:
bic r1, r1, #3
ldr lr, [r1], #4
cmp r12, #2
bgt .Lmemcpy_srcul3
beq .Lmemcpy_srcul2
cmp r2, #0x0c
blt .Lmemcpy_srcul1loop4
sub r2, r2, #0x0c
stmdb sp!, {r4, r5}
.Lmemcpy_srcul1loop16:
mov r3, lr, lsr #8
ldmia r1!, {r4, r5, r12, lr}
orr r3, r3, r4, lsl #24
mov r4, r4, lsr #8
orr r4, r4, r5, lsl #24
mov r5, r5, lsr #8
orr r5, r5, r12, lsl #24
mov r12, r12, lsr #8
orr r12, r12, lr, lsl #24
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul1loop16
ldmia sp!, {r4, r5}
adds r2, r2, #0x0c
blt .Lmemcpy_srcul1l4
.Lmemcpy_srcul1loop4:
mov r12, lr, lsr #8
ldr lr, [r1], #4
orr r12, r12, lr, lsl #24
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul1loop4
.Lmemcpy_srcul1l4:
sub r1, r1, #3
b .Lmemcpy_l4
.Lmemcpy_srcul2:
cmp r2, #0x0c
blt .Lmemcpy_srcul2loop4
sub r2, r2, #0x0c
stmdb sp!, {r4, r5}
.Lmemcpy_srcul2loop16:
mov r3, lr, lsr #16
ldmia r1!, {r4, r5, r12, lr}
orr r3, r3, r4, lsl #16
mov r4, r4, lsr #16
orr r4, r4, r5, lsl #16
mov r5, r5, lsr #16
orr r5, r5, r12, lsl #16
mov r12, r12, lsr #16
orr r12, r12, lr, lsl #16
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul2loop16
ldmia sp!, {r4, r5}
adds r2, r2, #0x0c
blt .Lmemcpy_srcul2l4
.Lmemcpy_srcul2loop4:
mov r12, lr, lsr #16
ldr lr, [r1], #4
orr r12, r12, lr, lsl #16
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul2loop4
.Lmemcpy_srcul2l4:
sub r1, r1, #2
b .Lmemcpy_l4
.Lmemcpy_srcul3:
cmp r2, #0x0c
blt .Lmemcpy_srcul3loop4
sub r2, r2, #0x0c
stmdb sp!, {r4, r5}
.Lmemcpy_srcul3loop16:
mov r3, lr, lsr #24
ldmia r1!, {r4, r5, r12, lr}
orr r3, r3, r4, lsl #8
mov r4, r4, lsr #24
orr r4, r4, r5, lsl #8
mov r5, r5, lsr #24
orr r5, r5, r12, lsl #8
mov r12, r12, lsr #24
orr r12, r12, lr, lsl #8
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul3loop16
ldmia sp!, {r4, r5}
adds r2, r2, #0x0c
blt .Lmemcpy_srcul3l4
.Lmemcpy_srcul3loop4:
mov r12, lr, lsr #24
ldr lr, [r1], #4
orr r12, r12, lr, lsl #8
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul3loop4
.Lmemcpy_srcul3l4:
sub r1, r1, #1
b .Lmemcpy_l4

181
kernel/lib/strsetmem.S Normal file
View File

@@ -0,0 +1,181 @@
/*
* Copyright 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1995 Mark Brinicombe.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe.
* 4. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Taken from FreeBSD memset.S, munged by Erbo to COMROGUE standards */
/* FUNC: PVOID StrSetMem(PVOID pMem, INT32 ch, SSIZE_T cb); */
/*
* Fills a block of memory with a constant byte value.
*
* Parameters:
* - pMem = Pointer to the memory block to be filled.
* - ch = The constant byte (character) to fill that memory with.
* - cb = The size in bytes of the memory block to be filled.
*
* Returns:
* pMem.
*/
.globl StrSetMem
StrSetMem:
and r3, r1, #0xff /* We deal with bytes */
mov r1, r2
cmp r1, #0x04 /* Do we have less than 4 bytes */
mov ip, r0
blt .Lmemset_lessthanfour
/* Ok first we will word align the address */
ands r2, ip, #0x03 /* Get the bottom two bits */
bne .Lmemset_wordunaligned /* The address is not word aligned */
/* We are now word aligned */
.Lmemset_wordaligned:
orr r3, r3, r3, lsl #8 /* Extend value to 16-bits */
tst ip, #0x04 /* Quad-align for armv5e */
orr r3, r3, r3, lsl #16 /* Extend value to 32-bits */
subne r1, r1, #0x04 /* Quad-align if necessary */
strne r3, [ip], #0x04
cmp r1, #0x10
blt .Lmemset_loop4 /* If less than 16 then use words */
mov r2, r3 /* Duplicate data */
cmp r1, #0x80 /* If < 128 then skip the big loop */
blt .Lmemset_loop32
/* Do 128 bytes at a time */
.Lmemset_loop128:
subs r1, r1, #0x80
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
bgt .Lmemset_loop128
bxeq lr /* Zero length so just exit */
add r1, r1, #0x80 /* Adjust for extra sub */
/* Do 32 bytes at a time */
.Lmemset_loop32:
subs r1, r1, #0x20
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
bgt .Lmemset_loop32
bxeq lr /* Zero length so just exit */
adds r1, r1, #0x10 /* Partially adjust for extra sub */
/* Deal with 16 bytes or more */
strged r2, [ip], #0x08
strged r2, [ip], #0x08
bxeq lr /* Zero length so just exit */
addlt r1, r1, #0x10 /* Possibly adjust for extra sub */
/* We have at least 4 bytes so copy as words */
.Lmemset_loop4:
subs r1, r1, #0x04
strge r3, [ip], #0x04
bgt .Lmemset_loop4
bxeq lr /* Zero length so just exit */
/* Compensate for 64-bit alignment check */
adds r1, r1, #0x04
bxeq lr
cmp r1, #2
strb r3, [ip], #0x01 /* Set 1 byte */
strgeb r3, [ip], #0x01 /* Set another byte */
strgtb r3, [ip] /* and a third */
bx lr /* Exit */
.Lmemset_wordunaligned:
rsb r2, r2, #0x004
strb r3, [ip], #0x01 /* Set 1 byte */
cmp r2, #0x02
strgeb r3, [ip], #0x01 /* Set another byte */
sub r1, r1, r2
strgtb r3, [ip], #0x01 /* and a third */
cmp r1, #0x04 /* More than 4 bytes left? */
bge .Lmemset_wordaligned /* Yup */
.Lmemset_lessthanfour:
cmp r1, #0x00
bxeq lr /* Zero length so exit */
strb r3, [ip], #0x01 /* Set 1 byte */
cmp r1, #0x02
strgeb r3, [ip], #0x01 /* Set another byte */
strgtb r3, [ip] /* and a third */
bx lr /* Exit */