Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3022 → Rev 4055

/branches/dd/kernel/arch/sparc64/_link.ld.in
1,8 → 1,8
/** SPARC64 linker script
*
* It is ELF format, but its only section looks like this:
* kernel text
* kernel data
* kernel text
* kernel data
*
*/
 
11,7 → 11,7
ENTRY(kernel_image_start)
 
SECTIONS {
.image VMA: AT (LMA) {
.image VMA: AT (LMA) {
ktext_start = .;
*(K_TEXT_START)
*(.text);
21,23 → 21,23
*(K_DATA_START)
*(.rodata);
*(.rodata.*);
*(.data); /* initialized data */
*(.data); /* initialized data */
*(.sdata);
*(.sdata2);
*(.sbss);
. = ALIGN(8);
hardcoded_ktext_size = .;
QUAD(ktext_end - ktext_start);
QUAD(ktext_end - ktext_start);
hardcoded_kdata_size = .;
QUAD(kdata_end - kdata_start);
hardcoded_load_address = .;
QUAD(VMA);
*(.bss); /* uninitialized static variables */
*(COMMON); /* global variables */
 
*(.bss); /* uninitialized static variables */
*(COMMON); /* global variables */
symbol_table = .;
*(symtab.*); /* Symbol table, must be LAST symbol!*/
 
*(symtab.*); /* Symbol table, must be LAST symbol!*/
kdata_end = .;
}
44,5 → 44,5
/DISCARD/ : {
*(*);
}
 
}
/branches/dd/kernel/arch/sparc64/include/regdef.h
55,8 → 55,11
#define WSTATE_NORMAL(n) (n)
#define WSTATE_OTHER(n) ((n) << 3)
 
#define UPA_CONFIG_MID_SHIFT 17
#define UPA_CONFIG_MID_MASK 0x1f
/*
* The following definitions concern the UPA_CONFIG register on US and the
* FIREPLANE_CONFIG register on US3.
*/
#define ICBUS_CONFIG_MID_SHIFT 17
 
#endif
 
/branches/dd/kernel/arch/sparc64/include/cpu_node.h
0,0 → 1,59
/*
* Copyright (c) 2005 Pavel Rimsky
* All rights reserved.
*
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR 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.
*/
 
/** @addtogroup sparc64
* @{
*/
/** @file
*/
 
#ifndef KERN_sparc64_CPU_NODE_H_
#define KERN_sparc64_CPU_NODE_H_
 
#include <genarch/ofw/ofw_tree.h>
 
 
/** Finds the parent node of all the CPU nodes (nodes named "cpu" or "cmp").
*
* Depending on the machine type (and possibly the OFW version), CPUs can be
* at "/" or at "/ssm@0,0".
*/
static inline ofw_tree_node_t *cpus_parent(void)
{
ofw_tree_node_t *parent;
parent = ofw_tree_find_child(ofw_tree_lookup("/"), "ssm@0,0");
if (parent == NULL)
parent = ofw_tree_lookup("/");
return parent;
}
 
#endif
 
/** @}
*/
 
/branches/dd/kernel/arch/sparc64/include/fpu_context.h
37,7 → 37,6
 
#include <arch/types.h>
 
#define ARCH_HAS_FPU
#define FPU_CONTEXT_ALIGN 8
 
typedef struct {
/branches/dd/kernel/arch/sparc64/include/types.h
35,10 → 35,6
#ifndef KERN_sparc64_TYPES_H_
#define KERN_sparc64_TYPES_H_
 
#define NULL 0
#define false 0
#define true 1
 
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
61,13 → 57,34
typedef uint64_t unative_t;
typedef int64_t native_t;
 
typedef uint8_t bool;
typedef uint64_t thread_id_t;
typedef uint64_t task_id_t;
typedef uint32_t context_id_t;
typedef struct {
} fncptr_t;
 
typedef int32_t inr_t;
typedef int32_t devno_t;
/**< Formats for uintptr_t, size_t, count_t and index_t */
#define PRIp "llx"
#define PRIs "llu"
#define PRIc "llu"
#define PRIi "llu"
 
/**< Formats for (u)int8_t, (u)int16_t, (u)int32_t, (u)int64_t and (u)native_t */
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 "lld"
#define PRIdn "lld"
 
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 "llu"
#define PRIun "llu"
 
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
#define PRIx64 "llx"
#define PRIxn "llx"
 
typedef uint8_t asi_t;
 
#endif
/branches/dd/kernel/arch/sparc64/include/memstr.h
37,10 → 37,10
 
#define memcpy(dst, src, cnt) __builtin_memcpy((dst), (src), (cnt))
 
extern void memsetw(uintptr_t dst, size_t cnt, uint16_t x);
extern void memsetb(uintptr_t dst, size_t cnt, uint8_t x);
extern void memsetw(void *dst, size_t cnt, uint16_t x);
extern void memsetb(void *dst, size_t cnt, uint8_t x);
 
extern int memcmp(uintptr_t src, uintptr_t dst, int cnt);
extern int memcmp(const void *a, const void *b, size_t cnt);
 
#endif
 
/branches/dd/kernel/arch/sparc64/include/atomic.h
37,6 → 37,7
 
#include <arch/barrier.h>
#include <arch/types.h>
#include <preemption.h>
 
/** Atomic add operation.
*
56,7 → 57,8
 
a = *((uint64_t *) x);
b = a + i;
asm volatile ("casx %0, %2, %1\n" : "+m" (*((uint64_t *)x)), "+r" (b) : "r" (a));
asm volatile ("casx %0, %2, %1\n" : "+m" (*((uint64_t *)x)),
"+r" (b) : "r" (a));
} while (a != b);
 
return a;
97,7 → 99,8
uint64_t v = 1;
volatile uintptr_t x = (uint64_t) &val->count;
 
asm volatile ("casx %0, %2, %1\n" : "+m" (*((uint64_t *) x)), "+r" (v) : "r" (0));
asm volatile ("casx %0, %2, %1\n" : "+m" (*((uint64_t *) x)),
"+r" (v) : "r" (0));
 
return v;
}
109,6 → 112,8
 
volatile uintptr_t x = (uint64_t) &val->count;
 
preemption_disable();
 
asm volatile (
"0:\n"
"casx %0, %3, %1\n"
/branches/dd/kernel/arch/sparc64/include/boot/boot.h
48,9 → 48,12
#define TASKMAP_MAX_RECORDS 32
#define MEMMAP_MAX_RECORDS 32
 
#define BOOTINFO_TASK_NAME_BUFLEN 32
 
typedef struct {
void * addr;
uint32_t size;
char name[BOOTINFO_TASK_NAME_BUFLEN];
} utask_t;
 
typedef struct {
/branches/dd/kernel/arch/sparc64/include/arch.h
41,10 → 41,16
#define ASI_AIUS 0x11 /** Access to secondary context with user privileges. */
#define ASI_NUCLEUS_QUAD_LDD 0x24 /** ASI for 16-byte atomic loads. */
#define ASI_DCACHE_TAG 0x47 /** ASI D-Cache Tag. */
#define ASI_UPA_CONFIG 0x4a /** ASI of the UPA_CONFIG register. */
#define ASI_ICBUS_CONFIG 0x4a /** ASI of the UPA_CONFIG/FIREPLANE_CONFIG register. */
 
#define NWINDOWS 8 /** Number of register window sets. */
 
#ifndef __ASM__
 
extern void arch_pre_main(void);
 
#endif /* __ASM__ */
 
#endif
 
/** @}
/branches/dd/kernel/arch/sparc64/include/asm.h
37,11 → 37,61
 
#include <arch/arch.h>
#include <arch/types.h>
#include <typedefs.h>
#include <align.h>
#include <arch/register.h>
#include <config.h>
#include <arch/stack.h>
#include <arch/barrier.h>
 
static inline void pio_write_8(ioport8_t *port, uint8_t v)
{
*port = v;
memory_barrier();
}
 
static inline void pio_write_16(ioport16_t *port, uint16_t v)
{
*port = v;
memory_barrier();
}
 
static inline void pio_write_32(ioport32_t *port, uint32_t v)
{
*port = v;
memory_barrier();
}
 
static inline uint8_t pio_read_8(ioport8_t *port)
{
uint8_t rv;
 
rv = *port;
memory_barrier();
 
return rv;
}
 
static inline uint16_t pio_read_16(ioport16_t *port)
{
uint16_t rv;
 
rv = *port;
memory_barrier();
 
return rv;
}
 
static inline uint32_t pio_read_32(ioport32_t *port)
{
uint32_t rv;
 
rv = *port;
memory_barrier();
 
return rv;
}
 
/** Read Processor State register.
*
* @return Value of PSTATE register.
86,6 → 136,28
asm volatile ("wr %0, %1, %%tick_cmpr\n" : : "r" (v), "i" (0));
}
 
/** Read STICK_compare Register.
*
* @return Value of STICK_compare register.
*/
static inline uint64_t stick_compare_read(void)
{
uint64_t v;
asm volatile ("rd %%asr25, %0\n" : "=r" (v));
return v;
}
 
/** Write STICK_compare Register.
*
* @param v New value of STICK_comapre register.
*/
static inline void stick_compare_write(uint64_t v)
{
asm volatile ("wr %0, %1, %%asr25\n" : : "r" (v), "i" (0));
}
 
/** Read TICK Register.
*
* @return Value of TICK register.
357,15 → 429,6
asm volatile ("wrpr %g0, %g0, %tl\n");
}
 
/** Read UPA_CONFIG register.
*
* @return Value of the UPA_CONFIG register.
*/
static inline uint64_t upa_config_read(void)
{
return asi_u64_read(ASI_UPA_CONFIG, 0);
}
 
extern void cpu_halt(void);
extern void cpu_sleep(void);
extern void asm_delay_loop(const uint32_t usec);
/branches/dd/kernel/arch/sparc64/include/trap/syscall.h
31,26 → 31,14
*/
/**
* @file
* @brief This file contains the trap_instruction handler.
*
* The trap_instruction trap is used to implement syscalls.
* @brief
*/
 
#ifndef KERN_sparc64_SYSCALL_TRAP_H_
#define KERN_sparc64_SYSCALL_TRAP_H_
 
#define TT_TRAP_INSTRUCTION(n) (0x100 + (n))
#define TT_TRAP_INSTRUCTION_LAST TT_TRAP_INSTRUCTION(127)
#define TT_TRAP_INSTRUCTION_0 0x100
 
#ifdef __ASM__
 
.macro TRAP_INSTRUCTION n
ba trap_instruction_handler
mov TT_TRAP_INSTRUCTION(\n) - TT_TRAP_INSTRUCTION(0), %g2
.endm
 
#endif /* __ASM__ */
 
#endif
 
/** @}
/branches/dd/kernel/arch/sparc64/include/trap/regwin.h
39,6 → 39,7
 
#include <arch/stack.h>
#include <arch/arch.h>
#include <align.h>
 
#define TT_CLEAN_WINDOW 0x24
#define TT_SPILL_0_NORMAL 0x80 /* kernel spills */
72,6 → 73,11
#define I6_OFFSET 112
#define I7_OFFSET 120
 
/* Uspace Window Buffer constants. */
#define UWB_SIZE ((NWINDOWS - 1) * STACK_WINDOW_SAVE_AREA_SIZE)
#define UWB_ALIGNMENT 1024
#define UWB_ASIZE ALIGN_UP(UWB_SIZE, UWB_ALIGNMENT)
 
#ifdef __ASM__
 
/*
/branches/dd/kernel/arch/sparc64/include/trap/interrupt.h
49,21 → 49,43
 
 
/* Interrupt ASI registers. */
#define ASI_UDB_INTR_W 0x77
#define ASI_INTR_W 0x77
#define ASI_INTR_DISPATCH_STATUS 0x48
#define ASI_UDB_INTR_R 0x7f
#define ASI_INTR_R 0x7f
#define ASI_INTR_RECEIVE 0x49
 
/* VA's used with ASI_UDB_INTR_W register. */
/* VA's used with ASI_INTR_W register. */
#if defined (US)
#define ASI_UDB_INTR_W_DATA_0 0x40
#define ASI_UDB_INTR_W_DATA_1 0x50
#define ASI_UDB_INTR_W_DATA_2 0x60
#define ASI_UDB_INTR_W_DISPATCH 0x70
#elif defined (US3)
#define VA_INTR_W_DATA_0 0x40
#define VA_INTR_W_DATA_1 0x48
#define VA_INTR_W_DATA_2 0x50
#define VA_INTR_W_DATA_3 0x58
#define VA_INTR_W_DATA_4 0x60
#define VA_INTR_W_DATA_5 0x68
#define VA_INTR_W_DATA_6 0x80
#define VA_INTR_W_DATA_7 0x88
#endif
#define VA_INTR_W_DISPATCH 0x70
 
/* VA's used with ASI_UDB_INTR_R register. */
/* VA's used with ASI_INTR_R register. */
#if defined(US)
#define ASI_UDB_INTR_R_DATA_0 0x40
#define ASI_UDB_INTR_R_DATA_1 0x50
#define ASI_UDB_INTR_R_DATA_2 0x60
#elif defined (US3)
#define VA_INTR_R_DATA_0 0x40
#define VA_INTR_R_DATA_1 0x48
#define VA_INTR_R_DATA_2 0x50
#define VA_INTR_R_DATA_3 0x58
#define VA_INTR_R_DATA_4 0x60
#define VA_INTR_R_DATA_5 0x68
#define VA_INTR_R_DATA_6 0x80
#define VA_INTR_R_DATA_7 0x88
#endif
 
/* Shifts in the Interrupt Vector Dispatch virtual address. */
#define INTR_VEC_DISPATCH_MID_SHIFT 14
/branches/dd/kernel/arch/sparc64/include/mm/frame.h
59,8 → 59,13
union frame_address {
uintptr_t address;
struct {
#if defined (US)
unsigned : 23;
uint64_t pfn : 28; /**< Physical Frame Number. */
#elif defined (US3)
unsigned : 21;
uint64_t pfn : 30; /**< Physical Frame Number. */
#endif
unsigned offset : 13; /**< Offset. */
} __attribute__ ((packed));
};
/branches/dd/kernel/arch/sparc64/include/mm/page.h
53,11 → 53,6
 
#define MMU_PAGES_PER_PAGE (1 << (PAGE_WIDTH - MMU_PAGE_WIDTH))
 
/*
* With 16K pages, there is only one page color.
*/
#define PAGE_COLOR_BITS 0 /**< 14 - 14; 2^14 == 16K == alias boundary. */
 
#ifdef KERNEL
 
#ifndef __ASM__
/branches/dd/kernel/arch/sparc64/include/mm/tte.h
50,6 → 50,7
 
#include <arch/types.h>
 
/* TTE tag's VA_tag field contains bits <63:VA_TAG_PAGE_SHIFT> of the VA */
#define VA_TAG_PAGE_SHIFT 22
 
/** Translation Table Entry - Tag. */
75,8 → 76,13
unsigned nfo : 1; /**< No-Fault-Only. */
unsigned ie : 1; /**< Invert Endianness. */
unsigned soft2 : 9; /**< Software defined field. */
#if defined (US)
unsigned diag : 9; /**< Diagnostic data. */
unsigned pfn : 28; /**< Physical Address bits, bits 40:13. */
#elif defined (US3)
unsigned : 7; /**< Reserved. */
unsigned pfn : 30; /**< Physical Address bits, bits 42:13 */
#endif
unsigned soft : 6; /**< Software defined field. */
unsigned l : 1; /**< Lock. */
unsigned cp : 1; /**< Cacheable in physically indexed cache. */
/branches/dd/kernel/arch/sparc64/include/mm/cache_spec.h
0,0 → 1,58
/*
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR 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.
*/
 
/** @addtogroup sparc64mm
* @{
*/
/** @file
*/
 
#ifndef KERN_sparc64_CACHE_SPEC_H_
#define KERN_sparc64_CACHE_SPEC_H_
 
/*
* The following macros are valid for the following processors:
*
* UltraSPARC, UltraSPARC II, UltraSPARC IIi, UltraSPARC III,
* UltraSPARC III+, UltraSPARC IV, UltraSPARC IV+
*
* Should we support other UltraSPARC processors, we need to make sure that
* the macros are defined correctly for them.
*/
#if defined (US)
#define DCACHE_SIZE (16 * 1024)
#elif defined (US3)
#define DCACHE_SIZE (64 * 1024)
#endif
#define DCACHE_LINE_SIZE 32
 
#endif
 
/** @}
*/
/branches/dd/kernel/arch/sparc64/include/mm/mmu.h
35,8 → 35,10
#ifndef KERN_sparc64_MMU_H_
#define KERN_sparc64_MMU_H_
 
#if defined(US)
/* LSU Control Register ASI. */
#define ASI_LSU_CONTROL_REG 0x45 /**< Load/Store Unit Control Register. */
#endif
 
/* I-MMU ASIs. */
#define ASI_IMMU 0x50
52,7 → 54,12
#define VA_IMMU_SFSR 0x18 /**< IMMU sync fault status register. */
#define VA_IMMU_TSB_BASE 0x28 /**< IMMU TSB base register. */
#define VA_IMMU_TAG_ACCESS 0x30 /**< IMMU TLB tag access register. */
#if defined (US3)
#define VA_IMMU_PRIMARY_EXTENSION 0x48 /**< IMMU TSB primary extension register */
#define VA_IMMU_NUCLEUS_EXTENSION 0x58 /**< IMMU TSB nucleus extension register */
#endif
 
 
/* D-MMU ASIs. */
#define ASI_DMMU 0x58
#define ASI_DMMU_TSB_8KB_PTR_REG 0x59
73,6 → 80,11
#define VA_DMMU_TAG_ACCESS 0x30 /**< DMMU TLB tag access register. */
#define VA_DMMU_VA_WATCHPOINT_REG 0x38 /**< DMMU VA data watchpoint register. */
#define VA_DMMU_PA_WATCHPOINT_REG 0x40 /**< DMMU PA data watchpoint register. */
#if defined (US3)
#define VA_DMMU_PRIMARY_EXTENSION 0x48 /**< DMMU TSB primary extension register */
#define VA_DMMU_SECONDARY_EXTENSION 0x50 /**< DMMU TSB secondary extension register */
#define VA_DMMU_NUCLEUS_EXTENSION 0x58 /**< DMMU TSB nucleus extension register */
#endif
 
#ifndef __ASM__
 
80,6 → 92,7
#include <arch/barrier.h>
#include <arch/types.h>
 
#if defined(US)
/** LSU Control Register. */
typedef union {
uint64_t value;
100,6 → 113,7
} __attribute__ ((packed));
} lsu_cr_reg_t;
#endif /* US */
 
#endif /* !def __ASM__ */
 
/branches/dd/kernel/arch/sparc64/include/mm/tlb.h
35,9 → 35,17
#ifndef KERN_sparc64_TLB_H_
#define KERN_sparc64_TLB_H_
 
#if defined (US)
#define ITLB_ENTRY_COUNT 64
#define DTLB_ENTRY_COUNT 64
#define DTLB_MAX_LOCKED_ENTRIES DTLB_ENTRY_COUNT
#endif
 
/** TLB_DSMALL is the only of the three DMMUs that can hold locked entries. */
#if defined (US3)
#define DTLB_MAX_LOCKED_ENTRIES 16
#endif
 
#define MEM_CONTEXT_KERNEL 0
#define MEM_CONTEXT_TEMP 1
 
53,6 → 61,9
/* TLB Demap Operation types. */
#define TLB_DEMAP_PAGE 0
#define TLB_DEMAP_CONTEXT 1
#if defined (US3)
#define TLB_DEMAP_ALL 2
#endif
 
#define TLB_DEMAP_TYPE_SHIFT 6
 
61,6 → 72,18
#define TLB_DEMAP_SECONDARY 1
#define TLB_DEMAP_NUCLEUS 2
 
/* There are more TLBs in one MMU in US3, their codes are defined here. */
#if defined (US3)
/* D-MMU: one small (16-entry) TLB and two big (512-entry) TLBs */
#define TLB_DSMALL 0
#define TLB_DBIG_0 2
#define TLB_DBIG_1 3
/* I-MMU: one small (16-entry) TLB and one big TLB */
#define TLB_ISMALL 0
#define TLB_IBIG 2
#endif
 
#define TLB_DEMAP_CONTEXT_SHIFT 4
 
/* TLB Tag Access shifts */
76,6 → 99,8
#include <arch/asm.h>
#include <arch/barrier.h>
#include <arch/types.h>
#include <arch/register.h>
#include <arch/cpu.h>
 
union tlb_context_reg {
uint64_t v;
90,6 → 115,9
typedef tte_data_t tlb_data_t;
 
/** I-/D-TLB Data Access Address in Alternate Space. */
 
#if defined (US)
 
union tlb_data_access_addr {
uint64_t value;
struct {
98,9 → 126,54
unsigned : 3;
} __attribute__ ((packed));
};
typedef union tlb_data_access_addr tlb_data_access_addr_t;
typedef union tlb_data_access_addr tlb_tag_read_addr_t;
typedef union tlb_data_access_addr dtlb_data_access_addr_t;
typedef union tlb_data_access_addr dtlb_tag_read_addr_t;
typedef union tlb_data_access_addr itlb_data_access_addr_t;
typedef union tlb_data_access_addr itlb_tag_read_addr_t;
 
#elif defined (US3)
 
/*
* In US3, I-MMU and D-MMU have different formats of the data
* access register virtual address. In the corresponding
* structures the member variable for the entry number is
* called "local_tlb_entry" - it contrasts with the "tlb_entry"
* for the US data access register VA structure. The rationale
* behind this is to prevent careless mistakes in the code
* caused by setting only the entry number and not the TLB
* number in the US3 code (when taking the code from US).
*/
 
union dtlb_data_access_addr {
uint64_t value;
struct {
uint64_t : 45;
unsigned : 1;
unsigned tlb_number : 2;
unsigned : 4;
unsigned local_tlb_entry : 9;
unsigned : 3;
} __attribute__ ((packed));
};
typedef union dtlb_data_access_addr dtlb_data_access_addr_t;
typedef union dtlb_data_access_addr dtlb_tag_read_addr_t;
 
union itlb_data_access_addr {
uint64_t value;
struct {
uint64_t : 45;
unsigned : 1;
unsigned tlb_number : 2;
unsigned : 6;
unsigned local_tlb_entry : 7;
unsigned : 3;
} __attribute__ ((packed));
};
typedef union itlb_data_access_addr itlb_data_access_addr_t;
typedef union itlb_data_access_addr itlb_tag_read_addr_t;
 
#endif
 
/** I-/D-TLB Tag Read Register. */
union tlb_tag_read_reg {
uint64_t value;
118,8 → 191,13
uint64_t value;
struct {
uint64_t vpn: 51; /**< Virtual Address bits 63:13. */
#if defined (US)
unsigned : 6; /**< Ignored. */
unsigned type : 1; /**< The type of demap operation. */
#elif defined (US3)
unsigned : 5; /**< Ignored. */
unsigned type: 2; /**< The type of demap operation. */
#endif
unsigned context : 2; /**< Context register selection. */
unsigned : 4; /**< Zero. */
} __attribute__ ((packed));
130,10 → 208,19
union tlb_sfsr_reg {
uint64_t value;
struct {
#if defined (US)
unsigned long : 40; /**< Implementation dependent. */
unsigned asi : 8; /**< ASI. */
unsigned : 2;
unsigned ft : 7; /**< Fault type. */
#elif defined (US3)
unsigned long : 39; /**< Implementation dependent. */
unsigned nf : 1; /**< Non-faulting load. */
unsigned asi : 8; /**< ASI. */
unsigned tm : 1; /**< I-TLB miss. */
unsigned : 3; /**< Reserved. */
unsigned ft : 5; /**< Fault type. */
#endif
unsigned e : 1; /**< Side-effect bit. */
unsigned ct : 2; /**< Context Register selection. */
unsigned pr : 1; /**< Privilege bit. */
144,9 → 231,53
};
typedef union tlb_sfsr_reg tlb_sfsr_reg_t;
 
#if defined (US3)
 
/*
* Functions for determining the number of entries in TLBs. They either return
* a constant value or a value based on the CPU autodetection.
*/
 
/**
* Determine the number of entries in the DMMU's small TLB.
*/
static inline uint16_t tlb_dsmall_size(void)
{
return 16;
}
 
/**
* Determine the number of entries in each DMMU's big TLB.
*/
static inline uint16_t tlb_dbig_size(void)
{
return 512;
}
 
/**
* Determine the number of entries in the IMMU's small TLB.
*/
static inline uint16_t tlb_ismall_size(void)
{
return 16;
}
 
/**
* Determine the number of entries in the IMMU's big TLB.
*/
static inline uint16_t tlb_ibig_size(void)
{
if (((ver_reg_t) ver_read()).impl == IMPL_ULTRASPARCIV_PLUS)
return 512;
else
return 128;
}
 
#endif
 
/** Read MMU Primary Context Register.
*
* @return Current value of Primary Context Register.
* @return Current value of Primary Context Register.
*/
static inline uint64_t mmu_primary_context_read(void)
{
155,17 → 286,17
 
/** Write MMU Primary Context Register.
*
* @param v New value of Primary Context Register.
* @param v New value of Primary Context Register.
*/
static inline void mmu_primary_context_write(uint64_t v)
{
asi_u64_write(ASI_DMMU, VA_PRIMARY_CONTEXT_REG, v);
flush();
flush_pipeline();
}
 
/** Read MMU Secondary Context Register.
*
* @return Current value of Secondary Context Register.
* @return Current value of Secondary Context Register.
*/
static inline uint64_t mmu_secondary_context_read(void)
{
174,23 → 305,26
 
/** Write MMU Primary Context Register.
*
* @param v New value of Primary Context Register.
* @param v New value of Primary Context Register.
*/
static inline void mmu_secondary_context_write(uint64_t v)
{
asi_u64_write(ASI_DMMU, VA_SECONDARY_CONTEXT_REG, v);
flush();
flush_pipeline();
}
 
#if defined (US)
 
/** Read IMMU TLB Data Access Register.
*
* @param entry TLB Entry index.
* @param entry TLB Entry index.
*
* @return Current value of specified IMMU TLB Data Access Register.
* @return Current value of specified IMMU TLB Data Access
* Register.
*/
static inline uint64_t itlb_data_access_read(index_t entry)
{
tlb_data_access_addr_t reg;
itlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_entry = entry;
199,28 → 333,29
 
/** Write IMMU TLB Data Access Register.
*
* @param entry TLB Entry index.
* @param value Value to be written.
* @param entry TLB Entry index.
* @param value Value to be written.
*/
static inline void itlb_data_access_write(index_t entry, uint64_t value)
{
tlb_data_access_addr_t reg;
itlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_entry = entry;
asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value);
flush();
flush_pipeline();
}
 
/** Read DMMU TLB Data Access Register.
*
* @param entry TLB Entry index.
* @param entry TLB Entry index.
*
* @return Current value of specified DMMU TLB Data Access Register.
* @return Current value of specified DMMU TLB Data Access
* Register.
*/
static inline uint64_t dtlb_data_access_read(index_t entry)
{
tlb_data_access_addr_t reg;
dtlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_entry = entry;
229,12 → 364,12
 
/** Write DMMU TLB Data Access Register.
*
* @param entry TLB Entry index.
* @param value Value to be written.
* @param entry TLB Entry index.
* @param value Value to be written.
*/
static inline void dtlb_data_access_write(index_t entry, uint64_t value)
{
tlb_data_access_addr_t reg;
dtlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_entry = entry;
244,13 → 379,13
 
/** Read IMMU TLB Tag Read Register.
*
* @param entry TLB Entry index.
* @param entry TLB Entry index.
*
* @return Current value of specified IMMU TLB Tag Read Register.
* @return Current value of specified IMMU TLB Tag Read Register.
*/
static inline uint64_t itlb_tag_read_read(index_t entry)
{
tlb_tag_read_addr_t tag;
itlb_tag_read_addr_t tag;
 
tag.value = 0;
tag.tlb_entry = entry;
259,13 → 394,13
 
/** Read DMMU TLB Tag Read Register.
*
* @param entry TLB Entry index.
* @param entry TLB Entry index.
*
* @return Current value of specified DMMU TLB Tag Read Register.
* @return Current value of specified DMMU TLB Tag Read Register.
*/
static inline uint64_t dtlb_tag_read_read(index_t entry)
{
tlb_tag_read_addr_t tag;
dtlb_tag_read_addr_t tag;
 
tag.value = 0;
tag.tlb_entry = entry;
272,19 → 407,130
return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value);
}
 
#elif defined (US3)
 
 
/** Read IMMU TLB Data Access Register.
*
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG)
* @param entry TLB Entry index.
*
* @return Current value of specified IMMU TLB Data Access
* Register.
*/
static inline uint64_t itlb_data_access_read(int tlb, index_t entry)
{
itlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_number = tlb;
reg.local_tlb_entry = entry;
return asi_u64_read(ASI_ITLB_DATA_ACCESS_REG, reg.value);
}
 
/** Write IMMU TLB Data Access Register.
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG)
* @param entry TLB Entry index.
* @param value Value to be written.
*/
static inline void itlb_data_access_write(int tlb, index_t entry,
uint64_t value)
{
itlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_number = tlb;
reg.local_tlb_entry = entry;
asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value);
flush_pipeline();
}
 
/** Read DMMU TLB Data Access Register.
*
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG, TLB_DBIG)
* @param entry TLB Entry index.
*
* @return Current value of specified DMMU TLB Data Access
* Register.
*/
static inline uint64_t dtlb_data_access_read(int tlb, index_t entry)
{
dtlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_number = tlb;
reg.local_tlb_entry = entry;
return asi_u64_read(ASI_DTLB_DATA_ACCESS_REG, reg.value);
}
 
/** Write DMMU TLB Data Access Register.
*
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1)
* @param entry TLB Entry index.
* @param value Value to be written.
*/
static inline void dtlb_data_access_write(int tlb, index_t entry,
uint64_t value)
{
dtlb_data_access_addr_t reg;
reg.value = 0;
reg.tlb_number = tlb;
reg.local_tlb_entry = entry;
asi_u64_write(ASI_DTLB_DATA_ACCESS_REG, reg.value, value);
membar();
}
 
/** Read IMMU TLB Tag Read Register.
*
* @param tlb TLB number (one of TLB_ISMALL or TLB_IBIG)
* @param entry TLB Entry index.
*
* @return Current value of specified IMMU TLB Tag Read Register.
*/
static inline uint64_t itlb_tag_read_read(int tlb, index_t entry)
{
itlb_tag_read_addr_t tag;
 
tag.value = 0;
tag.tlb_number = tlb;
tag.local_tlb_entry = entry;
return asi_u64_read(ASI_ITLB_TAG_READ_REG, tag.value);
}
 
/** Read DMMU TLB Tag Read Register.
*
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1)
* @param entry TLB Entry index.
*
* @return Current value of specified DMMU TLB Tag Read Register.
*/
static inline uint64_t dtlb_tag_read_read(int tlb, index_t entry)
{
dtlb_tag_read_addr_t tag;
 
tag.value = 0;
tag.tlb_number = tlb;
tag.local_tlb_entry = entry;
return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value);
}
 
#endif
 
 
/** Write IMMU TLB Tag Access Register.
*
* @param v Value to be written.
* @param v Value to be written.
*/
static inline void itlb_tag_access_write(uint64_t v)
{
asi_u64_write(ASI_IMMU, VA_IMMU_TAG_ACCESS, v);
flush();
flush_pipeline();
}
 
/** Read IMMU TLB Tag Access Register.
*
* @return Current value of IMMU TLB Tag Access Register.
* @return Current value of IMMU TLB Tag Access Register.
*/
static inline uint64_t itlb_tag_access_read(void)
{
293,7 → 539,7
 
/** Write DMMU TLB Tag Access Register.
*
* @param v Value to be written.
* @param v Value to be written.
*/
static inline void dtlb_tag_access_write(uint64_t v)
{
303,7 → 549,7
 
/** Read DMMU TLB Tag Access Register.
*
* @return Current value of DMMU TLB Tag Access Register.
* @return Current value of DMMU TLB Tag Access Register.
*/
static inline uint64_t dtlb_tag_access_read(void)
{
313,17 → 559,17
 
/** Write IMMU TLB Data in Register.
*
* @param v Value to be written.
* @param v Value to be written.
*/
static inline void itlb_data_in_write(uint64_t v)
{
asi_u64_write(ASI_ITLB_DATA_IN_REG, 0, v);
flush();
flush_pipeline();
}
 
/** Write DMMU TLB Data in Register.
*
* @param v Value to be written.
* @param v Value to be written.
*/
static inline void dtlb_data_in_write(uint64_t v)
{
333,7 → 579,7
 
/** Read ITLB Synchronous Fault Status Register.
*
* @return Current content of I-SFSR register.
* @return Current content of I-SFSR register.
*/
static inline uint64_t itlb_sfsr_read(void)
{
342,17 → 588,17
 
/** Write ITLB Synchronous Fault Status Register.
*
* @param v New value of I-SFSR register.
* @param v New value of I-SFSR register.
*/
static inline void itlb_sfsr_write(uint64_t v)
{
asi_u64_write(ASI_IMMU, VA_IMMU_SFSR, v);
flush();
flush_pipeline();
}
 
/** Read DTLB Synchronous Fault Status Register.
*
* @return Current content of D-SFSR register.
* @return Current content of D-SFSR register.
*/
static inline uint64_t dtlb_sfsr_read(void)
{
361,7 → 607,7
 
/** Write DTLB Synchronous Fault Status Register.
*
* @param v New value of D-SFSR register.
* @param v New value of D-SFSR register.
*/
static inline void dtlb_sfsr_write(uint64_t v)
{
371,7 → 617,7
 
/** Read DTLB Synchronous Fault Address Register.
*
* @return Current content of D-SFAR register.
* @return Current content of D-SFAR register.
*/
static inline uint64_t dtlb_sfar_read(void)
{
380,10 → 626,11
 
/** Perform IMMU TLB Demap Operation.
*
* @param type Selects between context and page demap.
* @param type Selects between context and page demap (and entire MMU
* demap on US3).
* @param context_encoding Specifies which Context register has Context ID for
* demap.
* @param page Address which is on the page to be demapped.
* demap.
* @param page Address which is on the page to be demapped.
*/
static inline void itlb_demap(int type, int context_encoding, uintptr_t page)
{
397,18 → 644,19
da.context = context_encoding;
da.vpn = pg.vpn;
asi_u64_write(ASI_IMMU_DEMAP, da.value, 0); /* da.value is the
* address within the
* ASI */
flush();
/* da.value is the address within the ASI */
asi_u64_write(ASI_IMMU_DEMAP, da.value, 0);
 
flush_pipeline();
}
 
/** Perform DMMU TLB Demap Operation.
*
* @param type Selects between context and page demap.
* @param type Selects between context and page demap (and entire MMU
* demap on US3).
* @param context_encoding Specifies which Context register has Context ID for
* demap.
* @param page Address which is on the page to be demapped.
* demap.
* @param page Address which is on the page to be demapped.
*/
static inline void dtlb_demap(int type, int context_encoding, uintptr_t page)
{
422,17 → 670,17
da.context = context_encoding;
da.vpn = pg.vpn;
asi_u64_write(ASI_DMMU_DEMAP, da.value, 0); /* da.value is the
* address within the
* ASI */
/* da.value is the address within the ASI */
asi_u64_write(ASI_DMMU_DEMAP, da.value, 0);
 
membar();
}
 
extern void fast_instruction_access_mmu_miss(unative_t unused, istate_t *istate);
extern void fast_data_access_mmu_miss(tlb_tag_access_reg_t tag, istate_t *istate);
extern void fast_data_access_protection(tlb_tag_access_reg_t tag , istate_t *istate);
extern void fast_instruction_access_mmu_miss(unative_t, istate_t *);
extern void fast_data_access_mmu_miss(tlb_tag_access_reg_t, istate_t *);
extern void fast_data_access_protection(tlb_tag_access_reg_t , istate_t *);
 
extern void dtlb_insert_mapping(uintptr_t page, uintptr_t frame, int pagesize, bool locked, bool cacheable);
extern void dtlb_insert_mapping(uintptr_t, uintptr_t, int, bool, bool);
 
extern void dump_sfsr_and_sfar(void);
 
/branches/dd/kernel/arch/sparc64/include/mm/cache.h
38,15 → 38,6
#include <mm/page.h>
#include <mm/frame.h>
 
#define dcache_flush_page(p) \
dcache_flush_color(PAGE_COLOR((p)))
#define dcache_flush_frame(p, f) \
dcache_flush_tag(PAGE_COLOR((p)), ADDR2PFN((f)));
 
extern void dcache_flush(void);
extern void dcache_flush_color(int c);
extern void dcache_flush_tag(int c, pfn_t tag);
 
#endif
 
/** @}
/branches/dd/kernel/arch/sparc64/include/mm/tsb.h
107,6 → 107,55
asi_u64_write(ASI_DMMU, VA_DMMU_TSB_BASE, v);
}
 
#if defined (US3)
 
/** Write DTSB Primary Extension register.
*
* @param v New content of the DTSB Primary Extension register.
*/
static inline void dtsb_primary_extension_write(uint64_t v)
{
asi_u64_write(ASI_DMMU, VA_DMMU_PRIMARY_EXTENSION, v);
}
 
/** Write DTSB Secondary Extension register.
*
* @param v New content of the DTSB Secondary Extension register.
*/
static inline void dtsb_secondary_extension_write(uint64_t v)
{
asi_u64_write(ASI_DMMU, VA_DMMU_SECONDARY_EXTENSION, v);
}
 
/** Write DTSB Nucleus Extension register.
*
* @param v New content of the DTSB Nucleus Extension register.
*/
static inline void dtsb_nucleus_extension_write(uint64_t v)
{
asi_u64_write(ASI_DMMU, VA_DMMU_NUCLEUS_EXTENSION, v);
}
 
/** Write ITSB Primary Extension register.
*
* @param v New content of the ITSB Primary Extension register.
*/
static inline void itsb_primary_extension_write(uint64_t v)
{
asi_u64_write(ASI_IMMU, VA_IMMU_PRIMARY_EXTENSION, v);
}
 
/** Write ITSB Nucleus Extension register.
*
* @param v New content of the ITSB Nucleus Extension register.
*/
static inline void itsb_nucleus_extension_write(uint64_t v)
{
asi_u64_write(ASI_IMMU, VA_IMMU_NUCLEUS_EXTENSION, v);
}
 
#endif
 
/* Forward declarations. */
struct as;
struct pte;
/branches/dd/kernel/arch/sparc64/include/register.h
117,23 → 117,6
};
typedef union fprs_reg fprs_reg_t;
 
/** UPA_CONFIG register.
*
* Note that format of this register differs significantly from
* processor version to version. The format defined here
* is the common subset for all supported processor versions.
*/
union upa_config {
uint64_t value;
struct {
uint64_t : 34;
unsigned pcon : 8; /**< Processor configuration. */
unsigned mid : 5; /**< Module (processor) ID register. */
unsigned pcap : 17; /**< Processor capabilities. */
} __attribute__ ((packed));
};
typedef union upa_config upa_config_t;
 
#endif
 
/** @}
/branches/dd/kernel/arch/sparc64/include/barrier.h
57,8 → 57,11
#define write_barrier() \
asm volatile ("membar #StoreStore\n" ::: "memory")
 
/** Flush Instruction Memory instruction. */
static inline void flush(void)
#define flush(a) \
asm volatile ("flush %0\n" :: "r" ((a)) : "memory")
 
/** Flush Instruction pipeline. */
static inline void flush_pipeline(void)
{
/*
* The FLUSH instruction takes address parameter.
79,6 → 82,39
asm volatile ("membar #Sync\n");
}
 
#if defined (US)
 
#define smc_coherence(a) \
{ \
write_barrier(); \
flush((a)); \
}
 
#define FLUSH_INVAL_MIN 4
#define smc_coherence_block(a, l) \
{ \
unsigned long i; \
write_barrier(); \
for (i = 0; i < (l); i += FLUSH_INVAL_MIN) \
flush((void *)(a) + i); \
}
 
#elif defined (US3)
 
#define smc_coherence(a) \
{ \
write_barrier(); \
flush_pipeline(); \
}
 
#define smc_coherence_block(a, l) \
{ \
write_barrier(); \
flush_pipeline(); \
}
 
#endif /* defined(US3) */
 
#endif
 
/** @}
/branches/dd/kernel/arch/sparc64/include/cpu.h
35,14 → 35,6
#ifndef KERN_sparc64_CPU_H_
#define KERN_sparc64_CPU_H_
 
#include <arch/types.h>
#include <arch/register.h>
#include <arch/asm.h>
 
#ifdef CONFIG_SMP
#include <arch/mm/cache.h>
#endif
 
#define MANUF_FUJITSU 0x04
#define MANUF_ULTRASPARC 0x17 /**< UltraSPARC I, UltraSPARC II */
#define MANUF_SUN 0x3e
51,14 → 43,29
#define IMPL_ULTRASPARCII 0x11
#define IMPL_ULTRASPARCII_I 0x12
#define IMPL_ULTRASPARCII_E 0x13
#define IMPL_ULTRASPARCIII 0x15
#define IMPL_ULTRASPARCIII 0x14
#define IMPL_ULTRASPARCIII_PLUS 0x15
#define IMPL_ULTRASPARCIII_I 0x16
#define IMPL_ULTRASPARCIV 0x18
#define IMPL_ULTRASPARCIV_PLUS 0x19
 
#define IMPL_SPARC64V 0x5
 
#ifndef __ASM__
 
#include <arch/types.h>
#include <typedefs.h>
#include <arch/register.h>
#include <arch/regdef.h>
#include <arch/asm.h>
 
#ifdef CONFIG_SMP
#include <arch/mm/cache.h>
#endif
 
typedef struct {
uint32_t mid; /**< Processor ID as read from
UPA_CONFIG. */
UPA_CONFIG/FIREPLANE_CONFIG. */
ver_reg_t ver;
uint32_t clock_frequency; /**< Processor frequency in Hz. */
uint64_t next_tick_cmpr; /**< Next clock interrupt should be
65,8 → 72,28
generated when the TICK register
matches this value. */
} cpu_arch_t;
 
 
/**
* Reads the module ID (agent ID/CPUID) of the current CPU.
*/
static inline uint32_t read_mid(void)
{
uint64_t icbus_config = asi_u64_read(ASI_ICBUS_CONFIG, 0);
icbus_config = icbus_config >> ICBUS_CONFIG_MID_SHIFT;
#if defined (US)
return icbus_config & 0x1f;
#elif defined (US3)
if (((ver_reg_t) ver_read()).impl == IMPL_ULTRASPARCIII_I)
return icbus_config & 0x1f;
else
return icbus_config & 0x3ff;
#endif
}
 
#endif
 
#endif
 
/** @}
*/
/branches/dd/kernel/arch/sparc64/include/drivers/z8530.h
File deleted
/branches/dd/kernel/arch/sparc64/include/drivers/ns16550.h
File deleted
/branches/dd/kernel/arch/sparc64/include/drivers/sgcn.h
0,0 → 1,126
/*
* Copyright (c) 2008 Pavel Rimsky
* All rights reserved.
*
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR 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.
*/
 
/** @addtogroup sparc64
* @{
*/
/** @file
*/
 
#ifndef KERN_sparc64_SGCN_H_
#define KERN_sparc64_SGCN_H_
 
#include <arch/types.h>
 
/* number of bytes in the TOC magic, including the terminating '\0' */
#define TOC_MAGIC_BYTES 8
 
/* number of bytes in the TOC key, including the terminating '\0' */
#define TOC_KEY_SIZE 8
 
/* maximum number of entries in the SRAM table of contents */
#define MAX_TOC_ENTRIES 32
 
/* number of bytes in the SGCN buffer magic, including the terminating '\0' */
#define SGCN_MAGIC_BYTES 4
 
/**
* Entry in the SRAM table of contents. Describes one segment of the SRAM
* which serves a particular purpose (e.g. OBP serial console, Solaris serial
* console, Solaris mailbox,...).
*/
typedef struct {
/** key (e.g. "OBPCONS", "SOLCONS", "SOLMBOX",...) */
char key[TOC_KEY_SIZE];
/** size of the segment in bytes */
uint32_t size;
/** offset of the segment within SRAM */
uint32_t offset;
} __attribute ((packed)) toc_entry_t;
 
/**
* SRAM table of contents. Describes all segments within the SRAM.
*/
typedef struct {
/** hard-wired to "TOCSRAM" */
char magic[TOC_MAGIC_BYTES];
/** we don't need this */
char unused[8];
/** TOC entries */
toc_entry_t keys[MAX_TOC_ENTRIES];
} __attribute__ ((packed)) iosram_toc_t;
 
/**
* SGCN buffer header. It is placed at the very beginning of the SGCN
* buffer.
*/
typedef struct {
/** hard-wired to "CON" */
char magic[SGCN_MAGIC_BYTES];
/** we don't need this */
char unused[8];
/** offset within the SGCN buffer of the input buffer start */
uint32_t in_begin;
/** offset within the SGCN buffer of the input buffer end */
uint32_t in_end;
/** offset within the SGCN buffer of the input buffer read pointer */
uint32_t in_rdptr;
/** offset within the SGCN buffer of the input buffer write pointer */
uint32_t in_wrptr;
 
/** offset within the SGCN buffer of the output buffer start */
uint32_t out_begin;
/** offset within the SGCN buffer of the output buffer end */
uint32_t out_end;
/** offset within the SGCN buffer of the output buffer read pointer */
uint32_t out_rdptr;
/** offset within the SGCN buffer of the output buffer write pointer */
uint32_t out_wrptr;
} __attribute__ ((packed)) sgcn_buffer_header_t;
 
void sgcn_grab(void);
void sgcn_release(void);
void sgcn_poll(void);
void sgcn_init(void);
 
#endif
 
/** @}
*/
/branches/dd/kernel/arch/sparc64/include/drivers/pci.h
51,8 → 51,8
};
 
struct pci_operations {
void (* enable_interrupt)(pci_t *pci, int inr);
void (* clear_interrupt)(pci_t *pci, int inr);
void (* enable_interrupt)(pci_t *, int);
void (* clear_interrupt)(pci_t *, int);
};
 
struct pci {
61,9 → 61,9
volatile uint64_t *reg; /**< Registers including interrupt registers. */
};
 
extern pci_t *pci_init(ofw_tree_node_t *node);
extern void pci_enable_interrupt(pci_t *pci, int inr);
extern void pci_clear_interrupt(pci_t *pci, int inr);
extern pci_t *pci_init(ofw_tree_node_t *);
extern void pci_enable_interrupt(pci_t *, int);
extern void pci_clear_interrupt(void *, int);
 
#endif
 
/branches/dd/kernel/arch/sparc64/include/drivers/fhc.h
44,9 → 44,9
 
extern fhc_t *central_fhc;
 
extern fhc_t *fhc_init(ofw_tree_node_t *node);
extern void fhc_enable_interrupt(fhc_t *fhc, int inr);
extern void fhc_clear_interrupt(fhc_t *fhc, int inr);
extern fhc_t *fhc_init(ofw_tree_node_t *);
extern void fhc_enable_interrupt(fhc_t *, int);
extern void fhc_clear_interrupt(void *, int);
 
#endif
 
/branches/dd/kernel/arch/sparc64/include/drivers/kbd.h
41,7 → 41,8
typedef enum {
KBD_UNKNOWN,
KBD_Z8530,
KBD_NS16550
KBD_NS16550,
KBD_SGCN
} kbd_type_t;
 
extern kbd_type_t kbd_type;
/branches/dd/kernel/arch/sparc64/include/drivers/scr.h
42,12 → 42,14
SCR_UNKNOWN,
SCR_ATYFB,
SCR_FFB,
SCR_CGSIX
SCR_CGSIX,
SCR_XVR
} scr_type_t;
 
extern scr_type_t scr_type;
 
extern void scr_init(ofw_tree_node_t *node);
extern void scr_redraw(void);
 
#endif
 
/branches/dd/kernel/arch/sparc64/include/cpu_family.h
0,0 → 1,83
/*
* Copyright (c) 2008 Pavel Rimsky
* All rights reserved.
*
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR 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.
*/
 
/** @addtogroup sparc64
* @{
*/
/** @file
*/
 
#ifndef KERN_sparc64_CPU_FAMILY_H_
#define KERN_sparc64_CPU_FAMILY_H_
 
#include <arch.h>
#include <cpu.h>
#include <arch/register.h>
#include <arch/asm.h>
 
/**
* Find the processor (sub)family.
*
* @return true iff the CPU belongs to the US family
*/
static inline bool is_us(void)
{
int impl = ((ver_reg_t) ver_read()).impl;
return (impl == IMPL_ULTRASPARCI) || (impl == IMPL_ULTRASPARCII) ||
(impl == IMPL_ULTRASPARCII_I) || (impl == IMPL_ULTRASPARCII_E);
}
 
/**
* Find the processor (sub)family.
*
* @return true iff the CPU belongs to the US-III subfamily
*/
static inline bool is_us_iii(void)
{
int impl = ((ver_reg_t) ver_read()).impl;
return (impl == IMPL_ULTRASPARCIII) ||
(impl == IMPL_ULTRASPARCIII_PLUS) ||
(impl == IMPL_ULTRASPARCIII_I);
}
 
/**
* Find the processor (sub)family.
*
* @return true iff the CPU belongs to the US-IV subfamily
*/
static inline bool is_us_iv(void)
{
int impl = ((ver_reg_t) ver_read()).impl;
return (impl == IMPL_ULTRASPARCIV) || (impl == IMPL_ULTRASPARCIV_PLUS);
}
#endif
 
/** @}
*/
 
/branches/dd/kernel/arch/sparc64/Makefile.inc
33,7 → 33,7
BFD_ARCH = sparc
BFD = binary
TARGET = sparc64-linux-gnu
TOOLCHAIN_DIR = /usr/local/sparc64
TOOLCHAIN_DIR = $(CROSS_PREFIX)/sparc64
 
GCC_CFLAGS += -m64 -mcpu=ultrasparc
SUNCC_CFLAGS += -m64 -xarch=sparc -xregs=appl,no%float
42,80 → 42,59
 
DEFS += -D__64_BITS__
 
## Own configuration directives
#
ifeq ($(PROCESSOR),us)
DEFS += -DUS
endif
 
## Compile with page hash table support.
#
ifeq ($(PROCESSOR),us3)
DEFS += -DUS3
endif
 
CONFIG_PAGE_HT = y
DEFS += -DCONFIG_PAGE_HT
ARCH_SOURCES = \
arch/$(KARCH)/src/cpu/cpu.c \
arch/$(KARCH)/src/asm.S \
arch/$(KARCH)/src/panic.S \
arch/$(KARCH)/src/console.c \
arch/$(KARCH)/src/context.S \
arch/$(KARCH)/src/fpu_context.c \
arch/$(KARCH)/src/dummy.s \
arch/$(KARCH)/src/mm/as.c \
arch/$(KARCH)/src/mm/cache.S \
arch/$(KARCH)/src/mm/frame.c \
arch/$(KARCH)/src/mm/page.c \
arch/$(KARCH)/src/mm/tlb.c \
arch/$(KARCH)/src/sparc64.c \
arch/$(KARCH)/src/start.S \
arch/$(KARCH)/src/proc/scheduler.c \
arch/$(KARCH)/src/proc/thread.c \
arch/$(KARCH)/src/trap/mmu.S \
arch/$(KARCH)/src/trap/trap_table.S \
arch/$(KARCH)/src/trap/trap.c \
arch/$(KARCH)/src/trap/exception.c \
arch/$(KARCH)/src/trap/interrupt.c \
arch/$(KARCH)/src/ddi/ddi.c \
arch/$(KARCH)/src/drivers/tick.c \
arch/$(KARCH)/src/drivers/kbd.c \
arch/$(KARCH)/src/drivers/sgcn.c \
arch/$(KARCH)/src/drivers/pci.c
 
## Compile with support for address space identifiers.
#
 
CONFIG_ASID = y
CONFIG_ASID_FIFO = y
 
## Compile with support for framebuffer.
#
 
CONFIG_FB = y
 
## Compile with support for Sun keyboard.
#
 
CONFIG_SUN_KBD = y
 
## Compile with support for OpenFirmware device tree.
#
 
CONFIG_OFW_TREE = y
 
ifeq ($(CONFIG_SMP),y)
DEFS += -DCONFIG_SMP
ifeq ($(CONFIG_FB),y)
ARCH_SOURCES += \
arch/$(KARCH)/src/drivers/scr.c
endif
 
ARCH_SOURCES = \
arch/$(ARCH)/src/cpu/cpu.c \
arch/$(ARCH)/src/asm.S \
arch/$(ARCH)/src/panic.S \
arch/$(ARCH)/src/console.c \
arch/$(ARCH)/src/context.S \
arch/$(ARCH)/src/fpu_context.c \
arch/$(ARCH)/src/dummy.s \
arch/$(ARCH)/src/mm/as.c \
arch/$(ARCH)/src/mm/cache.S \
arch/$(ARCH)/src/mm/frame.c \
arch/$(ARCH)/src/mm/page.c \
arch/$(ARCH)/src/mm/tlb.c \
arch/$(ARCH)/src/sparc64.c \
arch/$(ARCH)/src/start.S \
arch/$(ARCH)/src/proc/scheduler.c \
arch/$(ARCH)/src/proc/thread.c \
arch/$(ARCH)/src/trap/mmu.S \
arch/$(ARCH)/src/trap/trap_table.S \
arch/$(ARCH)/src/trap/trap.c \
arch/$(ARCH)/src/trap/exception.c \
arch/$(ARCH)/src/trap/interrupt.c \
arch/$(ARCH)/src/ddi/ddi.c \
arch/$(ARCH)/src/drivers/tick.c \
arch/$(ARCH)/src/drivers/kbd.c \
arch/$(ARCH)/src/drivers/scr.c \
arch/$(ARCH)/src/drivers/pci.c
 
ifeq ($(CONFIG_SMP),y)
ARCH_SOURCES += \
arch/$(ARCH)/src/smp/ipi.c \
arch/$(ARCH)/src/smp/smp.c
ARCH_SOURCES += \
arch/$(KARCH)/src/smp/ipi.c \
arch/$(KARCH)/src/smp/smp.c
endif
 
ifeq ($(CONFIG_TSB),y)
ARCH_SOURCES += \
arch/$(ARCH)/src/mm/tsb.c
ARCH_SOURCES += \
arch/$(KARCH)/src/mm/tsb.c
endif
 
ifdef CONFIG_Z8530
ARCH_SOURCES += \
arch/$(ARCH)/src/drivers/fhc.c
ARCH_SOURCES += \
arch/$(KARCH)/src/drivers/fhc.c
endif
/branches/dd/kernel/arch/sparc64/src/smp/smp.c
35,6 → 35,7
#include <smp/smp.h>
#include <genarch/ofw/ofw_tree.h>
#include <cpu.h>
#include <arch/cpu_family.h>
#include <arch/cpu.h>
#include <arch.h>
#include <config.h>
43,6 → 44,7
#include <synch/synch.h>
#include <synch/waitq.h>
#include <print.h>
#include <arch/cpu_node.h>
 
/**
* This global variable is used to pick-up application processors
61,15 → 63,55
ofw_tree_node_t *node;
count_t cnt = 0;
node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
while (node) {
cnt++;
node = ofw_tree_find_peer_by_device_type(node, "cpu");
if (is_us() || is_us_iii()) {
node = ofw_tree_find_child_by_device_type(cpus_parent(), "cpu");
while (node) {
cnt++;
node = ofw_tree_find_peer_by_device_type(node, "cpu");
}
} else if (is_us_iv()) {
node = ofw_tree_find_child(cpus_parent(), "cmp");
while (node) {
cnt += 2;
node = ofw_tree_find_peer_by_name(node, "cmp");
}
}
config.cpu_count = max(1, cnt);
}
 
/**
* Wakes up the CPU which is represented by the "node" OFW tree node.
* If "node" represents the current CPU, calling the function has
* no effect.
*/
static void wakeup_cpu(ofw_tree_node_t *node)
{
uint32_t mid;
ofw_tree_property_t *prop;
/* 'upa-portid' for US, 'portid' for US-III, 'cpuid' for US-IV */
prop = ofw_tree_getprop(node, "upa-portid");
if ((!prop) || (!prop->value))
prop = ofw_tree_getprop(node, "portid");
if ((!prop) || (!prop->value))
prop = ofw_tree_getprop(node, "cpuid");
if (!prop || prop->value == NULL)
return;
mid = *((uint32_t *) prop->value);
if (CPU->arch.mid == mid)
return;
 
waking_up_mid = mid;
if (waitq_sleep_timeout(&ap_completion_wq, 1000000, SYNCH_FLAGS_NONE) ==
ESYNCH_TIMEOUT)
printf("%s: waiting for processor (mid = %" PRIu32
") timed out\n", __func__, mid);
}
 
/** Wake application processors up. */
void kmp(void *arg)
{
76,31 → 118,18
ofw_tree_node_t *node;
int i;
node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
for (i = 0; node; node = ofw_tree_find_peer_by_device_type(node, "cpu"), i++) {
uint32_t mid;
ofw_tree_property_t *prop;
prop = ofw_tree_getprop(node, "upa-portid");
if (!prop || !prop->value)
continue;
mid = *((uint32_t *) prop->value);
if (CPU->arch.mid == mid) {
/*
* Skip the current CPU.
*/
continue;
if (is_us() || is_us_iii()) {
node = ofw_tree_find_child_by_device_type(cpus_parent(), "cpu");
for (i = 0; node;
node = ofw_tree_find_peer_by_device_type(node, "cpu"), i++)
wakeup_cpu(node);
} else if (is_us_iv()) {
node = ofw_tree_find_child(cpus_parent(), "cmp");
while (node) {
wakeup_cpu(ofw_tree_find_child(node, "cpu@0"));
wakeup_cpu(ofw_tree_find_child(node, "cpu@1"));
node = ofw_tree_find_peer_by_name(node, "cmp");
}
 
/*
* Processor with ID == mid can proceed with its initialization.
*/
waking_up_mid = mid;
if (waitq_sleep_timeout(&ap_completion_wq, 1000000, SYNCH_FLAGS_NONE) == ESYNCH_TIMEOUT)
printf("%s: waiting for processor (mid = %d) timed out\n",
__func__, mid);
}
}
 
/branches/dd/kernel/arch/sparc64/src/smp/ipi.c
46,6 → 46,33
#include <time/delay.h>
#include <panic.h>
 
/** Set the contents of the outgoing interrupt vector data.
*
* The first data item (data 0) will be set to the value of func, the
* rest of the vector will contain zeros.
*
* This is a helper function used from within the cross_call function.
*
* @param func value the first data item of the vector will be set to
*/
static inline void set_intr_w_data(void (* func)(void))
{
#if defined (US)
asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_0, (uintptr_t) func);
asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_1, 0);
asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_2, 0);
#elif defined (US3)
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_0, (uintptr_t) func);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_1, 0);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_2, 0);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_3, 0);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_4, 0);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_5, 0);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_6, 0);
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_7, 0);
#endif
}
 
/** Invoke function on another processor.
*
* Currently, only functions without arguments are supported.
71,16 → 98,15
status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0);
if (status & INTR_DISPATCH_STATUS_BUSY)
panic("Interrupt Dispatch Status busy bit set\n");
panic("Interrupt Dispatch Status busy bit set.");
ASSERT(!(pstate_read() & PSTATE_IE_BIT));
do {
asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_0,
(uintptr_t) func);
asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_1, 0);
asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_2, 0);
asi_u64_write(ASI_UDB_INTR_W,
set_intr_w_data(func);
asi_u64_write(ASI_INTR_W,
(mid << INTR_VEC_DISPATCH_MID_SHIFT) |
ASI_UDB_INTR_W_DISPATCH, 0);
VA_INTR_W_DISPATCH, 0);
membar();
125,7 → 151,7
func = tlb_shootdown_ipi_recv;
break;
default:
panic("Unknown IPI (%d).\n", ipi);
panic("Unknown IPI (%d).", ipi);
break;
}
/branches/dd/kernel/arch/sparc64/src/ddi/ddi.c
41,7 → 41,7
* Interrupts are disabled and task is locked.
*
* @param task Task.
* @param ioaddr Startign I/O space address.
* @param ioaddr Starting I/O space address.
* @param size Size of the enabled I/O range.
*
* @return 0 on success or an error code from errno.h.
/branches/dd/kernel/arch/sparc64/src/asm.S
41,6 → 41,7
*/
.global memcpy
memcpy:
mov %o0, %o3 ! save dst
add %o1, 7, %g1
and %g1, -8, %g1
cmp %o1, %g1
59,7 → 60,7
mov %g2, %g3
2:
jmp %o7 + 8 ! exit point
mov %o1, %o0
mov %o3, %o0
3:
and %g1, -8, %g1
cmp %o0, %g1
93,7 → 94,7
mov %g2, %g3
 
jmp %o7 + 8 ! exit point
mov %o1, %o0
mov %o3, %o0
 
/*
* Almost the same as memcpy() except the loads are from userspace.
100,6 → 101,7
*/
.global memcpy_from_uspace
memcpy_from_uspace:
mov %o0, %o3 ! save dst
add %o1, 7, %g1
and %g1, -8, %g1
cmp %o1, %g1
118,7 → 120,7
mov %g2, %g3
2:
jmp %o7 + 8 ! exit point
mov %o1, %o0
mov %o3, %o0
3:
and %g1, -8, %g1
cmp %o0, %g1
152,7 → 154,7
mov %g2, %g3
 
jmp %o7 + 8 ! exit point
mov %o1, %o0
mov %o3, %o0
 
/*
* Almost the same as memcpy() except the stores are to userspace.
159,6 → 161,7
*/
.global memcpy_to_uspace
memcpy_to_uspace:
mov %o0, %o3 ! save dst
add %o1, 7, %g1
and %g1, -8, %g1
cmp %o1, %g1
177,7 → 180,7
mov %g2, %g3
2:
jmp %o7 + 8 ! exit point
mov %o1, %o0
mov %o3, %o0
3:
and %g1, -8, %g1
cmp %o0, %g1
211,7 → 214,7
mov %g2, %g3
 
jmp %o7 + 8 ! exit point
mov %o1, %o0
mov %o3, %o0
 
.global memcpy_from_uspace_failover_address
.global memcpy_to_uspace_failover_address
274,6 → 277,8
wrpr %g0, 0, %cleanwin ! avoid information leak
 
mov %i2, %o0 ! uarg
xor %o1, %o1, %o1 ! %o1 is defined to hold pcb_ptr
! set it to 0
 
clr %i2
clr %i3
/branches/dd/kernel/arch/sparc64/src/console.c
38,12 → 38,7
#include <arch/drivers/scr.h>
#include <arch/drivers/kbd.h>
 
#ifdef CONFIG_Z8530
#include <genarch/kbd/z8530.h>
#endif
#ifdef CONFIG_NS16550
#include <genarch/kbd/ns16550.h>
#endif
#include <arch/drivers/sgcn.h>
 
#include <console/chardev.h>
#include <console/console.h>
54,47 → 49,81
#include <genarch/ofw/ofw_tree.h>
#include <arch.h>
#include <panic.h>
#include <string.h>
#include <print.h>
 
#define KEYBOARD_POLL_PAUSE 50000 /* 50ms */
 
/** Initialize kernel console to use framebuffer and keyboard directly. */
void standalone_sparc64_console_init(void)
/**
* Initialize kernel console to use framebuffer and keyboard directly.
* Called on UltraSPARC machines with standard keyboard and framebuffer.
*
* @param aliases the "/aliases" OBP node
*/
static void standard_console_init(ofw_tree_node_t *aliases)
{
stdin = NULL;
 
ofw_tree_node_t *aliases;
#ifdef CONFIG_FB
ofw_tree_property_t *prop;
ofw_tree_node_t *screen;
ofw_tree_node_t *keyboard;
aliases = ofw_tree_lookup("/aliases");
if (!aliases)
panic("Can't find /aliases.\n");
prop = ofw_tree_getprop(aliases, "screen");
if (!prop)
panic("Can't find property \"screen\".\n");
panic("Cannot find property 'screen'.");
if (!prop->value)
panic("Can't find screen alias.\n");
panic("Cannot find screen alias.");
screen = ofw_tree_lookup(prop->value);
if (!screen)
panic("Can't find %s\n", prop->value);
panic("Cannot find %s.", prop->value);
 
scr_init(screen);
 
prop = ofw_tree_getprop(aliases, "keyboard");
if (!prop)
panic("Can't find property \"keyboard\".\n");
panic("Cannot find property 'keyboard'.");
if (!prop->value)
panic("Can't find keyboard alias.\n");
panic("Cannot find keyboard alias.");
keyboard = ofw_tree_lookup(prop->value);
if (!keyboard)
panic("Can't find %s\n", prop->value);
panic("Cannot find %s.", prop->value);
 
kbd_init(keyboard);
#else
panic("Standard console requires FB, "
"but the kernel is not compiled with FB support.");
#endif
}
 
/** Initilize I/O on the Serengeti machine. */
static void serengeti_init(void)
{
sgcn_init();
}
 
/**
* Initialize input/output. Auto-detects the type of machine
* and calls the appropriate I/O init routine.
*/
void standalone_sparc64_console_init(void)
{
ofw_tree_node_t *aliases;
ofw_tree_property_t *prop;
aliases = ofw_tree_lookup("/aliases");
if (!aliases)
panic("Cannot find '/aliases'.");
/* "def-cn" = "default console" */
prop = ofw_tree_getprop(aliases, "def-cn");
if ((!prop) || (!prop->value) || (strcmp(prop->value, "/sgcn") != 0)) {
standard_console_init(aliases);
} else {
serengeti_init();
}
}
 
 
/** Kernel thread for polling keyboard.
*
* @param arg Ignored.
103,19 → 132,13
{
thread_detach(THREAD);
 
#ifdef CONFIG_Z8530
if (kbd_type == KBD_Z8530) {
/*
* The z8530 driver is interrupt-driven.
*/
if (kbd_type != KBD_SGCN)
return;
}
#endif
 
while (1) {
#ifdef CONFIG_NS16550
if (kbd_type == KBD_NS16550)
ns16550_poll();
#ifdef CONFIG_SGCN
if (kbd_type == KBD_SGCN)
sgcn_poll();
#endif
thread_usleep(KEYBOARD_POLL_PAUSE);
}
126,17 → 149,15
*/
void arch_grab_console(void)
{
#ifdef CONFIG_FB
scr_redraw();
#endif
switch (kbd_type) {
#ifdef CONFIG_Z8530
case KBD_Z8530:
z8530_grab();
#ifdef CONFIG_SGCN
case KBD_SGCN:
sgcn_grab();
break;
#endif
#ifdef CONFIG_NS16550
case KBD_NS16550:
ns16550_grab();
break;
#endif
default:
break;
}
148,16 → 169,11
void arch_release_console(void)
{
switch (kbd_type) {
#ifdef CONFIG_Z8530
case KBD_Z8530:
z8530_release();
#ifdef CONFIG_SGCN
case KBD_SGCN:
sgcn_release();
break;
#endif
#ifdef CONFIG_NS16550
case KBD_NS16550:
ns16550_release();
break;
#endif
default:
break;
}
/branches/dd/kernel/arch/sparc64/src/proc/thread.c
34,9 → 34,8
 
#include <proc/thread.h>
#include <arch/proc/thread.h>
#include <mm/frame.h>
#include <mm/page.h>
#include <arch/mm/page.h>
#include <mm/slab.h>
#include <arch/trap/regwin.h>
#include <align.h>
 
void thr_constructor_arch(thread_t *t)
50,12 → 49,12
void thr_destructor_arch(thread_t *t)
{
if (t->arch.uspace_window_buffer) {
uintptr_t uw_buf = (uintptr_t) t->arch.uspace_window_buffer;
/*
* Mind the possible alignment of the userspace window buffer
* belonging to a killed thread.
*/
frame_free(KA2PA(ALIGN_DOWN((uintptr_t)
t->arch.uspace_window_buffer, PAGE_SIZE)));
free((uint8_t *) ALIGN_DOWN(uw_buf, UWB_ALIGNMENT));
}
}
 
67,7 → 66,7
* The thread needs userspace window buffer and the object
* returned from the slab allocator doesn't have any.
*/
t->arch.uspace_window_buffer = frame_alloc(ONE_FRAME, FRAME_KA);
t->arch.uspace_window_buffer = malloc(UWB_ASIZE, 0);
} else {
uintptr_t uw_buf = (uintptr_t) t->arch.uspace_window_buffer;
 
76,7 → 75,7
* belonging to a killed thread.
*/
t->arch.uspace_window_buffer = (uint8_t *) ALIGN_DOWN(uw_buf,
PAGE_SIZE);
UWB_ASIZE);
}
}
 
/branches/dd/kernel/arch/sparc64/src/sparc64.c
47,10 → 47,11
#include <genarch/ofw/ofw_tree.h>
#include <userspace.h>
#include <ddi/irq.h>
#include <string.h>
 
bootinfo_t bootinfo;
 
/** Perform sparc64 specific initialization before main_bsp() is called. */
/** Perform sparc64-specific initialization before main_bsp() is called. */
void arch_pre_main(void)
{
/* Copy init task info. */
61,6 → 62,8
for (i = 0; i < bootinfo.taskmap.count; i++) {
init.tasks[i].addr = (uintptr_t) bootinfo.taskmap.tasks[i].addr;
init.tasks[i].size = bootinfo.taskmap.tasks[i].size;
strncpy(init.tasks[i].name, bootinfo.taskmap.tasks[i].name,
CONFIG_TASK_NAME_BUFLEN);
}
/* Copy boot allocations info. */
86,8 → 89,6
* But we only create 128 buckets.
*/
irq_init(1 << 11, 128);
standalone_sparc64_console_init();
}
}
 
101,16 → 102,16
 
void arch_post_smp_init(void)
{
static thread_t *t = NULL;
if (config.cpu_active == 1) {
standalone_sparc64_console_init();
 
 
if (!t) {
/*
* Create thread that polls keyboard.
*/
t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll", true);
/* Create thread that polls keyboard.
* XXX: this is only used by sgcn now
*/
thread_t *t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll",
true);
if (!t)
panic("cannot create kkbdpoll\n");
panic("Cannot create kkbdpoll.");
thread_ready(t);
}
}
161,5 → 162,19
while (1);
}
 
/** Construct function pointer
*
* @param fptr function pointer structure
* @param addr function address
* @param caller calling function address
*
* @return address of the function pointer
*
*/
void *arch_construct_function(fncptr_t *fptr, void *addr, void *caller)
{
return addr;
}
 
/** @}
*/
/branches/dd/kernel/arch/sparc64/src/trap/exception.c
45,57 → 45,57
 
void dump_istate(istate_t *istate)
{
printf("TSTATE=%#llx\n", istate->tstate);
printf("TPC=%#llx (%s)\n", istate->tpc, get_symtab_entry(istate->tpc));
printf("TNPC=%#llx (%s)\n", istate->tnpc, get_symtab_entry(istate->tnpc));
printf("TSTATE=%#" PRIx64 "\n", istate->tstate);
printf("TPC=%#" PRIx64 " (%s)\n", istate->tpc, get_symtab_entry(istate->tpc));
printf("TNPC=%#" PRIx64 " (%s)\n", istate->tnpc, get_symtab_entry(istate->tnpc));
}
 
/** Handle instruction_access_exception. (0x8) */
void instruction_access_exception(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle instruction_access_error. (0xa) */
void instruction_access_error(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle illegal_instruction. (0x10) */
void illegal_instruction(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle privileged_opcode. (0x11) */
void privileged_opcode(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle unimplemented_LDD. (0x12) */
void unimplemented_LDD(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle unimplemented_STD. (0x13) */
void unimplemented_STD(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle fp_disabled. (0x20) */
113,9 → 113,9
#ifdef CONFIG_FPU_LAZY
scheduler_fpu_lazy_request();
#else
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
#endif
}
 
122,98 → 122,98
/** Handle fp_exception_ieee_754. (0x21) */
void fp_exception_ieee_754(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle fp_exception_other. (0x22) */
void fp_exception_other(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle tag_overflow. (0x23) */
void tag_overflow(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle division_by_zero. (0x28) */
void division_by_zero(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle data_access_exception. (0x30) */
void data_access_exception(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
dump_sfsr_and_sfar();
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle data_access_error. (0x32) */
void data_access_error(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle mem_address_not_aligned. (0x34) */
void mem_address_not_aligned(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle LDDF_mem_address_not_aligned. (0x35) */
void LDDF_mem_address_not_aligned(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle STDF_mem_address_not_aligned. (0x36) */
void STDF_mem_address_not_aligned(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle privileged_action. (0x37) */
void privileged_action(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle LDQF_mem_address_not_aligned. (0x38) */
void LDQF_mem_address_not_aligned(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** Handle STQF_mem_address_not_aligned. (0x39) */
void STQF_mem_address_not_aligned(int n, istate_t *istate)
{
fault_if_from_uspace(istate, "%s\n", __func__);
fault_if_from_uspace(istate, "%s.", __func__);
dump_istate(istate);
panic("%s\n", __func__);
panic("%s.", __func__);
}
 
/** @}
/branches/dd/kernel/arch/sparc64/src/trap/interrupt.c
67,11 → 67,19
*/
void interrupt(int n, istate_t *istate)
{
uint64_t status;
uint64_t intrcv;
uint64_t data0;
status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0);
if (status & (!INTR_DISPATCH_STATUS_BUSY))
panic("Interrupt Dispatch Status busy bit not set.");
 
intrcv = asi_u64_read(ASI_INTR_RECEIVE, 0);
data0 = asi_u64_read(ASI_UDB_INTR_R, ASI_UDB_INTR_R_DATA_0);
#if defined (US)
data0 = asi_u64_read(ASI_INTR_R, ASI_UDB_INTR_R_DATA_0);
#elif defined (US3)
data0 = asi_u64_read(ASI_INTR_R, VA_INTR_R_DATA_0);
#endif
 
irq_t *irq = irq_dispatch_and_lock(data0);
if (irq) {
78,7 → 86,13
/*
* The IRQ handler was found.
*/
irq->handler(irq, irq->arg);
irq->handler(irq);
/*
* See if there is a clear-interrupt-routine and call it.
*/
if (irq->cir) {
irq->cir(irq->cir_arg, irq->inr);
}
spinlock_unlock(&irq->lock);
} else if (data0 > config.base) {
/*
97,8 → 111,8
* Spurious interrupt.
*/
#ifdef CONFIG_DEBUG
printf("cpu%d: spurious interrupt (intrcv=%#llx, "
"data0=%#llx)\n", CPU->id, intrcv, data0);
printf("cpu%u: spurious interrupt (intrcv=%#" PRIx64
", data0=%#" PRIx64 ")\n", CPU->id, intrcv, data0);
#endif
}
 
/branches/dd/kernel/arch/sparc64/src/trap/trap_table.S
329,198 → 329,22
fill_1_normal_tl0:
FILL_NORMAL_HANDLER_USERSPACE
 
/* TT = 0x100, TL = 0, trap_instruction_0 */
.org trap_table + TT_TRAP_INSTRUCTION(0)*ENTRY_SIZE
.global trap_instruction_0_tl0
trap_instruction_0_tl0:
TRAP_INSTRUCTION 0
/* TT = 0x100 - 0x17f, TL = 0, trap_instruction_0 - trap_instruction_7f */
.irp cur, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,\
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,\
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,\
127
.org trap_table + (TT_TRAP_INSTRUCTION_0+\cur)*ENTRY_SIZE
.global trap_instruction_\cur\()_tl0
trap_instruction_\cur\()_tl0:
ba trap_instruction_handler
mov \cur, %g2
.endr
 
/* TT = 0x101, TL = 0, trap_instruction_1 */
.org trap_table + TT_TRAP_INSTRUCTION(1)*ENTRY_SIZE
.global trap_instruction_1_tl0
trap_instruction_1_tl0:
TRAP_INSTRUCTION 1
 
/* TT = 0x102, TL = 0, trap_instruction_2 */
.org trap_table + TT_TRAP_INSTRUCTION(2)*ENTRY_SIZE
.global trap_instruction_2_tl0
trap_instruction_2_tl0:
TRAP_INSTRUCTION 2
 
/* TT = 0x103, TL = 0, trap_instruction_3 */
.org trap_table + TT_TRAP_INSTRUCTION(3)*ENTRY_SIZE
.global trap_instruction_3_tl0
trap_instruction_3_tl0:
TRAP_INSTRUCTION 3
 
/* TT = 0x104, TL = 0, trap_instruction_4 */
.org trap_table + TT_TRAP_INSTRUCTION(4)*ENTRY_SIZE
.global trap_instruction_4_tl0
trap_instruction_4_tl0:
TRAP_INSTRUCTION 4
 
/* TT = 0x105, TL = 0, trap_instruction_5 */
.org trap_table + TT_TRAP_INSTRUCTION(5)*ENTRY_SIZE
.global trap_instruction_5_tl0
trap_instruction_5_tl0:
TRAP_INSTRUCTION 5
 
/* TT = 0x106, TL = 0, trap_instruction_6 */
.org trap_table + TT_TRAP_INSTRUCTION(6)*ENTRY_SIZE
.global trap_instruction_6_tl0
trap_instruction_6_tl0:
TRAP_INSTRUCTION 6
 
/* TT = 0x107, TL = 0, trap_instruction_7 */
.org trap_table + TT_TRAP_INSTRUCTION(7)*ENTRY_SIZE
.global trap_instruction_7_tl0
trap_instruction_7_tl0:
TRAP_INSTRUCTION 7
 
/* TT = 0x108, TL = 0, trap_instruction_8 */
.org trap_table + TT_TRAP_INSTRUCTION(8)*ENTRY_SIZE
.global trap_instruction_8_tl0
trap_instruction_8_tl0:
TRAP_INSTRUCTION 8
 
/* TT = 0x109, TL = 0, trap_instruction_9 */
.org trap_table + TT_TRAP_INSTRUCTION(9)*ENTRY_SIZE
.global trap_instruction_9_tl0
trap_instruction_9_tl0:
TRAP_INSTRUCTION 9
 
/* TT = 0x10a, TL = 0, trap_instruction_10 */
.org trap_table + TT_TRAP_INSTRUCTION(10)*ENTRY_SIZE
.global trap_instruction_10_tl0
trap_instruction_10_tl0:
TRAP_INSTRUCTION 10
 
/* TT = 0x10b, TL = 0, trap_instruction_11 */
.org trap_table + TT_TRAP_INSTRUCTION(11)*ENTRY_SIZE
.global trap_instruction_11_tl0
trap_instruction_11_tl0:
TRAP_INSTRUCTION 11
 
/* TT = 0x10c, TL = 0, trap_instruction_12 */
.org trap_table + TT_TRAP_INSTRUCTION(12)*ENTRY_SIZE
.global trap_instruction_12_tl0
trap_instruction_12_tl0:
TRAP_INSTRUCTION 12
 
/* TT = 0x10d, TL = 0, trap_instruction_13 */
.org trap_table + TT_TRAP_INSTRUCTION(13)*ENTRY_SIZE
.global trap_instruction_13_tl0
trap_instruction_13_tl0:
TRAP_INSTRUCTION 13
 
/* TT = 0x10e, TL = 0, trap_instruction_14 */
.org trap_table + TT_TRAP_INSTRUCTION(14)*ENTRY_SIZE
.global trap_instruction_14_tl0
trap_instruction_14_tl0:
TRAP_INSTRUCTION 14
 
/* TT = 0x10f, TL = 0, trap_instruction_15 */
.org trap_table + TT_TRAP_INSTRUCTION(15)*ENTRY_SIZE
.global trap_instruction_15_tl0
trap_instruction_15_tl0:
TRAP_INSTRUCTION 15
 
/* TT = 0x110, TL = 0, trap_instruction_16 */
.org trap_table + TT_TRAP_INSTRUCTION(16)*ENTRY_SIZE
.global trap_instruction_16_tl0
trap_instruction_16_tl0:
TRAP_INSTRUCTION 16
 
/* TT = 0x111, TL = 0, trap_instruction_17 */
.org trap_table + TT_TRAP_INSTRUCTION(17)*ENTRY_SIZE
.global trap_instruction_17_tl0
trap_instruction_17_tl0:
TRAP_INSTRUCTION 17
 
/* TT = 0x112, TL = 0, trap_instruction_18 */
.org trap_table + TT_TRAP_INSTRUCTION(18)*ENTRY_SIZE
.global trap_instruction_18_tl0
trap_instruction_18_tl0:
TRAP_INSTRUCTION 18
 
/* TT = 0x113, TL = 0, trap_instruction_19 */
.org trap_table + TT_TRAP_INSTRUCTION(19)*ENTRY_SIZE
.global trap_instruction_19_tl0
trap_instruction_19_tl0:
TRAP_INSTRUCTION 19
 
/* TT = 0x114, TL = 0, trap_instruction_20 */
.org trap_table + TT_TRAP_INSTRUCTION(20)*ENTRY_SIZE
.global trap_instruction_20_tl0
trap_instruction_20_tl0:
TRAP_INSTRUCTION 20
 
/* TT = 0x115, TL = 0, trap_instruction_21 */
.org trap_table + TT_TRAP_INSTRUCTION(21)*ENTRY_SIZE
.global trap_instruction_21_tl0
trap_instruction_21_tl0:
TRAP_INSTRUCTION 21
 
/* TT = 0x116, TL = 0, trap_instruction_22 */
.org trap_table + TT_TRAP_INSTRUCTION(22)*ENTRY_SIZE
.global trap_instruction_22_tl0
trap_instruction_22_tl0:
TRAP_INSTRUCTION 22
 
/* TT = 0x117, TL = 0, trap_instruction_23 */
.org trap_table + TT_TRAP_INSTRUCTION(23)*ENTRY_SIZE
.global trap_instruction_23_tl0
trap_instruction_23_tl0:
TRAP_INSTRUCTION 23
 
/* TT = 0x118, TL = 0, trap_instruction_24 */
.org trap_table + TT_TRAP_INSTRUCTION(24)*ENTRY_SIZE
.global trap_instruction_24_tl0
trap_instruction_24_tl0:
TRAP_INSTRUCTION 24
 
/* TT = 0x119, TL = 0, trap_instruction_25 */
.org trap_table + TT_TRAP_INSTRUCTION(25)*ENTRY_SIZE
.global trap_instruction_25_tl0
trap_instruction_25_tl0:
TRAP_INSTRUCTION 25
 
/* TT = 0x11a, TL = 0, trap_instruction_26 */
.org trap_table + TT_TRAP_INSTRUCTION(26)*ENTRY_SIZE
.global trap_instruction_26_tl0
trap_instruction_26_tl0:
TRAP_INSTRUCTION 26
 
/* TT = 0x11b, TL = 0, trap_instruction_27 */
.org trap_table + TT_TRAP_INSTRUCTION(27)*ENTRY_SIZE
.global trap_instruction_27_tl0
trap_instruction_27_tl0:
TRAP_INSTRUCTION 27
 
/* TT = 0x11c, TL = 0, trap_instruction_28 */
.org trap_table + TT_TRAP_INSTRUCTION(28)*ENTRY_SIZE
.global trap_instruction_28_tl0
trap_instruction_28_tl0:
TRAP_INSTRUCTION 28
 
/* TT = 0x11d, TL = 0, trap_instruction_29 */
.org trap_table + TT_TRAP_INSTRUCTION(29)*ENTRY_SIZE
.global trap_instruction_29_tl0
trap_instruction_29_tl0:
TRAP_INSTRUCTION 29
 
/* TT = 0x11e, TL = 0, trap_instruction_30 */
.org trap_table + TT_TRAP_INSTRUCTION(30)*ENTRY_SIZE
.global trap_instruction_30_tl0
trap_instruction_30_tl0:
TRAP_INSTRUCTION 30
 
/* TT = 0x11f, TL = 0, trap_instruction_31 */
.org trap_table + TT_TRAP_INSTRUCTION(31)*ENTRY_SIZE
.global trap_instruction_31_tl0
trap_instruction_31_tl0:
TRAP_INSTRUCTION 31
 
/*
* Handlers for TL>0.
*/
782,10 → 606,10
add %sp, PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_TNPC, %o1
.else
/*
* Call the higher-level syscall handler.
* Call the higher-level syscall handler and enable interrupts.
*/
call syscall_handler
nop
wrpr %g0, PSTATE_PRIV_BIT | PSTATE_PEF_BIT | PSTATE_IE_BIT, %pstate
mov %o0, %i0 ! copy the value returned by the syscall
.endif
 
924,9 → 748,8
* Fill all windows stored in the buffer.
*/
clr %g4
set PAGE_SIZE - 1, %g5
0: andcc %g7, %g5, %g0 ! PAGE_SIZE alignment check
bz 0f ! %g7 is page-aligned, no more windows to refill
0: andcc %g7, UWB_ALIGNMENT - 1, %g0 ! alignment check
bz 0f ! %g7 is UWB_ALIGNMENT-aligned, no more windows to refill
nop
 
add %g7, -STACK_WINDOW_SAVE_AREA_SIZE, %g7
/branches/dd/kernel/arch/sparc64/src/cpu/cpu.c
32,12 → 32,46
/** @file
*/
 
#include <arch/cpu_family.h>
#include <cpu.h>
#include <arch.h>
#include <genarch/ofw/ofw_tree.h>
#include <arch/drivers/tick.h>
#include <print.h>
#include <arch/cpu_node.h>
 
/**
* Finds out the clock frequency of the current CPU.
*
* @param node node representing the current CPU in the OFW tree
* @return clock frequency if "node" is the current CPU and no error
* occurs, -1 if "node" is not the current CPU or on error
*/
static int find_cpu_frequency(ofw_tree_node_t *node)
{
ofw_tree_property_t *prop;
uint32_t mid;
 
/* 'upa-portid' for US, 'portid' for US-III, 'cpuid' for US-IV */
prop = ofw_tree_getprop(node, "upa-portid");
if ((!prop) || (!prop->value))
prop = ofw_tree_getprop(node, "portid");
if ((!prop) || (!prop->value))
prop = ofw_tree_getprop(node, "cpuid");
if (prop && prop->value) {
mid = *((uint32_t *) prop->value);
if (mid == CPU->arch.mid) {
prop = ofw_tree_getprop(node, "clock-frequency");
if (prop && prop->value) {
return *((uint32_t *) prop->value);
}
}
}
return -1;
}
 
/** Perform sparc64 specific initialization of the processor structure for the
* current processor.
*/
44,34 → 78,37
void cpu_arch_init(void)
{
ofw_tree_node_t *node;
uint32_t mid;
uint32_t clock_frequency = 0;
upa_config_t upa_config;
upa_config.value = upa_config_read();
CPU->arch.mid = upa_config.mid;
CPU->arch.mid = read_mid();
/*
* Detect processor frequency.
*/
node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
while (node) {
ofw_tree_property_t *prop;
prop = ofw_tree_getprop(node, "upa-portid");
if (prop && prop->value) {
mid = *((uint32_t *) prop->value);
if (mid == CPU->arch.mid) {
prop = ofw_tree_getprop(node,
"clock-frequency");
if (prop && prop->value)
clock_frequency = *((uint32_t *)
prop->value);
}
if (is_us() || is_us_iii()) {
node = ofw_tree_find_child_by_device_type(cpus_parent(), "cpu");
while (node) {
int f = find_cpu_frequency(node);
if (f != -1)
clock_frequency = (uint32_t) f;
node = ofw_tree_find_peer_by_device_type(node, "cpu");
}
node = ofw_tree_find_peer_by_device_type(node, "cpu");
} else if (is_us_iv()) {
node = ofw_tree_find_child(cpus_parent(), "cmp");
while (node) {
int f;
f = find_cpu_frequency(
ofw_tree_find_child(node, "cpu@0"));
if (f != -1)
clock_frequency = (uint32_t) f;
f = find_cpu_frequency(
ofw_tree_find_child(node, "cpu@1"));
if (f != -1)
clock_frequency = (uint32_t) f;
node = ofw_tree_find_peer_by_name(node, "cmp");
}
}
 
CPU->arch.clock_frequency = clock_frequency;
tick_init();
}
124,6 → 161,15
case IMPL_ULTRASPARCIII:
impl = "UltraSPARC III";
break;
case IMPL_ULTRASPARCIII_PLUS:
impl = "UltraSPARC III+";
break;
case IMPL_ULTRASPARCIII_I:
impl = "UltraSPARC IIIi";
break;
case IMPL_ULTRASPARCIV:
impl = "UltraSPARC IV";
break;
case IMPL_ULTRASPARCIV_PLUS:
impl = "UltraSPARC IV+";
break;
135,7 → 181,7
break;
}
 
printf("cpu%d: manuf=%s, impl=%s, mask=%d (%dMHz)\n", m->id, manuf,
printf("cpu%d: manuf=%s, impl=%s, mask=%d (%d MHz)\n", m->id, manuf,
impl, m->arch.ver.mask, m->arch.clock_frequency / 1000000);
}
 
/branches/dd/kernel/arch/sparc64/src/mm/tlb.c
54,14 → 54,13
#include <arch/mm/tsb.h>
#endif
 
static void dtlb_pte_copy(pte_t *t, index_t index, bool ro);
static void itlb_pte_copy(pte_t *t, index_t index);
static void do_fast_instruction_access_mmu_miss_fault(istate_t *istate,
const char *str);
static void do_fast_data_access_mmu_miss_fault(istate_t *istate,
tlb_tag_access_reg_t tag, const char *str);
static void do_fast_data_access_protection_fault(istate_t *istate,
tlb_tag_access_reg_t tag, const char *str);
static void dtlb_pte_copy(pte_t *, index_t, bool);
static void itlb_pte_copy(pte_t *, index_t);
static void do_fast_instruction_access_mmu_miss_fault(istate_t *, const char *);
static void do_fast_data_access_mmu_miss_fault(istate_t *, tlb_tag_access_reg_t,
const char *);
static void do_fast_data_access_protection_fault(istate_t *,
tlb_tag_access_reg_t, const char *);
 
char *context_encoding[] = {
"Primary",
86,11 → 85,11
 
/** Insert privileged mapping into DMMU TLB.
*
* @param page Virtual page address.
* @param frame Physical frame address.
* @param pagesize Page size.
* @param locked True for permanent mappings, false otherwise.
* @param cacheable True if the mapping is cacheable, false otherwise.
* @param page Virtual page address.
* @param frame Physical frame address.
* @param pagesize Page size.
* @param locked True for permanent mappings, false otherwise.
* @param cacheable True if the mapping is cacheable, false otherwise.
*/
void dtlb_insert_mapping(uintptr_t page, uintptr_t frame, int pagesize,
bool locked, bool cacheable)
103,7 → 102,7
pg.address = page;
fr.address = frame;
 
tag.value = ASID_KERNEL;
tag.context = ASID_KERNEL;
tag.vpn = pg.vpn;
 
dtlb_tag_access_write(tag.value);
126,10 → 125,10
 
/** Copy PTE to TLB.
*
* @param t Page Table Entry to be copied.
* @param index Zero if lower 8K-subpage, one if higher 8K-subpage.
* @param ro If true, the entry will be created read-only, regardless of its
* w field.
* @param t Page Table Entry to be copied.
* @param index Zero if lower 8K-subpage, one if higher 8K-subpage.
* @param ro If true, the entry will be created read-only, regardless
* of its w field.
*/
void dtlb_pte_copy(pte_t *t, index_t index, bool ro)
{
165,8 → 164,8
 
/** Copy PTE to ITLB.
*
* @param t Page Table Entry to be copied.
* @param index Zero if lower 8K-subpage, one if higher 8K-subpage.
* @param t Page Table Entry to be copied.
* @param index Zero if lower 8K-subpage, one if higher 8K-subpage.
*/
void itlb_pte_copy(pte_t *t, index_t index)
{
235,10 → 234,11
* Note that some faults (e.g. kernel faults) were already resolved by the
* low-level, assembly language part of the fast_data_access_mmu_miss handler.
*
* @param tag Content of the TLB Tag Access register as it existed when the
* trap happened. This is to prevent confusion created by clobbered
* Tag Access register during a nested DTLB miss.
* @param istate Interrupted state saved on the stack.
* @param tag Content of the TLB Tag Access register as it existed
* when the trap happened. This is to prevent confusion
* created by clobbered Tag Access register during a nested
* DTLB miss.
* @param istate Interrupted state saved on the stack.
*/
void fast_data_access_mmu_miss(tlb_tag_access_reg_t tag, istate_t *istate)
{
287,10 → 287,11
 
/** DTLB protection fault handler.
*
* @param tag Content of the TLB Tag Access register as it existed when the
* trap happened. This is to prevent confusion created by clobbered
* Tag Access register during a nested DTLB miss.
* @param istate Interrupted state saved on the stack.
* @param tag Content of the TLB Tag Access register as it existed
* when the trap happened. This is to prevent confusion
* created by clobbered Tag Access register during a nested
* DTLB miss.
* @param istate Interrupted state saved on the stack.
*/
void fast_data_access_protection(tlb_tag_access_reg_t tag, istate_t *istate)
{
331,6 → 332,26
}
}
 
/** Print TLB entry (for debugging purposes).
*
* The diag field has been left out in order to make this function more generic
* (there is no diag field in US3 architeture).
*
* @param i TLB entry number
* @param t TLB entry tag
* @param d TLB entry data
*/
static void print_tlb_entry(int i, tlb_tag_read_reg_t t, tlb_data_t d)
{
printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, "
"ie=%d, soft2=%#x, pfn=%#x, soft=%#x, l=%d, "
"cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n", i, t.vpn,
t.context, d.v, d.size, d.nfo, d.ie, d.soft2,
d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
}
 
#if defined (US)
 
/** Print contents of both TLBs. */
void tlb_print(void)
{
342,12 → 363,7
for (i = 0; i < ITLB_ENTRY_COUNT; i++) {
d.value = itlb_data_access_read(i);
t.value = itlb_tag_read_read(i);
 
printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, "
"ie=%d, soft2=%#x, diag=%#x, pfn=%#x, soft=%#x, l=%d, "
"cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n", i, t.vpn,
t.context, d.v, d.size, d.nfo, d.ie, d.soft2, d.diag,
d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
print_tlb_entry(i, t, d);
}
 
printf("D-TLB contents:\n");
354,22 → 370,63
for (i = 0; i < DTLB_ENTRY_COUNT; i++) {
d.value = dtlb_data_access_read(i);
t.value = dtlb_tag_read_read(i);
printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, "
"ie=%d, soft2=%#x, diag=%#x, pfn=%#x, soft=%#x, l=%d, "
"cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n", i, t.vpn,
t.context, d.v, d.size, d.nfo, d.ie, d.soft2, d.diag,
d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
print_tlb_entry(i, t, d);
}
}
 
#elif defined (US3)
 
/** Print contents of all TLBs. */
void tlb_print(void)
{
int i;
tlb_data_t d;
tlb_tag_read_reg_t t;
printf("TLB_ISMALL contents:\n");
for (i = 0; i < tlb_ismall_size(); i++) {
d.value = dtlb_data_access_read(TLB_ISMALL, i);
t.value = dtlb_tag_read_read(TLB_ISMALL, i);
print_tlb_entry(i, t, d);
}
printf("TLB_IBIG contents:\n");
for (i = 0; i < tlb_ibig_size(); i++) {
d.value = dtlb_data_access_read(TLB_IBIG, i);
t.value = dtlb_tag_read_read(TLB_IBIG, i);
print_tlb_entry(i, t, d);
}
printf("TLB_DSMALL contents:\n");
for (i = 0; i < tlb_dsmall_size(); i++) {
d.value = dtlb_data_access_read(TLB_DSMALL, i);
t.value = dtlb_tag_read_read(TLB_DSMALL, i);
print_tlb_entry(i, t, d);
}
printf("TLB_DBIG_1 contents:\n");
for (i = 0; i < tlb_dbig_size(); i++) {
d.value = dtlb_data_access_read(TLB_DBIG_0, i);
t.value = dtlb_tag_read_read(TLB_DBIG_0, i);
print_tlb_entry(i, t, d);
}
printf("TLB_DBIG_2 contents:\n");
for (i = 0; i < tlb_dbig_size(); i++) {
d.value = dtlb_data_access_read(TLB_DBIG_1, i);
t.value = dtlb_tag_read_read(TLB_DBIG_1, i);
print_tlb_entry(i, t, d);
}
}
 
#endif
 
void do_fast_instruction_access_mmu_miss_fault(istate_t *istate,
const char *str)
{
fault_if_from_uspace(istate, "%s\n", str);
fault_if_from_uspace(istate, "%s.", str);
dump_istate(istate);
panic("%s\n", str);
panic("%s.", str);
}
 
void do_fast_data_access_mmu_miss_fault(istate_t *istate,
379,12 → 436,12
 
va = tag.vpn << MMU_PAGE_WIDTH;
if (tag.context) {
fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d)\n", str, va,
fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d).", str, va,
tag.context);
}
dump_istate(istate);
printf("Faulting page: %p, ASID=%d\n", va, tag.context);
panic("%s\n", str);
printf("Faulting page: %p, ASID=%d.\n", va, tag.context);
panic("%s.", str);
}
 
void do_fast_data_access_protection_fault(istate_t *istate,
395,12 → 452,12
va = tag.vpn << MMU_PAGE_WIDTH;
 
if (tag.context) {
fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d)\n", str, va,
fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d).", str, va,
tag.context);
}
printf("Faulting page: %p, ASID=%d\n", va, tag.context);
dump_istate(istate);
panic("%s\n", str);
panic("%s.", str);
}
 
void dump_sfsr_and_sfar(void)
411,30 → 468,71
sfsr.value = dtlb_sfsr_read();
sfar = dtlb_sfar_read();
#if defined (US)
printf("DTLB SFSR: asi=%#x, ft=%#x, e=%d, ct=%d, pr=%d, w=%d, ow=%d, "
"fv=%d\n", sfsr.asi, sfsr.ft, sfsr.e, sfsr.ct, sfsr.pr, sfsr.w,
sfsr.ow, sfsr.fv);
#elif defined (US3)
printf("DTLB SFSR: nf=%d, asi=%#x, tm=%d, ft=%#x, e=%d, ct=%d, pr=%d, "
"w=%d, ow=%d, fv=%d\n", sfsr.nf, sfsr.asi, sfsr.tm, sfsr.ft,
sfsr.e, sfsr.ct, sfsr.pr, sfsr.w, sfsr.ow, sfsr.fv);
#endif
printf("DTLB SFAR: address=%p\n", sfar);
dtlb_sfsr_write(0);
}
 
#if defined (US3)
/** Invalidates given TLB entry if and only if it is non-locked or global.
*
* @param tlb TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1,
* TLB_ISMALL, TLB_IBIG).
* @param entry Entry index within the given TLB.
*/
static void tlb_invalidate_entry(int tlb, index_t entry)
{
tlb_data_t d;
tlb_tag_read_reg_t t;
if (tlb == TLB_DSMALL || tlb == TLB_DBIG_0 || tlb == TLB_DBIG_1) {
d.value = dtlb_data_access_read(tlb, entry);
if (!d.l || d.g) {
t.value = dtlb_tag_read_read(tlb, entry);
d.v = false;
dtlb_tag_access_write(t.value);
dtlb_data_access_write(tlb, entry, d.value);
}
} else if (tlb == TLB_ISMALL || tlb == TLB_IBIG) {
d.value = itlb_data_access_read(tlb, entry);
if (!d.l || d.g) {
t.value = itlb_tag_read_read(tlb, entry);
d.v = false;
itlb_tag_access_write(t.value);
itlb_data_access_write(tlb, entry, d.value);
}
}
}
#endif
 
/** Invalidate all unlocked ITLB and DTLB entries. */
void tlb_invalidate_all(void)
{
int i;
tlb_data_t d;
tlb_tag_read_reg_t t;
 
/*
* Walk all ITLB and DTLB entries and remove all unlocked mappings.
*
* The kernel doesn't use global mappings so any locked global mappings
* found must have been created by someone else. Their only purpose now
* found must have been created by someone else. Their only purpose now
* is to collide with proper mappings. Invalidate immediately. It should
* be safe to invalidate them as late as now.
*/
 
#if defined (US)
tlb_data_t d;
tlb_tag_read_reg_t t;
 
for (i = 0; i < ITLB_ENTRY_COUNT; i++) {
d.value = itlb_data_access_read(i);
if (!d.l || d.g) {
444,7 → 542,7
itlb_data_access_write(i, d.value);
}
}
 
for (i = 0; i < DTLB_ENTRY_COUNT; i++) {
d.value = dtlb_data_access_read(i);
if (!d.l || d.g) {
454,7 → 552,21
dtlb_data_access_write(i, d.value);
}
}
 
#elif defined (US3)
 
for (i = 0; i < tlb_ismall_size(); i++)
tlb_invalidate_entry(TLB_ISMALL, i);
for (i = 0; i < tlb_ibig_size(); i++)
tlb_invalidate_entry(TLB_IBIG, i);
for (i = 0; i < tlb_dsmall_size(); i++)
tlb_invalidate_entry(TLB_DSMALL, i);
for (i = 0; i < tlb_dbig_size(); i++)
tlb_invalidate_entry(TLB_DBIG_0, i);
for (i = 0; i < tlb_dbig_size(); i++)
tlb_invalidate_entry(TLB_DBIG_1, i);
#endif
 
}
 
/** Invalidate all ITLB and DTLB entries that belong to specified ASID
484,9 → 596,9
/** Invalidate all ITLB and DTLB entries for specified page range in specified
* address space.
*
* @param asid Address Space ID.
* @param page First page which to sweep out from ITLB and DTLB.
* @param cnt Number of ITLB and DTLB entries to invalidate.
* @param asid Address Space ID.
* @param page First page which to sweep out from ITLB and DTLB.
* @param cnt Number of ITLB and DTLB entries to invalidate.
*/
void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt)
{
/branches/dd/kernel/arch/sparc64/src/mm/as.c
76,7 → 76,7
as->arch.dtsb = (tsb_entry_t *) (tsb + ITSB_ENTRY_COUNT *
sizeof(tsb_entry_t));
 
memsetb((uintptr_t) as->arch.itsb,
memsetb(as->arch.itsb,
(ITSB_ENTRY_COUNT + DTSB_ENTRY_COUNT) * sizeof(tsb_entry_t), 0);
#endif
return 0;
164,7 → 164,25
itsb_base_write(tsb_base.value);
tsb_base.base = ((uintptr_t) as->arch.dtsb) >> MMU_PAGE_WIDTH;
dtsb_base_write(tsb_base.value);
#if defined (US3)
/*
* Clear the extension registers.
* In HelenOS, primary and secondary context registers contain
* equal values and kernel misses (context 0, ie. the nucleus context)
* are excluded from the TSB miss handler, so it makes no sense
* to have separate TSBs for primary, secondary and nucleus contexts.
* Clearing the extension registers will ensure that the value of the
* TSB Base register will be used as an address of TSB, making the code
* compatible with the US port.
*/
itsb_primary_extension_write(0);
itsb_nucleus_extension_write(0);
dtsb_primary_extension_write(0);
dtsb_secondary_extension_write(0);
dtsb_nucleus_extension_write(0);
#endif
#endif
}
 
/** Perform sparc64-specific tasks when an address space is removed from the
/branches/dd/kernel/arch/sparc64/src/mm/cache.S
27,10 → 27,8
*/
 
#include <arch/arch.h>
#include <arch/mm/cache_spec.h>
 
#define DCACHE_SIZE (16 * 1024)
#define DCACHE_LINE_SIZE 32
 
#define DCACHE_TAG_SHIFT 2
 
.register %g2, #scratch
49,45 → 47,3
retl
! beware SF Erratum #51, do not put the MEMBAR here
nop
 
/** Flush only D-cache lines of one virtual color.
*
* @param o0 Virtual color to be flushed.
*/
.global dcache_flush_color
dcache_flush_color:
mov (DCACHE_SIZE / DCACHE_LINE_SIZE) / 2, %g1
set DCACHE_SIZE / 2, %g2
sllx %g2, %o0, %g2
sub %g2, DCACHE_LINE_SIZE, %g2
0: stxa %g0, [%g2] ASI_DCACHE_TAG
membar #Sync
subcc %g1, 1, %g1
bnz,pt %xcc, 0b
sub %g2, DCACHE_LINE_SIZE, %g2
retl
nop
 
/** Flush only D-cache lines of one virtual color and one tag.
*
* @param o0 Virtual color to lookup the tag.
* @param o1 Tag of the cachelines to be flushed.
*/
.global dcache_flush_tag
dcache_flush_tag:
mov (DCACHE_SIZE / DCACHE_LINE_SIZE) / 2, %g1
set DCACHE_SIZE / 2, %g2
sllx %g2, %o0, %g2
sub %g2, DCACHE_LINE_SIZE, %g2
0: ldxa [%g2] ASI_DCACHE_TAG, %g3
srlx %g3, DCACHE_TAG_SHIFT, %g3
cmp %g3, %o1
bnz 1f
nop
stxa %g0, [%g2] ASI_DCACHE_TAG
membar #Sync
1: subcc %g1, 1, %g1
bnz,pt %xcc, 0b
sub %g2, DCACHE_LINE_SIZE, %g2
retl
nop
/branches/dd/kernel/arch/sparc64/src/mm/tsb.c
112,9 → 112,9
tsb->data.value = 0;
tsb->data.size = PAGESIZE_8K;
tsb->data.pfn = (t->frame >> MMU_FRAME_WIDTH) + index;
tsb->data.cp = t->c;
tsb->data.p = t->k; /* p as privileged */
tsb->data.v = t->p;
tsb->data.cp = t->c; /* cp as cache in phys.-idxed, c as cacheable */
tsb->data.p = t->k; /* p as privileged, k as kernel */
tsb->data.v = t->p; /* v as valid, p as present */
write_barrier();
173,3 → 173,4
 
/** @}
*/
 
/branches/dd/kernel/arch/sparc64/src/mm/frame.c
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64mm
/** @addtogroup sparc64mm
* @{
*/
/** @file
79,7 → 79,6
*/
frame_mark_unavailable(ADDR2PFN(KA2PA(PFN2ADDR(0))), 1);
}
}
 
/** @}
/branches/dd/kernel/arch/sparc64/src/mm/page.c
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup sparc64mm
/** @addtogroup sparc64mm
* @{
*/
/** @file
52,7 → 52,7
uintptr_t virt_page;
uintptr_t phys_page;
int pagesize_code;
} bsp_locked_dtlb_entry[DTLB_ENTRY_COUNT];
} bsp_locked_dtlb_entry[DTLB_MAX_LOCKED_ENTRIES];
 
/** Number of entries in bsp_locked_dtlb_entry array. */
static count_t bsp_locked_dtlb_entries = 0;
147,7 → 147,7
physaddr + i * sizemap[order].increment,
sizemap[order].pagesize_code, true, false);
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
/*
* Second, save the information about the mapping for APs.
*/
/branches/dd/kernel/arch/sparc64/src/drivers/fhc.c
45,6 → 45,7
#include <mm/slab.h>
#include <arch/types.h>
#include <genarch/ofw/ofw_tree.h>
#include <sysinfo/sysinfo.h>
 
fhc_t *central_fhc = NULL;
 
86,6 → 87,13
 
fhc->uart_imap = (uint32_t *) hw_map(paddr, reg->size);
/*
* Set sysinfo data needed by the uspace FHC driver.
*/
sysinfo_set_item_val("fhc.uart.size", NULL, reg->size);
sysinfo_set_item_val("fhc.uart.physical", NULL, paddr);
sysinfo_set_item_val("kbd.cir.fhc", NULL, 1);
 
return fhc;
}
 
96,13 → 104,14
fhc->uart_imap[FHC_UART_IMAP] |= IMAP_V_MASK;
break;
default:
panic("Unexpected INR (%d)\n", inr);
panic("Unexpected INR (%d).", inr);
break;
}
}
 
void fhc_clear_interrupt(fhc_t *fhc, int inr)
void fhc_clear_interrupt(void *fhcp, int inr)
{
fhc_t *fhc = (fhc_t *)fhcp;
ASSERT(fhc->uart_imap);
 
switch (inr) {
110,7 → 119,7
fhc->uart_imap[FHC_UART_ICLR] = 0;
break;
default:
panic("Unexpected INR (%d)\n", inr);
panic("Unexpected INR (%d).", inr);
break;
}
}
/branches/dd/kernel/arch/sparc64/src/drivers/kbd.c
34,19 → 34,26
 
#include <arch/drivers/kbd.h>
#include <genarch/ofw/ofw_tree.h>
 
#ifdef CONFIG_SUN_KBD
#include <genarch/kbrd/kbrd.h>
#endif
#ifdef CONFIG_Z8530
#include <genarch/kbd/z8530.h>
#include <genarch/drivers/z8530/z8530.h>
#endif
#ifdef CONFIG_NS16550
#include <genarch/kbd/ns16550.h>
#include <genarch/drivers/ns16550/ns16550.h>
#endif
 
#include <console/console.h>
#include <ddi/device.h>
#include <ddi/irq.h>
#include <arch/mm/page.h>
#include <arch/types.h>
#include <align.h>
#include <func.h>
#include <string.h>
#include <print.h>
#include <sysinfo/sysinfo.h>
 
kbd_type_t kbd_type = KBD_UNKNOWN;
 
63,6 → 70,15
uintptr_t aligned_addr;
ofw_tree_property_t *prop;
const char *name;
cir_t cir;
void *cir_arg;
 
#ifdef CONFIG_NS16550
ns16550_t *ns16550;
#endif
#ifdef CONFIG_Z8530
z8530_t *z8530;
#endif
name = ofw_tree_node_name(node);
84,30 → 100,33
*/
uint32_t interrupts;
prop = ofw_tree_getprop(node, "interrupts");
if (!prop || !prop->value)
panic("Can't find \"interrupts\" property.\n");
if ((!prop) || (!prop->value))
panic("Cannot find 'interrupt' property.");
interrupts = *((uint32_t *) prop->value);
 
/*
* Read 'reg' property.
*/
prop = ofw_tree_getprop(node, "reg");
if (!prop || !prop->value)
panic("Can't find \"reg\" property.\n");
if ((!prop) || (!prop->value))
panic("Cannot find 'reg' property.");
uintptr_t pa;
size_t size;
devno_t devno;
inr_t inr;
devno_t devno = device_assign_devno();
switch (kbd_type) {
case KBD_Z8530:
size = ((ofw_fhc_reg_t *) prop->value)->size;
if (!ofw_fhc_apply_ranges(node->parent, ((ofw_fhc_reg_t *) prop->value) , &pa)) {
if (!ofw_fhc_apply_ranges(node->parent,
((ofw_fhc_reg_t *) prop->value), &pa)) {
printf("Failed to determine keyboard address.\n");
return;
}
if (!ofw_fhc_map_interrupt(node->parent, ((ofw_fhc_reg_t *) prop->value), interrupts, &inr)) {
if (!ofw_fhc_map_interrupt(node->parent,
((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
&cir_arg)) {
printf("Failed to determine keyboard interrupt.\n");
return;
}
115,18 → 134,20
case KBD_NS16550:
size = ((ofw_ebus_reg_t *) prop->value)->size;
if (!ofw_ebus_apply_ranges(node->parent, ((ofw_ebus_reg_t *) prop->value) , &pa)) {
if (!ofw_ebus_apply_ranges(node->parent,
((ofw_ebus_reg_t *) prop->value), &pa)) {
printf("Failed to determine keyboard address.\n");
return;
}
if (!ofw_ebus_map_interrupt(node->parent, ((ofw_ebus_reg_t *) prop->value), interrupts, &inr)) {
if (!ofw_ebus_map_interrupt(node->parent,
((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
&cir_arg)) {
printf("Failed to determine keyboard interrupt.\n");
return;
};
break;
 
default:
panic("Unexpected type.\n");
panic("Unexpected keyboard type.");
}
/*
137,21 → 158,53
*/
aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
offset = pa - aligned_addr;
uintptr_t vaddr = hw_map(aligned_addr, offset + size) + offset;
 
switch (kbd_type) {
#ifdef CONFIG_Z8530
case KBD_Z8530:
z8530_init(devno, inr, vaddr);
devno = device_assign_devno();
z8530 = (z8530_t *) hw_map(aligned_addr, offset + size) +
offset;
kbrd_init(stdin);
(void) z8530_init(z8530, devno, inr, cir, cir_arg, &kbrdin);
/*
* This is the necessary evil until the userspace drivers are
* entirely self-sufficient.
*/
sysinfo_set_item_val("kbd", NULL, true);
sysinfo_set_item_val("kbd.type", NULL, KBD_Z8530);
sysinfo_set_item_val("kbd.devno", NULL, devno);
sysinfo_set_item_val("kbd.inr", NULL, inr);
sysinfo_set_item_val("kbd.address.kernel", NULL,
(uintptr_t) z8530);
sysinfo_set_item_val("kbd.address.physical", NULL, pa);
break;
#endif
#ifdef CONFIG_NS16550
case KBD_NS16550:
ns16550_init(devno, inr, vaddr);
devno = device_assign_devno();
ns16550 = (ns16550_t *) hw_map(aligned_addr, offset + size) +
offset;
kbrd_init(stdin);
(void) ns16550_init(ns16550, devno, inr, cir, cir_arg, &kbrdin);
/*
* This is the necessary evil until the userspace driver is
* entirely self-sufficient.
*/
sysinfo_set_item_val("kbd", NULL, true);
sysinfo_set_item_val("kbd.type", NULL, KBD_NS16550);
sysinfo_set_item_val("kbd.devno", NULL, devno);
sysinfo_set_item_val("kbd.inr", NULL, inr);
sysinfo_set_item_val("kbd.address.kernel", NULL,
(uintptr_t) ns16550);
sysinfo_set_item_val("kbd.address.physical", NULL, pa);
break;
#endif
default:
printf("Kernel is not compiled with the necessary keyboard driver this machine requires.\n");
printf("Kernel is not compiled with the necessary keyboard "
"driver this machine requires.\n");
}
}
 
/branches/dd/kernel/arch/sparc64/src/drivers/scr.c
37,7 → 37,7
#include <genarch/fb/fb.h>
#include <genarch/fb/visuals.h>
#include <arch/types.h>
#include <func.h>
#include <string.h>
#include <align.h>
#include <print.h>
 
55,6 → 55,10
void scr_init(ofw_tree_node_t *node)
{
ofw_tree_property_t *prop;
ofw_pci_reg_t *pci_reg;
ofw_pci_reg_t pci_abs_reg;
ofw_upa_reg_t *upa_reg;
ofw_sbus_reg_t *sbus_reg;
const char *name;
name = ofw_tree_node_name(node);
61,6 → 65,8
if (strcmp(name, "SUNW,m64B") == 0)
scr_type = SCR_ATYFB;
else if (strcmp(name, "SUNW,XVR-100") == 0)
scr_type = SCR_XVR;
else if (strcmp(name, "SUNW,ffb") == 0)
scr_type = SCR_FFB;
else if (strcmp(name, "cgsix") == 0)
67,11 → 73,12
scr_type = SCR_CGSIX;
if (scr_type == SCR_UNKNOWN) {
printf("Unknown keyboard device.\n");
printf("Unknown screen device.\n");
return;
}
uintptr_t fb_addr;
unsigned int fb_offset = 0;
uint32_t fb_width = 0;
uint32_t fb_height = 0;
uint32_t fb_depth = 0;
97,7 → 104,7
 
prop = ofw_tree_getprop(node, "reg");
if (!prop)
panic("Can't find \"reg\" property.\n");
panic("Cannot find 'reg' property.");
 
switch (scr_type) {
case SCR_ATYFB:
106,15 → 113,15
return;
}
ofw_pci_reg_t *fb_reg = &((ofw_pci_reg_t *) prop->value)[1];
ofw_pci_reg_t abs_reg;
pci_reg = &((ofw_pci_reg_t *) prop->value)[1];
if (!ofw_pci_reg_absolutize(node, fb_reg, &abs_reg)) {
if (!ofw_pci_reg_absolutize(node, pci_reg, &pci_abs_reg)) {
printf("Failed to absolutize fb register.\n");
return;
}
if (!ofw_pci_apply_ranges(node->parent, &abs_reg , &fb_addr)) {
if (!ofw_pci_apply_ranges(node->parent, &pci_abs_reg,
&fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
142,12 → 149,56
}
break;
case SCR_XVR:
if (prop->size / sizeof(ofw_pci_reg_t) < 2) {
printf("Too few screen registers.\n");
return;
}
pci_reg = &((ofw_pci_reg_t *) prop->value)[1];
if (!ofw_pci_reg_absolutize(node, pci_reg, &pci_abs_reg)) {
printf("Failed to absolutize fb register.\n");
return;
}
if (!ofw_pci_apply_ranges(node->parent, &pci_abs_reg,
&fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
 
fb_offset = 4 * 0x2000;
 
switch (fb_depth) {
case 8:
fb_scanline = fb_linebytes * (fb_depth >> 3);
visual = VISUAL_INDIRECT_8;
break;
case 16:
fb_scanline = fb_linebytes * (fb_depth >> 3);
visual = VISUAL_RGB_5_6_5;
break;
case 24:
fb_scanline = fb_linebytes * 4;
visual = VISUAL_RGB_8_8_8_0;
break;
case 32:
fb_scanline = fb_linebytes * (fb_depth >> 3);
visual = VISUAL_RGB_0_8_8_8;
break;
default:
printf("Unsupported bits per pixel.\n");
return;
}
break;
case SCR_FFB:
fb_scanline = 8192;
visual = VISUAL_BGR_0_8_8_8;
 
ofw_upa_reg_t *reg = &((ofw_upa_reg_t *) prop->value)[FFB_REG_24BPP];
if (!ofw_upa_apply_ranges(node->parent, reg, &fb_addr)) {
upa_reg = &((ofw_upa_reg_t *) prop->value)[FFB_REG_24BPP];
if (!ofw_upa_apply_ranges(node->parent, upa_reg, &fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
164,8 → 215,8
return;
}
ofw_sbus_reg_t *cg6_reg = &((ofw_sbus_reg_t *) prop->value)[0];
if (!ofw_sbus_apply_ranges(node->parent, cg6_reg, &fb_addr)) {
sbus_reg = &((ofw_sbus_reg_t *) prop->value)[0];
if (!ofw_sbus_apply_ranges(node->parent, sbus_reg, &fb_addr)) {
printf("Failed to determine screen address.\n");
return;
}
172,11 → 223,24
break;
default:
panic("Unexpected type.\n");
panic("Unexpected type.");
}
 
fb_init(fb_addr, fb_width, fb_height, fb_scanline, visual);
fb_properties_t props = {
.addr = fb_addr,
.offset = fb_offset,
.x = fb_width,
.y = fb_height,
.scan = fb_scanline,
.visual = visual,
};
fb_init(&props);
}
 
void scr_redraw(void)
{
fb_redraw();
}
 
/** @}
*/
/branches/dd/kernel/arch/sparc64/src/drivers/tick.c
45,11 → 45,12
 
#define TICK_RESTART_TIME 50 /* Worst case estimate. */
 
/** Initialize tick interrupt. */
/** Initialize tick and stick interrupt. */
void tick_init(void)
{
/* initialize TICK interrupt */
tick_compare_reg_t compare;
 
interrupt_register(14, "tick_int", tick_interrupt);
compare.int_dis = false;
compare.tick_cmpr = CPU->arch.clock_frequency / HZ;
56,6 → 57,21
CPU->arch.next_tick_cmpr = compare.tick_cmpr;
tick_compare_write(compare.value);
tick_write(0);
 
#if defined (US3)
/* disable STICK interrupts and clear any pending ones */
tick_compare_reg_t stick_compare;
softint_reg_t clear;
 
stick_compare.value = stick_compare_read();
stick_compare.int_dis = true;
stick_compare.tick_cmpr = 0;
stick_compare_write(stick_compare.value);
 
clear.value = 0;
clear.stick_int = 1;
clear_softint_write(clear.value);
#endif
}
 
/** Process tick interrupt.
67,7 → 83,7
{
softint_reg_t softint, clear;
uint64_t drift;
 
softint.value = softint_read();
/*
/branches/dd/kernel/arch/sparc64/src/drivers/sgcn.c
0,0 → 1,436
/*
* Copyright (c) 2008 Pavel Rimsky
* All rights reserved.
*
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR 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.
*/
 
/** @addtogroup sparc64
* @{
*/
/**
* @file
* @brief SGCN driver.
*/
 
#include <arch/drivers/sgcn.h>
#include <arch/drivers/kbd.h>
#include <genarch/ofw/ofw_tree.h>
#include <debug.h>
#include <string.h>
#include <print.h>
#include <mm/page.h>
#include <ipc/irq.h>
#include <ddi/ddi.h>
#include <ddi/device.h>
#include <console/chardev.h>
#include <console/console.h>
#include <ddi/device.h>
#include <sysinfo/sysinfo.h>
#include <synch/spinlock.h>
 
/*
* Physical address at which the SBBC starts. This value has been obtained
* by inspecting (using Simics) memory accesses made by OBP. It is valid
* for the Simics-simulated Serengeti machine. The author of this code is
* not sure whether this value is valid generally.
*/
#define SBBC_START 0x63000000000
 
/* offset of SRAM within the SBBC memory */
#define SBBC_SRAM_OFFSET 0x900000
 
/* size (in bytes) of the physical memory area which will be mapped */
#define MAPPED_AREA_SIZE (128 * 1024)
 
/* magic string contained at the beginning of SRAM */
#define SRAM_TOC_MAGIC "TOCSRAM"
 
/*
* Key into the SRAM table of contents which identifies the entry
* describing the OBP console buffer. It is worth mentioning
* that the OBP console buffer is not the only console buffer
* which can be used. It is, however, used because when the kernel
* is running, the OBP buffer is not used by OBP any more but OBP
* has already made neccessary arangements so that the output will
* be read from the OBP buffer and input will go to the OBP buffer.
* Therefore HelenOS needs to make no such arrangements any more.
*/
#define CONSOLE_KEY "OBPCONS"
 
/* magic string contained at the beginning of the console buffer */
#define SGCN_BUFFER_MAGIC "CON"
 
/**
* The driver is polling based, but in order to notify the userspace
* of a key being pressed, we need to supply the interface with some
* interrupt number. The interrupt number can be arbitrary as it it
* will never be used for identifying HW interrupts, but only in
* notifying the userspace.
*/
#define FICTIONAL_INR 1
 
 
/*
* Returns a pointer to the object of a given type which is placed at the given
* offset from the SRAM beginning.
*/
#define SRAM(type, offset) ((type *) (sram_begin + (offset)))
 
/* Returns a pointer to the SRAM table of contents. */
#define SRAM_TOC (SRAM(iosram_toc_t, 0))
 
/*
* Returns a pointer to the object of a given type which is placed at the given
* offset from the console buffer beginning.
*/
#define SGCN_BUFFER(type, offset) \
((type *) (sgcn_buffer_begin + (offset)))
 
/** Returns a pointer to the console buffer header. */
#define SGCN_BUFFER_HEADER (SGCN_BUFFER(sgcn_buffer_header_t, 0))
 
/** defined in drivers/kbd.c */
extern kbd_type_t kbd_type;
 
/** starting address of SRAM, will be set by the init_sram_begin function */
static uintptr_t sram_begin;
 
/**
* starting address of the SGCN buffer, will be set by the
* init_sgcn_buffer_begin function
*/
static uintptr_t sgcn_buffer_begin;
 
/**
* SGCN IRQ structure. So far used only for notifying the userspace of the
* key being pressed, not for kernel being informed about keyboard interrupts.
*/
static irq_t sgcn_irq;
 
// TODO think of a way how to synchronize accesses to SGCN buffer between the kernel and the userspace
 
/*
* Ensures that writing to the buffer and consequent update of the write pointer
* are together one atomic operation.
*/
SPINLOCK_INITIALIZE(sgcn_output_lock);
 
/*
* Prevents the input buffer read/write pointers from getting to inconsistent
* state.
*/
SPINLOCK_INITIALIZE(sgcn_input_lock);
 
 
/* functions referenced from definitions of I/O operations structures */
static void sgcn_noop(chardev_t *);
static void sgcn_putchar(chardev_t *, const char, bool);
static char sgcn_key_read(chardev_t *);
 
/** character device operations */
static chardev_operations_t sgcn_ops = {
.suspend = sgcn_noop,
.resume = sgcn_noop,
.read = sgcn_key_read,
.write = sgcn_putchar
};
 
/** SGCN character device */
chardev_t sgcn_io;
 
/**
* Set some sysinfo values (SRAM address and SRAM size).
*/
static void register_sram(uintptr_t sram_begin_physical)
{
sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
sysinfo_set_item_val("sram.address.physical", NULL,
sram_begin_physical);
}
 
/**
* Initializes the starting address of SRAM.
*
* The SRAM starts 0x900000 + C bytes behind the SBBC start in the
* physical memory, where C is the value read from the "iosram-toc"
* property of the "/chosen" OBP node. The sram_begin variable will
* be set to the virtual address which maps to the SRAM physical
* address.
*
* It also registers the physical area of SRAM and sets some sysinfo
* values (SRAM address and SRAM size).
*/
static void init_sram_begin(void)
{
ofw_tree_node_t *chosen;
ofw_tree_property_t *iosram_toc;
uintptr_t sram_begin_physical;
 
chosen = ofw_tree_lookup("/chosen");
if (!chosen)
panic("Cannot find '/chosen'.");
 
iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
if (!iosram_toc)
panic("Cannot find property 'iosram-toc'.");
if (!iosram_toc->value)
panic("Cannot find SRAM TOC.");
 
sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
+ *((uint32_t *) iosram_toc->value);
sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
register_sram(sram_begin_physical);
}
 
/**
* Initializes the starting address of the SGCN buffer.
*
* The offset of the SGCN buffer within SRAM is obtained from the
* SRAM table of contents. The table of contents contains
* information about several buffers, among which there is an OBP
* console buffer - this one will be used as the SGCN buffer.
*
* This function also writes the offset of the SGCN buffer within SRAM
* under the sram.buffer.offset sysinfo key.
*/
static void sgcn_buffer_begin_init(void)
{
init_sram_begin();
ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
/* lookup TOC entry with the correct key */
uint32_t i;
for (i = 0; i < MAX_TOC_ENTRIES; i++) {
if (strcmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
break;
}
ASSERT(i < MAX_TOC_ENTRIES);
sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
sysinfo_set_item_val("sram.buffer.offset", NULL,
SRAM_TOC->keys[i].offset);
}
 
/**
* Default suspend/resume operation for the input device.
*/
static void sgcn_noop(chardev_t *d)
{
}
 
/**
* Writes a single character to the SGCN (circular) output buffer
* and updates the output write pointer so that SGCN gets to know
* that the character has been written.
*/
static void sgcn_do_putchar(const char c)
{
uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
uint32_t end = SGCN_BUFFER_HEADER->out_end;
uint32_t size = end - begin;
/* we need pointers to volatile variables */
volatile char *buf_ptr = (volatile char *)
SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
 
/*
* Write the character and increment the write pointer modulo the
* output buffer size. Note that if we are to rewrite a character
* which has not been read by the SGCN controller yet (i.e. the output
* buffer is full), we need to wait until the controller reads some more
* characters. We wait actively, which means that all threads waiting
* for the lock are blocked. However, this situation is
* 1) rare - the output buffer is big, so filling the whole
* output buffer is improbable
* 2) short-lasting - it will take the controller only a fraction
* of millisecond to pick the unread characters up
* 3) not serious - the blocked threads are those that print something
* to user console, which is not a time-critical operation
*/
uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
while (*out_rdptr_ptr == new_wrptr)
;
*buf_ptr = c;
*out_wrptr_ptr = new_wrptr;
}
 
/**
* SGCN output operation. Prints a single character to the SGCN. If the line
* feed character is written ('\n'), the carriage return character ('\r') is
* written straight away.
*/
static void sgcn_putchar(struct chardev * cd, const char c, bool silent)
{
if (!silent) {
spinlock_lock(&sgcn_output_lock);
sgcn_do_putchar(c);
if (c == '\n')
sgcn_do_putchar('\r');
spinlock_unlock(&sgcn_output_lock);
}
}
 
/**
* Called when actively reading the character. Not implemented yet.
*/
static char sgcn_key_read(chardev_t *d)
{
return (char) 0;
}
 
/**
* The driver works in polled mode, so no interrupt should be handled by it.
*/
static irq_ownership_t sgcn_claim(irq_t *irq)
{
return IRQ_DECLINE;
}
 
/**
* The driver works in polled mode, so no interrupt should be handled by it.
*/
static void sgcn_irq_handler(irq_t *irq)
{
panic("Not yet implemented, SGCN works in polled mode.");
}
 
/**
* Grabs the input for kernel.
*/
void sgcn_grab(void)
{
ipl_t ipl = interrupts_disable();
volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
/* skip all the user typed before the grab and hasn't been processed */
spinlock_lock(&sgcn_input_lock);
*in_rdptr_ptr = *in_wrptr_ptr;
spinlock_unlock(&sgcn_input_lock);
 
spinlock_lock(&sgcn_irq.lock);
sgcn_irq.notif_cfg.notify = false;
spinlock_unlock(&sgcn_irq.lock);
interrupts_restore(ipl);
}
 
/**
* Releases the input so that userspace can use it.
*/
void sgcn_release(void)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&sgcn_irq.lock);
if (sgcn_irq.notif_cfg.answerbox)
sgcn_irq.notif_cfg.notify = true;
spinlock_unlock(&sgcn_irq.lock);
interrupts_restore(ipl);
}
 
/**
* Function regularly called by the keyboard polling thread. Finds out whether
* there are some unread characters in the input queue. If so, it picks them up
* and sends them to the upper layers of HelenOS.
*/
void sgcn_poll(void)
{
uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
uint32_t end = SGCN_BUFFER_HEADER->in_end;
uint32_t size = end - begin;
spinlock_lock(&sgcn_input_lock);
ipl_t ipl = interrupts_disable();
spinlock_lock(&sgcn_irq.lock);
/* we need pointers to volatile variables */
volatile char *buf_ptr = (volatile char *)
SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
if (*in_rdptr_ptr != *in_wrptr_ptr) {
/* XXX: send notification to userspace */
}
spinlock_unlock(&sgcn_irq.lock);
interrupts_restore(ipl);
 
while (*in_rdptr_ptr != *in_wrptr_ptr) {
buf_ptr = (volatile char *)
SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
char c = *buf_ptr;
*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
if (c == '\r') {
c = '\n';
}
chardev_push_character(&sgcn_io, c);
}
spinlock_unlock(&sgcn_input_lock);
}
 
/**
* A public function which initializes I/O from/to Serengeti console
* and sets it as a default input/output.
*/
void sgcn_init(void)
{
sgcn_buffer_begin_init();
 
kbd_type = KBD_SGCN;
 
devno_t devno = device_assign_devno();
irq_initialize(&sgcn_irq);
sgcn_irq.devno = devno;
sgcn_irq.inr = FICTIONAL_INR;
sgcn_irq.claim = sgcn_claim;
sgcn_irq.handler = sgcn_irq_handler;
irq_register(&sgcn_irq);
sysinfo_set_item_val("kbd", NULL, true);
sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
sysinfo_set_item_val("kbd.devno", NULL, devno);
sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
sysinfo_set_item_val("fb.kind", NULL, 4);
chardev_initialize("sgcn_io", &sgcn_io, &sgcn_ops);
stdin = &sgcn_io;
stdout = &sgcn_io;
}
 
/** @}
*/
/branches/dd/kernel/arch/sparc64/src/drivers/pci.c
42,43 → 42,41
#include <arch/types.h>
#include <debug.h>
#include <print.h>
#include <func.h>
#include <string.h>
#include <arch/asm.h>
#include <sysinfo/sysinfo.h>
 
#define PCI_SABRE_REGS_REG 0
#define SABRE_INTERNAL_REG 0
#define PSYCHO_INTERNAL_REG 2
 
#define PCI_SABRE_IMAP_BASE 0x200
#define PCI_SABRE_ICLR_BASE 0x300
#define OBIO_IMR_BASE 0x200
#define OBIO_IMR(ino) (OBIO_IMR_BASE + ((ino) & INO_MASK))
 
#define PCI_PSYCHO_REGS_REG 2
#define OBIO_CIR_BASE 0x300
#define OBIO_CIR(ino) (OBIO_CIR_BASE + ((ino) & INO_MASK))
 
#define PCI_PSYCHO_IMAP_BASE 0x200
#define PCI_PSYCHO_ICLR_BASE 0x300
static void obio_enable_interrupt(pci_t *, int);
static void obio_clear_interrupt(pci_t *, int);
 
static pci_t *pci_sabre_init(ofw_tree_node_t *node);
static void pci_sabre_enable_interrupt(pci_t *pci, int inr);
static void pci_sabre_clear_interrupt(pci_t *pci, int inr);
static pci_t *pci_sabre_init(ofw_tree_node_t *);
static pci_t *pci_psycho_init(ofw_tree_node_t *);
 
static pci_t *pci_psycho_init(ofw_tree_node_t *node);
static void pci_psycho_enable_interrupt(pci_t *pci, int inr);
static void pci_psycho_clear_interrupt(pci_t *pci, int inr);
 
/** PCI operations for Sabre model. */
static pci_operations_t pci_sabre_ops = {
.enable_interrupt = pci_sabre_enable_interrupt,
.clear_interrupt = pci_sabre_clear_interrupt
.enable_interrupt = obio_enable_interrupt,
.clear_interrupt = obio_clear_interrupt
};
/** PCI operations for Psycho model. */
static pci_operations_t pci_psycho_ops = {
.enable_interrupt = pci_psycho_enable_interrupt,
.clear_interrupt = pci_psycho_clear_interrupt
.enable_interrupt = obio_enable_interrupt,
.clear_interrupt = obio_clear_interrupt
};
 
/** Initialize PCI controller (model Sabre).
*
* @param node OpenFirmware device tree node of the Sabre.
* @param node OpenFirmware device tree node of the Sabre.
*
* @return Address of the initialized PCI structure.
* @return Address of the initialized PCI structure.
*/
pci_t *pci_sabre_init(ofw_tree_node_t *node)
{
95,11 → 93,12
ofw_upa_reg_t *reg = prop->value;
count_t regs = prop->size / sizeof(ofw_upa_reg_t);
 
if (regs < PCI_SABRE_REGS_REG + 1)
if (regs < SABRE_INTERNAL_REG + 1)
return NULL;
 
uintptr_t paddr;
if (!ofw_upa_apply_ranges(node->parent, &reg[PCI_SABRE_REGS_REG], &paddr))
if (!ofw_upa_apply_ranges(node->parent, &reg[SABRE_INTERNAL_REG],
&paddr))
return NULL;
 
pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
108,8 → 107,14
 
pci->model = PCI_SABRE;
pci->op = &pci_sabre_ops;
pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_SABRE_REGS_REG].size);
pci->reg = (uint64_t *) hw_map(paddr, reg[SABRE_INTERNAL_REG].size);
 
/*
* Set sysinfo data needed by the uspace OBIO driver.
*/
sysinfo_set_item_val("obio.base.physical", NULL, paddr);
sysinfo_set_item_val("kbd.cir.obio", NULL, 1);
 
return pci;
}
 
116,9 → 121,9
 
/** Initialize the Psycho PCI controller.
*
* @param node OpenFirmware device tree node of the Psycho.
* @param node OpenFirmware device tree node of the Psycho.
*
* @return Address of the initialized PCI structure.
* @return Address of the initialized PCI structure.
*/
pci_t *pci_psycho_init(ofw_tree_node_t *node)
{
135,11 → 140,12
ofw_upa_reg_t *reg = prop->value;
count_t regs = prop->size / sizeof(ofw_upa_reg_t);
 
if (regs < PCI_PSYCHO_REGS_REG + 1)
if (regs < PSYCHO_INTERNAL_REG + 1)
return NULL;
 
uintptr_t paddr;
if (!ofw_upa_apply_ranges(node->parent, &reg[PCI_PSYCHO_REGS_REG], &paddr))
if (!ofw_upa_apply_ranges(node->parent, &reg[PSYCHO_INTERNAL_REG],
&paddr))
return NULL;
 
pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
148,31 → 154,27
 
pci->model = PCI_PSYCHO;
pci->op = &pci_psycho_ops;
pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_PSYCHO_REGS_REG].size);
pci->reg = (uint64_t *) hw_map(paddr, reg[PSYCHO_INTERNAL_REG].size);
 
/*
* Set sysinfo data needed by the uspace OBIO driver.
*/
sysinfo_set_item_val("obio.base.physical", NULL, paddr);
sysinfo_set_item_val("kbd.cir.obio", NULL, 1);
 
return pci;
}
 
void pci_sabre_enable_interrupt(pci_t *pci, int inr)
void obio_enable_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_SABRE_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK;
pci->reg[OBIO_IMR(inr & INO_MASK)] |= IMAP_V_MASK;
}
 
void pci_sabre_clear_interrupt(pci_t *pci, int inr)
void obio_clear_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_SABRE_ICLR_BASE + (inr & INO_MASK)] = 0;
pci->reg[OBIO_CIR(inr & INO_MASK)] = 0; /* set IDLE */
}
 
void pci_psycho_enable_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_PSYCHO_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK;
}
 
void pci_psycho_clear_interrupt(pci_t *pci, int inr)
{
pci->reg[PCI_PSYCHO_ICLR_BASE + (inr & INO_MASK)] = 0;
}
 
/** Initialize PCI controller. */
pci_t *pci_init(ofw_tree_node_t *node)
{
215,14 → 217,14
 
void pci_enable_interrupt(pci_t *pci, int inr)
{
ASSERT(pci->model);
ASSERT(pci->op && pci->op->enable_interrupt);
pci->op->enable_interrupt(pci, inr);
}
 
void pci_clear_interrupt(pci_t *pci, int inr)
void pci_clear_interrupt(void *pcip, int inr)
{
ASSERT(pci->model);
pci_t *pci = (pci_t *)pcip;
 
ASSERT(pci->op && pci->op->clear_interrupt);
pci->op->clear_interrupt(pci, inr);
}
/branches/dd/kernel/arch/sparc64/src/start.S
27,6 → 27,7
#
 
#include <arch/arch.h>
#include <arch/cpu.h>
#include <arch/regdef.h>
#include <arch/boot/boot.h>
#include <arch/stack.h>
47,6 → 48,16
#define BSP_FLAG 1
 
/*
* 2^PHYSMEM_ADDR_SIZE is the size of the physical address space on
* a given processor.
*/
#if defined (US)
#define PHYSMEM_ADDR_SIZE 41
#elif defined (US3)
#define PHYSMEM_ADDR_SIZE 43
#endif
 
/*
* Here is where the kernel is passed control from the boot loader.
*
* The registers are expected to be in this state:
67,11 → 78,13
and %o0, %l0, %l7 ! l7 <= bootstrap processor?
andn %o0, %l0, %l6 ! l6 <= start of physical memory
 
! Get bits 40:13 of physmem_base.
! Get bits (PHYSMEM_ADDR_SIZE - 1):13 of physmem_base.
srlx %l6, 13, %l5
sllx %l5, 13 + (63 - 40), %l5
srlx %l5, 63 - 40, %l5 ! l5 <= physmem_base[40:13]
! l5 <= physmem_base[(PHYSMEM_ADDR_SIZE - 1):13]
sllx %l5, 13 + (63 - (PHYSMEM_ADDR_SIZE - 1)), %l5
srlx %l5, 63 - (PHYSMEM_ADDR_SIZE - 1), %l5
/*
* Setup basic runtime environment.
*/
83,6 → 96,8
! consistent
wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent needless clean_window
! traps for kernel
wrpr %g0, 0, %wstate ! use default spill/fill trap
 
wrpr %g0, 0, %tl ! TL = 0, primary context
! register is used
244,7 → 259,8
 
/*
* Precompute kernel 8K TLB data template.
* %l5 contains starting physical address bits [40:13]
* %l5 contains starting physical address
* bits [(PHYSMEM_ADDR_SIZE - 1):13]
*/
sethi %hi(kernel_8k_tlb_data_template), %l4
ldx [%l4 + %lo(kernel_8k_tlb_data_template)], %l3
282,15 → 298,32
nop
 
 
1:
#ifdef CONFIG_SMP
/*
* Determine the width of the MID and save its mask to %g3. The width
* is
* * 5 for US and US-IIIi,
* * 10 for US3 except US-IIIi.
*/
#if defined(US)
mov 0x1f, %g3
#elif defined(US3)
mov 0x3ff, %g3
rdpr %ver, %g2
sllx %g2, 16, %g2
srlx %g2, 48, %g2
cmp %g2, IMPL_ULTRASPARCIII_I
move %xcc, 0x1f, %g3
#endif
 
/*
* Read MID from the processor.
*/
1:
ldxa [%g0] ASI_UPA_CONFIG, %g1
srlx %g1, UPA_CONFIG_MID_SHIFT, %g1
and %g1, UPA_CONFIG_MID_MASK, %g1
ldxa [%g0] ASI_ICBUS_CONFIG, %g1
srlx %g1, ICBUS_CONFIG_MID_SHIFT, %g1
and %g1, %g3, %g1
 
#ifdef CONFIG_SMP
/*
* Active loop for APs until the BSP picks them up. A processor cannot
* leave the loop until the global variable 'waking_up_mid' equals its