/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, ®[PCI_SABRE_REGS_REG], &paddr)) |
if (!ofw_upa_apply_ranges(node->parent, ®[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, ®[PCI_PSYCHO_REGS_REG], &paddr)) |
if (!ofw_upa_apply_ranges(node->parent, ®[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 |