Initial checkin of COMROGUE source after having gotten initial memory map right

This commit is contained in:
Eric J. Bowersox
2013-04-11 02:10:10 -06:00
commit 5b93e58fb3
110 changed files with 29045 additions and 0 deletions

77
kernel/Makefile Normal file
View File

@@ -0,0 +1,77 @@
#
# 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
ARMDIR ?= /opt/gnuarm/bin
ARMPREFIX ?= arm-none-eabi
CC = $(ARMDIR)/$(ARMPREFIX)-gcc
CPP = $(ARMDIR)/$(ARMPREFIX)-cpp
AS = $(ARMDIR)/$(ARMPREFIX)-as
LD = $(ARMDIR)/$(ARMPREFIX)-ld
OBJDUMP = $(ARMDIR)/$(ARMPREFIX)-objdump
OBJCOPY = $(ARMDIR)/$(ARMPREFIX)-objcopy
DEFS = -D__COMROGUE_INTERNALS__
INCLUDES = -I../include -I../idl
CFLAGS = $(INCLUDES) -mabi=aapcs -mfloat-abi=hard -mcpu=arm1176jzf-s -Wall -O2 \
-nostdlib -nostartfiles -ffreestanding $(DEFS)
AFLAGS = -mcpu=arm1176jzf-s -mfloat-abi=hard
ASM_CPP_FLAGS = $(INCLUDES) $(DEFS) -D__ASM__
PRESTART_OBJS = prestart.o early_trace.o collect_startup.o early_mm.o
LIB_OBJS = divide.o qdivrem.o intlib.o str.o strcopymem.o
RES_OBJS = lowlevel.o trace.o
INIT_OBJS = start.o kistart.o
all: kernel.img
comrogue-kernel.elf : $(PRESTART_OBJS) $(LIB_OBJS) $(RES_OBJS) $(INIT_OBJS) comrogue-kernel.lds
$(CPP) $(ASM_CPP_FLAGS) -P -o comrogue-kernel.lds.parsed comrogue-kernel.lds
$(LD) -T comrogue-kernel.lds.parsed $(PRESTART_OBJS) $(LIB_OBJS) $(RES_OBJS) \
$(INIT_OBJS) -o comrogue-kernel.elf
kernel.img : comrogue-kernel.elf
$(OBJDUMP) -D comrogue-kernel.elf > comrogue-kernel.list
$(OBJDUMP) -t comrogue-kernel.elf > comrogue-kernel.syms
sort comrogue-kernel.syms > comrogue-kernel.syms.sorted
$(OBJCOPY) comrogue-kernel.elf -O binary kernel.img
%.o: %.S
$(CPP) $(ASM_CPP_FLAGS) -o $(basename $<).s $<
$(AS) $(AFLAGS) -o $@ $(basename $<).s
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
-rm *.o *.s kernel.img comrogue-kernel.elf comrogue-kernel.lds.parsed comrogue-kernel.list \
comrogue-kernel.syms*

245
kernel/collect_startup.c Normal file
View File

@@ -0,0 +1,245 @@
/*
* 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.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/startup.h>
/* The startup information buffer. */
SEG_INIT_DATA static STARTUP_INFO startup_info = {
.cb = sizeof(STARTUP_INFO),
.paTTB = 0,
.kaTTB = 0,
.cpgTTBGap = 0,
.paMPDB = 0,
.kaMPDB = 0,
.cpgMPDB = 0,
.paFirstPageTable = 0,
.cpgPageTables = 0,
.ctblFreeOnLastPage = 0,
.paFirstFree = 0,
.vmaFirstFree = 0
};
/*
* Find a variable by name on the command line.
*
* Parameters:
* - pszCmdLine = Command-line pointer.
* - pszVariableName = Name of variable to search for.
*
* Returns:
* NULL if the variable was not found, otherwise a pointer to the first character in the command line
* following the variable name and associated = sign (first character of the value).
*/
SEG_INIT_CODE static PCSTR find_variable(PCSTR pszCmdLine, PCSTR pszVariableName)
{
register PCSTR p = pszCmdLine;
register PCSTR p1, q;
while (*p)
{
for (; *p && (*p != *pszVariableName); p++) ;
if (*p)
{
for (p1 = p, q = pszVariableName; *p1 && *q && (*p1 == *q); p1++, q++) ;
if (!(*q) && *p1 == '=')
return p1 + 1;
p++;
}
}
return NULL;
}
/*
* Returns whether a character is a valid digit.
*
* Parameters:
* - ch = The character to be tested.
* - base = The base of the number being converted.
*
* Returns:
* TRUE if the character is a valid digit, FALSE otherwise.
*/
SEG_INIT_CODE static BOOL is_valid_digit(CHAR ch, UINT32 base)
{
register UINT32 nbase;
if (base > 10)
{
if ((ch >= 'a') && (ch < ('a' + base - 10)))
return TRUE;
if ((ch >= 'A') && (ch < ('A' + base - 10)))
return TRUE;
}
nbase = (base > 10) ? 10 : base;
if ((ch >= '0') && (ch < ('0' + nbase)))
return TRUE;
return FALSE;
}
/*
* Decodes a number in a command-line parameter. Decoding stops at the first character that is not a valid digit.
*
* Parameters:
* - pVal = Pointer to the value in the command line.
* - base = Base of the number to convert. If this is 16, the decoder will skip over a "0x" or "0X" prefix
* of the value, if one exists.
*
* Returns:
* The converted numeric value.
*/
SEG_INIT_CODE static UINT32 decode_number(PCSTR pVal, UINT32 base)
{
register UINT32 accum = 0;
register UINT32 digit;
if ((base == 16) && (*pVal == '0') && ((*(pVal + 1) == 'x') || (*(pVal + 1) == 'X')))
pVal += 2;
while (is_valid_digit(*pVal, base))
{
if (*pVal >= 'a')
digit = (*pVal - 'a') + 10;
else if (*pVal >= 'A')
digit = (*pVal - 'A') + 10;
else
digit = (*pVal - '0');
accum = accum * base + digit;
pVal++;
}
return accum;
}
/*
* Parses the command line passed in via the ATAGS and extracts certain values to the startup info
* data structure.
*
* Parameters:
* - pszCmdLine = Pointer to the command line.
*
* Returns:
* Nothing.
*
* Side effects:
* Modifies the "startup_info" structure.
*/
SEG_INIT_CODE static void parse_cmdline(PCSTR pszCmdLine)
{
static DECLARE_INIT_STRING8_CONST(szFBWidth, "bcm2708_fb.fbwidth");
static DECLARE_INIT_STRING8_CONST(szFBHeight, "bcm2708_fb.fbheight");
static DECLARE_INIT_STRING8_CONST(szRevision, "bcm2708.boardrev");
static DECLARE_INIT_STRING8_CONST(szSerial, "bcm2708.serial");
static DECLARE_INIT_STRING8_CONST(szMACAddr, "smsc95xx.macaddr");
static DECLARE_INIT_STRING8_CONST(szEMMCFreq, "sdhci-bcm2708.emmc_clock_freq");
static DECLARE_INIT_STRING8_CONST(szVCMemBase, "vc_mem.mem_base");
static DECLARE_INIT_STRING8_CONST(szVCMemSize, "vc_mem.mem_size");
register PCSTR p;
register int i;
p = find_variable(pszCmdLine, szFBWidth);
startup_info.cxFBWidth = (UINT16)(p ? decode_number(p, 10) : 0);
p = find_variable(pszCmdLine, szFBHeight);
startup_info.cyFBHeight = (UINT16)(p ? decode_number(p, 10) : 0);
p = find_variable(pszCmdLine, szRevision);
startup_info.uiRevision = (p ? decode_number(p, 16) : 0);
p = find_variable(pszCmdLine, szSerial);
startup_info.uiSerialNumber = (p ? decode_number(p, 16) : 0);
p = find_variable(pszCmdLine, szMACAddr);
if (p)
{
for (i=0; i<6; i++)
{
startup_info.abMACAddress[i] = (BYTE)decode_number(p, 16);
p += 3;
}
}
else
{
for (i=0; i<6; i++)
startup_info.abMACAddress[i] = 0;
}
p = find_variable(pszCmdLine, szEMMCFreq);
startup_info.uiEMMCClockFreq = (p ? decode_number(p, 10) : 0);
p = find_variable(pszCmdLine, szVCMemBase);
startup_info.paVCMem = (PHYSADDR)(p ? decode_number(p, 16) : 0);
p = find_variable(pszCmdLine, szVCMemSize);
startup_info.cbVCMem = (p ? decode_number(p, 16) : 0);
startup_info.cpgSystemTotal = startup_info.cbVCMem >> SYS_PAGE_BITS;
}
/*
* Collects startup information in an init-data buffer and returns a pointer to that buffer.
*
* Parameters:
* - always0 = Always 0.
* - uiMachineType = Machine type constant.
* - pAtags = Pointer to ATAGS data set up before kernel was started.
*
* Returns:
* A pointer to the assembled STARTUP_INFO data structure.
*
* Side effects:
* Modifies the "startup_info" structure, which it returns a pointer to.
*/
SEG_INIT_CODE PSTARTUP_INFO KiCollectStartupInfo(UINT32 always0, UINT32 uiMachineType, PATAG_HEADER pAtags)
{
/* Fill in the information we can calculate right away. */
startup_info.uiMachineType = uiMachineType;
/* Scan the ATAG headers to determine what other info to include. */
while (pAtags->uiTag != ATAGTYPE_NONE)
{
switch (pAtags->uiTag)
{
case ATAGTYPE_CORE:
/* nothing really useful in this block */
break;
case ATAGTYPE_MEM:
/* fill in total number of available system memory pages */
startup_info.cpgSystemAvail = ((PATAG_MEM)pAtags)->uiSize >> SYS_PAGE_BITS;
break;
case ATAGTYPE_CMDLINE:
parse_cmdline(((PATAG_CMDLINE)pAtags)->szCommandLine);
break;
default:
/* no other ATAG types are seen on Raspberry Pi */
break;
}
pAtags = kiNextATAG(pAtags);
}
return &startup_info;
}

134
kernel/comrogue-kernel.lds Normal file
View File

@@ -0,0 +1,134 @@
/*
* 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/internals/mmu.h>
#include <comrogue/internals/layout.h>
ENTRY(COMROGUEPrestart)
SECTIONS
{
/* all these are prestart code that runs in low memory with MMU off */
/* space is reclaimed once the kernel begins operation in high memory with MMU on */
.prestart.text PHYSADDR_LOAD : AT (PHYSADDR_LOAD) {
paPrestartCode = .;
*(.prestartHEAD.text) /* must be first! */
*(.prestart.text)
*(.prestart.rodata)
*(.prestart.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgPrestartCode = (. - paPrestartCode) >> SYS_PAGE_BITS;
paPrestartData = .;
.prestart.data : AT(paPrestartData) {
*(.prestart.data)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgPrestartData = (. - paPrestartData) >> SYS_PAGE_BITS;
cpgPrestartTotal = . >> SYS_PAGE_BITS;
paLibraryCode = .;
/* kernel library code, in high memory mapped to be visible to user processes */
.lib.text VMADDR_LIBRARY_FENCE : AT (paLibraryCode) {
vmaLibraryCode = .;
*(.lib.text)
*(.lib.rodata)
*(.lib.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgLibraryCode = (. - vmaLibraryCode) >> SYS_PAGE_BITS;
paKernelCode = paLibraryCode + (. - vmaLibraryCode);
/* kernel resident code, runs in high memory with MMU on */
.text VMADDR_KERNEL_FENCE : AT(paKernelCode) {
vmaKernelCode = .;
*(.text)
*(.rodata)
*(.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgKernelCode = (. - vmaKernelCode) >> SYS_PAGE_BITS;
paKernelData = paKernelCode + (. - vmaKernelCode);
.data : AT(paKernelData) {
vmaKernelData = .;
*(.data)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgKernelData = (. - vmaKernelData) >> SYS_PAGE_BITS;
paKernelBss = paKernelData + (. - vmaKernelData);
.bss : AT(paKernelBss) {
vmaKernelBss = .;
*(.bss)
*(COMMON)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgKernelBss = (. - vmaKernelBss) >> SYS_PAGE_BITS;
paInitCode = paKernelBss + (. - vmaKernelBss);
/* kernel one-time initialization code, runs in high memory with MMU on */
/* space is reclaimed once the kernel finishes initialization */
.init.text : AT(paInitCode) {
vmaInitCode = .;
*(.initHEAD.text) /* must be first! */
*(.init.text)
*(.init.rodata)
*(.init.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgInitCode = (. - vmaInitCode) >> SYS_PAGE_BITS;
paInitData = paInitCode + (. - vmaInitCode);
.init.data : AT(paInitData) {
vmaInitData = .;
*(.init.data)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgInitData = (. - vmaInitData) >> SYS_PAGE_BITS;
paInitBss = paInitData + (. - vmaInitData);
.init.bss : AT(paInitBss) {
vmaInitBss = .;
*(.init.bss)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgInitBss = (. - vmaInitBss) >> SYS_PAGE_BITS;
paFirstFree = paInitBss + (. - vmaInitBss);
vmaFirstFree = .;
/DISCARD/ : {
*(.comment)
*(.note*)
*(.ARM.attributes)
}
}

479
kernel/divide.S Normal file
View File

@@ -0,0 +1,479 @@
/*
* 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 */
.section ".lib.text"
.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

398
kernel/early_mm.c Normal file
View File

@@ -0,0 +1,398 @@
/*
* 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.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/layout.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/startup.h>
#include <comrogue/internals/trace.h>
#ifdef THIS_FILE
#undef THIS_FILE
DECLARE_THIS_FILE
#endif
/*-----------------------------------------------------------------------------
* Early memory-management code that handles creating the mappings for the TTB
*-----------------------------------------------------------------------------
*/
/* Data stored in here temporarily and reflected back to startup info when we're done. */
SEG_INIT_DATA static PTTB g_pTTB = NULL; /* pointer to TTB */
SEG_INIT_DATA static UINT32 g_cpgForPageTables = 0; /* number of pages being used for page tables */
SEG_INIT_DATA static UINT32 g_ctblFreeonLastPage = 0; /* number of page tables free on last page */
SEG_INIT_DATA static PPAGETAB g_ptblNext = NULL; /* pointer to next free page table */
/*
* Morphs the "flags" bits used for a page table entry in the TTB and for a page entry in the page table
* into the "flags" bits used for a section entry in the TTB.
*
* Parameters:
* - uiTableFlags = Flag bits that would be used for a page table entry in the TTB.
* - uiPageFlags = Flag bits that would be used for a page entry in the page table.
*
* Returns:
* The flag bits that would be used for a section entry in the TTB. If a bit or option is set
* in either uiTableFlags or uiPageFlags, it will be set in the appropriate place in the result.
*/
SEG_INIT_CODE static UINT32 make_section_flags(UINT32 uiTableFlags, UINT32 uiPageFlags)
{
register UINT32 rc = TTBSEC_ALWAYS;
rc |= ((uiTableFlags & TTBPGTBL_PXN) >> 2);
rc |= ((uiTableFlags & TTBPGTBL_NS) << 16);
rc |= (uiTableFlags & TTBPGTBL_DOM_MASK);
rc |= (uiTableFlags & TTBPGTBL_P);
rc |= ((uiPageFlags & PGTBLSM_XN) << 4);
rc |= (uiPageFlags & PGTBLSM_B);
rc |= (uiPageFlags & PGTBLSM_C);
rc |= ((uiPageFlags & PGTBLSM_AP) << 6);
rc |= ((uiPageFlags & PGTBLSM_TEX) << 6);
rc |= ((uiPageFlags & PGTBLSM_APX) << 6);
rc |= ((uiPageFlags & PGTBLSM_S) << 6);
rc |= ((uiPageFlags & PGTBLSM_NG) << 6);
return rc;
}
/*
* Allocates page mapping entries within a single current entry in the TTB.
*
* Parameters:
* - paBase = The page-aligned base physical address to map.
* - pTTBEntry = Pointer to the TTB entry to be used.
* - ndxPage = The "first" index within the current page to use.
* - cpg = The maximum number of pages we want to map. This function will only map as many pages as will
* fit in the current TTB entry, as indicated by ndxPage.
* - uiTableFlags = Flags to be used or verified for the TTB entry.
* - uiPageFlags = Flags to be used for new page table entries.
*
* Returns:
* The number of pages that were actually mapped by this function call, or -1 if there was an error in the mapping.
*
* Side effects:
* May modify the ndxTTB'th entry in the TTB, if it was not previously allocated. May modify the current page
* table that the TTB entry points to, where applicable. If we need to allocate a new page table, may modify the
* global variables g_cpgForPageTables, g_ctblFreeonLastPage, and g_ptblNext.
*/
SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 ndxPage, INT32 cpg, UINT32 uiTableFlags,
UINT32 uiPageFlags)
{
INT32 cpgCurrent; /* number of pages we're mapping */
PPAGETAB pTab; /* pointer to current or new page table */
register INT32 i; /* loop counter */
switch (pTTBEntry->data & TTBQUERY_MASK)
{
case TTBQUERY_FAULT: /* not allocated, allocate a new page table for the slot */
if (g_ctblFreeonLastPage == 0)
{
g_cpgForPageTables++;
g_ctblFreeonLastPage = 2;
}
g_ctblFreeonLastPage--;
pTab = g_ptblNext++;
for (i=0; i<SYS_PGTBL_ENTRIES; i++)
{
pTab->pgtbl[i].data = 0; /* blank out the new page table */
pTab->pgaux[i].data = 0;
}
pTTBEntry->data = ((UINT32)pTab) | uiTableFlags; /* poke new entry */
break;
case TTBQUERY_PGTBL: /* existing page table */
if ((pTTBEntry->data & TTBPGTBL_ALLFLAGS) != uiTableFlags)
return -1; /* table flags not compatible */
break;
case TTBQUERY_SEC:
case TTBQUERY_PXNSEC:
/* existing section, deal with this later */
break;
}
/* Figure out how many entries we're going to map. */
cpgCurrent = SYS_PGTBL_ENTRIES - ndxPage; /* total free slots on page */
if (cpg < cpgCurrent)
cpgCurrent = cpg; /* only map up to max requested */
if (pTTBEntry->data & TTBSEC_ALWAYS)
{
/* this is a section, make sure its base address covers this mapping and its flags are compatible */
if ((pTTBEntry->data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags))
return -1;
if ((pTTBEntry->data & TTBSEC_BASE) != (paBase & TTBSEC_BASE))
return -1;
}
else
{
/* fill in entries in the page table */
pTab = (PPAGETAB)(pTTBEntry->data & TTBPGTBL_BASE);
for (i=0; i<cpgCurrent; i++)
{
if ((pTab->pgtbl[ndxPage + i].data & PGQUERY_MASK) != PGQUERY_FAULT)
return -1; /* stepping on existing mapping */
pTab->pgtbl[ndxPage + i].data = paBase | uiPageFlags;
pTab->pgaux[ndxPage + i].data = 0; /* TODO */
paBase += SYS_PAGE_SIZE;
}
}
return cpgCurrent;
}
/*
* Maps a certain number of memory pages beginning at a specified physical address into virtual memory
* beginning at a specified virtual address.
*
* Parameters:
* - paBase = The page-aligned base physical address to map.
* - vmaBase = The page-aligned virtual address to map those pages to.
* - cpg = The number of pages to be mapped.
* - uiTableFlags = Flags to be used or verified for TTB entries.
* - uiPageFlags = Flags to be used for new page table entries.
*
* Returns:
* TRUE if the mapping succeeded, FALSE if it failed.
*
* Side effects:
* May modify unallocated entries in the TTB. May modify any page tables that are pointed to by TTB entries,
* where applicable. If we need to allocate new page tables, may modify the global variables g_cpgForPageTables,
* g_ctblFreeonLastPage, and g_ptblNext.
*/
SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg, UINT32 uiTableFlags,
UINT32 uiPageFlags)
{
static DECLARE_INIT_STRING8_CONST(sz1, "Map ");
static DECLARE_INIT_STRING8_CONST(sz2, "->");
static DECLARE_INIT_STRING8_CONST(sz3, ",cpg=");
static DECLARE_INIT_STRING8_CONST(sz4, ",tf=");
static DECLARE_INIT_STRING8_CONST(sz5, ",pf=");
INT32 ndxTTB = mmVMA2TTBIndex(vmaBase); /* TTB entry index */
INT32 ndxPage = mmVMA2PGTBLIndex(vmaBase); /* starting page entry index */
INT32 cpgCurrent; /* current number of pages mapped */
ETrWriteString8(sz1);
ETrWriteWord(paBase);
ETrWriteString8(sz2);
ETrWriteWord(vmaBase);
ETrWriteString8(sz3);
ETrWriteWord(cpg);
ETrWriteString8(sz4);
ETrWriteWord(uiTableFlags);
ETrWriteString8(sz5);
ETrWriteWord(uiPageFlags);
ETrWriteChar8('\n');
if ((cpg > 0) && (ndxPage > 0))
{
/* We are starting in the middle of a VM page. Map to the end of the VM page. */
cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, ndxPage, cpg, uiTableFlags, uiPageFlags);
if (cpgCurrent < 0)
{
/* ETrWriteChar8('a'); */
return FALSE;
}
/* adjust base physical address, page count, and TTB index */
paBase += (cpgCurrent << SYS_PAGE_BITS);
cpg -= cpgCurrent;
ndxTTB++;
/* N.B.: from this point on ndxPage will be treated as 0 */
}
while (cpg >= SYS_PGTBL_ENTRIES)
{
/* try to map a whole section's worth at a time */
if ((paBase & TTBSEC_BASE) == paBase)
{
/* paBase is section-aligned now as well, we can use a direct 1Mb section mapping */
switch (g_pTTB[ndxTTB].data & TTBQUERY_MASK)
{
case TTBQUERY_FAULT: /* unmapped - map the section */
g_pTTB[ndxTTB].data = paBase | make_section_flags(uiTableFlags, uiPageFlags);
break;
case TTBQUERY_PGTBL: /* collided with a page table */
/* ETrWriteChar8('b'); */
return FALSE;
case TTBQUERY_SEC: /* test existing section */
case TTBQUERY_PXNSEC:
if ((g_pTTB[ndxTTB].data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags))
{
/* ETrWriteChar8('c'); */
return FALSE; /* invalid flags */
}
if ((g_pTTB[ndxTTB].data & TTBSEC_BASE) != paBase)
{
/* ETrWriteChar8('d'); */
return FALSE; /* invalid base address */
}
break;
}
cpgCurrent = SYS_PGTBL_ENTRIES; /* we mapped a whole section worth */
}
else
{
/* just map 256 individual pages */
cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags);
if (cpgCurrent < 0)
{
/* ETrWriteChar8('e'); */
return FALSE;
}
}
/* adjust base physical address, page count, and TTB index */
paBase += (cpgCurrent << SYS_PAGE_BITS);
cpg -= cpgCurrent;
ndxTTB++;
}
if (cpg > 0)
{
/* map the "tail end" onto the next TTB */
if (alloc_pages(paBase, g_pTTB + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags) < 0)
{
/* ETrWriteChar8('f'); */
return FALSE;
}
}
return TRUE;
}
/* External references to symbols defined by the linker script. */
extern char paFirstFree, cpgPrestartTotal, paLibraryCode, vmaLibraryCode, cpgLibraryCode, paKernelCode,
vmaKernelCode, cpgKernelCode, paKernelData, vmaKernelData, cpgKernelData, cpgKernelBss, paInitCode,
vmaInitCode, cpgInitCode, paInitData, vmaInitData, cpgInitData, cpgInitBss, vmaFirstFree;
/*
* Initializes a TTB (used as TTB1 and initially TTB0 as well) with mappings to all the pieces of the kernel and
* to memory-mapped IO, and fills in details in the startup info structure.
*
* Parameters:
* - pstartup - Pointer to startup info structure, which is modified by this function.
*
* Returns:
* - Physical address of the new TTB1.
*
* Side effects:
* Modifies physical memory beyond the end of the kernel to store TTB and page tables. Uses several
* static globals in this module for work space while performing memory mappings.
*/
SEG_INIT_CODE PHYSADDR EMmInit(PSTARTUP_INFO pstartup)
{
static DECLARE_INIT_STRING8_CONST(szTTBAt, "EMmInit: TTB1@");
static DECLARE_INIT_STRING8_CONST(szPageTable, "Page table pages:");
static DECLARE_INIT_STRING8_CONST(szFree, "\nFree last page:");
PHYSADDR paTTB = (PHYSADDR)(&paFirstFree); /* location of the system TTB1 */
UINT32 cbMPDB; /* number of bytes in the MPDB */
register INT32 i; /* loop counter */
/* Locate the appropriate place for TTB1, on a 16K boundary. */
pstartup->cpgTTBGap = 0;
while (paTTB & (SYS_TTB1_SIZE - 1))
{
paTTB += SYS_PAGE_SIZE;
pstartup->cpgTTBGap++;
}
ETrWriteString8(szTTBAt);
ETrWriteWord(paTTB);
ETrWriteChar8('\n');
/* Save off the TTB location and initialize it. */
pstartup->paTTB = paTTB;
g_pTTB = (PTTB)paTTB;
for (i=0; i<SYS_TTB1_ENTRIES; i++)
g_pTTB[i].data = 0;
/* Allocate space for the Master Page Database but do not initialize it. */
pstartup->paMPDB = paTTB + SYS_TTB1_SIZE;
cbMPDB = pstartup->cpgSystemTotal << 2;
pstartup->cpgMPDB = cbMPDB >> SYS_PAGE_BITS;
if (cbMPDB & (SYS_PAGE_SIZE - 1))
{
pstartup->cpgMPDB++;
cbMPDB = pstartup->cpgMPDB << SYS_PAGE_BITS;
}
/* Initialize the "next page table" pointer. */
pstartup->paFirstPageTable = pstartup->paMPDB + cbMPDB;
g_ptblNext = (PPAGETAB)(pstartup->paFirstPageTable);
/* Map the "prestart" area (everything below load address, plus prestart code & data) as identity. */
VERIFY(map_pages(0, 0, (INT32)(&cpgPrestartTotal), TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01));
/* Map the IO area as identity. */
VERIFY(map_pages(PHYSADDR_IO_BASE, PHYSADDR_IO_BASE, PAGE_COUNT_IO, TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01));
/* Map the library area. */
VERIFY(map_pages((PHYSADDR)(&paLibraryCode), (KERNADDR)(&vmaLibraryCode), (INT32)(&cpgLibraryCode),
TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP10));
/* Map the kernel code area. */
VERIFY(map_pages((PHYSADDR)(&paKernelCode), (KERNADDR)(&vmaKernelCode), (INT32)(&cpgKernelCode),
TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the kernel data/BSS area. */
VERIFY(map_pages((PHYSADDR)(&paKernelData), (KERNADDR)(&vmaKernelData),
(INT32)(&cpgKernelData) + (INT32)(&cpgKernelBss),
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the kernel init code area. */
VERIFY(map_pages((PHYSADDR)(&paInitCode), (KERNADDR)(&vmaInitCode), (INT32)(&cpgInitCode),
TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the kernel init data/BSS area. */
VERIFY(map_pages((PHYSADDR)(&paInitData), (KERNADDR)(&vmaInitData),
(INT32)(&cpgInitData) + (INT32)(&cpgInitBss),
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the TTB itself. */
pstartup->kaTTB = (KERNADDR)(&vmaFirstFree);
VERIFY(map_pages(paTTB, pstartup->kaTTB, SYS_TTB1_SIZE / SYS_PAGE_SIZE,
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the Master Page Database. */
pstartup->kaMPDB = pstartup->kaTTB + SYS_TTB1_SIZE;
VERIFY(map_pages(pstartup->paMPDB, pstartup->kaTTB + SYS_TTB1_SIZE, pstartup->cpgMPDB,
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the IO area into high memory as well. */
VERIFY(map_pages(PHYSADDR_IO_BASE, VMADDR_IO_BASE, PAGE_COUNT_IO, TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01));
#if 0
/* Dump the TTB and page tables to trace output. */
ETrDumpWords((PUINT32)paTTB, (SYS_TTB1_SIZE + (g_cpgForPageTables << SYS_PAGE_BITS)) >> 2);
ETrWriteString8(szPageTable);
ETrWriteWord(g_cpgForPageTables);
ETrWriteString8(szFree);
ETrWriteWord(g_ctblFreeonLastPage);
ETrWriteChar8('\n');
#endif
/* Fill in the rest of the data in the startup info structure. */
pstartup->cpgPageTables = g_cpgForPageTables;
pstartup->ctblFreeOnLastPage = g_ctblFreeonLastPage;
pstartup->paFirstFree = pstartup->paFirstPageTable + (g_cpgForPageTables << SYS_PAGE_BITS);
pstartup->vmaFirstFree = pstartup->kaMPDB + cbMPDB;
return paTTB; /* return this for startup ASM code to use */
}

245
kernel/early_trace.c Normal file
View File

@@ -0,0 +1,245 @@
/*
* 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.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/llio.h>
#include <comrogue/internals/auxdev.h>
#include <comrogue/internals/gpio.h>
#include <comrogue/internals/16550.h>
#include <comrogue/internals/trace.h>
/* Hex digits. */
static DECLARE_INIT_STRING8_CONST(szHexDigits, "0123456789ABCDEF");
/*
* Initializes the trace functionality (the aux UART).
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Side effects:
* GPIO 14 configured for output from UART1; UART1 initialized to 115200 8N1 and enabled for output.
*/
SEG_INIT_CODE void ETrInit(void)
{
register UINT32 ra;
/* Initialize UART */
llIOWrite(AUX_REG_ENABLE, AUX_ENABLE_MU); /* enable UART1 */
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_CNTL, 0);
llIOWrite(AUX_MU_REG_LCR, U16550_LCR_LENGTH_8|U16550_LCR_PARITY_NONE); /* 8 bits, no parity */
llIOWrite(AUX_MU_REG_MCR, 0);
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_FCR, U16550_FCR_RXCLEAR|U16550_FCR_TXCLEAR|U16550_FCR_LEVEL_14);
llIOWrite(AUX_MU_REG_BAUD, 270); /* 115200 baud */
ra = llIORead(GPFSEL1_REG);
ra &= ~GP_FUNC_MASK(4); /* GPIO 14 - connects to pin 8 on GPIO connector */
ra |= GP_FUNC_BITS(4, GP_PIN_ALT5); /* Alt function 5 - UART1 TxD */
llIOWrite(GPFSEL1_REG, ra);
llIOWrite(GPPUD_REG, 0);
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, GP_BIT(14));
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, 0);
llIOWrite(AUX_MU_REG_CNTL, AUXMU_CNTL_TXENABLE);
}
/*
* Writes a raw character to trace output.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Character written to UART1.
*/
SEG_INIT_CODE static void write_trace(UINT32 c)
{
register UINT32 lsr = llIORead(AUX_MU_REG_LSR);
while (!(lsr & U16550_LSR_TXEMPTY))
lsr = llIORead(AUX_MU_REG_LSR);
llIOWrite(AUX_MU_REG_THR, c);
}
/*
* Writes a character to trace output, translating newlines.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Either 1 or 2 characters written to UART1.
*/
SEG_INIT_CODE void ETrWriteChar8(CHAR c)
{
if (c == '\n')
write_trace('\r');
write_trace((UINT32)c);
}
/*
* Writes a null-terminated string to trace output. Newlines in the string are translated.
*
* Parameters:
* - psz = Pointer to string to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters in string written to UART1.
*/
SEG_INIT_CODE void ETrWriteString8(PCSTR psz)
{
while (*psz)
ETrWriteChar8(*psz++);
}
/*
* Writes the value of a 32-bit word to trace output.
*
* Parameters:
* - uiValue = Value to be written to trace output.
*
* Returns:
* Nothing.
*
* Side effects:
* 8 characters written to UART1.
*/
SEG_INIT_CODE void ETrWriteWord(UINT32 uiValue)
{
register UINT32 uiShift = 32;
do
{
uiShift -= 4;
write_trace(szHexDigits[(uiValue >> uiShift) & 0xF]);
} while (uiShift > 0);
}
/*
* Dumps the values of memory words beginning at a specified address.
*
* Parameters:
* - puiWords = Pointer to words to be dumped.
* - cWords = Number of words to be dumped.
*
* Returns:
* Nothing.
*
* Side effects:
* Many characters written to UART1.
*/
SEG_INIT_CODE void ETrDumpWords(PUINT32 puiWords, UINT32 cWords)
{
static DECLARE_INIT_STRING8_CONST(szSpacer1, ": ");
register UINT32 i;
for (i = 0; i < cWords; i++)
{
if ((i & 0x3) == 0)
{
ETrWriteWord((UINT32)(puiWords + i));
ETrWriteString8(szSpacer1);
}
ETrWriteWord(puiWords[i]);
if ((i & 0x3) == 0x3)
ETrWriteChar8('\n');
else
ETrWriteChar8(' ');
}
if ((cWords & 0x3) != 0)
ETrWriteChar8('\n');
}
/*
* Prints an "assertion failed" message to trace output.
*
* Parameters:
* - pszFile = The file name the assertion was declared in.
* - nLine = The line number the assertion was declared at.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters written to UART1.
*/
SEG_INIT_CODE void ETrAssertFailed(PCSTR pszFile, INT32 nLine)
{
static DECLARE_INIT_STRING8_CONST(szPrefix, "** ASSERTION FAILED: ");
ETrWriteString8(szPrefix);
ETrWriteString8(pszFile);
write_trace(':');
ETrWriteWord((UINT32)nLine);
ETrWriteChar8('\n');
}
/*
* Puts the CPU into a loop where it blinks the green ACTIVITY light forever.
*
* Parameters:
* None.
*
* Returns:
* DOES NOT RETURN!
*
* Side effects:
* GPIO 16 configured for output and turns on and off indefinitely.
*/
SEG_INIT_CODE void ETrInfiniBlink(void)
{
register UINT32 ra;
ra = llIORead(GPFSEL1_REG);
ra &= GP_FUNC_MASK(6); /* GPIO 16 - connects to green ACTIVITY LED */
ra |= GP_FUNC_BITS(6, GP_PIN_OUTPUT); /* output in all circumstances */
llIOWrite(GPFSEL1_REG, ra);
for(;;)
{
llIOWrite(GPSET0_REG, GP_BIT(16));
llIODelay(0x100000);
llIOWrite(GPCLR0_REG, GP_BIT(16));
llIODelay(0x100000);
}
}

81
kernel/intlib.c Normal file
View File

@@ -0,0 +1,81 @@
/*
* 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 <comrogue/internals/seg.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.
*/
SEG_LIB_CODE 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;
}

94
kernel/kistart.c Normal file
View File

@@ -0,0 +1,94 @@
/*
* 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.
*/
#define __COMROGUE_INIT__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/trace.h>
#include <comrogue/internals/startup.h>
#include <comrogue/internals/mmu.h>
#ifdef THIS_FILE
#undef THIS_FILE
DECLARE_THIS_FILE
#endif
/*--------------------------------------------------------------------------------------------------------
* Startup info buffer. Data is copied into here by the assembly code before KiSystemStartup is invoked.
*--------------------------------------------------------------------------------------------------------
*/
SEG_INIT_DATA STARTUP_INFO kiStartupInfo; /* startup info buffer */
SEG_INIT_CODE static void dump_startup_info()
{
TrPrintf8("Mach type %x, revision %x, serial %x\n", kiStartupInfo.uiMachineType, kiStartupInfo.uiRevision,
kiStartupInfo.uiSerialNumber);
TrPrintf8("Memory: %u total pages (%u available), %u TTB gap\n", kiStartupInfo.cpgSystemTotal,
kiStartupInfo.cpgSystemAvail, kiStartupInfo.cpgTTBGap);
TrPrintf8("TTB1 @ PA %08X, VMA %08X\n", kiStartupInfo.paTTB, kiStartupInfo.kaTTB);
TrPrintf8("MPDB @ PA %08X, VMA %08X, %u pages\n", kiStartupInfo.paMPDB, kiStartupInfo.kaMPDB, kiStartupInfo.cpgMPDB);
TrPrintf8("Page tables @ PA %08X, %u pages, %u free on last one\n", kiStartupInfo.paFirstPageTable,
kiStartupInfo.cpgPageTables, kiStartupInfo.ctblFreeOnLastPage);
TrPrintf8("First free PA = %08X, first free VMA = %08X\n", kiStartupInfo.paFirstFree, kiStartupInfo.vmaFirstFree);
TrPrintf8("EMMC clock freq = %u\n", kiStartupInfo.uiEMMCClockFreq);
TrPrintf8("VC memory is at PHYS:%08X, %u bytes, framebuffer %ux%u\n", kiStartupInfo.paVCMem, kiStartupInfo.cbVCMem,
kiStartupInfo.cxFBWidth, kiStartupInfo.cyFBHeight);
TrPrintf8("MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", kiStartupInfo.abMACAddress[0],
kiStartupInfo.abMACAddress[1], kiStartupInfo.abMACAddress[2], kiStartupInfo.abMACAddress[3],
kiStartupInfo.abMACAddress[4], kiStartupInfo.abMACAddress[5]);
}
/*---------------------
* System startup code
*---------------------
*/
static DECLARE_INIT_STRING8_CONST(banner, "--- COMROGUE %d.%02d\n- KiSystemStartup\n");
/*
* Starts the COMROGUE Operating System.
*
* Parameters:
* None.
*
* Returns:
* DOES NOT RETURN!
*
* Side effects:
* Uses the information in kiStartupInfo.
*/
SEG_INIT_CODE void KiSystemStartup(void)
{
TrPrintf8(banner, 0, 0);
dump_startup_info();
TrInfiniBlink();
}

96
kernel/lowlevel.S Normal file
View File

@@ -0,0 +1,96 @@
/*
* 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.
*/
.section ".text"
/*------------------------
* Low-level IO functions
*------------------------
*/
/*
* Writes a 32-bit word of data to a memory-mapped IO port.
*
* Parameters:
* - kaPort = Kernel address of the IO port to write to.
* - uiData = Data to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Writing to any given IO port may have arbitrary side effects.
*/
.globl llIOWriteK
llIOWriteK:
str r1,[r0]
bx lr
/*
* Reads a 32-bit word of data from a memory-mapped IO port.
*
* Parameters:
* - kaPort = Kernel address of the IO port we read from.
*
* Returns:
* The word of data read from the IO port.
*
* Side effects:
* Reading from any given IO port may have arbitrary side effects.
*/
.globl llIOReadK
llIOReadK:
ldr r0,[r0]
bx lr
/*
* Delays for a certain number of cycles, to allow an IO operation to work.
*
* Parameters:
* - uiTicks = The number of "ticks" to delay.
*
* Returns:
* Nothing.
*/
.globl llIODelay
llIODelay:
push {lr}
.delaytop:
nop
nop
bl .delayreturn
nop
nop
subs r0, r0, #1
bne .delaytop
pop {lr}
.delayreturn:
bx lr

271
kernel/prestart.S Normal file
View File

@@ -0,0 +1,271 @@
/*
* 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.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/internals/asm-macros.h>
#include <comrogue/internals/layout.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/sctlr.h>
/*------------------------------------------------------------------------------------------
* The prestart code that gets control when the kernel is first loaded; its objective is to
* set up the MMU and hand over control to the actual start code.
*------------------------------------------------------------------------------------------
*/
.section ".prestartHEAD.text"
.globl COMROGUEPrestart
/* On entry: r0 = 0, r1 = machine type, r2 = atags address */
COMROGUEPrestart:
/* Initialize a temporary stack area. */
mov ip, # PHYSADDR_LOAD
sub sp, ip, #4
/* Go collect the startup info. */
bl KiCollectStartupInfo
mov r11, r0 /* r11 = address of startup info structure */
/* at this point r0-r2 are free for other code to use */
/* Early trace initialize; we reinitialize it later. */
bl ETrInit
ldr r0, =.initMessage
bl ETrWriteString8
/* Copy the early vector table into place, including the vector words that live after the table itself. */
ldr r0, =.earlyVectorTable
ldr r1, =.earlyVectorTableEnd
mov r2, #0
b .vec1
.vec0:
ldm r0!, {r3-r6} /* copy 16 bytes at a time */
stm r2!, {r3-r6}
.vec1:
cmp r0, r1
bne .vec0
/* Initialize early memory management (the TTB1). */
mov r0, r11
bl EMmInit
mov r10, r0 /* r10 = address of TTB */
/* Set up and start the MMU. */
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 /* clear caches */
mcr p15, 0, ip, c8, c7, 0 /* clear TLB */
mov ip, #1
mcr p15, 0, ip, c2, c0, 2 /* set TTBCR */
mvn ip, #0
mcr p15, 0, ip, c3, c0, 0 /* configure domain 0 = client, all others = invalid */
mcr p15, 0, r10, c2, c0, 0 /* set TTB0 */
mcr p15, 0, r10, c2, c0, 1 /* set TTB1 */
mrc p15, 0, ip, c1, c0, 0 /* get control register 1 */
orr ip, ip, # SCTLR_M /* MMU = on */
orr ip, ip, # SCTLR_XP /* subpage AP bits disabled in 2nd-level page tables */
instr_barrier
mcr p15, 0, ip, c1, c0, 0 /* store control register 1 */
mrc p15, 0, ip, c0, c0, 0 /* read ID register */
instr_barrier
#if 0
ldr r0, =.msg1
bl ETrWriteString8
#endif
/* now go to the start area in kernel space */
mov r0, r11
ldr ip, =COMROGUEStart
mov pc, ip
#if 0
.balign 4
.msg1:
.asciz "got here 1\n"
.balign 4
#endif
/*-------------------------------------------------------------
* Early exception-handler code, mainly for debugging purposes
*-------------------------------------------------------------
*/
.earlyReset:
ldr r0, =.resetMessage
b .earlyFUBAR
.earlyUndef:
ldr r0, =.undefMessage
b .earlyFUBAR
.earlySVC:
ldr r0, =.svcMessage
b .earlyFUBAR
.earlyPrefetch:
ldr r0, =.prefetchMessage
b .earlyFUBAR
.earlyData:
ldr r0, =.dataMessage
b .earlyFUBAR
.earlyHyp:
ldr r0, =.hypMessage
b .earlyFUBAR
.earlyIRQ:
ldr r0, =.irqMessage
b .earlyFUBAR
.earlyFIQ:
ldr r0, =.fiqMessage
.earlyFUBAR:
bl ETrWriteString8
.hang:
wfe
b .hang
.earlyVectorTable:
ldr pc, .resetVector
ldr pc, .undefVector
ldr pc, .svcVector
ldr pc, .prefetchVector
ldr pc, .dataVector
ldr pc, .hypVector
ldr pc, .irqVector
ldr pc, .fiqVector
.resetVector:
.word .earlyReset
.undefVector:
.word .earlyUndef
.svcVector:
.word .earlySVC
.prefetchVector:
.word .earlyPrefetch
.dataVector:
.word .earlyData
.hypVector:
.word .earlyHyp
.irqVector:
.word .earlyIRQ
.fiqVector:
.word .earlyFIQ
.earlyVectorTableEnd:
.balign 4
.initMessage:
.asciz "COMROGUEPrestart\n"
.balign 4
.resetMessage:
.asciz "+++ RESET!!!\n"
.balign 4
.undefMessage:
.asciz "+++ UNDEF!!!\n"
.balign 4
.svcMessage:
.asciz "+++ SVC!!!\n"
.balign 4
.prefetchMessage:
.asciz "+++ PREFETCH!!!\n"
.balign 4
.dataMessage:
.asciz "+++ DATA!!!\n"
.balign 4
.hypMessage:
.asciz "+++ HYP!!!\n"
.balign 4
.irqMessage:
.asciz "+++ IRQ!!!\n"
.balign 4
.fiqMessage:
.asciz "+++ FIQ!!!\n"
/*--------------------------------------------------------------------------------------
* Low-level IO functions that are placed here to make them callable from prestart code
*--------------------------------------------------------------------------------------
*/
.section ".prestart.text"
/*
* Writes a 32-bit word of data to a memory-mapped IO port.
*
* Parameters:
* - paPort = Physical address of the IO port to write to.
* - uiData = Data to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Writing to any given IO port may have arbitrary side effects.
*/
.globl llIOWritePA
llIOWritePA:
str r1,[r0]
bx lr
/*
* Reads a 32-bit word of data from a memory-mapped IO port.
*
* Parameters:
* - paPort = Physical address of the IO port we read from.
*
* Returns:
* The word of data read from the IO port.
*
* Side effects:
* Reading from any given IO port may have arbitrary side effects.
*/
.globl llIOReadPA
llIOReadPA:
ldr r0,[r0]
bx lr
/*
* Delays for a certain number of cycles, to allow an IO operation to work.
*
* Parameters:
* - uiTicks = The number of "ticks" to delay.
*
* Returns:
* Nothing.
*/
.globl llIODelayPA
llIODelayPA:
push {lr}
.delaytop:
nop
nop
bl .delayreturn
nop
nop
subs r0, r0, #1
bne .delaytop
pop {lr}
.delayreturn:
bx lr

279
kernel/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.
*/
SEG_LIB_CODE 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).
*/
SEG_LIB_CODE 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_LIB_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/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 */

117
kernel/start.S Normal file
View File

@@ -0,0 +1,117 @@
/*
* 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/internals/layout.h>
#include <comrogue/internals/sctlr.h>
.section ".initHEAD.text"
.globl COMROGUEStart
/* entry: r0 = physical (low-memory) address of STARTUP_INFO1 structure */
COMROGUEStart:
/* initialize the stack pointer */
ldr sp, =.initstack
/* clear init bss */
ldr r4, =vmaInitBss
ldr r5, =vmaFirstFree
mov r6, #0
mov r7, #0
mov r8, #0
mov r9, #0
bl .erase
/* clear resident bss */
ldr r4, =vmaKernelBss
ldr r5, =vmaInitCode
bl .erase
/* initialize trace */
push {r0}
bl TrInit
#if 0
ldr r0, =.msg0
bl TrWriteString8
#endif
pop {r0}
/* copy startup info to our local buffer */
mov r1, r0
ldr r0, =kiStartupInfo
mov r11, r0 /* save for later */
ldr r2, [r1] /* get number of bytes to copy */
ldr ip, =StrCopyMem /* this is needed to branch to a library function */
ldr lr, =.postCopy
mov pc, ip
.postCopy:
#if 0
ldr r0, =.msg1
bl TrWriteString8
#endif
mcr p15, 0, r6, c7, c7, 0 /* clear caches */
mcr p15, 0, r6, c8, c7, 0 /* clear TLB */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, # SCTLR_I /* activate instruction cache */
orr r0, r0, # SCTLR_C /* activate data cache */
mcr p15, 0, r0, c1, c0, 0
/* transfer to C code to continue initialization */
ldr ip, =KiSystemStartup
ldr lr, =.hang
mov pc, ip /* transfer to C code */
.hang:
wfe /* if KiSystemStartup returns, just hang */
b .hang
/* Simple erase routine. Start and end addresses in r4 and r5. r6-r9 assumed to be 0. */
/* Do not touch r0-r2. */
.erase:
cmp r4, r5 /* are we done? */
movhs pc, lr /* yes, return */
stm r4!, {r6-r9} /* stomp 16 bytes */
b .erase
#if 0
.balign 4
.msg0:
.asciz "got here 2\n"
.balign 4
.msg1:
.asciz "got here 3\n"
#endif
.section ".init.bss"
.balign 4
.space 4096
.initstack:

423
kernel/str.c Normal file
View File

@@ -0,0 +1,423 @@
/*
* 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.
*/
SEG_LIB_CODE 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.
*/
SEG_LIB_CODE 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.
*/
SEG_LIB_CODE 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).
*/
SEG_LIB_CODE static PCHAR convert_number_engine8(UINT64 value, PCHAR pchBuf, INT32 nBytes, INT32 nBase,
BOOL fUppercase)
{
static DECLARE_LIB_STRING8_CONST(szDigitsUppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
static DECLARE_LIB_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_LIB_STRING8_CONST(szPadSpace, " ");
static DECLARE_LIB_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.
*/
SEG_LIB_CODE HRESULT StrFormatV8(PFNFORMAT8 pfnFormat, PVOID pArg, PCSTR pszFormat, va_list pargs)
{
static DECLARE_LIB_STRING8_CONST(szFlagChars, "0+- #"); /* flag characters and values */
static const UINT32 SEG_LIB_RODATA auiFlagValues[] =
{ FLAG_ZEROPAD, FLAG_LEFTJUST, FLAG_PLUSSIGN, FLAG_SPACESIGN, FLAG_ALTMODE, 0 };
static DECLARE_LIB_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);
}

273
kernel/strcopymem.S Normal file
View File

@@ -0,0 +1,273 @@
/*-
* 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 */
.section ".lib.text"
/*
* 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, INT32 nBytes); */
/*
* 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.
* - nBytes = 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

290
kernel/trace.c Normal file
View File

@@ -0,0 +1,290 @@
/*
* 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 <stdarg.h>
#include <comrogue/types.h>
#include <comrogue/str.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/llio.h>
#include <comrogue/internals/auxdev.h>
#include <comrogue/internals/gpio.h>
#include <comrogue/internals/16550.h>
/* Hex digits. */
static DECLARE_STRING8_CONST(szHexDigits, "0123456789ABCDEF");
/*
* Initializes the trace functionality (the aux UART).
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Side effects:
* GPIO 14 configured for output from UART1; UART1 initialized to 115200 8N1 and enabled for output.
*/
void TrInit(void)
{
register UINT32 ra;
/* Initialize UART */
llIOWrite(AUX_REG_ENABLE, AUX_ENABLE_MU); /* enable UART1 */
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_CNTL, 0);
llIOWrite(AUX_MU_REG_LCR, U16550_LCR_LENGTH_8|U16550_LCR_PARITY_NONE); /* 8 bits, no parity */
llIOWrite(AUX_MU_REG_MCR, 0);
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_FCR, U16550_FCR_RXCLEAR|U16550_FCR_TXCLEAR|U16550_FCR_LEVEL_14);
llIOWrite(AUX_MU_REG_BAUD, 270); /* 115200 baud */
ra = llIORead(GPFSEL1_REG);
ra &= ~GP_FUNC_MASK(4); /* GPIO 14 - connects to pin 8 on GPIO connector */
ra |= GP_FUNC_BITS(4, GP_PIN_ALT5); /* Alt function 5 - UART1 TxD */
llIOWrite(GPFSEL1_REG, ra);
llIOWrite(GPPUD_REG, 0);
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, GP_BIT(14));
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, 0);
llIOWrite(AUX_MU_REG_CNTL, AUXMU_CNTL_TXENABLE);
}
/*
* Makes sure all trace output has been flushed out the UART.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Side effects:
* UART1 transmitter is empty upon return from this function.
*/
static void flush_trace(void)
{
register UINT32 lsr = llIORead(AUX_MU_REG_LSR);
while (!(lsr & U16550_LSR_TXEMPTY))
lsr = llIORead(AUX_MU_REG_LSR);
}
/*
* Writes a raw character to trace output.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Character written to UART1.
*/
static void write_trace(UINT32 c)
{
flush_trace();
llIOWrite(AUX_MU_REG_THR, c);
}
/*
* Writes a character to trace output, translating newlines.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Either 1 or 2 characters written to UART1.
*/
void TrWriteChar8(CHAR c)
{
if (c == '\n')
write_trace('\r');
write_trace((UINT32)c);
}
/*
* Writes a null-terminated string to trace output. Newlines in the string are translated.
*
* Parameters:
* - psz = Pointer to string to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters in string written to UART1.
*/
void TrWriteString8(PCSTR psz)
{
while (*psz)
TrWriteChar8(*psz++);
}
/*
* Writes the value of a 32-bit word to trace output.
*
* Parameters:
* - uiValue = Value to be written to trace output.
*
* Returns:
* Nothing.
*
* Side effects:
* 8 characters written to UART1.
*/
void TrWriteWord(UINT32 uiValue)
{
register UINT32 uiShift = 32;
do
{
uiShift -= 4;
write_trace(szHexDigits[(uiValue >> uiShift) & 0xF]);
} while (uiShift > 0);
}
/*
* Used by the "trace printf" functions to actually output character data.
*
* Parameters:
* - pDummy = Always points to a NULL value; not used.
* - pchData = Pointer to the data to be written.
* - cchData = The number of characters to be written.
*
* Returns:
* S_OK in all circumstances.
*
* Side effects:
* cchData characters written to UART1.
*/
static HRESULT write_trace_buf8(PPVOID pDummy, PCCHAR pchData, UINT32 cchData)
{
register UINT32 i;
for (i=0; i<cchData; i++)
TrWriteChar8(pchData[i]);
return S_OK;
}
/*
* Formats output to the trace output.
*
* Parameters:
* - pszFormat = Format string for the output, 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.
*
* Side effects:
* Characters written to UART1, the count of which is given by the output code.
*/
HRESULT TrVPrintf8(PCSTR pszFormat, va_list pargs)
{
return StrFormatV8(write_trace_buf8, NULL, pszFormat, pargs);
}
/*
* Formats output to the trace output.
*
* Parameters:
* - pszFormat = Format string for the output, like a printf format string.
* - <args> = Arguments to be substitute dinto the format string.
*
* 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.
*
* Side effects:
* Characters written to UART1, the count of which is given by the output code.
*/
HRESULT TrPrintf8(PCSTR pszFormat, ...)
{
HRESULT hr;
va_list argp;
va_start(argp, pszFormat);
hr = StrFormatV8(write_trace_buf8, NULL, pszFormat, argp);
va_end(argp);
return hr;
}
/*
* Prints an "assertion failed" message to trace output.
*
* Parameters:
* - pszFile = The file name the assertion was declared in.
* - nLine = The line number the assertion was declared at.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters written to UART1.
*/
void TrAssertFailed(PCSTR pszFile, INT32 nLine)
{
static DECLARE_STRING8_CONST(szMessage, "*** ASSERTION FAILED at %s:%d\n");
TrPrintf8(szMessage, pszFile, nLine);
}
/*
* Puts the CPU into a loop where it blinks the green ACTIVITY light forever.
*
* Parameters:
* None.
*
* Returns:
* DOES NOT RETURN!
*
* Side effects:
* GPIO 16 configured for output and turns on and off indefinitely.
*/
void TrInfiniBlink(void)
{
register UINT32 ra;
flush_trace();
ra = llIORead(GPFSEL1_REG);
ra &= GP_FUNC_MASK(6); /* GPIO 16 - connects to green ACTIVITY LED */
ra |= GP_FUNC_BITS(6, GP_PIN_OUTPUT); /* output in all circumstances */
llIOWrite(GPFSEL1_REG, ra);
for(;;)
{
llIOWrite(GPSET0_REG, GP_BIT(16));
llIODelay(0x100000);
llIOWrite(GPCLR0_REG, GP_BIT(16));
llIODelay(0x100000);
}
}