Browse Source
cpu/mips32r2_common adds base architecture support for mips32r2 cores it can be built in it own right as a 'CPU', but is dependant on a bootloader (like u-boot) to have bootstrapped the system, this has been tested on a 'malta' FPGA system (BOARD=mips-malta) with various mips32r2 compliant cores (interAptiv, P5600, etc).pr/rotary

10 changed files with 1355 additions and 0 deletions
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
#include <mips/m32c0.h> |
||||
#include <mips/regdef.h> |
||||
#include <mips/asm.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
|
||||
#include "periph/uart.h" |
||||
#include "periph/timer.h" |
||||
#include "arch/panic_arch.h" |
||||
#include "kernel_init.h" |
||||
#include "cpu.h" |
||||
#include "board.h" |
||||
|
||||
void mips_start(void); |
||||
|
||||
extern void _fini(void); |
||||
extern void atexit(void (*)(void)); |
||||
extern void _init(void); |
||||
extern void exit(int); |
||||
|
||||
#ifdef FLASH_XIP |
||||
extern char _rom_data_copy __attribute__((section("data"))); |
||||
extern char _fdata __attribute__((section("data"))); |
||||
extern char _edata __attribute__((section("data"))); |
||||
#endif |
||||
|
||||
/*
|
||||
* Note the mips toolchain crt expects to jump to main but RIOT wants the user |
||||
* code to start at main for some perverse reason, but thankfully the crt |
||||
* does provide this hook function which gets called fairly close to the jump |
||||
* to main, thus if we finish off the job of the crt here and never returns |
||||
* we can support this madness. |
||||
*/ |
||||
void software_init_hook(void) |
||||
{ |
||||
#ifdef FLASH_XIP |
||||
/* copy initialised data from its LMA to VMA */ |
||||
memcpy(&_fdata, &_rom_data_copy, (int)&_edata - (int)&_fdata); |
||||
#endif |
||||
|
||||
atexit(_fini); |
||||
_init(); |
||||
|
||||
mips_start(); |
||||
|
||||
exit(-1); |
||||
} |
||||
|
||||
|
||||
void mips_start(void) |
||||
{ |
||||
board_init(); |
||||
|
||||
#if MODULE_NEWLIB |
||||
#error "This Port is designed to work with the (newlib) C library provided with the mips sdk toolchain" |
||||
#endif |
||||
|
||||
/* kernel_init */ |
||||
kernel_init(); |
||||
} |
||||
|
||||
void panic_arch(void) |
||||
{ |
||||
printf("\nPANIC!\n"); |
||||
assert(0); |
||||
while (1) { |
||||
} |
||||
} |
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup cpu_mips32r2_commom MIPS32R2 Common |
||||
* @ingroup cpu |
||||
* @brief Common implementations and headers for mips32r2 compliant devices |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Common implementations and headers for mips32r2 compliant devices |
||||
* |
||||
* @author Neil Jones <neil.jones@imgtec.com> |
||||
*/ |
||||
|
||||
#ifndef CPU_H_ |
||||
#define CPU_H_ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include "irq.h" |
||||
|
||||
/**
|
||||
* @brief Print the last instruction's address |
||||
* |
||||
* @todo: Not supported |
||||
*/ |
||||
static inline void cpu_print_last_instruction(void) |
||||
{ |
||||
/* This function must exist else RIOT won't compile */ |
||||
} |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
/** @} */ |
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
#ifndef _CPU_CONF_H_ |
||||
#define _CPU_CONF_H_ |
||||
|
||||
/**
|
||||
* @defgroup cpu_mips32r2_commom MIPS32R2 Common |
||||
* @ingroup cpu |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Common CPU definitions for mip32r2 compatable devices. |
||||
* |
||||
* @author Neil Jones <neil.jones@imgtec.com> |
||||
*/ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Configuration of default stack sizes |
||||
* |
||||
* printf takes a pretty tortured route through the C lib |
||||
* then via UHI syscall exception to end up at the UART |
||||
* driver. |
||||
* |
||||
* When debugging timer code we get printfs on the idle threads |
||||
* stack which can easily blow its limits. |
||||
* |
||||
* Note code must be compiled at -Os with these values, using -O0 |
||||
* you'll overflow these stacks. |
||||
* |
||||
* NO ISR stack is in use yet, interrupt use the current running stack |
||||
* hence the big-ish default stack size. |
||||
* @{ |
||||
*/ |
||||
|
||||
#ifndef THREAD_EXTRA_STACKSIZE_PRINTF |
||||
#define THREAD_EXTRA_STACKSIZE_PRINTF (1024) |
||||
#endif |
||||
|
||||
#ifndef THREAD_STACKSIZE_DEFAULT |
||||
#define THREAD_STACKSIZE_DEFAULT (2048) |
||||
#endif |
||||
|
||||
#ifndef THREAD_STACKSIZE_IDLE |
||||
#ifdef NDEBUG |
||||
#define THREAD_STACKSIZE_IDLE (512) |
||||
#else |
||||
#define THREAD_STACKSIZE_IDLE (512 + THREAD_EXTRA_STACKSIZE_PRINTF) |
||||
#endif |
||||
#endif |
||||
|
||||
#define ISR_STACKSIZE (0) |
||||
/** @} */ |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
/** @} */ |
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/* This file must exist to get timer code to build */ |
||||
|
||||
/* No peripherals I/O via JTAG or Bootloader using UHI */ |
||||
|
||||
/*
|
||||
* Note mips32r2_common can be selected in its own right as a CPU |
||||
* for testing on PFGA systems (like BOARD=mips-malta) with limited |
||||
* or no peripherals |
||||
*/ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
#include <mips/m32c0.h> |
||||
#include "arch/irq_arch.h" |
||||
|
||||
|
||||
unsigned int irq_arch_enable(void) |
||||
{ |
||||
unsigned int status; |
||||
|
||||
__asm__ volatile ("ei %0" : "=r" (status)); |
||||
return status; |
||||
} |
||||
|
||||
unsigned int irq_arch_disable(void) |
||||
{ |
||||
unsigned int status; |
||||
|
||||
__asm__ volatile ("di %0" : "=r" (status)); |
||||
return status; |
||||
} |
||||
|
||||
void irq_arch_restore(unsigned int state) |
||||
{ |
||||
if (state & SR_IE) { |
||||
mips32_bs_c0(C0_STATUS, SR_IE); |
||||
} |
||||
else { |
||||
mips32_bc_c0(C0_STATUS, SR_IE); |
||||
} |
||||
} |
||||
|
||||
int irq_arch_in(void) |
||||
{ |
||||
return (mips32_get_c0(C0_STATUS) & SR_EXL) != 0; |
||||
} |
@ -0,0 +1,151 @@
|
||||
/* |
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the copyright holder 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 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. |
||||
*/ |
||||
|
||||
|
||||
/* ************ PLEASE READ ME !!!! **************** |
||||
|
||||
This file is missing from $MIPS_ELF_ROOT/share/mips/hal |
||||
|
||||
Future toolchain versions will have this file included and this local copy will |
||||
be no longer needed. |
||||
|
||||
Note the above copyright/license is 3 Clause BSD and as such is compatible with LGPLv2.1 |
||||
as such we grant licensing this file under LGPLv2.1 (See the file LICENSE in the top level |
||||
directory for more details) as well. |
||||
|
||||
Thanks for reading. |
||||
*/ |
||||
|
||||
.set nomips16
|
||||
#include <mips/asm.h> |
||||
#include <mips/regdef.h> |
||||
#include <mips/m32c0.h> |
||||
#include <mips/hal.h> |
||||
#include <mips/endian.h> |
||||
|
||||
# |
||||
# FUNCTION: _dsp_save |
||||
# |
||||
# DESCRIPTION: save the DSP context. |
||||
# |
||||
# RETURNS: int |
||||
# |
||||
# 0: No context saved |
||||
# CTX_*: Type of conext stored |
||||
# |
||||
LEAF(_dsp_save) |
||||
PTR_S zero, LINKCTX_NEXT(a0) |
||||
move v0, zero |
||||
|
||||
# Test for DSP support |
||||
mfc0 t0, C0_CONFIG3 |
||||
ext t0, t0, CFG3_DSPP_SHIFT, 1 |
||||
beqz t0, 1f |
||||
|
||||
# Test for DSP enabled |
||||
mfc0 t0, C0_STATUS |
||||
ext t0, t0, SR_MX_SHIFT, 1 |
||||
beqz t0, 1f |
||||
|
||||
lui v0, %hi(LINKCTX_TYPE_DSP) |
||||
addiu v0, v0, %lo(LINKCTX_TYPE_DSP) |
||||
.set push
|
||||
.set dsp
|
||||
rddsp t1 |
||||
mfhi t2, $ac1 |
||||
mflo t3, $ac1 |
||||
mfhi t4, $ac2 |
||||
mflo t5, $ac2 |
||||
mfhi t6, $ac3 |
||||
mflo t7, $ac3 |
||||
.set pop
|
||||
sw t1, DSPCTX_DSPC(a0) |
||||
sw t2, DSPCTX_HI1(a0) |
||||
sw t3, DSPCTX_LO1(a0) |
||||
sw t4, DSPCTX_HI2(a0) |
||||
sw t5, DSPCTX_LO2(a0) |
||||
sw t6, DSPCTX_HI3(a0) |
||||
sw t7, DSPCTX_LO3(a0) |
||||
REG_S v0, LINKCTX_ID(a0) |
||||
1: |
||||
jr ra |
||||
END(_dsp_save) |
||||
|
||||
# |
||||
# FUNCTION: _dsp_load |
||||
# |
||||
# DESCRIPTION: load the DSP context. |
||||
# |
||||
# RETURNS: int |
||||
# |
||||
# 0: Unrecognised context |
||||
# CTX_*: Type of context restored |
||||
# |
||||
LEAF(_dsp_load) |
||||
REG_L v0, LINKCTX_ID(a0) |
||||
lui v1, %hi(LINKCTX_TYPE_DSP) |
||||
addiu v1, v1, %lo(LINKCTX_TYPE_DSP) |
||||
bne v0,v1,1f |
||||
|
||||
# Test for DSP support |
||||
mfc0 t0, C0_CONFIG3 |
||||
ext t0, t0, CFG3_DSPP_SHIFT, 1 |
||||
beqz t0, 1f |
||||
|
||||
# Force on DSP |
||||
di t3 |
||||
ehb |
||||
or t3, t3, SR_MX |
||||
mtc0 t3, C0_STATUS |
||||
ehb |
||||
|
||||
lw t1, DSPCTX_DSPC(a0) |
||||
lw t2, DSPCTX_HI1(a0) |
||||
lw t3, DSPCTX_LO1(a0) |
||||
lw t4, DSPCTX_HI2(a0) |
||||
lw t5, DSPCTX_LO2(a0) |
||||
lw t6, DSPCTX_HI3(a0) |
||||
lw t7, DSPCTX_LO3(a0) |
||||
.set push
|
||||
.set dsp
|
||||
wrdsp t1 |
||||
mthi t2, $ac1 |
||||
mtlo t3, $ac1 |
||||
mthi t4, $ac2 |
||||
mtlo t5, $ac2 |
||||
mthi t6, $ac3 |
||||
mtlo t7, $ac3 |
||||
.set pop
|
||||
jr ra |
||||
1: |
||||
# Don't recognise this context, fail |
||||
move v0, zero |
||||
jr ra |
||||
END(_dsp_load) |
@ -0,0 +1,288 @@
|
||||
/* |
||||
* Copyright 2014-2015, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the copyright holder 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 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. |
||||
*/ |
||||
|
||||
|
||||
/* ************ PLEASE READ ME !!!! **************** |
||||
|
||||
This file is a copy of the mips_excpt_entry.S from $MIPS_ELF_ROOT/share/mips/hal |
||||
(from the 2016.05-03 version) with a single modification, we add a global flag |
||||
'__exception_restore' so we can jump to the restore code sequence from C. |
||||
|
||||
Future toolchain versions will have this change included and this file will |
||||
be no longer needed. |
||||
|
||||
Note the above copyright/license is 3 Clause BSD and as such is compatible with LGPLv2.1 |
||||
as such we grant licensing this file under LGPLv2.1 (See the file LICENSE in the top level |
||||
directory for more details) as well. |
||||
|
||||
Thanks for reading. |
||||
*/ |
||||
|
||||
|
||||
# Keep each function in a separate named section |
||||
#define _FUNCTION_SECTIONS_ |
||||
.set nomips16
|
||||
|
||||
#include <mips/asm.h> |
||||
#include <mips/regdef.h> |
||||
#include <mips/cpu.h> |
||||
#include <mips/hal.h> |
||||
|
||||
# Context size, adjusted for ABI parameter area |
||||
#define ADJ (NARGSAVE * SZARG) |
||||
# Round up to 16-byte boundary (maximum stack alignment required for any |
||||
# supported ABI) |
||||
#define CTX_SIZEROUND ((CTX_SIZE + ALSZ) & ALMASK) |
||||
#define CTX_SIZEADJ (CTX_SIZEROUND + ADJ) |
||||
|
||||
#define e_ISR s1 |
||||
#define e_CR s3 |
||||
#define e_BADV s4 |
||||
#define e_SR s5 |
||||
#define e_EPC s6 |
||||
#define e_RA s7 |
||||
|
||||
# DESCRIPTION: Exception entry point. This is small because it must go at |
||||
# EBASE+0x180. It saves enough context to chain onwards to |
||||
# __exception_save. |
||||
# |
||||
LEAF(__exception_entry) |
||||
.set push
|
||||
.set noat
|
||||
.weak _mips_tlb_refill
|
||||
_mips_tlb_refill = __exception_save |
||||
__tlb_refill_loop: |
||||
# Support an alternative entry point at the start of the exception |
||||
# vector. Since the exception vector is normally placed first |
||||
# in the link map this allows a user to start execution from the |
||||
# same address that an executable is loaded to. |
||||
LA k1, __first_boot |
||||
lw k1, 0(k1) |
||||
beqz k1, 1f |
||||
# The start code is responsible for clearing __first_boot prior |
||||
# to installing the exception handlers. |
||||
j _start |
||||
1: |
||||
LA k1, _mips_tlb_refill |
||||
beqz k1, __tlb_refill_loop |
||||
jr k1 |
||||
|
||||
.org 0x80
|
||||
.weak _mips_xtlb_refill
|
||||
_mips_xtlb_refill = __exception_save |
||||
__xtlb_refill_loop: |
||||
LA k1, _mips_xtlb_refill |
||||
beqz k1, __xtlb_refill_loop |
||||
jr k1 |
||||
|
||||
.org 0x100
|
||||
.weak _mips_cache_error
|
||||
__cache_error_loop: |
||||
LA k1, _mips_cache_error |
||||
beqz k1, __cache_error_loop |
||||
jr k1 |
||||
|
||||
.org 0x180
|
||||
# Free up k1, defering sp adjustment until later |
||||
REG_S k1, (-CTX_SIZEROUND + CTX_K1)(sp) |
||||
|
||||
# Use k1 to invoke __exception_save |
||||
LA k1, _mips_general_exception |
||||
jr k1 |
||||
.set pop
|
||||
END(__exception_entry) |
||||
|
||||
# |
||||
# FUNCTION: __exception_save |
||||
# |
||||
# DESCRIPTION: Exception context save. Save the context, then fake up a call |
||||
# frame. |
||||
# |
||||
ANESTED(__exception_save, _mips_general_exception, CTX_SIZEADJ, zero) |
||||
.globl __exception_save;
|
||||
.globl __exception_restore;
|
||||
.set push
|
||||
.set noat
|
||||
|
||||
# k1 is already saved, so use it to save the users sp |
||||
move k1, sp |
||||
# Finally adjust sp |
||||
PTR_ADDU sp, sp, -CTX_SIZEADJ # This should be picked up by the backtracer |
||||
|
||||
# Save context |
||||
REG_S $1, CTX_REG(1) + ADJ(sp) |
||||
REG_S $2, CTX_REG(2) + ADJ(sp) |
||||
REG_S $3, CTX_REG(3) + ADJ(sp) |
||||
REG_S $4, CTX_REG(4) + ADJ(sp) |
||||
REG_S $5, CTX_REG(5) + ADJ(sp) |
||||
REG_S $6, CTX_REG(6) + ADJ(sp) |
||||
REG_S $7, CTX_REG(7) + ADJ(sp) |
||||
REG_S $8, CTX_REG(8) + ADJ(sp) |
||||
REG_S $9, CTX_REG(9) + ADJ(sp) |
||||
REG_S $10, CTX_REG(10) + ADJ(sp) |
||||
REG_S $11, CTX_REG(11) + ADJ(sp) |
||||
REG_S $12, CTX_REG(12) + ADJ(sp) |
||||
REG_S $13, CTX_REG(13) + ADJ(sp) |
||||
REG_S $14, CTX_REG(14) + ADJ(sp) |
||||
REG_S $15, CTX_REG(15) + ADJ(sp) |
||||
REG_S $16, CTX_REG(16) + ADJ(sp) |
||||
REG_S $17, CTX_REG(17) + ADJ(sp) |
||||
REG_S $18, CTX_REG(18) + ADJ(sp) |
||||
REG_S $19, CTX_REG(19) + ADJ(sp) |
||||
REG_S $20, CTX_REG(20) + ADJ(sp) |
||||
REG_S $21, CTX_REG(21) + ADJ(sp) |
||||
REG_S $22, CTX_REG(22) + ADJ(sp) |
||||
REG_S $23, CTX_REG(23) + ADJ(sp) |
||||
REG_S $24, CTX_REG(24) + ADJ(sp) |
||||
REG_S $25, CTX_REG(25) + ADJ(sp) |
||||
REG_S $26, CTX_REG(26) + ADJ(sp) |
||||
# k1/$27 has already been saved |
||||
REG_S $28, CTX_REG(28) + ADJ(sp) |
||||
REG_S k1, CTX_REG(29) + ADJ(sp) # Use saved sp from earlier |
||||
REG_S $30, CTX_REG(30) + ADJ(sp) |
||||
REG_S $31, CTX_REG(31) + ADJ(sp) |
||||
PTR_S $0, CTX_LINK + ADJ(sp) # Clear the link field |
||||
|
||||
#if (__mips_isa_rev < 6) |
||||
mfhi $9 |
||||
mflo $10 |
||||
REG_S $9, CTX_HI0 + ADJ(sp) |
||||
REG_S $10, CTX_LO0 + ADJ(sp) |
||||
#endif |
||||
|
||||
# Trick the backtracer into stepping back to the point where the exception |
||||
# occurred. |
||||
PTR_MFC0 ra, C0_EPC |
||||
mfc0 e_CR, C0_CR |
||||
REG_S ra, CTX_EPC + ADJ(sp) |
||||
|
||||
# Finish storing the rest of the CP0 registers |
||||
PTR_MFC0 $9, C0_BADVADDR |
||||
REG_S $9, CTX_BADVADDR + ADJ(sp) |
||||
sw e_CR, CTX_CAUSE + ADJ(sp) |
||||
|
||||
move $11, $0 |
||||
move $12, $0 |
||||
mfc0 $9, C0_CONFIG3 |
||||
ext $10, $9, CFG3_BP_SHIFT, 1 |
||||
beqz $10, 1f |
||||
mfc0 $11, C0_BADPINSTR |
||||
1: |
||||
ext $9, $9, CFG3_BI_SHIFT, 1 |
||||
beqz $9, 1f |
||||
mfc0 $12, C0_BADINSTR |
||||
1: |
||||
sw $11, CTX_BADPINSTR + ADJ(sp) |
||||
sw $12, CTX_BADINSTR + ADJ(sp) |
||||
|
||||
# Start computing the address of the context for a0 |
||||
move a0, sp |
||||
|
||||
# Clear EXL. Exceptions can now nest. |
||||
mfc0 e_SR, C0_SR |
||||
sw e_SR, CTX_STATUS + ADJ(sp) |
||||
lui $9, %hi(~SR_EXL) |
||||
addiu $9, $9, %lo(~SR_EXL) |
||||
and e_SR, e_SR, $9 |
||||
mtc0 e_SR, C0_SR |
||||
|
||||
# Manually set up the return address to restore the context below |
||||
LA ra, __exception_restore |
||||
# Extract the cause code |
||||
and a1, e_CR, CR_XMASK |
||||
|
||||
# Finish computing the address of the context for a0 |
||||
addiu a0, a0, ADJ |
||||
|
||||
# Shift exception number down into expected range |
||||
srl a1, a1, 2 |
||||
|
||||
# Call the handler, indirect through t9 albeit not for any specific |
||||
# reason |
||||
LA t9, _mips_handle_exception |
||||
jr t9 |
||||
|
||||
# Return point from handler |
||||
# Load context |
||||
# now a function on its own, note save code just falls through. |
||||
|
||||
|
||||
__exception_restore: |
||||
|
||||
#if (__mips_isa_rev < 6) |
||||
REG_L $9, CTX_HI0 + ADJ(sp) |
||||
REG_L $10, CTX_LO0 + ADJ(sp) |
||||
mthi $9 |
||||
mtlo $10 |
||||
#endif |
||||
|
||||
REG_L $1, CTX_REG(1) + ADJ(sp) |
||||
REG_L $2, CTX_REG(2) + ADJ(sp) |
||||
REG_L $3, CTX_REG(3) + ADJ(sp) |
||||
REG_L $4, CTX_REG(4) + ADJ(sp) |
||||
REG_L $5, CTX_REG(5) + ADJ(sp) |
||||
REG_L $6, CTX_REG(6) + ADJ(sp) |
||||
REG_L $7, CTX_REG(7) + ADJ(sp) |
||||
REG_L $8, CTX_REG(8) + ADJ(sp) |
||||
REG_L $9, CTX_REG(9) + ADJ(sp) |
||||
REG_L $10, CTX_REG(10) + ADJ(sp) |
||||
REG_L $11, CTX_REG(11) + ADJ(sp) |
||||
REG_L $12, CTX_REG(12) + ADJ(sp) |
||||
REG_L $13, CTX_REG(13) + ADJ(sp) |
||||
REG_L $14, CTX_REG(14) + ADJ(sp) |
||||
REG_L $15, CTX_REG(15) + ADJ(sp) |
||||
REG_L $16, CTX_REG(16) + ADJ(sp) |
||||
REG_L $17, CTX_REG(17) + ADJ(sp) |
||||
REG_L $18, CTX_REG(18) + ADJ(sp) |
||||
REG_L $19, CTX_REG(19) + ADJ(sp) |
||||
REG_L $20, CTX_REG(20) + ADJ(sp) |
||||
REG_L $21, CTX_REG(21) + ADJ(sp) |
||||
REG_L $22, CTX_REG(22) + ADJ(sp) |
||||
REG_L $23, CTX_REG(23) + ADJ(sp) |
||||
REG_L $24, CTX_REG(24) + ADJ(sp) |
||||
REG_L $25, CTX_REG(25) + ADJ(sp) |
||||
# $26/K0 and $27/K1 are restored with interrupts disabled |
||||
REG_L $28, CTX_REG(28) + ADJ(sp) |
||||
# $29/SP is restored last |
||||
REG_L $30, CTX_REG(30) + ADJ(sp) |
||||
REG_L $31, CTX_REG(31) + ADJ(sp) |
||||
di |
||||
lw k0, CTX_STATUS + ADJ(sp) |
||||
REG_L k1, CTX_EPC + ADJ(sp) |
||||
mtc0 k0, C0_SR |
||||
PTR_MTC0 k1, C0_EPC |
||||
ehb |
||||
REG_L k0, CTX_K0 + ADJ(sp) |
||||
REG_L k1, CTX_K1 + ADJ(sp) |
||||
REG_L sp, CTX_SP + ADJ(sp) |
||||
# Return from exception |
||||
eret |
||||
.set pop
|
||||
END(__exception_save) |
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup cpu_mips32r2_common |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief common periph/pm functions |
||||
* |
||||
* @author Neil Jones <neil.jones@imgtec.com> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <mips/m32c0.h> |
||||
#include "periph/pm.h" |
||||
|
||||
#ifndef FEATURES_PERIPH_PM |
||||
void pm_set_lowest(void) |
||||
{ |
||||
/* Dont wait if interrupts are not enabled - we would never return!*/ |
||||
if (mips32_get_c0(C0_STATUS) & SR_IE) { |
||||
__asm volatile ("wait"); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
void pm_off(void) |
||||
{ |
||||
/* No Generic Power off Mechanism */ |
||||
} |
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
#include <mips/cpu.h> |
||||
#include <mips/m32c0.h> |
||||
#include <mips/regdef.h> |
||||
#include <mips/asm.h> |
||||
#include <string.h> |
||||
|
||||
#include <periph/timer.h> |
||||
#include "cpu_conf.h" |
||||
#include <stdio.h> |
||||
#include "sched.h" |
||||
#include "thread.h" |
||||
#include "board.h" |
||||
#include "irq.h" |
||||
#include "timex.h" |
||||
#include "div.h" |
||||
|
||||
#include <sys/time.h> |
||||
|
||||
/*
|
||||
* setting TIMER_ACCURACY_SHIFT lower will improve accuracy |
||||
* at the cost of more regular interrupts (hence less power efficient). |
||||
* */ |
||||
#define TIMER_ACCURACY_SHIFT (10) |
||||
#define TIMER_ACCURACY (1 << TIMER_ACCURACY_SHIFT) |
||||
#define CHANNELS (3) |
||||
|
||||
/* TICKS_PER_US must be set in the board file */ |
||||
#ifndef TICKS_PER_US |
||||
#error "Please set TICK_PER_US in your board file" |
||||
#endif |
||||
|
||||
/*
|
||||
* The base MIPS count / compare timer is fixed frequency at core clock / 2 |
||||
* and is pretty basic This timer is currently only supported in Vectored |
||||
* Interrupt Mode (VI), EIC mode is not supported yet. |
||||
* |
||||
* RIOT's xtimer expects the timer to operate at 1MHZ or any 2^n multiple or |
||||
* factor of this, thus we maintain a software timer which counts at 1MHz. |
||||
* This is not particularly power efficient and may add latency too. |
||||
* |
||||
* If other SoC specific timers are available which are more flexible then |
||||
* it is advised to use them, this timer is a fallback version |
||||
* that should work on all MIPS implementations. |
||||
* |
||||
*/ |
||||
|
||||
static timer_isr_ctx_t timer_isr_ctx; |
||||
volatile unsigned int counter; |
||||
volatile unsigned int compares[CHANNELS]; |
||||
static volatile int spurious_int; |
||||
|
||||
/*
|
||||
* The mips toolchain C library does not implement gettimeofday() |
||||
* |
||||
* implement it here using the timer. |
||||
* |
||||
*/ |
||||
int gettimeofday(struct timeval *__restrict __p, void *__restrict __tz) |
||||
{ |
||||
uint64_t now = counter * US_PER_MS; |
||||
__p->tv_sec = div_u64_by_1000000(now); |
||||
__p->tv_usec = now - (__p->tv_sec * US_PER_SEC); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg) |
||||
{ |
||||
assert(dev == 0); |
||||
|
||||
(void)freq; /*Cannot adjust Frequency */ |
||||
|
||||
timer_isr_ctx.cb = cb; |
||||
timer_isr_ctx.arg = arg; |
||||
|
||||
/* Clear down soft counters */ |
||||
memset((void *)compares, 0, sizeof(compares)); |
||||
|
||||
counter = (1 << TIMER_ACCURACY_SHIFT); |
||||
|
||||
/* Set compare up */ |
||||
mips_setcompare(mips_getcount() + TICKS_PER_US * TIMER_ACCURACY); |
||||
|
||||
/* Start the timer if stopped */ |
||||
mips32_bc_c0(C0_CAUSE, CR_DC); |
||||
|
||||
/* Enable Timer Interrupts */ |
||||
mips32_bs_c0(C0_STATUS, SR_HINT5); |
||||
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int timer_set(tim_t dev, int channel, unsigned int timeout) |
||||
{ |
||||
assert(dev == 0); |
||||
assert(channel < CHANNELS); |
||||
|
||||
timeout >>= TIMER_ACCURACY_SHIFT; |
||||
timeout <<= TIMER_ACCURACY_SHIFT; |
||||
|
||||
uint32_t status = irq_arch_disable(); |
||||
compares[channel] = counter + timeout; |
||||
irq_arch_restore(status); |
||||
|
||||
return channel; |
||||
} |
||||
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int value) |
||||
{ |
||||
assert(dev == 0); |
||||
assert(channel < CHANNELS); |
||||
|
||||
value >>= TIMER_ACCURACY_SHIFT; |
||||
value <<= TIMER_ACCURACY_SHIFT; |
||||
|
||||
uint32_t status = irq_arch_disable(); |
||||
compares[channel] = value; |
||||
irq_arch_restore(status); |
||||
|
||||
return channel; |
||||
} |
||||
|
||||
int timer_clear(tim_t dev, int channel) |
||||
{ |
||||
assert(dev == 0); |
||||
assert(channel < CHANNELS); |
||||
|
||||
uint32_t status = irq_arch_disable(); |
||||
compares[channel] = 0; |
||||
irq_arch_restore(status); |
||||
|
||||
return channel; |
||||
} |
||||
|
||||
unsigned int timer_read(tim_t dev) |
||||
{ |
||||
assert(dev == 0); |
||||
|
||||
return counter; |
||||
} |
||||
|
||||
void timer_start(tim_t dev) |
||||
{ |
||||
mips32_bc_c0(C0_CAUSE, CR_DC); |
||||
} |
||||
|
||||
void timer_stop(tim_t dev) |
||||
{ |
||||
mips32_bs_c0(C0_CAUSE, CR_DC); |
||||
} |
||||
|
||||
void timer_irq_enable(tim_t dev) |
||||
{ |
||||
mips32_bs_c0(C0_STATUS, SR_HINT5); |
||||
} |
||||
|
||||
void timer_irq_disable(tim_t dev) |
||||
{ |
||||
mips32_bc_c0(C0_STATUS, SR_HINT5); |
||||
} |
||||
|
||||
|
||||
void __attribute__ ((interrupt("vector=hw5"))) _mips_isr_hw5(void) |
||||
{ |
||||
register int cr = mips_getcr(); |
||||
|
||||
if (cr & CR_TI) { |
||||
uint32_t status = irq_arch_disable(); |
||||
counter += TIMER_ACCURACY; |
||||
irq_arch_restore(status); |
||||
|
||||
if (counter == compares[0]) { |
||||
/*
|
||||
* The Xtimer code expects the ISR to take some time |
||||
* but our counter is a fake software one, so bump it a |
||||
* bit to give the impression some time elapsed in the ISR. |
||||
* Without this the callback ( _shoot(timer) on xtimer_core.c ) |
||||
* never fires. |
||||
*/ |
||||
counter += TIMER_ACCURACY; |
||||
timer_isr_ctx.cb(timer_isr_ctx.arg, 0); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
if (counter == compares[1]) { |
||||
timer_isr_ctx.cb(timer_isr_ctx.arg, 1); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
if (counter == compares[2]) { |
||||
timer_isr_ctx.cb(timer_isr_ctx.arg, 2); |
||||
|
||||
if (sched_context_switch_request) { |
||||
thread_yield(); |
||||
} |
||||
} |
||||
|
||||
mips_setcompare(mips_getcount() + TICKS_PER_US * TIMER_ACCURACY); |
||||
|
||||
} |
||||
else { |
||||
spurious_int++; |
||||
} |
||||
} |
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2016, Imagination Technologies Limited and/or its |
||||
* affiliated group companies. |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
#include <mips/cpu.h> |
||||
#include <mips/hal.h> |
||||
#include <unistd.h> |
||||
#include <sys/stat.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include "thread.h" |
||||
#include "cpu.h" |
||||
#include "irq.h" |
||||
#include "cpu_conf.h" |
||||
#include "periph_conf.h" /* for debug uart number */ |
||||
#include "periph/uart.h" |
||||
#include "malloc.h" |
||||
|
||||
#define STACK_END_PAINT (0xdeadc0de) |
||||
#define C0_STATUS_EXL (2) |
||||
#define PADDING (16) |
||||
#define MICROMIPS_ISA_MODE (1) |
||||
#define M32_SYSCALL (0xC) |
||||
#define M32_SYSCALL_MASK (0xfc00003f) |
||||
|
||||
/*
|
||||
* note the major 16bits of a 32bit MicroMIPS opcode appear first in the |
||||
* instruction stream |
||||
*/ |
||||
#define MM_SYSCALL (0x8B7C0000) |
||||
#define MM_SYSCALL_MASK (0xfffffc00) |
||||
|
||||
|
||||
#ifdef MIPS_HARD_FLOAT |
||||
/* pointer to the current and old fpu context for lazy context switching */ |
||||
static struct fp64ctx *currentfpctx; /* fpu context of current running task */ |
||||
static struct fp64ctx *oldfpctx; /* fpu context of last task that executed fpu */ |
||||
#endif |
||||
|
||||
/*
|
||||
* Stack Layout, note struct gpctx is defined in |
||||
* $MIPS_ELF_ROOT/mips-mti-elf/include/mips/hal.h |
||||
* |
||||
* Top Of Stack |
||||
* --------------- |
||||
* | | |
||||
* | User stack | |
||||
* | | |
||||
* --------------- <--- gpctx->sp |
||||
* | | |
||||
* | gpctx | |
||||
* | | |
||||
* --------------- |
||||
* | 16 byte pad | |
||||
* --------------- <--- sched_active_thread->sp |
||||
*/ |
||||
|
||||
char *thread_arch_stack_init(thread_task_func_t task_func, void *arg, |
||||
void *stack_start, int stack_size) |
||||
{ |
||||
/* make sure it is aligned to 8 bytes this is a requirement of the O32 ABI */ |
||||
uintptr_t *p = (uintptr_t *)(((long)(stack_start) + stack_size) & ~7); |
||||
uintptr_t *fp; |
||||
|
||||
/* paint */ |
||||
p--; |
||||
*p-- = STACK_END_PAINT; |
||||
|
||||
/* prepare stack for __exception_restore() */ |
||||
fp = p; |
||||
p -= sizeof(struct gpctx) / sizeof(unsigned int); |
||||
|
||||
struct gpctx *initial_ctx = (struct gpctx *)p; |
||||
initial_ctx->a[0] = (reg_t)arg; |
||||
initial_ctx->status = mips32_get_c0(C0_STATUS) | SR_IE; /* Enable interrupts */ |
||||
__asm volatile ("sw $gp, 0(%0)" : : "r" (&initial_ctx->gp)); |
||||
initial_ctx->epc = (reg_t)task_func; |
||||
initial_ctx->ra = (reg_t)sched_task_exit; |
||||
initial_ctx->sp = (reg_t)fp; |
||||
initial_ctx->link = (struct linkctx *)NULL; |
||||
|
||||
#ifdef MIPS_MICROMIPS |
||||
initial_ctx->epc |= MICROMIPS_ISA_MODE; |
||||
initial_ctx->ra |= MICROMIPS_ISA_MODE; |
||||
#endif |
||||
|
||||
#ifdef MIPS_HARD_FLOAT |
||||
/*
|
||||
* Disable FPU so we get an exception on first use to allow |
||||
* Lazy FPU context save and restore |
||||
*/ |
||||
initial_ctx->status &= ~SR_CU1; |
||||
initial_ctx->status |= SR_FR; /*use double width FPU */ |
||||
#endif |
||||
/*
|
||||
* note the -4 (-16 bytes) as the toolchain exception handling code |
||||
* adjusts the sp for alignment |
||||
*/ |
||||
p -= PADDING/sizeof(unsigned int); |
||||
|
||||
return (void *)p; |
||||
} |
||||
|
||||
void thread_arch_stack_print(void) |
||||
{ |
||||
uintptr_t *sp = (void *)sched_active_thread->sp; |
||||
|
||||
printf("Stack trace:\n"); |
||||
while (*sp != STACK_END_PAINT) { |
||||
printf(" 0x%p: 0x%08lx\n", sp, *sp); |
||||
sp++; |
||||
} |
||||
} |
||||
|
||||
|
||||
/* This function calculates the ISR_usage */ |
||||
int thread_arch_isr_stack_usage(void) |
||||
{ |
||||
/* TODO */ |
||||
return -1; |
||||
} |
||||
|
||||
void *thread_arch_isr_stack_pointer(void) |
||||
{ |
||||
/* TODO */ |
||||
return (void *)-1; |
||||
} |
||||
|
||||
void *thread_arch_isr_stack_start(void) |
||||
{ |
||||
/* TODO */ |
||||
return (void *)-1; |
||||
} |
||||
|
||||
extern void __exception_restore(void); |
||||
void thread_arch_start_threading(void) |
||||
{ |
||||
unsigned int status = mips32_get_c0(C0_STATUS); |
||||
|
||||
/*
|
||||
* Set Exception level if we are not already running at it |
||||
* the EXL mode depends on the bootloader. |
||||
*/ |
||||
|
||||
if ((status & C0_STATUS_EXL) == 0) { |
||||
mips32_set_c0(C0_STATUS, status | C0_STATUS_EXL); |
||||
} |
||||
|
||||
sched_run(); |
||||
|
||||
__asm volatile ("lw $sp, 0(%0)" : : "r" (&sched_active_thread->sp)); |
||||
|
||||
__exception_restore(); |
||||
|
||||
UNREACHABLE(); |
||||
} |
||||
|
||||
void thread_arch_yield(void) |
||||
{ |
||||
/*
|
||||
* throw a syscall exception to get into exception level |
||||
* we context switch at exception level. |
||||
* |
||||
* Note syscall 1 is reserved for UHI see: |
||||
* http://wiki.prplfoundation.org/w/images/4/42/UHI_Reference_Manual.pdf
|
||||
*/ |
||||
__asm volatile ("syscall 2"); |
||||
} |
||||
|
||||
struct linkctx* exctx_find(reg_t id, struct gpctx *gp) |
||||
{ |
||||
struct linkctx **ctx = (struct linkctx **)&gp->link; |
||||
while (*ctx) { |
||||
if ((*ctx)->id == id) { |
||||
return *ctx; |
||||
} |
||||
ctx = &(*ctx)->next; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
/* unaligned access helper */ |
||||
static inline uint32_t __attribute__((optimize("-O3"))) |
||||
mem_rw(const void *vaddr) |
||||
{ |
||||
uint32_t v; |
||||
memcpy(&v, vaddr, sizeof(v)); |
||||
return v; |
||||
} |
||||
|
||||
|
||||
#ifdef MIPS_DSP |
||||
extern int _dsp_save(struct dspctx *ctx); |
||||
extern int _dsp_load(struct dspctx *ctx); |
||||
#endif |
||||
/*
|
||||
* The nomips16 attribute should not really be needed, it works around a toolchain |
||||
* issue in 2016.05-03. |
||||
*/ |
||||
void __attribute__((nomips16)) |
||||
_mips_handle_exception(struct gpctx *ctx, int exception) |
||||
{ |
||||
unsigned int syscall_num = 0; |
||||
#ifdef MIPS_DSP |
||||
struct dspctx dsp_ctx; /* intentionally allocated on current stack */ |
||||
#endif |
||||
|
||||
switch (exception) { |
||||
|
||||
case EXC_SYS: |
||||
#ifdef MIPS_MICROMIPS |
||||
/* note major 16bits of opcode is first in instruction stream */ |
||||
syscall_num = |
||||
mem_rw((const void *)(ctx->epc & ~MICROMIPS_ISA_MODE)) |
||||
& 0x3FF; |
||||
#else |
||||
syscall_num = (mem_rw((const void *)ctx->epc) >> 6) & 0xFFFF; |
||||
#endif |
||||
|
||||
#ifdef DEBUG_VIA_UART |
||||
#include <mips/uhi_syscalls.h> |
||||
/*
|
||||
* intercept UHI write syscalls (printf) which would normally |
||||
* get routed to debug probe or bootloader handler and output |
||||
* via a UART |
||||
*/ |
||||
|
||||
if (syscall_num == __MIPS_UHI_SYSCALL_NUM) { |
||||
if (ctx->t2[1] == __MIPS_UHI_WRITE && |
||||
(ctx->a[0] == STDOUT_FILENO || ctx->a[0] == STDERR_FILENO)) { |
||||
uint32_t status = irq_arch_disable(); |
||||
uart_write(DEBUG_VIA_UART, (uint8_t *)ctx->a[1], ctx->a[2]); |
||||
ctx->v[0] = ctx->a[2]; |
||||
ctx->epc += 4; /* move PC past the syscall */ |
||||
irq_arch_restore(status); |
||||
return; |
||||
} |
||||
else if (ctx->t2[1] == __MIPS_UHI_FSTAT && |
||||
(ctx->a[0] == STDOUT_FILENO || ctx->a[0] == STDERR_FILENO)) { |
||||
/*
|
||||
* Printf fstat's the stdout/stderr file so |
||||
* fill out a minimal struct stat. |
||||
*/ |
||||
struct stat *sbuf = (struct stat *)ctx->a[1]; |
||||
memset(sbuf, 0, sizeof(struct stat)); |
||||
sbuf->st_mode = S_IRUSR | S_IWUSR | S_IWGRP; |
||||
sbuf->st_blksize = BUFSIZ; |
||||
/* return 0 */ |
||||
ctx->v[0] = 0; |
||||
ctx->epc += 4; /* move PC past the syscall */ |
||||
return; |
||||
} |
||||
} |
||||
else |
||||
#endif |
||||
if (syscall_num == 2) { |
||||
unsigned int return_instruction = 0; |
||||
struct gpctx *new_ctx; |
||||
#ifdef MIPS_DSP |
||||
struct dspctx *new_dspctx; |
||||
#endif |
||||
/*
|
||||
* Syscall 1 is reserved for UHI. |
||||
*/ |
||||
|
||||
/*
|
||||
* save the stack pointer in the thread info |
||||
* note we want the saved value to include the |
||||
* saved off context and the 16 bytes padding. |
||||
* Note we cannot use the current sp value as |
||||
* the prologue of this function has adjusted it |
||||
*/ |
||||
< |