Initial checkin of COMROGUE source after having gotten initial memory map right
This commit is contained in:
77
kernel/Makefile
Normal file
77
kernel/Makefile
Normal 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
245
kernel/collect_startup.c
Normal 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
134
kernel/comrogue-kernel.lds
Normal 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
479
kernel/divide.S
Normal 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
398
kernel/early_mm.c
Normal 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
245
kernel/early_trace.c
Normal 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
81
kernel/intlib.c
Normal 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
94
kernel/kistart.c
Normal 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
96
kernel/lowlevel.S
Normal 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
271
kernel/prestart.S
Normal 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
279
kernel/qdivrem.c
Normal 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
71
kernel/quad.h
Normal 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
117
kernel/start.S
Normal 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
423
kernel/str.c
Normal 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
273
kernel/strcopymem.S
Normal 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
290
kernel/trace.c
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user