/branches/tracing/contrib/util/DownloadAndPatchSILO.sh |
---|
0,0 → 1,74 |
#!/bin/bash |
# Download SILO and patch it so that it can be used to create a bootable CD |
# for the Serengeti machine |
# by Pavel Rimsky <rimskyp@seznam.cz> |
# portions by Martin Decky <martin@decky.cz> |
# |
# GPL'ed, copyleft |
# |
# stuff to be downloaded |
SILO_DOWNLOAD_FILE='silo-loaders-1.4.11.tar.gz' |
SILO_DOWNLOAD_URL='http://silo.auxio.org/pub/silo/old/'$SILO_DOWNLOAD_FILE |
# check whether the last command failed, if so, write an error message and exit |
check_error() { |
if [ "$1" -ne "0" ]; then |
echo |
echo "Script failed: $2" |
exit |
fi |
} |
# temporary files are to be stored in /tmp |
# the resulting file in the current directory |
WD=`pwd` |
cd /tmp |
# download SILO from its official website |
echo ">>> Downloading SILO" |
wget $SILO_DOWNLOAD_URL |
check_error $? "Error downloading SILO." |
# unpack the downloaded file |
echo ">>> Unpacking tarball" |
tar xvzf $SILO_DOWNLOAD_FILE |
check_error $? "Error unpacking tarball." |
# CD to the unpacked directory |
echo ">>> Changing to the unpacked SILO directory" |
cd boot |
check_error $? "Changing directory failed." |
# patch it - remove bytes 512 to 512 + 32 (counted from 0), which belong to |
# the ELF header which is not recognized by the Serengeti firmware |
echo ">>> Patching SILO" |
(((xxd -p -l 512 isofs.b) && (xxd -p -s 544 isofs.b)) | xxd -r -p) \ |
> isofs.b.patched |
check_error $? "Patching SILO failed" |
mv isofs.b.patched isofs.b |
# get rid of files which are not needed for creating the bootable CD |
echo ">>> Purging SILO directory" |
for file in `ls`; do |
if [ \( -f $file \) -a \( $file != "isofs.b" \) -a \( $file != "second.b" \) ]; |
then |
rm -fr $file; |
fi |
done |
check_error $? "Purging SILO directory failed" |
# create the gzipped tarball with patched SILO |
echo ">>> Creating tarball with patched SILO" |
tar cvzf silo.patched.tar.gz *.b |
check_error $? "Creating tarball with patched SILO failed" |
# and move it to the directory where the user expects it to be |
echo ">>> Moving the tarball with patched SILO to the current directory" |
mv silo.patched.tar.gz $WD |
check_error $? "Moving the tarball with patched SILO failed" |
# move back to the working directory from /tmp |
cd $WD |
/branches/tracing/kernel/test/debug/mips1.c |
---|
38,10 → 38,10 |
#include <arch.h> |
char * test_mips1(bool quiet) |
char *test_mips1(bool quiet) |
{ |
if (!quiet) |
printf("You should enter kconsole debug mode now.\n"); |
printf("If kconsole is compiled in, you should enter debug mode now.\n"); |
asm volatile ( |
"break\n" |
/branches/tracing/kernel/kernel.config |
---|
76,6 → 76,11 |
@ "opteron" Opteron |
! [ARCH=amd64] MACHINE (choice) |
# CPU type |
@ "us" UltraSPARC I-II subarchitecture |
@ "us3" UltraSPARC III-IV subarchitecture |
! [ARCH=sparc64] MACHINE (choice) |
# Machine type |
@ "msim" MSIM Simulator |
@ "simics" Virtutech Simics simulator |
138,10 → 143,21 |
# Support for Z8530 serial port |
! [ARCH=sparc64] CONFIG_Z8530 (y/n) |
# Support for NS16550 serial port |
! [ARCH=sparc64|ARCH=ia64] CONFIG_NS16550 (y/n) |
# Support for NS16550 serial port |
! [ARCH=sparc64|(ARCH=ia64&MACHINE!=ski)] CONFIG_NS16550 (n/y) |
# Support for Serengeti console |
! [ARCH=sparc64] CONFIG_SGCN (y/n) |
# IOSapic on default address support |
! [ARCH=ia64&MACHINE!=ski] CONFIG_IOSAPIC (y/n) |
# Interrupt-driven driver for Legacy Keyboard? |
! [CONFIG_NS16550=n&CONFIG_IOSAPIC=y&MACHINE!=ski] CONFIG_I8042_INTERRUPT_DRIVEN (y/n) |
# Interrupt-driven driver for NS16550? |
! [CONFIG_NS16550=y&((ARCH!=ia64)|CONFIG_IOSAPIC=y)&MACHINE!=ski] CONFIG_NS16550_INTERRUPT_DRIVEN (y/n) |
# Virtually indexed D-cache support |
! [ARCH=sparc64] CONFIG_VIRT_IDX_DCACHE (y/n) |
150,12 → 166,15 |
## Debugging configuration directives |
# General debuging and assert checking |
# General debugging and assert checking |
! CONFIG_DEBUG (y/n) |
# Extensive debugging output |
! [CONFIG_DEBUG=y] CONFIG_EDEBUG (n/y) |
# Kernel console support |
! CONFIG_KCONSOLE (y/n) |
# Detailed kernel logging |
! CONFIG_LOG (n/y) |
# Deadlock detection support for spinlocks |
! [CONFIG_DEBUG=y&CONFIG_SMP=y] CONFIG_DEBUG_SPINLOCK (y/n) |
/branches/tracing/kernel/genarch/include/kbd/z8530.h |
---|
39,17 → 39,18 |
#include <console/chardev.h> |
#include <ipc/irq.h> |
#include <ddi/irq.h> |
extern bool z8530_belongs_to_kernel; |
extern void z8530_init(devno_t devno, inr_t inr, uintptr_t vaddr); |
extern void z8530_init(devno_t, uintptr_t, inr_t, cir_t, void *); |
extern void z8530_poll(void); |
extern void z8530_grab(void); |
extern void z8530_release(void); |
extern void z8530_interrupt(void); |
extern char z8530_key_read(chardev_t *d); |
extern char z8530_key_read(chardev_t *); |
extern irq_ownership_t z8530_claim(void); |
extern void z8530_irq_handler(irq_t *irq, void *arg, ...); |
extern void z8530_irq_handler(irq_t *, void *, ...); |
#endif |
/branches/tracing/kernel/genarch/include/kbd/ns16550.h |
---|
38,15 → 38,16 |
#define KERN_NS16550_H_ |
#include <console/chardev.h> |
#include <ddi/irq.h> |
#include <ipc/irq.h> |
extern void ns16550_init(devno_t devno, inr_t inr, uintptr_t vaddr); |
extern void ns16550_init(devno_t, uintptr_t, inr_t, cir_t, void *); |
extern void ns16550_poll(void); |
extern void ns16550_grab(void); |
extern void ns16550_release(void); |
extern char ns16550_key_read(chardev_t *d); |
extern char ns16550_key_read(chardev_t *); |
extern irq_ownership_t ns16550_claim(void); |
extern void ns16550_irq_handler(irq_t *irq, void *arg, ...); |
extern void ns16550_irq_handler(irq_t *, void *, ...); |
#include <arch/types.h> |
#ifndef ia64 |
58,6 → 59,7 |
#define IIR_REG 2 /** Interrupt Ident Register (read). */ |
#define FCR_REG 2 /** FIFO control register (write). */ |
#define LCR_REG 3 /** Line Control register. */ |
#define MCR_REG 4 /** Modem Control Register. */ |
#define LSR_REG 5 /** Line Status Register. */ |
#define IER_ERBFI 0x01 /** Enable Receive Buffer Full Interrupt. */ |
64,57 → 66,68 |
#define LCR_DLAB 0x80 /** Divisor Latch Access bit. */ |
#define MCR_OUT2 0x08 /** OUT2. */ |
/** Structure representing the ns16550 device. */ |
typedef struct { |
devno_t devno; |
volatile ioport_t io_port; /** Memory mapped registers of the ns16550. */ |
/** Memory mapped registers of the ns16550. */ |
volatile ioport_t io_port; |
} ns16550_t; |
static inline uint8_t ns16550_rbr_read(ns16550_t *dev) |
{ |
return inb(dev->io_port+RBR_REG); |
return inb(dev->io_port + RBR_REG); |
} |
static inline void ns16550_rbr_write(ns16550_t *dev, uint8_t v) |
{ |
outb(dev->io_port+RBR_REG,v); |
outb(dev->io_port + RBR_REG, v); |
} |
static inline uint8_t ns16550_ier_read(ns16550_t *dev) |
{ |
return inb(dev->io_port+IER_REG); |
return inb(dev->io_port + IER_REG); |
} |
static inline void ns16550_ier_write(ns16550_t *dev, uint8_t v) |
{ |
outb(dev->io_port+IER_REG,v); |
outb(dev->io_port + IER_REG, v); |
} |
static inline uint8_t ns16550_iir_read(ns16550_t *dev) |
{ |
return inb(dev->io_port+IIR_REG); |
return inb(dev->io_port + IIR_REG); |
} |
static inline void ns16550_fcr_write(ns16550_t *dev, uint8_t v) |
{ |
outb(dev->io_port+FCR_REG,v); |
outb(dev->io_port + FCR_REG, v); |
} |
static inline uint8_t ns16550_lcr_read(ns16550_t *dev) |
{ |
return inb(dev->io_port+LCR_REG); |
return inb(dev->io_port + LCR_REG); |
} |
static inline void ns16550_lcr_write(ns16550_t *dev, uint8_t v) |
{ |
outb(dev->io_port+LCR_REG,v); |
outb(dev->io_port + LCR_REG, v); |
} |
static inline uint8_t ns16550_lsr_read(ns16550_t *dev) |
{ |
return inb(dev->io_port+LSR_REG); |
return inb(dev->io_port + LSR_REG); |
} |
static inline uint8_t ns16550_mcr_read(ns16550_t *dev) |
{ |
return inb(dev->io_port + MCR_REG); |
} |
static inline void ns16550_mcr_write(ns16550_t *dev, uint8_t v) |
{ |
outb(dev->io_port + MCR_REG, v); |
} |
#endif |
/branches/tracing/kernel/genarch/include/fb/visuals.h |
---|
44,6 → 44,7 |
#define VISUAL_RGB_0_8_8_8 5 |
#define VISUAL_BGR_0_8_8_8 6 |
#define VISUAL_SB1500_PALETTE 7 |
#endif |
/branches/tracing/kernel/genarch/include/fb/fb.h |
---|
38,8 → 38,34 |
#include <arch/types.h> |
#include <synch/spinlock.h> |
/** |
* Properties of the framebuffer device. |
*/ |
typedef struct fb_properties { |
/** Physical address of the framebuffer device. */ |
uintptr_t addr; |
/** |
* Address where the first (top left) pixel is mapped, |
* relative to "addr". |
*/ |
unsigned int offset; |
/** Screen width in pixels. */ |
unsigned int x; |
/** Screen height in pixels. */ |
unsigned int y; |
/** Bytes per one scanline. */ |
unsigned int scan; |
/** Color model. */ |
unsigned int visual; |
} fb_properties_t; |
SPINLOCK_EXTERN(fb_lock); |
void fb_init(uintptr_t addr, unsigned int x, unsigned int y, unsigned int scan, unsigned int visual); |
void fb_init(fb_properties_t *props); |
#endif |
/branches/tracing/kernel/genarch/include/ofw/ofw_tree.h |
---|
30,6 → 30,7 |
#define KERN_OFW_TREE_H_ |
#include <arch/types.h> |
#include <ddi/irq.h> |
#include <typedefs.h> |
#define OFW_TREE_PROPERTY_MAX_NAMELEN 32 |
43,11 → 44,11 |
ofw_tree_node_t *peer; |
ofw_tree_node_t *child; |
uint32_t node_handle; /**< Old OpenFirmware node handle. */ |
uint32_t node_handle; /**< Old OpenFirmware node handle. */ |
char *da_name; /**< Disambigued name. */ |
char *da_name; /**< Disambigued name. */ |
unsigned properties; /**< Number of properties. */ |
unsigned properties; /**< Number of properties. */ |
ofw_tree_property_t *property; |
/** |
105,7 → 106,7 |
uint32_t child_space; |
uint32_t child_base; |
uint32_t parent_space; |
uint64_t parent_base; /* group phys.mid and phys.lo together */ |
uint64_t parent_base; /* group phys.mid and phys.lo together */ |
uint32_t size; |
} __attribute__ ((packed)); |
typedef struct ofw_ebus_range ofw_ebus_range_t; |
127,8 → 128,8 |
typedef struct ofw_ebus_intr_mask ofw_ebus_intr_mask_t; |
struct ofw_pci_reg { |
uint32_t space; /* needs to be masked to obtain pure space id */ |
uint64_t addr; /* group phys.mid and phys.lo together */ |
uint32_t space; /* needs to be masked to obtain pure space id */ |
uint64_t addr; /* group phys.mid and phys.lo together */ |
uint64_t size; |
} __attribute__ ((packed)); |
typedef struct ofw_pci_reg ofw_pci_reg_t; |
135,7 → 136,7 |
struct ofw_pci_range { |
uint32_t space; |
uint64_t child_base; /* group phys.mid and phys.lo together */ |
uint64_t child_base; /* group phys.mid and phys.lo together */ |
uint64_t parent_base; |
uint64_t size; |
} __attribute__ ((packed)); |
160,27 → 161,43 |
} __attribute__ ((packed)); |
typedef struct ofw_upa_reg ofw_upa_reg_t; |
extern void ofw_tree_init(ofw_tree_node_t *root); |
extern void ofw_tree_init(ofw_tree_node_t *); |
extern void ofw_tree_print(void); |
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 ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root, uint32_t handle); |
extern const char *ofw_tree_node_name(const ofw_tree_node_t *); |
extern ofw_tree_node_t *ofw_tree_lookup(const char *); |
extern ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *, |
const char *); |
extern ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *, const char *); |
extern ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *, |
const char *); |
extern ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *, |
const char *); |
extern ofw_tree_node_t *ofw_tree_find_peer_by_name(ofw_tree_node_t *node, |
const char *name); |
extern ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *, |
uint32_t); |
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); |
extern bool ofw_ebus_apply_ranges(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uintptr_t *pa); |
extern bool ofw_pci_apply_ranges(ofw_tree_node_t *node, ofw_pci_reg_t *reg, uintptr_t *pa); |
extern bool ofw_sbus_apply_ranges(ofw_tree_node_t *node, ofw_sbus_reg_t *reg, uintptr_t *pa); |
extern bool ofw_upa_apply_ranges(ofw_tree_node_t *node, ofw_upa_reg_t *reg, uintptr_t *pa); |
extern bool ofw_fhc_apply_ranges(ofw_tree_node_t *, ofw_fhc_reg_t *, |
uintptr_t *); |
extern bool ofw_central_apply_ranges(ofw_tree_node_t *, ofw_central_reg_t *, |
uintptr_t *); |
extern bool ofw_ebus_apply_ranges(ofw_tree_node_t *, ofw_ebus_reg_t *, |
uintptr_t *); |
extern bool ofw_pci_apply_ranges(ofw_tree_node_t *, ofw_pci_reg_t *, |
uintptr_t *); |
extern bool ofw_sbus_apply_ranges(ofw_tree_node_t *, ofw_sbus_reg_t *, |
uintptr_t *); |
extern bool ofw_upa_apply_ranges(ofw_tree_node_t *, ofw_upa_reg_t *, |
uintptr_t *); |
extern bool ofw_pci_reg_absolutize(ofw_tree_node_t *node, ofw_pci_reg_t *reg, ofw_pci_reg_t *out); |
extern bool ofw_pci_reg_absolutize(ofw_tree_node_t *, ofw_pci_reg_t *, |
ofw_pci_reg_t *); |
extern bool ofw_fhc_map_interrupt(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, uint32_t interrupt, int *inr); |
extern bool ofw_ebus_map_interrupt(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uint32_t interrupt, int *inr); |
extern bool ofw_pci_map_interrupt(ofw_tree_node_t *node, ofw_pci_reg_t *reg, int ino, int *inr); |
extern bool ofw_fhc_map_interrupt(ofw_tree_node_t *, ofw_fhc_reg_t *, |
uint32_t, int *, cir_t *, void **); |
extern bool ofw_ebus_map_interrupt(ofw_tree_node_t *, ofw_ebus_reg_t *, |
uint32_t, int *, cir_t *, void **); |
extern bool ofw_pci_map_interrupt(ofw_tree_node_t *, ofw_pci_reg_t *, |
int, int *, cir_t *, void **); |
#endif |
/branches/tracing/kernel/genarch/src/kbd/ns16550.c |
---|
38,8 → 38,8 |
#include <genarch/kbd/key.h> |
#include <genarch/kbd/scanc.h> |
#include <genarch/kbd/scanc_sun.h> |
#include <arch/drivers/kbd.h> |
#ifndef ia64 |
#include <arch/drivers/kbd.h> |
#include <arch/drivers/ns16550.h> |
#endif |
#include <ddi/irq.h> |
107,11 → 107,14 |
/** Initialize ns16550. |
* |
* @param devno Device number. |
* @param inr Interrupt number. |
* @param vaddr Virtual address of device's registers. |
* @param devno Device number. |
* @param port Virtual/IO address of device's registers. |
* @param inr Interrupt number. |
* @param cir Clear interrupt function. |
* @param cir_arg First argument to cir. |
*/ |
void ns16550_init(devno_t devno, inr_t inr, ioport_t port) |
void |
ns16550_init(devno_t devno, ioport_t port, inr_t inr, cir_t cir, void *cir_arg) |
{ |
chardev_initialize("ns16550_kbd", &kbrd, &ops); |
stdin = &kbrd; |
124,18 → 127,31 |
ns16550_irq.inr = inr; |
ns16550_irq.claim = ns16550_claim; |
ns16550_irq.handler = ns16550_irq_handler; |
ns16550_irq.cir = cir; |
ns16550_irq.cir_arg = cir_arg; |
irq_register(&ns16550_irq); |
while ((ns16550_lsr_read(&ns16550) & LSR_DATA_READY)) |
ns16550_rbr_read(&ns16550); |
sysinfo_set_item_val("kbd", NULL, true); |
#ifndef ia64 |
sysinfo_set_item_val("kbd.type", NULL, KBD_NS16550); |
#endif |
sysinfo_set_item_val("kbd.devno", NULL, devno); |
sysinfo_set_item_val("kbd.inr", NULL, inr); |
sysinfo_set_item_val("kbd.address.virtual", NULL, port); |
sysinfo_set_item_val("kbd.port", NULL, port); |
#ifdef CONFIG_NS16550_INTERRUPT_DRIVEN |
/* Enable interrupts */ |
ns16550_ier_write(&ns16550, IER_ERBFI); |
ns16550_mcr_write(&ns16550, MCR_OUT2); |
#endif |
#ifdef ia64 |
uint8_t c; |
// This switches rbr & ier to mode when accept baudrate constant |
c = ns16550_lcr_read(&ns16550); |
ns16550_lcr_write(&ns16550, 0x80 | c); |
ns16550_rbr_write(&ns16550, 0x0c); |
149,10 → 165,7 |
/** Process ns16550 interrupt. */ |
void ns16550_interrupt(void) |
{ |
/* TODO |
* |
* ns16550 works in the polled mode so far. |
*/ |
ns16550_poll(); |
} |
/* Called from getc(). */ |
201,6 → 214,7 |
*/ |
void ns16550_poll(void) |
{ |
#ifndef CONFIG_NS16550_INTERRUPT_DRIVEN |
ipl_t ipl; |
ipl = interrupts_disable(); |
220,6 → 234,7 |
spinlock_unlock(&ns16550_irq.lock); |
interrupts_restore(ipl); |
#endif |
while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY) { |
uint8_t x; |
251,7 → 266,10 |
void ns16550_irq_handler(irq_t *irq, void *arg, ...) |
{ |
panic("Not yet implemented, ns16550 works in polled mode.\n"); |
if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) |
ipc_irq_send_notif(irq); |
else |
ns16550_interrupt(); |
} |
/** @} |
/branches/tracing/kernel/genarch/src/kbd/i8042.c |
---|
37,6 → 37,9 |
*/ |
#include <genarch/kbd/i8042.h> |
#ifdef ia64 |
#include <arch/drivers/kbd.h> |
#endif |
#include <genarch/kbd/key.h> |
#include <genarch/kbd/scanc.h> |
#include <genarch/kbd/scanc_pc.h> |
184,7 → 187,9 |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.devno", NULL, kbd_devno); |
sysinfo_set_item_val("kbd.inr", NULL, kbd_inr); |
#ifdef KBD_LEGACY |
sysinfo_set_item_val("kbd.type", NULL, KBD_LEGACY); |
#endif |
sysinfo_set_item_val("mouse", NULL, true); |
sysinfo_set_item_val("mouse.devno", NULL, mouse_devno); |
sysinfo_set_item_val("mouse.inr", NULL, mouse_inr); |
/branches/tracing/kernel/genarch/src/kbd/z8530.c |
---|
43,7 → 43,6 |
#include <ipc/irq.h> |
#include <arch/interrupt.h> |
#include <arch/drivers/kbd.h> |
#include <arch/drivers/fhc.h> |
#include <cpu.h> |
#include <arch/asm.h> |
#include <arch.h> |
83,12 → 82,14 |
*/ |
z8530_write_a(&z8530, WR0, WR0_TX_IP_RST); |
z8530_write_a(&z8530, WR1, WR1_IARCSC); /* interrupt on all characters */ |
/* interrupt on all characters */ |
z8530_write_a(&z8530, WR1, WR1_IARCSC); |
/* 8 bits per character and enable receiver */ |
z8530_write_a(&z8530, WR3, WR3_RX8BITSCH | WR3_RX_ENABLE); |
z8530_write_a(&z8530, WR9, WR9_MIE); /* Master Interrupt Enable. */ |
/* Master Interrupt Enable. */ |
z8530_write_a(&z8530, WR9, WR9_MIE); |
spinlock_lock(&z8530_irq.lock); |
z8530_irq.notif_cfg.notify = false; |
108,7 → 109,8 |
} |
/** Initialize z8530. */ |
void z8530_init(devno_t devno, inr_t inr, uintptr_t vaddr) |
void |
z8530_init(devno_t devno, uintptr_t vaddr, inr_t inr, cir_t cir, void *cir_arg) |
{ |
chardev_initialize("z8530_kbd", &kbrd, &ops); |
stdin = &kbrd; |
121,6 → 123,8 |
z8530_irq.inr = inr; |
z8530_irq.claim = z8530_claim; |
z8530_irq.handler = z8530_irq_handler; |
z8530_irq.cir = cir; |
z8530_irq.cir_arg = cir_arg; |
irq_register(&z8530_irq); |
sysinfo_set_item_val("kbd", NULL, true); |
197,18 → 201,10 |
void z8530_irq_handler(irq_t *irq, void *arg, ...) |
{ |
/* |
* So far, we know we got this interrupt through the FHC. |
* Since we don't have enough documentation about the FHC |
* and because the interrupt looks like level sensitive, |
* we cannot handle it by scheduling one of the level |
* interrupt traps. Process the interrupt directly. |
*/ |
if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) |
ipc_irq_send_notif(irq); |
else |
z8530_interrupt(); |
fhc_clear_interrupt(central_fhc, irq->inr); |
} |
/** @} |
/branches/tracing/kernel/genarch/src/fb/fb.c |
---|
191,6 → 191,26 |
BLUE(rgb, 3); |
} |
static void sb1500rgb_byte8(void *dst, int rgb) |
{ |
if (RED(rgb, 1) && GREEN(rgb, 1) && BLUE(rgb, 1)) |
*((uint8_t *) dst) = 255; |
else if (RED(rgb, 1) && GREEN(rgb, 1)) |
*((uint8_t *) dst) = 150; |
else if (GREEN(rgb, 1) && BLUE(rgb, 1)) |
*((uint8_t *) dst) = 47; |
else if (RED(rgb, 1) && BLUE(rgb, 1)) |
*((uint8_t *) dst) = 48; |
else if (RED(rgb, 1)) |
*((uint8_t *) dst) = 32; |
else if (GREEN(rgb, 1)) |
*((uint8_t *) dst) = 47; |
else if (BLUE(rgb, 1)) |
*((uint8_t *) dst) = 2; |
else |
*((uint8_t *) dst) = 1; |
} |
/** Return pixel color - 8-bit depth (color palette/3:2:3) |
* |
* See the comment for rgb_byte(). |
436,22 → 456,21 |
/** Initialize framebuffer as a chardev output device |
* |
* @param addr Physical address of the framebuffer |
* @param x Screen width in pixels |
* @param y Screen height in pixels |
* @param scan Bytes per one scanline |
* @param visual Color model |
* |
* @param props Properties of the framebuffer device. |
*/ |
void fb_init(uintptr_t addr, unsigned int x, unsigned int y, unsigned int scan, |
unsigned int visual) |
void fb_init(fb_properties_t *props) |
{ |
switch (visual) { |
switch (props->visual) { |
case VISUAL_INDIRECT_8: |
rgb2scr = rgb_byte8; |
scr2rgb = byte8_rgb; |
pixelbytes = 1; |
break; |
case VISUAL_SB1500_PALETTE: |
rgb2scr = sb1500rgb_byte8; |
scr2rgb = byte8_rgb; |
pixelbytes = 1; |
break; |
case VISUAL_RGB_5_5_5: |
rgb2scr = rgb_byte555; |
scr2rgb = byte555_rgb; |
486,19 → 505,20 |
panic("Unsupported visual.\n"); |
} |
unsigned int fbsize = scan * y; |
unsigned int fbsize = props->scan * props->y + props->offset; |
/* Map the framebuffer */ |
fbaddress = (uint8_t *) hw_map((uintptr_t) addr, fbsize); |
fbaddress = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize); |
fbaddress += props->offset; |
xres = x; |
yres = y; |
scanline = scan; |
xres = props->x; |
yres = props->y; |
scanline = props->scan; |
rows = y / FONT_SCANLINES; |
columns = x / COL_WIDTH; |
rows = props->y / FONT_SCANLINES; |
columns = props->x / COL_WIDTH; |
fb_parea.pbase = (uintptr_t) addr; |
fb_parea.pbase = (uintptr_t) props->addr; |
fb_parea.vbase = (uintptr_t) fbaddress; |
fb_parea.frames = SIZE2FRAMES(fbsize); |
fb_parea.cacheable = false; |
508,9 → 528,9 |
sysinfo_set_item_val("fb.kind", NULL, 1); |
sysinfo_set_item_val("fb.width", NULL, xres); |
sysinfo_set_item_val("fb.height", NULL, yres); |
sysinfo_set_item_val("fb.scanline", NULL, scan); |
sysinfo_set_item_val("fb.visual", NULL, visual); |
sysinfo_set_item_val("fb.address.physical", NULL, addr); |
sysinfo_set_item_val("fb.scanline", NULL, props->scan); |
sysinfo_set_item_val("fb.visual", NULL, props->visual); |
sysinfo_set_item_val("fb.address.physical", NULL, props->addr); |
sysinfo_set_item_val("fb.invert-colors", NULL, invert_colors); |
/* Allocate double buffer */ |
524,6 → 544,7 |
blankline = (uint8_t *) malloc(ROW_BYTES, FRAME_ATOMIC); |
if (!blankline) |
panic("Failed to allocate blank line for framebuffer."); |
unsigned int x, y; |
for (y = 0; y < FONT_SCANLINES; y++) |
for (x = 0; x < xres; x++) |
(*rgb2scr)(&blankline[POINTPOS(x, y)], COLOR(BGCOLOR)); |
/branches/tracing/kernel/genarch/src/ofw/ebus.c |
---|
44,7 → 44,8 |
#include <macros.h> |
/** Apply EBUS ranges to EBUS register. */ |
bool ofw_ebus_apply_ranges(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uintptr_t *pa) |
bool |
ofw_ebus_apply_ranges(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uintptr_t *pa) |
{ |
ofw_tree_property_t *prop; |
ofw_ebus_range_t *range; |
62,11 → 63,13 |
for (i = 0; i < ranges; i++) { |
if (reg->space != range[i].child_space) |
continue; |
if (overlaps(reg->addr, reg->size, range[i].child_base, range[i].size)) { |
if (overlaps(reg->addr, reg->size, range[i].child_base, |
range[i].size)) { |
ofw_pci_reg_t pci_reg; |
pci_reg.space = range[i].parent_space; |
pci_reg.addr = range[i].parent_base + (reg->addr - range[i].child_base); |
pci_reg.addr = range[i].parent_base + |
(reg->addr - range[i].child_base); |
pci_reg.size = reg->size; |
return ofw_pci_apply_ranges(node->parent, &pci_reg, pa); |
76,7 → 79,9 |
return false; |
} |
bool ofw_ebus_map_interrupt(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uint32_t interrupt, int *inr) |
bool |
ofw_ebus_map_interrupt(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, |
uint32_t interrupt, int *inr, cir_t *cir, void **cir_arg) |
{ |
ofw_tree_property_t *prop; |
ofw_tree_node_t *controller; |
104,8 → 109,8 |
unsigned int i; |
for (i = 0; i < count; i++) { |
if ((intr_map[i].space == space) && (intr_map[i].addr == addr) |
&& (intr_map[i].intr == intr)) |
if ((intr_map[i].space == space) && |
(intr_map[i].addr == addr) && (intr_map[i].intr == intr)) |
goto found; |
} |
return false; |
113,10 → 118,12 |
found: |
/* |
* We found the device that functions as an interrupt controller |
* for the interrupt. We also found partial mapping from interrupt to INO. |
* for the interrupt. We also found partial mapping from interrupt to |
* INO. |
*/ |
controller = ofw_tree_find_node_by_handle(ofw_tree_lookup("/"), intr_map[i].controller_handle); |
controller = ofw_tree_find_node_by_handle(ofw_tree_lookup("/"), |
intr_map[i].controller_handle); |
if (!controller) |
return false; |
130,7 → 137,8 |
/* |
* Let the PCI do the next step in mapping the interrupt. |
*/ |
if (!ofw_pci_map_interrupt(controller, NULL, intr_map[i].controller_ino, inr)) |
if (!ofw_pci_map_interrupt(controller, NULL, intr_map[i].controller_ino, |
inr, cir, cir_arg)) |
return false; |
return true; |
/branches/tracing/kernel/genarch/src/ofw/fhc.c |
---|
109,7 → 109,9 |
return false; |
} |
bool ofw_fhc_map_interrupt(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, uint32_t interrupt, int *inr) |
bool |
ofw_fhc_map_interrupt(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, |
uint32_t interrupt, int *inr, cir_t *cir, void **cir_arg) |
{ |
fhc_t *fhc = NULL; |
if (!node->device) { |
126,6 → 128,8 |
fhc_enable_interrupt(fhc, interrupt); |
*inr = interrupt; |
*cir = fhc_clear_interrupt; |
*cir_arg = fhc; |
return true; |
} |
/branches/tracing/kernel/genarch/src/ofw/ofw_tree.c |
---|
54,12 → 54,14 |
/** Get OpenFirmware node property. |
* |
* @param node Node in which to lookup the property. |
* @param name Name of the property. |
* @param node Node in which to lookup the property. |
* @param name Name of the property. |
* |
* @return Pointer to the property structure or NULL if no such property. |
* @return Pointer to the property structure or NULL if no such |
* property. |
*/ |
ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name) |
ofw_tree_property_t * |
ofw_tree_getprop(const ofw_tree_node_t *node, const char *name) |
{ |
unsigned int i; |
73,9 → 75,9 |
/** Return value of the 'name' property. |
* |
* @param node Node of interest. |
* @param node Node of interest. |
* |
* @return Value of the 'name' property belonging to the node. |
* @return Value of the 'name' property belonging to the node. |
*/ |
const char *ofw_tree_node_name(const ofw_tree_node_t *node) |
{ |
93,10 → 95,11 |
/** Lookup child of given name. |
* |
* @param node Node whose child is being looked up. |
* @param name Name of the child being looked up. |
* @param node Node whose child is being looked up. |
* @param name Name of the child being looked up. |
* |
* @return NULL if there is no such child or pointer to the matching child node. |
* @return NULL if there is no such child or pointer to the |
* matching child node. |
*/ |
ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name) |
{ |
127,12 → 130,14 |
/** 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. |
* @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. |
* @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 * |
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; |
153,12 → 158,14 |
* Child nodes are looked up recursively contrary to peer nodes that |
* are looked up iteratively to avoid stack overflow. |
* |
* @param root Root of the searched subtree. |
* @param handle OpenFirmware handle. |
* @param root Root of the searched subtree. |
* @param handle OpenFirmware handle. |
* |
* @return NULL if there is no such node or pointer to the matching node. |
* @return NULL if there is no such node or pointer to the matching |
* node. |
*/ |
ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root, uint32_t handle) |
ofw_tree_node_t * |
ofw_tree_find_node_by_handle(ofw_tree_node_t *root, uint32_t handle) |
{ |
ofw_tree_node_t *cur; |
180,12 → 187,14 |
/** 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. |
* @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. |
* @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 * |
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; |
202,15 → 211,41 |
} |
/** Lookup first peer of given name. |
* |
* @param node Node whose peer is being looked up. |
* @param name Name of the child being looked up. |
* |
* @return NULL if there is no such peer or pointer to the matching |
* peer node. |
*/ |
ofw_tree_node_t * |
ofw_tree_find_peer_by_name(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, "name"); |
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. |
* @param path Path to the node. |
* |
* @return NULL if there is no such node or pointer to the leaf node. |
* @return NULL if there is no such node or pointer to the leaf |
* node. |
*/ |
ofw_tree_node_t *ofw_tree_lookup(const char *path) |
{ |
char buf[NAME_BUF_LEN+1]; |
char buf[NAME_BUF_LEN + 1]; |
ofw_tree_node_t *node = ofw_root; |
index_t i, j; |
236,8 → 271,8 |
* Child nodes are processed recursively and peer nodes are processed |
* iteratively in order to avoid stack overflow. |
* |
* @param node Root of the subtree. |
* @param path Current path, NULL for the very root of the entire tree. |
* @param node Root of the subtree. |
* @param path Current path, NULL for the very root of the entire tree. |
*/ |
static void ofw_tree_node_print(const ofw_tree_node_t *node, const char *path) |
{ |
/branches/tracing/kernel/genarch/src/ofw/pci.c |
---|
49,7 → 49,8 |
#define PCI_IGN 0x1f |
bool ofw_pci_apply_ranges(ofw_tree_node_t *node, ofw_pci_reg_t *reg, uintptr_t *pa) |
bool |
ofw_pci_apply_ranges(ofw_tree_node_t *node, ofw_pci_reg_t *reg, uintptr_t *pa) |
{ |
ofw_tree_property_t *prop; |
ofw_pci_range_t *range; |
68,10 → 69,13 |
unsigned int i; |
for (i = 0; i < ranges; i++) { |
if ((reg->space & PCI_SPACE_MASK) != (range[i].space & PCI_SPACE_MASK)) |
if ((reg->space & PCI_SPACE_MASK) != |
(range[i].space & PCI_SPACE_MASK)) |
continue; |
if (overlaps(reg->addr, reg->size, range[i].child_base, range[i].size)) { |
*pa = range[i].parent_base + (reg->addr - range[i].child_base); |
if (overlaps(reg->addr, reg->size, range[i].child_base, |
range[i].size)) { |
*pa = range[i].parent_base + |
(reg->addr - range[i].child_base); |
return true; |
} |
} |
79,7 → 83,9 |
return false; |
} |
bool ofw_pci_reg_absolutize(ofw_tree_node_t *node, ofw_pci_reg_t *reg, ofw_pci_reg_t *out) |
bool |
ofw_pci_reg_absolutize(ofw_tree_node_t *node, ofw_pci_reg_t *reg, |
ofw_pci_reg_t *out) |
{ |
if (reg->space & PCI_ABS_MASK) { |
/* already absolute */ |
103,7 → 109,8 |
unsigned int i; |
for (i = 0; i < assigned_addresses; i++) { |
if ((assigned_address[i].space & PCI_REG_MASK) == (reg->space & PCI_REG_MASK)) { |
if ((assigned_address[i].space & PCI_REG_MASK) == |
(reg->space & PCI_REG_MASK)) { |
out->space = assigned_address[i].space; |
out->addr = reg->addr + assigned_address[i].addr; |
out->size = reg->size; |
119,7 → 126,9 |
* So far, we only know how to map interrupts of non-PCI devices connected |
* to a PCI bridge. |
*/ |
bool ofw_pci_map_interrupt(ofw_tree_node_t *node, ofw_pci_reg_t *reg, int ino, int *inr) |
bool |
ofw_pci_map_interrupt(ofw_tree_node_t *node, ofw_pci_reg_t *reg, int ino, |
int *inr, cir_t *cir, void **cir_arg) |
{ |
pci_t *pci = node->device; |
if (!pci) { |
132,6 → 141,8 |
pci_enable_interrupt(pci, ino); |
*inr = (PCI_IGN << IGN_SHIFT) | ino; |
*cir = pci_clear_interrupt; |
*cir_arg = pci; |
return true; |
} |
/branches/tracing/kernel/generic/include/byteorder.h |
---|
51,6 → 51,14 |
#define uint32_t_be2host(n) (n) |
#define uint64_t_be2host(n) (n) |
#define host2uint16_t_le(n) uint16_t_byteorder_swap(n) |
#define host2uint32_t_le(n) uint32_t_byteorder_swap(n) |
#define host2uint64_t_le(n) uint64_t_byteorder_swap(n) |
#define host2uint16_t_be(n) (n) |
#define host2uint32_t_be(n) (n) |
#define host2uint64_t_be(n) (n) |
#else |
#define uint16_t_le2host(n) (n) |
61,6 → 69,14 |
#define uint32_t_be2host(n) uint32_t_byteorder_swap(n) |
#define uint64_t_be2host(n) uint64_t_byteorder_swap(n) |
#define host2uint16_t_le(n) (n) |
#define host2uint32_t_le(n) (n) |
#define host2uint64_t_le(n) (n) |
#define host2uint16_t_be(n) uint16_t_byteorder_swap(n) |
#define host2uint32_t_be(n) uint32_t_byteorder_swap(n) |
#define host2uint64_t_be(n) uint64_t_byteorder_swap(n) |
#endif |
static inline uint64_t uint64_t_byteorder_swap(uint64_t n) |
/branches/tracing/kernel/generic/include/ddi/irq.h |
---|
83,6 → 83,9 |
struct irq; |
typedef void (* irq_handler_t)(struct irq *irq, void *arg, ...); |
/** Type for function used to clear the interrupt. */ |
typedef void (* cir_t)(void *arg, inr_t inr); |
/** IPC notification config structure. |
* |
* Primarily, this structure is encapsulated in the irq_t structure. |
144,6 → 147,11 |
/** Argument for the handler. */ |
void *arg; |
/** Clear interrupt routine. */ |
cir_t cir; |
/** First argument to the clear interrupt routine. */ |
void *cir_arg; |
/** Notification configuration structure. */ |
ipc_notif_cfg_t notif_cfg; |
} irq_t; |
/branches/tracing/kernel/generic/include/adt/bitmap.h |
---|
49,6 → 49,14 |
extern void bitmap_clear_range(bitmap_t *bitmap, index_t start, count_t bits); |
extern void bitmap_copy(bitmap_t *dst, bitmap_t *src, count_t bits); |
static inline int bitmap_get(bitmap_t *bitmap,index_t bit) |
{ |
if(bit >= bitmap->bits) |
return 0; |
return !! ((bitmap->map)[bit/8] & (1 << (bit & 7))); |
} |
#endif |
/** @} |
/branches/tracing/kernel/generic/src/ddi/irq.c |
---|
145,6 → 145,8 |
irq->claim = NULL; |
irq->handler = NULL; |
irq->arg = NULL; |
irq->cir = NULL; |
irq->cir_arg = NULL; |
irq->notif_cfg.notify = false; |
irq->notif_cfg.answerbox = NULL; |
irq->notif_cfg.code = NULL; |
/branches/tracing/kernel/generic/src/mm/tlb.c |
---|
134,9 → 134,7 |
void tlb_shootdown_ipi_send(void) |
{ |
#ifndef ia64 |
ipi_broadcast(VECTOR_TLB_SHOOTDOWN_IPI); |
#endif |
} |
/** Receive TLB shootdown message. */ |
/branches/tracing/kernel/generic/src/ipc/irq.c |
---|
100,7 → 100,7 |
*((uint64_t *) code->cmds[i].addr) = |
code->cmds[i].value; |
break; |
#if defined(ia32) || defined(amd64) |
#if defined(ia32) || defined(amd64) || defined(ia64) |
case CMD_PORT_READ_1: |
dstval = inb((long) code->cmds[i].addr); |
break; |
/branches/tracing/kernel/Makefile |
---|
126,6 → 126,18 |
DEFS += -DCONFIG_NS16550 |
endif |
ifeq ($(CONFIG_I8042_INTERRUPT_DRIVEN),y) |
DEFS += -DCONFIG_I8042_INTERRUPT_DRIVEN |
endif |
ifeq ($(CONFIG_NS16550_INTERRUPT_DRIVEN),y) |
DEFS += -DCONFIG_NS16550_INTERRUPT_DRIVEN |
endif |
ifeq ($(CONFIG_IOSAPIC),y) |
DEFS += -DCONFIG_IOSAPIC |
endif |
ifeq ($(CONFIG_VIRT_IDX_DCACHE),y) |
DEFS += -DCONFIG_VIRT_IDX_DCACHE |
endif |
/branches/tracing/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/tracing/kernel/arch/sparc64/include/cpu_node.h |
---|
0,0 → 1,58 |
/* |
* 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/tracing/kernel/arch/sparc64/include/arch.h |
---|
41,7 → 41,7 |
#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. */ |
/branches/tracing/kernel/arch/sparc64/include/asm.h |
---|
136,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. |
407,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/tracing/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/tracing/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/tracing/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/tracing/kernel/arch/sparc64/include/mm/cache_spec.h |
---|
38,19 → 38,20 |
/* |
* The following macros are valid for the following processors: |
* |
* UltraSPARC, UltraSPARC II, UltraSPARC IIi |
* 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 |
#define ICACHE_SIZE (16 * 1024) |
#define ICACHE_WAYS 2 |
#define ICACHE_LINE_SIZE 32 |
#endif |
/** @} |
/branches/tracing/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/tracing/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,7 → 286,7 |
/** 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) |
{ |
165,7 → 296,7 |
/** 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,7 → 305,7 |
/** 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) |
{ |
182,15 → 313,18 |
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,12 → 333,12 |
/** 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; |
214,13 → 348,14 |
/** 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,9 → 407,120 |
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) |
{ |
284,7 → 530,7 |
/** 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,7 → 559,7 |
/** 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) |
{ |
323,7 → 569,7 |
/** 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,7 → 588,7 |
/** 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) |
{ |
352,7 → 598,7 |
/** 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 */ |
/* 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/tracing/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/tracing/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/tracing/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/tracing/kernel/arch/sparc64/include/cpu.h |
---|
35,15 → 35,6 |
#ifndef KERN_sparc64_CPU_H_ |
#define KERN_sparc64_CPU_H_ |
#include <arch/types.h> |
#include <typedefs.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 |
52,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 |
66,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/tracing/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/tracing/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/tracing/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/tracing/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/tracing/kernel/arch/sparc64/include/drivers/scr.h |
---|
42,7 → 42,8 |
SCR_UNKNOWN, |
SCR_ATYFB, |
SCR_FFB, |
SCR_CGSIX |
SCR_CGSIX, |
SCR_XVR |
} scr_type_t; |
extern scr_type_t scr_type; |
/branches/tracing/kernel/arch/sparc64/include/cpu_family.h |
---|
0,0 → 1,82 |
/* |
* 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/tracing/kernel/arch/sparc64/Makefile.inc |
---|
80,6 → 80,18 |
DEFS += -DCONFIG_SMP |
endif |
ifeq ($(CONFIG_SGCN),y) |
DEFS += -DCONFIG_SGCN |
endif |
ifeq ($(MACHINE),us) |
DEFS += -DUS |
endif |
ifeq ($(MACHINE),us3) |
DEFS += -DUS3 |
endif |
ARCH_SOURCES = \ |
arch/$(ARCH)/src/cpu/cpu.c \ |
arch/$(ARCH)/src/asm.S \ |
106,8 → 118,10 |
arch/$(ARCH)/src/drivers/tick.c \ |
arch/$(ARCH)/src/drivers/kbd.c \ |
arch/$(ARCH)/src/drivers/scr.c \ |
arch/$(ARCH)/src/drivers/sgcn.c \ |
arch/$(ARCH)/src/drivers/pci.c |
ifeq ($(CONFIG_SMP),y) |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/smp/ipi.c \ |
/branches/tracing/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 = %" PRIu32 ") timed out\n", |
__func__, mid); |
} |
} |
/branches/tracing/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. |
73,14 → 100,13 |
if (status & INTR_DISPATCH_STATUS_BUSY) |
panic("Interrupt Dispatch Status busy bit set\n"); |
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(); |
/branches/tracing/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/tracing/kernel/arch/sparc64/src/console.c |
---|
38,6 → 38,8 |
#include <arch/drivers/scr.h> |
#include <arch/drivers/kbd.h> |
#include <arch/drivers/sgcn.h> |
#ifdef CONFIG_Z8530 |
#include <genarch/kbd/z8530.h> |
#endif |
54,24 → 56,25 |
#include <genarch/ofw/ofw_tree.h> |
#include <arch.h> |
#include <panic.h> |
#include <func.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; |
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"); |
95,6 → 98,36 |
kbd_init(keyboard); |
} |
/** 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("Can't find /aliases.\n"); |
/* "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. |
112,11 → 145,27 |
} |
#endif |
#ifdef CONFIG_NS16550 |
#ifdef CONFIG_NS16550_INTERRUPT_DRIVEN |
if (kbd_type == KBD_NS16550) { |
/* |
* The ns16550 driver is interrupt-driven. |
*/ |
return; |
} |
#endif |
#endif |
while (1) { |
#ifdef CONFIG_NS16550 |
#ifndef CONFIG_NS16550_INTERRUPT_DRIVEN |
if (kbd_type == KBD_NS16550) |
ns16550_poll(); |
#endif |
#endif |
#ifdef CONFIG_SGCN |
if (kbd_type == KBD_SGCN) |
sgcn_poll(); |
#endif |
thread_usleep(KEYBOARD_POLL_PAUSE); |
} |
} |
137,6 → 186,11 |
ns16550_grab(); |
break; |
#endif |
#ifdef CONFIG_SGCN |
case KBD_SGCN: |
sgcn_grab(); |
break; |
#endif |
default: |
break; |
} |
158,6 → 212,11 |
ns16550_release(); |
break; |
#endif |
#ifdef CONFIG_SGCN |
case KBD_SGCN: |
sgcn_release(); |
break; |
#endif |
default: |
break; |
} |
/branches/tracing/kernel/arch/sparc64/src/sparc64.c |
---|
86,7 → 86,7 |
* But we only create 128 buckets. |
*/ |
irq_init(1 << 11, 128); |
standalone_sparc64_console_init(); |
} |
} |
/branches/tracing/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\n"); |
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) { |
79,6 → 87,12 |
* The IRQ handler was found. |
*/ |
irq->handler(irq, irq->arg); |
/* |
* 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) { |
/* |
98,7 → 112,7 |
*/ |
#ifdef CONFIG_DEBUG |
printf("cpu%u: spurious interrupt (intrcv=%#" PRIx64 |
", data0=%#" PRIx64 ")\n", CPU->id, intrcv, data0); |
", data0=%#" PRIx64 ")\n", CPU->id, intrcv, data0); |
#endif |
} |
/branches/tracing/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; |
/branches/tracing/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,16 → 370,57 |
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) |
{ |
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/tracing/kernel/arch/sparc64/src/mm/as.c |
---|
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/tracing/kernel/arch/sparc64/src/mm/cache.S |
---|
47,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/tracing/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/tracing/kernel/arch/sparc64/src/mm/page.c |
---|
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; |
166,3 → 166,4 |
/** @} |
*/ |
/branches/tracing/kernel/arch/sparc64/src/drivers/fhc.c |
---|
101,8 → 101,9 |
} |
} |
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) { |
/branches/tracing/kernel/arch/sparc64/src/drivers/kbd.c |
---|
63,6 → 63,8 |
uintptr_t aligned_addr; |
ofw_tree_property_t *prop; |
const char *name; |
cir_t cir; |
void *cir_arg; |
name = ofw_tree_node_name(node); |
103,11 → 105,14 |
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,11 → 120,14 |
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; |
}; |
142,16 → 150,17 |
switch (kbd_type) { |
#ifdef CONFIG_Z8530 |
case KBD_Z8530: |
z8530_init(devno, inr, vaddr); |
z8530_init(devno, vaddr, inr, cir, cir_arg); |
break; |
#endif |
#ifdef CONFIG_NS16550 |
case KBD_NS16550: |
ns16550_init(devno, inr, (ioport_t)vaddr); |
ns16550_init(devno, (ioport_t)vaddr, inr, cir, cir_arg); |
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/tracing/kernel/arch/sparc64/src/drivers/scr.c |
---|
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,7 → 73,7 |
scr_type = SCR_CGSIX; |
if (scr_type == SCR_UNKNOWN) { |
printf("Unknown keyboard device.\n"); |
printf("Unknown screen device.\n"); |
return; |
} |
106,15 → 112,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 → 148,54 |
} |
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; |
} |
switch (fb_depth) { |
case 8: |
fb_scanline = fb_linebytes * (fb_depth >> 3); |
visual = VISUAL_SB1500_PALETTE; |
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 → 212,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; |
} |
175,7 → 223,15 |
panic("Unexpected type.\n"); |
} |
fb_init(fb_addr, fb_width, fb_height, fb_scanline, visual); |
fb_properties_t props = { |
.addr = fb_addr, |
.offset = 0, |
.x = fb_width, |
.y = fb_height, |
.scan = fb_scanline, |
.visual = visual, |
}; |
fb_init(&props); |
} |
/** @} |
/branches/tracing/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/tracing/kernel/arch/sparc64/src/drivers/sgcn.c |
---|
0,0 → 1,450 |
/* |
* 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 <func.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); |
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; |
/** |
* Registers the physical area of the SRAM so that the userspace SGCN |
* driver can map it. Moreover, it sets some sysinfo values (SRAM address |
* and SRAM size). |
*/ |
static void register_sram_parea(uintptr_t sram_begin_physical) |
{ |
static parea_t sram_parea; |
sram_parea.pbase = sram_begin_physical; |
sram_parea.vbase = (uintptr_t) sram_begin; |
sram_parea.frames = MAPPED_AREA_SIZE / FRAME_SIZE; |
sram_parea.cacheable = false; |
ddi_parea_register(&sram_parea); |
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("Can't find /chosen.\n"); |
iosram_toc = ofw_tree_getprop(chosen, "iosram-toc"); |
if (!iosram_toc) |
panic("Can't find property \"iosram-toc\".\n"); |
if (!iosram_toc->value) |
panic("Can't find SRAM TOC.\n"); |
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_parea(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) |
{ |
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(void) |
{ |
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, void *arg, ...) |
{ |
panic("Not yet implemented, SGCN works in polled mode.\n"); |
} |
/** |
* 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) { |
if (sgcn_irq.notif_cfg.notify && sgcn_irq.notif_cfg.answerbox) { |
ipc_irq_send_notif(&sgcn_irq); |
spinlock_unlock(&sgcn_irq.lock); |
interrupts_restore(ipl); |
spinlock_unlock(&sgcn_input_lock); |
return; |
} |
} |
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/tracing/kernel/arch/sparc64/src/drivers/pci.c |
---|
45,40 → 45,37 |
#include <func.h> |
#include <arch/asm.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 → 92,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,7 → 106,7 |
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); |
return pci; |
} |
116,9 → 114,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 → 133,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 → 147,21 |
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); |
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 → 204,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/tracing/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 |
/branches/tracing/kernel/arch/ia64/include/interrupt.h |
---|
50,10 → 50,13 |
#define IVT_FIRST 0 |
/** External Interrupt vectors. */ |
#define VECTOR_TLB_SHOOTDOWN_IPI 0xf0 |
#define INTERRUPT_TIMER 255 |
#define IRQ_KBD 241 |
#define IRQ_MOUSE 252 |
#define IRQ_KBD (0x01+LAGACY_INTERRUPT_BASE) |
#define IRQ_MOUSE (0x0c+LAGACY_INTERRUPT_BASE) |
#define INTERRUPT_SPURIOUS 15 |
#define LAGACY_INTERRUPT_BASE 0x20 |
/** General Exception codes. */ |
#define GE_ILLEGALOP 0 |
150,6 → 153,7 |
extern void external_interrupt(uint64_t vector, istate_t *istate); |
extern void disabled_fp_register(uint64_t vector, istate_t *istate); |
#endif |
/** @} |
/branches/tracing/kernel/arch/ia64/include/proc/task.h |
---|
31,14 → 31,19 |
*/ |
/** @file |
*/ |
#include <proc/task.h> |
#ifndef KERN_ia64_TASK_H_ |
#define KERN_ia64_TASK_H_ |
#include <adt/bitmap.h> |
typedef struct { |
bitmap_t *iomap; |
} task_arch_t; |
#define task_create_arch(t) |
#define task_create_arch(t) {(t)->arch.iomap=NULL;} |
#define task_destroy_arch(t) |
#endif |
/branches/tracing/kernel/arch/ia64/include/bootinfo.h |
---|
67,6 → 67,7 |
unsigned long sys_freq; |
unsigned long freq_scale; |
unsigned int wakeup_intno; |
int hello_configured; |
} bootinfo_t; |
/branches/tracing/kernel/arch/ia64/include/mm/page.h |
---|
48,8 → 48,15 |
#define IO_PAGE_WIDTH 26 /* 64M */ |
#define FW_PAGE_WIDTH 28 /* 256M */ |
/** Staticly mapped IO spaces */ |
#define USPACE_IO_PAGE_WIDTH 12 /* 4K */ |
/** Staticly mapped IO spaces - offsets to 0xe...00 of virtual adresses |
becauce of "minimal virtual bits implemented is 51" |
it is possible to have here values up to 0x0007000000000000 |
*/ |
/* Firmware area (bellow 4GB in phys mem) */ |
#define FW_OFFSET 0x00000000F0000000 |
/* Legacy IO space */ |
/branches/tracing/kernel/arch/ia64/include/mm/tlb.h |
---|
46,8 → 46,8 |
/** Data and instruction Translation Register indices. */ |
#define DTR_KERNEL 0 |
#define ITR_KERNEL 0 |
#define DTR_KSTACK1 1 |
#define DTR_KSTACK2 2 |
#define DTR_KSTACK1 4 |
#define DTR_KSTACK2 5 |
/** Portion of TLB insertion format data structure. */ |
union tlb_entry { |
/branches/tracing/kernel/arch/ia64/include/cpu.h |
---|
87,6 → 87,8 |
static inline void ipi_send_ipi(int id,int eid,int intno) |
{ |
(bootinfo->sapic)[2*(id*256+eid)]=intno; |
srlz_d(); |
} |
/branches/tracing/kernel/arch/ia64/include/drivers/kbd.h |
---|
0,0 → 1,48 |
/* |
* Copyright (c) 2006 Jakub Jermar, Jakub Vana |
* 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 ia6464 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_ia64_KBD_H_ |
#define KERN_ia64_KBD_H_ |
#define KBD_UNKNOWN 0 |
#define KBD_SKI 1 |
#define KBD_LEGACY 2 |
#define KBD_NS16550 3 |
#endif |
/** @} |
*/ |
/branches/tracing/kernel/arch/ia64/src/ia64.c |
---|
60,13 → 60,16 |
#include <arch/atomic.h> |
#include <panic.h> |
#include <print.h> |
#include <sysinfo/sysinfo.h> |
/*NS16550 as a COM 1*/ |
#define NS16550_IRQ 4 |
#define NS16550_IRQ (4+LAGACY_INTERRUPT_BASE) |
#define NS16550_PORT 0x3f8 |
bootinfo_t *bootinfo; |
static uint64_t iosapic_base=0xfec00000; |
void arch_pre_main(void) |
{ |
/* Setup usermode init tasks. */ |
110,10 → 113,40 |
} |
static void iosapic_init(void) |
{ |
uint64_t IOSAPIC = PA2KA((unative_t)(iosapic_base))|FW_OFFSET; |
int i; |
int myid,myeid; |
myid=ia64_get_cpu_id(); |
myeid=ia64_get_cpu_eid(); |
for(i=0;i<16;i++) |
{ |
if(i==2) continue; //Disable Cascade interrupt |
((uint32_t*)(IOSAPIC+0x00))[0]=0x10+2*i; |
srlz_d(); |
((uint32_t*)(IOSAPIC+0x10))[0]=LAGACY_INTERRUPT_BASE+i; |
srlz_d(); |
((uint32_t*)(IOSAPIC+0x00))[0]=0x10+2*i+1; |
srlz_d(); |
((uint32_t*)(IOSAPIC+0x10))[0]=myid<<(56-32) | myeid<<(48-32); |
srlz_d(); |
} |
} |
void arch_post_mm_init(void) |
{ |
if(config.cpu_active==1) |
{ |
iosapic_init(); |
irq_init(INR_COUNT, INR_COUNT); |
#ifdef SKI |
ski_init_console(); |
121,7 → 154,8 |
ega_init(); |
#endif |
} |
it_init(); |
it_init(); |
} |
void arch_post_cpu_init(void) |
139,9 → 173,14 |
static void i8042_kkbdpoll(void *arg) |
{ |
while (1) { |
i8042_poll(); |
#ifdef CONFIG_NS16550 |
#ifndef CONFIG_NS16550_INTERRUPT_DRIVEN |
ns16550_poll(); |
#endif |
#else |
#ifndef CONFIG_I8042_INTERRUPT_DRIVEN |
i8042_poll(); |
#endif |
#endif |
thread_usleep(POLL_INTERVAL); |
} |
148,6 → 187,14 |
} |
#endif |
void end_of_irq_void(void *cir_arg __attribute__((unused)),inr_t inr __attribute__((unused))); |
void end_of_irq_void(void *cir_arg __attribute__((unused)),inr_t inr __attribute__((unused))) |
{ |
return; |
} |
void arch_post_smp_init(void) |
{ |
165,13 → 212,13 |
#ifdef I460GX |
devno_t kbd = device_assign_devno(); |
devno_t mouse = device_assign_devno(); |
/* keyboard controller */ |
i8042_init(kbd, IRQ_KBD, mouse, IRQ_MOUSE); |
#ifdef CONFIG_NS16550 |
ns16550_init(kbd, NS16550_IRQ, NS16550_PORT); // as a COM 1 |
ns16550_init(kbd, NS16550_PORT, NS16550_IRQ,end_of_irq_void,NULL); // as a COM 1 |
#else |
devno_t mouse = device_assign_devno(); |
i8042_init(kbd, IRQ_KBD, mouse, IRQ_MOUSE); |
#endif |
thread_t *t; |
t = thread_create(i8042_kkbdpoll, NULL, TASK, 0, "kkbdpoll", true); |
182,6 → 229,15 |
#endif |
} |
sysinfo_set_item_val("ia64_iospace", NULL, true); |
sysinfo_set_item_val("ia64_iospace.address", NULL, true); |
sysinfo_set_item_val("ia64_iospace.address.virtual", NULL, IO_OFFSET); |
} |
231,6 → 287,12 |
{ |
#ifdef SKI |
ski_kbd_grab(); |
#else |
#ifdef CONFIG_NS16550 |
ns16550_grab(); |
#else |
i8042_grab(); |
#endif |
#endif |
} |
/** Return console to userspace |
240,6 → 302,13 |
{ |
#ifdef SKI |
ski_kbd_release(); |
#else |
#ifdef CONFIG_NS16550 |
ns16550_release(); |
#else |
i8042_release(); |
#endif |
#endif |
} |
/branches/tracing/kernel/arch/ia64/src/ski/ski.c |
---|
44,6 → 44,7 |
#include <proc/thread.h> |
#include <synch/spinlock.h> |
#include <arch/asm.h> |
#include <arch/drivers/kbd.h> |
#define SKI_KBD_INR 0 |
227,6 → 228,7 |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.inr", NULL, SKI_KBD_INR); |
sysinfo_set_item_val("kbd.devno", NULL, ski_kbd_devno); |
sysinfo_set_item_val("kbd.type", NULL, KBD_SKI); |
} |
void ski_kbd_grab(void) |
/branches/tracing/kernel/arch/ia64/src/smp/smp.c |
---|
96,12 → 96,28 |
void ipi_broadcast_arch(int ipi ) |
{ |
ipi_broadcast_arch_all(ipi); |
int id,eid; |
int myid,myeid; |
myid=ia64_get_cpu_id(); |
myeid=ia64_get_cpu_eid(); |
//printf("Sending ipi %d on %d\n",ipi,CPU->id); |
for(id=0;id<256;id++) |
for(eid=0;eid<256;eid++) |
if((id!=myid) || (eid!=myeid)) |
if(cpu_by_id_eid_list[id][eid]) |
ipi_send_ipi(id,eid,ipi); |
} |
void smp_init(void) |
{ |
if(!bootinfo->hello_configured) return; |
//If we have not system prepared by hello, we are not able to start AP's |
//this means we are running on simulator |
sapic_init(); |
ipi_broadcast_arch_all(bootinfo->wakeup_intno); |
volatile long long brk; |
/branches/tracing/kernel/arch/ia64/src/ddi/ddi.c |
---|
1,5 → 1,5 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* Copyright (c) 2006 Jakub Jermar, Jakub vana |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
35,7 → 35,12 |
#include <ddi/ddi.h> |
#include <proc/task.h> |
#include <arch/types.h> |
#include <mm/slab.h> |
#include <errno.h> |
#define IO_MEMMAP_PAGES 16384 |
#define PORTS_PER_PAGE 4 |
/** Enable I/O space range for task. |
* |
* Interrupts are disabled and task is locked. |
48,6 → 53,23 |
*/ |
int ddi_iospace_enable_arch(task_t *task, uintptr_t ioaddr, size_t size) |
{ |
if(!task->arch.iomap) |
{ |
uint8_t *map; |
task->arch.iomap=malloc(sizeof(bitmap_t),0); |
map=malloc(BITS2BYTES(IO_MEMMAP_PAGES),0); |
if(!map) |
return ENOMEM; |
bitmap_initialize(task->arch.iomap,map,IO_MEMMAP_PAGES); |
bitmap_clear_range(task->arch.iomap,0,IO_MEMMAP_PAGES); |
} |
uintptr_t iopage = ioaddr / PORTS_PER_PAGE; |
size = ALIGN_UP (size+ioaddr-4*iopage,PORTS_PER_PAGE); |
bitmap_set_range(task->arch.iomap,iopage,size/4); |
return 0; |
} |
/branches/tracing/kernel/arch/ia64/src/mm/tlb.c |
---|
475,6 → 475,73 |
} |
} |
static int is_io_page_accessible(int page) |
{ |
if(TASK->arch.iomap) return bitmap_get(TASK->arch.iomap,page); |
else return 0; |
} |
#define IO_FRAME_BASE 0xFFFFC000000 |
/** There is special handling of memmaped lagacy io, because |
* of 4KB sized access |
* only for userspace |
* |
* @param va virtual address of page fault |
* @param istate Structure with saved interruption state. |
* |
* |
* @return 1 on success, 0 on fail |
*/ |
static int try_memmap_io_insertion(uintptr_t va, istate_t *istate) |
{ |
if((va >= IO_OFFSET ) && (va < IO_OFFSET + (1<<IO_PAGE_WIDTH))) |
if(TASK){ |
uint64_t io_page=(va & ((1<<IO_PAGE_WIDTH)-1)) >> (USPACE_IO_PAGE_WIDTH); |
if(is_io_page_accessible(io_page)){ |
//printf("Insert %llX\n",va); |
uint64_t page,frame; |
page = IO_OFFSET + (1 << USPACE_IO_PAGE_WIDTH) * io_page; |
frame = IO_FRAME_BASE + (1 << USPACE_IO_PAGE_WIDTH) * io_page; |
tlb_entry_t entry; |
entry.word[0] = 0; |
entry.word[1] = 0; |
entry.p = true; /* present */ |
entry.ma = MA_UNCACHEABLE; |
entry.a = true; /* already accessed */ |
entry.d = true; /* already dirty */ |
entry.pl = PL_USER; |
entry.ar = AR_READ | AR_WRITE; |
entry.ppn = frame >> PPN_SHIFT; //MUSIM spocitat frame |
entry.ps = USPACE_IO_PAGE_WIDTH; |
dtc_mapping_insert(page, TASK->as->asid, entry); //Musim zjistit ASID |
return 1; |
}else { |
fault_if_from_uspace(istate,"IO access fault at %p",va); |
return 0; |
} |
} else |
return 0; |
else |
return 0; |
return 0; |
} |
/** Data TLB fault handler for faults with VHPT turned off. |
* |
* @param vector Interruption vector. |
511,10 → 578,11 |
dtc_pte_copy(t); |
page_table_unlock(AS, true); |
} else { |
page_table_unlock(AS, true); |
if (try_memmap_io_insertion(va,istate)) return; |
/* |
* Forward the page fault to the address space page fault handler. |
*/ |
page_table_unlock(AS, true); |
if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) { |
fault_if_from_uspace(istate,"Page fault at %p",va); |
panic("%s: va=%p, rid=%d, iip=%p\n", __func__, va, rid, istate->cr_iip); |
/branches/tracing/kernel/arch/ia64/src/interrupt.c |
---|
53,6 → 53,7 |
#include <ipc/irq.h> |
#include <ipc/ipc.h> |
#include <synch/spinlock.h> |
#include <mm/tlb.h> |
#define VECTORS_64_BUNDLE 20 |
#define VECTORS_16_BUNDLE 48 |
234,19 → 235,19 |
vector_to_string(vector)); |
} |
static void end_of_local_irq(void) |
{ |
asm volatile ("mov cr.eoi=r0;;"); |
} |
void external_interrupt(uint64_t vector, istate_t *istate) |
{ |
irq_t *irq; |
cr_ivr_t ivr; |
ivr.value = ivr_read(); |
srlz_d(); |
irq = irq_dispatch_and_lock(ivr.vector); |
if (irq) { |
irq->handler(irq, irq->arg); |
spinlock_unlock(&irq->lock); |
} else { |
switch (ivr.vector) { |
case INTERRUPT_SPURIOUS: |
#ifdef CONFIG_DEBUG |
254,12 → 255,60 |
#endif |
break; |
#ifdef CONFIG_SMP |
case VECTOR_TLB_SHOOTDOWN_IPI: |
tlb_shootdown_ipi_recv(); |
end_of_local_irq(); |
break; |
#endif |
case INTERRUPT_TIMER: |
{ |
irq_t *irq = irq_dispatch_and_lock(ivr.vector); |
if (irq) { |
irq->handler(irq, irq->arg); |
spinlock_unlock(&irq->lock); |
} else { |
panic("\nUnhandled Internal Timer Interrupt (%d)\n",ivr.vector); |
} |
} |
break; |
default: |
panic("\nUnhandled External Interrupt Vector %d\n", |
ivr.vector); |
{ |
int ack=false; |
irq_t *irq = irq_dispatch_and_lock(ivr.vector); |
if (irq) { |
/* |
* The IRQ handler was found. |
*/ |
if (irq->preack) { |
/* Send EOI before processing the interrupt */ |
end_of_local_irq(); |
ack=true; |
} |
irq->handler(irq, irq->arg); |
spinlock_unlock(&irq->lock); |
} else { |
/* |
* Unhandled interrupt. |
*/ |
end_of_local_irq(); |
ack=true; |
#ifdef CONFIG_DEBUG |
printf("\nUnhandled External Interrupt Vector %d\n",ivr.vector); |
#endif |
} |
if(!ack) end_of_local_irq(); |
} |
break; |
} |
} |
} |
/** @} |
/branches/tracing/kernel/arch/ia64/src/drivers/ega.c |
---|
46,12 → 46,18 |
#include <console/console.h> |
#include <sysinfo/sysinfo.h> |
#include <arch/drivers/ega.h> |
#include <ddi/ddi.h> |
/* |
* The EGA driver. |
* Simple and short. Function for displaying characters and "scrolling". |
*/ |
static parea_t ega_parea; /**< Physical memory area for EGA video RAM. */ |
SPINLOCK_INITIALIZE(egalock); |
static uint32_t ega_cursor; |
static uint8_t *videoram; |
75,12 → 81,21 |
chardev_initialize("ega_out", &ega_console, &ega_ops); |
stdout = &ega_console; |
ega_parea.pbase = VIDEORAM & 0xffffffff; |
ega_parea.vbase = (uintptr_t) videoram; |
ega_parea.frames = 1; |
ega_parea.cacheable = false; |
ddi_parea_register(&ega_parea); |
sysinfo_set_item_val("fb", NULL, true); |
sysinfo_set_item_val("fb.kind", NULL, 2); |
sysinfo_set_item_val("fb.width", NULL, ROW); |
sysinfo_set_item_val("fb.height", NULL, ROWS); |
sysinfo_set_item_val("fb.address.physical", NULL, VIDEORAM); |
sysinfo_set_item_val("fb.blinking", NULL, true); |
sysinfo_set_item_val("fb.address.physical", NULL, VIDEORAM & 0xffffffff); |
#ifndef CONFIG_FB |
putchar('\n'); |
/branches/tracing/kernel/arch/arm32/src/arm32.c |
---|
86,7 → 86,15 |
console_init(device_assign_devno()); |
#ifdef CONFIG_FB |
fb_init(machine_get_fb_address(), 640, 480, 1920, VISUAL_RGB_8_8_8); |
fb_properties_t prop = { |
.addr = machine_get_fb_address(), |
.offset = 0, |
.x = 640, |
.y = 480, |
.scan = 1920, |
.visual = VISUAL_RGB_8_8_8, |
}; |
fb_init(&prop); |
#endif |
} |
/branches/tracing/kernel/arch/ppc32/src/ppc32.c |
---|
94,7 → 94,15 |
default: |
panic("Unsupported bits per pixel"); |
} |
fb_init(bootinfo.screen.addr, bootinfo.screen.width, bootinfo.screen.height, bootinfo.screen.scanline, visual); |
fb_properties_t prop = { |
.addr = bootinfo.screen.addr, |
.offset = 0, |
.x = bootinfo.screen.width, |
.y = bootinfo.screen.height, |
.scan = bootinfo.screen.scanline, |
.visual = visual, |
}; |
fb_init(&prop); |
/* Initialize IRQ routing */ |
irq_init(IRQ_COUNT, IRQ_COUNT); |
103,7 → 111,8 |
pic_init(bootinfo.keyboard.addr, PAGE_SIZE); |
/* Initialize I/O controller */ |
cuda_init(device_assign_devno(), bootinfo.keyboard.addr + 0x16000, 2 * PAGE_SIZE); |
cuda_init(device_assign_devno(), |
bootinfo.keyboard.addr + 0x16000, 2 * PAGE_SIZE); |
/* Merge all zones to 1 big zone */ |
zone_merge_all(); |
128,7 → 137,10 |
void userspace(uspace_arg_t *kernel_uarg) |
{ |
userspace_asm((uintptr_t) kernel_uarg->uspace_uarg, (uintptr_t) kernel_uarg->uspace_stack + THREAD_STACK_SIZE - SP_DELTA, (uintptr_t) kernel_uarg->uspace_entry); |
userspace_asm((uintptr_t) kernel_uarg->uspace_uarg, |
(uintptr_t) kernel_uarg->uspace_stack + |
THREAD_STACK_SIZE - SP_DELTA, |
(uintptr_t) kernel_uarg->uspace_entry); |
/* Unreachable */ |
for (;;) |
/branches/tracing/kernel/arch/mips32/src/mips32.c |
---|
126,7 → 126,15 |
console_init(device_assign_devno()); |
#ifdef CONFIG_FB |
/* GXemul framebuffer */ |
fb_init(0x12000000, 640, 480, 1920, VISUAL_RGB_8_8_8); |
fb_properties_t gxemul_prop = { |
.addr = 0x12000000, |
.offset = 0, |
.x = 640, |
.y = 480, |
.scan = 1920, |
.visual = VISUAL_RGB_8_8_8, |
}; |
fb_init(&gxemul_prop); |
#endif |
sysinfo_set_item_val("machine." STRING(MACHINE), NULL, 1); |
} |
/branches/tracing/kernel/arch/ia32/src/asm.S |
---|
158,6 → 158,7 |
*/ |
.global sysenter_handler |
sysenter_handler: |
sti |
pushl %ebp # remember user stack |
pushl %edi # remember return user address |
/branches/tracing/kernel/arch/ia32/src/drivers/vesa.c |
---|
86,7 → 86,15 |
panic("Unsupported bits per pixel"); |
} |
fb_init(vesa_ph_addr, vesa_width, vesa_height, vesa_scanline, visual); |
fb_properties_t vesa_props = { |
.addr = vesa_ph_addr, |
.offset = 0, |
.x = vesa_width, |
.y = vesa_height, |
.scan = vesa_scanline, |
.visual = visual, |
}; |
fb_init(&vesa_props); |
} |
#endif |
/branches/tracing/uspace/app/bdsh/cmds/modules/cp/cp.c |
---|
30,6 → 30,11 |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <getopt.h> |
#include <string.h> |
#include <fcntl.h> |
#include <assert.h> |
#include "config.h" |
#include "util.h" |
#include "errors.h" |
37,37 → 42,183 |
#include "cp.h" |
#include "cmds.h" |
static char *cmdname = "cp"; |
#define CP_VERSION "0.0.1" |
#define CP_DEFAULT_BUFLEN 1024 |
/* Dispays help for cp in various levels */ |
static const char *cmdname = "cp"; |
static struct option const long_options[] = { |
{ "buffer", required_argument, 0, 'b' }, |
{ "force", no_argument, 0, 'f' }, |
{ "recursive", no_argument, 0, 'r' }, |
{ "help", no_argument, 0, 'h' }, |
{ "version", no_argument, 0, 'v' }, |
{ "verbose", no_argument, 0, 'V' }, |
{ 0, 0, 0, 0 } |
}; |
static int strtoint(const char *s1) |
{ |
long t1; |
if (-1 == (t1 = strtol(s1, (char **) NULL, 10))) |
return -1; |
if (t1 <= 0) |
return -1; |
return (int) t1; |
} |
static int64_t copy_file(const char *src, const char *dest, size_t blen, int vb) |
{ |
int fd1, fd2, bytes = 0; |
off_t total = 0; |
int64_t copied = 0; |
char *buff = NULL; |
if (vb) |
printf("Copying %s to %s\n", src, dest); |
if (-1 == (fd1 = open(src, O_RDONLY))) { |
printf("Unable to open source file %s\n", src); |
return -1; |
} |
if (-1 == (fd2 = open(dest, O_CREAT))) { |
printf("Unable to open destination file %s\n", dest); |
close(fd1); |
return -1; |
} |
total = lseek(fd1, 0, SEEK_END); |
if (vb) |
printf("%d bytes to copy\n", total); |
lseek(fd1, 0, SEEK_SET); |
if (NULL == (buff = (char *) malloc(blen))) { |
printf("Unable to allocate enough memory to read %s\n", |
src); |
copied = -1; |
goto out; |
} |
for (;;) { |
ssize_t res; |
bytes = read(fd1, buff, blen); |
if (bytes <= 0) |
break; |
copied += bytes; |
res = bytes; |
do { |
/* |
* Theoretically, it may not be enough to call write() |
* only once. Also the previous read() may have |
* returned less data than requested. |
*/ |
bytes = write(fd2, buff, res); |
if (bytes < 0) |
goto err; |
res -= bytes; |
} while (res > 0); |
assert(res == 0); |
} |
if (bytes < 0) { |
err: |
printf("Error copying %s, (%d)\n", src, bytes); |
copied = bytes; |
} |
out: |
close(fd1); |
close(fd2); |
if (buff) |
free(buff); |
return copied; |
} |
void help_cmd_cp(unsigned int level) |
{ |
printf("This is the %s help for '%s'.\n", |
level ? EXT_HELP : SHORT_HELP, cmdname); |
static char helpfmt[] = |
"Usage: %s [options] <source> <dest>\n" |
"Options: (* indicates not yet implemented)\n" |
" -h, --help A short option summary\n" |
" -v, --version Print version information and exit\n" |
"* -V, --verbose Be annoyingly noisy about what's being done\n" |
"* -f, --force Do not complain when <dest> exists\n" |
"* -r, --recursive Copy entire directories\n" |
" -b, --buffer ## Set the read buffer size to ##\n" |
"Currently, %s is under development, some options may not work.\n"; |
if (level == HELP_SHORT) { |
printf("`%s' copies files and directories\n", cmdname); |
} else { |
help_cmd_cp(HELP_SHORT); |
printf(helpfmt, cmdname, cmdname); |
} |
return; |
} |
/* Main entry point for cp, accepts an array of arguments */ |
int cmd_cp(char **argv) |
{ |
unsigned int argc; |
unsigned int i; |
unsigned int argc, buffer = 0, verbose = 0; |
int c, opt_ind; |
int64_t ret; |
/* Count the arguments */ |
for (argc = 0; argv[argc] != NULL; argc ++); |
argc = cli_count_args(argv); |
printf("%s %s\n", TEST_ANNOUNCE, cmdname); |
printf("%d arguments passed to %s", argc - 1, cmdname); |
for (c = 0, optind = 0, opt_ind = 0; c != -1;) { |
c = getopt_long(argc, argv, "hvVfrb:", long_options, &opt_ind); |
switch (c) { |
case 'h': |
help_cmd_cp(1); |
return CMD_SUCCESS; |
case 'v': |
printf("%d\n", CP_VERSION); |
return CMD_SUCCESS; |
case 'V': |
verbose = 1; |
break; |
case 'f': |
break; |
case 'r': |
break; |
case 'b': |
if (-1 == (buffer = strtoint(optarg))) { |
printf("%s: Invalid buffer specification, " |
"(should be a number greater than zero)\n", |
cmdname); |
return CMD_FAILURE; |
} |
if (verbose) |
printf("Buffer = %d\n", buffer); |
break; |
} |
} |
if (argc < 2) { |
printf("\n"); |
return CMD_SUCCESS; |
if (buffer == 0) |
buffer = CP_DEFAULT_BUFLEN; |
argc -= optind; |
if (argc != 2) { |
printf("%s: invalid number of arguments. Try %s --help\n", |
cmdname, cmdname); |
return CMD_FAILURE; |
} |
printf(":\n"); |
for (i = 1; i < argc; i++) |
printf("[%d] -> %s\n", i, argv[i]); |
ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose); |
return CMD_SUCCESS; |
if (verbose) |
printf("%d bytes copied\n", ret); |
if (ret >= 0) |
return CMD_SUCCESS; |
else |
return CMD_FAILURE; |
} |
/branches/tracing/uspace/app/init/init.c |
---|
112,6 → 112,7 |
console_wait(); |
version_print(); |
spawn("/app/klog"); |
spawn("/app/bdsh"); |
return 0; |
/branches/tracing/uspace/dist/readme |
---|
0,0 → 1,0 |
Lorem ipsum. |
/branches/tracing/uspace/lib/libfs/libfs.c |
---|
196,12 → 196,15 |
nodep = ops->node_get(dev_handle, |
index); |
if (nodep) { |
if (!ops->link(cur, nodep, component)) { |
int rc; |
rc = ops->link(cur, nodep, component); |
if (rc != EOK) { |
if (lflag & L_CREATE) { |
(void)ops->destroy( |
nodep); |
} |
ipc_answer_0(rid, ENOSPC); |
ipc_answer_0(rid, rc); |
} else { |
ipc_answer_5(rid, EOK, |
fs_handle, dev_handle, |
266,10 → 269,13 |
else |
nodep = ops->node_get(dev_handle, index); |
if (nodep) { |
if (!ops->link(cur, nodep, component)) { |
int rc; |
rc = ops->link(cur, nodep, component); |
if (rc != EOK) { |
if (lflag & L_CREATE) |
(void)ops->destroy(nodep); |
ipc_answer_0(rid, ENOSPC); |
ipc_answer_0(rid, rc); |
} else { |
ipc_answer_5(rid, EOK, |
fs_handle, dev_handle, |
/branches/tracing/uspace/lib/libfs/libfs.h |
---|
47,7 → 47,7 |
void (* node_put)(void *); |
void * (* create)(dev_handle_t, int); |
int (* destroy)(void *); |
bool (* link)(void *, void *, const char *); |
int (* link)(void *, void *, const char *); |
int (* unlink)(void *, void *); |
fs_index_t (* index_get)(void *); |
size_t (* size_get)(void *); |
/branches/tracing/uspace/lib/libc/include/libc.h |
---|
39,12 → 39,18 |
#include <kernel/syscall/syscall.h> |
#include <libarch/syscall.h> |
#define __SYSCALL0(id) __syscall0(0, 0, 0, 0, 0, 0, id) |
#define __SYSCALL1(id, p1) __syscall1(p1, 0, 0, 0, 0, 0, id) |
#define __SYSCALL2(id, p1, p2) __syscall2(p1, p2, 0, 0, 0, 0, id) |
#define __SYSCALL3(id, p1, p2, p3) __syscall3(p1, p2, p3, 0, 0, 0, id) |
#define __SYSCALL4(id, p1, p2, p3, p4) __syscall4(p1, p2, p3, p4, 0, 0, id) |
#define __SYSCALL5(id, p1, p2, p3, p4, p5) __syscall5(p1, p2, p3, p4, p5, 0, id) |
#define __SYSCALL0(id) \ |
__syscall0(0, 0, 0, 0, 0, 0, id) |
#define __SYSCALL1(id, p1) \ |
__syscall1(p1, 0, 0, 0, 0, 0, id) |
#define __SYSCALL2(id, p1, p2) \ |
__syscall2(p1, p2, 0, 0, 0, 0, id) |
#define __SYSCALL3(id, p1, p2, p3) \ |
__syscall3(p1, p2, p3, 0, 0, 0, id) |
#define __SYSCALL4(id, p1, p2, p3, p4) \ |
__syscall4(p1, p2, p3, p4, 0, 0, id) |
#define __SYSCALL5(id, p1, p2, p3, p4, p5) \ |
__syscall5(p1, p2, p3, p4, p5, 0, id) |
#define __SYSCALL6(id, p1, p2, p3, p4, p5, p6) \ |
__syscall6(p1, p2, p3, p4, p5, p6, id) |
/branches/tracing/uspace/lib/libc/include/ctype.h |
---|
79,11 → 79,19 |
static inline int tolower(int c) |
{ |
if (isupper(c)) |
return (c + ('a' - 'A' > 0 ? 'a' - 'A' : 'A' - 'a')); |
return (c + ('a' - 'A')); |
else |
return c; |
} |
static inline int toupper(int c) |
{ |
if (islower(c)) |
return (c + ('A' - 'a')); |
else |
return c; |
} |
#endif |
/** @} |
/branches/tracing/uspace/lib/libc/include/ipc/loader.h |
---|
44,7 → 44,7 |
LOADER_SET_ARGS, |
LOADER_LOAD, |
LOADER_RUN |
} fb_request_t; |
} loader_request_t; |
#endif |
/branches/tracing/uspace/lib/libc/include/errno.h |
---|
47,6 → 47,7 |
#define ERANGE (-263) |
#define EXDEV (-264) |
#define EIO (-265) |
#define EMLINK (-266) |
#endif |
/branches/tracing/uspace/lib/libc/arch/ia64/include/ddi.h |
---|
0,0 → 1,98 |
/* |
* Copyright (c) 2005 Jakub Jermar, Jakub Vana |
* 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 ia64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_ia64_DDI_H_ |
#define LIBC_ia64_DDI_H_ |
#include <libarch/types.h> |
typedef uint64_t ioport_t; |
uint64_t get_ia64_iospace_address(void); |
extern uint64_t ia64_iospace_address; |
#define IA64_IOSPACE_ADDRESS (ia64_iospace_address?ia64_iospace_address:(ia64_iospace_address=get_ia64_iospace_address())) |
static inline void outb(ioport_t port,uint8_t v) |
{ |
*((uint8_t *)(IA64_IOSPACE_ADDRESS + ( (port & 0xfff) | ( (port >> 2) << 12 )))) = v; |
asm volatile ("mf\n" ::: "memory"); |
} |
static inline void outw(ioport_t port,uint16_t v) |
{ |
*((uint16_t *)(IA64_IOSPACE_ADDRESS + ( (port & 0xfff) | ( (port >> 2) << 12 )))) = v; |
asm volatile ("mf\n" ::: "memory"); |
} |
static inline void outl(ioport_t port,uint32_t v) |
{ |
*((uint32_t *)(IA64_IOSPACE_ADDRESS + ( (port & 0xfff) | ( (port >> 2) << 12 )))) = v; |
asm volatile ("mf\n" ::: "memory"); |
} |
static inline uint8_t inb(ioport_t port) |
{ |
asm volatile ("mf\n" ::: "memory"); |
return *((uint8_t *)(IA64_IOSPACE_ADDRESS + ( (port & 0xfff) | ( (port >> 2) << 12 )))); |
} |
static inline uint16_t inw(ioport_t port) |
{ |
asm volatile ("mf\n" ::: "memory"); |
return *((uint16_t *)(IA64_IOSPACE_ADDRESS + ( (port & 0xffE) | ( (port >> 2) << 12 )))); |
} |
static inline uint32_t inl(ioport_t port) |
{ |
asm volatile ("mf\n" ::: "memory"); |
return *((uint32_t *)(IA64_IOSPACE_ADDRESS + ( (port & 0xfff) | ( (port >> 2) << 12 )))); |
} |
#endif |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/arch/ia64/Makefile.inc |
---|
41,7 → 41,8 |
ARCH_SOURCES += arch/$(ARCH)/src/syscall.S \ |
arch/$(ARCH)/src/fibril.S \ |
arch/$(ARCH)/src/tls.c |
arch/$(ARCH)/src/tls.c\ |
arch/$(ARCH)/src/ddi.c |
BFD_NAME = elf64-ia64-little |
BFD_ARCH = ia64-elf64 |
/branches/tracing/uspace/lib/libc/arch/ia64/src/ddi.c |
---|
0,0 → 1,13 |
#include <libarch/ddi.h> |
#include <sysinfo.h> |
uint64_t ia64_iospace_address=0; |
uint64_t get_ia64_iospace_address(void) |
{ |
return sysinfo_value("ia64_iospace.address.virtual"); |
} |
/branches/tracing/uspace/srv/kbd/genarch/include/nofb.h |
---|
0,0 → 1,48 |
/* |
* 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 kbd |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KBD_genarch_NOFB_H_ |
#define KBD_genarch_NOFB_H_ |
#include <key_buffer.h> |
#include <genarch/scanc.h> |
extern int kbd_process_no_fb(keybuffer_t *keybuffer, int scan_code); |
#endif |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/kbd/genarch/src/nofb.c |
---|
0,0 → 1,187 |
/* |
* Copyright (c) 2006 Josef Cejka |
* 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 kbdmips32 mips32 |
* @brief HelenOS mips32 arch dependent parts of uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
*/ |
#include <genarch/nofb.h> |
#include <stdio.h> // DELETE!!! |
#define KEY_F1 0x504f1bL |
#define KEY_F2 0x514f1bL |
#define KEY_F3 0x524f1bL |
#define KEY_F4 0x534f1bL |
#define KEY_F5 0x35315b1bL |
#define KEY_F6 0x37315b1bL |
#define KEY_F7 0x38315b1bL |
#define KEY_F8 0x39315b1bL |
#define KEY_F9 0x30325b1bL |
#define KEY_F10 0x31325b1bL |
#define KEY_F11 0x33325b1bL |
#define KEY_F12 0x34325b1bL |
/** |
* Processes the key pressed - pushes the key code into the key buffer. |
* Used in MSIM and Serengeti, i.e. non-framebuffer consoles. |
*/ |
int kbd_process_no_fb(keybuffer_t *keybuffer, int scan_code) |
{ |
static unsigned long buf = 0; |
static int count = 0; |
if(scan_code == 0x7e) { |
switch (buf) { |
case KEY_F5: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 5); |
buf = count = 0; |
return 1; |
case KEY_F6: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 6); |
buf = count = 0; |
return 1; |
case KEY_F7: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 7); |
buf = count = 0; |
return 1; |
case KEY_F8: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 8); |
buf = count = 0; |
return 1; |
case KEY_F9: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 9); |
buf = count = 0; |
return 1; |
case KEY_F10: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 10); |
buf = count = 0; |
return 1; |
case KEY_F11: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 11); |
buf = count = 0; |
return 1; |
case KEY_F12: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 12); |
buf = count = 0; |
return 1; |
default: |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
keybuffer_push(keybuffer, (buf >> 24) &0xff); |
keybuffer_push(keybuffer, scan_code); |
buf = count = 0; |
return 1; |
} |
} |
buf |= ((unsigned long) scan_code)<<(8*(count++)); |
if((buf & 0xff) != (KEY_F1 & 0xff)) { |
keybuffer_push(keybuffer, buf); |
buf = count = 0; |
return 1; |
} |
if (count <= 1) |
return 1; |
if ((buf & 0xffff) != (KEY_F1 & 0xffff) |
&& (buf & 0xffff) != (KEY_F5 & 0xffff) ) { |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
buf = count = 0; |
return 1; |
} |
if (count <= 2) |
return 1; |
switch (buf) { |
case KEY_F1: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 1); |
buf = count = 0; |
return 1; |
case KEY_F2: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 2); |
buf = count = 0; |
return 1; |
case KEY_F3: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 3); |
buf = count = 0; |
return 1; |
case KEY_F4: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 4); |
buf = count = 0; |
return 1; |
} |
if((buf & 0xffffff) != (KEY_F5 & 0xffffff) |
&& (buf & 0xffffff) != (KEY_F9 & 0xffffff)) { |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) & 0xff); |
keybuffer_push(keybuffer, (buf >> 16) & 0xff); |
buf=count=0; |
return 1; |
} |
if (count <= 3) |
return 1; |
switch (buf) { |
case KEY_F5: |
case KEY_F6: |
case KEY_F7: |
case KEY_F8: |
case KEY_F9: |
case KEY_F10: |
case KEY_F11: |
case KEY_F12: |
return 1; |
default: |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
keybuffer_push(keybuffer, (buf >> 24) &0xff); |
buf = count = 0; |
return 1; |
} |
return 1; |
} |
/** @} |
*/ |
/branches/tracing/uspace/srv/kbd/Makefile |
---|
59,6 → 59,15 |
genarch/src/kbd.c |
CFLAGS += -DMOUSE_ENABLED |
endif |
ifeq ($(ARCH), ia64) |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/mouse.c \ |
arch/$(ARCH)/src/scanc.c \ |
arch/$(ARCH)/src/lkbd.c |
GENARCH_SOURCES = \ |
genarch/src/kbd.c |
CFLAGS += -DMOUSE_ENABLED |
endif |
ifeq ($(ARCH), amd64) |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/mouse.c \ |
69,16 → 78,21 |
endif |
ifeq ($(ARCH), sparc64) |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/scanc.c |
arch/$(ARCH)/src/scanc.c \ |
arch/$(ARCH)/src/sgcn.c |
GENARCH_SOURCES = \ |
genarch/src/kbd.c |
genarch/src/kbd.c \ |
genarch/src/nofb.c |
endif |
ifeq ($(ARCH), arm32) |
ARCH_SOURCES += \ |
arch/$(ARCH)/src/kbd_gxemul.c |
endif |
ifeq ($(ARCH), mips32) |
GENARCH_SOURCES += \ |
genarch/src/nofb.c |
endif |
GENERIC_OBJECTS := $(addsuffix .o,$(basename $(GENERIC_SOURCES))) |
ARCH_OBJECTS := $(addsuffix .o,$(basename $(ARCH_SOURCES))) |
GENARCH_OBJECTS := $(addsuffix .o,$(basename $(GENARCH_SOURCES))) |
/branches/tracing/uspace/srv/kbd/arch/sparc64/include/sgcn.h |
---|
0,0 → 1,46 |
/* |
* 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 kbdsparc64 sparc64 |
* @brief Serengeti-specific parts of uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KBD_sparc64_SGCN_H_ |
#define KBD_sparc64_SGCN_H_ |
void sgcn_init(void); |
void sgcn_key_pressed(void); |
#endif |
/** @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/sparc64/src/kbd.c |
---|
35,6 → 35,7 |
*/ |
#include <arch/kbd.h> |
#include <arch/sgcn.h> |
#include <ipc/ipc.h> |
#include <sysinfo.h> |
#include <kbd.h> |
78,6 → 79,7 |
#define KBD_Z8530 1 |
#define KBD_NS16550 2 |
#define KBD_SGCN 3 |
int kbd_arch_init(void) |
{ |
91,6 → 93,9 |
ns16550_cmds[0].addr = (void *) sysinfo_value("kbd.address.virtual"); |
ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &ns16550_kbd); |
break; |
case KBD_SGCN: |
sgcn_init(); |
break; |
default: |
break; |
} |
100,6 → 105,11 |
/** Process keyboard events */ |
int kbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call) |
{ |
if (sysinfo_value("kbd.type") == KBD_SGCN) { |
sgcn_key_pressed(); |
return 1; |
} |
int scan_code = IPC_GET_ARG1(*call); |
if (scan_code == KBD_ALL_KEYS_UP) |
/branches/tracing/uspace/srv/kbd/arch/sparc64/src/sgcn.c |
---|
0,0 → 1,147 |
/* |
* 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 kbdsparc64 sparc64 |
* @brief Serengeti-specific parts of uspace keyboard handler. |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
*/ |
#include <arch/sgcn.h> |
#include <as.h> |
#include <ddi.h> |
#include <ipc/ipc.h> |
#include <kbd.h> |
#include <genarch/nofb.h> |
#include <genarch/kbd.h> |
#include <sysinfo.h> |
#include <stdio.h> |
#include <futex.h> |
/** |
* SGCN buffer header. It is placed at the very beginning of the SGCN |
* buffer. |
*/ |
typedef struct { |
/** hard-wired to "CON" */ |
char magic[4]; |
/** 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; |
} __attribute__ ((packed)) sgcn_buffer_header_t; |
/* |
* 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 *) (sram_virt_addr + sram_buffer_offset + (offset))) |
/** Returns a pointer to the console buffer header. */ |
#define SGCN_BUFFER_HEADER (SGCN_BUFFER(sgcn_buffer_header_t, 0)) |
extern keybuffer_t keybuffer; |
/** |
* Virtual address mapped to SRAM. |
*/ |
static uintptr_t sram_virt_addr; |
/** |
* SGCN buffer offset within SGCN. |
*/ |
static uintptr_t sram_buffer_offset; |
/** |
* Initializes the SGCN driver. |
* Maps the physical memory (SRAM) and registers the interrupt. |
*/ |
void sgcn_init(void) |
{ |
sram_virt_addr = (uintptr_t) as_get_mappable_page( |
sysinfo_value("sram.area.size")); |
int result = physmem_map( |
(void *) sysinfo_value("sram.address.physical"), |
(void *) sram_virt_addr, |
sysinfo_value("sram.area.size") / PAGE_SIZE, |
AS_AREA_READ | AS_AREA_WRITE |
); |
if (result != 0) { |
printf("SGCN: uspace driver could not map physical memory."); |
} |
sram_buffer_offset = sysinfo_value("sram.buffer.offset"); |
ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), |
0, (void *) 0); |
} |
/** |
* Handler of the "key pressed" event. Reads codes of all the pressed keys from |
* the buffer. |
*/ |
void sgcn_key_pressed(void) |
{ |
char c; |
uint32_t begin = SGCN_BUFFER_HEADER->in_begin; |
uint32_t end = SGCN_BUFFER_HEADER->in_end; |
uint32_t size = end - begin; |
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); |
while (*in_rdptr_ptr != *in_wrptr_ptr) { |
c = *buf_ptr; |
*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin; |
buf_ptr = (volatile char *) |
SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr); |
if (c == '\r') { |
c = '\n'; |
} |
kbd_process_no_fb(&keybuffer, c); |
} |
} |
/** @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/ia64/include/lkbd.h |
---|
0,0 → 1,76 |
/* |
* Copyright (c) 2006 Josef Cejka |
* 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 kbdamd64 amd64 |
* @brief HelenOS ia32 / amd64 arch dependent parts of uspace keyboard and mouse handler. |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
* @ingroup kbdia32 |
*/ |
#ifndef KBD_ia32_KBD_H_ |
#define KBD_ia32_KBD_H_ |
#include <ddi.h> |
#include <libarch/ddi.h> |
#define i8042_DATA 0x60 |
#define i8042_STATUS 0X64 |
typedef unsigned char u8; |
typedef short u16; |
static inline void i8042_data_write(u8 data) |
{ |
outb(i8042_DATA, data); |
} |
static inline u8 i8042_data_read(void) |
{ |
return inb(i8042_DATA); |
} |
static inline u8 i8042_status_read(void) |
{ |
return inb(i8042_STATUS); |
} |
static inline void i8042_command_write(u8 command) |
{ |
outb(i8042_STATUS, command); |
} |
#endif |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/ia64/include/scanc.h |
---|
0,0 → 1,59 |
/* |
* Copyright (c) 2001-2004 Jakub Jermar |
* Copyright (c) 2006 Josef Cejka |
* 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 kbdia32 |
* @{ |
*/ |
/** @file |
* @ingroup kbdamd64 |
*/ |
#ifndef KBD_ia32_SCANC_H_ |
#define KBD_ia32_SCANC_H_ |
/** Scancodes. */ |
#define SC_ESC 0x01 |
#define SC_BACKSPACE 0x0e |
#define SC_LSHIFT 0x2a |
#define SC_RSHIFT 0x36 |
#define SC_CAPSLOCK 0x3a |
#define SC_SPEC_ESCAPE 0xe0 |
#define SC_LEFTARR 0x4b |
#define SC_RIGHTARR 0x4d |
#define SC_UPARR 0x48 |
#define SC_DOWNARR 0x50 |
#define SC_DELETE 0x53 |
#define SC_HOME 0x47 |
#define SC_END 0x4f |
#endif |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/ia64/src/kbd.c |
---|
39,7 → 39,30 |
#include <sysinfo.h> |
#include <kbd.h> |
#include <keys.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <align.h> |
#include <async.h> |
#include <ipc/ipc.h> |
#include <errno.h> |
#include <stdio.h> |
#include <ddi.h> |
#include <sysinfo.h> |
#include <as.h> |
#include <ipc/fb.h> |
#include <ipc/ipc.h> |
#include <ipc/ns.h> |
#include <ipc/services.h> |
#include <libarch/ddi.h> |
extern int lkbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call); |
extern int lkbd_arch_init(void); |
#define KEY_F1 0x504f1b |
#define KEY_F2 0x514f1b |
#define KEY_F3 0x524f1b |
53,8 → 76,45 |
#define KEY_F11 0x7e33325b1b |
#define KEY_F12 0x7e34325b1b |
#define NSKEY_F1 0x415b5b1b |
#define NSKEY_F2 0x425b5b1b |
#define NSKEY_F3 0x435b5b1b |
#define NSKEY_F4 0x445b5b1b |
#define NSKEY_F5 0x455b5b1b |
#define NSKEY_F6 0x37315b1b |
#define NSKEY_F7 0x38315b1b |
#define NSKEY_F8 0x39315b1b |
#define NSKEY_F9 0x30325b1b |
#define NSKEY_F10 0x31325b1b |
#define NSKEY_F11 0x33325b1b |
#define NSKEY_F12 0x34325b1b |
#define FUNCTION_KEYS 0x100 |
#define KBD_SKI 1 |
#define KBD_LEGACY 2 |
#define KBD_NS16550 3 |
/* NS16550 registers */ |
#define RBR_REG 0 /** Receiver Buffer Register. */ |
#define IER_REG 1 /** Interrupt Enable Register. */ |
#define IIR_REG 2 /** Interrupt Ident Register (read). */ |
#define FCR_REG 2 /** FIFO control register (write). */ |
#define LCR_REG 3 /** Line Control register. */ |
#define MCR_REG 4 /** Modem Control Register. */ |
#define LSR_REG 5 /** Line Status Register. */ |
irq_cmd_t ski_cmds[1] = { |
{ CMD_IA64_GETCHAR, 0, 0, 2 } |
}; |
64,10 → 124,33 |
ski_cmds |
}; |
irq_cmd_t ns16550_cmds[1] = { |
{ CMD_PORT_READ_1, 0, 0, 2 }, |
}; |
irq_code_t ns16550_kbd = { |
1, |
ns16550_cmds |
}; |
uint16_t ns16550_port; |
int kbd_type; |
int kbd_arch_init(void) |
{ |
if (sysinfo_value("kbd")) { |
ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &ski_kbd); |
kbd_type=sysinfo_value("kbd.type"); |
if(kbd_type==KBD_SKI) ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &ski_kbd); |
if(kbd_type==KBD_LEGACY) return lkbd_arch_init(); |
if(kbd_type==KBD_NS16550) { |
ns16550_kbd.cmds[0].addr= (void *) (sysinfo_value("kbd.port")+RBR_REG); |
ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &ns16550_kbd); |
iospace_enable(task_get_id(),ns16550_port=sysinfo_value("kbd.port"),8); |
} |
return 0; |
} |
return 1; |
81,14 → 164,163 |
return "0123456789ABCDEF"[v]; |
} |
*/ |
#define LSR_DATA_READY 0x01 |
int kbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call) |
int kbd_ns16550_process(keybuffer_t *keybuffer, ipc_call_t *call) |
{ |
static unsigned long buf = 0; |
static int count = 0, esc_count=0; |
int scan_code = IPC_GET_ARG2(*call); |
if (scan_code == 0x1b) { |
esc_count++; |
if (esc_count == 3) { |
__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE); |
} |
} else { |
esc_count = 0; |
} |
if(scan_code==0x0d) return 1; //Delete CR |
if(scan_code==0x7f) scan_code='\b'; //Convert backspace |
if(scan_code == 0x7e) { |
switch (buf) { |
case NSKEY_F6: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 6); |
buf = count = 0; |
return 1; |
case NSKEY_F7: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 7); |
buf = count = 0; |
return 1; |
case NSKEY_F8: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 8); |
buf = count = 0; |
return 1; |
case NSKEY_F9: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 9); |
buf = count = 0; |
return 1; |
case NSKEY_F10: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 10); |
buf = count = 0; |
return 1; |
case NSKEY_F11: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 11); |
buf = count = 0; |
return 1; |
case NSKEY_F12: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 12); |
buf = count = 0; |
return 1; |
default: |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
keybuffer_push(keybuffer, (buf >> 24) &0xff); |
keybuffer_push(keybuffer, scan_code); |
buf = count = 0; |
return 1; |
} |
} |
buf |= ((unsigned long) scan_code)<<(8*(count++)); |
if((buf & 0xff) != (NSKEY_F1 & 0xff)) { |
keybuffer_push(keybuffer, buf); |
buf = count = 0; |
return 1; |
} |
if (count <= 1) |
return 1; |
if ((buf & 0xffff) != (NSKEY_F1 & 0xffff)) { |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
buf = count = 0; |
return 1; |
} |
if (count <= 2) |
return 1; |
if ((buf & 0xffffff) != (NSKEY_F1 & 0xffffff) |
&& (buf & 0xffffff) != (NSKEY_F6 & 0xffffff) |
&& (buf & 0xffffff) != (NSKEY_F9 & 0xffffff) ) { |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
buf = count = 0; |
return 1; |
} |
if (count <= 3) |
return 1; |
switch (buf) { |
case NSKEY_F1: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 1); |
buf = count = 0; |
return 1; |
case NSKEY_F2: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 2); |
buf = count = 0; |
return 1; |
case NSKEY_F3: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 3); |
buf = count = 0; |
return 1; |
case NSKEY_F4: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 4); |
buf = count = 0; |
return 1; |
case NSKEY_F5: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 5); |
buf = count = 0; |
return 1; |
} |
switch (buf) { |
case NSKEY_F6: |
case NSKEY_F7: |
case NSKEY_F8: |
case NSKEY_F9: |
case NSKEY_F10: |
case NSKEY_F11: |
case NSKEY_F12: |
return 1; |
default: |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
keybuffer_push(keybuffer, (buf >> 24) &0xff); |
buf = count = 0; |
return 1; |
} |
return 1; |
} |
int kbd_ski_process(keybuffer_t *keybuffer, ipc_call_t *call) |
{ |
static unsigned long long buf = 0; |
static int count = 0; |
static int esc_count = 0; |
int scan_code = IPC_GET_ARG2(*call); |
/* |
* Please preserve this code (it can be used to determine scancodes) |
*/ |
155,10 → 387,21 |
} |
buf = count = 0; |
} |
return 1; |
} |
int kbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call) |
{ |
printf("KBD Key pressed: %x(%c)\n",IPC_GET_ARG2(*call),IPC_GET_ARG2(*call)); |
if(kbd_type==KBD_SKI) return kbd_ski_process(keybuffer,call); |
if(kbd_type==KBD_NS16550) return kbd_ns16550_process(keybuffer,call); |
if(kbd_type==KBD_LEGACY) return lkbd_arch_process(keybuffer,call); |
} |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/ia64/src/scanc.c |
---|
0,0 → 1,202 |
/* |
* Copyright (c) 2001-2004 Jakub Jermar |
* Copyright (c) 2006 Josef Cejka |
* 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 kbdia32 |
* @brief Scancodes for PC keyboards. |
* @{ |
*/ |
/** @file |
* @ingroup kbdamd64 |
*/ |
#include <genarch/scanc.h> |
/** Primary meaning of scancodes. */ |
int sc_primary_map[] = { |
SPECIAL, /* 0x00 */ |
SPECIAL, /* 0x01 - Esc */ |
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', |
'\b', /* 0x0e - Backspace */ |
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', |
SPECIAL, /* 0x1d - LCtrl */ |
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', |
'`', |
SPECIAL, /* 0x2a - LShift */ |
'\\', |
'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', |
SPECIAL, /* 0x36 - RShift */ |
'*', |
SPECIAL, /* 0x38 - LAlt */ |
' ', |
SPECIAL, /* 0x3a - CapsLock */ |
(FUNCTION_KEYS | 1), /* 0x3b - F1 */ |
(FUNCTION_KEYS | 2), /* 0x3c - F2 */ |
(FUNCTION_KEYS | 3), /* 0x3d - F3 */ |
(FUNCTION_KEYS | 4), /* 0x3e - F4 */ |
(FUNCTION_KEYS | 5), /* 0x3f - F5 */ |
(FUNCTION_KEYS | 6), /* 0x40 - F6 */ |
(FUNCTION_KEYS | 7), /* 0x41 - F7 */ |
(FUNCTION_KEYS | 8), /* 0x42 - F8 */ |
(FUNCTION_KEYS | 9), /* 0x43 - F9 */ |
(FUNCTION_KEYS | 10), /* 0x44 - F10 */ |
SPECIAL, /* 0x45 - NumLock */ |
SPECIAL, /* 0x46 - ScrollLock */ |
'7', '8', '9', '-', |
'4', '5', '6', '+', |
'1', '2', '3', |
'0', '.', |
SPECIAL, /* 0x54 - Alt-SysRq */ |
SPECIAL, /* 0x55 - F11/F12/PF1/FN */ |
SPECIAL, /* 0x56 - unlabelled key next to LAlt */ |
(FUNCTION_KEYS | 11), /* 0x57 - F11 */ |
(FUNCTION_KEYS | 12), /* 0x58 - F12 */ |
SPECIAL, /* 0x59 */ |
SPECIAL, /* 0x5a */ |
SPECIAL, /* 0x5b */ |
SPECIAL, /* 0x5c */ |
SPECIAL, /* 0x5d */ |
SPECIAL, /* 0x5e */ |
SPECIAL, /* 0x5f */ |
SPECIAL, /* 0x60 */ |
SPECIAL, /* 0x61 */ |
SPECIAL, /* 0x62 */ |
SPECIAL, /* 0x63 */ |
SPECIAL, /* 0x64 */ |
SPECIAL, /* 0x65 */ |
SPECIAL, /* 0x66 */ |
SPECIAL, /* 0x67 */ |
SPECIAL, /* 0x68 */ |
SPECIAL, /* 0x69 */ |
SPECIAL, /* 0x6a */ |
SPECIAL, /* 0x6b */ |
SPECIAL, /* 0x6c */ |
SPECIAL, /* 0x6d */ |
SPECIAL, /* 0x6e */ |
SPECIAL, /* 0x6f */ |
SPECIAL, /* 0x70 */ |
SPECIAL, /* 0x71 */ |
SPECIAL, /* 0x72 */ |
SPECIAL, /* 0x73 */ |
SPECIAL, /* 0x74 */ |
SPECIAL, /* 0x75 */ |
SPECIAL, /* 0x76 */ |
SPECIAL, /* 0x77 */ |
SPECIAL, /* 0x78 */ |
SPECIAL, /* 0x79 */ |
SPECIAL, /* 0x7a */ |
SPECIAL, /* 0x7b */ |
SPECIAL, /* 0x7c */ |
SPECIAL, /* 0x7d */ |
SPECIAL, /* 0x7e */ |
SPECIAL, /* 0x7f */ |
}; |
/** Secondary meaning of scancodes. */ |
int sc_secondary_map[] = { |
SPECIAL, /* 0x00 */ |
0x1b, /* 0x01 - Esc */ |
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', |
SPECIAL, /* 0x0e - Backspace */ |
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', |
SPECIAL, /* 0x1d - LCtrl */ |
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', |
'~', |
SPECIAL, /* 0x2a - LShift */ |
'|', |
'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', |
SPECIAL, /* 0x36 - RShift */ |
'*', |
SPECIAL, /* 0x38 - LAlt */ |
' ', |
SPECIAL, /* 0x3a - CapsLock */ |
SPECIAL, /* 0x3b - F1 */ |
SPECIAL, /* 0x3c - F2 */ |
SPECIAL, /* 0x3d - F3 */ |
SPECIAL, /* 0x3e - F4 */ |
SPECIAL, /* 0x3f - F5 */ |
SPECIAL, /* 0x40 - F6 */ |
SPECIAL, /* 0x41 - F7 */ |
SPECIAL, /* 0x42 - F8 */ |
SPECIAL, /* 0x43 - F9 */ |
SPECIAL, /* 0x44 - F10 */ |
SPECIAL, /* 0x45 - NumLock */ |
SPECIAL, /* 0x46 - ScrollLock */ |
'7', '8', '9', '-', |
'4', '5', '6', '+', |
'1', '2', '3', |
'0', '.', |
SPECIAL, /* 0x54 - Alt-SysRq */ |
SPECIAL, /* 0x55 - F11/F12/PF1/FN */ |
SPECIAL, /* 0x56 - unlabelled key next to LAlt */ |
SPECIAL, /* 0x57 - F11 */ |
SPECIAL, /* 0x58 - F12 */ |
SPECIAL, /* 0x59 */ |
SPECIAL, /* 0x5a */ |
SPECIAL, /* 0x5b */ |
SPECIAL, /* 0x5c */ |
SPECIAL, /* 0x5d */ |
SPECIAL, /* 0x5e */ |
SPECIAL, /* 0x5f */ |
SPECIAL, /* 0x60 */ |
SPECIAL, /* 0x61 */ |
SPECIAL, /* 0x62 */ |
SPECIAL, /* 0x63 */ |
SPECIAL, /* 0x64 */ |
SPECIAL, /* 0x65 */ |
SPECIAL, /* 0x66 */ |
SPECIAL, /* 0x67 */ |
SPECIAL, /* 0x68 */ |
SPECIAL, /* 0x69 */ |
SPECIAL, /* 0x6a */ |
SPECIAL, /* 0x6b */ |
SPECIAL, /* 0x6c */ |
SPECIAL, /* 0x6d */ |
SPECIAL, /* 0x6e */ |
SPECIAL, /* 0x6f */ |
SPECIAL, /* 0x70 */ |
SPECIAL, /* 0x71 */ |
SPECIAL, /* 0x72 */ |
SPECIAL, /* 0x73 */ |
SPECIAL, /* 0x74 */ |
SPECIAL, /* 0x75 */ |
SPECIAL, /* 0x76 */ |
SPECIAL, /* 0x77 */ |
SPECIAL, /* 0x78 */ |
SPECIAL, /* 0x79 */ |
SPECIAL, /* 0x7a */ |
SPECIAL, /* 0x7b */ |
SPECIAL, /* 0x7c */ |
SPECIAL, /* 0x7d */ |
SPECIAL, /* 0x7e */ |
SPECIAL, /* 0x7f */ |
}; |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/ia64/src/mouse.c |
---|
0,0 → 1,117 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* 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. |
*/ |
#include <ipc/ipc.h> |
#include <async.h> |
#include <kbd.h> |
#include <keys.h> |
#define i8042_MOUSE_DATA 0x20 |
#define BUFSIZE 3 |
typedef struct { |
union { |
unsigned char data[BUFSIZE]; |
struct { |
unsigned leftbtn : 1; |
unsigned rightbtn : 1; |
unsigned middlebtn : 1; |
unsigned isone : 1; /* Always one */ |
unsigned xsign : 1; |
unsigned ysign : 1; |
unsigned xovfl : 1; |
unsigned yovfl : 1; |
unsigned char x; |
unsigned char y; |
} val; |
}u; |
}ps2packet_t; |
static ps2packet_t buf; |
static int bufpos = 0; |
static int leftbtn = 0; |
static int rightbtn = 0; |
static int middlebtn = 0; |
/** Convert 9-bit 2-complement signed number to integer */ |
static int bit9toint(int sign, unsigned char data) |
{ |
int tmp; |
if (!sign) |
return data; |
tmp = ((unsigned char)~data) + 1; |
return -tmp; |
} |
/** Process mouse data |
* |
* @return True if mouse command was recognized and processed |
*/ |
int mouse_arch_process(int phoneid, ipc_call_t *call) |
{ |
int status = IPC_GET_ARG1(*call); |
int data = IPC_GET_ARG2(*call); |
int x,y; |
if (!(status & i8042_MOUSE_DATA)) |
return 0; |
/* Check that we have not lost synchronization */ |
if (bufpos == 0 && !(data & 0x8)) |
return 1; /* Synchro lost, ignore byte */ |
buf.u.data[bufpos++] = data; |
if (bufpos == BUFSIZE) { |
bufpos = 0; |
if (phoneid != -1) { |
if (buf.u.val.leftbtn ^ leftbtn) { |
leftbtn = buf.u.val.leftbtn; |
async_msg_1(phoneid, KBD_MS_LEFT, leftbtn); |
} |
if (buf.u.val.rightbtn & rightbtn) { |
rightbtn = buf.u.val.middlebtn; |
async_msg_1(phoneid, KBD_MS_RIGHT, rightbtn); |
} |
if (buf.u.val.rightbtn & rightbtn) { |
middlebtn = buf.u.val.middlebtn; |
async_msg_1(phoneid, KBD_MS_MIDDLE, middlebtn); |
} |
x = bit9toint(buf.u.val.xsign, buf.u.val.x); |
y = bit9toint(buf.u.val.ysign, buf.u.val.y); |
if (x || y) |
async_msg_2(phoneid, KBD_MS_MOVE, (ipcarg_t)x, |
(ipcarg_t)(-y)); |
} |
} |
return 1; |
} |
/branches/tracing/uspace/srv/kbd/arch/ia64/src/lkbd.c |
---|
0,0 → 1,166 |
/* |
* Copyright (c) 2001-2004 Jakub Jermar |
* Copyright (c) 2006 Josef Cejka |
* 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 kbdia64 ia64 |
* @brief HelenOS ia64 |
* @ingroup kbd |
* @{ |
*/ |
/** @file |
* @ingroup kbdia64 |
*/ |
#include <arch/lkbd.h> |
#include <ipc/ipc.h> |
#include <unistd.h> |
#include <kbd.h> |
#include <keys.h> |
#include <genarch/kbd.h> |
#include <sysinfo.h> |
/* Interesting bits for status register */ |
#define i8042_OUTPUT_FULL 0x1 |
#define i8042_INPUT_FULL 0x2 |
#define i8042_MOUSE_DATA 0x20 |
/* Command constants */ |
#define i8042_CMD_KBD 0x60 |
#define i8042_CMD_MOUSE 0xd4 |
/* Keyboard cmd byte */ |
#define i8042_KBD_IE 0x1 |
#define i8042_MOUSE_IE 0x2 |
#define i8042_KBD_DISABLE 0x10 |
#define i8042_MOUSE_DISABLE 0x20 |
#define i8042_KBD_TRANSLATE 0x40 |
/* Mouse constants */ |
#define MOUSE_OUT_INIT 0xf4 |
#define MOUSE_ACK 0xfa |
#define KEY_RELEASE 0x80 |
static volatile int keyflags; /**< Tracking of multiple keypresses. */ |
static volatile int lockflags; /**< Tracking of multiple keys lockings. */ |
irq_cmd_t i8042_cmds[2] = { |
{ CMD_PORT_READ_1, (void *) 0x64, 0, 1 }, |
{ CMD_PORT_READ_1, (void *) 0x60, 0, 2 } |
}; |
irq_code_t i8042_kbd = { |
2, |
i8042_cmds |
}; |
static void wait_ready(void) { |
while (i8042_status_read() & i8042_INPUT_FULL) |
; |
} |
/** Register uspace irq handler |
* @return |
*/ |
int lkbd_arch_init(void) |
{ |
int i; |
int mouseenabled = 0; |
iospace_enable(task_get_id(), (void *) i8042_DATA, 5); |
/* Disable kbd, enable mouse */ |
i8042_command_write(i8042_CMD_KBD); |
wait_ready(); |
i8042_command_write(i8042_CMD_KBD); |
wait_ready(); |
i8042_data_write(i8042_KBD_DISABLE); |
wait_ready(); |
/* Flush all current IO */ |
while (i8042_status_read() & i8042_OUTPUT_FULL) |
i8042_data_read(); |
/* Initialize mouse */ |
i8042_command_write(i8042_CMD_MOUSE); |
wait_ready(); |
i8042_data_write(MOUSE_OUT_INIT); |
wait_ready(); |
int mouseanswer = 0; |
for (i=0;i < 1000; i++) { |
int status = i8042_status_read(); |
if (status & i8042_OUTPUT_FULL) { |
int data = i8042_data_read(); |
if (status & i8042_MOUSE_DATA) { |
mouseanswer = data; |
break; |
} |
} |
usleep(1000); |
} |
if (mouseanswer == MOUSE_ACK) { |
/* enable mouse */ |
mouseenabled = 1; |
ipc_register_irq(sysinfo_value("mouse.inr"), sysinfo_value("mouse.devno"), 0, &i8042_kbd); |
} |
/* Enable kbd */ |
ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &i8042_kbd); |
int newcontrol = i8042_KBD_IE | i8042_KBD_TRANSLATE; |
if (mouseenabled) |
newcontrol |= i8042_MOUSE_IE; |
i8042_command_write(i8042_CMD_KBD); |
wait_ready(); |
i8042_data_write(newcontrol); |
wait_ready(); |
return 0; |
} |
/** Process keyboard & mouse events */ |
int lkbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call) |
{ |
int status = IPC_GET_ARG1(*call); |
if ((status & i8042_MOUSE_DATA)) |
return 0; |
int scan_code = IPC_GET_ARG2(*call); |
if (scan_code & KEY_RELEASE) |
key_released(keybuffer, scan_code ^ KEY_RELEASE); |
else |
key_pressed(keybuffer, scan_code); |
return 1; |
} |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/kbd/arch/mips32/src/kbd.c |
---|
34,6 → 34,7 |
/** @file |
*/ |
#include <arch/kbd.h> |
#include <genarch/nofb.h> |
#include <ipc/ipc.h> |
#include <sysinfo.h> |
#include <kbd.h> |
99,146 → 100,6 |
} |
*/ |
static int kbd_arch_process_no_fb(keybuffer_t *keybuffer, int scan_code) |
{ |
static unsigned long buf = 0; |
static int count = 0; |
/* Please preserve this code (it can be used to determine scancodes) |
keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf)); |
keybuffer_push(keybuffer, to_hex(scan_code&0xf)); |
keybuffer_push(keybuffer, ' '); |
keybuffer_push(keybuffer, ' '); |
return 1; |
*/ |
if(scan_code == 0x7e) { |
switch (buf) { |
case MSIM_KEY_F5: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 5); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F6: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 6); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F7: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 7); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F8: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 8); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F9: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 9); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F10: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 10); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F11: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 11); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F12: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 12); |
buf = count = 0; |
return 1; |
default: |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
keybuffer_push(keybuffer, (buf >> 24) &0xff); |
keybuffer_push(keybuffer, scan_code); |
buf = count = 0; |
return 1; |
} |
} |
buf |= ((unsigned long) scan_code)<<(8*(count++)); |
if((buf & 0xff) != (MSIM_KEY_F1 & 0xff)) { |
keybuffer_push(keybuffer, buf); |
buf = count = 0; |
return 1; |
} |
if (count <= 1) |
return 1; |
if ((buf & 0xffff) != (MSIM_KEY_F1 & 0xffff) |
&& (buf & 0xffff) != (MSIM_KEY_F5 & 0xffff) ) { |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
buf = count = 0; |
return 1; |
} |
if (count <= 2) |
return 1; |
switch (buf) { |
case MSIM_KEY_F1: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 1); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F2: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 2); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F3: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 3); |
buf = count = 0; |
return 1; |
case MSIM_KEY_F4: |
keybuffer_push(keybuffer,FUNCTION_KEYS | 4); |
buf = count = 0; |
return 1; |
} |
if((buf & 0xffffff) != (MSIM_KEY_F5 & 0xffffff) |
&& (buf & 0xffffff) != (MSIM_KEY_F9 & 0xffffff)) { |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) & 0xff); |
keybuffer_push(keybuffer, (buf >> 16) & 0xff); |
buf=count=0; |
return 1; |
} |
if (count <= 3) |
return 1; |
switch (buf) { |
case MSIM_KEY_F5: |
case MSIM_KEY_F6: |
case MSIM_KEY_F7: |
case MSIM_KEY_F8: |
case MSIM_KEY_F9: |
case MSIM_KEY_F10: |
case MSIM_KEY_F11: |
case MSIM_KEY_F12: |
return 1; |
default: |
keybuffer_push(keybuffer, buf & 0xff); |
keybuffer_push(keybuffer, (buf >> 8) &0xff); |
keybuffer_push(keybuffer, (buf >> 16) &0xff); |
keybuffer_push(keybuffer, (buf >> 24) &0xff); |
buf = count = 0; |
return 1; |
} |
return 1; |
} |
static int kbd_arch_process_fb(keybuffer_t *keybuffer, int scan_code) |
{ |
static unsigned long buf = 0; |
371,7 → 232,7 |
if (fb_fb) |
return kbd_arch_process_fb(keybuffer, scan_code); |
return kbd_arch_process_no_fb(keybuffer, scan_code); |
return kbd_process_no_fb(keybuffer, scan_code); |
} |
/** @} |
*/ |
/branches/tracing/uspace/srv/console/console.c |
---|
327,7 → 327,6 |
break; |
case KBD_PUSHCHAR: |
/* got key from keyboard driver */ |
retval = 0; |
c = IPC_GET_ARG1(call); |
/* switch to another virtual console */ |
/branches/tracing/uspace/srv/console/gcons.c |
---|
250,8 → 250,8 |
*/ |
void gcons_mouse_move(int dx, int dy) |
{ |
mouse_x = limit(mouse_x+dx, 0, xres); |
mouse_y = limit(mouse_y+dy, 0, yres); |
mouse_x = limit(mouse_x + dx, 0, xres); |
mouse_y = limit(mouse_y + dy, 0, yres); |
async_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y); |
} |
258,7 → 258,7 |
static int gcons_find_conbut(int x, int y) |
{ |
int status_start = STATUS_START + (xres - 800) / 2;; |
int status_start = STATUS_START + (xres - 800) / 2; |
if (y < STATUS_TOP || y >= STATUS_TOP + STATUS_HEIGHT) |
return -1; |
268,10 → 268,10 |
if (x >= status_start + (STATUS_WIDTH + STATUS_SPACE) * CONSOLE_COUNT) |
return -1; |
if (((x - status_start) % (STATUS_WIDTH+STATUS_SPACE)) < STATUS_SPACE) |
if (((x - status_start) % (STATUS_WIDTH + STATUS_SPACE)) < STATUS_SPACE) |
return -1; |
return (x - status_start) / (STATUS_WIDTH+STATUS_SPACE); |
return (x - status_start) / (STATUS_WIDTH + STATUS_SPACE); |
} |
/** Handle mouse click |
/branches/tracing/uspace/srv/fb/sgcn.h |
---|
0,0 → 1,46 |
/* |
* 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. |
*/ |
/** @defgroup sgcnfb SGCN |
* @brief userland driver of the Serengeti console output |
* @{ |
*/ |
/** @file |
*/ |
#ifndef FB_SGCN_H_ |
#define FB_SGCN_H_ |
int sgcn_init(void); |
#endif |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/fb/serial_console.c |
---|
0,0 → 1,110 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* Copyright (c) 2008 Martin Decky |
* 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. |
*/ |
/** |
* @defgroup serial Serial console |
* @brief Serial console services (putc, puts, clear screen, cursor goto,...) |
* @{ |
*/ |
/** @file |
*/ |
#include <stdio.h> |
#include "serial_console.h" |
#define MAX_CONTROL 20 |
static uint32_t width; |
static uint32_t height; |
static putc_function_t putc_function; |
void serial_puts(char *str) |
{ |
while (*str) |
putc_function(*(str++)); |
} |
void serial_goto(const unsigned int row, const unsigned int col) |
{ |
if ((row > height) || (col > width)) |
return; |
char control[20]; |
snprintf(control, 20, "\033[%u;%uf", row + 1, col + 1); |
serial_puts(control); |
} |
void serial_clrscr(void) |
{ |
serial_puts("\033[2J"); |
} |
void serial_scroll(int i) |
{ |
if (i > 0) { |
serial_goto(height - 1, 0); |
while (i--) |
serial_puts("\033D"); |
} else if (i < 0) { |
serial_goto(0, 0); |
while (i++) |
serial_puts("\033M"); |
} |
} |
void serial_set_style(const unsigned int mode) |
{ |
char control[MAX_CONTROL]; |
snprintf(control, MAX_CONTROL, "\033[%um", mode); |
serial_puts(control); |
} |
void serial_cursor_disable(void) |
{ |
serial_puts("\033[?25l"); |
} |
void serial_cursor_enable(void) |
{ |
serial_puts("\033[?25h"); |
} |
void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h) |
{ |
width = w; |
height = h; |
putc_function = putc_fn; |
} |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/fb/msim.c |
---|
49,6 → 49,7 |
#include <align.h> |
#include <ddi.h> |
#include "serial_console.h" |
#include "msim.h" |
#define WIDTH 80 |
66,57 → 67,6 |
*virt_addr = c; |
} |
static void msim_puts(char *str) |
{ |
while (*str) |
*virt_addr = *(str++); |
} |
static void msim_clrscr(void) |
{ |
msim_puts("\033[2J"); |
} |
static void msim_goto(const unsigned int row, const unsigned int col) |
{ |
if ((row > HEIGHT) || (col > WIDTH)) |
return; |
char control[MAX_CONTROL]; |
snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1); |
msim_puts(control); |
} |
static void msim_set_style(const unsigned int mode) |
{ |
char control[MAX_CONTROL]; |
snprintf(control, MAX_CONTROL, "\033[%um", mode); |
msim_puts(control); |
} |
static void msim_cursor_disable(void) |
{ |
msim_puts("\033[?25l"); |
} |
static void msim_cursor_enable(void) |
{ |
msim_puts("\033[?25h"); |
} |
static void msim_scroll(int i) |
{ |
if (i > 0) { |
msim_goto(HEIGHT - 1, 0); |
while (i--) |
msim_puts("\033D"); |
} else if (i < 0) { |
msim_goto(0, 0); |
while (i++) |
msim_puts("\033M"); |
} |
} |
static void msim_client_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
int retval; |
141,9 → 91,9 |
/* Clear the terminal, set scrolling region |
to 0 - 25 lines */ |
msim_clrscr(); |
msim_goto(0, 0); |
msim_puts("\033[0;25r"); |
serial_clrscr(); |
serial_goto(0, 0); |
serial_puts("\033[0;25r"); |
while (true) { |
callid = async_get_call(&call); |
157,7 → 107,7 |
newrow = IPC_GET_ARG2(call); |
newcol = IPC_GET_ARG3(call); |
if ((lastcol != newcol) || (lastrow != newrow)) |
msim_goto(newrow, newcol); |
serial_goto(newrow, newcol); |
lastcol = newcol + 1; |
lastrow = newrow; |
msim_putc(c); |
166,7 → 116,7 |
case FB_CURSOR_GOTO: |
newrow = IPC_GET_ARG1(call); |
newcol = IPC_GET_ARG2(call); |
msim_goto(newrow, newcol); |
serial_goto(newrow, newcol); |
lastrow = newrow; |
lastcol = newcol; |
retval = 0; |
175,7 → 125,7 |
ipc_answer_2(callid, EOK, HEIGHT, WIDTH); |
continue; |
case FB_CLEAR: |
msim_clrscr(); |
serial_clrscr(); |
retval = 0; |
break; |
case FB_SET_STYLE: |
182,9 → 132,9 |
fgcolor = IPC_GET_ARG1(call); |
bgcolor = IPC_GET_ARG2(call); |
if (fgcolor < bgcolor) |
msim_set_style(0); |
serial_set_style(0); |
else |
msim_set_style(7); |
serial_set_style(7); |
retval = 0; |
break; |
case FB_SCROLL: |
193,15 → 143,15 |
retval = EINVAL; |
break; |
} |
msim_scroll(i); |
msim_goto(lastrow, lastcol); |
serial_scroll(i); |
serial_goto(lastrow, lastcol); |
retval = 0; |
break; |
case FB_CURSOR_VISIBILITY: |
if(IPC_GET_ARG1(call)) |
msim_cursor_enable(); |
serial_cursor_enable(); |
else |
msim_cursor_disable(); |
serial_cursor_disable(); |
retval = 0; |
break; |
default: |
218,6 → 168,8 |
physmem_map(phys_addr, virt_addr, 1, AS_AREA_READ | AS_AREA_WRITE); |
serial_console_init(msim_putc, WIDTH, HEIGHT); |
async_set_client_connection(msim_client_connection); |
return 0; |
} |
/branches/tracing/uspace/srv/fb/serial_console.h |
---|
0,0 → 1,52 |
/* |
* 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. |
*/ |
/** |
* @defgroup serial Serial console |
* @brief Serial console services (putc, puts, clear screen, cursor goto,...) |
* @{ |
*/ |
/** @file |
*/ |
#ifndef FB_SERIAL_CONSOLE_H_ |
#define FB_SERIAL_CONSOLE_H_ |
typedef void (*putc_function_t)(char); |
void serial_puts(char *str); |
void serial_goto(const unsigned int row, const unsigned int col); |
void serial_clrscr(void); |
void serial_scroll(int i); |
void serial_set_style(const unsigned int mode); |
void serial_cursor_disable(void); |
void serial_cursor_enable(void); |
void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h); |
#endif |
/branches/tracing/uspace/srv/fb/main.c |
---|
38,6 → 38,7 |
#include "fb.h" |
#include "ega.h" |
#include "msim.h" |
#include "sgcn.h" |
#include "main.h" |
#define NAME "fb" |
79,6 → 80,12 |
initialized = true; |
} |
#endif |
#ifdef SGCN_ENABLED |
if ((!initialized) && (sysinfo_value("fb.kind") == 4)) { |
if (sgcn_init() == 0) |
initialized = true; |
} |
#endif |
if (!initialized) |
return -1; |
/branches/tracing/uspace/srv/fb/sgcn.c |
---|
0,0 → 1,250 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* Copyright (c) 2008 Martin Decky |
* 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. |
*/ |
/** @defgroup sgcnfb SGCN |
* @brief userland driver of the Serengeti console output |
* @{ |
*/ |
/** @file |
*/ |
#include <async.h> |
#include <ipc/ipc.h> |
#include <ipc/fb.h> |
#include <sysinfo.h> |
#include <as.h> |
#include <errno.h> |
#include <stdio.h> |
#include <ddi.h> |
#include "serial_console.h" |
#include "sgcn.h" |
#define WIDTH 80 |
#define HEIGHT 24 |
/** |
* Virtual address mapped to SRAM. |
*/ |
static uintptr_t sram_virt_addr; |
/** |
* SGCN buffer offset within SGCN. |
*/ |
static uintptr_t sram_buffer_offset; |
/* Allow only 1 connection */ |
static int client_connected = 0; |
/** |
* SGCN buffer header. It is placed at the very beginning of the SGCN |
* buffer. |
*/ |
typedef struct { |
/** hard-wired to "CON" */ |
char magic[4]; |
/** we don't need this */ |
char unused[24]; |
/** 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; |
/* |
* 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 *) (sram_virt_addr + sram_buffer_offset + (offset))) |
/** Returns a pointer to the console buffer header. */ |
#define SGCN_BUFFER_HEADER (SGCN_BUFFER(sgcn_buffer_header_t, 0)) |
/** |
* Pushes the character to the SGCN serial. |
* @param c character to be pushed |
*/ |
static void sgcn_putc(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); |
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; |
} |
/** |
* Main function of the thread serving client connections. |
*/ |
static void sgcn_client_connection(ipc_callid_t iid, ipc_call_t *icall) |
{ |
int retval; |
ipc_callid_t callid; |
ipc_call_t call; |
char c; |
int lastcol = 0; |
int lastrow = 0; |
int newcol; |
int newrow; |
int fgcolor; |
int bgcolor; |
int i; |
if (client_connected) { |
ipc_answer_0(iid, ELIMIT); |
return; |
} |
client_connected = 1; |
ipc_answer_0(iid, EOK); |
/* Clear the terminal, set scrolling region |
to 0 - 24 lines */ |
serial_clrscr(); |
serial_goto(0, 0); |
serial_puts("\033[0;24r"); |
while (true) { |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
client_connected = 0; |
ipc_answer_0(callid, EOK); |
return; |
case FB_PUTCHAR: |
c = IPC_GET_ARG1(call); |
newrow = IPC_GET_ARG2(call); |
newcol = IPC_GET_ARG3(call); |
if ((lastcol != newcol) || (lastrow != newrow)) |
serial_goto(newrow, newcol); |
lastcol = newcol + 1; |
lastrow = newrow; |
sgcn_putc(c); |
retval = 0; |
break; |
case FB_CURSOR_GOTO: |
newrow = IPC_GET_ARG1(call); |
newcol = IPC_GET_ARG2(call); |
serial_goto(newrow, newcol); |
lastrow = newrow; |
lastcol = newcol; |
retval = 0; |
break; |
case FB_GET_CSIZE: |
ipc_answer_2(callid, EOK, HEIGHT, WIDTH); |
continue; |
case FB_CLEAR: |
serial_clrscr(); |
retval = 0; |
break; |
case FB_SET_STYLE: |
fgcolor = IPC_GET_ARG1(call); |
bgcolor = IPC_GET_ARG2(call); |
if (fgcolor < bgcolor) |
serial_set_style(0); |
else |
serial_set_style(7); |
retval = 0; |
break; |
case FB_SCROLL: |
i = IPC_GET_ARG1(call); |
if ((i > HEIGHT) || (i < -HEIGHT)) { |
retval = EINVAL; |
break; |
} |
serial_scroll(i); |
serial_goto(lastrow, lastcol); |
retval = 0; |
break; |
case FB_CURSOR_VISIBILITY: |
if(IPC_GET_ARG1(call)) |
serial_cursor_enable(); |
else |
serial_cursor_disable(); |
retval = 0; |
break; |
default: |
retval = ENOENT; |
} |
ipc_answer_0(callid, retval); |
} |
} |
/** |
* Initializes the SGCN serial driver. |
*/ |
int sgcn_init(void) |
{ |
sram_virt_addr = (uintptr_t) as_get_mappable_page( |
sysinfo_value("sram.area.size")); |
int result = physmem_map( |
(void *) sysinfo_value("sram.address.physical"), |
(void *) sram_virt_addr, |
sysinfo_value("sram.area.size") / PAGE_SIZE, |
AS_AREA_READ | AS_AREA_WRITE |
); |
if (result != 0) { |
printf("SGCN: uspace driver couldn't map physical memory: %d\n", |
result); |
} |
serial_console_init(sgcn_putc, WIDTH, HEIGHT); |
sram_buffer_offset = sysinfo_value("sram.buffer.offset"); |
async_set_client_connection(sgcn_client_connection); |
return 0; |
} |
/** |
* @} |
*/ |
/branches/tracing/uspace/srv/fb/ega.c |
---|
64,9 → 64,12 |
#define EGA_IO_ADDRESS 0x3d4 |
#define EGA_IO_SIZE 2 |
#define NORMAL_COLOR 0x0f |
#define INVERTED_COLOR 0xf0 |
int ega_normal_color=0x0f; |
int ega_inverted_color=0xf0; |
#define NORMAL_COLOR ega_normal_color |
#define INVERTED_COLOR ega_inverted_color |
#define EGA_STYLE(fg,bg) ((fg) > (bg) ? NORMAL_COLOR : INVERTED_COLOR) |
/* Allow only 1 connection */ |
76,7 → 79,7 |
static unsigned int scr_height; |
static char *scr_addr; |
static unsigned int style = NORMAL_COLOR; |
static unsigned int style; |
static void clrscr(void) |
{ |
312,6 → 315,13 |
ega_ph_addr = (void *) sysinfo_value("fb.address.physical"); |
scr_width = sysinfo_value("fb.width"); |
scr_height = sysinfo_value("fb.height"); |
if(sysinfo_value("fb.blinking")) |
{ |
ega_normal_color&=0x77; |
ega_inverted_color&=0x77; |
} |
style = NORMAL_COLOR; |
iospace_enable(task_get_id(), (void *) EGA_IO_ADDRESS, 2); |
sz = scr_width * scr_height * 2; |
/branches/tracing/uspace/srv/fb/Makefile |
---|
56,14 → 56,24 |
SOURCES += ega.c |
CFLAGS += -DEGA_ENABLED |
endif |
ifeq ($(ARCH), ia64) |
SOURCES += ega.c |
CFLAGS += -DEGA_ENABLED |
endif |
ifeq ($(ARCH), amd64) |
SOURCES += ega.c |
CFLAGS += -DEGA_ENABLED |
endif |
ifeq ($(ARCH), mips32) |
SOURCES += msim.c |
SOURCES += msim.c \ |
serial_console.c |
CFLAGS += -DMSIM_ENABLED -DFB_INVERT_ENDIAN |
endif |
ifeq ($(ARCH), sparc64) |
SOURCES += sgcn.c \ |
serial_console.c |
CFLAGS += -DSGCN_ENABLED |
endif |
CFLAGS += -D$(ARCH) |
/branches/tracing/uspace/srv/fs/tmpfs/tmpfs_dump.c |
---|
59,6 → 59,7 |
{ |
struct rdentry entry; |
libfs_ops_t *ops = &tmpfs_libfs_ops; |
int rc; |
do { |
char *fname; |
93,7 → 94,8 |
} |
fname[entry.len] = 0; |
if (!ops->link((void *) parent, (void *) node, fname)) { |
rc = ops->link((void *) parent, (void *) node, fname); |
if (rc != EOK) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
134,8 → 136,9 |
return false; |
} |
fname[entry.len] = 0; |
if (!ops->link((void *) parent, (void *) node, fname)) { |
rc = ops->link((void *) parent, (void *) node, fname); |
if (rc != EOK) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
/branches/tracing/uspace/srv/fs/tmpfs/tmpfs_ops.c |
---|
75,7 → 75,7 |
static void *tmpfs_node_get(dev_handle_t, fs_index_t); |
static void tmpfs_node_put(void *); |
static void *tmpfs_create_node(dev_handle_t, int); |
static bool tmpfs_link_node(void *, void *, const char *); |
static int tmpfs_link_node(void *, void *, const char *); |
static int tmpfs_unlink_node(void *, void *); |
static int tmpfs_destroy_node(void *); |
308,7 → 308,7 |
return (void *) node; |
} |
bool tmpfs_link_node(void *prnt, void *chld, const char *nm) |
int tmpfs_link_node(void *prnt, void *chld, const char *nm) |
{ |
tmpfs_dentry_t *parentp = (tmpfs_dentry_t *) prnt; |
tmpfs_dentry_t *childp = (tmpfs_dentry_t *) chld; |
317,13 → 317,13 |
tmpfs_name_t *namep = malloc(sizeof(tmpfs_name_t)); |
if (!namep) |
return false; |
return ENOMEM; |
tmpfs_name_initialize(namep); |
size_t len = strlen(nm); |
namep->name = malloc(len + 1); |
if (!namep->name) { |
free(namep); |
return false; |
return ENOMEM; |
} |
strcpy(namep->name, nm); |
namep->parent = parentp; |
343,7 → 343,7 |
parentp->child = childp; |
} |
return true; |
return EOK; |
} |
int tmpfs_unlink_node(void *prnt, void *chld) |
/branches/tracing/uspace/srv/fs/fat/fat_idx.c |
---|
423,6 → 423,32 |
return fidx; |
} |
void fat_idx_hashin(fat_idx_t *idx) |
{ |
unsigned long pkey[] = { |
[UPH_DH_KEY] = idx->dev_handle, |
[UPH_PFC_KEY] = idx->pfc, |
[UPH_PDI_KEY] = idx->pdi, |
}; |
futex_down(&used_futex); |
hash_table_insert(&up_hash, pkey, &idx->uph_link); |
futex_up(&used_futex); |
} |
void fat_idx_hashout(fat_idx_t *idx) |
{ |
unsigned long pkey[] = { |
[UPH_DH_KEY] = idx->dev_handle, |
[UPH_PFC_KEY] = idx->pfc, |
[UPH_PDI_KEY] = idx->pdi, |
}; |
futex_down(&used_futex); |
hash_table_remove(&up_hash, pkey, 3); |
futex_up(&used_futex); |
} |
fat_idx_t * |
fat_idx_get_by_index(dev_handle_t dev_handle, fs_index_t index) |
{ |
/branches/tracing/uspace/srv/fs/fat/fat.h |
---|
209,6 → 209,8 |
extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned); |
extern fat_idx_t *fat_idx_get_by_index(dev_handle_t, fs_index_t); |
extern void fat_idx_destroy(fat_idx_t *); |
extern void fat_idx_hashin(fat_idx_t *); |
extern void fat_idx_hashout(fat_idx_t *); |
extern int fat_idx_init(void); |
extern void fat_idx_fini(void); |
/branches/tracing/uspace/srv/fs/fat/fat_dentry.c |
---|
36,16 → 36,81 |
*/ |
#include "fat_dentry.h" |
#include <ctype.h> |
#include <string.h> |
#define FAT_PAD ' ' |
static bool is_d_char(const char ch) |
{ |
if (isalnum(ch) || ch == '_') |
return true; |
else |
return false; |
} |
#define FAT_DENTRY_UNUSED 0x00 |
#define FAT_DENTRY_E5_ESC 0x05 |
#define FAT_DENTRY_DOT 0x2e |
#define FAT_DENTRY_ERASED 0xe5 |
/** Compare path component with the name read from the dentry. |
* |
* This function compares the path component with the name read from the dentry. |
* The comparison is case insensitive and tolerates a mismatch on the trailing |
* dot character at the end of the name (i.e. when there is a dot, but no |
* extension). |
* |
* @param name Node name read from the dentry. |
* @param component Path component. |
* |
* @return Zero on match, non-zero otherwise. |
*/ |
int fat_dentry_namecmp(char *name, const char *component) |
{ |
int rc; |
if (!(rc = stricmp(name, component))) |
return rc; |
if (!strchr(name, '.')) { |
/* |
* There is no '.' in the name, so we know that there is enough |
* space for appending an extra '.' to name. |
*/ |
name[strlen(name)] = '.'; |
name[strlen(name) + 1] = '\0'; |
rc = stricmp(name, component); |
} |
return rc; |
} |
void dentry_name_canonify(fat_dentry_t *d, char *buf) |
bool fat_dentry_name_verify(const char *name) |
{ |
unsigned i, dot; |
bool dot_found = false; |
for (i = 0; name[i]; i++) { |
if (name[i] == '.') { |
if (dot_found) { |
return false; |
} else { |
dot_found = true; |
dot = i; |
} |
} else { |
if (!is_d_char(name[i])) |
return false; |
} |
} |
if (dot_found) { |
if (dot > FAT_NAME_LEN) |
return false; |
if (i - dot > FAT_EXT_LEN + 1) |
return false; |
} else { |
if (i > FAT_NAME_LEN) |
return false; |
} |
return true; |
} |
void fat_dentry_name_get(const fat_dentry_t *d, char *buf) |
{ |
int i; |
for (i = 0; i < FAT_NAME_LEN; i++) { |
71,8 → 136,47 |
*buf = '\0'; |
} |
fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d) |
void fat_dentry_name_set(fat_dentry_t *d, const char *name) |
{ |
int i; |
const char fake_ext[] = " "; |
for (i = 0; i < FAT_NAME_LEN; i++) { |
switch ((uint8_t) *name) { |
case 0xe5: |
d->name[i] = FAT_DENTRY_E5_ESC; |
name++; |
break; |
case '\0': |
case '.': |
d->name[i] = FAT_PAD; |
break; |
default: |
d->name[i] = toupper(*name++); |
break; |
} |
} |
if (*name++ != '.') |
name = fake_ext; |
for (i = 0; i < FAT_EXT_LEN; i++) { |
switch ((uint8_t) *name) { |
case 0xe5: |
d->ext[i] = FAT_DENTRY_E5_ESC; |
name++; |
break; |
case '\0': |
d->ext[i] = FAT_PAD; |
break; |
default: |
d->ext[i] = toupper(*name++); |
break; |
} |
} |
} |
fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d) |
{ |
if (d->attr & FAT_ATTR_VOLLABEL) { |
/* volume label entry */ |
return FAT_DENTRY_SKIP; |
79,7 → 183,7 |
} |
if (d->name[0] == FAT_DENTRY_ERASED) { |
/* not-currently-used entry */ |
return FAT_DENTRY_SKIP; |
return FAT_DENTRY_FREE; |
} |
if (d->name[0] == FAT_DENTRY_UNUSED) { |
/* never used entry */ |
/branches/tracing/uspace/srv/fs/fat/fat_dentry.h |
---|
34,17 → 34,30 |
#define FAT_FAT_DENTRY_H_ |
#include <stdint.h> |
#include <bool.h> |
#define FAT_NAME_LEN 8 |
#define FAT_EXT_LEN 3 |
#define FAT_NAME_DOT ". " |
#define FAT_NAME_DOT_DOT ".. " |
#define FAT_EXT_PAD " " |
#define FAT_ATTR_RDONLY (1 << 0) |
#define FAT_ATTR_VOLLABEL (1 << 3) |
#define FAT_ATTR_SUBDIR (1 << 4) |
#define FAT_PAD ' ' |
#define FAT_DENTRY_UNUSED 0x00 |
#define FAT_DENTRY_E5_ESC 0x05 |
#define FAT_DENTRY_DOT 0x2e |
#define FAT_DENTRY_ERASED 0xe5 |
typedef enum { |
FAT_DENTRY_SKIP, |
FAT_DENTRY_LAST, |
FAT_DENTRY_FREE, |
FAT_DENTRY_VALID |
} fat_dentry_clsf_t; |
70,8 → 83,11 |
uint32_t size; |
} __attribute__ ((packed)) fat_dentry_t; |
extern void dentry_name_canonify(fat_dentry_t *, char *); |
extern fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *); |
extern int fat_dentry_namecmp(char *, const char *); |
extern bool fat_dentry_name_verify(const char *); |
extern void fat_dentry_name_get(const fat_dentry_t *, char *); |
extern void fat_dentry_name_set(fat_dentry_t *, const char *); |
extern fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *); |
#endif |
/branches/tracing/uspace/srv/fs/fat/fat_fat.c |
---|
182,7 → 182,7 |
boundary = ROUND_UP(nodep->size, bps * spc); |
/* zero out already allocated space */ |
for (o = nodep->size - 1; o < pos && o < boundary; |
for (o = nodep->size; o < pos && o < boundary; |
o = ALIGN_DOWN(o + bps, bps)) { |
int flags = (o % bps == 0) ? |
BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE; |
285,10 → 285,10 |
} |
} |
/** Allocate clusters in FAT1. |
/** Allocate clusters in all copies of FAT. |
* |
* This function will attempt to allocate the requested number of clusters in |
* the first FAT instance. The FAT will be altered so that the allocated |
* all instances of the FAT. The FAT will be altered so that the allocated |
* clusters form an independent chain (i.e. a chain which does not belong to any |
* file yet). |
* |
315,7 → 315,7 |
unsigned b, c, cl; |
lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t)); |
if (lifo) |
if (!lifo) |
return ENOMEM; |
bps = uint16_t_le2host(bs->bps); |
326,8 → 326,8 |
* Search FAT1 for unused clusters. |
*/ |
futex_down(&fat_alloc_lock); |
for (b = 0, cl = 0; b < sf; blk++) { |
blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NOREAD); |
for (b = 0, cl = 0; b < sf; b++) { |
blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NONE); |
for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) { |
fat_cluster_t *clst = (fat_cluster_t *)blk->data + c; |
if (uint16_t_le2host(*clst) == FAT_CLST_RES0) { |
385,8 → 385,8 |
/* Mark all clusters in the chain as free in all copies of FAT. */ |
while (firstc < FAT_CLST_LAST1) { |
assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD); |
nextc = fat_get_cluster(bs, dev_handle, firstc); |
assert(nextc >= FAT_CLST_FIRST && nextc < FAT_CLST_BAD); |
for (fatno = FAT1; fatno < bs->fatcnt; fatno++) |
fat_set_cluster(bs, dev_handle, fatno, firstc, |
FAT_CLST_RES0); |
409,7 → 409,7 |
if (fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl, |
(uint16_t) -1) == 0) { |
/* No clusters allocated to the node yet. */ |
nodep->firstc = host2uint16_t_le(mcl); |
nodep->firstc = mcl; |
nodep->dirty = true; /* need to sync node */ |
return; |
} |
/branches/tracing/uspace/srv/fs/fat/fat.c |
---|
116,6 → 116,9 |
case VFS_TRUNCATE: |
fat_truncate(callid, &call); |
break; |
case VFS_DESTROY: |
fat_destroy(callid, &call); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
/branches/tracing/uspace/srv/fs/fat/fat_ops.c |
---|
94,10 → 94,14 |
d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps); |
d->firstc = host2uint16_t_le(node->firstc); |
if (node->type == FAT_FILE) |
if (node->type == FAT_FILE) { |
d->size = host2uint32_t_le(node->size); |
/* TODO: update other fields? (e.g time fields, attr field) */ |
} else if (node->type == FAT_DIRECTORY) { |
d->attr = FAT_ATTR_SUBDIR; |
} |
/* TODO: update other fields? (e.g time fields) */ |
b->dirty = true; /* need to sync block */ |
block_put(b); |
} |
223,7 → 227,7 |
static void fat_node_put(void *); |
static void *fat_create_node(dev_handle_t, int); |
static int fat_destroy_node(void *); |
static bool fat_link(void *, void *, const char *); |
static int fat_link(void *, void *, const char *); |
static int fat_unlink(void *, void *); |
static void *fat_match(void *, const char *); |
static fs_index_t fat_index_get(void *); |
284,25 → 288,58 |
{ |
fat_idx_t *idxp; |
fat_node_t *nodep; |
fat_bs_t *bs; |
fat_cluster_t mcl, lcl; |
uint16_t bps; |
int rc; |
bs = block_bb_get(dev_handle); |
bps = uint16_t_le2host(bs->bps); |
if (flags & L_DIRECTORY) { |
/* allocate a cluster */ |
rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl); |
if (rc != EOK) |
return NULL; |
} |
nodep = fat_node_get_new(); |
if (!nodep) |
if (!nodep) { |
fat_free_clusters(bs, dev_handle, mcl); |
return NULL; |
} |
idxp = fat_idx_get_new(dev_handle); |
if (!idxp) { |
fat_free_clusters(bs, dev_handle, mcl); |
fat_node_put(nodep); |
return NULL; |
} |
/* idxp->lock held */ |
if (flags & L_DIRECTORY) { |
int i; |
block_t *b; |
/* |
* Populate the new cluster with unused dentries. |
*/ |
for (i = 0; i < bs->spc; i++) { |
b = _fat_block_get(bs, dev_handle, mcl, i, |
BLOCK_FLAGS_NOREAD); |
/* mark all dentries as never-used */ |
memset(b->data, 0, bps); |
b->dirty = false; |
block_put(b); |
} |
nodep->type = FAT_DIRECTORY; |
nodep->firstc = mcl; |
nodep->size = bps * bs->spc; |
} else { |
nodep->type = FAT_FILE; |
nodep->firstc = FAT_CLST_RES0; |
nodep->size = 0; |
} |
nodep->size = 0; |
nodep->firstc = FAT_CLST_RES0; |
nodep->lnkcnt = 0; /* not linked anywhere */ |
nodep->refcnt = 1; |
nodep->dirty = true; |
nodep->idx = idxp; |
idxp->nodep = nodep; |
341,14 → 378,174 |
return EOK; |
} |
bool fat_link(void *prnt, void *chld, const char *name) |
int fat_link(void *prnt, void *chld, const char *name) |
{ |
return false; /* not supported at the moment */ |
fat_node_t *parentp = (fat_node_t *)prnt; |
fat_node_t *childp = (fat_node_t *)chld; |
fat_dentry_t *d; |
fat_bs_t *bs; |
block_t *b; |
int i, j; |
uint16_t bps; |
unsigned dps; |
unsigned blocks; |
futex_down(&childp->lock); |
if (childp->lnkcnt == 1) { |
/* |
* On FAT, we don't support multiple hard links. |
*/ |
futex_up(&childp->lock); |
return EMLINK; |
} |
assert(childp->lnkcnt == 0); |
futex_up(&childp->lock); |
if (!fat_dentry_name_verify(name)) { |
/* |
* Attempt to create unsupported name. |
*/ |
return ENOTSUP; |
} |
/* |
* Get us an unused parent node's dentry or grow the parent and allocate |
* a new one. |
*/ |
futex_down(&parentp->idx->lock); |
bs = block_bb_get(parentp->idx->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
dps = bps / sizeof(fat_dentry_t); |
blocks = parentp->size / bps; |
for (i = 0; i < blocks; i++) { |
b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE); |
for (j = 0; j < dps; j++) { |
d = ((fat_dentry_t *)b->data) + j; |
switch (fat_classify_dentry(d)) { |
case FAT_DENTRY_SKIP: |
case FAT_DENTRY_VALID: |
/* skipping used and meta entries */ |
continue; |
case FAT_DENTRY_FREE: |
case FAT_DENTRY_LAST: |
/* found an empty slot */ |
goto hit; |
} |
} |
block_put(b); |
} |
/* |
* We need to grow the parent in order to create a new unused dentry. |
*/ |
futex_up(&parentp->idx->lock); |
return ENOTSUP; /* XXX */ |
hit: |
/* |
* At this point we only establish the link between the parent and the |
* child. The dentry, except of the name and the extension, will remain |
* uninitialized until the the corresponding node is synced. Thus the |
* valid dentry data is kept in the child node structure. |
*/ |
memset(d, 0, sizeof(fat_dentry_t)); |
fat_dentry_name_set(d, name); |
b->dirty = true; /* need to sync block */ |
block_put(b); |
futex_up(&parentp->idx->lock); |
futex_down(&childp->idx->lock); |
/* |
* If possible, create the Sub-directory Identifier Entry and the |
* Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries |
* are not mandatory according to Standard ECMA-107 and HelenOS VFS does |
* not use them anyway, so this is rather a sign of our good will. |
*/ |
b = fat_block_get(bs, childp, 0, BLOCK_FLAGS_NONE); |
d = (fat_dentry_t *)b->data; |
if (fat_classify_dentry(d) == FAT_DENTRY_LAST || |
strcmp(d->name, FAT_NAME_DOT) == 0) { |
memset(d, 0, sizeof(fat_dentry_t)); |
strcpy(d->name, FAT_NAME_DOT); |
strcpy(d->ext, FAT_EXT_PAD); |
d->attr = FAT_ATTR_SUBDIR; |
d->firstc = host2uint16_t_le(childp->firstc); |
/* TODO: initialize also the date/time members. */ |
} |
d++; |
if (fat_classify_dentry(d) == FAT_DENTRY_LAST || |
strcmp(d->name, FAT_NAME_DOT_DOT) == 0) { |
memset(d, 0, sizeof(fat_dentry_t)); |
strcpy(d->name, FAT_NAME_DOT_DOT); |
strcpy(d->ext, FAT_EXT_PAD); |
d->attr = FAT_ATTR_SUBDIR; |
d->firstc = (parentp->firstc == FAT_CLST_ROOT) ? |
host2uint16_t_le(FAT_CLST_RES0) : |
host2uint16_t_le(parentp->firstc); |
/* TODO: initialize also the date/time members. */ |
} |
b->dirty = true; /* need to sync block */ |
block_put(b); |
childp->idx->pfc = parentp->firstc; |
childp->idx->pdi = i * dps + j; |
futex_up(&childp->idx->lock); |
futex_down(&childp->lock); |
childp->lnkcnt = 1; |
childp->dirty = true; /* need to sync node */ |
futex_up(&childp->lock); |
/* |
* Hash in the index structure into the position hash. |
*/ |
fat_idx_hashin(childp->idx); |
return EOK; |
} |
int fat_unlink(void *prnt, void *chld) |
{ |
return ENOTSUP; /* not supported at the moment */ |
fat_node_t *parentp = (fat_node_t *)prnt; |
fat_node_t *childp = (fat_node_t *)chld; |
fat_bs_t *bs; |
fat_dentry_t *d; |
uint16_t bps; |
block_t *b; |
futex_down(&parentp->lock); |
futex_down(&childp->lock); |
assert(childp->lnkcnt == 1); |
futex_down(&childp->idx->lock); |
bs = block_bb_get(childp->idx->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
b = _fat_block_get(bs, childp->idx->dev_handle, childp->idx->pfc, |
(childp->idx->pdi * sizeof(fat_dentry_t)) / bps, |
BLOCK_FLAGS_NONE); |
d = (fat_dentry_t *)b->data + |
(childp->idx->pdi % (bps / sizeof(fat_dentry_t))); |
/* mark the dentry as not-currently-used */ |
d->name[0] = FAT_DENTRY_ERASED; |
b->dirty = true; /* need to sync block */ |
block_put(b); |
/* remove the index structure from the position hash */ |
fat_idx_hashout(childp->idx); |
/* clear position information */ |
childp->idx->pfc = FAT_CLST_RES0; |
childp->idx->pdi = 0; |
futex_up(&childp->idx->lock); |
childp->lnkcnt = 0; |
childp->dirty = true; |
futex_up(&childp->lock); |
futex_up(&parentp->lock); |
return EOK; |
} |
void *fat_match(void *prnt, const char *component) |
374,6 → 571,7 |
d = ((fat_dentry_t *)b->data) + j; |
switch (fat_classify_dentry(d)) { |
case FAT_DENTRY_SKIP: |
case FAT_DENTRY_FREE: |
continue; |
case FAT_DENTRY_LAST: |
block_put(b); |
381,10 → 579,10 |
return NULL; |
default: |
case FAT_DENTRY_VALID: |
dentry_name_canonify(d, name); |
fat_dentry_name_get(d, name); |
break; |
} |
if (stricmp(name, component) == 0) { |
if (fat_dentry_namecmp(name, component) == 0) { |
/* hit */ |
void *node; |
/* |
464,6 → 662,7 |
d = ((fat_dentry_t *)b->data) + j; |
switch (fat_classify_dentry(d)) { |
case FAT_DENTRY_SKIP: |
case FAT_DENTRY_FREE: |
continue; |
case FAT_DENTRY_LAST: |
block_put(b); |
525,6 → 724,10 |
.is_file = fat_is_file |
}; |
/* |
* VFS operations. |
*/ |
void fat_mounted(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
694,6 → 897,7 |
d = ((fat_dentry_t *)b->data) + o; |
switch (fat_classify_dentry(d)) { |
case FAT_DENTRY_SKIP: |
case FAT_DENTRY_FREE: |
continue; |
case FAT_DENTRY_LAST: |
block_put(b); |
700,7 → 904,7 |
goto miss; |
default: |
case FAT_DENTRY_VALID: |
dentry_name_canonify(d, name); |
fat_dentry_name_get(d, name); |
block_put(b); |
goto hit; |
} |
/branches/tracing/uspace/srv/vfs/vfs_ops.c |
---|
234,6 → 234,7 |
mr_res.triplet.index = (fs_index_t) rindex; |
mr_res.size = (size_t) rsize; |
mr_res.lnkcnt = (unsigned) rlnkcnt; |
mr_res.type = VFS_NODE_DIRECTORY; |
rootfs.fs_handle = fs_handle; |
rootfs.dev_handle = dev_handle; |
302,6 → 303,16 |
int mode = IPC_GET_ARG3(*request); |
size_t len; |
/* |
* Make sure that we are called with exactly one of L_FILE and |
* L_DIRECTORY. |
*/ |
if ((lflag & (L_FILE | L_DIRECTORY)) == 0 || |
(lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) { |
ipc_answer_0(rid, EINVAL); |
return; |
} |
if (oflag & O_CREAT) |
lflag |= L_CREATE; |
if (oflag & O_EXCL) |
456,7 → 467,7 |
* the same open file at a time. |
*/ |
futex_down(&file->lock); |
/* |
* Lock the file's node so that no other client can read/write to it at |
* the same time. |
465,6 → 476,15 |
rwlock_read_lock(&file->node->contents_rwlock); |
else |
rwlock_write_lock(&file->node->contents_rwlock); |
if (file->node->type == VFS_NODE_DIRECTORY) { |
/* |
* Make sure that no one is modifying the namespace |
* while we are in readdir(). |
*/ |
assert(read); |
rwlock_read_lock(&namespace_rwlock); |
} |
int fs_phone = vfs_grab_phone(file->node->fs_handle); |
490,6 → 510,9 |
ipcarg_t rc; |
async_wait_for(msg, &rc); |
size_t bytes = IPC_GET_ARG1(answer); |
if (file->node->type == VFS_NODE_DIRECTORY) |
rwlock_read_unlock(&namespace_rwlock); |
/* Unlock the VFS node. */ |
if (read) |
/branches/tracing/uspace/srv/vfs/vfs.h |
---|
190,8 → 190,15 |
*/ |
#define L_PARENT 64 |
typedef enum vfs_node_type { |
VFS_NODE_UNKNOWN, |
VFS_NODE_FILE, |
VFS_NODE_DIRECTORY, |
} vfs_node_type_t; |
typedef struct { |
vfs_triplet_t triplet; |
vfs_node_type_t type; |
size_t size; |
unsigned lnkcnt; |
} vfs_lookup_res_t; |
213,6 → 220,9 |
unsigned lnkcnt; |
link_t nh_link; /**< Node hash-table link. */ |
vfs_node_type_t type; /**< Partial info about the node type. */ |
size_t size; /**< Cached size if the node is a file. */ |
/** |
/branches/tracing/uspace/srv/vfs/vfs_node.c |
---|
175,15 → 175,22 |
node->index = result->triplet.index; |
node->size = result->size; |
node->lnkcnt = result->lnkcnt; |
node->type = result->type; |
link_initialize(&node->nh_link); |
rwlock_initialize(&node->contents_rwlock); |
hash_table_insert(&nodes, key, &node->nh_link); |
} else { |
node = hash_table_get_instance(tmp, vfs_node_t, nh_link); |
if (node->type == VFS_NODE_UNKNOWN && |
result->type != VFS_NODE_UNKNOWN) { |
/* Upgrade the node type. */ |
node->type = result->type; |
} |
} |
assert(node->size == result->size); |
assert(node->lnkcnt == result->lnkcnt); |
assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN); |
_vfs_node_addref(node); |
futex_up(&nodes_futex); |
/branches/tracing/uspace/srv/vfs/vfs_lookup.c |
---|
182,6 → 182,12 |
result->triplet.index = (fs_index_t) IPC_GET_ARG3(answer); |
result->size = (size_t) IPC_GET_ARG4(answer); |
result->lnkcnt = (unsigned) IPC_GET_ARG5(answer); |
if (lflag & L_FILE) |
result->type = VFS_NODE_FILE; |
else if (lflag & L_DIRECTORY) |
result->type = VFS_NODE_DIRECTORY; |
else |
result->type = VFS_NODE_UNKNOWN; |
} |
return rc; |
/branches/tracing/boot/boot.config |
---|
83,5 → 83,8 |
@ "fat" FAT16 image |
! RDFMT (choice) |
# Preserve A.OUT header in isofs.b |
! [ARCH=sparc64] CONFIG_AOUT_ISOFS_B (y/n) |
# External ramdisk |
! [ARCH=sparc64] CONFIG_RD_EXTERNAL (y/n) |
/branches/tracing/boot/genarch/balloc.h |
---|
31,7 → 31,7 |
#include <types.h> |
#define BALLOC_MAX_SIZE (1024 * 1024) |
#define BALLOC_MAX_SIZE (128 * 1024) |
typedef struct { |
uintptr_t base; |
/branches/tracing/boot/genarch/ofw_tree.c |
---|
121,7 → 121,6 |
memcpy(current_node->da_name, &path[i], len); |
current_node->da_name[len] = '\0'; |
/* |
* Recursively process the potential child node. |
*/ |
219,10 → 218,28 |
ofw_tree_node_t *ofw_tree_build(void) |
{ |
ofw_tree_node_t *root; |
phandle ssm_node; |
ofw_tree_node_t *ssm; |
root = ofw_tree_node_alloc(); |
if (root) |
ofw_tree_node_process(root, NULL, ofw_root); |
/* |
* The firmware client interface does not automatically include the |
* "ssm" node in the list of children of "/". A nasty yet working |
* solution is to explicitly stick "ssm" to the OFW tree. |
*/ |
ssm_node = ofw_find_device("/ssm@0,0"); |
if (ssm_node != -1) { |
ssm = ofw_tree_node_alloc(); |
if (ssm) { |
ofw_tree_node_process( |
ssm, root, ofw_find_device("/ssm@0,0")); |
ssm->peer = root->child; |
root->child = ssm; |
} |
} |
return root; |
} |
/branches/tracing/boot/genarch/ofw.c |
---|
48,7 → 48,8 |
if (ofw_chosen == -1) |
halt(); |
if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) <= 0) |
if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout, |
sizeof(ofw_stdout)) <= 0) |
ofw_stdout = 0; |
ofw_root = ofw_find_device("/"); |
57,11 → 58,13 |
halt(); |
} |
if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu, sizeof(ofw_mmu)) <= 0) { |
if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu, |
sizeof(ofw_mmu)) <= 0) { |
puts("\r\nError: Unable to get mmu property, halted.\r\n"); |
halt(); |
} |
if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop, sizeof(ofw_memory_prop)) <= 0) { |
if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop, |
sizeof(ofw_memory_prop)) <= 0) { |
puts("\r\nError: Unable to get memory property, halted.\r\n"); |
halt(); |
} |
81,14 → 84,18 |
/** Perform a call to OpenFirmware client interface. |
* |
* @param service String identifying the service requested. |
* @param nargs Number of input arguments. |
* @param nret Number of output arguments. This includes the return value. |
* @param rets Buffer for output arguments or NULL. The buffer must accommodate nret - 1 items. |
* @param service String identifying the service requested. |
* @param nargs Number of input arguments. |
* @param nret Number of output arguments. This includes the return |
* value. |
* @param rets Buffer for output arguments or NULL. The buffer must |
* accommodate nret - 1 items. |
* |
* @return Return value returned by the client interface. |
* @return Return value returned by the client interface. |
*/ |
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; |
119,7 → 126,9 |
return ofw_call("finddevice", 1, 1, NULL, name); |
} |
int ofw_get_property(const phandle device, const char *name, void *buf, const int buflen) |
int |
ofw_get_property(const phandle device, const char *name, void *buf, |
const int buflen) |
{ |
return ofw_call("getprop", 4, 1, NULL, device, name, buf, buflen); |
} |
144,7 → 153,8 |
unsigned int ret = 1; |
if (ofw_get_property(device, "#address-cells", &ret, sizeof(ret)) <= 0) |
if (ofw_get_property(ofw_root, "#address-cells", &ret, sizeof(ret)) <= 0) |
if (ofw_get_property(ofw_root, "#address-cells", &ret, |
sizeof(ret)) <= 0) |
ret = OFW_ADDRESS_CELLS; |
return ret; |
156,7 → 166,8 |
unsigned int ret; |
if (ofw_get_property(device, "#size-cells", &ret, sizeof(ret)) <= 0) |
if (ofw_get_property(ofw_root, "#size-cells", &ret, sizeof(ret)) <= 0) |
if (ofw_get_property(ofw_root, "#size-cells", &ret, |
sizeof(ret)) <= 0) |
ret = OFW_SIZE_CELLS; |
return ret; |
192,7 → 203,8 |
ofw_arg_t result[4]; |
int shift; |
if (ofw_call("call-method", 3, 5, result, "translate", ofw_mmu, virt) != 0) { |
if (ofw_call("call-method", 3, 5, result, "translate", ofw_mmu, |
virt) != 0) { |
puts("Error: MMU method translate() failed, halting.\n"); |
halt(); |
} |
212,7 → 224,8 |
{ |
ofw_arg_t retaddr; |
if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len, virt) != 0) { |
if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len, |
virt) != 0) { |
puts("Error: MMU method claim() failed, halting.\n"); |
halt(); |
} |
269,8 → 282,8 |
phys_lo = (uintptr_t) phys; |
} |
return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size, virt, |
phys_hi, phys_lo); |
return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size, |
virt, phys_hi, phys_lo); |
} |
/** Save OpenFirmware physical memory map. |
281,10 → 294,13 |
*/ |
int ofw_memmap(memmap_t *map) |
{ |
unsigned int ac = ofw_get_address_cells(ofw_memory); |
unsigned int sc = ofw_get_size_cells(ofw_memory); |
unsigned int ac = ofw_get_address_cells(ofw_memory) / |
(sizeof(uintptr_t) / sizeof(uint32_t)); |
unsigned int sc = ofw_get_size_cells(ofw_memory) / |
(sizeof(uintptr_t) / sizeof(uint32_t)); |
printf("address cells: %d, size cells: %d. ", ac, sc); |
uint32_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)]; |
uintptr_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)]; |
int ret = ofw_get_property(ofw_memory, "reg", buf, sizeof(buf)); |
if (ret <= 0) /* ret is the number of written bytes */ |
return false; |
292,11 → 308,22 |
int pos; |
map->total = 0; |
map->count = 0; |
for (pos = 0; (pos < ret / sizeof(uint32_t)) && |
for (pos = 0; (pos < ret / sizeof(uintptr_t)) && |
(map->count < MEMMAP_MAX_RECORDS); pos += ac + sc) { |
void * start = (void *) ((uintptr_t) buf[pos + ac - 1]); |
void *start = (void *) (buf[pos + ac - 1]); |
unsigned int size = buf[pos + ac + sc - 1]; |
/* |
* This is a hot fix of the issue which occurs on machines |
* where there are holes in the physical memory (such as |
* SunBlade 1500). Should we detect a hole in the physical |
* memory, we will ignore any memory detected behind |
* the hole and pretend the hole does not exist. |
*/ |
if ((map->count > 0) && (map->zones[map->count - 1].start + |
map->zones[map->count - 1].size < start)) |
break; |
if (size > 0) { |
map->zones[map->count].start = start; |
map->zones[map->count].size = size; |
308,13 → 335,13 |
return true; |
} |
int ofw_screen(screen_t *screen) |
{ |
char device_name[BUF_SIZE]; |
uint32_t virtaddr; |
if (ofw_get_property(ofw_aliases, "screen", device_name, sizeof(device_name)) <= 0) |
if (ofw_get_property(ofw_aliases, "screen", device_name, |
sizeof(device_name)) <= 0) |
return false; |
phandle device = ofw_find_device(device_name); |
321,21 → 348,26 |
if (device == -1) |
return false; |
if (ofw_get_property(device, "address", &virtaddr, sizeof(virtaddr)) <= 0) |
if (ofw_get_property(device, "address", &virtaddr, |
sizeof(virtaddr)) <= 0) |
return false; |
screen->addr = (void *) ((uintptr_t) virtaddr); |
if (ofw_get_property(device, "width", &screen->width, sizeof(screen->width)) <= 0) |
if (ofw_get_property(device, "width", &screen->width, |
sizeof(screen->width)) <= 0) |
return false; |
if (ofw_get_property(device, "height", &screen->height, sizeof(screen->height)) <= 0) |
if (ofw_get_property(device, "height", &screen->height, |
sizeof(screen->height)) <= 0) |
return false; |
if (ofw_get_property(device, "depth", &screen->bpp, sizeof(screen->bpp)) <= 0) |
if (ofw_get_property(device, "depth", &screen->bpp, |
sizeof(screen->bpp)) <= 0) |
return false; |
if (ofw_get_property(device, "linebytes", &screen->scanline, sizeof(screen->scanline)) <= 0) |
if (ofw_get_property(device, "linebytes", &screen->scanline, |
sizeof(screen->scanline)) <= 0) |
return false; |
return true; |
/branches/tracing/boot/arch/sparc64/Makefile.inc |
---|
28,6 → 28,14 |
TMP = distroot |
ifeq ($(CONFIG_AOUT_ISOFS_B),n) |
SILO_PACKAGE=silo.patched.tar.gz |
endif |
ifeq ($(CONFIG_AOUT_ISOFS_B),y) |
SILO_PACKAGE=silo.tar.gz |
endif |
build: $(BASE)/image.iso |
ifeq ($(CONFIG_RD_EXTERNAL),y) |
39,7 → 47,7 |
$(BASE)/image.iso: depend arch/$(ARCH)/loader/image.boot |
mkdir -p $(TMP)/boot |
mkdir -p $(TMP)/HelenOS |
cat arch/$(ARCH)/silo/silo.tar.gz | (cd $(TMP)/boot; tar xvfz -) |
cat arch/$(ARCH)/silo/$(SILO_PACKAGE) | (cd $(TMP)/boot; tar xvfz -) |
cp arch/$(ARCH)/silo/README arch/$(ARCH)/silo/COPYING $(TMP)/boot |
cat arch/$(ARCH)/silo/silo.conf | $(SILO_CONF_FILTER) >$(TMP)/boot/silo.conf |
cp arch/$(ARCH)/loader/image.boot $(TMP)/HelenOS/image.boot |
/branches/tracing/boot/arch/sparc64/loader/asm.S |
---|
105,9 → 105,28 |
* 1. Make sure that the code we have moved has drained to main memory. |
* 2. Invalidate I-cache. |
* 3. Flush instruction pipeline. |
*/ |
call icache_flush |
membar #StoreStore |
*/ |
/* |
* US3 processors have a write-invalidate cache, so explicitly |
* invalidating it is not required. Whether to invalidate I-cache |
* or not is decided according to the value of the global |
* "subarchitecture" variable (set in the bootstrap). |
*/ |
set subarchitecture, %g2 |
ldub [%g2], %g2 |
cmp %g2, 3 |
be 1f |
nop |
0: |
call icache_flush |
nop |
1: |
membar #StoreStore |
/* |
* Flush the instruction pipeline. |
*/ |
flush %i7 |
mov %o0, %l1 |
134,7 → 153,6 |
retl |
! SF Erratum #51 |
nop |
.global ofw |
ofw: |
save %sp, -STACK_WINDOW_SAVE_AREA_SIZE, %sp |
/branches/tracing/boot/arch/sparc64/loader/main.c |
---|
39,6 → 39,7 |
#include <string.h> |
bootinfo_t bootinfo; |
component_t components[COMPONENTS]; |
char *release = RELEASE; |
55,6 → 56,15 |
char *timestamp = ""; |
#endif |
/** UltraSPARC subarchitecture - 1 for US, 3 for US3 */ |
uint8_t subarchitecture; |
/** |
* mask of the MID field inside the ICBUS_CONFIG register shifted by |
* MID_SHIFT bits to the right |
*/ |
uint16_t mid_mask; |
/** Print version information. */ |
static void version_print(void) |
{ |
63,6 → 73,39 |
release, revision, timestamp); |
} |
/* the lowest ID (read from the VER register) of some US3 CPU model */ |
#define FIRST_US3_CPU 0x14 |
/* the greatest ID (read from the VER register) of some US3 CPU model */ |
#define LAST_US3_CPU 0x19 |
/* UltraSPARC IIIi processor implementation code */ |
#define US_IIIi_CODE 0x15 |
/** |
* Sets the global variables "subarchitecture" and "mid_mask" to |
* correct values. |
*/ |
static void detect_subarchitecture(void) |
{ |
uint64_t v; |
asm volatile ("rdpr %%ver, %0\n" : "=r" (v)); |
v = (v << 16) >> 48; |
if ((v >= FIRST_US3_CPU) && (v <= LAST_US3_CPU)) { |
subarchitecture = SUBARCH_US3; |
if (v == US_IIIi_CODE) |
mid_mask = (1 << 5) - 1; |
else |
mid_mask = (1 << 10) - 1; |
} else if (v < FIRST_US3_CPU) { |
subarchitecture = SUBARCH_US; |
mid_mask = (1 << 5) - 1; |
} else { |
printf("\nThis CPU is not supported by HelenOS."); |
} |
} |
void bootstrap(void) |
{ |
void *base = (void *) KERNEL_VIRTUAL_ADDRESS; |
72,6 → 115,7 |
version_print(); |
detect_subarchitecture(); |
init_components(components); |
if (!ofw_get_physmem_start(&bootinfo.physmem_start)) { |
83,7 → 127,7 |
printf("Error: unable to get memory map, halting.\n"); |
halt(); |
} |
if (bootinfo.memmap.total == 0) { |
printf("Error: no memory detected, halting.\n"); |
halt(); |
/branches/tracing/boot/arch/sparc64/loader/main.h |
---|
41,6 → 41,9 |
#define BSP_PROCESSOR 1 |
#define AP_PROCESSOR 0 |
#define SUBARCH_US 1 |
#define SUBARCH_US3 3 |
typedef struct { |
void *addr; |
uint32_t size; |
/branches/tracing/boot/arch/sparc64/loader/ofwarch.c |
---|
40,6 → 40,10 |
#include "main.h" |
#include "asm.h" |
/* these tho variables will be set by the detect_subarchitecture function */ |
extern uint8_t subarchitecture; |
extern uint16_t mid_mask; |
void write(const char *str, const int len) |
{ |
int i; |
56,36 → 60,40 |
return flag != -1; |
} |
int ofw_cpu(void) |
/** |
* Starts all CPUs represented by following siblings of the given node, |
* except for the current CPU. |
* |
* @param child The first child of the OFW tree node whose children |
* represent CPUs to be woken up. |
* @param current_mid MID of the current CPU, the current CPU will |
* (of course) not be woken up. |
* @return Number of CPUs which have the same parent node as |
* "child". |
*/ |
static int wake_cpus_in_node(phandle child, uint64_t current_mid) |
{ |
int cpus; |
char type_name[BUF_SIZE]; |
phandle node; |
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 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; |
int cpus; |
for (cpus = 0; node != 0 && node != -1; node = ofw_get_peer_node(node), |
cpus++) { |
if (ofw_get_property(node, "device_type", type_name, |
for (cpus = 0; child != 0 && child != -1; |
child = ofw_get_peer_node(child), cpus++) { |
if (ofw_get_property(child, "device_type", type_name, |
sizeof(type_name)) > 0) { |
if (strcmp(type_name, "cpu") == 0) { |
uint32_t mid; |
if (ofw_get_property(node, "upa-portid", &mid, |
sizeof(mid)) <= 0) |
/* |
* "upa-portid" for US, "portid" for US-III, |
* "cpuid" for US-IV |
*/ |
if (ofw_get_property( |
child, "upa-portid", |
&mid, sizeof(mid)) <= 0 |
&& ofw_get_property(child, "portid", |
&mid, sizeof(mid)) <= 0 |
&& ofw_get_property(child, "cpuid", |
&mid, sizeof(mid)) <= 0) |
continue; |
if (current_mid != mid) { |
93,7 → 101,7 |
* Start secondary processor. |
*/ |
(void) ofw_call("SUNW,start-cpu", 3, 1, |
NULL, node, KERNEL_VIRTUAL_ADDRESS, |
NULL, child, KERNEL_VIRTUAL_ADDRESS, |
bootinfo.physmem_start | |
AP_PROCESSOR); |
} |
104,12 → 112,59 |
return cpus; |
} |
/** |
* Finds out the current CPU's MID and wakes up all AP processors. |
*/ |
int ofw_cpu(void) |
{ |
int cpus; |
phandle node; |
phandle subnode; |
phandle cpus_parent; |
phandle cmp; |
char name[BUF_SIZE]; |
/* get the current CPU MID */ |
uint64_t current_mid; |
asm volatile ("ldxa [%1] %2, %0\n" |
: "=r" (current_mid) |
: "r" (0), "i" (ASI_ICBUS_CONFIG)); |
current_mid >>= ICBUS_CONFIG_MID_SHIFT; |
current_mid &= mid_mask; |
/* wake up CPUs */ |
cpus_parent = ofw_find_device("/ssm@0,0"); |
if (cpus_parent == 0 || cpus_parent == -1) { |
cpus_parent = ofw_find_device("/"); |
} |
node = ofw_get_child_node(cpus_parent); |
cpus = wake_cpus_in_node(node, current_mid); |
while (node != 0 && node != -1) { |
if (ofw_get_property(node, "name", name, |
sizeof(name)) > 0) { |
if (strcmp(name, "cmp") == 0) { |
subnode = ofw_get_child_node(node); |
cpus += wake_cpus_in_node(subnode, |
current_mid); |
} |
} |
node = ofw_get_peer_node(node); |
} |
return cpus; |
} |
/** Get physical memory starting address. |
* |
* @param start Pointer to variable where the physical memory starting |
* address will be stored. |
* @param start Pointer to variable where the physical memory starting |
* address will be stored. |
* |
* @return Non-zero on succes, zero on failure. |
* @return Non-zero on succes, zero on failure. |
*/ |
int ofw_get_physmem_start(uintptr_t *start) |
{ |
/branches/tracing/boot/arch/sparc64/loader/register.h |
---|
33,8 → 33,7 |
#define PSTATE_PRIV_BIT 4 |
#define PSTATE_AM_BIT 8 |
#define ASI_UPA_CONFIG 0x4a |
#define UPA_CONFIG_MID_SHIFT 17 |
#define UPA_CONFIG_MID_MASK 0x1f |
#define ASI_ICBUS_CONFIG 0x4a |
#define ICBUS_CONFIG_MID_SHIFT 17 |
#endif |
/branches/tracing/boot/arch/sparc64/silo/silo.patched.tar.gz |
---|
0,0 → 1,372 |
‹ ;!³H ìZlU~ÿÎìxwì8Éxc;N.Ï?ˆ—œkoçÇq4zÊq)¤=襳NL“6‰-bîZÕ“ÍÚñµ@×fëú"rLœÅX\tgBŽDæ莆=“¿Zq”R©ZB”Z!¹à Îöó™M–ˆ*Ô_iwÞïûþzßï½y{v=p°µƒ¾Ê'Šgc{;¿×nÚ-~sqCtc”Ö®nh߸.Ú¾i=E×®]nýJ¹òŸ‡öÄ‚ºcßïÜ÷p_Ö¿ð,<ÿH¶4Zºž¨úTµ¡7i£•MhTñ³—rvzµ^Q¾CSB·*ëíèR$Œ+ü,…êNõ:ó1C9ÝDµ²IJ\#²Wët*ˆ¶1KØ[t²·*~~55™üÇèæã nR ã9ñ»&®úhÊ FÒèØ…^¼Ý”ÒèkCÐInMjTƒ¶0Ãrð›!º¨Í(By[ê;Š(O§-ÍR„v±I§™&Cy»ÉPßi2ÊAóò¨bh‡~™Sy¼ù·.íÕ\>îÒÒ£)ÝåãÑú1$Ù ¯¹ýß³éD{4j¦-á=<ÞÕüzåò=TU€9ÞÐ |
ä˜iª þ%Üç·)~[©«7ÛI³/•çÀ¯à¾5]ù«\?ô’Ç#ÿ©N™NC²!9“GŒÓ2(&È’ |
°ÇÞÊŒ˜cË´3© |
+)¢xï†<R |
+¸7šô|ä;<22ÏŠåÁ}ËÃMW{¯B_2ø¬\»LuÅŸƒ2à¨ü |
+ž3ŽhWñ^Öïéï&ð'¶zý¯¢Œ¶ |
+s|qÙàm¹UVèÌ\ |
+¼õæ¯þ|XƒÞ)˜É§†J@S¡Ê!…JÙG‡äÞyàíd?÷qîeœ…¹Õخٿ"¦Êö »`ŸšwT³´(N8wÇ8¶å6ö¿¤ïÿCA!%5c3rèÏf©?W‹'ÐÇðÀ÷qJ¶$+”™A.ª*ðË1x4èå=ÆíÈDè«uš3³ŒKJ2”™Åm—xL!®Løq…e8öÖs#o…YvωS¬òu30znÎÕI1ŽEÏ”<Lã%BJÿ(úN†^˜³s§‡³Ûõð˜"ê㪑_Õ¬kÓróÃ]ižüÏaSö â!S²#6Çå„bK#AßÕ¦E°?=œ4¶æY÷áçì¶ç0VI’©2<t¾§‚6|®ÞÈÜ×D«ÝöÂÈ¢:m/̱®¹Ëø]AßG<²½œtã<-L“™~ú_ÁoÚà“WOñÜû:^É}ÎÝ/ÎùóRÁúãõ‰£ˆv´•´#Ž°nâdHë&ÑŽñ5à9žÿ§Þ<xÒ¸øƒÊÓ«m´^ý+”˦WçXÿ*çQ5“ÿ ëÖ|Ê ÊLþpVçÀ 1=ä@¶·«¯Dtµ(6&yÝ‚qµ:IzÊËKÜß-Êc,[ç3n{ƒsSÀ0³X!—$œ¶3³ ™R>”ߟj;óžCÖ æ)ºQ´}€þè€&Zε¹”%ë´}ˆ¶[P¿Œ2æíÌ•„j…àÑlÛ™_ç¾dèÌ,Ó„[¦…å|ÊmàSåvöûiŠÀçuðýò°ÖÄ~¦&üq~èÍÏ¿ö |
+øåöBip㳸å[×ù9ƒãçM;bÉ(/⼂ùx’ípµ5X¹x·Y²¯—®ỎX—™¿¢ü_ÊóÏü"ïKœÿác]Èû;˜Ïé&-âó$ËÌór½ÝˆzsgH5n,¼&þ¥—ïâ„Ð<ÿ›]ßÿ¼x:óô²vÃñ¢Ä·ÑE<ðsÉÐÙǘ7ÐÚlUŠÍhû mçЦ€ÎO–ù`¾ma´ƒocq¢ |
+mÀû«TØÚìÇ |
+wÝ1?öÞÒ?ƒ¿oOöÕPæìK½ ÍÌsJ~:Zþ7ë¬E<¶c×ýÆþµ»ö¬ª³Ý]SlçõwJ«g^¸Ëüçïäx½owZË ƒdµ(wZ„´Ìåmþ‡ÂÖãÒ™ià*į,ÖÖB¼f8‚õB\èrŸ»npón×/~žùaÙwÑ_Xïp|f}|Ôlí¼Ôlm¿Ülí˜k¶î9±ÑP1‡ÖäciÁ_X·þúB9U)¶A†ï±³MbóûÑjCqVê |/²¶ûyÕ¿t–ÀºÕ&³¨»k¤z¡b=´¹çÊ€$ßnžpý8·rœôÚY2Êòr¾é‡ÇA?{›Ø†òJn;KFMv³¡rlö`„„ºÆ|€‡*æ× 9ð¼0Ãk_Ì÷Ø‘Ç^&»*3Ãyœá²Øã Mn™ëŒ/»•(XÒ‰vC:ßisåêLþÞ·0߬›KÃî¶qý<t‡}YÖxÚ±ÝÝoµxû-_>eW&È€œä\q=/eFŠ×Ýà]-ò«ž‚_àaoU§<;zdðÝÆîë{/?¸û„ǯán.ìMÞ1‹ß‰%[¯fEì ·Œµü%K|ígá#³¯ÃGª6¸¶˜?˜ |
+Ÿà}B˜}kõñ´½Ê4Ýø<>î^„¯&¯Å4;úˆk¿è÷c`ÚÇgdBö×n¥¾¼¥¾Ý-*ðËócƒÎàSÂÏÝO1î;ˆy± ¿\Žò/¸<+¦D,UÿQœòyÐMrÜ÷ñœF=UTgÓêWýx 9úñ ¾wý˳օˆ%3ÈsR4—IÖå\£uçF^§ð~é(¯#Ç ¿ |
+:¶ |
+…cäp}Éç8Ê™7n›]ó¦+ÇpøM rŒCŽËºX†û2°oÜ(æí¸{ÄçØ'<~ŸÝâñóY1ãïcŸmõà0þïn°Å-¿À²pqÛxÜ}¯3^»Â¯j¹\v]îzæy”!gø,ú‹ühÏ~äÆôy¶ÇšðìgÁ°¿]BÿDucº‰<>#×ã±{¶Â맚|¸4y½-Åg<Ü<·ìþYÛÌ2è~¦È'…õS‘Ÿü'héôù´°® |
+£¿Àï3×{ùòW©ê˜Ê|ÀÇåÙ`ìóäÀÞ•åðà>OÞaï\ÀNù°Sæ³ bXè¼’çƒÇÔ{9¸:UY5Oþb«æë$4ä¶ÍwñzË_÷ª~žëæ±îy‚à3¨w!›YLƒm$àÅë‡=}º6Â>òö€ó{þþ»¹v"Žç`gçŸòûÁÎØn~·úçå~¡Í¯wtuõtÇzöÎÓ»º;ðûö;¢ÑµÇ m;wuØÍŸÙ:ÞÛÃýì=°{wç÷÷îêôñíÚÓuCöìÞËðîz»öÄÜ:£a¸Î=â½ÿCî¸]±}û~cgÏž.—MÚëvßðJ?xpo“صgï>†èît‡Ówöt?ØÕ½ÏãöZÄö»ù|ïÝ×Õ |
+’â]>'Å¿óµ’åczÝ:Aﮜ |
+ï¡”Á§–‚ß úw€®”Õl‰û.²îq4“çDJ4Ù‹YG6Ø‹yÜ"°5ðþ*d³Nƒ-ƒßò„lËÏ–â@g°C óp¹/’$”|žqð̇üSøÙá(|áQ›ýz~`¥-õµ6á¾~ØÃò÷KÙš?Ú¨‡9>þ:-æ{6ñRâ{1ìÇWú)ÿ t?rV#çæØ |
+aÀ,î^=‡9½ÊZœr^æbD<·n£ÇíYw{ìˆx¥–»æöðä 0÷ùv÷›LâPtýgç՛ׯûÛßþö·¿Ýýí~ßo§Õ”Ò‡~ ùx—ʤ2èIå•3Tb¹ |
+[’OºØVè±ÕлNŒÎ³ê~?ÏZnëe4ñ4Œ?ò»˜‡×°›2g6åÚbN¨£1€óØc-Gx…߆ðm2¼áåƘÀLjnàãDxˆ…»¤2Ÿæ(ŠÛÅõš°¹«¼—YKIÇ$»¦Ø¹H)»¦ |
+é2óüdï=iLŽk |
+ÊX |
+^/Ý |
+½ü=jS´—‰õ@ºÚTš©lèJ |
+Õé.JÜ žÇ¥mö4ßÆüºg7dÙª$}K‹Ð„õAõyƯ¢ññ”-ÃøEºm†ôOÊÿ¼ß8ß6!?åUaýÜŸ¢ú=N4ﮡ};Žov_~¹É¥Ç“;¾“Žw¬Ê˜NëD®»õq¼¨gXºÛØÐîÕäÃFq(ç$ÙV›}æl²3"|÷_rþ:&e´¢ùt¹vƒVÇVÈ dPEw%§µó0ô¤nÏKÕãî¥53ô(ïa}pŒ`b&ß³â{O´Þ%yFºGÊ4ù5Í:™æë@sÃ’<Û°[Èn\À’-²÷`%ÜY‚“ãêqÈÚñä¸Oë ÌÑóËñ©SµIÖ ó 6&öµ |
+àCU)/aOÑÞ§ÁŠ:©ÍsöÄàùáü¶ìZBزGN´e×ùmÙ£1-6nË®%zf†ÂÂ<:<nË®ÕÜÄÑúضeG;<´ðmÙCáOÛ²O¤y¢-;§y |
+[v-F4æ·e„ìÄ„-{4ÒS[v-!é?0nË®%Fç‹P= OÔã ê¤z ·q¶ìÙz^¤-;퇒ͲàÙ…Û²óòæ·e×ès…,Dä·e×hçúH˜"ß3w®-ûfÔ}'Fòù¦+´ð1Ìýd7Ì÷jF«/ê6Bð©ÊÐ:/ùª™Éð«.èˆo">%àQ¾\8»Œ§kÃAÌ)Zñ¸ÎÛh“B<C}5Þì·ÎGën²[¾œ|Õ,î§N:Eù¾6æþ©ï'…ŒÇ¬@ƒcÞ?÷pqõЇTC¥±üñâÂפ}þÇ;¾e•83ϲL¦;°;³%ðNf@cŽç4Ãiîd³ÐWKº0íÏ£œ_’¿žàMƒ=XÁ\wŠÖûRv§‘OÑÇivëMqᯓ‚ÜÜAr¦Ï¥ñ¢Ï+é;°,ÓWó½õð²âèlE~“ó]¢ÓÞd+ßéÓ»H_ÂsÑ´WIç |
+¹Å÷gÀ^ßÃqaÌ6–e*_³,M88_ _Lj›/¦ýÈ·(O1}‹*Ó›Óˆçß<QŠwŠyÎ…ñ³uùå!^pýmÏ×lƒ™×¨Žv]Æý™ùþõÔ–xÞFïDc4î„6x–è$ºÈÖ}[m˜ö™f’|Ý¡ÓøÚUÌËÆúÃ;I_k³ s˜Ï— —J8¡»ç)à#ù¢ ´%“.ƒ|ëÿ¼šKßÈ÷Tœûfþ”ÎlÉõñêñXËs÷ío»qáýÈ›óOäôææð0K?8¬7¬‹1S%Ÿ@Œûž˜ºé¤˜“Ó:ù˜×°ÎLò>å¤yhD?h“–{‡ü}($Þ)L0GñþëîâçW8©©nî¯6Å}ÔÁؘCwýdže˜=ɧƒôîCúA˜ R-‘߇4:0чãEÖ‡´¢ËÈúVt}1>¤|ÌÛwa>¤]ÃK+º.Ƈ²´è‹ñ!ÕÄ›ã,ºß]ô~¼»xÒñ9HøÝdç„<>¤Zý¸iÈø´©–÷!Õtÿ^ÐSøF÷ñ0÷!î§0ͱˆ‡Z.|Hµú¯#^ø&Wû&÷Žûjõ#îä^Pwæñ0ááqztïë¤t©+\…ø£:êtNRA¯ð!žèCŠ¹qüÉ}H£)ö#ü |
+Òh_?óør<Ãã>¤üýÀÔ>¤ìщ>¤ZBøFü>¤Zý¹}HCmŸö!%]=ԕ߇tJÙÈãCš•È†9îCªÕ“ÜŽº*ÚÆ}HC«P·ì¶DxÚmk~ÒŠ,Í#9áÏïCJëòI |
+Å…)ßç²f]¸©V?ƒ¯!ȇ”ä’|HCñ‰zF®oÝ>Jß:×—ßps?¾ç€wà³ùñ«¬|~|Ù²žDYÎWÖÔ~|¼ïH?¾OÉLß¹ýø¸ì8@Ã}Ôãǧ%âR'ÎïÇ—¥+§Çzî=#æǧm~|áêq?¾põõø’üø´ÍÔŸülò㋾5îǧע–mŸÏO«çüÄ-ø9Ùï¬z.?¾]Ð HF¨Ùº†™Lbm²ù™ÓÁß¼WõRÚnƒ¯OŸ@9O]&[ı^§®ìÚl"Þ󄒦ﮧ®+»œü;·ç‰9iù|ô€ÊGýô|âé´â6Ù}ÞJ&„-Fï;æ[”V@x(tQ:Kh§p!K¡¼3éL®žíi5-T†:˜9Û»™Ïs½àÒË\Wq\¨Â—æ„}9á;ŒòV ¼¢1¾áB |
+O‚ù6â}¦a¯„™ |
+çµ€ñHøZ„òà\Œx§„¹Š×9vÁ4W$°•yu„ÏäÁ_ŠøÓæR„ÿï<4_˜O$¼áóà,@üÿHÂÿÝ»[§öIÿ±Žs ݼR¾|›zöLD~ŽJ;ó&îçNÅCLû£LþQ&ÿ2Im&åKË•I×.l‹/ôLÉ‹=Ë'pž³± ÷^²=–ºàǶ.¸€sÜ0'{É®Nž«èíqÚ¹à»ÜæÇMë··IågÚv>Ò^8cÃoŸ&úÝÛ—„ƒÔo³ç.òsáÈF×ðÒ(ñmÂù‰SœÕH{}òìGõÑOó’ŸÑHgury†#p|<¬¦¼“ùúyÏ’”ópY·8”g3ãëxâ·˜@7ÙY?¦s\x!ŽxªRXÆ9çâv>ñs>bÏëàûÄÉ„Ø;¡ýf)‹¡7ò³¨4²‘ÚKû˜:›µ‹ô ‹©{£|_Óÿ\€šýÁú0ÎÞ[ËJ>{ç8li°Ð±4èV†àAËݤk™»Y²AçÎït³Ÿù1®ú{†ïÀåÌ?p3ÖÚ·S?-Ó|”Æí-(îC,XJ߀ÜXOLäíY&ÞÿŒ¾o™»ÅÞR‚ÛÙsö‘n£ÀTŠ£öáå[)^~bÈÔ¶è)ÿ#åÌ–/Ò|”FåótºS)gnù‰˜È›Xbœ_bÝ6&Ñ/Í~“xèš9A\Õ+^\‘A¼Jë%Ú—4ûŸfqƒï…« MW§1´é8Œ< |
+-vrãj½i}dm£ÞÙÚª7·¶¬Õ¿¦olÝмºe^§¾¦©SojélÕW7vt6µD:ŒçFVëkhjÓ‘µ©AoÙ°>ÚØÞÁX/Ói%.@æû"ÍM«uûˆ™[ZÚ6 e‡ÞØÒÐ~[g£8v†Ý¾¡¹³Io‹´Symtrø øu‘Ž,¦5Í‘µ(‡èonìlÔ››P$JìlolÌ_ÝÔÑiih ògcÉ©ýšÖöõ‘N½ |
+——W!.…ì©…l›Åæ°Eìza³Tåa‡âT\Š[Q¿P‚Š®T+†¦îäf“Š¼òrÊË%¯y¡ª¸DÉnNŸ—SVÈŠ@Ãtv)›ÍÊY»’]Í®e7²»ÝÁ6³ÝìeöŽâ¥yy‰Nä/ô2¶‰e”Œ3ãÉeÊ3ük¬8Q +~`e¬X棳¨<2?Õäƒhòáváö3~´¨Á2÷%LEÙZŠx—Ìç‘85‰Ã/Ëœ‰ûRÜ¥<Ï•ôïp8ñsÉ_Á¤Ÿû<?ÏEþÔ¯ø§´€OAÜ%ò‚Wm®6Gø?I.ü`FœŸÃb6dK™Î*1ŽûYû>þW!þ6¶1*«¬ÎqøyžV˜ [ÎËþ…ë'2¤ò+Àñ¯@‰AÀ.ÅU,µìA`71-u3ÁU¢Ðô¬b+Y5¨£\:/We#Óû%Ö ³X™¤DÔ)È)²ø§Òª9¤‹×¶4ø9%xïÅ{ç&Ž,E¨yK8¨K-ÞUÜ.ŽÑâ)+Ù ¥LÒHWè |
+³œ“Ëñ^Æa]œ+~YªÎÿK@‘‹óCPZ†Øj¤ÕðP§¡Œµ!\ƒÐÀ—&ú'®V¢dáÖÔ•Ìåqb ûæ½™Lé6XÐÌXùãâè7‡ó·g |
+¡úr> /[Ø.ºô>ùÍ‘“Ë^¯2U Y¥òaH>P Ä/IøeìêUÔ=9eýq@ØÁô½JcÄ0å+þ¹P摆üõf%S"?Dòï³<ÌPáņêxánÌÿ±'Äl¼¬¯dnnÊhF‹ô[Lü0¦³Å‘M9¿dº |
+(|÷M^p Ÿ1½—]ì#í@FùÇ™X@Æ®‚↿¬V–b½o3)þcQîxÊ9ù«FûŒ?©Ä–——SÍ D—-èž-Ÿg}?¯pV÷Aý.4ª>©p• Nï=!k"_Í5ÁÓÏž_Btì¿O$ìêœOÞR\.´ |
+úJÁ¥ŽÆ2ÖûËq¢A²«í›Fa`Àüa•.ä¨éÕ®‹*Pë¡ÙÁ¨?”m–È#ŒpÁÂ/†ô—¬cîpôµó÷…Ï@ùËFiòú#†éõÎyÕ_è(—œXÚ‹×o(†Õ«Š%Õsè;CùØ°{nsö´ ´¬É[\r+í1Òð~w¤ÌtRFT|½yT2.¸~~+ãA§Kx½Q#ËÂÕ=ý«8ÏRï˜+VúÔUXӻĔŸ¨hBŒ&ˆdÝÿf19qzïÓRÚ |
+àõãò&‹;Ì4-í–3PsÝì»zQ¼J`([$OJIO:âìº/©X®ÑEYõâ=p_1µ?¶J½#h«ÉBÀQÿ¢5?;~{B™5:dAµsïñxoŒÓŽ ©øÖ„n>ý«ýjh'¾ 㔟¯zq̃ô“_njxýÓy¡§W&à@y‡ñ^¬õ±òŽøÆÿ\YxVx?ÿH^õÈÓ¤–´uÍ’VudI¸¶\Nw‹÷6œY¯û¿r¬±ÈÂ"ÈÝ>Ó†-x^ðÍUÿàÑ°WrœÂVÞó ÂÒ¥NAðóK}êÌŸ/{/l¾åxCô[~$Ȇu_;©¸¦Ø´ÐW±À ›,åNh!MíÅvV;ž`Èã0ŠšEÜaéLÂ?6!# ¦¨âRnĸëwÏ»`QñHÃo(–ËPc§>ÌþPWuíªÊÚ¿“ù-é«>ó¸ |
+VDl¸¬¥ò'|Ô>åçÜ{¸~jÄϪÌb0H68ùé³ý$+´K%s§£Œ4~8ûÀ|ûRlõâÅ‘é;ð‹oëR! ªfŠûy£ÖnC¶BDqdÙ+‹"Fê ¯Ü,o^ÄÕOlñzàea£ÔA`tßv@¾7ƒµ|‡Ì$z÷™jÛ\h·LKÁUž»j&Ìîì̤žæâÆǨK$üy^Cеüû¢¡þŽ1ùQòNŽîÒËüŸa‰N˜*òUÎSRì¢S¤÷•Vi0U“œé q€Ú˜(fÌÚMrÉÁ~à÷ |
+²YíV£þú·ŽÛ4Ï-Ìœ ÞRóìÍEŠã¤ób[¿'-N”ZùžxÇ•sF&²l²Å%‰ÇwÜ6Y””‘LßiqÈØx¸m-foËkosÿÜb²uâ¼Î%¥»1?;· 2Ç1^£5Þ#sbY+“r}O²Õ=Ÿ5†Û -¸ž·é´Ã5Î<€÷€¬dMè-µÃ3°4´hXR‚<{×D¨ ü÷Ƚâ |
+ÍsÄ |
+âÛoñþìËF´Ç:€%2®Âr›&'|G$”&HGY†¾¾Y®¨»ñ²˜C—‰~ûbZ¿ç>goåïõýü•£¼NûÌrd¨jiÑúéþS¤ë¯ùg÷vŸ9tÛ«ž½þÒçY—D¼òÒ=ᣞ®ä[mdù§n%³?Ä}Aoqu~šã.ò³ A‡¯‰‡…Ï6ÄÞçT=çõìè |
+šò!.Íç:ld~ÄÓ†Ä?ê<~wv¬J~ò‰mÂ+ï1ÚË´Â>óÌ»÷ª§^‹þz+â˵=‹`5¿ÍÄ`Â}V»ØîKÓ¹qqEP¥‡Ð |
+U©ã]TÒq¹{ö»ûH»3G |
+þÁ‡LîbõêÁ0ªj ¥è þ~ÑÙžáÇonfZÍÝM-Œˆ)ŠŒWÃÁü DWÌ7gDgÙhÐ[ýÿ%¿ëDïI~¾.–»ÇÊq9DeÛŽÓÈ"dÉ2= |
+M;ÇVenª@•Ç:Õ3j×f]pÿ <'*¬¢ÛѦ×t®/\ÆFßêHt®‹ÇZNÂéÑÑú¶þtrª~[ݸº°Œ#|b^Jå©o_¡VQRõ §×ßk>k$ñ¤«‰¾à»^yÚ¿®&®Î]O‚©°Ç1ˆ6€ØIåëÖ¤Æ_£Ÿã*Ÿ9Äî“u>wd¬w7*Ûé~ð€÷ëò×/ªOuŒ`!Òœ¥8¶sAzîí„ M“fv›43wÎ)æ²2ÿ2O¿ã£J¨.R÷³^®æÃ~œoqáÈ‚^]A!îqßfD<Å„}Ýߘ¼Êcc÷Ï>‹i$ü²ó)IqM”²“Yª¶ |
+ÉÔ<9xÍݤÉw |
+njq›Oí¡Þ [7K5v[ðBí8÷øçÞ®j#§Öþ÷ü?ÌŠ_±ÐÀ;ÛÝmí%•~û?Þ#QoˆÀfŒþZ¬ìTÂñËÂçο¿ŽÄ$)´ð¡#u> ßäºð ²]¶Õ¡cW_cÆN*}fª} =Ù…ñaµÈóh*æ1órýS¹?A;ŸEzª.ÃÞ®kW2r½9†%žzbþ{oÂ6]m*¡˜ã–è³>ÕT@Û¿g–†/0và€e^ú]¸/·ˆz°àßÃ{n‘GŒ(=mèPƇ¥¸¿Ó–€©'çbåÙŒ”4ø->‚M¤=œú˜º˜º¬e>ÒÖ\J½ŸÊÄTyšg6·åŸ¿y¬‚cä1C‹WÌ1³y²C]âiÞ¥ÃþÝß•J”A|_ÀÌêÁ1Z®ËêQöÜûâ{z¾±ÖûQì2˜û# ™â#v¨²õè³A |
+¸aö„†É³'nÚ ¶ßp!žÂ«C3²¨¿Ç.4LçÊ€SVrD/´>–ÎB›Î¿®žÚë‡,[9Ú+ÙBv uÐg@0MUÇ<”µ>_Jû ª*ˆAV÷‰m÷¿å¤Xm3ÁxœëšÙÿRxd |
+ IÓëšpšÊäw4úÇñ<œšªËeK‘Ç—–õʼ½»ŒÍ9–6¹“=gæ'ÒsiŒg¿ÎüRl1 |
+ŸÐY/Óï‚ÿË‹2hg5Ï•þ¦DávómLT…<N&‰À3‚ê£äÔî·Vƒ©½”ÆS-»\{V'û0;õëj’UÜ #:Áç>‹›]Â+’º’×ݺãEìèíº[ðU£÷Îè?Îó dø寀âŸçù±ó³=eöÅ¿X’¸ƒ¼}½Û‡£Š@êd“E‡&.ÓÂ Ó z‘@)3ì÷Ôêžt:þdŠçá;ìõÙ«Æ×u×cŽ?«M—Vuø:‰Ø+:M£0~ãÅa&u·ñ³÷×bòiIb#œiØS¸¹qáµ½•y›þÿÚ"C¿™½T´Z+^<K÷1‡o÷rbn¸Kþð0ŠÜ/Ž…6O4R$¿U+Ï4bçSJ"§ÝÐ×Ñ/¨GÖroî |
+Fœ4FËâ,lq! –7E‡5¹*<sV |
+ï ¹BÑB’˜fK‘™l‘º²˜ônâÆs÷ºÔ;rãˆÅÇU±¹d[–ÚVöp¬*LoF+®°-ææÿ_sC+2Z`:ð™ìýÕ\Èx{À®~ ¯ÀøK¤ã—tó™†X¬Q`°1öÏ·M;ÓHKÔ”ÅÚRºÏL:àUƒ±˜À§"à×æùµ4€ÃÒFº 7¬$xÆ~ÇF²rïýçrì¦>bsž^è;gX´ ¢Ñ7íSá‚„veí7°¿ó |
+£eà¯8Qº—¿Éš¼Vå4qG„’‡9÷fœîÜ›ãFÁO›½^sÈ_3É*ªOrYpù"é<$Ï$ÕjìÊ¿W±È`ùG¨ÿJWß¿ŠÚ·Âº¯ tv<Qwbj‹½˜pÓÛAê×Hâ•”ÍDçÔŠ4:Ÿ5E8@I¦LRÀ½¤Í |
+·–ºÊUQaˆÍðÆ‚DUqíòï·Õl;Y^):CqFb°ò=™åÐa…ÔãJý2³àWQÜ·Ú{}œßçßðã7¿ô |
+I ÀÚð“ÓÒ73Õo§êLDªMç|¶î`ŸÂdÍ7X½=:9ö4˜·ðVx,׈çÄ¥}*Àòƒ²Þ6—Ä{ü߬¢bES…°t ,l繶ͦ&óâÔvËûLQíS™ÕˆW¦ñIÚ‰YÓ¹Y8é·=Oö·5xµ¬sïy |
+8l'Êì(‚Ž/6Ñß`ÿ’‡ßƒÎöÿó}-[íæÞäY?¹Íë×½M½Ô1\»$cô÷§·ùJÊ·Þà…w‰ ÿžÐÓgÐÕ[ÔæœÍyÌ´íGŸÓÐì9P-è½MÀA0Ç£¼E#þöÑ{rXuŠ {/ökæ«ŸI_¹P{ëcĹ.¾”{=(4œoÌówÚ¡ýbäŽ=¯A=óåM|38zd¬~%kЕ*Ìþ@±<“»/Y!á”ó‘aî¼ ¼"ðÁNUéÐÎü¼C“T†ZƒIîfï;ÿèœ=\Ôqž£Ì®m…–eødeцŸ¶ÜoO‰0CÕRW$óºñt7›/Q‹»l)O}øôìß»,«'A!¸ ûÿ¢.Ŷóµ~´6U¾8¤Ó.ÚªY^ ÙKØ›J 0=œ¡¥a2â%·»lè–^ÎÜË’ÜQÚ"U>À÷öPû…º°Å |
+Š¦eŠw0ÏîŒ ë`üºx^-.ßW%_Qi™iÚ8[|JÂÎý:Ÿ±†¦)½¡xd²#Áž |
+o#!6×>2°Ï7Óÿ¨$ƒÚ¬|ÙøG“ðŸ*À-â\ê'/ÃǪP×67íüß’;OA‰M£‘ÿ¨üå”Ù{>²ºü–6±ûaëS;ò¥‹%‘Ù>ñ¤DÇ+9¦mY;ÎÈÔmÿ×d`ÉÞçÊqå¥P‡z‡C}Ò°;>çðùÄ 17Ëé÷Œ. &.{€íÌ•¨5°á |
+ÝÒÀè?˜¢ç?WUG4Kû¾ÅçÈ…Iõç™…6>ß,f¼w)%bàòȬªâ™=¯èÚ¸ô…Ú=F[‘ëKø¬øª¸ñՉؤj€VÉî‚ÅwÆc¢½ù6Ôçwà¾äÞ‹m9׶½UÅר/"Ìù"˜IèWÈÿ¦€¥þëV*ë”ïS½Dv—þm3ÍQ¸|Þ·° |
+%õ«+J36_KºÕŒmïÔÄ;<W£ÿ u_y}ÛR^»MÙààÔsg|]êøn¦ ëu…‚åø âýƨ‹#Côð{“e_às$?[]ƒ¾Id„èËú_Öij³\H¡°hÊÈ+“4°Î³0ÌbÌü-Ó}Ö÷áªÃ4ñ9‹¼3ƒëUÃÅ“RDò6àŸÞ× ¼8÷m5/ëDcÑnLîà((2µuYÀ´m·dÞ&á™Oý²erŸbÖ/õâŠÜXüðÜÿÅméâ‡tRzRôb&ð9h„·òͲ†1ôÙB„ïá³3¿K©ÑN“äÀWl=¢=ï¶v¾‰»SÇÌmý{׆K Ì•_‰C9¥´×¯µZHžæÞâ<¦ª |
+S$¥ç{‘MfYO¡ß³Íæ³_HäùÜ£ñ÷ëg[¼ÿÅòšãâÎÉÜïï? |
+¶<OûØÙû1I›û‚&Cýí`ùPˆ<À™¯M•±0ªÛš¤R°]V©âo¯÷ŒØO>cFN |
+¿º£+µ |
+c¨Y×fênð8wW |
+<—úz“ÁĜ봱²ÏA½ëìLÒ]ÿ>7Žòllºµ·òí÷I>öR½qãF«ö‚·Å J‘ªèËV°Óˆ7‰¾ùr·§FåfvM%E6÷è0ðà-ÒΥݗ¿–l>`7´ÞÇgÊpC'ZcREOÞ£ÞÙàÅpE|š®ÝmÞÃÌT’ÛÊ©è |
+~¯™ßN«Þ`1qšÀú§j0`¿õÚFÛŸx¤©–r‡¥†¡ü©™ÎÇbƒÏÙ‚[L•¤c-yÅÛub |
+êÚ“÷ |
+óe™úî´“Óž4¾)ž[1ˆÖ±ðî…Úmï£à¤Ëúe–Ç·#DC£y9”@]÷pcÇ’. RL+eÓ~mÝ“½ÛÝuÚ6ËÉŠX(Èbæû›»£øÝ" |
+C8²tæîJq ¯O™y^W(,Aúp@D^¿=÷ó‰²S‘ªÔ’Û‰Oùmy.²hI»§ð~|$ì$8격ÛQê@tÕâ-×4¼µM†×ìʼ³#×Ëöè€Ëv9Jò$¶ÖŒ´å}>eögHÅÀÊè+yS½/Ñ™§W —삸ýÏþSÆ9†ƒ …@]´€Û"B¶îXw;ºÕFµ„û tran!õÃ}yÍWxco8”¥Ï÷¤!ð‹Î[ü]N jŒàI‘ßQÚ–c:m19_îåöÚ¾¶`TL2˜ä¹Y倫ÅTêðÿ£ÞEþ´‚ÞÉ0å2E<™–JZÿÊ}4î«Ï_â:78\Ý÷7®îéæ |
+%Bs™FfRVEX’®Lë´ïµõzð |
+½µdËOÒ(Ö!℈ÞÞ(˜ãþÇÅ=öêÇÅãP‘aïÕd°ÒgF’ðÐ!JèŸÂIî{I8jt}nÂt 3ï ³`bn–I˜*òŒËÅý.5•¹Ý&µ´¬›wºúدOm€/õ¿‰¯¦v”…Ê¿ÃI5Üà[À\ÈÇzCÏãÄs+QÛ¼eÔÜÎ^¤7po¬?øÌ’}éü4©§•R«ù”dzÀJ‰Ä~•x ÖrånÌÿ}Ø„àlK›qÑ]b×”æ°äžïTÛñµ›½ \Ã@s€=–D°ÒÁHž×Y©16–õaè¸ñÖfÌ«®&ér»‡w–=5ÇFË-¡ t“tËÁÞÆPKV_õœ5ñbljŽ´›lHÁH$AÚ°©“"÷ùøÃ,‰œfÆ×>nèý¯3¾M´Žo×UÔýåÙ½Bý ‘pd:JÜÎ}w¢+F,6„ö÷~&µ”Íï<4Kÿ’{âò>Ï`G¥ú#,ÏX-ѳdï6ÑÃg§UàzBBV¯³uÛГ=×8M„øFö¶î§…=3KÍ)Ì‹×Õ{ |
+NÇ¡\Îû&Œì<¼´`®qrõí€5¬‹•%§LŽ‡¾ÈqêÁºž9Ø𑺼ôù ÖEkA»éH‰~úLv˜µ¨%•`×—–Ù,á=Ÿ{b–ŽjŒ j^<¹ˆéȾ‡~^—KÙK×YŸ Ú} ÊõÛz‹ô`8HÁ‡q÷§Z`K{9ÔGøøK0Ú“A•<ŠÍÂÞС¦ê™à¼:mœ`yÌ™åJóˆë=îU§]*2àäÑ!Q€'¥nó5Ó;Ó}F-‡µo”£¸=Ó-þ¹ëÁ/oLÖØn‹á[çHeO†k€øp/ÝþyÝ‘¸>.`û¶ý¶§Lò¼º¥X2ÉîXß'ÓÐÉ$¯ð ˆn:pt~fÊŬúz}bßú²#ulÈiüì4Þ‰z/ƒõÝDÉ -"²åàù×pèÙ£+úwQÈÍÏÄ©qnüºwý?õJRJÆÃAéŒçy‡PNóܽ_²¥)}{Tj÷dPmä–!J«Bô÷†ÌOÿ+[¥`‰mkfÐÎÑB>"±«ýðà¾kŒÃ“ sEn½<õˆÌ |
+ºÍ¹×ÚuŠyŠN°ëºÕ¦Md2Î,/ïȶ¹?{^mfJä®wŸ¸æú(±L# |
+ö—·Åà:JÅwº¨Bø×›/5Æ©EÄŠÊ4[5i…b¾Î¡Æ1u( |
+‘DZìiJ–{)“‚Û†H |
+ÄDÒ7bO¨¤d9GÀ3÷eÃd+J®ßeºŸx%ïý¾BA§£‚Éý½=ߛʴG©„±}£ä S{žÿw<—ºO÷}~í\?îöèT±ÙhˆÀ‰<nîEŽ$ èè¸#8 t´K§nÿãsät¦Í Š3¹À1U‰Kä*x…Xjè$´Lß›€é|‡ó\G˜QBC[á´\‡u¼2\oõ-Ôý°[ˢà J.¸0ïkÖço;âÿs¹ÁÛÌe_ª³"¹êŠ_äû?ÇŒ,ˆåOš²ñÙê© ,ë=Aù9É»Zâ··žþ}x q‚:o§Ï7Ù4ó% ²Å½§y:$ o뛉*U•Çšm´ áÏÚ[dùÆ[~®Øú¤øq[úf±a)/7Ôa]h—yˆ,ñ¾(ÙgZoj×!·¡ÇR^ÖK«#«¯ÇÏ),ãËGyáþëNÍþº3°Ž€˜Û…ßIvc™©ïØ©¢}uÚXL2×Gy….–f~NùÛŵm½ü¹:/ê†c,é׿¹‡}YŠ×a¾šl!Üáy€½U½ÙR7î Âìmžq@(½V0ñ1½_=”m–W#še«l2pOw„D‚Êëoì¤1j–TbŸrÇ,BÞ†Ûpëœ×\K"^V/ØOr4ÚE7‰<2=™¿¦q yýªûX ö¯ö4‰˜Ó:¦º(i¹<ë€Òù÷¿dBzÖö(öÜ°Úý•‘<õÔýn’Æu’ѼÔpfS |
+hÜÙ5·¿H¼+-ÉFkÄgºb£>ÇËÊ3Ôhzz\ÓÞŽrÑΤüª°qñE)ŸØ5Þí¬¹ñBÆÄîrXÂÐÎ6fTÄç×qPwò;¿xïy‘÷ w{K=¡ÙnVô¿=„þ64N1Gk´ð¬ÈN±kŸ?Gô~\̸<¢±·Ó°à•%ö²Fkô\õ‚Èl¸õˆ÷¨Í)^/LÑõü™Måè¡-þ“2†…žî |
+¼!ãÓÇÙL x6#o_ý]Ú€I’†¸âz•kgVbØŠòþ¯Ã_YEÊn•à\¸×?!2ˆ¸'ùùAý=‰z |
+`Ë/ï´Ø™9ÖÞq…Ƕ·f="» |
+âÄ}05+¨'ÿEA7Â\èÔˆ‘-Fp7rºz«ù®š4„hJóbõARØó?§‚#%HR—±Ôà{hIÛ^À!‚ÚY©'¼³ú@†½Sƒ¬u¿-ùÈSË&§âV¢|¦®I¬¾3_“È×´Ë™½q57 |
+±I…]*o˜ |
+qg7Õ2?å>ßÖxóGÝ{Ñ4pG¶¼Ë»’G]³Ý'óBº¢»ÝŒÀ¤]TÁ¯md`rx7èo•ƒÄ›üœ#à ´ä-;£[»|sظqDzâýºiW#m.£ùMçréx7ùrœE€BLj’òA(.袉/'DºêWíœï±`ñ»µíƒ;ðÝ—•%'¿Nêò?‘‹ù´õÊ3¢«3Z,ÜfZ=r_cµ¡Rô%¨e8ͳO¸õü&º&ê÷ÿg.œ‹ñcÉÞø{K…(í©Úõ \pÙbÿ¿-Þ¤‚Ýæ÷¡â½@ÌßlBn'x#ôºáÙðF¨o]Éî0Y6$(žƒ´À?Ùñ"彞÷XƒË¹C‡å¬!®©B‹«z°¶®½hûøKk÷®‘´»‰äs+ç³K•ž²Ü¤Ü´òaŽ4°ÀÔ¯˜T#;0Oð¤(©XèàZ'«{º¿rÁ¾[â\ì§YM©FXÒ®µ›iBwv¼mò3ì |
+ZÖiÒûògPZ³îQ›,â»ût–Ñ¥¾¤»úP¯§úÎŒÒÃ¥Ç觬W¢®¿]"Š^3~U.¾0,ªÒž6øº&ÊÝdýè½ùsS ÌCíuYï“/(Y¾5©/£o<ã1#;C*<½ |
+7s–]G^q6fs«“ Î|(Ùß |
+òpÍ‘a Dƒ3ÑbØ˘×ä‘#®R¶ò“Çà˜âõT>º·nHª]OÞ•FÍY¢XéÎ÷˜[.pŠÊÏÎÒ×>×2m:ðŸ"!Håã«–sß-Ñ6Jxž_«¤–IÈ~Ë倶¶ òéŒÖÔ[GoWsëkVWßgú·iTØÅía1qùü¢¶]þ›´^îÅ{o;{õK~lÍZUò:ûî±|½ÖáÃuØŽÂÖ°~(Êíað(öz›Ílã‡áÀX®MâNDìRzã[þÝÇ8e,eb°„ñ/ØL×^…z¤øÜÁwHÌ4h1Æ0Á¿$°Íƒ2î–>¶³Yz⓾¢Î¾|&Ùii_•t¯mé¯]7t‡†aÛjFæ'WÎ7/ySŽ|oëÁ¾¿ •l¾úã¢+‹>dë=5.SwøÇ$Çþ2øéú·HLT·Ÿø z¦Á^ýØ4°œÄॽÃZ¿ówo,ÂGÐYE'8§ÜsIãÔ«¢0¥å’½?ö?l¿¹·˜ŽÄZö˜Ó<T0XiãµÓ]ïdB2Ö4LÉ2§ü…Bû‰Òdí§X´Ë;ï.»ä•(»ì¢>ŠÄÿ^nE+ ´àoN>&o×ÖW¿.Θ²!ÈwÔ¨&ˆYN˜zk3¬ïÂ;fÎ'>_£ÎUÏ$Ô@]e;üã¬\ŽÜƒžÔŽÿ8;%õty¸í`‘ |
+j}]ú™ýÍÌ‘Jû;~ù~ç.ëú„räQ]¹¡è0{ú’刼V1VmI |
+†js^?0¯Ç¾ |
+/¥Œ¬!®p‚¤íÎB]ö«ëpÓ½½Yœ’Ó±Ñ?§;N3:›ì»uÌ ÇÊ>¦æBú`K°ÄÑÔ„±Î8uˆÀ÷ÛÈSã¨mÅΤ(9\¶LFšÛqöæ¨Ií'(/£Æ”"{5£CtÉÜ<o¤¾ÏÔ |
+ÚUÄfóƒÂûQ®‹¿ín¶ÝgŸºÕ¾o7_ßã‹ÈEA ë<‘6S÷`I :D–ŸÀ†ŠiyôŽäž‹; ƒÙÔæB¾ÙŸ¹~PõŠç¾@& Å)ù¡’_[¡.Ë7vÙ3Xå˜å:ØÒ”À~ÛÓtµ,ÏÑ‘3'í çOϘõñºÇV_ÒʲíñŽg"·-üùäì}å*ã2wìxzúåY&RúÓ\þÌjŠE.÷'çÈ\ |
+yóI¤dTç—£XuídqT4Î3¾r)O¥p N_go¢ÉÚ²ö”\´Ë®g{ÞªLýÎÏ”ÿÚ¼líÜ(Ùx"5ò ¸pîÝúéì?¬S´2ëþ™ˆ¢‡“‰6wNË{5.ŽÆ«+òÓÏ<îq4Íò Ä%ð@ì‹Ø}*GÕ8à¡žÊb¾ó¶9_ÏÖügÒÆIà“ÊÚmÑv˜‚Ttü†#oRú¡“hIò?Ò‚GÑS9µì£ÜJSÕ!‚åe•pSð©M_”‚éÃä·Ã/&ÒÎÏÆoWêBsȧ¿x¸©V´‰!ÞyZã¡k_â7*{ÕÌéPÈ£AOÙv´(—òÂS&›¶Î®œ•`ÈÐØvŒ.önH{ç¹lñú$dzAV?·iW7Ÿ÷=$–¶RO_%«)R–j'fqè.ÿmbvŸ¢üF™"níI\Αo+ØB/â/¿ |
+€7b‚¸^zZAÙYk:6|J¸œãÍ%9¦\¦^– n”ú‰âòè(n%mùplˆåRžZŸ^Ôž qäõ6Úh‚>¦k‘§ÎàVÑsãH¼æX§ñûã4ã²Ôk¹ñ§°%5êà¡%C©¯õ |
+ý™ì ©xVÑË_ÑvÚ:%ʧË[nö·"‡5ŠLV½‚e³òçï;Ónk#¸”*½®ÎYˆµ1;©’?þQuãmÖpAঔœVÀ½’4œã;NG“+Jã·Ä%¡˜Ó)Çðæ¡g²€1 …ygænµxrÌO4xºý ñß I¦úþz9¿¢,Zªzõbѹq}^]qt]‡xG1—·6%j¢9Á¡»&SZPÍüI•kTñâÝñ"e»êËl vùOÜLDëزøºc5Vfô §Ý¡³ãkP…|Ñ0´~ Õõ¹³p»~±¬kø}ÑáõÓož«WòrÓ2.úð¬lP¨Iô3éEµ·ùñ;Sb>Ñ/&z]óÅ”ø¿¶šd˜…;-Õù†úV” Iÿ' l†¾%£{þ†ëšó|-Œëú½§ |
+Môxé®lîC·u‰éßyªZõ<Ù䓽ֵ?Eê;ŒÊœÌÌhßL,Õ†±)‘i=:Úä¾y¥5k{Ýß›ÄD¦öãú¯y {Š¨àXàÙs—…ßá |
+¢Bw~Ó¶3þØ<QÒ(Ô»^gÈñJ ödGIÓ*F\¯t.öeDß!xÊ^]ÏʾSTÀþÌS7mÊÂ: ˜öQ· |
+…µGÎ~wNÞkÞˆ¦GùúÚ)f;hOßRÔ{[øo•ç¢jÎŽ²"v Vœ8/1IÔUÃf;Ýíš©2Ìî~˜ìú;ÖþÝe¿Ûì0*ÁB¯àIí—,òH½‘e¢tóìf}à'oÐ,²²CQO*:׊\̲œˆËRÑuJ…–µrtøå¬2ìf²Ø ¤/XZ’^ÎUnšlúp·=šdÿ”/ܶÔxÇ»ØËr°$ÁèÑ.ÙxÝ£GT¯×1³õKuÏ›k£Q=|¬Ýìÿ13Ü |
+~e-ô6˜-][‹WHq£^xûö!Hµð¯Ïß³ Þ€œU#?N¢Vˆí/sXæ§ÜyŸ¦ìbeñt ÚKw°ŽïÿF®4ÊÖËétaÛÄÌ*_Bôª“XÓƯ÷pÚx |
+’¶¾pœ.Þ… |
+Óî±|Kºœìc<L=Åæ¨}éý#~ÉvR4¨ºÞ}®:™›[‡Â)ævÄ\/ÌDf§ƒ’i>~¿X9ôg£5ÿ†Û}µ&5×”:‰D1KjÞ¶â×Ø(òWX\ ®ŽWÃQémEBÞH°¹…Ï3{¾®Ø©¼Æd“o:à¸6øyFø$©iZlÎd‹g¶e¤lº)UL@.âÚªÅ{À±ÜÚ|+ |
+À÷¨SñÄ—zkÎS êV³ ÎÖô~¨†Ñ%zêÎ@+1ð à ê指–Æ¢c>ë^¢[¶B2 l¼}f³Ñþ‹" d,+â3s<ŽQøâìçÛCC§–ü§ý!hè;Q~!hº†Z…S,ˆÑÓãjˆ3Y;nK~°–Wp´4?ÞZtTY.Sxy•k·øDGËßr·µT¡ÿð@ägÍ<ÈTÍí´L”À¼ÁšGÝ·]C"Ú”³rªâÿÄuÔ9®Â{äv°) |
+ˆÊô×@ÏW†1,Ó:,›£‘Ö¼–:1¯øOŒ”`ÝÚeÚ½g |
+ôqsð³w'¬\YÙ,|÷<óc¨êüÊVýiuëÊý¡µ |
+}ö´àÅÛ‚Í¥]4Ÿ!±Ü‹EÜ‹:h±æÈõ,í…Ét` |
+Õ¹—”(‹69Êßk“—FÞ&ìUKŸ,ZmÇç¯]Î'ÐHðîÖA¢“p8NÌôþþ±ò7DÄQ@’²÷M’öåFÆ“ƒŸ“Õý›CÆ#.Þ 5äj¼ÑèØ÷g¼[«÷s3üoãjf `»¬Zyõ^¤ð@qا£æŶüR9*ixbÏ<Šqt³ þuâQÅ#>ÓMíÊìÀÈ%¶cœ„¸çzʺs%`gËô>§µ’kâëÇxo¡AKè|GÒôSxÆ\^»åÈžá(FNI…¬ù'œý7R)™ûµÂ˜óÖ%#±üø0ˆÍ¢µa”„ÂÍ•~¹¶-ÅŠQÛ(=˼ÍÈÈ~à›‡eÑÊiR4r×ü÷ƒÓÞ¢Äc±MëZ¼ðìø-Ä„µÝvÿ…™Æ10¹mËUÉî_Í·õ!NÔLD-ï|ɾÑw¦¸óò¸ |
+´D±y»5â™Ç¯˜ÓÖ:–è¤K^ŒÕŸ5Eú69ñå Òçcƒ·ä*ùvÙÜ'W‡2ÓÿR#ËôHÑ›á;wa |
+rEè¿ôÛÕæ樆տÙQ‘ìvì“cƒà?Ë»m‘£HwÓr(†}GàPÏ÷â·RÕ>³}Äz£ñ9µò• |
+ߧœA„©úì¿þjËÚ.ã|ÏT8’Â1/+i›6¹þåZ¿j0ãRæب¹Øu©e]ΔYJ8…Z))Äôå`R{*ìñ>(élÙߧ pq_Ô—¿E熨œÇÅ‹¡¿{$ØM;<^¡•{À¶J Öåæ>¯æÒÊSâAõsþÖ¿;rŠ‡]*9™t¸-÷oUÝÞ†Ï_]x}8{7VìèÁt°qÑÊ”ün—âõ;‰~sKÎÇ&"º9l¼J¦‹‚Dìþìpÿw„AüŠvãº#Ô.“o¶•Ù®ó:újiŒx,ðäÎd]-ÓKª'‹æúDÊt2À½·J¹eù‡°tEE/èQ8Ÿ˜–¶/Ö‹qùJ,ÇIy.[Iâw ‘¹1Xå}W@q v»žç¹ÔH¶#/J |
+fôŸéq1ýÖ[˜odW ;~=i6ôÙ GÌ6"EÛ›BDfLSkfj4ƒŸ:E.=–n©¶¬¡§kš°Cl˜Ûl¼û~V¿Ähg„œry¾Ô_ã{Nˆ•*lûÇŽX¢ýü'~ãÑ\ Ùwù–w^Ùö‡Ž¶ë›Ã/ñzñÊY3ÖËŠ“¬ã†pa©‘>¶d ëv{s£ZèF5§Rº"ÇÖgUmá,<‹Û#Íæ¦ÇBBŸuÞò_8sQ±Öø5Æ]¨tÞä`ÜÙÆÌ8†l õWxþC…U ÷¹•¢$‹ |
+aoŸø |
+Å®÷ø°ëäìÕ}]畹”óå`ÑùËÔ9%ýéÓÁV|öSwç·r˃k÷ѱÃïZ$î^ˆ²?ESc•î-#›6CϟݬGµÆt-òI6`WøòñÊËð%Î!7²jpoæ£7ãính4§Ònf}O³Ò!Â7q6Úa,‰Ð”~^®·¬ÝõÀþø¥P/“zúW+žá¤19%ð+ó:@gJMsÔf¨tíÐàCºl“j1Z}a’{²²õ»kM›ÂÊë¿ûPûæúŸ· ºc©Å5‚Òc]´ÀÅ3Ob†õä"¨‘[ç5Γ¸—# 9l |
+~šzañ¯€QWp±‰ß[p`96µØ}wþµ®ÐRñyïJ©EfËøaQÛ‹¬ºðiÝä[.E¼áŒæ²Tœ3Âñ£˜ñ•ùG |
+~D·žò×°àeE¸Õ«Csf¿<_.øŒÒˆÀ¹g'<èÜ*ö|¬šïÐœfÒá„'‹Ô—ç1ñÅ ¸'}s»ŒbY¡Cãè×JòÒ¯ÅÚz%·zÞìogµKÖ-÷§|cïG„8C"]©òœž;hC«• E:ëPÅàS×ømÒÆ×8«XÇb¾èH¿gÓmüË~érì˜Wñ=ŸÎ/àG<ʦ#Í2wö¶ß)”¬èäõ™¤îtT×æãפx:â µ/¦ ökÛ |
+ø>4©[Ê캑Á«…3=Jû‡–&Ÿ®»^ÖYqí˜^õAÙ#Oç‡Ùn™Ÿ)œòMT¼œ |
+\£}2ˆê÷»hy¶ÞÞö·Øð×~Þ½”ïI[ÁÃ+™yµžîaoWZ«C?Ð ò;WüYd Meà3èEÌêŽÑá÷~šîͤdCñ£®t%Ͷ\‚äVåãMG) |
+1c¹ØÝðøDt\‘%¬‹%æÙù¹0ÏüK´ 8ðœ|+¤#û~ú™\=êH&'µ7µÅ]eÈn¶×ïIhïžÍi¿…føÛ–¿><Cdâ1¬PM”Û±~"HvPŽõïö Zév@ä¦Ý¥oÇVw7æ¤Ã׫ _àr§§®G°ZÌé‹×ÑTkؾØ}Ôƒ…nd›g>” ~ˤ°`•}ZpJ7ÐB9íy”‚ûÓòñi¼úh<ÚŽ¡Nt×"ðÓÖ¿%!Ow»Ø;‹î.qÓöb¯“:¡ºx,fþºÃ 1(:ÞW.j,‹ƒéÛç÷9mŽšq¤CXÇ/ç“A±*tÌ,¥Ñ?¿]>àû"_{/I¨¦J©ÖÁ'Bš7õÁê)q2×ÇP mƒ=U‰Ÿv¯µKgseÀ£;_‚4Ö°8ʧÎ÷P\`XÚŽw_…£8æ yY¼åG?kàµ8Ê …¼©2 ¼ ¹™µ‚ß绹¢ª‡»-7:µp÷…è€xí³‡¬i‘<u±r…Š’ˆ_Ö¦K©Cmßœ¥‚XOsžKߪÄ݉ýh9?Üü/Zy¦/C»Í„/T"OK,M“YÐ^mÑQçZ§Q ‘M3Å2l¾]¶D›çâ|a4ø½B*ßÙ*ÛtiòàoŒh<÷EDÙ3ŦøßæY8W_MÖðš6û‚ܦ$ÄvýßÜÇ´Áu¥tãoŠˆ³o‡)܈¬¡X^¯+Ö/äoË£Œ”p ÈÙ[v¸Ò>"ˆÜõÈЖ“{ÿìÀFöJ<>}ˆãåx†Éë>ë» Ä'àPþdÑøìà-¥DœdL¶åj"΂ݼ»F” 2ÑȽ×Z@›N£/1_ˆ’»bi§ñ®I |
+4jÑs’§ŽÛ_vs¶Q@_T¬×ÏšúÖï½ ¬Ì›Z›¡½Ì“˜s”.vâ²~Üö»î†KTùç³níÁ& žoE4D}(åÎdÎáSJE›Î£Vû£©Šè™N"9sKÃð‡¨Zþ=YºUB ÈþôOµê¼%²>ÍIãð˵Î[;Á§³I m`¶Öb+ ÔM¬þðáb–b_ÇÊïºd[©ÒùÉÅ:Ʊ |
+µdÎYóÀcåXOcµç}eR9Ò<fު+ìó«ß˜“&§ksO¨éQX¥3èÎ3„â´—ÜÖ.±QF+4ð9±¹¸Í‹ß¢´G,œÛ áÙкúƒR¿ÎþE± ®@0Ó»ßV‚ü{h†ß¹qãs¡ÌäÀz _¼ÔÛK\hêe(±2i`hö1Øói‰óõÉ©`H†Ïé-ß_þ&gd°/ùþê×UºBïCRÿyLÎñp¾ŠºÊÌ,slb0knúsÖ¶öËî®ÛYgÏ/÷Y8Wœ±,.B,v©¸§>âùjÿøÕÆ\•ÌÝ èDŸòYîNkpÃ~*ÖP‘E…ûp3¹À¤9i<=ÁÅØ ð_àZ3LV¼áÇãMá?!ºøÇLM(•g÷ü®ð¼s±^£îuW‹[?¯ÏýIl@ðb¹¸å3„Ü1eêÑ•<C8(Ä,½tr5+Xî^–1vjíÚy~ã'ìP‹5«c3]Û—cGÌvÁ±°þýS‘þ!7çÑìKõªm ç*‘Ñ}sýÖK ž6^ì±HûÂ!ÁM;â:ÚõÒ02¿ô4ùàäü–¹2ú‹3Ž›Œø‹UÜ"Rp͈Rôtå¤aqéÀ2x7®.g"€/ªÏ™æ kŒª—pU”[Gv.–«ÎɈ)Dò÷“Ïejð…es™21E÷WihTL¨kaÀƒ`ª‡õùÿµy:/l¬Ç®£ZƓ׸¤ùÎ?Ük:^P A”p‚Ÿ#Ž‹Eú¾55ÝâBŸiE½e\Ú}>^Üsà h¨šû µ¡h[¥E7FG»ù… är9ÀwŒ:çÂDѵr8öp |
+›Qöñž^ûÓÚþ—OrÕqþorã“ûën¢RPS×7h2ÈÑGfî¿ä0| |
+–j]yz” Þ2Ú}#;U¸žóøئ—rAüÄæ)êrhª(/ºÜãëî {ù³‡!þõjKz Ñ’1-p•²ðØóxô¹šx£Ÿbvy2Î#7 ¹¸³]¢)º¦ “çü$Pðär©¥ÿüÕ‡px ‹D(CгX#w·ÀüÃœ• „“Ýî†79¥jÏŽsGE¬·œž.è^ر̶‰‰ÿ…vWë” 9mWÒkÄÄÇÞmòyZ|4‡›8->Ä·5{@i'äßÈ·(¾z·Æ:6ãYöXÇš]lèâÇGÀu% å[öqº‡žæ®Ï |
+¤³ØŒô®÷|1äô-xAž[ª?üÓæbDaö¡ßµÁ@‚ïd`êõ\ñ€¿7È‚2AjD”¸VMr“K[,?bÔ…?½E´M½é$L»PŒpi•w(Ï=·3Ë’[ŽÃz! O¸–áí£7(}A#|7"±ëõh–^K•œ æƒH»V-{wðF:Ýíg‰Åšj&Ñ‚±åu“rÁX/k>ç8ÁXß‹˜×ó&:™ˆ¼ƒ |
+z¥§XC/XÓ¤gX©€êM;‹{ yìu"ï·¢ï'aQ…ìâúÚRBL`WÛ#’‹VßRB²8¤VlúÑqÓ¡qÞ‘dM*·¶àD§c/F6eر7œÌÿ¥¾ÌÁ®o=}~qyúÚá«<¦ƒÎºlýÔ\ýX¿«L™û+ŒõSU˜¢’ü¤¿…Íé ªw¬š4R |
+üéÝaxké<î[WQ½™Eû¡w6œv¬‚Úægk‘E>2¼/l`ØRÇdÙü<¶Õ;ƒ”iqöRvÏJ>ÿ%¯}@é/¯®ÐkwÐîX¯)óʆH¡ Qà¯ÕçƒÀSÙ´åÑF%•}¬Ò8AžŒ_pHª—Å+e¤ÊÛˆ£¤}‹òâÖÑëðkO¡Ûæ |
+OˆÊ–CfÊñh´ã¸À‰¤Ï9[‡ú*›þ×ÖÛ»¡à\L…™|*Ìò4GìÏ>$ôL ?¿.Ɖèµ<nW<o‰'Ül4³ï&{^˜é$0=–ªyVÄþà‚Ag“¶ÆΪ2ëµ"×0àH»T3Bôƒ劻ëT¿bDéJoÕW®ë\mÜÅ*»ÇHƒsºÒ+s$uÁír Ú=)SFÉlh*ÄMìÁ¹lªl5uÁH·ÿœ?a3òËæâ`’ë‚WÿåèQZvÛñ|›ÝmÏrx¾sºoÏ #¿³®ó |
+Ê šˆw¦·Ç]_<7†¸-_)JìÊÄûX̸ƒ`è0µ±Ô¬©wdkF(Q:™l Šm~QÙ˜ÄÂ÷ ‡i8Ï2wyœä¡º}3=SŒy3±Ù6pöhWÄ]©áçð;c%¥å®cbÃ/Yì΄æ.¥œ~Å–GŠGöY°/T5©¸E¿õ}±Õ³áíSz›>GõÆaÉ»ê¶dò…¬~Ϲ›ë©ýÓ¤ |
+„zZÝÕÌìçkAô&ÒÏT‹Ø „€š«›nÿ“¼[ |
+|oZn¹’K~²Lj7ŸXó^t>ö•éñ¹/ÔhùWfjÊÿöÏO#ÿoè30zëu£Ì-^Rö\à/WÈè „lò»ÃnV A¹.|š+×\<ÜA~¦B¤÷ëø; ȶÂþaicê’tp”͸ðòX¯ûÖŠ«FÙ[v[qË´ËúvÚ›öʨ7þ©Ð=¿zv&ÚÖe+f0I\€‹W2ŽÅ]ë "äЮ»¦þúŸ$Bpáº"9'?¶Ú£ñÓC ð`ÍKEñ¸ÓÍã& |
+ãÑáTŽ§íÀÏêà7†ÃRï©CùSÊ÷ßü³ ~¹2&1¨nß{ÙŠVÉcãP¸%ãsùšÃ›.V”]9_ ð’ˆNR‹¿’å(„õÖ ƒâ<ç}†fœÓ«Ißã |
+óô²ÖßÉI½ôN&‡\îm(påWÎ#· ý#Y9W‚Ã_F5‚yLÈýQõFîè¹âõ鞉޹ë¥W–ÿQ¯Zsâ¿ ÜSÛŠ?Oy!fŸ²¾Ì¡<Ô“Š.¾X$Ý-‰LF}xöÜ»|Ú†gÔéýS—ðÚõ'‡ñ©`ßÅc¯â’±'CßG%h,€éå4_ü!ÞÕîi`tq•`”¤ÞÌuâûW¬~UwŸXúLÖdÌGØÚÚi.úëz{ç”ñÇE® ÅE%Ò Ó7+O¬‚ê/×ÍåÛ£ÕFÔóJo¯Ä«Êq’u‘wþ—‰#5“=kËéÌç’î¿y{~ÛP7yZäKÊ”IFi`Í*~ÆÖõ€eÕÏwõw‹Ù~Ë[·¸í¦>¾è²žîŽ>ªºé»û¦4©N ¨òu×I< |
+ÖHúþU¯± ÐO_ŒpxdðË?`WÌ£Ô/ÏáyñœïDñËÉ™yt$ôPÙ=QÌÛ*ó:—ú‡á6$ÿ>P1"ˆ:ñ*p4˜ádÙ_šÀÛÅ4Ví«†w¤[Pió¤?H´…ã‘„‡zçŠsûÏÄc=? ]üyã/4ŸîUÕà,°ø—[½±b£G=ÆÐ-F±du ä·Á±ÅÅP>žÐµöàÞë!F%m˜V.=Á{ñ…2iïìQÿ€C{8ÆÆ¢cPõG†»·ç÷`Œ¶Nˆ?!NÀ[µî_¯ã‡OožïÇ)0>lHµÀdw¦kÄ~kÞh¶zÎ[ñ4÷!íµh÷߀Ÿ³âwÜ+[AÚãb›=øÓ |
+´vWk''áçgz©—ïTïo¯_ÍI»ÌË.×ý=¤´Ÿ§4¿ |
+è¸$²ç’ü‹2Ø^xð:ÎA 7•ˆ‰F€¦×†„6w ãæó=©B*‡¦K§ˆJîÜ\ÁUÔ±"„É:†°êùa…žáï•~ÀJäZVŽ–Þ ]Ezx¦;º•Ó¤‰§«ÜBê–{¥b&Rk{äý4¼¼µy®) ³¶½x•Xœ]'÷žq{ö~ÒßËk1JVf¯úž5]ÎjGQ<›zÏß'> üx‚x°K>nغŽÒüäe²h÷I±þq#¥Ì–Óôþýbeëãùi;ü”{*)oJÒEß.§“›í7’õ–¾ ûd¥¦=Rƒó'hqLÛÛÎù„Èe¿º˜£$´ô„GS¯È©éLÖMéÓ•r«ô¯¢¬ Áp½g‚iüÀô0‡¦£Ü5 >Âëz㱈,ߟƒw´eUŒÌ犬b[ºgƒ<&yñ&8×–iaUS調ÿ~^ºç™E;ã´llËE¿ŽeÚo©ÿæ‰ÏIÍòÞÙIL\\VçñgáäÌ%üêîÆÜ4?¡%öTÙ\(¸°±ÞL¡(ÏS‘µV@Û XqÝ9†ù0rQG>û¼Dåšì–¦Mº³Ï8B;ðî<EfðÝBBÆ–,‹3ÒзTÕ®>1C¿ÝÄPƒck¦P |
+ Ù¸ š‹g¶.^/ûÚh5 ÁKñ¡i:¼¿â‹n#›8Éyw5Î[EæŸyz°8D§œìØ¿ÀmàXöÿ(Ynžfìœæ'¡(÷1wÈ¥˜óŒb$ZHQŽFß_ÉJꬒzǖ㌞øtC’z¤¯ž-κuº+þ0ý2Åû¶s!x-6(ôâôñ;˜™ÓPöÁ|OÉÝÏê«Ãêféåu%,ÒŠÀ:Ô”'!6Gñ/E78+[Œ6Þ:·^16üæÓÉäàlS@/jEÁ¹6.n\\1é–ƒ»ÚJ—Tþÿ9¬]Û\ª7T2µÎ‰Y¨¹d8Û“±Ò¸z?0G#Et$2Ƚàaýñæ:¨pûp6Q*‡çóÑ ñØ< |
+ÍÛÏ£.aüCÊ{N£p¦Rd§\g¸ÊQ¼ [R3yü6þêîº$°àN3£¤ÁtÂÚÆŽk}JDñ¢¸¨•Q¼¨×*ßR{Ke5Á¢ |
+Hùç ±`•¯ïádïyëÀÈ´òÓlOpoymdð+\v Cjn<%Œ®$öR@l |
+|HP;Iäi§<à={¸Îò‚~3´¾ß§ÏúSšuÁ¿Û®N-rkëáðP]…Gî1×°äÌè:n©Î˶¼Éô-fì¬~šÛ`¤‰ó¨Æ‚*X |
+Lág±oª0gÅeüuFˆp6´ˆƒTlÛGDö_£yhÞ›•=³ |
+^[aÇçÔˆ6’<õ |
+>™>Ï*ĹþÜ'~½ë%¡_“fJ |
+vG¨§J2ÚIkËßtbçÓb½HɦÒÂ6Ý.so®yþ7øο^IÖ”(÷å7º®ðñêÛ¥ÊæÆö$·Ö‹ÇsãœCÔ™m±;û’¨¡U |
+¯“U´H‰•}F§Èz°ü³çœ^nIš.pþDÏE\ÓçhüØ®cÐãÍH{ÌÐúÚ/ß7+ì{¸×)Ѹ¥³ È£’—hgÅE"d`Y³°Þ¹ØXîBÞ+ØL6¶›upÃîI¡9€èTl?ιÃéfÚú?‘Qîû‡;uaíbÚf QÓ¢Rã½s!®m ×U‚‰ƒ ‹ |
+ëê‡*íg0=žVðà”¸Zq˜¯aÓ0V &$½ù'7:;PéWÃìr+òÇôè±¾@?Þ‚;ƒìý.yà(õ”]X–cÆìUÄùO©×Åž›ç+âó»-<r¶²|¢Ë>F{†¿z}Ó©uš!ƒZK—€—rØš;Åç{HhC Éë3-zW`ŸÏðÓ*ø¶ík¸h96z쩸1X/§m¹Âüäð|ò•oª×ú ÑNêhÕT†–³´JƒcØe¥çòÑa |
+gøÞUŒ½nÒ¬z÷Œ‚ ¾êû˜_ÍŸÈÆ}ª\D8ÖŸý‰‡kïÉ{îkárŽœqÜQ"ƒ¾Çu9ØÙezï 'AÌÕ6§Ý¬aÝ-6RÈ7`·+‘ñø.ITvIÄeJˆ dÔšè`êÌÿˆ |
+ñ<ìwH3RpIf ]^²A…ô¸¥QcBmtáö wšœ°Tÿäqg°ÒeG#Ìž³J‘ÜA%zñžŒ2O (+ž£imOåæ—h)´ØƒúÁwAcÜ¥ïÚC›V–ò°qÉö3íw²j+ïMC–Ÿq¶ïjA©Þï¢ó¶71W€2fåžr¤Å½z(92j·²ôþÕl¶€¿¸?Ï|nZø4¾ƒø€’t$#·ï'þk߇þu9^WxÅkׯrî´(¨ì¬kòï³3ŒWm©y |
+ýÃW¿…DÝ÷²+ÿ.¿ýoÑ¿¸¹§»"¶×g‡1 |
+Õêm1í—#~gÙå:aŸ7yÞÜ}?®Í¼•ŽZÏ]/ç]v´ÙÍ[:qI æ¶Ä=7êHŽMCÉ]o«gPìžÔÔ” |
+\öTkÿˆ2i¤7æYøà4+] úOËVXƒ,"!.ìѱ!?Œ)Þs)p~S9ËY¥evX†~ëç¤Z(¹Þc£—ºÈ?´xuë€AÙŽæàøüòõ<C5z/WÅ4¶6m,m£ƒá@ìéíÞå•ùSvuùpEråôŽÙ”¸šç¤ò:Ü]†Ú„DNæW©WqËÿèŠ)u;ô4ñKˆ5 ®ù]¸™ìÅþqôØßXäš6}ÚMA¨û±J¼¸T=ÊŽ RFö{v,@WrµVÎo‡Z´GRZÞYÛ¿9ÚË_‚¥º«?g…O˜oÚÊhœYB0°»¤F¨_‹úI2µÎ |
+é-鱃 |
+²3pSè€voþ4/X%¸S§|xu£€ÛÎL¬€ç||ù¤Ôÿþ?xFŽÈÒfã4 |
+W²ùï™Á¹õ·Õ*¹r@¸Ô·¾yc>m¯åFÇqN(ø¬@ݯ>³¦Õ¡Š°ØÝ&èeÄ6à“=ز¥WÿáK?vfu¾íd¹Öü#ÜÒúľññr·û¤c¼×=‡ÐM‚éù²n€c¬Åº`ÚŸaÎŒÛ-šó²t2©dAiþÁS*OçoEXƤ¢èyCä¹Û[·#=,†‚XƯ9·ønu*·ëlw¼Ë¦£kM—ÜœAEçlj혿Ӫ`–ËçÑk(/Bi!öñäv¢¹c–r;°¦68ÚÕ<€üË|ùx‚pÜŽK5³Ž± |
+LlåƒiÕ|UPc1µ—u=X—äYþ 9^-MS;^Ai‡¯äýïï½¼ÒO/µþ©TĈˆWêòȵ¬xœÃÙkžQA/GŽŒU—jÏ—;Û=mã_X#ù«P_6©½*c"‰‡ðÇSvÍöžÎ™ æµåõdÅí`ø-.®¶?ú‘¢ZWwÇÆöd·Ä‹Æ˜K;„!yá=âç ü{•¬€ááO^µi<êðÝCEýº2ÍÙÑE›&h^PŽOÎü¦N`JÐ:bm±—È×+GJÁêOÒ½]Ü‹œµŒF¨_ìÆ~ƒêŒSV 9ŽÙ1Ie=Í[þŒ†±ëÈQê #ÔyJš]Þ |
+)ñóHú>V+ ú×ð |
+ÆÐÜ<³H‰ßȶƒÔVƒ^ Çr é†u3,¯©úEñv6æ\ÁðhÊl)Á9œŽ7:³_q%# ><¹:]/KvK u.q%{éÑÚîêOcuvÂ6ümÁÆvYóæÿÿ™šï2b–õY÷ |
+®¬2m_±ÃM¶oÑÄC€ýKJ |
+îø÷¨×þôþe ]”†åßZZšgmL¯ˆEh¼T…ðOž_¸\¤ˆ€Û1¬Þ~J¨úK·Ô±Rߧ{Ýq„ª–DÏDPK xïã}•'ß½å¤Yf*çѯ¶_ìŸ:õíÔ‚½Pìµõzd4}Ifœ1Wѣ䊉‡¤|ÙîzþÖ0v?8Ê’òV/ŒVnƒ¶Î+¨YBÓ‚ÒuT»[vï¾ÅÉÝ•¼«WÕH¸Gt£ÿ7Õ¹‰wü(•‡…]÷€ª+&„ÿhƒüPÆr9CMru¨™»Ygâ£ô`Õ‹ö¸ñ$=Y%ºìSŠ€À“ų»è+ZšÓ°‚”<:À³Óp]šÆUI‘ÚRÛÍÏúpLa£êsS›E ~ËܳÞ:Q§C‹?‰ák˜ÓÕç~<ŸIÜ…‚~õêàÀÎŤvÁÝ»‚çlÙ1÷P#ª3ZÖ? |
+³G„bÅ6òuâõš•œ„{ÙiIu…*Ë~Ì®’D#TjYyžn%q¶üz‰"ňû,fìWä7†y^.5D‚ƒ§¥þ䮤z(´GjTz;‡]#úÛU£wxhº}äýSŸñ>æÊ)$:rÑ/]pØ‹¾óAÉöµDʲ …Ýßýâþí×Õ[pQA:”î IaÔè†1ºa"J‹ÒR#D`ôF7lÒ%=jt¼¿â½ãswnÏóœï9ǤÏ]éÊäu³†$Rº®µZ·÷K |
+ñ";ZIK<O<óŽß*̤îÅË)Çã÷ìµ2„%úh¯Û·4T¤¿Çãù5ÛÈ‚B_²Ù?»§§2D¶ |
+Þ |
+3[œ2z° |
+õà˜aânÄÓû±W}`Ò®ìâÇ |
+£kº}a€02±·@ƒ#ÍU~h.j¶¥"èhXÏcaöLþÑ~&•¬ |
+›á:&æÇ |
+†øÆË1‚•G`»._ö ±ø{‘òûýÛËž×ê<^ J;2’AN3¤¬rR=ç+…§c:þhWJ}®Cvf×È D})YX]Ã&x²/x× ‰++¾k¨–5Ŷ†à¥`{ð›i¯|ÕÐ*ÀwjÖŠ±!œý`:s³¢¯›yæ¢<æ_”o¨*5(,‘e–—£[ <9šê>GYµJ©¸¡¶ÈQÑ<Qö\+aÔʸ]úóÞòÉòçfÆÀƒÛ‘Çm[Jg‹¡{Ý᤽Ϟ͡jñ ¾¿4Ï;3žÙt’6UÁÕdåÃÅÅòçz¬Nx‡p›ÑK@ª<³'Û÷‹9QæÌTÔ7÷Óu©ºuò1NN°|˜§ÔêÌ!¼°âœL…Øî?ѪaÜ{±QùqL_ £>°ì{Ñ—£l b^ôË¡‚¸¸°H'\ÿÔzÍ+‘íï«#65Œ©aɃ¤âºõ´WW²\}©¦‡cÕQ!êzï}ÊNø¦JÉ2h8;Kdœf2žqÞ•ÏÆœïÌÚœä £Ÿ‡úçíï÷ºš®u=ÈÛ²D׬åBì+©˜i9@H®±"Ñ®ÀÈéVÚ+l ã&=wVéy¼øT}©DvšM0é/øi¼*+›Ì’d\ð_ÙI ÆgÉÁ±jÁ…ðSºzyRÂ䜤BçY6Š°ÛIÍ";Véðäor 4ž`àÙjìê,|zªrãÜëñu?çÀnÝ2ˆ£¼’3û¼v¯·gôâ'X#xñŽÙb˜ðÍÞj éxº×]ãî Œ[žŒZþ0º+<ºÛ]è\‹1”…6,.u+ŸÖDÙ‡Áîg¼î=æUKDg¯E¿à“³HBÕfÎèéj¶éšÞ–F‰¬1œ’¾Æô[)W|F‹H¸BróHýYþβzoÝaÄ=Š›ùïú>Yö:— Xm™Ç |
+˜5ÑYGý÷²_ê-ÔùíÙ·ÅSÈ’m©!sÌSjXíóä•PͽÏ/€Öÿv¶¦Râ„N˜NJá”^ðóòåÆBÏq™õÙÅIvŠeß̼Š/‘$noÿxøî¼PYéü‡Ú¹ÝÃ.ÙÚÚ;«)ôƗᵇ]jÆo¦+W¢Ÿ13™_<ÅÆÅJÙ@<÷Y1£=µî{Ç\‡×kT“'xË&¨ß•<Ìßý°|¹˜„óå50÷:¯&j!Å/¡™ƒ~Ð@J÷!1Mï |
+•ú-gbÁ= º¡9ßïQËûéÛ æ3×Ö]åñ°!¾ý·)óå~fl|nØ°61ä²{-¦Ñ~`úÓó |
+ñZ«živðsˆeÈø—<ÒñŽ¿ÔÈHI¶/—MÏ|M”±Kä}T@ª\œ®f¦–ýÎÌÁÁ³¬4PÔÿŶ߿¤Ëò”€þ·ãÝ;ëH“žZ‚6»k÷X>ïøEÎƱq†”fÎûà…Pãï¥.Õ-šî¦y”…Öás‚~üUöYÑCŒDA„;™ÃN’Â[7.û›8<BÈÏáM´‡íÏeÚ“‡¸ž ”C£µW„Ç*êùÀB•ùN-cÆ-)Ùvº•‘P™Oç3¡ÍT¬B!”Èá{Ys0AÏô•>!k9Úšê¬äRŠ§//ŽÇ¥ðß}9’ùÌn9U&©™³°#œîá)“Û´ÙZŒÔŸQ©ö^-G™'î•ë"í]6Û‘Ç]†Õ)¯)í„‚Y.ŠÖž’‰=–l$npÛìïÛ éijóî>ž¢êjy¹Âqæ"èX]UŸUéÿÄÿÁiìW+ie*’¡ú=ù/xDw øiýq |
+Çïút¬Ô/è…š/¢ñËöc‚Ŭ“{j—‡úÙïHŒH„ÅýØ X®YÄNÓäGX“ü¹6<£¤âäeô=fµbÿ)3Á®Oåm¶dÐ5!\š²cœf’5k¾{úŽ»“@±Áh_—Ü |
+ ñ†)·¾Á |
+õ»4¬“óy6C' |
+¬ŸÉµêÙjÌ^£=òO_wؽVhXy%–Oz.ëË°º<NéŽ|æ%=«€4xuvšÙX |
+U%öúŽ'Æß®Ÿ›¥n~]©\)ÆËÌ7{ì>ãÝzcågzz‡‚ìÆð;SnJ#¼5wŒIäÌ |
+–îÁ|Wl$þ+´‡ý‚÷ ûïËÛ¼^ÃL=Ãþ¸ñàÒ\˾ê |
+Jír€g!œŸf¢dkâ¬d³z&ì-õdx¹sA0wèìrpu;gu¹·réÈÎÌ@ËðaªÒ7EG¢& {#“ -([âØi/¢¬ðûÆLsbERƒ•ó¿÷æ¶Íúç3gùÒ5®ÖŠV0c©´â,œW‚Hœðàà™Iíà™ÂA•ØMÜtJ~0x«¾æ6ÑFŠX6ï᦯ŠÜ‘–@”ù}i˜O7aÛ“‰-Á§øª\ñCÏö™Æ¥<ÆeSˆü¤ˆcÔpp§ìñȄͬ¤¦MNûØ¢"ô7½’ è!QÍÙ€Ú¥àˆ|CÍ+ùpP"ëšÁÇVzCG'[œ¨7<ú²ÕÍýwˆVaúšœa'ˆ´«üègèw]êçý…ÔäÁ£Ž`g6¿7e?Yç¶GÊŠ°0ý;LÄ%OVò*iÝ;™…›ÌL› +\zÊy8Á®ÿ:¼ØŸ#®Ãèœì |
+»0e"jFìnò$Û»D#;ÉNofýüÐĉ,®Ô W`½•íàý”ºòn¯¼E`ãt§ |
+?§ˆàLJäî#ŽLÚ<ü#<ƒì”-™Ø(9÷¤ßoékñ bÄÂ:¨é |
+HŒÙqå-j8pÒW¤Aõ¦éJþ)ð/’,r×Ëñ!QMÞCÞxßáQÑÑÑ&ºÜyò¬½‰N¯µ¼ÿjű’?@×dfÒ"˜G¡ÊûZlk¨jÔ>hN¦—1žµôã7j½Ýgn)øT¥Ä .§bïA#‰>ÚhrqMèsr½åö´Ø&Z‰‹¥H@”óK®£!Páv^GÒ¤ªû¯ îj¬ˆ*3â†Ò,˜•È‘bA¨©Êˆίœyœ |
+{}£¾Ø+AQݦßSs |
+Îs”s6Öø/W0LXíw²Ü¼Úƒ€‹ÿû‡äAx2bD´ÉMýa“©\mfØøÍɧ—ï7Ñ·¶?"Ý`õ`C_¾·¯Ã°l|éÅb CÄít–EYsì~OÕøhß{XrÕØ©rΣ`çËûDÿ6 dw´3ìRó IIòcU•†ì}¹¢ |
+˜#¤¥Ùý[éY*òg8 ÏÓ)©µDàƒÈUî_™z:4mº2lú·rÀ‡[K¿R¼4«E™²À…jåÕNŠ |
+~âPœñoeþ£©Þ¤BGݲÍñWµUb¢OÜ*¿ÿ,Å%72aë³sñ§L÷ÇéûlvEct`À܉–²éžk«Õ4<WGîY2H'.´ҲækQ? |
+_tÖÚ’{6Á3á²zû²ÒȻ ñµÙÚò€þ?k^粤‘üdñšl§xQ°á»ºj¦Ò |
+†ÜX±÷K3¿Ê¼ÓIÍð¡dåFsœÑ9_—ÚsÄíPµœ¼v«úo[gæ¼S¹´[h«šä…!;öÙ#âX$PÐ÷ªeŸt:o¾ngªè˜žÐô‹¡ÉCÏ›¸é¥CÇ'V·iÃaŠ˜Ðé,€Õuû5Ç@éWebé'4Q˜a:šdõ |
+£[Pàb–¦†üŒ9Øò]õí%¨÷ÙUnŒø6C–(ú™Òk²¦×·ë:…g."²~£•Â«ËÞÎê+H¯eÑ°Éi×ð»É0©MÌQô‹8ö*ÓÉ ¸U'iåxÐbKáS½V˜¯¦a–sÜ£´}w~¤A³N:çl´7Å¡3ÎèY |
+ó‰ˆ8 Ì}%s³ê:³ÚÂ$:d4Äéé´¢‚s±OŒ`'ðñˆ¿Ö¸uÇ>KÈÉ 2lº |
+ˆ$6ÐYTºÕ埆&yæ½Yžñ~s›8ÝÖ)U°µFBJe(*¿÷Ò²~I Ï |
+H®ˆþþýì&aÿŸç&)¡AœÏ÷ûí,¹b÷N;eë3¡‘>¦ø"#@E×–·àíFP'Ú(çÔØf=dÖœ[ÎGšyíÙ\”äÓyµ·ˆÐ3b*\Ð3åf¬•A9וxéË¡c5óݯ„·ƒÊ›¶éÒö‹—‰ |
+KŸÕyŠr‹VZ¢S„X¨N[J½*ͪ¢£œú˜¨= ôªƒ+¬% `?¼9ì_©ýdº˜3ƒ`¦8ØíUè"!Šmùï„¥ÈøÑ_¥/è©^dó/R ðùTIO)—±â™î¶çŒõÁ§!0¥£ÕJ¦È^±W;ÛÀd†ôŒŠ'±ŠÁEOÚaJ™áÚéOøäæ3ÄõùÂõ%þúêúò~X ¡¯±Ë«B§RQ¾pu[eð~h ý/(A<ƒK‡¾Õ3T' ›wŒ§3@¬‡þöÊ^ÜAÛT¡iF¢gÀh¾ùxmÈ[^I‰^Ÿ“÷V*ô;©4ójMgï¼ðKô¼t8R”+ôuqvFŸ¿Ñ’îDWŠàÃ.»"&±¾IWð%î’Ëi~‡1îÑSçʤ… ¾&¦°Ö”F÷Hšgå…vÜ)ÌÔózÄß´« •*7•h3ÊØÜ |
+îJ,b›/"ü‹†Œ’,΄æ8fíXyç\ô2$ïܬx°ØG ñs'ƒ»—zgÁ· RpóÂÒ=߯øg›ÇÖNh±Ûøû!ZŒSƒùŠª“•¦ñcºË¸£JËÀ+çC™éæˆíSÌúqÖN`s²_j¹Òn)õ©½˜…w´À.f›z2~Ι‡˜1KèȲp+¤d¼9ËÅMéáöUt®~e*¯"úpÊVe‘2ƒþòÍ?v*Pwû _ Hy˜WÒdâú๸„˜ôÕÌlydx&^±·Ê®Î€~©uŽ)é“úk’—lb›Ó?Ë ¢,&шؓfåIyjˆ÷5+½Ùtgèr#Ç4~¡~¯Yoòš5a{Ò<ûO1C¡¯ôLNüŠdw6|áWÙU/á¤U7õUV®8y½õµlÁ$Ò|âÀë±cʼnÆO†‹G±€[Çs/Ê>…Ñ_\þ6/-ÛÔp׿ìL¬¸RØ=vž8` ;¹„”—Ò+©Ï.à×Ã@A ¼» Û2¾¡ñ[ tJ;<ÆÿÌv7M L!È_ê*ñ¤ÓôrßøÔe~’ |
+ýR'ª.°‚¼Ý¦pJúg‰ °éZ˜²WðѺ |
+°íǾòN§Õ² |
+KŸc#fdÕ)Þ(F“?szo|}†˜8T=*ƒ»=¶O5©Wo.|¥êÑ=´U¢ |
+ó¤ÁìH¯Ê0¢•ßãç浪ìš\…žÆª«Ø‘m ZåTí¾½Õ¡vRWg±²C÷¾Ö9Ú½§}—¿Î´*~Kñ¡E›ª)åÉO©–ß=ñ©qL”™[\6P?m—Ê)x»{é°÷uûŸþœ¹P‹ÊUV@ÜqÅEUÞüùQ.ú6¯’íØõ ÂùòKÜõ2Ä}$•®ñ‚#€êJOà*œÌaäP¿„ܼŒXrÐ%ºuãÆ7nܸqãÆ7nܸqãÆ7nܸqãÆ7nܸqãÆ7nܸqãÆÿ·ÿêmf× @ |
\ No newline at end of file |
/branches/tracing/boot/arch/ia64/loader/main.c |
---|
44,7 → 44,15 |
return; |
} |
#define DEFAULT_MEMORY_BASE 0x4000000 |
#define DEFAULT_MEMORY_SIZE 0x4000000 |
#define DEFAULT_LEGACY_IO_BASE 0x00000FFFFC000000 |
#define DEFAULT_LEGACY_IO_SIZE 0x4000000 |
#define DEFAULT_FREQ_SCALE 0x0000000100000001 // 1/1 |
#define DEFAULT_SYS_FREQ 100000000 //100MHz |
#ifdef REVISION |
char *revision = ", revision " REVISION; |
#else |
78,7 → 86,6 |
version_print(); |
93,7 → 100,30 |
printf(" %P: %s image (size %d bytes)\n", components[i].start, |
components[i].name, components[i].size); |
if(!bootinfo->hello_configured) |
{ |
/* |
* Load configuration defaults for simulators |
*/ |
bootinfo->memmap_items=0; |
bootinfo->memmap[bootinfo->memmap_items].base=DEFAULT_MEMORY_BASE; |
bootinfo->memmap[bootinfo->memmap_items].size=DEFAULT_MEMORY_SIZE; |
bootinfo->memmap[bootinfo->memmap_items].type=EFI_MEMMAP_FREE_MEM; |
bootinfo->memmap_items++; |
bootinfo->memmap[bootinfo->memmap_items].base=DEFAULT_LEGACY_IO_BASE; |
bootinfo->memmap[bootinfo->memmap_items].size=DEFAULT_LEGACY_IO_SIZE; |
bootinfo->memmap[bootinfo->memmap_items].type=EFI_MEMMAP_IO_PORTS; |
bootinfo->memmap_items++; |
bootinfo->freq_scale = DEFAULT_FREQ_SCALE; |
bootinfo->sys_freq = DEFAULT_SYS_FREQ; |
} |
bootinfo->taskmap.count = 0; |
for (i = 0; i < COMPONENTS; i++) { |
/branches/tracing/boot/arch/ia64/loader/gefi/HelenOS/hello.c |
---|
237,6 → 237,7 |
bootinfo->wakeup_intno=wakeup_intno; |
bootinfo->sys_freq=sys_freq; |
bootinfo->freq_scale=freq_scale; |
bootinfo->hello_configured=1; |
bootinfo->memmap_items=0; |
/branches/tracing/boot/arch/ia64/loader/gefi/HelenOS/division.c |
---|
0,0 → 1,0 |
link ../../../../../../uspace/lib/softint/generic/division.c |
/branches/tracing/boot/arch/ia64/loader/gefi/HelenOS/division.h |
---|
0,0 → 1,0 |
link ../../../../../../uspace/lib/softint/include/division.h |
/branches/tracing/boot/arch/ia64/loader/gefi/HelenOS/mkimage.c |
---|
0,0 → 1,17 |
#include<stdio.h> |
#include<stdlib.h> |
int main(int argc,char** argv) |
{ |
FILE *fi,*fo; |
int count=0; |
int ch; |
fi=fopen("image.bin","rb"); |
fo=fopen("image.c","wb"); |
fprintf(fo,"char HOSimage[]={\n"); |
if((ch=getc(fi))!=EOF) {fprintf(fo,"0x%02X",ch);count++;} |
while((ch=getc(fi))!=EOF) {fprintf(fo,",0x%02X",ch);count++;} |
fprintf(fo,"};\nint HOSimagesize=%d;\n",count); |
return EXIT_SUCCESS; |
} |
/branches/tracing/boot/arch/ia64/loader/gefi/HelenOS/Makefile |
---|
28,7 → 28,8 |
CRTOBJS = ../gnuefi/crt0-efi-$(ARCH).o |
LDSCRIPT = ../gnuefi/elf_$(ARCH)_efi.lds |
LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L../lib -L../gnuefi $(CRTOBJS) |
LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) |
#LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) |
LOADLIBES = -lefi -lgnuefi |
FORMAT = efi-app-$(ARCH) |
46,15 → 47,18 |
$(OBJDUMP) -d hello.efi > hello.disass |
#When selected first lines or second lines, select if image is linked into hello or not - usefull for network boot |
#hello.so: hello.o image.o |
#hello.so: hello.o image.o division.o |
hello.so: hello.o image.bin |
# $(LD) $(LDFLAGS) -Map hello.map hello.o image.o -o hello.so $(LOADLIBES) #link image inside hello |
$(LD) $(LDFLAGS) -Map hello.map hello.o -o hello.so $(LOADLIBES) #dont link image inside hello |
# $(LD) $(LDFLAGS) -Map hello.map hello.o division.o image.o -o hello.so $(LOADLIBES) #link image inside hello |
$(LD) $(LDFLAGS) -Map hello.map hello.o division.o -o hello.so $(LOADLIBES) #dont link image inside hello |
hello.o: hello.c |
$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c hello.c -o hello.o |
division.o: division.c |
$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c division.c -o division.o |
image.bin: ../../image.boot |
$(OBJCOPY) -O binary ../../image.boot image.bin |
/branches/tracing/boot/arch/ppc64/Makefile.inc |
---|
26,6 → 26,8 |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
DEFS += -DOPEN_BOOT |
build: $(BASE)/image.boot |
$(BASE)/image.boot: depend arch/$(ARCH)/loader/image.boot |
35,7 → 37,7 |
-rm arch/$(ARCH)/loader/image.boot |
arch/$(ARCH)/loader/image.boot: |
make -C arch/$(ARCH)/loader COMPILER=$(COMPILER) KERNELDIR=../../../$(KERNELDIR) USPACEDIR=../../../$(USPACEDIR) |
make -C arch/$(ARCH)/loader COMPILER=$(COMPILER) KERNELDIR=../../../$(KERNELDIR) USPACEDIR=../../../$(USPACEDIR) "DEFS=$(DEFS)" |
clean: generic_clean |
make -C arch/$(ARCH)/loader clean COMPILER=$(COMPILER) KERNELDIR=../../../$(KERNELDIR) USPACEDIR=../../../$(USPACEDIR) |