/trunk/kernel/genarch/include/ofw/ofw_tree.h |
---|
128,6 → 128,9 |
extern const char *ofw_tree_node_name(const ofw_tree_node_t *node); |
extern ofw_tree_node_t *ofw_tree_lookup(const char *path); |
extern ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name); |
extern ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name); |
extern ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node, const char *device_type); |
extern ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node, const char *device_type); |
extern bool ofw_fhc_apply_ranges(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, uintptr_t *pa); |
extern bool ofw_central_apply_ranges(ofw_tree_node_t *node, ofw_central_reg_t *reg, uintptr_t *pa); |
/trunk/kernel/genarch/src/ofw/ofw_tree.c |
---|
97,7 → 97,7 |
* |
* @return NULL if there is no such child or pointer to the matching child node. |
*/ |
static ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name) |
ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name) |
{ |
ofw_tree_node_t *cur; |
124,6 → 124,53 |
return NULL; |
} |
/** Lookup first child of given device type. |
* |
* @param node Node whose child is being looked up. |
* @param name Device type of the child being looked up. |
* |
* @return NULL if there is no such child or pointer to the matching child node. |
*/ |
ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node, const char *name) |
{ |
ofw_tree_node_t *cur; |
ofw_tree_property_t *prop; |
for (cur = node->child; cur; cur = cur->peer) { |
prop = ofw_tree_getprop(cur, "device_type"); |
if (!prop || !prop->value) |
continue; |
if (strcmp(prop->value, name) == 0) |
return cur; |
} |
return NULL; |
} |
/** Lookup first peer of given device type. |
* |
* @param node Node whose peer is being looked up. |
* @param name Device type of the child being looked up. |
* |
* @return NULL if there is no such child or pointer to the matching child node. |
*/ |
ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node, const char *name) |
{ |
ofw_tree_node_t *cur; |
ofw_tree_property_t *prop; |
for (cur = node->peer; cur; cur = cur->peer) { |
prop = ofw_tree_getprop(cur, "device_type"); |
if (!prop || !prop->value) |
continue; |
if (strcmp(prop->value, name) == 0) |
return cur; |
} |
return NULL; |
} |
/** Lookup OpenFirmware node by its path. |
* |
* @param path Path to the node. |
/trunk/kernel/arch/sparc64/include/boot/boot.h |
---|
70,10 → 70,6 |
memzone_t zones[MEMMAP_MAX_RECORDS]; |
} memmap_t; |
typedef struct { |
uint32_t clock_frequency; |
} processor_t; |
/** Bootinfo structure. |
* |
* Must be in sync with bootinfo structure used by the boot loader. |
81,7 → 77,6 |
typedef struct { |
taskmap_t taskmap; |
memmap_t memmap; |
processor_t processor; |
ballocs_t ballocs; |
ofw_tree_node_t *ofw_root; |
} bootinfo_t; |
/trunk/kernel/arch/sparc64/include/arch.h |
---|
39,8 → 39,8 |
#define ASI_AIUP 0x10 /** Access to primary context with user privileges. */ |
#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_UPA_CONFIG 0x4a /** ASI of the UPA_CONFIG register. */ |
#define NWINDOW 8 /** Number of register window sets. */ |
/trunk/kernel/arch/sparc64/include/asm.h |
---|
358,6 → 358,15 |
__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); |
/trunk/kernel/arch/sparc64/include/register.h |
---|
117,6 → 117,23 |
}; |
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 |
/** @} |
/trunk/kernel/arch/sparc64/src/sparc64.c |
---|
37,7 → 37,6 |
#include <config.h> |
#include <arch/trap/trap.h> |
#include <arch/console.h> |
#include <arch/drivers/tick.h> |
#include <proc/thread.h> |
#include <console/console.h> |
#include <arch/boot/boot.h> |
72,7 → 71,6 |
void arch_pre_mm_init(void) |
{ |
trap_init(); |
tick_init(); |
} |
void arch_post_mm_init(void) |
/trunk/kernel/arch/sparc64/src/cpu/cpu.c |
---|
35,20 → 35,51 |
#include <arch/asm.h> |
#include <cpu.h> |
#include <arch.h> |
#include <print.h> |
#include <arch/register.h> |
#include <print.h> |
#include <arch/boot/boot.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <arch/types.h> |
#include <arch/drivers/tick.h> |
/** Perform sparc64 specific initialization of the processor structure for the current processor. */ |
void cpu_arch_init(void) |
{ |
CPU->arch.clock_frequency = bootinfo.processor.clock_frequency; |
ofw_tree_node_t *node; |
uint32_t mid; |
uint32_t clock_frequency = 0; |
upa_config_t upa_config; |
upa_config.value = upa_config_read(); |
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 == upa_config.mid) { |
prop = ofw_tree_getprop(node, "clock-frequency"); |
if (prop && prop->value) |
clock_frequency = *((uint32_t *) prop->value); |
} |
} |
node = ofw_tree_find_peer_by_device_type(node, "cpu"); |
} |
CPU->arch.clock_frequency = clock_frequency; |
tick_init(); |
} |
/** Read version information from the current processor. */ |
void cpu_identify(void) |
{ |
CPU->arch.ver.value = ver_read(); |
} |
/** Print version information for a processor. |
* |
* @param m Processor structure of the CPU for which version information is to be printed. |
*/ |
void cpu_print_report(cpu_t *m) |
{ |
char *manuf, *impl; |
/trunk/kernel/arch/sparc64/src/drivers/tick.c |
---|
52,7 → 52,7 |
interrupt_register(14, "tick_int", tick_interrupt); |
compare.int_dis = false; |
compare.tick_cmpr = bootinfo.processor.clock_frequency/HZ; |
compare.tick_cmpr = CPU->arch.clock_frequency/HZ; |
tick_compare_write(compare.value); |
tick_write(0); |
} |
/trunk/kernel/arch/sparc64/src/start.S |
---|
43,8 → 43,9 |
* from the boot loader. |
* |
* The registers are expected to be in this state: |
* - %o0 bootinfo structure address |
* - %o1 bootinfo structure size |
* - %o0 non-zero for the bootstrup processor, zero for application/secondary processors |
* - %o1 bootinfo structure address |
* - %o2 bootinfo structure size |
* |
* Moreover, we depend on boot having established the |
* following environment: |
55,6 → 56,8 |
.global kernel_image_start |
kernel_image_start: |
brz %o0, kernel_image_start ! block secondary processors |
nop |
/* |
* Setup basic runtime environment. |
72,8 → 75,6 |
* Copy the bootinfo structure passed from the boot loader |
* to the kernel bootinfo structure. |
*/ |
mov %o1, %o2 |
mov %o0, %o1 |
sethi %hi(bootinfo), %o0 |
call memcpy |
or %o0, %lo(bootinfo), %o0 |
/trunk/boot/genarch/ofw.h |
---|
90,7 → 90,6 |
extern uintptr_t ofw_cif; |
extern phandle ofw_chosen; |
extern ihandle ofw_stdout; |
extern phandle ofw_root; |
113,6 → 112,7 |
extern int ofw_package_to_path(const phandle device, char *buf, const int buflen); |
extern int ofw(ofw_args_t *arg); |
extern unsigned long ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets, ...); |
extern unsigned int ofw_get_address_cells(const phandle device); |
extern unsigned int ofw_get_size_cells(const phandle device); |
extern void *ofw_translate(const void *virt); |
/trunk/boot/genarch/ofw.c |
---|
83,7 → 83,7 |
* |
* @return Return value returned by the client interface. |
*/ |
static unsigned long ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets, ...) |
unsigned long ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets, ...) |
{ |
va_list list; |
ofw_args_t args; |
/trunk/boot/arch/sparc64/loader/ofwarch.h |
---|
34,8 → 34,6 |
#define OFW_ADDRESS_CELLS 2 |
#define OFW_SIZE_CELLS 2 |
extern int bpp2align[]; |
extern int ofw_cpu(void); |
extern int ofw_cpu(cpu_t *cpu); |
#endif |
/trunk/boot/arch/sparc64/loader/asm.S |
---|
100,6 → 100,7 |
mov %o0, %l1 |
mov %o1, %o0 |
mov %o2, %o1 |
mov %o3, %o2 |
jmp %l1 ! jump to kernel |
nop |
/trunk/boot/arch/sparc64/loader/main.c |
---|
36,8 → 36,6 |
#include "ofwarch.h" |
#include <align.h> |
#define KERNEL_VIRTUAL_ADDRESS 0x400000 |
bootinfo_t bootinfo; |
void bootstrap(void) |
57,11 → 55,7 |
halt(); |
} |
if (!ofw_cpu(&bootinfo.cpu)) |
printf("Error: unable to get cpu properties\n"); |
printf("\nDevice info\n"); |
printf(" cpu: %dMHz\n", bootinfo.cpu.clock_frequency/1000000); |
printf("\nSystem info\n"); |
printf(" memory: %dM\n", bootinfo.memmap.total>>20); |
printf("\nMemory statistics\n"); |
96,6 → 90,11 |
bootinfo.ofw_root = ofw_tree_build(); |
printf("done.\n"); |
printf("\nChecking for secondary processors..."); |
if (!ofw_cpu()) |
printf("Error: unable to get cpu properties\n"); |
printf("done.\n"); |
printf("\nBooting the kernel...\n"); |
jump_to_kernel((void *) KERNEL_VIRTUAL_ADDRESS, &bootinfo, sizeof(bootinfo)); |
jump_to_kernel((void *) KERNEL_VIRTUAL_ADDRESS, 1, &bootinfo, sizeof(bootinfo)); |
} |
/trunk/boot/arch/sparc64/loader/asm.h |
---|
35,6 → 35,6 |
#define memcpy(dst, src, cnt) __builtin_memcpy((dst), (src), (cnt)) |
extern void halt(void); |
extern void jump_to_kernel(void *entry, void *bootinfo, unsigned int bootinfo_size) __attribute__((noreturn)); |
extern void jump_to_kernel(void *entry, int bsp, void *bootinfo, unsigned int bootinfo_size) __attribute__((noreturn)); |
#endif |
/trunk/boot/arch/sparc64/loader/main.h |
---|
34,6 → 34,8 |
#include <balloc.h> |
#include <types.h> |
#define KERNEL_VIRTUAL_ADDRESS 0x400000 |
#define TASKMAP_MAX_RECORDS 32 |
typedef struct { |
47,13 → 49,8 |
} taskmap_t; |
typedef struct { |
uint32_t clock_frequency; |
} cpu_t; |
typedef struct { |
taskmap_t taskmap; |
memmap_t memmap; |
cpu_t cpu; |
ballocs_t ballocs; |
ofw_tree_node_t *ofw_root; |
} bootinfo_t; |
/trunk/boot/arch/sparc64/loader/ofwarch.c |
---|
53,7 → 53,12 |
return flag != -1; |
} |
int ofw_cpu(cpu_t *cpu) |
#define ASI_UPA_CONFIG 0x4a |
#define UPA_CONFIG_MID_SHIFT 17 |
#define UPA_CONFIG_MID_MASK 0x1f |
int ofw_cpu(void) |
{ |
char type_name[BUF_SIZE]; |
61,22 → 66,32 |
node = ofw_get_child_node(ofw_root); |
if (node == 0 || node == -1) { |
printf("Could not find any child nodes of the root node.\n"); |
return; |
return 0; |
} |
uint64_t current_mid; |
__asm__ volatile ("ldxa [%1] %2, %0\n" : "=r" (current_mid) : "r" (0), "i" (ASI_UPA_CONFIG)); |
current_mid >>= UPA_CONFIG_MID_SHIFT; |
current_mid &= UPA_CONFIG_MID_MASK; |
for (; node != 0 && node != -1; node = ofw_get_peer_node(node)) { |
if (ofw_get_property(node, "device_type", type_name, sizeof(type_name)) > 0) { |
if (strcmp(type_name, "cpu") == 0) { |
uint32_t mhz; |
uint32_t mid; |
if (ofw_get_property(node, "clock-frequency", &mhz, sizeof(mhz)) <= 0) |
if (ofw_get_property(node, "upa-portid", &mid, sizeof(mid)) <= 0) |
continue; |
cpu->clock_frequency = mhz; |
return 1; |
if (current_mid != mid) { |
/* |
* Start secondary processor. |
*/ |
(void) ofw_call("SUNW,start-cpu", 3, 1, NULL, node, KERNEL_VIRTUAL_ADDRESS, 0); |
} |
} |
}; |
} |
} |
return 0; |
return 1; |
} |