diff options
| author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 | 
|---|---|---|
| committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 | 
| commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
| tree | 65ca85f13617aee1dce474596800950f266a456c /roms/openhackware/src | |
| download | qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.tar.gz qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.tar.bz2 qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.zip  | |
Diffstat (limited to 'roms/openhackware/src')
58 files changed, 28152 insertions, 0 deletions
diff --git a/roms/openhackware/src/bios.h b/roms/openhackware/src/bios.h new file mode 100644 index 00000000..83d9af47 --- /dev/null +++ b/roms/openhackware/src/bios.h @@ -0,0 +1,588 @@ +/* + * <bios.h> + * + * header for Open Hack'Ware + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ +#if !defined (__BIOS_H__) +#define __BIOS_H__ + +#define USE_OPENFIRMWARE +//#define DEBUG_BIOS 1 + +#define BIOS_VERSION "0.4.1" + +#define DSISR 18 +#define DAR   19 +#define SRR0  26 +#define SRR1  27 + +#define _tostring(s) #s +#define stringify(s) _tostring(s) + +#if !defined (ASSEMBLY_CODE) + +#ifdef DEBUG_BIOS +#define DPRINTF(fmt, args...) do { dprintf(fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do { } while (0) +#endif +#define ERROR(fmt, args...) do { printf("ERROR: " fmt , ##args); } while (0) +#define MSG(fmt, args...) do { printf(fmt , ##args); } while (0) + +#define offsetof(_struct, field)                                      \ +({                                                                    \ +    typeof(_struct) __tmp_struct;                                     \ +    int __off;                                                        \ +    __off = (char *)(&__tmp_struct.field) - (char *)(&__tmp_struct);  \ +    __off;                                                            \ +}) + +#define unused __attribute__ (( unused))  + +/* Useful macro in C code */ +#define MTSPR(num, value)                                            \ +__asm__ __volatile__ ("mtspr " stringify(num) ", %0" :: "r"(value)); + +/* Architectures */ +enum { +    ARCH_PREP = 0, +    ARCH_CHRP, +    ARCH_MAC99, +    ARCH_POP, +    ARCH_HEATHROW, +}; + +/* Hardware definition(s) */ +extern uint32_t isa_io_base; +#define ISA_IO_BASE 0x80000000 +extern int arch; + +/*****************************************************************************/ +/* From start.S : BIOS start code and asm helpers */ +void transfer_handler (void *residual, void *load_addr, +                       void *OF_entry, void *bootinfos, +                       void *cmdline, void *not_used, +                       void *nip, void *stack_base); +void bug (void); + +/* PPC helpers */ +uint32_t mfmsr (void); +void mtmsr (uint32_t msr); +uint32_t mfpvr (void); +void mftb (uint32_t *tb); +void MMU_on (void); +void MMU_off (void); +/* IO helpers */ +uint32_t inb (uint16_t port); +void outb (uint16_t port, uint32_t val); +uint32_t inw (uint16_t port); +void outw (uint16_t port, uint32_t val); +uint32_t inl (uint16_t port); +void outl (uint16_t port, uint32_t val); +void eieio (void); +/* Misc helpers */ +uint16_t ldswap16 (uint16_t *addr); +void stswap16 (void *addr, uint16_t val); +uint32_t ldswap32 (uint32_t *addr); +void stswap32 (void *addr, uint32_t val); +void mul64 (uint32_t *ret, uint32_t a, uint32_t b); +void add64 (uint32_t *ret, uint32_t *a, uint32_t *b); + +typedef struct jmp_buf { +    uint32_t gpr[32]; +    uint32_t lr; +    uint32_t ctr; +    uint32_t xer; +    uint32_t ccr; +} jmp_buf; +int setjmp (jmp_buf env); +void longjmp (jmp_buf env); + +/*****************************************************************************/ +/* PCI BIOS                                                                  */ +typedef struct pci_common_t pci_common_t; +typedef struct pci_host_t pci_host_t; +typedef struct pci_device_t pci_device_t; +typedef struct pci_bridge_t pci_bridge_t; +typedef struct pci_ops_t pci_ops_t; +typedef union pci_u_t pci_u_t; + +typedef struct pci_dev_t pci_dev_t; +struct pci_dev_t { +    uint16_t vendor; +    uint16_t product; +    const unsigned char *type; +    const unsigned char *name; +    const unsigned char *model; +    const unsigned char *compat; +    int acells; +    int scells; +    int icells; +    int (*config_cb)(pci_device_t *device); +    const void *private; +}; + +pci_host_t *pci_init (void); +void pci_get_mem_range (pci_host_t *host, uint32_t *start, uint32_t *len); + +/*****************************************************************************/ +/* nvram.c : NVRAM management routines */ +typedef struct nvram_t nvram_t; +extern nvram_t *nvram; + +uint8_t NVRAM_read (nvram_t *nvram, uint32_t addr); +void NVRAM_write (nvram_t *nvram, uint32_t addr, uint8_t value); +uint16_t NVRAM_get_size (nvram_t *nvram); +int NVRAM_format (nvram_t *nvram); +nvram_t *NVRAM_get_config (uint32_t *RAM_size, int *boot_device, +                           void **boot_image, uint32_t *boot_size, +                           void **cmdline, uint32_t *cmdline_size, +                           void **ramdisk, uint32_t *ramdisk_size); + +/*****************************************************************************/ +/* bloc.c : bloc devices management */ +typedef struct pos_t { +    uint32_t bloc; +    uint32_t offset; +} pos_t; + +typedef struct bloc_device_t bloc_device_t; +typedef struct part_t part_t; +typedef struct fs_t fs_t; + +bloc_device_t *bd_open (int device); +int bd_seek (bloc_device_t *bd, uint32_t bloc, uint32_t pos); +int bd_read (bloc_device_t *bd, void *buffer, int len); +int bd_write (bloc_device_t *bd, const void *buffer, int len); +#define _IOCTL(a, b) (((a) << 16) | (b)) +#define MEM_SET_ADDR _IOCTL('M', 0x00) +#define MEM_SET_SIZE _IOCTL('M', 0x01) +int bd_ioctl (bloc_device_t *bd, int func, void *args); +uint32_t bd_seclen (bloc_device_t *bd); +void bd_close (bloc_device_t *bd); +void bd_reset_all(void); +uint32_t bd_seclen (bloc_device_t *bd); +uint32_t bd_maxbloc (bloc_device_t *bd); +void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum, +                  int *cyl, int *head, int *sect); +uint32_t bd_CHS2sect (bloc_device_t *bd, +                      int cyl, int head, int sect); +part_t *bd_probe (int boot_device); +bloc_device_t *bd_get (int device); +void bd_put (bloc_device_t *bd); +void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum); +part_t **_bd_parts (bloc_device_t *bd); + +void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, +                          uint32_t io_base2, uint32_t io_base3, +                          void *OF_private0, void *OF_private1); +void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1, +                            void *OF_private); + +/*****************************************************************************/ +/* part.c : partitions management */ +enum part_flags_t { +    PART_TYPE_RAW     = 0x0000, +    PART_TYPE_PREP    = 0x0001, +    PART_TYPE_APPLE   = 0x0002, +    PART_TYPE_ISO9660 = 0x0004, +    PART_FLAG_DUMMY   = 0x0010, +    PART_FLAG_DRIVER  = 0x0020, +    PART_FLAG_PATCH   = 0x0040, +    PART_FLAG_FS      = 0x0080, +    PART_FLAG_BOOT    = 0x0100, +}; + +enum { +    PART_PREP = 0x01, +    PART_CHRP = 0x02, +}; + +part_t *part_open (bloc_device_t *bd, +                   uint32_t start, uint32_t size, uint32_t spb); +int part_seek (part_t *part, uint32_t bloc, uint32_t pos); +int part_read (part_t *part, void *buffer, int len); +int part_write (part_t *part, const void *buffer, int len); +void part_close (part_t *part); +uint32_t part_blocsize (part_t *part); +uint32_t part_flags (part_t *part); +uint32_t part_size (part_t *part); +fs_t *part_fs (part_t *part); + +part_t *part_get (bloc_device_t *bd, int partnum); +part_t *part_probe (bloc_device_t *bd, int set_raw); +int part_set_boot_file (part_t *part, uint32_t start, uint32_t offset, +                        uint32_t size); + +/*****************************************************************************/ +/* fs.c : file system management */ +typedef struct dir_t dir_t; +typedef struct dirent_t dirent_t; +typedef struct inode_t inode_t; + +struct dirent_t { +    dir_t *dir; +    inode_t *inode; +    const unsigned char *dname; +}; + +enum { +    INODE_TYPE_UNKNOWN = 0x00FF, +    INODE_TYPE_DIR     = 0x0000, +    INODE_TYPE_FILE    = 0x0001, +    INODE_TYPE_OTHER   = 0x0002, +    INODE_TYPE_MASK    = 0x00FF, +    INODE_FLAG_EXEC    = 0x0100, +    INODE_FLAG_BOOT    = 0x0200, +    INODE_FLAG_MASK    = 0xFF00, +}; + +/* probe a filesystem from a partition */ +fs_t *fs_probe (part_t *part, int set_raw); +part_t *fs_part (fs_t *fs); +/* Recurse thru directories */ +dir_t *fs_opendir (fs_t *fs, const unsigned char *name); +dirent_t *fs_readdir (dir_t *dir); +unsigned char *fs_get_path (dirent_t *dirent); +void fs_closedir (dir_t *dir); +/* Play with files */ +inode_t *fs_open (fs_t *fs, const unsigned char *name); +int fs_seek (inode_t *inode, uint32_t bloc, uint32_t pos); +int fs_read (inode_t *inode, void *buffer, int len); +int fs_write (inode_t *inode, const void *buffer, unused int len); +void fs_close (inode_t *inode); +uint32_t fs_get_type (fs_t *fs); +uint32_t fs_inode_get_type (inode_t *inode); +uint32_t fs_inode_get_flags (inode_t *inode); +part_t *fs_inode_get_part (inode_t *inode); + +/* Bootfile */ +unsigned char *fs_get_boot_dirname (fs_t *fs); +inode_t *fs_get_bootfile (fs_t *fs); +int fs_raw_set_bootfile (part_t *part, +                         uint32_t start_bloc, uint32_t start_offset, +                         uint32_t size_bloc, uint32_t size_offset); + +/*****************************************************************************/ +/* file.c : file management */ +#define DEFAULT_LOAD_DEST 0x00100000 + +uint32_t file_seek (inode_t *file, uint32_t pos); + +/* Executable files loader */ +int bootfile_load (void **dest, void **entry, void **end, +                   part_t *part, int type, const unsigned char *fname, +                   uint32_t offset); + +/*****************************************************************************/ +/* char.c : char devices */ +typedef struct chardev_t chardev_t; +typedef struct cops_t cops_t; + +struct cops_t { +    int (*open)(void *private); +    int (*close)(void *private); +    int (*read)(void *private); +    int (*write)(void *private, int c); +    /* Won't implement seek for now */ +}; + +enum { +    CHARDEV_KBD = 0, +    CHARDEV_MOUSE, +    CHARDEV_SERIAL, +    CHARDEV_DISPLAY, +    CHARDEV_LAST, +}; + +int chardev_register (int type, cops_t *ops, void *private); +int chardev_open (chardev_t *dev); +int chardev_close (chardev_t *dev); +int chardev_read (chardev_t *dev, void *buffer, int maxlen); +int chardev_write (chardev_t *dev, const void *buffer, int maxlen); +int chardev_type (chardev_t *dev); + +/* Console driver */ +int console_open (void); +int console_read (void *buffer, int maxlen); +int console_write (const void *buffer, int len); +void console_close (void); + +/* PC serial port */ +#define SERIAL_OUT_PORT (0x03F8) +int pc_serial_register (uint16_t base); + +/* CUDA host */ +typedef struct cuda_t cuda_t; +cuda_t *cuda_init (uint32_t base); +void cuda_reset (cuda_t *cuda); + +/*****************************************************************************/ +/* vga.c : VGA console */ +extern unsigned long vga_fb_phys_addr; +extern int vga_fb_width; +extern int vga_fb_height; +extern int vga_fb_linesize; +extern int vga_fb_bpp; +extern int vga_fb_depth; +void vga_prep_init(void); +void vga_set_address (uint32_t address); +void vga_set_mode(int width, int height, int depth); +void vga_set_palette(int i, unsigned int rgba); +#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define RGB(r, g, b) RGBA(r, g, b, 0xff) +unsigned int vga_get_color(unsigned int rgba); + +void vga_draw_buf (const void *buf, int buf_linesize, +                   int posx, int posy, int width, int height); +void vga_fill_rect (int posx, int posy, int width, int height, uint32_t color); +void vga_bitblt(int xs, int ys, int xd, int yd, int w, int h); +void vga_check_mode(int width, int height, int depth); + +/* text primitives */ +void vga_text_set_fgcol(unsigned int rgba); +void vga_text_set_bgcol(unsigned int rgba); +void vga_putcharxy(int x, int y, int ch, +                   unsigned int fgcol, unsigned int bgcol); +void vga_putchar(int ch); +void vga_puts(const char *s); + +/*****************************************************************************/ +/* bootinfos.c : build structures needed by kernels to boot */ +void prepare_bootinfos (void *p, uint32_t memsize, +                        void *cmdline, void *initrd, uint32_t initrd_size); +void residual_build (void *p, uint32_t memsize, +                     uint32_t load_base, uint32_t load_size, +                     uint32_t last_alloc); + +/*****************************************************************************/ +/* of.c : Open-firmware emulation */ +#define OF_NAMELEN_MAX 1024 +#define OF_PROPLEN_MAX 256 + +int OF_init (void); +int OF_register_mb (const unsigned char *model, const unsigned char **compats); +int OF_register_cpu (const unsigned char *name, int num, uint32_t pvr, +                     uint32_t min_freq, uint32_t max_freq, uint32_t bus_freq, +                     uint32_t tb_freq, uint32_t reset_io); +#if 0 +int OF_register_translations (int nb, OF_transl_t *translations); +#endif +uint32_t OF_claim_virt (uint32_t virt, uint32_t size, int *range); +int OF_register_memory (uint32_t memsize, uint32_t bios_size); +int OF_register_bootargs (const unsigned char *bootargs); +void *OF_register_pci_host (pci_dev_t *dev, uint16_t rev, uint32_t ccode, +                            uint32_t cfg_base, uint32_t cfg_len, +                            uint32_t mem_base, uint32_t mem_len, +                            uint32_t io_base, uint32_t io_len, +                            uint32_t rbase, uint32_t rlen, +                            uint16_t min_grant, uint16_t max_latency); +void *OF_register_pci_bridge (void *parent, pci_dev_t *dev, +                              uint32_t cfg_base, uint32_t cfg_len, +                              uint8_t devfn, uint8_t rev, uint32_t ccode, +                              uint16_t min_grant, uint16_t max_latency); +void *OF_register_pci_device (void *parent, pci_dev_t *dev, +                              uint8_t devfn, uint8_t rev, uint32_t ccode, +                              uint16_t min_grant, uint16_t max_latency); +void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses); +void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, +                             uint32_t *regions, uint32_t *sizes, +                             int irq_line); +void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, +                            void *private_data); +void OF_finalize_pci_ide (void *dev,  +                          uint32_t io_base0, uint32_t io_base1, +                          uint32_t io_base2, uint32_t io_base3); +int OF_register_bus (const unsigned char *name, uint32_t address, +                     const unsigned char *type); +int OF_register_serial (const unsigned char *bus, const unsigned char *name, +                        uint32_t io_base, int irq); +int OF_register_stdio (const unsigned char *dev_in, +                       const unsigned char *dev_out); +void OF_vga_register (const unsigned char *name, unused uint32_t address, +                      int width, int height, int depth, +                      unsigned long vga_bios_addr,  +                      unsigned long vga_bios_size); +void *OF_blockdev_register (void *parent, void *private, +                            const unsigned char *type, +                            const unsigned char *name, int devnum, +                            const char *alias); +void OF_blockdev_set_boot_device (void *disk, int partnum, +                                  const unsigned char *file); + +int OF_entry (void *p); +int OF_client_entry (void *p); +void RTAS_init (void); + +/*****************************************************************************/ +/* main.c : main BIOS code */ +/* Memory management */ +/* Memory areas */ +extern uint32_t _data_start, _data_end; +extern uint32_t _OF_vars_start, _OF_vars_end; +extern uint32_t _sdata_start, _sdata_end; +extern uint32_t _ro_start, _ro_end; +extern uint32_t _RTAS_start, _RTAS_end; +extern uint32_t _RTAS_data_start, _RTAS_data_end; +extern uint32_t _bss_start, _bss_end; +extern uint32_t _ram_start; +extern const unsigned char *BIOS_str; +extern const unsigned char *copyright; +void *mem_align (int align); +void freep (void *p); + +/* Endian-safe memory read/write */ +static inline void put_be64 (void *addr, uint64_t l) +{ +    *(uint64_t *)addr = l; +} + +static inline uint64_t get_be64 (void *addr) +{ +    return *(uint64_t *)addr; +} + +static inline void put_le64 (void *addr, uint64_t l) +{ +    uint32_t *p; + +    p = addr; +    stswap32(p, l); +    stswap32(p + 1, l >> 32); +} + +static inline uint64_t get_le64 (void *addr) +{ +    uint64_t val; +    uint32_t *p; + +    p = addr; +    val = ldswap32(p); +    val |= (uint64_t)ldswap32(p + 1) << 32; +     +    return val; +} + +static inline void put_be32 (void *addr, uint32_t l) +{ +    *(uint32_t *)addr = l; +} + +static inline uint32_t get_be32 (void *addr) +{ +    return *(uint32_t *)addr; +} + +static inline void put_le32 (void *addr, uint32_t l) +{ +    stswap32(addr, l); +} + +static inline uint32_t get_le32 (void *addr) +{ +    return ldswap32(addr); +} + +static inline void put_be16 (void *addr, uint16_t l) +{ +    *(uint16_t *)addr = l; +} + +static inline uint16_t get_be16 (void *addr) +{ +    return *(uint16_t *)addr; +} + +static inline void put_le16 (void *addr, uint16_t l) +{ +    stswap16(addr, l); +} + +static inline uint16_t get_le16 (void *addr) +{ +    return ldswap16(addr); +} + +/* String functions */ +long strtol (const unsigned char *str, unsigned char **end, int base); + +int write_buf (const unsigned char *buf, int len); + +/* Misc */ +void usleep (uint32_t usec); +void sleep (int sec); +uint32_t crc32 (uint32_t crc, const uint8_t *p, int len); +void set_loadinfo (void *load_base, uint32_t size); +void set_check (int do_it); +void check_location (const void *buf, const char *func, const char *name); + +static inline void pokeb (void *location, uint8_t val) +{ +#ifdef DEBUG_BIOS +    check_location(location, __func__, "location"); +#endif +    *((uint8_t *)location) = val; +} + +static inline uint8_t peekb (void *location) +{ +#ifdef DEBUG_BIOS +    check_location(location, __func__, "location"); +#endif +    return *((uint8_t *)location); +} + +static inline void pokew (void *location, uint16_t val) +{ +#ifdef DEBUG_BIOS +    check_location(location, __func__, "location"); +#endif +    *((uint8_t *)location) = val; +} + +static inline uint16_t peekw (void *location) +{ +#ifdef DEBUG_BIOS +    check_location(location, __func__, "location"); +#endif +    return *((uint16_t *)location); +} + +static inline void pokel (void *location, uint32_t val) +{ +#ifdef DEBUG_BIOS +    check_location(location, __func__, "location"); +#endif +    *((uint32_t *)location) = val; +} + +static inline uint32_t peekl (void *location) +{ +#ifdef DEBUG_BIOS +    check_location(location, __func__, "location"); +#endif +    return *((uint32_t *)location); +} + +/* Console */ +int cs_write (const unsigned char *buf, int len); + +#endif /* !defined (ASSEMBLY_CODE) */ + + +#endif /* !defined (__BIOS_H__) */ diff --git a/roms/openhackware/src/bloc.c b/roms/openhackware/src/bloc.c new file mode 100644 index 00000000..b171ed6e --- /dev/null +++ b/roms/openhackware/src/bloc.c @@ -0,0 +1,1258 @@ +/* + * <bloc.c> + * + * Open Hack'Ware BIOS bloc devices management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" + +#undef DPRINTF +#define DPRINTF(fmt, args...) do { } while (0) + +struct bloc_device_t { +    int device; +    /* Hardware */ +    uint32_t io_base; +    int drv; +    /* Geometry */ +    int heads; +    int trks; +    int sects; +    int seclen; +    /* Position */ +    int bloc; +    int vbloc; +    int vpos; +    /* Access */ +    int (*init)(bloc_device_t *bd, int device); +    int (*read_sector)(bloc_device_t *bd, void *buffer, int secnum); +    int (*ioctl)(bloc_device_t *bd, int func, void *args); +    /* buffer */ +    char *buffer; +    /* Private data */ +    int tmp; +    void *private; +#ifdef USE_OPENFIRMWARE +    void *OF_private; +#endif +    /* Partitions */ +    part_t *parts, *bparts; +    part_t *boot_part; +    int bpartnum; +    /* Chain */ +    bloc_device_t *next; +}; + +static bloc_device_t *bd_list; +  +static int fdc_initialize (bloc_device_t *bd, int device); +static int fdc_read_sector (bloc_device_t *bd, void *buffer, int secnum); + +static int ide_initialize (bloc_device_t *bd, int device); +static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum); +static int ide_reset (bloc_device_t *bd); + +static int mem_initialize (bloc_device_t *bd, int device); +static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum); +static int mem_ioctl (bloc_device_t *bd, int func, void *args); + +bloc_device_t *bd_open (int device) +{ +    bloc_device_t *bd; +    int num; + +    bd = bd_get(device); +    if (bd != NULL) +        return bd; +    bd = malloc(sizeof(bloc_device_t)); +    if (bd == NULL) +        return NULL; +    bd->ioctl = NULL; +    switch (device) { +    case 'a': +        num = 0; +        bd->init = &fdc_initialize; +        bd->read_sector = &fdc_read_sector; +        break; +    case 'b': +        num = 1; +        bd->init = &fdc_initialize; +        bd->read_sector = &fdc_read_sector; +        break; +    case 'c': +        num = 0; +        bd->init = &ide_initialize; +        bd->read_sector = &ide_read_sector; +        break; +    case 'd': +        num = 1; +        bd->init = &ide_initialize; +        bd->read_sector = &ide_read_sector; +        break; +    case 'e': +        num = 2; +        bd->init = &ide_initialize; +        bd->read_sector = &ide_read_sector; +        break; +    case 'f': +        num = 3; +        bd->init = &ide_initialize; +        bd->read_sector = &ide_read_sector; +        break; +    case 'm': +        num = 0; +        bd->init = &mem_initialize; +        bd->read_sector = &mem_read_sector; +        bd->ioctl = &mem_ioctl; +        break; +    default: +        return NULL; +    } +    bd->bloc = -1; +    if ((*bd->init)(bd, num) < 0) { +        free(bd); +        return NULL; +    } +    bd->buffer = malloc(bd->seclen); +    if (bd->buffer == NULL) { +        free(bd); +        return NULL; +    } +    bd->device = device; + +    return bd; +} + +int bd_seek (bloc_device_t *bd, uint32_t bloc, uint32_t pos) +{ +    uint32_t maxbloc; + +    maxbloc = bd_maxbloc(bd); +    if (bloc > maxbloc) { +        DPRINTF("%p bloc: %d maxbloc: %d C: %d H: %d S: %d\n", +                bd, bloc, maxbloc, bd->trks, bd->heads, bd->sects); +        return -1; +    } +    bd->vbloc = bloc; +    bd->vpos = pos; +    DPRINTF("%s: %p %08x %08x %08x %08x %08x\n", __func__, bd, bloc, pos, +            bd->bloc, bd->vbloc, bd->vpos); + +    return 0; +} + +int bd_read (bloc_device_t *bd, void *buffer, int len) +{ +    int clen, total; + +    for (total = 0; len > 0; total += clen) { +        if (bd->vbloc != bd->bloc) { +            /* Do physical seek */ +#if 0 +            DPRINTF("Read sector %d\n", bd->vbloc); +#endif +            if ((*bd->read_sector)(bd, bd->buffer, bd->vbloc) < 0) { +                printf("Error reading bloc %d\n", bd->vbloc); +                return -1; +            } +            bd->bloc = bd->vbloc; +        } +        clen = bd->seclen - bd->vpos; +        if (clen > len) +            clen = len; +        memcpy(buffer, bd->buffer + bd->vpos, clen); +#if 0 +        DPRINTF("%s: %p copy %d bytes (%08x %08x %08x) %08x %08x %08x %08x\n", +                __func__, bd, clen, bd->bloc, bd->vbloc, bd->vpos, +                ((uint32_t *)buffer)[0], ((uint32_t *)buffer)[1], +                ((uint32_t *)buffer)[2], ((uint32_t *)buffer)[3]); +#endif +        bd->vpos += clen; +        if (bd->vpos == bd->seclen) { +            bd->vbloc++; +            bd->vpos = 0; +        } +        buffer += clen; +        len -= clen; +    } + +    return total; +} + +int bd_write (unused bloc_device_t *bd, +              unused const void *buffer, unused int len) +{ +    return -1; +} + +int bd_ioctl (bloc_device_t *bd, int func, void *args) +{ +    if (bd->ioctl == NULL) +        return -1; + +    return (*bd->ioctl)(bd, func, args); +} + +void bd_close (unused bloc_device_t *bd) +{ +} + +void bd_reset_all(void) +{ +    bloc_device_t *bd; +    for (bd = bd_list; bd != NULL; bd = bd->next) { +        if (bd->init == &ide_initialize) { +            /* reset IDE drive because Darwin wants all IDE devices to be reset */ +            ide_reset(bd); +        } +    } +} + +uint32_t bd_seclen (bloc_device_t *bd) +{ +    return bd->seclen; +} + +uint32_t bd_maxbloc (bloc_device_t *bd) +{ +    return bd_CHS2sect(bd, bd->trks, 0, 1); +} + +/* XXX: to be suppressed */ +void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum) +{ +    dprintf("%s: part %p (%p) %d\n", __func__, partition, bd->boot_part, partnum); +    if (bd->boot_part == NULL) { +        bd->boot_part = partition; +        bd->bpartnum = partnum; +    } +} + +part_t **_bd_parts (bloc_device_t *bd) +{ +    return &bd->parts; +} + +part_t **_bd_bparts (bloc_device_t *bd) +{ +    return &bd->bparts; +} + +void bd_set_boot_device (bloc_device_t *bd) +{ +#if defined (USE_OPENFIRMWARE) +    OF_blockdev_set_boot_device(bd->OF_private, bd->bpartnum, "\\\\ofwboot"); +#endif +} + +part_t *bd_probe (int boot_device) +{ +    char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', }; +    bloc_device_t *bd, **cur; +    part_t *boot_part, *tmp; +    int i, force_raw; + +    boot_part = NULL; +    /* Probe bloc devices */ +    for (i = 0; devices[i] != '\0'; i++) { +        if (devices[i] == 'm' && boot_device != 'm') +            break; +        bd = bd_open(devices[i]); +        if (bd != NULL) { +            DPRINTF("New bloc device %c: %p\n", devices[i], bd); +            for (cur = &bd_list; *cur != NULL; cur = &(*cur)->next) +                continue; +            *cur = bd; +        } else { +            DPRINTF("No bloc device %c\n", devices[i]); +        } +    } +    /* Probe partitions for each bloc device found */ +    for (bd = bd_list; bd != NULL; bd = bd->next) { +        dprintf("Probe partitions for device %c\n", bd->device); +        if (bd->device == 'm') +            force_raw = 1; +        else +            force_raw = 0; +        tmp = part_probe(bd, force_raw); +        if (boot_device == bd->device) { +            boot_part = tmp; +            bd_set_boot_device(bd); +        } +    } + +    return boot_part; +} + +bloc_device_t *bd_get (int device) +{ +    bloc_device_t *cur; + +    for (cur = bd_list; cur != NULL; cur = cur->next) { +        if (cur->device == device) { +            DPRINTF("%s: found device %c: %p\n", __func__, device, cur); +            return cur; +        } +    } + +    return NULL; +} + +void bd_put (unused bloc_device_t *bd) +{ +} + +void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum, +                  int *cyl, int *head, int *sect) +{ +    uint32_t tmp; + +    tmp = secnum / bd->sects; +    *sect = secnum - (tmp * bd->sects) + 1; +    *cyl = tmp / bd->heads; +    *head = tmp - (*cyl * bd->heads); +} + +uint32_t bd_CHS2sect (bloc_device_t *bd, +                      int cyl, int head, int sect) +{ +    return (((cyl * bd->heads) + head) * bd->sects) + sect - 1; +} + +/* Floppy driver */ +#define FDC_OUT_BASE    (0x03F0) +#define FDC_DOR_PORT    (FDC_OUT_BASE + 0x0002) +#define FDC_TAPE_PORT   (FDC_OUT_BASE + 0x0003) +#define FDC_MAIN_STATUS (FDC_OUT_BASE + 0x0004) +#define FDC_WRITE_PORT  (FDC_OUT_BASE + 0x0005) +#define FDC_READ_PORT   (FDC_OUT_BASE + 0x0005) + +static int fdc_read_data (uint8_t *addr, int len) +{ +    uint8_t status; +    int i; + +    for (i = 0; i < len; i++) { +        status = inb(FDC_MAIN_STATUS); +        if ((status & 0xD0) != 0xD0) { +#if 0 +            ERROR("fdc_read_data: read data status != READ_DATA: %0x\n", +                  status); +#endif +            return -1; +        } +        addr[i] = inb(FDC_READ_PORT); +    } + +    return 0; +} + +static inline int fdc_write_cmd (uint8_t cmd) +{ +    uint8_t status; + +    status = inb(FDC_MAIN_STATUS); +    if ((status & 0xC0) != 0x80) { +#if 0 +        ERROR("fdc_write_cmd: read data status != WRITE_CMD: %0x\n", +              status); +#endif +        return -1; +    } +    outb(FDC_WRITE_PORT, cmd); + +    return 0; +} + +static int fdc_reset (void) +{ +    uint8_t dor; +     +    dor = inb(FDC_DOR_PORT); +    /* Stop motors & enter reset */ +    dor &= ~0x34; +    outb(FDC_DOR_PORT, dor); +    usleep(1000); +    /* leave reset state */ +    dor |= 0x04; +    outb(FDC_DOR_PORT, dor); +    usleep(1000); + +    return 0; +} + +static int fdc_recalibrate (int drv) +{ +    uint8_t data[2]; + +    if (drv == 0) +        data[0] = 0; +    else +        data[0] = 1; +    if (fdc_write_cmd(0x07) < 0) { +        ERROR("fdc_recalibrate != WRITE_CMD\n"); +        return -1; +    } +    if (fdc_write_cmd(data[0]) < 0) { +        ERROR("fdc_recalibrate data\n"); +        return -1; +    } +    /* Wait for drive to go out of busy state */ +    while ((inb(FDC_MAIN_STATUS) & 0x0F) != 0x00) +        continue; +    /* Check command status */ +    if (fdc_write_cmd(0x08) < 0) { +        ERROR("fdc_recalibrate != SENSE_INTERRUPT_STATUS\n"); +        return -1; +    } +    data[0] = inb(FDC_READ_PORT); +    data[1] = inb(FDC_READ_PORT); +    if (data[0] & 0xD0) { +        /* recalibrate / seek failed */ +        return -1; +    } +    /* Status should be WRITE_CMD right now */ +    if ((inb(FDC_MAIN_STATUS) & 0xD0) != 0x80) { +        ERROR("fdc_recalibrate status\n"); +        return -1; +    } + +    return 0; +} + +static int fdc_start_read (int drv, uint8_t hd, uint8_t trk, uint8_t sect, +                           int mt) +{ +    uint8_t fdc_cmd[9], status; +    int i; +     +    fdc_cmd[0] = 0x66; +    if (mt) +        fdc_cmd[0] |= 0x80; +    fdc_cmd[1] = 0x00; +    if (hd) +        fdc_cmd[1] |= 0x04; +    if (drv) +        fdc_cmd[1] |= 0x01; +    fdc_cmd[2] = trk; +    fdc_cmd[3] = hd; +    fdc_cmd[4] = sect; +    fdc_cmd[5] = 0x02; +    fdc_cmd[6] = 0x12; +    fdc_cmd[7] = 0x00; +    fdc_cmd[8] = 0x00; +    for (i = 0; i < (int)sizeof(fdc_cmd); i++) { +        status = inb(FDC_MAIN_STATUS); +        if ((status & 0xC0) != 0x80) { +            ERROR("fdc_start_read: write command status != WRITE_CMD: %0x\n", +                  status); +            return -1; +        } +        outb(FDC_WRITE_PORT, fdc_cmd[i]); +    } +    status = inb(FDC_MAIN_STATUS); +    if ((status & 0xD0) != 0xD0) { +        ERROR("fdc_read_sector: status != READ_DATA: %0x\n", status); +        return -1; +    } + +    return 0; +} + +/* FDC driver entry points */ +static int fdc_initialize (bloc_device_t *bd, int device) +{ +    uint8_t fifo[10]; +#if 0 +    uint32_t tape; +#endif +    int status; + +    if (device > 1) +        return -1; +    DPRINTF("Init FDC drive %d\n", device); +    /* Manage 1.44 MB disks only, for now */ +    bd->drv = device; +    bd->heads = 2; +    bd->trks = 80; +    bd->sects = 18; +    bd->seclen = 512; +    bd->tmp = -1; +    fdc_reset(); +    /* Dump registers */ +    if (fdc_write_cmd(0x0E) < 0) { +#if 0 +        ERROR("fdc_reset: DUMP_REGISTER != WRITE_CMD\n"); +#endif +        return -1; +    } +    if (fdc_read_data(fifo, 10) < 0) { +        ERROR("fdc_reset: DUMP_REGISTER data\n"); +        return -1; +    } +    /* SPECIFY: be sure we're not in DMA mode */ +    if (fdc_write_cmd(0x03) < 0) { +        ERROR("fdc_reset: SPECIFY != WRITE_CMD\n"); +        return -1; +    } +    if (fdc_write_cmd(fifo[4]) < 0 || fdc_write_cmd(fifo[5] | 0x01)) { +        ERROR("fdc_reset: SPECIFY data\n"); +        return -1; +    } +    /* Status should be WRITE_CMD right now */ +    status = inb(FDC_MAIN_STATUS); +    if ((status & 0xD0) != 0x80) { +        ERROR("fdc_initialise: read data status != WRITE_CMD: %0x\n", +               status); +        return -1; +    } +    /* RECALIBRATE */ +    if (fdc_recalibrate(device) < 0) { +        printf("fd%c: no floppy inserted\n", 'a' + device); +        return -1; +    } +    printf("fd%c initialized\n", 'a' + device); + +    return 0; +} + +static int fdc_read_sector (bloc_device_t *bd, void *buffer, int secnum) +{ +    int head, cyl, sect; +    int need_restart; + +#if DEBUG_BIOS > 1 +    printf("Read fdc sector: %d at: %0x\n", secnum, (uint32_t)buffer); +    bd_sect2CHS(bd, secnum, &cyl, &head, §); +    printf("cur: %d hd: %d trk: %d sect: %d\n", bd->bloc, head, cyl, sect); +#endif +    if (secnum != bd->tmp) { +        if (fdc_reset() < 0 || fdc_recalibrate(bd->drv) < 0) +            return -1; +        need_restart = 1; +    } else { +        need_restart = 0; +    } +    bd_sect2CHS(bd, secnum, &cyl, &head, §); +    if (need_restart == 1 || (head == 0 && sect == 1)) { +        if (need_restart == 0) { +            /* Read the status */ +            uint8_t tmp[7]; + +            while (fdc_read_data(tmp, 1) == 0) +                continue; +        } +#if !defined (DEBUG_BIOS) +        printf("."); +#endif +        if (fdc_start_read(bd->drv, head, cyl, sect, 1) < 0) +            return -1; +        bd->bloc = secnum; +        bd->tmp = secnum; +    } +    if (fdc_read_data(buffer, bd->seclen) < 0) +        return -1; +    bd->tmp++; + +    return bd->seclen; +} + +/* SCSI subset */ +/* SPC: primary commands, common to all devices */ +static int spc_inquiry_req (void *buffer, int maxlen) +{ +    uint8_t *p; +     +    p = buffer; +    p[0] = 0x12; +    /* No page code */ +    p[1] = 0x00; +    p[2] = 0x00; +    p[3] = maxlen >> 8; +    p[4] = maxlen; +    p[5] = 0x00; + +    return 6; +} + +static int spc_inquiry_treat (void *buffer, int len) +{ +    const uint8_t *p; + +    if (len < 36) +        return -1; +    p = buffer; +    if ((p[0] >> 5) != 0) { +        ERROR("Logical unit not ready\n"); +        return -1; +    } + +    return p[0] & 0x1F; +} + +static int spc_test_unit_ready_req (void *buffer) +{ +    uint8_t *p; +     +    p = buffer; +    p[0] = 0x00; +    p[1] = 0x00; +    p[2] = 0x00; +    p[3] = 0x00; +    p[4] = 0x00; +    p[5] = 0x00; + +    return 6; +} + +/* MMC: multimedia commands */ +static int mmc_read_capacity_req (void *buffer) +{ +    uint8_t *p; +     +    p = buffer; +    p[0] = 0x25; +    p[1] = 0x00; +    p[2] = 0x00; +    p[3] = 0x00; +    p[4] = 0x00; +    p[5] = 0x00; +    p[6] = 0x00; +    p[7] = 0x00; +    p[8] = 0x00; +    p[9] = 0x00; + +    return 10; +} + +static int mmc_read_capacity_treat (uint32_t *size, uint32_t *ssize, +                                    const void *buffer, int len) +{ +    const uint8_t *p; +     +    if (len != 8) +        return -1; +    p = buffer; +    /* Only handle CDROM address mode for now */ +    *size = ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + 1; +    *ssize = ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); + +    return 0; +} + +static int mmc_read12_req (void *buffer, uint32_t LBA, uint32_t size) +{ +    uint8_t *p; +     +    p = buffer; +    p[0] = 0xA8; +    p[1] = 0x00; +    p[2] = LBA >> 24; +    p[3] = LBA >> 16; +    p[4] = LBA >> 8; +    p[5] = LBA; +    p[6] = size >> 24; +    p[7] = size >> 16; +    p[8] = size >> 8; +    p[9] = size; +    p[10] = 0x00; +    p[11] = 0x00; + +    return 12; +} + +/* IDE disk driver */ +static uint32_t ide_base[2] = { 0x1F0, 0x170, }; +static uint32_t ide_base2[2] = { 0x3F6, 0x376, }; + +typedef struct ide_ops_t { +    uint8_t (*port_read)(bloc_device_t *bd, int port); +    void (*port_write)(bloc_device_t *bd, int port, uint8_t value); +    uint32_t (*data_readl)(bloc_device_t *bd); +    void (*data_writel)(bloc_device_t *bd, uint32_t val); +    void (*control_write)(bloc_device_t *bd, uint32_t val); +    uint32_t base[4]; +#ifdef USE_OPENFIRMWARE +    void *OF_private[2]; +#endif +} ide_ops_t; + +/* IDE ISA access */ +static uint8_t ide_isa_port_read (bloc_device_t *bd, int port) +{ +    return inb(bd->io_base + port); +} + +static void ide_isa_port_write (bloc_device_t *bd, int port, uint8_t value) +{ +    outb(bd->io_base + port, value); +} + +static uint32_t ide_isa_data_readl (bloc_device_t *bd) +{ +    return inl(bd->io_base); +} + +static void ide_isa_data_writel (bloc_device_t *bd, uint32_t val) +{ +    return outl(bd->io_base, val); +} + +static void ide_isa_control_write (bloc_device_t *bd, uint32_t val) +{ +    outb(bd->tmp, val); +} + +static ide_ops_t ide_isa_ops = { +    &ide_isa_port_read, +    &ide_isa_port_write, +    &ide_isa_data_readl, +    &ide_isa_data_writel, +    &ide_isa_control_write, +    { 0, }, +#ifdef USE_OPENFIRMWARE +    { NULL, }, +#endif +}; + +static ide_ops_t *ide_pci_ops; + +/* IDE PCI access for pc */ +static uint8_t ide_pci_port_read (bloc_device_t *bd, int port) +{ +    uint8_t value; +    value = inb(bd->io_base + port); +    return value; +} + +static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value) +{ +    outb(bd->io_base + port, value); +} + +static uint32_t ide_pci_data_readl (bloc_device_t *bd) +{ +    return inl(bd->io_base); +} + +static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val) +{ +    outl(bd->io_base, val); +} + +static void ide_pci_control_write (bloc_device_t *bd, uint32_t val) +{ +    outb(bd->tmp + 2, val); +} + +static ide_ops_t ide_pci_pc_ops = { +    &ide_pci_port_read, +    &ide_pci_port_write, +    &ide_pci_data_readl, +    &ide_pci_data_writel, +    &ide_pci_control_write, +    { 0, }, +#ifdef USE_OPENFIRMWARE +    { NULL, }, +#endif +}; + +void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, +                          uint32_t io_base2, uint32_t io_base3, +                          void *OF_private0, void *OF_private1) +{ +    if (ide_pci_ops == NULL) { +        ide_pci_ops = malloc(sizeof(ide_ops_t)); +        if (ide_pci_ops == NULL) +            return; +        memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t)); +    } +    if ((io_base0 != 0 || io_base1 != 0) && +        ide_pci_ops->base[0] == 0 && ide_pci_ops->base[2] == 0) { +        ide_pci_ops->base[0] = io_base0; +        ide_pci_ops->base[2] = io_base1; +#ifdef USE_OPENFIRMWARE +        ide_pci_ops->OF_private[0] = OF_private0; +#endif +    } +    if ((io_base2 != 0 || io_base3 != 0) && +        ide_pci_ops->base[1] == 0 && ide_pci_ops->base[3] == 0) { +        ide_pci_ops->base[1] = io_base2; +        ide_pci_ops->base[3] = io_base3; +#ifdef USE_OPENFIRMWARE +        ide_pci_ops->OF_private[1] = OF_private1; +#endif +    } +} + +/* IDE PCI access for pmac */ +static uint8_t ide_pmac_port_read (bloc_device_t *bd, int port) +{ +    uint32_t addr; + +    if (port != 8) +        addr = bd->io_base + (port << 4); +    else +        addr = bd->io_base + 0x160; +    eieio(); +     +    return *((uint8_t *)addr); +} + +static void ide_pmac_port_write (bloc_device_t *bd, int port, uint8_t value) +{ +    uint32_t addr; + +    if (port != 8) +        addr = bd->io_base + (port << 4); +    else +        addr = bd->io_base + 0x160; +    *((uint8_t *)addr) = value; +    eieio(); +} + +static uint32_t ide_pmac_data_readl (bloc_device_t *bd) +{ +    eieio(); +    return ldswap32((uint32_t *)bd->io_base); +    //    return *((uint32_t *)bd->io_base); +} + +static void ide_pmac_data_writel (bloc_device_t *bd, uint32_t val) +{ +    //    *((uint32_t *)bd->io_base) = val; +    stswap32((uint32_t *)bd->io_base, val); +    eieio(); +} + +static void ide_pmac_control_write (bloc_device_t *bd, uint32_t val) +{ +    ide_pmac_port_write(bd, 8, val); +} + +static ide_ops_t ide_pmac_ops = { +    &ide_pmac_port_read, +    &ide_pmac_port_write, +    &ide_pmac_data_readl, +    &ide_pmac_data_writel, +    &ide_pmac_control_write, +    { 0, }, +#ifdef USE_OPENFIRMWARE +    { NULL, }, +#endif +}; + +void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1, +                            unused void *OF_private) +{ +    if (ide_pci_ops == NULL) { +        ide_pci_ops = malloc(sizeof(ide_ops_t)); +        if (ide_pci_ops == NULL) +            return; +        memcpy(ide_pci_ops, &ide_pmac_ops, sizeof(ide_ops_t)); +    } +    if (io_base0 != 0 && ide_pci_ops->base[0] == 0) { +        ide_pci_ops->base[0] = io_base0; +#ifdef USE_OPENFIRMWARE +        ide_pci_ops->OF_private[0] = OF_private; +#endif +    } +    if (io_base1 != 0 && ide_pci_ops->base[1] == 0) { +        ide_pci_ops->base[1] = io_base1; +#ifdef USE_OPENFIRMWARE +        ide_pci_ops->OF_private[1] = OF_private; +#endif +    } +} + +static inline uint8_t ide_port_read (bloc_device_t *bd, int port) +{ +    ide_ops_t *ops = bd->private; +     +    return ops->port_read(bd, port); +} + +static inline void ide_port_write (bloc_device_t *bd, int port, uint8_t value) +{ +    ide_ops_t *ops = bd->private; +     +    ops->port_write(bd, port, value); +} + +static inline uint32_t ide_data_readl (bloc_device_t *bd) +{ +    ide_ops_t *ops = bd->private; +     +    return ops->data_readl(bd); +} + +static inline void ide_data_writel (bloc_device_t *bd, uint32_t val) +{ +    ide_ops_t *ops = bd->private; +     +    return ops->data_writel(bd, val); +} + +static inline void ide_control_write (bloc_device_t *bd, uint32_t val) +{ +    ide_ops_t *ops = bd->private; +     +    return ops->control_write(bd, val); +} + +static int ide_reset (bloc_device_t *bd) +{ +    int status, is_cdrom, lcyl; + +    ide_control_write(bd, 0x04); +    status = ide_port_read(bd, 0x07); +    if (status != 0x90) { +        return -1; +    } +    ide_control_write(bd, 0x00); +    if (bd->drv == 0) +        ide_port_write(bd, 0x06, 0xa0); +    else +        ide_port_write(bd, 0x06, 0xb0); + +    lcyl = ide_port_read(bd, 0x04); +    switch (lcyl) { +    case 0x00: +        /* IDE drive */ +        is_cdrom = 0; +        break; +    case 0x14: +        /* ATAPI device */ +        is_cdrom = 1; +        break; +    default: +        return -1; +    } + +    return is_cdrom; +} + +static void atapi_pad_req (void *buffer, int len); +static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer, +                            int maxlen); +static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum); + +static int ide_initialize (bloc_device_t *bd, int device) +{ +#ifdef USE_OPENFIRMWARE +    void *OF_parent; +#endif +    const unsigned char *devname, *devtype, *alias; +    uint32_t atapi_buffer[9]; +    uint32_t size; +    int status, base, is_cdrom, len, i; + +    if (device > 1) +        base = 1; +    else +        base = 0; +    if (ide_pci_ops != NULL) { +        bd->private = ide_pci_ops; +        bd->io_base = ide_pci_ops->base[base]; +        bd->tmp = ide_pci_ops->base[2 + base]; +        if (bd->io_base == 0x00000000 || bd->io_base == 0xFFFFFFFF) { +            ERROR("No IDE drive %c\n", device); +            return -1; +        } +    } else { +        bd->private = &ide_isa_ops; +        bd->io_base = ide_base[base]; +        bd->tmp = ide_base2[base]; +    } +    bd->drv = device & 1; +    DPRINTF("Init IDE drive %d-%d (%d)\n", base, bd->drv, device); +    is_cdrom = ide_reset(bd); +    printf("ide%d: drive %d: ", +           (device >> 1), bd->drv); +    switch(is_cdrom) { +    case 0: +        printf("Hard Disk\n"); +        devname = "disk"; +        devtype = "hd"; +        alias = "hd"; +        break; +    case 1: +        printf("CD-ROM\n"); +        devname = "cdrom"; +        devtype = "cdrom"; +        alias = "cd"; +        break; +    default: +        printf("none\n"); +        devname = NULL; +        devtype = NULL; +        alias = NULL; +        break; +    } +    if (is_cdrom < 0) +        return -1; +#ifdef USE_OPENFIRMWARE +    /* Register disk into OF tree */ +    OF_parent = ide_pci_ops->OF_private[base]; +    if (OF_parent != NULL) { +        bd->OF_private = OF_blockdev_register(OF_parent, bd, devtype, +                                              devname, bd->drv, alias); +    } +#endif +    /* Select drive */ +    if (bd->drv == 0) +        ide_port_write(bd, 0x06, 0x40); +    else +        ide_port_write(bd, 0x06, 0x50); +    /* WIN_DEVICE_RESET */ +    ide_port_write(bd, 0x07, 0x08); +    status = ide_port_read(bd, 0x07); +    if (is_cdrom) { +        if (status != 0x00) { +            ERROR("WIN_DEVICE_RESET : status %0x != 0x00 (is_cdrom: %d)\n", +                  status, is_cdrom); +            return -1; +        } +        /* TEST_UNIT_READY */ +        DPRINTF("TEST_UNIT_READY\n"); +        len = spc_test_unit_ready_req(&atapi_buffer); +        atapi_pad_req(&atapi_buffer, len); +        ide_port_write(bd, 0x07, 0xA0); +        status = ide_port_read(bd, 0x07); +        if (status != 0x08) { +            ERROR("ATAPI TEST_UNIT_READY : status %0x != 0x08\n", status); +            /*return -1;*/ /* fails to boot from cdrom? */ +        } +        for (i = 0; i < 3; i++) { +            ide_data_writel(bd, ldswap32(&atapi_buffer[i])); +        } +        status = ide_port_read(bd, 0x07); +        if (status != 0x40) { +            ERROR("ATAPI TEST_UNIT_READY : status %0x != 0x40\n", status); +            return -1; +        } +        /* INQUIRY */ +        DPRINTF("INQUIRY\n"); +        len = spc_inquiry_req(&atapi_buffer, 36); +        atapi_pad_req(&atapi_buffer, len); +        atapi_make_req(bd, atapi_buffer, 36); +        status = ide_port_read(bd, 0x07); +        if (status != 0x48) { +            ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status); +            return -1; +        } +        for (i = 0; i < 9; i++) +            stswap32(&atapi_buffer[i], ide_data_readl(bd)); +        if (spc_inquiry_treat(&atapi_buffer, 36) != 0x05) { +            ERROR("Only ATAPI CDROMs are handled for now\n"); +            return -1; +        } +        /* READ_CAPACITY */ +        DPRINTF("READ_CAPACITY\n"); +        len = mmc_read_capacity_req(&atapi_buffer); +        atapi_pad_req(&atapi_buffer, len); +        atapi_make_req(bd, atapi_buffer, 8); +        status = ide_port_read(bd, 0x07); +        if (status != 0x48) { +            ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status); +            return -1; +        } +        for (i = 0; i < 2; i++) +            stswap32(&atapi_buffer[i], ide_data_readl(bd)); +        if (mmc_read_capacity_treat(&size, &bd->seclen, +                                    &atapi_buffer, 8) != 0) { +            ERROR("Error retrieving ATAPI CDROM capacity\n"); +            return -1; +        } +        bd->read_sector = &atapi_read_sector; +        DPRINTF("ATAPI: size=%d ssize=%d\n", size, bd->seclen); +    } else { +        if (status != 0x41) { +            ERROR("WIN_DEVICE_RESET : status %0x != 0x41 (is_cdrom: %d)\n", +                  status, is_cdrom); +            return -1; +        } +        /* WIN_READ_NATIVE_MAX */ +        ide_port_write(bd, 0x07, 0xF8); +        status = ide_port_read(bd, 0x07); +        if (status != 0x40) { +            ERROR("WIN_READ_NATIVE_MAX : status %0x != 0x40\n", status); +            return -1; +        } +        /* Retrieve parameters */ +        size = (ide_port_read(bd, 0x06) & ~0xF0) << 24; +        size |= ide_port_read(bd, 0x05) << 16; +        size |= ide_port_read(bd, 0x04) << 8; +        size |= ide_port_read(bd, 0x03); +        bd->seclen = 512; +    }  +    bd->heads = 16; +    bd->sects = 64; +    bd->trks = (size + (16 * 64 - 1)) >> 10; +    +    return 0; +} + +static void atapi_pad_req (void *buffer, int len) +{ +    uint8_t *p; + +    p = buffer; +    memset(p + len, 0, 12 - len); +} + +static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer, +                            int maxlen) +{ +    int i; +    /* select drive */ +    if (bd->drv == 0) +        ide_port_write(bd, 0x06, 0x40); +    else +        ide_port_write(bd, 0x06, 0x50); +    ide_port_write(bd, 0x04, maxlen & 0xff); +    ide_port_write(bd, 0x05, (maxlen >> 8) & 0xff); +    ide_port_write(bd, 0x07, 0xA0); +    for (i = 0; i < 3; i++) +        ide_data_writel(bd, ldswap32(&buffer[i])); +} + +static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum) +{ +    uint32_t atapi_buffer[4]; +    uint8_t *p; +    uint32_t status, value; +    int i, len; + +    len = mmc_read12_req(atapi_buffer, secnum, 1); +    atapi_pad_req(&atapi_buffer, len); +    atapi_make_req(bd, atapi_buffer, bd->seclen); +    status = ide_port_read(bd, 0x07); +    if (status != 0x48) { +        ERROR("ATAPI READ12 : status %0x != 0x48\n", status); +        return -1; +    } +    p = buffer; +    for (i = 0; i < bd->seclen; i += 4) { +        value = ide_data_readl(bd); +        *p++ = value; +        *p++ = value >> 8; +        *p++ = value >> 16; +        *p++ = value >> 24; +    } +    status = ide_port_read(bd, 0x07); +    if (status != 0x40) { +        ERROR("ATAPI READ12 done : status %0x != 0x48\n", status); +        return -1; +    } + +    return 0; +} + +static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum) +{ +    uint32_t value; +    uint8_t *p; +    int status; +    int i; +     +    bd->drv &= 1; +    //    printf("ide_read_sector: drv %d secnum %d buf %p\n", bd->drv, secnum, buffer); +    /* select drive & set highest bytes */ +    if (bd->drv == 0) +        ide_port_write(bd, 0x06, 0x40 | (secnum >> 24)); +    else +        ide_port_write(bd, 0x06, 0x50 | (secnum >> 24)); +    /* Set hcyl */ +    ide_port_write(bd, 0x05, secnum >> 16); +    /* Set lcyl */ +    ide_port_write(bd, 0x04, secnum >> 8); +    /* Set sect */ +    ide_port_write(bd, 0x03, secnum); +    /* Read 1 sector */ +    ide_port_write(bd, 0x02, 1); +    /* WIN_READ */ +    ide_port_write(bd, 0x07, 0x20); +    status = ide_port_read(bd, 0x07); +    //    DPRINTF("ide_read_sector: try %d\n", secnum); +    if (status != 0x58) { +        ERROR("ide_read_sector: %d status %0x != 0x58\n", secnum, status); +        return -1; +    } +    /* Get data */ +    p = buffer; +    for (i = 0; i < bd->seclen; i += 4) { +        value = ide_data_readl(bd); +        *p++ = value; +        *p++ = value >> 8; +        *p++ = value >> 16; +        *p++ = value >> 24; +    } +    status = ide_port_read(bd, 0x07); +    if (status != 0x50) { +        ERROR("ide_read_sector 6: status %0x != 0x50\n", status); +        return -1; +    } + +    return bd->seclen; +} + +/* Memory image access driver */ +static int mem_initialize (bloc_device_t *bd, int device) +{ +    bd->seclen = 512; +    bd->private = NULL; +    bd->heads = 1; +    bd->sects = 1; +    bd->trks = 1; + +    return device == 'm'; +} + +static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum) +{ +    if (buffer != (char *)bd->private + (bd->seclen * secnum)) { +        memmove(buffer, +                (char *)bd->private + (bd->seclen * secnum), bd->seclen); +    } + +    return bd->seclen; +} + +static int mem_ioctl (bloc_device_t *bd, int func, void *args) +{ +    uint32_t *u32; +    int ret; + +    switch (func) { +    case MEM_SET_ADDR: +        bd->private = args; +        ret = 0; +        break; +    case MEM_SET_SIZE: +        u32 = args; +        bd->trks = (*u32 + bd->seclen - 1) / bd->seclen + 1; +    default: +        ret = -1; +        break; +    } + +    return ret; +} diff --git a/roms/openhackware/src/boot.S b/roms/openhackware/src/boot.S new file mode 100644 index 00000000..0519b7eb --- /dev/null +++ b/roms/openhackware/src/boot.S @@ -0,0 +1,100 @@ +/*  + *	<boot.S> + *	 + *     First stage BIOS loader for Open Hack'Ware. + *    + *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) + *    + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + *    + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* + * setup one RAM bank then + * relocate the one page BIOS second stage into RAM. + * + * We consider that we know nothing about the CPU state + * at the time we enter this code. + * + */ + +#define ASSEMBLY_CODE +#include "bios.h" + +.section .rom, "ax" +.align 2 +_boot_start: +        /* Minimal setup */ +        li    r0, 0                                          ; +        /* r11 is _boot_start address */ +        mflr    r11                                          ; +        addi    r11, r11, (_boot_start - _start - 4)         ; +        /* Disable MMU and interruptions */ +        addi    r12, r11, (_boot_no_mmu - _boot_start)       ; +        mtspr   SRR0, r12                                    ; +        mfmsr   r12                                          ; +        lis     r13, 0x0004                                  ; +        ori     r13, r13, 0xEF71                             ; +        andc    r15, r12, r13                                ; +        mtspr   SRR1, r12                                    ; +        rfi                                                  ; +_boot_no_mmu: +        /* TODO: initialize physical RAM (we need at least one page) +         * before doing anything else. +         * This may be machine dependent code. +         */ +_boot_copy: +        /* Copy the second stage bootloader into RAM +         * We may need a tiny driver if we need to boot from special device +         * (ie disc-on-chip, ...) +         */ +        lis    r12, (VECTORS_SIZE / 4)@h                     ; +        ori    r12, r12, (VECTORS_SIZE / 4)@l                ; +        mtctr  r12                                           ; +        clrrwi r12, r11, BIOS_IMAGE_BITS                     ; +        addis  r3, r12, VECTORS_SIZE@h                       ; +        addi   r3, r3, VECTORS_SIZE@l                        ; +        subi   r12, r12, 4                                   ; +        lis    r13, VECTORS_BASE@h                           ; +        ori    r13, r13, VECTORS_BASE@l                      ; +        mtlr   r13                                           ; +        subi   r13, r13, 4                                   ; +_boot_copy_loop: +        lwzu   r14, 4(r12)                                   ; +        stwu   r14, 4(r13)                                   ; +        bdnz   _boot_copy_loop                               ; +        /* Synchronize the whole execution context */ +        addi    r12, r11, (_boot_sync - _boot_start)         ; +        mtspr   SRR0, r12                                    ; +        mfmsr   r12                                          ; +        mtspr   SRR1, r12                                    ; +        rfi                                                  ; +_boot_sync: +        /* All done, jump into the loaded code */ +        blrl                                                 ; +        /* If we ever return, reboot */ +        b _start                                             ; + +.space BOOT_SIZE - 4 - (. - _boot_start), 0xFF +/* Reset entry point */ +        . = 0x1FC +_start: +        bl _boot_start                                       ; diff --git a/roms/openhackware/src/boot.ld b/roms/openhackware/src/boot.ld new file mode 100644 index 00000000..57070ee9 --- /dev/null +++ b/roms/openhackware/src/boot.ld @@ -0,0 +1,45 @@ +/*  + *   <boot.ld> + *       + *   First stage BIOS loader for Open Hack'Ware linker script. + *    + *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) + *    + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +OUTPUT_ARCH(powerpc:common) + +MEMORY +{ +        /* NOTE: some old ld do not support wrapping to zero,  +           so we set a dummy address different from 0xFFFFFE00 */ +        rom (rx) : ORIGIN = 0xEFFFFE00, LENGTH = 512 +} + +SECTIONS +{ +        .rom      : { *(.rom)     } > rom +        /DISCARD/ : { *(.text)    } +        /DISCARD/ : { *(.rodata)  } +        /DISCARD/ : { *(.data)    } +        /DISCARD/ : { *(.bss)     } +        /DISCARD/ : { *(.sbss)    } +        /DISCARD/ : { *(.sdata)   } +        /DISCARD/ : { *(.sdata2)  } +        /DISCARD/ : { *(.stab)    } +        /DISCARD/ : { *(.stabstr) } +        /DISCARD/ : { *(.comment) } +        /DISCARD/ : { *(.note)    } +} diff --git a/roms/openhackware/src/bootinfos.c b/roms/openhackware/src/bootinfos.c new file mode 100644 index 00000000..60f85a6b --- /dev/null +++ b/roms/openhackware/src/bootinfos.c @@ -0,0 +1,282 @@ +/* + * <bootinfos.c> + * + * Generate boot informations (bootinfos for Linux and residual data). + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include "bios.h" + +#define BI_FIRST		0x1010  /* first record - marker */ +#define BI_LAST			0x1011	/* last record - marker */ +#define BI_CMD_LINE		0x1012 +#define BI_BOOTLOADER_ID	0x1013 +#define BI_INITRD		0x1014 +#define BI_SYSMAP		0x1015 +#define BI_MACHTYPE		0x1016 +#define BI_MEMSIZE		0x1017 +#define BI_BOARD_INFO		0x1018 + +static inline void put_long (void *addr, uint32_t l) +{ +    char *pos = addr; +    pos[0] = (l >> 24) & 0xFF; +    pos[1] = (l >> 16) & 0xFF; +    pos[2] = (l >> 8) & 0xFF; +    pos[3] = l & 0xFF; +} + +static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, +                               void *data) +{ +    char *pos = addr; + +    put_long(pos, tag); +    pos += 4; +    put_long(pos, size + 8); +    pos += 4; +    memcpy(pos, data, size); +    pos += size; + +    return pos; +} + +void prepare_bootinfos (void *p, uint32_t memsize, +                        void *cmdline, void *initrd, uint32_t initrd_size) +{ +    uint32_t tmpi[2]; + +    /* BI_FIRST */ +    p = set_bootinfo_tag(p, BI_FIRST, 0, NULL); +    /* BI_CMD_LINE */ +    if (cmdline != 0) { +        p = set_bootinfo_tag(p, BI_CMD_LINE, strlen(cmdline), cmdline); +    } else { +        p = set_bootinfo_tag(p, BI_CMD_LINE, 0, NULL); +    } +    /* BI_MEM_SIZE */ +    p = set_bootinfo_tag(p, BI_MEMSIZE, 4, &memsize); +    /* BI_INITRD */ +    tmpi[0] = (uint32_t)initrd; +    tmpi[1] = initrd_size; +    p = set_bootinfo_tag(p, BI_INITRD, 8, tmpi); +    /* BI_LAST */ +    p = set_bootinfo_tag(p, BI_LAST, 0, 0); +} + +/* Residual data */ +#define MAX_CPUS 16 +#define MAX_SEGS 64 +#define MAX_MEMS 64 +#define MAX_DEVS 256 + +typedef struct vital_t { +    /* Motherboard dependents */ +    uint8_t model[32]; +    uint8_t serial[64]; +    uint16_t version; +    uint16_t revision; +    uint32_t firmware; +    uint32_t NVRAM_size; +    uint32_t nSIMMslots; +    uint32_t nISAslots; +    uint32_t nPCIslots; +    uint32_t nPCMCIAslots; +    uint32_t nMCAslots; +    uint32_t nEISAslots; +    uint32_t CPUHz; +    uint32_t busHz; +    uint32_t PCIHz; +    uint32_t TBdiv; +    /* CPU infos */ +    uint32_t wwidth; +    uint32_t page_size; +    uint32_t ChBlocSize; +    uint32_t GrSize; +    /* Cache and TLBs */ +    uint32_t cache_size; +    uint32_t cache_type; +    uint32_t cache_assoc; +    uint32_t cache_lnsize; +    uint32_t Icache_size; +    uint32_t Icache_assoc; +    uint32_t Icache_lnsize; +    uint32_t Dcache_size; +    uint32_t Dcache_assoc; +    uint32_t Dcache_lnsize; +    uint32_t TLB_size; +    uint32_t TLB_type; +    uint32_t TLB_assoc; +    uint32_t ITLB_size; +    uint32_t ITLB_assoc; +    uint32_t DTLB_size; +    uint32_t DTLB_assoc; +    void *ext_vital; +} vital_t; + +typedef struct PPC_CPU_t { +    uint32_t pvr; +    uint32_t serial; +    uint32_t L2_size; +    uint32_t L2_assoc; +} PPC_CPU_t; + +typedef struct map_t { +    uint32_t usage; +    uint32_t base; +    uint32_t count; +} map_t; + +typedef struct PPC_mem_t { +    uint32_t size; +} PPC_mem_t; + +typedef struct PPC_device_t { +    uint32_t busID; +    uint32_t devID; +    uint32_t serial; +    uint32_t flags; +    uint32_t type; +    uint32_t subtype; +    uint32_t interface; +    uint32_t spare; +} PPC_device_t; + +typedef struct residual_t { +    uint32_t  length; +    uint16_t  version; +    uint16_t  revision; +    vital_t   vital; +    uint32_t  nCPUs; +    PPC_CPU_t CPUs[MAX_CPUS]; +    uint32_t  max_mem; +    uint32_t  good_mem; +    uint32_t  nmaps; +    map_t     maps[MAX_SEGS]; +    uint32_t  nmems; +    PPC_mem_t memories[MAX_MEMS]; +    uint32_t  ndevices; +    PPC_device_t devices[MAX_DEVS]; +    /* TOFIX: No PNP devices */ +} residual_t; + +void residual_build (void *p, uint32_t memsize, +                     uint32_t load_base, uint32_t load_size, +                     uint32_t last_alloc) +{ +    const unsigned char model[] = "Qemu\0PPC\0"; +    residual_t *res = p; +    int i; + +    if (res == NULL) +        return; +    res->length = sizeof(residual_t); +    res->version = 1; +    res->revision = 0; +    memcpy(res->vital.model, model, sizeof(model)); +    res->vital.version = 1; +    res->vital.revision = 0; +    res->vital.firmware = 0x1D1; +    res->vital.NVRAM_size = 0x2000; +    res->vital.nSIMMslots = 1; +    res->vital.nISAslots = 0; +    res->vital.nPCIslots = 0; +    res->vital.nPCMCIAslots = 0; +    res->vital.nMCAslots = 0; +    res->vital.nEISAslots = 0; +    res->vital.CPUHz = 200 * 1000 * 1000; +    res->vital.busHz = 100 * 1000 * 1000; +    res->vital.PCIHz = 33 * 1000 * 1000; +    res->vital.TBdiv = 1000; +    res->vital.wwidth = 32; +    res->vital.page_size = 4096; +    res->vital.ChBlocSize = 32; +    res->vital.GrSize = 32; +    res->vital.cache_size = 0; +    res->vital.cache_type = 0; /* No cache */ +    res->vital.cache_assoc = 8; /* Same as 601 */ +    res->vital.cache_lnsize = 32; +    res->vital.Icache_size = 0; +    res->vital.Icache_assoc = 8; +    res->vital.Icache_lnsize = 32; +    res->vital.Dcache_size = 0; +    res->vital.Dcache_assoc = 8; +    res->vital.Dcache_lnsize = 32; +    res->vital.TLB_size = 0; +    res->vital.TLB_type = 0; /* None */ +    res->vital.TLB_assoc = 2; +    res->vital.ITLB_size = 0; +    res->vital.ITLB_assoc = 2; +    res->vital.DTLB_size = 0; +    res->vital.DTLB_assoc = 2; +    res->vital.ext_vital = NULL; +    res->nCPUs = 1; +    res->CPUs[0].pvr = mfpvr(); +    res->CPUs[0].serial = 0; +    res->CPUs[0].L2_size = 0; +    res->CPUs[0].L2_assoc = 8; +    /* Memory infos */ +    res->max_mem = memsize; +    res->good_mem = memsize; +    /* Memory mappings */ +    /* First segment: firmware */ +    last_alloc = (last_alloc + 4095) & ~4095; +    res->maps[0].usage = 0x0007; +    res->maps[0].base  = 0x00000000; +    res->maps[0].count = last_alloc >> 12; +    i = 1; +    if (last_alloc != load_base) { +        /* Free memory between firmware and boot image */ +        res->maps[1].usage = 0x0010; +        res->maps[1].base = last_alloc >> 12; +        res->maps[1].count = (load_base - last_alloc) >> 12; +        i++; +    } +    /* Boot image */ +    load_size = (load_size + 4095) & ~4095; +    res->maps[i].usage = 0x0008; +    res->maps[i].base  = load_base >> 12; +    res->maps[i].count = load_size >> 12; +    i++; +    /* Free memory */ +    res->maps[i].usage = 0x0010; +    res->maps[i].base  = (load_base + load_size) >> 12; +    res->maps[i].count = (memsize >> 12) - res->maps[i].base; +    i++; +    /* ISA IO region : 8MB */ +    res->maps[i].usage = 0x0040; +    res->maps[i].base  = 0x80000000 >> 12; +    res->maps[i].count = 0x00800000 >> 12; +    i++; +    /* System registers : 8MB */ +    res->maps[i].usage = 0x0200; +    res->maps[i].base  = 0xBF800000 >> 12; +    res->maps[i].count = 0x00800000 >> 12; +    i++; +    /* System ROM : 64 kB */ +    res->maps[i].usage = 0x2000; +    res->maps[i].base  = 0xFFFF0000 >> 12; +    res->maps[i].count = 0x00010000 >> 12; +    i++; +    res->nmaps = i; +    /* Memory SIMMs */ +    res->nmems = 1; +    res->memories[0].size = memsize; +    /* Describe no devices */ +    res->ndevices = 0; +} diff --git a/roms/openhackware/src/char.c b/roms/openhackware/src/char.c new file mode 100644 index 00000000..4e74ac6a --- /dev/null +++ b/roms/openhackware/src/char.c @@ -0,0 +1,780 @@ +/* + * <char.c> + * + * Open Hack'Ware BIOS character devices drivers. + *  + *  Copyright (c) 2004-2005 Jocelyn Mayer + * + *  cuda driver: Copyright (c) 2004-2005 Fabrice Bellard + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "adb.h" + +//#define DEBUG_CHARDEV +//#define DEBUG_CUDA +//#define DEBUG_ADB + +#ifdef DEBUG_CHARDEV +#define CHARDEV_DPRINTF(fmt, args...) \ +do { dprintf("CHARDEV - %s: " fmt, __func__ , ##args); } while (0) +#else +#define CHARDEV_DPRINTF(fmt, args...) do { } while (0) +#endif + +/* Generic character device API */ +struct chardev_t { +    chardev_t *next; +    int type; +    cops_t *ops; +    void *private; +}; + +static chardev_t *char_devices; + +int chardev_register (int type, cops_t *ops, void *private) +{ +    chardev_t *dev, **cur; + +    CHARDEV_DPRINTF("Register char device of type %d\n", type); +    if (type > CHARDEV_LAST) +        return -1; +    dev = malloc(sizeof(chardev_t)); +    if (dev == NULL) +        return -1; +    dev->type = type; +    dev->ops = ops; +    dev->private = private; +    for (cur = &char_devices; *cur != NULL; cur = &((*cur)->next)) +        continue; +    *cur = dev; + +    return 0; +} + +int chardev_open (chardev_t *dev) +{ +    if (dev->ops == NULL) +        return -1; +    if (dev->ops->open == NULL) +        return 0; + +    return (*dev->ops->open)(dev->private); +} + +int chardev_close (chardev_t *dev) +{ +    if (dev->ops == NULL) +        return -1; +    if (dev->ops->close == NULL) +        return 0; + +    return (*dev->ops->close)(dev->private); +} + +int chardev_read (chardev_t *dev, void *buffer, int maxlen) +{ +    unsigned char *p; +    int len; +    int c; + +    if (dev->ops == NULL || dev->ops->read == NULL) +        return -1; + +    p = buffer; +    for (len = 0; len < maxlen; len++) { +        c = (*dev->ops->read)(dev->private); +        if (c < 0) +            break; +        *p++ = c; +    } + +    return len; +} + +int chardev_write (chardev_t *dev, const void *buffer, int maxlen) +{ +    const unsigned char *p; +    int len; +    int c; + +    if (dev->ops == NULL || dev->ops->write == NULL) +        return -1; + +    p = buffer; +    for (len = 0; len < maxlen; len++) { +        c = *p++; +        if ((*dev->ops->write)(dev->private, c) < 0) +            break; +    } + +    return len; +} + +int chardev_type (chardev_t *dev) +{ +    return dev->type; +} + +/* Console driver */ +static chardev_t *console_in_devs[17], *console_out_devs[17]; +static int console_last_in; + +int console_open (void) +{ +    chardev_t *cur; +    int i, j, n, register_outd; + +    i = 0; +    j = 0; +    n = 0; +    /* Check all character devices and register those which are usable +     * as IO for the console +     */ +    CHARDEV_DPRINTF("enter\n"); +    for (cur = char_devices; cur != NULL; cur = cur->next, n++) { +        register_outd = 0; +        switch (cur->type) { +        case  CHARDEV_SERIAL: +            CHARDEV_DPRINTF("one serial port\n"); +            register_outd = 1; +            /* No break here */ +        case CHARDEV_KBD: +            CHARDEV_DPRINTF("one input port %d %d\n", n, i); +            if (i < 16 && chardev_open(cur) == 0) { +                console_in_devs[i++] = cur; +            } +            if (!register_outd) +                break; +            /* No break here */ +        case CHARDEV_DISPLAY: +            CHARDEV_DPRINTF("one output port %d %d\n", n, j); +            if (j < 16 && chardev_open(cur) == 0) { +                console_out_devs[j++] = cur; +            } +            break; +        default: +            CHARDEV_DPRINTF("Skip device %d\n", n); +            break; +        } +    } +     +    return 0; +} + +int console_read (void *buffer, int maxlen) +{ +    chardev_t *cur; +    int i, in; + +    CHARDEV_DPRINTF("enter\n"); +    /* Get data from the first in device responding to us */ +    cur = console_in_devs[console_last_in]; +    for (i = console_last_in;;) { +        CHARDEV_DPRINTF("read from device %d\n", i); +        in = chardev_read(cur, buffer, maxlen); +        if (in > 0) { +            console_last_in = i; +#if 0 +            printf("Read %d chars '%c'...\n", in, *((char *)buffer)); +#endif +            return in; +        } +        cur = console_in_devs[++i]; +        if (cur == NULL) { +            i = 0; +            cur = console_in_devs[0]; +        } +        if (i == console_last_in || cur == NULL) +            break; +    } +    console_last_in = i; +    CHARDEV_DPRINTF("out\n"); + +    return 0; +} + +int console_write (const void *buffer, int len) +{ +    chardev_t *cur; +    int i, out, max; + +    /* Write data to all devices */ +    max = 0; +    for (i = 0; i < 16; i++) { +        cur = console_out_devs[i]; +        if (cur == NULL) +            break; +        out = chardev_write(cur, buffer, len); +        if (out > max) +            max = out; +    } + +    return max; +} + +void console_close (void) +{ +    chardev_t *cur; +    int i; + +    for (i = 0; i < 16; i++) { +        cur = console_out_devs[i]; +        if (cur == NULL) +            break; +        chardev_close(cur); +        console_out_devs[i] = NULL; +    } +} + +/* PC serial port "driver" */ +#define PC_SERIAL_LSR_OFFSET (5) +typedef struct pc_serial_t { +    uint16_t base; +} pc_serial_t; + +static int pc_serial_open (unused void *private) +{ +    return 0; +} + +static int pc_serial_writeb (void *private, int data) +{ +    pc_serial_t *serial = private; + +    /* Wait for the FIFO to be ready to accept more chars. +     * Note: this is completely buggy and would never work on real hardware, +     *       as the serial port (especialy the FIFO) has not been programmed +     *       anywhere before ! +     */ +    if (!(inb(serial->base + PC_SERIAL_LSR_OFFSET) & 0x20)) +        usleep(100); +    outb(serial->base, data); + +    return 0; +} + +static int pc_serial_readb (void *private) +{ +    pc_serial_t *serial = private; + +    if (!(inb(serial->base + PC_SERIAL_LSR_OFFSET) & 0x01)) +        return -1; + +    return inb(serial->base); +} + +static int pc_serial_close (unused void *private) +{ +    return 0; +} + +static cops_t pc_serial_ops = { +    .open = &pc_serial_open, +    .read = &pc_serial_readb, +    .write = &pc_serial_writeb, +    .close = &pc_serial_close, +}; + +/* XXX: debug stuff only ! (TOFIX with a generic debug console) */ +int serial_write (const void *buffer, int len) +{ +    const char *p; + +    for (p = buffer; len > 0; len--) { +        if (!(inb(0x3F8 + PC_SERIAL_LSR_OFFSET) & 0x20)) +            usleep(100); +        outb(0x3F8, *p++); +    } + +    return 0; +} + +int pc_serial_register (uint16_t base) +{ +    pc_serial_t *serial; +     +    serial = malloc(sizeof(pc_serial_t)); +    if (serial == NULL) +        return -1; +    serial->base = base; +    /* XXX: TODO: initialize the serial port (FIFO, speed, ...) */ +     +    return chardev_register(CHARDEV_SERIAL, &pc_serial_ops, serial); +} + +/* VGA console device */ +static int vga_cons_open (unused void *private) +{ +    return 0; +} + +static int vga_cons_writeb (unused void *private, int data) +{ +    vga_putchar(data); + +    return 0; +} + +static int vga_cons_close (unused void *private) +{ +    return 0; +} + +static cops_t vga_cons_ops = { +    .open = &vga_cons_open, +    .read = NULL, +    .write = &vga_cons_writeb, +    .close = &vga_cons_close, +}; + +int vga_console_register (void) +{ +    return chardev_register(CHARDEV_DISPLAY, &vga_cons_ops, NULL); +} + +/* Macintosh via-cuda driver */ +#ifdef DEBUG_CUDA +#define CUDA_DPRINTF(fmt, args...) \ +do { dprintf("CUDA - %s: " fmt, __func__ , ##args); } while (0) +#else +#define CUDA_DPRINTF(fmt, args...) do { } while (0) +#endif + +/* VIA registers - spaced 0x200 bytes apart */ +#define RS		0x200		/* skip between registers */ +#define B		0		/* B-side data */ +#define A		RS		/* A-side data */ +#define DIRB		(2*RS)		/* B-side direction (1=output) */ +#define DIRA		(3*RS)		/* A-side direction (1=output) */ +#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */ +#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */ +#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */ +#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */ +#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */ +#define SR		(10*RS)		/* Shift register */ +#define ACR		(11*RS)		/* Auxiliary control register */ +#define PCR		(12*RS)		/* Peripheral control register */ +#define IFR		(13*RS)		/* Interrupt flag register */ +#define IER		(14*RS)		/* Interrupt enable register */ +#define ANH		(15*RS)		/* A-side data, no handshake */ + +/* Bits in B data register: all active low */ +#define TREQ		0x08		/* Transfer request (input) */ +#define TACK		0x10		/* Transfer acknowledge (output) */ +#define TIP		0x20		/* Transfer in progress (output) */ + +/* Bits in ACR */ +#define SR_CTRL		0x1c		/* Shift register control bits */ +#define SR_EXT		0x0c		/* Shift on external clock */ +#define SR_OUT		0x10		/* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET		0x80		/* set bits in IER */ +#define IER_CLR		0		/* clear bits in IER */ +#define SR_INT		0x04		/* Shift register full/empty */ + +#define CUDA_BUF_SIZE 16 + +#define ADB_PACKET	0 +#define CUDA_PACKET	1 + +struct cuda_t { +    uint32_t base; +    adb_bus_t *adb_bus; +}; + +static uint8_t cuda_readb (cuda_t *dev, int reg) +{ +    return *(volatile uint8_t *)(dev->base + reg); +} + +static void cuda_writeb (cuda_t *dev, int reg, uint8_t val) +{ +    *(volatile uint8_t *)(dev->base + reg) = val; +} + +static void cuda_wait_irq (cuda_t *dev) +{ +    int val; + +    CUDA_DPRINTF("\n"); +    for(;;) { +        val = cuda_readb(dev, IFR); +        cuda_writeb(dev, IFR, val & 0x7f); +        if (val & SR_INT) +            break; +    } +} + +static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf, +                         int buf_len, uint8_t *obuf) +{ +    int i, obuf_len, val; + +    cuda_writeb(dev, ACR, cuda_readb(dev, ACR) | SR_OUT); +    cuda_writeb(dev, SR, pkt_type); +    cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP); +    if (buf) { +        CUDA_DPRINTF("Send buf len: %d\n", buf_len); +        /* send 'buf' */ +        for(i = 0; i < buf_len; i++) { +            cuda_wait_irq(dev); +            cuda_writeb(dev, SR, buf[i]); +            cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK); +        } +    } +    cuda_wait_irq(dev); +    cuda_writeb(dev, ACR, cuda_readb(dev, ACR) & ~SR_OUT); +    cuda_readb(dev, SR); +    cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK); +     +    obuf_len = 0; +    if (obuf) { +        cuda_wait_irq(dev); +        cuda_readb(dev, SR); +        cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP); +        for(;;) { +            cuda_wait_irq(dev); +            val = cuda_readb(dev, SR); +            if (obuf_len < CUDA_BUF_SIZE) +                obuf[obuf_len++] = val; +            if (cuda_readb(dev, B) & TREQ) +                break; +            cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK); +        } +        cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK); + +        cuda_wait_irq(dev); +        cuda_readb(dev, SR); +    } +    CUDA_DPRINTF("Got len: %d\n", obuf_len); + +    return obuf_len; +} + +#if 0 +void cuda_test(void) +{ +    int keycode; +    printf("cuda test:\n"); +    cuda_init(0x80400000 + 0x16000); +    for(;;) { +        keycode = adb_read_key(); +        if (keycode >= 0) +            printf("keycode=%x\n", keycode); +    } +} +#endif + +/* Cuda ADB glue */ +static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len, +                         uint8_t *rcv_buf) +{ +    uint8_t buffer[CUDA_BUF_SIZE], *pos; + +    CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]); +    len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer); +    if (len > 1 && buffer[0] == ADB_PACKET) { +        pos = buffer + 2; +        len -= 2; +    } else { +        pos = buffer + 1; +        len = -1; +    } +    memcpy(rcv_buf, pos, len); + +    return len; +} + +cuda_t *cuda_init (uint32_t base) +{ +    cuda_t *cuda; + +    CUDA_DPRINTF(" base=%08x\n", base); +    cuda = malloc(sizeof(cuda_t)); +    if (cuda == NULL) +        return NULL; +    cuda->base = base; +    cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP); +#if 0 +    { +        int len; + +        /* enable auto poll */ +        buf[0] = 0x01; +        buf[1] = 1; +        len = cuda_request(cuda, CUDA_PACKET, buf, 2, obuf); +        if (len != 2 || obuf[0] != CUDA_PACKET || obuf[1] != 1) { +            printf("cuda: invalid reply for auto poll request"); +            free(cuda); +            return NULL; +        } +    } +#endif +    cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req); +    if (cuda->adb_bus == NULL) { +        free(cuda); +        return NULL; +    } +    adb_bus_init(cuda->adb_bus); + +    return cuda; +} + +void cuda_reset (cuda_t *cuda) +{ +    adb_bus_reset(cuda->adb_bus); +} + +/* ADB generic driver */ +#ifdef DEBUG_ADB +#define ADB_DPRINTF(fmt, args...) \ +do { dprintf("ADB - %s: " fmt, __func__ , ##args); } while (0) +#else +#define ADB_DPRINTF(fmt, args...) do { } while (0) +#endif + +int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg, +             uint8_t *buf, int len) +{ +    uint8_t adb_send[ADB_BUF_SIZE], adb_rcv[ADB_BUF_SIZE]; +     +    ADB_DPRINTF("cmd: %d reg: %d len: %d\n", cmd, reg, len); +    if (dev->bus == NULL || dev->bus->req == NULL) { +        ADB_DPRINTF("ERROR: invalid bus !\n"); +        bug(); +    } +    /* Sanity checks */ +    if (cmd != ADB_LISTEN && len != 0) { +        /* No buffer transmitted but for LISTEN command */ +        ADB_DPRINTF("in buffer for cmd %d\n", cmd); +        return -1; +    } +    if (cmd == ADB_LISTEN && ((len < 2 || len > 8) || buf == NULL)) { +        /* Need a buffer with a regular register size for LISTEN command */ +        ADB_DPRINTF("no/invalid buffer for ADB_LISTEN (%d)\n", len); +        return -1; +    } +    if ((cmd == ADB_TALK || cmd == ADB_LISTEN) && reg > 3) { +        /* Need a valid register number for LISTEN and TALK commands */ +        ADB_DPRINTF("invalid reg for TALK/LISTEN command (%d %d)\n", cmd, reg); +        return -1; +    } +    switch (cmd) { +    case ADB_SEND_RESET: +        adb_send[0] = ADB_SEND_RESET; +        break; +    case ADB_FLUSH: +        adb_send[0] = (dev->addr << 4) | ADB_FLUSH; +        break; +    case ADB_LISTEN: +        memcpy(adb_send + 1, buf, len); +        /* No break here */ +    case ADB_TALK: +        adb_send[0] = (dev->addr << 4) | cmd | reg; +        break; +    } +    memset(adb_rcv, 0, ADB_BUF_SIZE); +    len = (*dev->bus->req)(dev->bus->host, adb_send, len + 1, adb_rcv); +#ifdef DEBUG_ADB +    printf("%x %x %x %x\n", adb_rcv[0], adb_rcv[1], adb_rcv[2], adb_rcv[3]); +#endif +    switch (len) { +    case 0: +        /* No data */ +        break; +    case 2 ... 8: +        /* Register transmitted */ +        if (buf != NULL) +            memcpy(buf, adb_rcv, len); +        break; +    default: +        /* Should never happen */ +        ADB_DPRINTF("Cmd %d returned %d bytes !\n", cmd, len); +        return -1; +    } +    ADB_DPRINTF("retlen: %d\n", len); +     +    return len; +} + +void adb_bus_reset (adb_bus_t *bus) +{ +    adb_reset(bus); +} + +adb_bus_t *adb_bus_new (void *host, +                        int (*req)(void *host, const uint8_t *snd_buf, +                                   int len, uint8_t *rcv_buf)) +{ +    adb_bus_t *new; + +    new = malloc(sizeof(adb_bus_t)); +    if (new == NULL) +        return NULL; +    new->host = host; +    new->req = req; + +    return new; +} + +/* ADB */ +void *adb_kbd_new (void *private); + +static int adb_mouse_open (void *private); +static int adb_mouse_close (void *private); +static int adb_mouse_read (void *private); + +static cops_t adb_mouse_ops = { +    &adb_mouse_open, +    &adb_mouse_close, +    &adb_mouse_read, +    NULL, +}; + +/* Check and relocate all ADB devices as suggested in + * ADB_manager Apple documentation + */ +int adb_bus_init (adb_bus_t *bus) +{ +    uint8_t buffer[ADB_BUF_SIZE]; +    uint8_t adb_addresses[16] = +        { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, }; +    adb_dev_t tmp_device, **cur; +    int address; +    int reloc = 0, next_free = 7; +    int keep; + +    /* Reset the bus */ +    ADB_DPRINTF("\n"); +    adb_reset(bus); +    cur = &bus->devices; +    memset(&tmp_device, 0, sizeof(adb_dev_t)); +    tmp_device.bus = bus; +    for (address = 1; address < 8 && adb_addresses[reloc] > 0;) { +        if (address == ADB_RES) { +            /* Reserved */ +            address++; +            continue; +        } +        ADB_DPRINTF("Check device on ADB address %d\n", address); +        tmp_device.addr = address; +        switch (adb_reg_get(&tmp_device, 3, buffer)) { +        case 0: +            ADB_DPRINTF("No device on ADB address %d\n", address); +            /* Register this address as free */ +            if (adb_addresses[next_free] != 0) +                adb_addresses[next_free++] = address; +            /* Check next ADB address */ +            address++; +            break; +        case 2: +            /* One device answered : +             * make it available and relocate it to a free address +             */ +            if (buffer[0] == ADB_CHADDR) { +                /* device self test failed */ +                ADB_DPRINTF("device on ADB address %d self-test failed " +                            "%02x %02x %02x\n", address, +                            buffer[0], buffer[1], buffer[2]); +                keep = 0; +            } else { +                ADB_DPRINTF("device on ADB address %d self-test OK\n", +                            address); +                keep = 1; +            } +            ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n", +                        address, adb_addresses[reloc], reloc); +            buffer[0] = ((buffer[0] & 0x40) & ~0x90) | adb_addresses[reloc]; +            if (keep == 1) +                buffer[0] |= 0x20; +            buffer[1] = ADB_CHADDR_NOCOLL; +            if (adb_reg_set(&tmp_device, 3, buffer, 2) < 0) { +                ADB_DPRINTF("ADB device relocation failed\n"); +                return -1; +            } +            if (keep == 1) { +                *cur = malloc(sizeof(adb_dev_t)); +                if (*cur == NULL) { +                    return -1; +                } +                (*cur)->type = address; +                (*cur)->bus = bus; +                (*cur)->addr = adb_addresses[reloc++]; +                /* Flush buffers */ +                adb_flush(*cur); +                switch ((*cur)->type) { +                case ADB_PROTECT: +                    ADB_DPRINTF("Found one protected device\n"); +                    break; +                case ADB_KEYBD: +                    ADB_DPRINTF("Found one keyboard\n"); +                    adb_kbd_new(*cur); +                    break; +                case ADB_MOUSE: +                    ADB_DPRINTF("Found one mouse\n"); +                    chardev_register(CHARDEV_MOUSE, &adb_mouse_ops, *cur); +                    break; +                case ADB_ABS: +                    ADB_DPRINTF("Found one absolute positioning device\n"); +                    break; +                case ADB_MODEM: +                    ADB_DPRINTF("Found one modem\n"); +                    break; +                case ADB_RES: +                    ADB_DPRINTF("Found one ADB res device\n"); +                    break; +                case ADB_MISC: +                    ADB_DPRINTF("Found one ADB misc device\n"); +                    break; +                } +                cur = &((*cur)->next); +            } +            break; +        case 1: +        case 3 ... 7: +            /* SHOULD NOT HAPPEN : register 3 is always two bytes long */ +            ADB_DPRINTF("Invalid returned len for ADB register 3\n"); +            return -1; +        case -1: +            /* ADB ERROR */ +            ADB_DPRINTF("error gettting ADB register 3\n"); +            return -1; +        } +    } + +    return 0; +} + +/* ADB mouse chardev interface (TODO) */ +static int adb_mouse_open (unused void *private) +{ +    return 0; +} + +static int adb_mouse_close (unused void *private) +{ +    return 0; +} + +static int adb_mouse_read (unused void *private) +{ +    return -1; +} diff --git a/roms/openhackware/src/dev/bus/adb.h b/roms/openhackware/src/dev/bus/adb.h new file mode 100644 index 00000000..e48b120f --- /dev/null +++ b/roms/openhackware/src/dev/bus/adb.h @@ -0,0 +1,102 @@ +/* + * ADB bus definitions for Open Hack'Ware + * + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined(__OHW_ADB_H__) +#define __OHW_ADB_H__ + +typedef struct adb_bus_t adb_bus_t; +typedef struct adb_dev_t adb_dev_t; + +#define ADB_BUF_SIZE 8 +struct adb_bus_t { +    void *host; +    int (*req)(void *host, const uint8_t *snd_buf, int len, uint8_t *rcv_buf); +    adb_dev_t *devices; +}; + +struct adb_dev_t { +    adb_dev_t *next; +    adb_bus_t *bus; +    uint8_t addr; +    uint8_t type; +    uint32_t state; +}; + +#define ADB_BUF_SIZE 8 + +/* ADB commands */ +enum { +    ADB_SEND_RESET = 0x00, +    ADB_FLUSH      = 0x01, +    ADB_LISTEN     = 0x08, +    ADB_TALK       = 0x0C, +}; +/* ADB default IDs before relocation */ +enum { +    ADB_PROTECT    = 0x01, +    ADB_KEYBD      = 0x02, +    ADB_MOUSE      = 0x03, +    ADB_ABS        = 0x04, +    ADB_MODEM      = 0x05, +    ADB_RES        = 0x06, +    ADB_MISC       = 0x07, +}; +/* ADB special device handlers IDs */ +enum { +    ADB_CHADDR        = 0x00, +    ADB_CHADDR_ACTIV  = 0xFD, +    ADB_CHADDR_NOCOLL = 0xFE, +    ADB_SELF_TEST     = 0xFF, +}; + +int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg, +             uint8_t *buf, int len); +void adb_bus_reset (adb_bus_t *bus); +adb_bus_t *adb_bus_new (void *host, +                        int (*req)(void *host, const uint8_t *snd_buf, +                                   int len, uint8_t *rcv_buf)); +int adb_bus_init (adb_bus_t *bus); + +static inline int adb_reset (adb_bus_t *bus) +{ +    adb_dev_t fake_device; +     +    memset(&fake_device, 0, sizeof(adb_dev_t)); +    fake_device.bus = bus; + +    return adb_cmd(&fake_device, ADB_SEND_RESET, 0, NULL, 0); +} + +static inline int adb_flush (adb_dev_t *dev) +{ +    return adb_cmd(dev, ADB_FLUSH, 0, NULL, 0); +} + +static inline int adb_reg_get (adb_dev_t *dev, uint8_t reg, uint8_t *buf) +{ +    return adb_cmd(dev, ADB_TALK, reg, buf, 0); +} + +static inline int adb_reg_set (adb_dev_t *dev, uint8_t reg, +                               uint8_t *buf, int len) +{ +    return adb_cmd(dev, ADB_LISTEN, reg, buf, len); +} + +#endif /* !defined(__OHW_ADB_H__) */ diff --git a/roms/openhackware/src/dev/char/char.h b/roms/openhackware/src/dev/char/char.h new file mode 100644 index 00000000..14f17e77 --- /dev/null +++ b/roms/openhackware/src/dev/char/char.h @@ -0,0 +1,29 @@ +/* + * <char.h> + * + * Open Hack'Ware BIOS misc char devices definitions. + *  + *  Copyright (c) 2005 Jocelyn Mayer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_DEV_CHAR_H__) +#define __OHW_DEV_CHAR_H__ + +/* Keyboard devices registration */ +int pckbd_register (void); +void *adb_kbd_new (void *private); + +#endif /* !defined (__OHW_DEV_CHAR_H__) */ diff --git a/roms/openhackware/src/dev/char/kbd.c b/roms/openhackware/src/dev/char/kbd.c new file mode 100644 index 00000000..78f52040 --- /dev/null +++ b/roms/openhackware/src/dev/char/kbd.c @@ -0,0 +1,122 @@ +/* + * <kbd.c> + * + * Open Hack'Ware BIOS generic keyboard input translation. + *  + *  Copyright (c) 2005 Jocelyn Mayer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "kbd.h" + +//#define DEBUG_KBD +#ifdef DEBUG_KBD +#define KBD_DPRINTF(fmt, args...) \ +do { dprintf("KBD - %s: " fmt, __func__ , ##args); } while (0) +#else +#define KBD_DPRINTF(fmt, args...) do { } while (0) +#endif + +void *kbd_new (int len) +{ +    kbd_t *kbd; + +    if (len < (int)sizeof(kbd_t)) { +        kbd = NULL; +    } else { +        kbd = malloc(len); +        if (kbd != NULL) +            memset(kbd, 0, len); +    } + +    return kbd; +} + +int kbd_set_keymap (kbd_t *kbd, int nb_keys, keymap_t *keymap) +{ +    kbd->nb_keys = nb_keys; +    kbd->keymap = keymap; + +    return 0; +} + +int kbd_translate_key (kbd_t *kbd, int keycode, int up_down) +{ +    keymap_t *keyt; +    int mod_state, key, type; +    int ret; + +    ret = -1; +    /* Get key table */ +    if (keycode < kbd->nb_keys) { +        keyt = &kbd->keymap[keycode]; +        /* Get modifier state */ +        mod_state = (kbd->mod_state | (kbd->mod_state >> 8)) & 0xFF; +        /* Adjust with lock */ +        if (keyt->lck_shift >= 0) { +            if ((kbd->mod_state >> (16 + keyt->lck_shift)) & 0x01) { +                KBD_DPRINTF("adjust with lock %02x => %02x (%d %08x)\n", +                            mod_state, +                            mod_state ^ ((kbd->mod_state >> +                                          (16 + keyt->lck_shift)) & +                                         0x01), +                            keyt->lck_shift, kbd->mod_state); +            } +            mod_state ^= (kbd->mod_state >> (16 + keyt->lck_shift)) & 0x01; +        } +        key = keyt->trans[mod_state]; +        type = key & 0xFF000000; +        key &= ~0xFF000000; +        switch (type) { +        case KBD_TYPE_REGULAR: +            if (!up_down) { +                /* We don't care about up events on "normal" keys */ +                ret = key; +            } +            break; +        case KBD_TYPE_LOCK: +            if (!up_down) { +                kbd->mod_state ^= key; +                ret = -2; +                KBD_DPRINTF("Change modifier type %d key %04x %s => %08x\n", +                            type, key, up_down ? "up" : "down", +                            kbd->mod_state); +            } +            break; +        case KBD_TYPE_LMOD: +        case KBD_TYPE_RMOD: +            if (up_down) +                kbd->mod_state &= ~key; +            else +                kbd->mod_state |= key; +            KBD_DPRINTF("Change modifier type %d key %04x %s => %08x\n", +                        type, key, up_down ? "up" : "down", kbd->mod_state); +            ret = -2; /* The caller may know the key was a modifier */ +            break; +        default: +            KBD_DPRINTF("Unknown key: keycode=%02x mod_state=%02x (%08x)\n", +                        keycode, mod_state, kbd->mod_state); +            break; +        } +    } else { +        KBD_DPRINTF("Unmanaged key: keycode=%02x mod_state %08x\n", +                    keycode, kbd->mod_state); +    } + +    return ret; +} diff --git a/roms/openhackware/src/dev/char/kbd.h b/roms/openhackware/src/dev/char/kbd.h new file mode 100644 index 00000000..3a56609f --- /dev/null +++ b/roms/openhackware/src/dev/char/kbd.h @@ -0,0 +1,104 @@ +/* + * <kbd.h> + * + * Open Hack'Ware BIOS generic keyboard management definitions. + *  + *  Copyright (c) 2005 Jocelyn Mayer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_KBD_H__) +#define __OHW_KBD_H__ + +typedef struct kbd_t kbd_t; +typedef struct keymap_t keymap_t; +struct kbd_t { +    uint32_t mod_state; +    /* Modifier state               +     *                0x00 kk ll rr +     *                   |  |  |  | +     * Not used for now -+  |  |  | +     * Locks ---------------+  |  | +     * Left modifiers ---------+  | +     * Right modifiers -----------+ +     */ +    int nb_keys; +    keymap_t *keymap; +}; + +/* Modifiers */ +typedef enum { +    KBD_MOD_SHIFT   = 0x01, +    KBD_MOD_CTRL    = 0x02, +    KBD_MOD_ALT     = 0x04, +    KBD_MOD_CMD     = 0x08, +    KBD_MOD_OPT     = 0x10, +} kbd_modifiers; + +/* Locks */ +typedef enum { +    KBD_LCK_CAPS    = 0x01, +    KBD_LCK_NUM     = 0x02, +    KBD_LCK_SCROLL  = 0x04, +} kbd_locks; + +/* Lock shifts */ +typedef enum { +    KBD_SH_NONE     = -1, +    KBD_SH_CAPS     = 0, +    KBD_SH_NUML     = 1, +    KBD_SH_SCRL     = 2, +} kbd_lck_shifts; + +enum { +    KBD_TYPE_REGULAR = 0 << 24, +    KBD_TYPE_LMOD    = 1 << 24, +    KBD_TYPE_RMOD    = 2 << 24, +    KBD_TYPE_LOCK    = 3 << 24, +}; + +#define KBD_MOD_MAP(mod) \ +KBD_SH_NONE, { (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \ +               (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \ +               (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \ +               (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), } +#define KBD_MOD_MAP_LSHIFT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_SHIFT) +#define KBD_MOD_MAP_RSHIFT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_SHIFT << 8)) +#define KBD_MOD_MAP_LCTRL  KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_CTRL) +#define KBD_MOD_MAP_RCTRL  KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_CTRL << 8)) +#define KBD_MOD_MAP_LALT   KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_ALT) +#define KBD_MOD_MAP_RALT   KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_ALT << 8)) +#define KBD_MOD_MAP_LCMD   KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_CMD) +#define KBD_MOD_MAP_RCMD   KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_CMD << 8)) +#define KBD_MOD_MAP_LOPT   KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_OPT) +#define KBD_MOD_MAP_ROPT   KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_OPT << 8)) +#define KBD_MOD_MAP_CAPS   KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_CAPS << 16)) +#define KBD_MOD_MAP_NUML   KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_NUML << 16)) +#define KBD_MOD_MAP_SCROLL KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_SCRL << 16)) +#define KBD_MAP_NONE KBD_MOD_MAP(-1) + +/* Keymap definition */ +struct keymap_t { +    /* Set the lock which applies to this key (if any) */ +    int lck_shift; +    /* Key translations */ +    uint32_t trans[32]; +}; + +void *kbd_new (int len); +int kbd_set_keymap (kbd_t *kbd, int nb_keys, keymap_t *keymap); +int kbd_translate_key (kbd_t *kbd, int keycode, int up_down); + +#endif /* !defined (__OHW_KBD_H__) */ diff --git a/roms/openhackware/src/dev/char/kbdadb.c b/roms/openhackware/src/dev/char/kbdadb.c new file mode 100644 index 00000000..4f7dd374 --- /dev/null +++ b/roms/openhackware/src/dev/char/kbdadb.c @@ -0,0 +1,482 @@ +/* + * <adbkbd.c> + * + * Open Hack'Ware BIOS ADB keyboard support. + *  + *  Copyright (c) 2005 Jocelyn Mayer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "adb.h" +#include "kbd.h" + +#ifdef DEBUG_ADB +#define ADB_DPRINTF(fmt, args...) \ +do { dprintf("ADB - %s: " fmt, __func__ , ##args); } while (0) +#else +#define ADB_DPRINTF(fmt, args...) do { } while (0) +#endif + +/* ADB US keyboard translation map + * XXX: for now, only shift modifier is defined + */ +static keymap_t ADB_kbd_us[] = { +    /* 0x00 */ +    { KBD_SH_CAPS, { 0x61, 0x41,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x73, 0x53,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x64, 0x44,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x66, 0x46,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x68, 0x48,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x67, 0x47,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x7A, 0x5A,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x78, 0x58,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x08 */ +    { KBD_SH_CAPS, { 0x63, 0x43,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x76, 0x56,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x60, 0x40,   -1,   -1,   -1,   -1,   -1,   -1, /* ? */ +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x62, 0x42,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x71, 0x51,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x77, 0x57,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x65, 0x45,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x72, 0x52,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x10 */ +    { KBD_SH_CAPS, { 0x79, 0x59,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x74, 0x54,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x31, 0x21,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x32, 0x40,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x33, 0x23,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x34, 0x24,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x36, 0x5E,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x35, 0x25,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x18 */ +    { KBD_SH_CAPS, { 0x3D, 0x2B,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x39, 0x28,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x37, 0x26,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x2D, 0x5F,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x38, 0x2A,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x30, 0x29,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x5D, 0x7D,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x6F, 0x4F,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x20 */ +    { KBD_SH_CAPS, { 0x75, 0x55,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x5B, 0x7B,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x69, 0x49,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x70, 0x50,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MOD_MAP(0x0D), }, +    { KBD_SH_CAPS, { 0x6C, 0x4C,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x6A, 0x4A,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x27, 0x22,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x28 */ +    { KBD_SH_CAPS, { 0x6B, 0x4B,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x3B, 0x3A,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x5C, 0x7C,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x2C, 0x3C,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x2F, 0x3F,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x6E, 0x4E,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x6D, 0x4D,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_CAPS, { 0x2E, 0x3E,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x30 : tab */ +    { KBD_MOD_MAP(0x09), }, +    /* 0x31 : space */ +    { KBD_MOD_MAP(0x20), }, +    /* 0x32 : '<' '>' */ +    { KBD_SH_CAPS, { 0x3C, 0x3E,   -1,   -1,   -1,   -1,   -1,   -1, /* ? */ +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x33 : backspace */ +    { KBD_MOD_MAP(0x08), }, +    { KBD_MAP_NONE, }, +    /* 0x35 : ESC */ +    { KBD_MOD_MAP(0x1B), }, +    /* 0x36 : control */ +    { KBD_MOD_MAP_LCTRL, }, +    /* 0x37 : command */ +    { KBD_MOD_MAP_LCMD,   }, +    /* 0x38 : left shift */ +    { KBD_MOD_MAP_LSHIFT, }, +    /* 0x39 : caps-lock */ +    { KBD_MOD_MAP_CAPS,   }, +    /* 0x3A : option */ +    { KBD_MOD_MAP_LOPT,   }, +    /* 0x3B : left */ +    { KBD_MAP_NONE, }, +    /* 0x3C : right */ +    { KBD_MAP_NONE, }, +    /* 0x3D : down */ +    { KBD_MAP_NONE, }, +    /* 0x3E : up */ +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    /* 0x40 */ +    { KBD_MAP_NONE, }, +    { KBD_SH_NUML, { 0x7F, 0x2E,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MAP_NONE, }, +    { KBD_SH_NONE, { 0x2A, 0x2A,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MAP_NONE, }, +    { KBD_SH_NONE, { 0x2B, 0x2B,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MAP_NONE, }, +    { KBD_MOD_MAP(0x7F), }, +    /* 0x48 */ +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    { KBD_SH_NONE, { 0x2F, 0x2F,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MOD_MAP(0x0D), }, +    { KBD_MAP_NONE, }, +    { KBD_SH_NONE, { 0x2D, 0x2D,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MAP_NONE, }, +    /* 0x50 */ +    { KBD_MAP_NONE, }, +    { KBD_SH_NONE, { 0x3D, 0x3D,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x30,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x31,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x32,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x33,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x34,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x35,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    /* 0x58 */ +    { KBD_SH_NUML, {   -1, 0x36,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x37,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MAP_NONE, }, +    { KBD_SH_NUML, {   -1, 0x38,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_SH_NUML, {   -1, 0x39,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +                       -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { KBD_MAP_NONE, }, +    { KBD_MOD_MAP(0x2F), }, +    { KBD_MAP_NONE, }, +    /* 0x60 : F5 */ +    { KBD_MAP_NONE, }, +    /* 0x61 : F6 */ +    { KBD_MAP_NONE, }, +    /* 0x62 : F7 */ +    { KBD_MAP_NONE, }, +    /* 0x63 : F3 */ +    { KBD_MAP_NONE, }, +    /* 0x64 : F8 */ +    { KBD_MAP_NONE, }, +    /* 0x65 : F9 */ +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    /* 0x67 : F11 */ +    { KBD_MAP_NONE, }, +    /* 0x68 */ +    { KBD_MAP_NONE, }, +    /* 0x69 : F13 */ +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    /* 0x6B : F14 */ +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    /* 0x6D : F10 */ +    { KBD_MAP_NONE, }, +    { KBD_MAP_NONE, }, +    /* 0x6F : F12 */ +    { KBD_MAP_NONE, }, +    /* 0x70 */ +    { KBD_MAP_NONE, }, +    /* 0x71 : F15 */ +    { KBD_MAP_NONE, }, +    /* 0x72 : help */ +    { KBD_MAP_NONE, }, +    /* 0x73 : home */ +    { KBD_MAP_NONE, }, +    /* 0x74 : page up */ +    { KBD_MAP_NONE, }, +    /* 0x75 : del */ +    { KBD_MAP_NONE, }, +    /* 0x76 : F4 */ +    { KBD_MAP_NONE, }, +    /* 0x77 : end */ +    { KBD_MAP_NONE, }, +    /* 0x78 : F2 */ +    { KBD_MAP_NONE, }, +    /* 0x79 : page down */ +    { KBD_MAP_NONE, }, +    /* 0x7A : F1 */ +    { KBD_MAP_NONE, }, +    /* 0x7B : right shift */ +    { KBD_MOD_MAP_RSHIFT, }, +    /* 0x7C : right option */ +    { KBD_MOD_MAP_ROPT,   }, +    /* 0x7D : right control */ +    { KBD_MOD_MAP_RCTRL, }, +    { KBD_MAP_NONE, }, +    /* 0x7F : power */ +    { KBD_MAP_NONE, }, +}; + +typedef struct adb_kbd_t adb_kbd_t; +struct adb_kbd_t { +    kbd_t kbd; +    int next_key; +}; + +static int adb_kbd_open (unused void *private) +{ +    return 0; +} + +static int adb_kbd_close (unused void *private) +{ +    return 0; +} + +static int adb_kbd_read (void *private) +{ +    uint8_t buffer[ADB_BUF_SIZE]; +    adb_dev_t *dev = private; +    adb_kbd_t *kbd; +    int key; +    int ret; + +    kbd = (void *)dev->state; +    ADB_DPRINTF("enter\n"); +    /* Get saved state */ +    ret = -1; +    for (key = -1; key == -1; ) { +        if (kbd->next_key != -1) { +            key = kbd->next_key; +            kbd->next_key = -1; +        } else { +            if (adb_reg_get(dev, 0, buffer) != 2) { +                goto out; +            } +            kbd->next_key = buffer[1] == 0xFF ? -1 : buffer[1]; +            key = buffer[0]; +        } +        ret = kbd_translate_key(&kbd->kbd, key & 0x7F, key >> 7); +        ADB_DPRINTF("Translated %d (%02x) into %d (%02x)\n", +                    key, key, ret, ret); +    } + out: + +    return ret; +} + +static cops_t adb_kbd_ops = { +    &adb_kbd_open, +    &adb_kbd_close, +    &adb_kbd_read, +    NULL, +}; + +void *adb_kbd_new (void *private) +{ +    adb_kbd_t *kbd; +    adb_dev_t *dev = private; + +    kbd = kbd_new(sizeof(adb_kbd_t)); +    if (kbd != NULL) { +        kbd_set_keymap(&kbd->kbd, +                       sizeof(ADB_kbd_us) / sizeof(keymap_t), ADB_kbd_us); +        kbd->next_key = -1; +        dev->state = (int32_t)kbd; +        chardev_register(CHARDEV_KBD, &adb_kbd_ops, private); +    } + +    return kbd; +} diff --git a/roms/openhackware/src/dev/char/pckbd.c b/roms/openhackware/src/dev/char/pckbd.c new file mode 100644 index 00000000..45b5a67d --- /dev/null +++ b/roms/openhackware/src/dev/char/pckbd.c @@ -0,0 +1,214 @@ +/* + * <pckbd.c> + * + * Open Hack'Ware BIOS PC keyboard driver. + *  + *  Copyright (c) 2005 Jocelyn Mayer + * + *  This code is a rework (mostly simplification) from code + *  proposed by Matthew Wood <mwood@realmsys.com> + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" + +/* IO definitions */ +#define PCKBD_IO_BASE                   0x60 +#define PCKBD_COMMAND_OFFSET            0x4 +#define PCKBD_STATUS_OFFSET             0x4 + +/* Indexes for keyboard state */ +#define SHIFT 0x1 +#define CTRL  0x2 +#define ALT   0x4 + +/* Scan codes */ +#define L_SHIFT  0x2a +#define R_SHIFT  0x36 +#define L_CTRL   0x1d +/* XXX: R_CTRL ? */ +#define L_ALT    0x38 +/* XXX: missing capslock */ +/* XXX: TODO: add keypad/numlock ... (pc105 kbd) */ + +typedef struct kbdmap_t kbdmap_t; +struct kbdmap_t { +    char translate[8]; +}; + +typedef struct pckbd_t pckbd_t; +struct pckbd_t { +    int modifiers; +    kbdmap_t *map; +    int maplen; +    int io_base; +}; + +/* XXX: should not be here cause it's locale dependent */ +static kbdmap_t pc_map_us[] = { +    /* 0x00 */ +    { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { { 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, }, }, +    { {  '1',  '!',   -1,   -1,  '1',  '!',   -1,   -1, }, }, +    { {  '2', '\'', '\'',   -1,   -1,  '2', '\'', '\'', }, }, +    { {  '3',  '#',   -1,   -1,  '3',  '#',   -1,   -1, }, }, +    { {  '4',  '$',   -1,   -1,  '4',  '$',   -1,   -1, }, }, +    { {  '5',  '%',   -1,   -1,  '5',  '%',   -1,   -1, }, }, +    { {  '6',  '^',   -1,   -1,  '6',  '^',   -1,   -1, }, }, +    /* 0x08 */ +    { {  '7',  '&',   -1,   -1,  '7',  '&',   -1,   -1, }, }, +    { {  '8',  '*',   -1,   -1,  '8',  '*',   -1,   -1, }, }, +    { {  '9',  '(',   -1,   -1,  '9',  '(',   -1,   -1, }, }, +    { {  '0',  ')',   -1,   -1,  '0',  ')',   -1,   -1, }, }, +    { {  '-',  '_',   -1,   -1,  '-',  '_',   -1,   -1, }, }, +    { {  '=',  '+',   -1,   -1,  '=',  '+',   -1,   -1, }, }, +    { { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, }, +    { { 0x2a,   -1,   -1,   -1, 0x2a,   -1,   -1,   -1, }, }, +    /* 0x10 */ +    { {  'q',  'Q',   -1,   -1,  'q',  'Q',   -1,   -1, }, }, +    { {  'w',  'W',   -1,   -1,  'w',  'W',   -1,   -1, }, }, +    { {  'e',  'E',   -1,   -1,  'e',  'E',   -1,   -1, }, }, +    { {  'r',  'R',   -1,   -1,  'r',  'R',   -1,   -1, }, }, +    { {  't',  'T',   -1,   -1,  't',  'T',   -1,   -1, }, }, +    { {  'y',  'Y',   -1,   -1,  'y',  'Y',   -1,   -1, }, }, +    { {  'u',  'U',   -1,   -1,  'u',  'U',   -1,   -1, }, }, +    { {  'i',  'I',   -1,   -1,  'i',  'I',   -1,   -1, }, }, +    /* 0x18 */ +    { {  'o',  'O',   -1,   -1,  'o',  'O',   -1,   -1, }, }, +    { {  'p',  'P',   -1,   -1,  'p',  'P',   -1,   -1, }, }, +    { {  '[',  '{', 0x1b, 0x1b,  '[',  '{', 0x1b, 0x1b, }, }, +    { {  ']',  '}',   -1,   -1,  ']',  '}',   -1,   -1, }, }, +    { { 0x0d, 0x0d, '\r', '\r', 0x0d, 0x0d, '\r', '\r', }, }, +    { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { {  'a',  'A',   -1,   -1,  'a',  'A',   -1,   -1, }, }, +    { {  's',  'S',   -1,   -1,  's',  'S',   -1,   -1, }, }, +    /* 0x20 */ +    { {  'd',  'D',   -1,   -1,  'd',  'D',   -1,   -1, }, }, +    { {  'f',  'F',   -1,   -1,  'f',  'F',   -1,   -1, }, }, +    { {  'g',  'G', 0x07, 0x07,  'g',  'G', 0x07, 0x07, }, }, +    { {  'h',  'H', 0x08, 0x08,  'h',  'H', 0x08, 0x08, }, }, +    { {  'j',  'J', '\r', '\r',  'j',  'J', '\r', '\r', }, }, +    { {  'k',  'K',   -1,   -1,  'k',  'K',   -1,   -1, }, }, +    { {  'l',  'L',   -1,   -1,  'l',  'L',   -1,   -1, }, }, +    { {  ';',  ':',   -1,   -1,  ';',  ':',   -1,   -1, }, }, +    /* 0x28 */ +    { { '\'',  '"',   -1,   -1, '\'',  '"',   -1,   -1, }, }, +    { {  '`',  '~',   -1,   -1,  '`',  '~',   -1,   -1, }, }, +    { { 0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { { '\\',  '|',   -1,   -1, '\\',  '|',   -1,   -1, }, }, +    { {  'z',  'Z',   -1,   -1,  'z',  'Z',   -1,   -1, }, }, +    { {  'x',  'X',   -1,   -1,  'x',  'X',   -1,   -1, }, }, +    { {  'c',  'C',   -1,   -1,  'c',  'C',   -1,   -1, }, }, +    { {  'v',  'V', 0x16, 0x16,  'v',  'V',   -1,   -1, }, }, +    /* 0x30 */ +    { {  'b',  'B',   -1,   -1,  'b',  'B',   -1,   -1, }, }, +    { {  'n',  'N',   -1,   -1,  'n',  'N',   -1,   -1, }, }, +    { {  'm',  'M', 0x0d, 0x0d,  'm',  'M', 0x0d, 0x0d, }, }, +    { {  ',',  '<',   -1,   -1,  ',',  '<',   -1,   -1, }, }, +    { {  '.',  '>',   -1,   -1,  '.',  '>',   -1,   -1, }, }, +    { {  '/',  '?',   -1,   -1,  '/',  '?',   -1,   -1, }, }, +    { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { {  '*',  '*',   -1,   -1,  '*',  '*',   -1,   -1, }, }, +    /* 0x38 */ +    { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, }, +    { {  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ', }, }, +}; + +static int pckbd_open (unused void *private) +{ +    return 0; +} + +static int pckbd_close (unused void *private) +{ +    return 0; +} + +static int pckbd_readb (void *private) +{ +    pckbd_t *kbd = private; +    int status, key, up, mod; +    int ret; + +    for (ret = -1; ret < 0; ) { +        status = inb(kbd->io_base + PCKBD_STATUS_OFFSET); +        if (!(status & 1)) { +            /* No more data available */ +            break; +        } +        key = inb(kbd->io_base); +        up = (key & 0x80) != 0; +        key &= ~0x80; +        switch (key) { +        case 0: +            break; +        case L_ALT: +            mod = ALT; +            goto set_modifiers; +        case L_SHIFT: +        case R_SHIFT: +            mod = SHIFT; +            goto set_modifiers; +        case L_CTRL: +#if 0 /* XXX: missing definition */ +        case R_CTRL: +#endif +            mod = CTRL; +        set_modifiers: +            if (up) +                kbd->modifiers &= ~mod; +            else +                kbd->modifiers |= mod; +            break; +        default: +            /* We don't care about up events or unknown keys */ +            if (!up && key < kbd->maplen) +                ret = kbd->map[key].translate[kbd->modifiers]; +            break; +        } +    } + +    return ret; +} + +static cops_t pckbd_ops = { +    &pckbd_open, +    &pckbd_close, +    &pckbd_readb, +    NULL, +}; + +int pckbd_register (void) +{ +    pckbd_t *kbd; + +    kbd = malloc(sizeof(pckbd_t)); +    if (kbd == NULL) +        return -1; +    memset(kbd, 0, sizeof(pckbd_t)); +    /* Set IO base */ +    /* XXX: should be a parameter... */ +    kbd->io_base = PCKBD_IO_BASE; +    /* Set default keymap */ +    kbd->map = pc_map_us; +    kbd->maplen = sizeof(pc_map_us) / sizeof(kbdmap_t); +    /* Reset modifiers state */ +    kbd->modifiers = 0x00; +    chardev_register(CHARDEV_KBD, &pckbd_ops, kbd); + +    return 0; +} diff --git a/roms/openhackware/src/libc/include/ctype.h b/roms/openhackware/src/libc/include/ctype.h new file mode 100644 index 00000000..09309c16 --- /dev/null +++ b/roms/openhackware/src/libc/include/ctype.h @@ -0,0 +1,113 @@ +/* + * <ctype.h> + * + * Open Hack'Ware BIOS POSIX like ctype definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_CTYPE_H__) +#define __OHW_CTYPE_H__ + +/* Beware that those routines only support ASCII */ +static inline int islower (int c) +{ +    return c >= 'a' && c <= 'z'; +} + +static inline int isupper (int c) +{ +    return c >= 'A' && c <= 'Z'; +} + +static inline int isalpha (int c) +{ +    return islower(c) || isupper(c); +} + +static inline int isdigit (int c) +{ +    return c >= '0' && c <= '9'; +} + +static inline int isalnum (int c) +{ +    return isalpha(c) || isdigit(c); +} + +static inline int isxdigit (int c) +{ +    return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static inline int isspace (int c) +{ +    return c == ' ' || c == '\f' || c == '\n' || c == '\r' || +        c == '\t' || c == '\v'; +} + +static inline int isgraph (int c) +{ +    return (c >= 0x21 && c <= 0x7E) || (c >= 0xA1 && c <= 0xFF); +} + +static inline int isprint (int c) +{ +    return isgraph(c) && c != ' '; +} + +static inline int ispunct (int c) +{ +    return isprint(c) && !isalpha(c) && !isspace(c); +} + +static inline int isblank (int c) +{ +    return c == ' ' || c == '\t'; +} + +static inline int iscntrl (int c) +{ +    return !isprint(c); +} + +static inline int isascii (int c) +{ +    return (c & 0x80) == 0; +} + +static inline int tolower (int c) +{ +    if (isupper(c)) +        c |= 0x20; + +    return c; +} + +static inline int toupper (int c) +{ +    if (islower(c)) +        c &= ~0x20; + +    return c; +} + +static inline int toascii (int c) +{ +    return c & ~0x80; +} + +#endif /* !defined (__OHW_CTYPE_H__) */ diff --git a/roms/openhackware/src/libc/include/endian.h b/roms/openhackware/src/libc/include/endian.h new file mode 100644 index 00000000..d0ec7971 --- /dev/null +++ b/roms/openhackware/src/libc/include/endian.h @@ -0,0 +1,514 @@ +/* + * <endian.h> + * + * Open Hack'Ware BIOS: provides all common endianness conversions functions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ +/* + * This file provides: + *  void cpu_to_be16p (uint16_t *outp, uint16_t in); + *  void cpu_to_be32p (uint32_t *outp, uint32_t in); + *  void cpu_to_be64p (uint64_t *outp, uint64_t in); + *  void cpu_to_le16p (uint16_t *outp, uint16_t in); + *  void cpu_to_le32p (uint32_t *outp, uint32_t in); + *  void cpu_to_le64p (uint64_t *outp, uint64_t in); + *  void endian_to_cpu16p (uint16_t *outp, uint16_t in, endian_t endian); + *  void endian_to_cpu32p (uint32_t *outp, uint32_t in, endian_t endian); + *  void endian_to_cpu64p (uint64_t *outp, uint64_t in, endian_t endian); + *  void cpu16_to_endianp (uint16_t *outp, uint16_t in, endian_t endian); + *  void cpu32_to_endianp (uint32_t *outp, uint32_t in, endian_t endian); + *  void cpu64_to_endianp (uint64_t *outp, uint64_t in, endian_t endian); + * + */ + +#if !defined (__OHW_ENDIAN_H__) +#define __OHW_ENDIAN_H__ + +#include <stdint.h> + +typedef enum endian_t endian_t; +enum endian_t { +    ENDIAN_1234 = 0, +    ENDIAN_4321, +    ENDIAN_3412, +    ENDIAN_2143, +}; + +/* Generic endian conversion functions */ +static inline void generic_cpu_swap16p (uint16_t *outp, uint16_t in) +{ +    *outp = ((in & 0xFF00) >> 8) | ((in & 0x00FF) << 8); +} + +static inline void generic_cpu_swap32p (uint32_t *outp, uint32_t in) +{ +    *outp = ((in & 0xFF000000) >> 24) | ((in & 0x00FF0000) >> 8) | +        ((in & 0x0000FF00) << 8) | ((in & 0x000000FF) << 24); +} + +static inline void generic_cpu_swap64p (uint64_t *outp, uint64_t in) +{ +    *outp = ((in & 0xFF00000000000000ULL) >> 56) | +        ((in & 0x00FF000000000000ULL) >> 40) | +        ((in & 0x0000FF0000000000ULL) >> 24) | +        ((in & 0x000000FF00000000ULL) >> 8) | +        ((in & 0x00000000FF000000ULL) << 8) | +        ((in & 0x0000000000FF0000ULL) << 24) | +        ((in & 0x000000000000FF00ULL) << 40) | +        ((in & 0x00000000000000FFULL) << 56); +} + +static inline void generic_cpu_swap64p_32 (uint64_t *outp, uint64_t in) +{ +    uint32_t *_outp = (uint32_t *)outp; + +    generic_cpu_swap32p(_outp, in); +    generic_cpu_swap32p(_outp + 1, in >> 32); +} + +#if defined (__i386__) + +#define __CPU_ENDIAN_4321__ +#define __CPU_LENGTH_32__ + +#elif defined (__x86_64__) + +#define __CPU_ENDIAN_4321__ +#define __CPU_LENGTH_64__ + +#elif defined (__powerpc__) || defined (_ARCH_PPC) + +#define __CPU_ENDIAN_1234__ +#define __CPU_LENGTH_32__ + +#define __HAVE_CPU_SWAP16P__ +static inline void cpu_swap16p (uint16_t *outp, uint16_t in) +{ +    __asm__ __volatile__ ("sthbrx %4, 0(%3)"); +} + +#define __HAVE_CPU_SWAP32P__ +static inline void cpu_swap32p (uint32_t *outp, uint32_t in) +{ +    __asm__ __volatile__ ("stwbrx %4, 0(%3)"); +} + +#define __HAVE_CPU_SWAP64P__ +static inline void cpu_swap64p (uint64_t *outp, uint64_t in) +{ +    return generic_cpu_swap64p_32(outp, in); +} + +#else + +#error "unsupported CPU architecture" + +#endif + +/* Use generic swap function if no cpu specific were provided */ +#if !defined (__HAVE_CPU_SWAP16P__) +static inline void cpu_swap16p (uint16_t *outp, uint16_t in) +{ +    generic_cpu_swap16p(outp, in); +} +#endif + +#if !defined (__HAVE_CPU_SWAP32P__) +static inline void cpu_swap32p (uint32_t *outp, uint32_t in) +{ +    generic_cpu_swap32p(outp, in); +} +#endif + +#if !defined (__HAVE_CPU_SWAP64P__) +static inline void cpu_swap64p (uint64_t *outp, uint64_t in) +{ +#if defined (__CPU_LENGTH_64__) +    generic_cpu_swap64p(outp, in); +#elif defined (__CPU_LENGTH_32__) +    generic_cpu_swap64p_32(outp, in); +#else +#error "Don't know how to make 64 bits swapping on this arch" +#endif +} +#endif + +static inline void cpu_nswap16p (uint16_t *outp, uint16_t in) +{ +    *outp = in; +} + +static inline void cpu_nswap32p (uint32_t *outp, uint32_t in) +{ +    *outp = in; +} + +static inline void cpu_nswap64p (uint64_t *outp, uint64_t in) +{ +    *outp = in; +} + +static inline void _endian_be16_p (uint16_t *outp, uint16_t in, +                                   endian_t endian) +{ +    switch (endian) { +    case ENDIAN_4321: +    case ENDIAN_2143: +        cpu_swap16p(outp, in); +        break; +    case ENDIAN_1234: +    case ENDIAN_3412: +        cpu_nswap16p(outp, in); +        break; +    } +}         + +static inline void _endian_be32_p (uint32_t *outp, uint32_t in, +                                   endian_t endian) +{ +    switch (endian) { +    case ENDIAN_4321: +        cpu_swap32p(outp, in); +        break; +    case ENDIAN_1234: +        cpu_nswap32p(outp, in); +        break; +    case ENDIAN_2143: +        /* TODO */ +        break; +    case ENDIAN_3412: +        /* TODO */ +        break; +    } +}         + +static inline void _endian_be64_p (uint64_t *outp, uint64_t in, +                                   endian_t endian) +{ +    switch (endian) { +    case ENDIAN_4321: +        cpu_swap64p(outp, in); +        break; +    case ENDIAN_1234: +        cpu_nswap64p(outp, in); +        break; +    case ENDIAN_2143: +        /* TODO */ +        break; +    case ENDIAN_3412: +        /* TODO */ +        break; +    } +}         + +static inline void _endian_le16_p (uint16_t *outp, uint16_t in, +                                   endian_t endian) +{ +    switch (endian) { +    case ENDIAN_4321: +    case ENDIAN_2143: +        cpu_nswap16p(outp, in); +        break; +    case ENDIAN_1234: +    case ENDIAN_3412: +        cpu_swap16p(outp, in); +        break; +    } +}         + +static inline void _endian_le32_p (uint32_t *outp, uint32_t in, +                                   endian_t endian) +{ +    switch (endian) { +    case ENDIAN_4321: +        cpu_nswap32p(outp, in); +        break; +    case ENDIAN_1234: +        cpu_swap32p(outp, in); +        break; +    case ENDIAN_2143: +        /* TODO */ +        break; +    case ENDIAN_3412: +        /* TODO */ +        break; +    } +}         + +static inline void _endian_le64_p (uint64_t *outp, uint64_t in, +                                   endian_t endian) +{ +    switch (endian) { +    case ENDIAN_4321: +        cpu_nswap64p(outp, in); +        break; +    case ENDIAN_1234: +        cpu_swap64p(outp, in); +        break; +    case ENDIAN_2143: +        /* TODO */ +        break; +    case ENDIAN_3412: +        /* TODO */ +        break; +    } +}         + +static inline void endian_to_be16p (uint16_t *outp, uint16_t in, +                                    endian_t endian) +{ +    _endian_be16_p(outp, in, endian); +} + +static inline void endian_to_be32p (uint32_t *outp, uint32_t in, +                                    endian_t endian) +{ +    _endian_be32_p(outp, in, endian); +} + +static inline void endian_to_be64p (uint64_t *outp, uint64_t in, +                                    endian_t endian) +{ +    _endian_be64_p(outp, in, endian); +} + +static inline void endian_to_le16p (uint16_t *outp, uint16_t in, +                                    endian_t endian) +{ +    _endian_le16_p(outp, in, endian); +} + +static inline void endian_to_le32p (uint32_t *outp, uint32_t in, +                                    endian_t endian) +{ +    _endian_le32_p(outp, in, endian); +} + +static inline void endian_to_le64p (uint64_t *outp, uint64_t in, +                                    endian_t endian) +{ +    _endian_le64_p(outp, in, endian); +} + +static inline void be16_to_endianp (uint16_t *outp, uint16_t in, +                                    endian_t endian) +{ +    _endian_be16_p(outp, in, endian); +} + +static inline void be32_to_endianp (uint32_t *outp, uint32_t in, +                                    endian_t endian) +{ +    _endian_be32_p(outp, in, endian); +} + +static inline void be64_to_endianp (uint64_t *outp, uint64_t in, +                                    endian_t endian) +{ +    _endian_be64_p(outp, in, endian); +} + +static inline void le16_to_endianp (uint16_t *outp, uint16_t in, +                                    endian_t endian) +{ +    _endian_le16_p(outp, in, endian); +} + +static inline void le32_to_endianp (uint32_t *outp, uint32_t in, +                                    endian_t endian) +{ +    _endian_le32_p(outp, in, endian); +} + +static inline void le64_to_endianp (uint64_t *outp, uint64_t in, +                                    endian_t endian) +{ +    _endian_le64_p(outp, in, endian); +} + +#if defined (__CPU_ENDIAN_4321__) + +static inline void cpu_to_be16p (uint16_t *outp, uint16_t in) +{ +    cpu_swap16p(outp, in); +} + +static inline void cpu_to_be32p (uint32_t *outp, uint32_t in) +{ +    cpu_swap32p(outp, in); +} + +static inline void cpu_to_be64p (uint64_t *outp, uint64_t in) +{ +    cpu_swap64p(outp, in); +} + +static inline void cpu_to_le16p (uint16_t *outp, uint16_t in) +{ +    cpu_nswap16p(outp, in); +} + +static inline void cpu_to_le32p (uint32_t *outp, uint32_t in) +{ +    cpu_nswap32p(outp, in); +} + +static inline void cpu_to_le64p (uint64_t *outp, uint64_t in) +{ +    cpu_nswap64p(outp, in); +} + +static inline void be16_to_cpup (uint16_t *outp, uint16_t in) +{ +    cpu_swap16p(outp, in); +} + +static inline void be32_to_cpup (uint32_t *outp, uint32_t in) +{ +    cpu_swap32p(outp, in); +} + +static inline void be64_to_cpup (uint64_t *outp, uint64_t in) +{ +    cpu_swap64p(outp, in); +} + +static inline void le16_to_cpup (uint16_t *outp, uint16_t in) +{ +    cpu_nswap16p(outp, in); +} + +static inline void le32_to_cpup (uint32_t *outp, uint32_t in) +{ +    cpu_nswap32p(outp, in); +} + +static inline void le64_to_cpup (uint64_t *outp, uint64_t in) +{ +    cpu_nswap64p(outp, in); +} + +static inline void endian_to_cpu16p (uint16_t *outp, uint16_t in, +                                     endian_t endian) +{ +    endian_to_le16p(outp, in, endian); +} + +static inline void endian_to_cpu32p (uint32_t *outp, uint32_t in, +                                     endian_t endian) +{ +    endian_to_le32p(outp, in, endian); +} + +static inline void endian_to_cpu64p (uint64_t *outp, uint64_t in, +                                     endian_t endian) +{ +    endian_to_le64p(outp, in, endian); +} + +static inline void cpu16_to_endianp (uint16_t *outp, uint16_t in, +                                     endian_t endian) +{ +    le16_to_endianp(outp, in, endian); +} + +static inline void cpu32_to_endianp (uint32_t *outp, uint32_t in, +                                     endian_t endian) +{ +    le32_to_endianp(outp, in, endian); +} + +static inline void cpu64_to_endianp (uint64_t *outp, uint64_t in, +                                     endian_t endian) +{ +    le64_to_endianp(outp, in, endian); +} + +#elif defined (__CPU_ENDIAN_1234__) + +static inline void cpu_to_be16p (uint16_t *outp, uint16_t in) +{ +    cpu_nswap16p(outp, in); +} + +static inline void cpu_to_be32p (uint32_t *outp, uint32_t in) +{ +    cpu_nswap32p(outp, in); +} + +static inline void cpu_to_be64p (uint64_t *outp, uint64_t in) +{ +    cpu_nswap64p(outp, in); +} + +static inline void cpu_to_le16p (uint16_t *outp, uint16_t in) +{ +    cpu_swap16p(outp, in); +} + +static inline void cpu_to_le32p (uint32_t *outp, uint32_t in) +{ +    cpu_swap32p(outp, in); +} + +static inline void cpu_to_le64p (uint64_t *outp, uint64_t in) +{ +    cpu_swap64p(outp, in); +} + +static inline void endian_to_cpu16p (uint16_t *outp, uint16_t in, +                                     endian_t endian) +{ +    endian_to_be16p(outp, in, endian); +} + +static inline void endian_to_cpu32p (uint32_t *outp, uint32_t in, +                                     endian_t endian) +{ +    endian_to_be32p(outp, in, endian); +} + +static inline void endian_to_cpu64p (uint64_t *outp, uint64_t in, +                                     endian_t endian) +{ +    endian_to_be64p(outp, in, endian); +} + +static inline void cpu16_to_endianp (uint16_t *outp, uint16_t in, +                                     endian_t endian) +{ +    be16_to_endianp(outp, in, endian); +} + +static inline void cpu32_to_endianp (uint32_t *outp, uint32_t in, +                                     endian_t endian) +{ +    be32_to_endianp(outp, in, endian); +} + +static inline void cpu64_to_endianp (uint64_t *outp, uint64_t in, +                                     endian_t endian) +{ +    be64_to_endianp(outp, in, endian); +} + +#else /* 2143 / 3412 */ +/* TODO */ +#error "TODO" +#endif + +#endif /* !defined (__OHW_ENDIAN_H__) */ diff --git a/roms/openhackware/src/libc/include/errno.h b/roms/openhackware/src/libc/include/errno.h new file mode 100644 index 00000000..f6242a58 --- /dev/null +++ b/roms/openhackware/src/libc/include/errno.h @@ -0,0 +1,62 @@ +/* + * <errno.h> + * + * Open Hack'Ware BIOS errno management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ +#if !defined (__OHW_ERRNO_H__) +#define __OHW_ERRNO_H__ + +struct task { +    int errno; +}; + +extern struct task cur_task; + +void *get_current_stack (void); + +static inline int *errno_location (void) +{ +    /* XXX: to fix */ +#if 0 +    struct task *taskp; +     +    taskp = get_current_stack(); + +    return &taskp->errno; +#else +    return &cur_task.errno; +#endif +} + +static inline void set_errno (int errnum) +{ +    *(errno_location()) = errnum; +} + +static inline int get_errno (void) +{ +    return *(errno_location()); +} + +#define errno get_errno() + +enum { +    ENOMEM, +}; + +#endif /* !defined (__OHW_ERRNO_H__) */ diff --git a/roms/openhackware/src/libc/include/fcntl.h b/roms/openhackware/src/libc/include/fcntl.h new file mode 100644 index 00000000..d55c477b --- /dev/null +++ b/roms/openhackware/src/libc/include/fcntl.h @@ -0,0 +1,33 @@ +/* + * <fcntl.h> + * + * Open Hack'Ware BIOS: subset of POSIX fcntl definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_FCNTL_H__) +#define __OHW_FCNTL_H__ + +enum { +    O_RDONLY = 0x0001, +    O_WRONLY = 0x0002, +    O_RDWR   = 0x0003, +    O_CREAT  = 0x0010, +    O_EXCL   = 0x0020, +}; + +#endif /* !defined (__OHW_FCNTL_H__) */ diff --git a/roms/openhackware/src/libc/include/stddef.h b/roms/openhackware/src/libc/include/stddef.h new file mode 100644 index 00000000..0e973eb1 --- /dev/null +++ b/roms/openhackware/src/libc/include/stddef.h @@ -0,0 +1,38 @@ +/* + * <stddef.h> + * + * Open Hack'Ware BIOS: subset of POSIX standard definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_STDDEF_H__) +#define __OHW_STDDEF_H__ + +#include <stdint.h> + +typedef signed long ptrdiff_t; +typedef unsigned long size_t; +typedef signed long ssize_t; +typedef signed long off_t; + +/* We use unicode UCS-4 as the standard character set */ +typedef uint32_t wchar_t; + +/* XXX: to be moveed elsewhere */ +typedef uint32_t mode_t; + +#endif /* !defined (__OHW_STDDEF_H__) */ diff --git a/roms/openhackware/src/libc/include/stdint.h b/roms/openhackware/src/libc/include/stdint.h new file mode 100644 index 00000000..1efd3b3f --- /dev/null +++ b/roms/openhackware/src/libc/include/stdint.h @@ -0,0 +1,74 @@ +/* + * <stdint.h> + * + * Open Hack'Ware BIOS: arch dependent basic types + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_STDINT_H__) +#define __OHW_STDINT_H__ + +#if defined (__i386__) + +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned long long uint64_t; +typedef signed long long int64_t; + +#elif defined (__x86_64__) + +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned long uint64_t; +typedef signed long int64_t; + +#elif defined (__powerpc__) || defined (_ARCH_PPC) + +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned long long uint64_t; +typedef signed long long int64_t; + +#elif defined (__powerpc64__) || defined (_ARCH_PPC64) + +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned long uint64_t; +typedef signed long int64_t; +#else + +#error "unsupported CPU architecture" + +#endif + +#endif /* !defined (__OHW_STDINT_H__) */ diff --git a/roms/openhackware/src/libc/include/stdio.h b/roms/openhackware/src/libc/include/stdio.h new file mode 100644 index 00000000..f6bca865 --- /dev/null +++ b/roms/openhackware/src/libc/include/stdio.h @@ -0,0 +1,43 @@ +/* + * <stdio.h> + * + * Open Hack'Ware BIOS: subset of POSIX stdio definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_STDIO_H__) +#define __OHW_STDIO_H__ + +/* va_list is defined here */ +#include <stdarg.h> +/* size_t is defined here */ +#include <stddef.h> + +#define EOF ((int)-1) + +int printf (const char *format, ...); +int dprintf (const char *format, ...); +int sprintf (char *str, const char *format, ...); +int snprintf (char *str, size_t size, const char *format, ...); +int vprintf (const char *format, va_list ap); +int vdprintf (const char *format, va_list ap); +int vsprintf (char *str, const char *format, va_list ap); +int vsnprintf (char *str, size_t size, const char *format, va_list ap); + +int rename (const char *oldpath, const char *newpath); + +#endif /* !defined (__OHW_STDIO_H__) */ diff --git a/roms/openhackware/src/libc/include/stdlib.h b/roms/openhackware/src/libc/include/stdlib.h new file mode 100644 index 00000000..d0fab6cd --- /dev/null +++ b/roms/openhackware/src/libc/include/stdlib.h @@ -0,0 +1,50 @@ +/* + * <stdlib.h> + * + * Open Hack'Ware BIOS: subset of POSIX stdlib definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_STDLIB_H__) +#define __OHW_STDLIB_H__ + +#define NULL ((void *)0) + +/* size_t is declared here */ +#include <stddef.h> + +void *malloc (size_t size); +void free (void *ptr); +void *realloc (void *ptr, size_t size); + +/* memset is declared here */ +#include <string.h> + +static inline void *calloc (size_t nmemb, size_t size) +{ +    void *ret; + +    ret = malloc(nmemb * size); +    if (ret != NULL) +        memset(ret, 0, nmemb * size); + +    return ret; +} + +int mkstemp (char *template); + +#endif /* !defined (__OHW_STDLIB_H__) */ diff --git a/roms/openhackware/src/libc/include/string.h b/roms/openhackware/src/libc/include/string.h new file mode 100644 index 00000000..a2c4e0ea --- /dev/null +++ b/roms/openhackware/src/libc/include/string.h @@ -0,0 +1,90 @@ +/* + * <string.h> + * + * Open Hack'Ware BIOS: subset of POSIX string definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_STRING_H__) +#define __OHW_STRING_H__ + +/* size_t is declared here */ +#include <stddef.h> + +void *memcpy (void *dest, const void *src, size_t n); +void *memccpy (void *dest, const void *src, int c, size_t n); +void *mempcpy (void *dest, const void *src, size_t n); +void *memmove (void *dest, const void *src, size_t n); +void *memcmove (void *dest, const void *src, int c, size_t n); +void *mempmove (void *dest, const void *src, size_t n); +void *memset (void *s, int c, size_t n); +int memcmp (const void *s1, const void *s2, size_t n); +void *memchr (const void *s, int c, size_t n); +void *rawmemchr (const void *s, int c); +void *memrchr (const void *s, int c, size_t n); +void *memmem (const void *haystack, size_t haystacklen, +              const void *needle, size_t neddlelen); +void *strcpy (char *dest, const char *src); +void *strncpy (char *dest, const char *src, size_t n); +char *strdup (const char *s); +char *strndup (const char *s, size_t n); +void *stpcpy (char *dest, const char *src); +void *stpncpy (char *dest, const char *src, size_t n); +char *strcat (char *dest, const char *src); +char *strncat (char *dest, const char *src, size_t n); +int strcmp (const char *s1, const char *s2); +int strcasecmp (const char *s1, const char *s2); +int strncmp (const char *s1, const char *s2, size_t n); +int strncasecmp (const char *s1, const char *s2, size_t n); +char *strchr (const char *s, int c); +char *strchrnul (const char *s, int c); +char *strrchr (const char *s, int c); +char *strstr (const char *haystack, const char *needle); +char *strcasestr (const char *haystack, const char *needle); +#if 0 // TODO +size_t strspn (const char *s, const char *accept); +size_t strcspn (const char *s, const char *reject); +char *strpbrk (const char *s, const char *accept); +char *strtok (char *s, const char *delim); +char *strtok_r (char *s, const char *delim, char **ptrptr); +char *strsep (char **stringp, const char *delim); +#endif // TODO +char *basename (char *path); +char *dirname (char *path); +size_t strlen (const char *s); +size_t strnlen (const char *s, size_t maxlen); + +#if 0 +static inline int ffs (int value) +{ +    int tmp; +     +    __asm__ __volatile__ ("cntlzw %0, %1" : "=r" (tmp) : "r" (value)); +     +    return 32 - tmp; +} +#endif + +static inline int ffs (int value) +{ +    return __builtin_ffs(value); +} + +int ffsl (long i); +int ffsll (long long i); + +#endif /* !defined (__OHW_STRING_H__) */ diff --git a/roms/openhackware/src/libc/include/strings.h b/roms/openhackware/src/libc/include/strings.h new file mode 100644 index 00000000..64c2cfd7 --- /dev/null +++ b/roms/openhackware/src/libc/include/strings.h @@ -0,0 +1,27 @@ +/* + * <strings.h> + * + * Open Hack'Ware BIOS: Fake header for POSIX compatibility + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_STRINGS_H__) +#define __OHW_STRINGS_H__ + +#include <string.h> + +#endif /* !defined (__OHW_STRINGS_H__) */ diff --git a/roms/openhackware/src/libc/include/unistd.h b/roms/openhackware/src/libc/include/unistd.h new file mode 100644 index 00000000..4199a032 --- /dev/null +++ b/roms/openhackware/src/libc/include/unistd.h @@ -0,0 +1,43 @@ +/* + * <unistd.h> + * + * Open Hack'Ware BIOS: subset of POSIX unistd definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_UNISTD_H__) +#define __OHW_UNISTD_H__ + +/* size_t is defined here */ +/* mode_t is defined here (SHOULD NOT !) */ +/* off_t is defined here */ +#include <stddef.h> + +int open (const char *pathname, int flags, mode_t mode); +int close (int fd); +ssize_t read (int fd, void *buf, size_t count); +ssize_t write (int fd, const void *buf, size_t count); +enum { +    SEEK_SET = 0x01, +    SEEK_CUR = 0x02, +    SEEK_END = 0x03, +}; +off_t lseek (int fd, off_t offset, int whence); +int truncate (const char *path, off_t length); +int ftruncate (int fd, off_t length); + +#endif /* !defined (__OHW_UNISTD_H__) */ diff --git a/roms/openhackware/src/libc/src/errno.c b/roms/openhackware/src/libc/src/errno.c new file mode 100644 index 00000000..3417998d --- /dev/null +++ b/roms/openhackware/src/libc/src/errno.c @@ -0,0 +1,25 @@ +/* + * <errno.c> + * + * Open Hack'Ware BIOS: errno management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include "errno.h" + +/* XXX: to fix */ +struct task cur_task; diff --git a/roms/openhackware/src/libc/src/format.c b/roms/openhackware/src/libc/src/format.c new file mode 100644 index 00000000..f62d5dc4 --- /dev/null +++ b/roms/openhackware/src/libc/src/format.c @@ -0,0 +1,467 @@ +/* + * <format.c> + * + * Open Hack'Ware BIOS: formated output functions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +/* functions prototypes are here */ +#include <stdio.h> +/* va_list is defined here */ +#include <stdarg.h> +/* size_t is defined here */ +#include <stddef.h> +/* NULL is defined here */ +#include <stdlib.h> +/* write is defined here */ +#include <unistd.h> +/* memcpy is defined here */ +/* memset is defined here */ +/* strlen is defined here */ +#include <string.h> + +#define unused __attribute__ (( unused )) +int console_write (const void *buffer, int len); +/* XXX: this is a hack to be fixed */ +int serial_write (const void *buffer, int len); +#define debug_write serial_write + +/* Low level output fonctions */ +typedef size_t (*outf_t)(void *private, const unsigned char *buf, size_t len); + +/* output to fd */ +#if defined (__USE__vprintf__) +size_t outfd (void *private, const unsigned char *buf, size_t len) +{ +    int *fd = private; + +    if (*fd == 1 || *fd == 2) +        return console_write(buf, len); + +    return write(*fd, buf, len); +} + +size_t outf_dbg (void *private, const unsigned char *buf, size_t len) +{ +    int *fd = private; + +    if (*fd == 1 || *fd == 2) +        return debug_write(buf, len); + +    return write(*fd, buf, len); +} + +/* output to buffer */ +size_t outbuf (void *private, const unsigned char *buf, size_t len) +{ +    unsigned char **dst = private; + +    memcpy(*dst, buf, len); +    (*dst) += len; +    (*dst)[0] = '\0'; + +    return len; +} + +/* misc formatted output functions */ +/* out one character */ +static size_t outc (outf_t outf, void *private, +                    unsigned int value, size_t maxlen) +{ +    unsigned char buffer; +     +    if (maxlen < 1) +        return 0; +    buffer = value; +    if ((*outf)(private, &buffer, 1) == (size_t)-1) +        return -1; + +    return 1; +} + +/* out one int in decimal */ +static size_t outdecs (outf_t outf, void *private, +                       int value, size_t fill, size_t maxlen) +{ +    unsigned char buffer[12]; +    size_t pos, len; +    int sign; +     +    buffer[11] = '\0'; +    pos = 10; +    if (value == 0) { +        sign = 0; +        buffer[pos--] = '0'; +    } else { +        if (value < 0) { +            sign = -1; +            value = -value; +        } else { +            sign = 1; +        } +        for (; value != 0; pos--) { +            buffer[pos] = (value % 10) + '0'; +            value = value / 10; +        } +    } +    if (fill != 0) +        fill -= pos - 10; +    for (; fill != 0 && pos != 0; fill--) { +        buffer[pos--] = '0'; +    } +    if (sign == -1) +        buffer[pos--] = '-'; +    len = 10 - pos; +    if (len > maxlen) +        len = maxlen; +    if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1) +        return -1; + +    return len; +} + +/* out one unsigned int as decimal */ +static size_t outdecu (outf_t outf, void *private, +                       unsigned int value, size_t fill, size_t maxlen) +{ +    unsigned char buffer[11]; +    size_t pos, len; +     +    buffer[10] = '\0'; +    pos = 9; +    if (value == 0) { +        buffer[pos--] = '0'; +    } else { +        for (; value != 0; pos--) { +            buffer[pos] = (value % 10) + '0'; +            value = value / 10; +        } +    } +    if (fill != 0) +        fill -= pos - 9; +    for (; fill != 0 && pos != (size_t)-1; fill--) { +        buffer[pos--] = '0'; +    } +    len = 9 - pos; +    if (len > maxlen) +        len = maxlen; +    if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1) +        return -1; + +    return len; +} + +/* out one unsigned int as hexadecimal */ +static size_t outhex (outf_t outf, void *private, +                      unsigned int value, size_t fill, size_t maxlen) +{ +    unsigned char buffer[9]; +    size_t pos, len; +    int d; + +    buffer[8] = '\0'; +    pos = 7; +    if (value == 0) { +        buffer[pos--] = '0'; +    } else { +        for (; value != 0; pos--) { +            d = value & 0xF; +            if (d > 9) +            d += 'a' - '0' - 10; +            buffer[pos] = d + '0'; +            value = value >> 4; +        } +    } +    if (fill > 0) +        fill -= pos - 7; +    for (; fill != 0 && pos != (size_t)-1; fill--) { +        buffer[pos--] = '0'; +    } +    len = 7 - pos; +    if (len > maxlen) +        len = maxlen; +    if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1) +        return -1; + +    return len; +} + +static size_t outstr (outf_t outf, void *private, +                      const unsigned char *str, unused size_t fill, +                      size_t maxlen) +{ +#define TMPBUF_LEN 256 +#if 0 +    unsigned char tmpbuf[TMPBUF_LEN]; +    size_t len, totlen, tmp; +#else +    size_t len, totlen; +#endif + +    if (str == NULL) { +        /* Avoid crash if given a NULL string */ +        str = "<null>"; +    } +    len = strlen(str); +    totlen = 0; +#if 0 +    if (len < fill) { +        memset(tmpbuf, ' ', TMPBUF_LEN); +        fill -= len; +        for (; fill > 0; fill -= tmp) { +            tmp = fill; +            if (tmp > TMPBUF_LEN) +                tmp = TMPBUF_LEN; +            totlen += tmp; +            if (totlen > maxlen) { +                tmp = maxlen - totlen; +                totlen = maxlen; +            } +            (*outf)(private, tmpbuf, tmp); +        } +    } +#endif +    totlen += len; +    if (totlen > maxlen) { +        len = maxlen - totlen; +        totlen = maxlen; +    } +    if ((*outf)(private, str, len) == (size_t)-1) +        return -1; + +    return totlen; +} + +int _vprintf(outf_t outf, void *private, size_t maxlen, +             const unsigned char *format, va_list ap) +{ +    const unsigned char *p, *str; +    size_t maxfill, totlen, len, tmp; +    int cur; + +    cur = 0; +    str = format; +    for (totlen = 0; totlen != maxlen;) { +        for (p = str; (*p != '%' || cur > 6) && *p != '\0'; p++) +            continue; +        len = p - str; +        if (len + totlen > maxlen) +            len = maxlen - totlen; +        tmp = (*outf)(private, str, p - str); +        if (tmp == (size_t)-1) +            return -1; +        totlen += tmp; +        if (*p == '\0') +            break; +        maxfill = -2; +        str = p; +    next: +        p++; +        switch (*p) { +        case '\0': +            /* Invalid format */ +            goto invalid; +        case '0': +            if (maxfill >= (size_t)-2) { +                maxfill = -1; +                goto next; +            } +            /* No break here */ +        case '1' ... '9': +            switch (maxfill) { +            case -2: +                /* Invalid format */ +                goto invalid; +            case -1: +                maxfill = *p - '0'; +                break; +            default: +                maxfill = (maxfill * 10) + *p - '0'; +                break; +            } +            goto next; +        case 'l': +            /* Ignore it */ +            goto next; +        case 'h': +            /* Ignore it */ +            goto next; +        case 'd': +            if (maxfill == (size_t)-2 || maxfill == (size_t)(-1)) +                maxfill = 0; +            tmp = outdecs(outf, private, +                          va_arg(ap, int), maxfill, maxlen - totlen); +            break; +        case 'u': +            if (maxfill == (size_t)-2 || maxfill == (size_t)(-1)) +                maxfill = 0; +            tmp = outdecu(outf, private, +                          va_arg(ap, unsigned int), maxfill, maxlen - totlen); +            break; +        case 'x': +            if (maxfill == (size_t)-2 || maxfill == (size_t)(-1)) +                maxfill = 0; +            tmp = outhex(outf, private, +                         va_arg(ap, unsigned int), maxfill, maxlen - totlen); +            break; +        case 'p': +            if (p != str + 1) { +                /* Invalid format */ +                goto invalid; +            } else { +                if (maxfill == (size_t)-2 || maxfill == (size_t)(-1)) +                    maxfill = 0; +                tmp = outhex(outf, private, va_arg(ap, unsigned int), +                             maxfill, maxlen - totlen); +            } +            break; +        case 'c': +            if (p != str + 1) { +                /* Invalid format */ +                goto invalid; +            } else { +                tmp = outc(outf, private, +                           va_arg(ap, int), maxlen - totlen); +            } +            break; +        case 's': +            if (maxfill == (size_t)-2 || maxfill == (size_t)(-1)) +                maxfill = 0; +            str = va_arg(ap, const unsigned char *); +            tmp = outstr(outf, private, str, maxfill, maxlen - totlen); +            break; +        case '%': +            if (p != str + 1) { +                /* Invalid format */ +                goto invalid; +            } else { +                tmp = outc(outf, private, '%', maxlen - totlen); +            } +        default: +        invalid: +            /* Invalid format : display the raw string */ +            len = p - str + 1; +            if (len + totlen > maxlen) +                len = maxlen - totlen; +            tmp = (*outf)(private, str, len); +            break; +        } +        if (tmp == (size_t)-1) +            return -1; +        totlen += tmp; +        str = p + 1; +    } + +    return 0; +} +#else /* defined (__USE__vprintf__) */ +size_t outfd (void *private, const unsigned char *buf, size_t len); +size_t outf_dbg (void *private, const unsigned char *buf, size_t len); +size_t outbuf (void *private, const unsigned char *buf, size_t len); +int _vprintf(outf_t outf, void *private, size_t maxlen, +             const unsigned char *format, va_list ap); +#endif /* defined (__USE__vprintf__) */ + +#if defined (__USE_printf__) +int printf (const char *format, ...) +{ +    va_list ap; +    int fd = 1; +    int ret; + +    va_start(ap, format); +    ret = _vprintf(&outfd, &fd, -1, format, ap); +    va_end(ap); + +    return ret; +} +#endif /* defined (__USE_printf__) */ + +#if defined (__USE_dprintf__) +int dprintf (const char *format, ...) +{ +    va_list ap; +    int fd = 1; +    int ret; + +    va_start(ap, format); +    ret = _vprintf(&outf_dbg, &fd, -1, format, ap); +    va_end(ap); + +    return ret; +} +#endif /* defined (__USE_dprintf__) */ + +#if defined (__USE_sprintf__) +int sprintf (char *str, const char *format, ...) +{ +    va_list ap; +    int ret; + +    va_start(ap, format); +    ret = _vprintf(&outbuf, &str, -1, format, ap); +    va_end(ap); + +    return ret; +} +#endif /* defined (__USE_sprintf__) */ + +#if defined (__USE_snprintf__) +int snprintf (char *str, size_t size, const char *format, ...) +{ +    va_list ap; +    int ret; + +    va_start(ap, format); +    ret = _vprintf(&outbuf, &str, size, format, ap); +    va_end(ap); + +    return ret; +} +#endif /* defined (__USE_snprintf__) */ + +#if defined (__USE_vprintf__) +int vprintf (const char *format, va_list ap) +{ +    int fd = 1; + +    return _vprintf(&outfd, &fd, -1, format, ap); +} +#endif /* defined (__USE_vprintf__) */ + +#if defined (__USE_vdprintf__) +int vdprintf (const char *format, va_list ap) +{ +    int fd = 1; + +    return _vprintf(&outf_dbg, &fd, -1, format, ap); +} +#endif /* defined (__USE_vdprintf__) */ + +#if defined (__USE_vsprintf__) +int vsprintf (char *str, const char *format, va_list ap) +{ +    return _vprintf(&outbuf, &str, -1, format, ap); +} +#endif /* defined (__USE_vsprintf__) */ + +#if defined (__USE_vsnprintf__) +int vsnprintf (char *str, size_t size, const char *format, va_list ap) +{ +    return _vprintf(&outbuf, &str, size, format, ap); +} +#endif /* defined (__USE_vsnprintf__) */ diff --git a/roms/openhackware/src/libc/src/malloc.c b/roms/openhackware/src/libc/src/malloc.c new file mode 100644 index 00000000..14bd8e55 --- /dev/null +++ b/roms/openhackware/src/libc/src/malloc.c @@ -0,0 +1,730 @@ +/* + * <malloc.c> + * + * Open Hack'Ware BIOS: memory management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +/* functions prototypes are here */ +/* NULL is declared here */ +#include <stdlib.h> +/* memcpy is defined here */ +#include <string.h> +/* set_errno is defined here */ +#include <errno.h> + +//#define DEBUG_MEMOPS +#if defined (DEBUG_MEMOPS) +#define MEMOPS_PRINTF(fmt, args...) do { dprintf(fmt , ##args); } while (0) +#else +#define MEMOPS_PRINTF(fmt, args...) do { } while (0) +#endif + +#define unused __attribute__ (( unused )) + +/* XXX: TODO: put this elsewhere */ +void *page_get (int nb_pages); +void page_put (void *addr, int nb_pages); + +/* XXX: TOTO: put this elsewhere */ +#if defined (__i386__) +#define NATURAL_ALIGN_BITS 2 +#define PAGE_BITS 12 +#define __32_BITS 1 +#elif defined (__powerpc__) || defined (_ARCH_PPC) +#define NATURAL_ALIGN_BITS 2 +#define PAGE_BITS 12 +#define __32_BITS 1 +#elif defined (__x86_64__) +#define NATURAL_ALIGN_BITS 3 +#define PAGE_BITS 12 +#else +#error "Unsupported architecture" +#endif +#define PAGE_SIZE (1 << PAGE_BITS) +#define PAGE(addr) ((void *)((unsigned long)(addr) & ~(PAGE_SIZE - 1))) + + +#define MIN_ELEM_BITS (NATURAL_ALIGN_BITS + 1) +#define MIN_ELEM_SIZE (1 << (MIN_ELEM_BITS)) +#define MAX_ELEM_BITS (PAGE_BITS) +#define MAX_ELEM_SIZE (1 << (MAX_ELEM_BITS - 1)) +#define POOL_MAX ((MAX_ELEM_BITS) - (MIN_ELEM_BITS)) +#define CACHE_MAX 16 + +typedef struct free_slot_t free_slot_t; +struct free_slot_t { +    struct free_slot_t *next; +}; + +typedef struct page_descr_t page_descr_t; +struct page_descr_t { +    struct page_descr_t *next; +    struct page_descr_t *prev; +    void *addr; +    unsigned long nb; +}; + +/* + * This points to the first descriptor page where stand: + * - 1 descriptor for this page. + * - 1 decriptor pages list head. + * - POOL_MAX pool descriptors list heads. + * - CACHE_MAX page cache entries list heads. + */ +static void *malloc_base; + +/* Shared functions */ +static inline page_descr_t *main_descr_get (void) +{ +    return (page_descr_t *)malloc_base + 1; +} + +static inline page_descr_t *pool_head_get (int pool_idx) +{ +    return main_descr_get() + 1 + pool_idx; +} + +static inline page_descr_t *cache_head_get (int cache_idx) +{ +    return pool_head_get(POOL_MAX) + 1 + cache_idx; +} + +static void free_slots_init (void *page, int incr, int size) +{ +    free_slot_t *slot, *next; +     +    for (slot = page; +         slot < (free_slot_t *)((char *)page + size); slot = next) { +        next = (void *)((char *)slot + incr); +        slot->next = next; +    } +    slot = (void *)((char *)slot - incr); +    slot->next = NULL; +} + +static page_descr_t *descr_find_free (page_descr_t *head_descr, +                                      page_descr_t *skip_descr) +{ +    page_descr_t *cur_descr, *best; +    unsigned long max_used; + +    /* Try to always return the page with the less free slots to reduce +     * memory fragmentation. +     */ +    max_used = 0; +    best = NULL; +    for (cur_descr = head_descr->next; +         cur_descr != head_descr; cur_descr = cur_descr->next) { +        if (cur_descr != skip_descr && cur_descr->addr != NULL && +            cur_descr->nb >= max_used) { +            max_used = cur_descr->nb; +            best = cur_descr; +        } +    } + +    return best; +} + +/* Page descriptors management */ +static void page_descr_free (page_descr_t *head_descr) +{ +    head_descr->next->prev = head_descr->prev; +    head_descr->prev->next = head_descr->next; +    page_put(head_descr, 1); +} + +static page_descr_t *page_descr_get (void) +{ +    page_descr_t *main_descr, *head_descr, *page_descr; +    free_slot_t *first_free; + +    main_descr = main_descr_get(); +    head_descr = main_descr->addr; +    first_free = head_descr->addr; +    if (first_free == NULL) { +        /* Find a page with free descriptors */ +        head_descr = descr_find_free(main_descr, NULL); +        if (head_descr != NULL) { +            /* Get the first free slot */ +            first_free = head_descr->addr; +        } else { +            /* Allocate a new page */ +            head_descr = page_get(1); +            if (head_descr == NULL) { +                MEMOPS_PRINTF("%s: cannot get new head descriptor\n", +                              __func__); +                return NULL; +            } +            /* Initialise free slots */ +            free_slots_init(head_descr, sizeof(page_descr_t), PAGE_SIZE); +            /* Initialise page head descriptor */ +            head_descr->addr = head_descr + 1; +            head_descr->nb = 0; +            head_descr->next = main_descr; +            head_descr->prev = main_descr->prev; +            /* Update main descriptor */ +            main_descr->prev->next = head_descr; +            main_descr->prev = head_descr; +            main_descr->nb++; +            first_free = head_descr->addr; +        } +        main_descr->addr = head_descr; +    } +    head_descr->addr = first_free->next; +    if (head_descr->nb == 0) +        main_descr->nb--; +    head_descr->nb++; +    page_descr = (page_descr_t *)first_free; +    page_descr->prev = NULL; +    page_descr->next = NULL; +    page_descr->addr = NULL; +    page_descr->nb = 0; +     +    return page_descr; +} + +static void page_descr_put (page_descr_t *page_descr) +{ +    page_descr_t *main_descr, *head_descr, *next_descr, *free_descr; +    free_slot_t *first_free, *next_free; +     +    head_descr = PAGE(page_descr); +    /* Mark this descriptor as free */ +    next_free = head_descr->addr; +    first_free = (free_slot_t *)page_descr; +    first_free->next = next_free; +    /* Update page descriptor */ +    head_descr->addr = first_free; +    head_descr->nb--; +    main_descr = main_descr_get(); +    if (head_descr->nb == 0) { +        /* Try to free this page */ +        if (main_descr->addr == head_descr || +            main_descr->addr == NULL || +            main_descr->nb > 0) +            free_descr = descr_find_free(main_descr, head_descr); +        else +            free_descr = main_descr->addr; +        if (free_descr != NULL) { +            /* Update main descriptor */ +            page_descr_free(head_descr); +            main_descr->addr = free_descr; +        } else { +            main_descr->addr = head_descr; +            main_descr->nb++; +        } +    } else if (next_free == NULL) { +        free_descr = head_descr; +        for (head_descr = main_descr->next; +             main_descr->nb > 0 && head_descr != main_descr; +             head_descr = next_descr) { +            next_descr = head_descr->next; +            if (head_descr->nb == 0) { +                if (main_descr->addr == head_descr) +                    main_descr->addr = NULL; +                page_descr_free(head_descr); +                main_descr->nb--; +            } +        } +        if (main_descr->addr == NULL) +            main_descr->addr = free_descr; +    } +} + +/* Page cache management */ +static inline unsigned long cache_idx (void *addr) +{ +    return ((unsigned long)addr >> PAGE_BITS) & (CACHE_MAX - 1); +} + +static inline unsigned long page_cache_pool_idx (page_descr_t *cache_descr) +{ +    return (cache_descr->nb & 0xF); +} + +static inline page_descr_t *page_cache_page_descr (page_descr_t *cache_descr) +{ +    return (page_descr_t *)(cache_descr->nb & ~0xF); +} + +static int page_cache_add_page (page_descr_t *page_descr, int pool_idx) +{ +    page_descr_t *main_descr, *cache_head, *cache_descr; + +    main_descr = main_descr_get(); +    cache_head = cache_head_get(cache_idx(page_descr->addr)); +    cache_descr = page_descr_get(); +    if (cache_descr == NULL) { +        MEMOPS_PRINTF("%s: cannot get cache page\n", __func__); +        return -1; +    } +    cache_descr->nb = pool_idx | (unsigned long)page_descr; +    cache_descr->prev = cache_head; +    cache_descr->next = cache_head->next; +    cache_descr->addr = page_descr->addr; +    cache_head->next->prev = cache_descr; +    cache_head->next = cache_descr; + +    return 0; +} + +static page_descr_t *page_cache_get_descr (void *addr) +{ +    page_descr_t *main_descr, *cache_head, *cache_descr; + +    main_descr = main_descr_get(); +    cache_head = cache_head_get(cache_idx(addr)); +    for (cache_descr = cache_head->next; +         cache_descr != cache_head; cache_descr = cache_descr->next) { +        if (cache_descr->addr == addr) { +            return cache_descr; +        } +    } +    MEMOPS_PRINTF("%s: cannot get cache page descr\n", __func__); + +    return NULL; +} + +static void page_cache_remove_descr (page_descr_t *cache_descr) +{ +    cache_descr->next->prev = cache_descr->prev; +    cache_descr->prev->next = cache_descr->next; +    page_descr_put(cache_descr); +} + +/* Allocation by pool (size <= PAGE_SIZE / 2) */ +static void pool_descr_free (page_descr_t *cache_descr, +                             page_descr_t *pool_descr) +{ +    page_put(PAGE(pool_descr->addr), 1); +    page_cache_remove_descr(cache_descr); +    pool_descr->next->prev = pool_descr->prev; +    pool_descr->prev->next = pool_descr->next; +    page_descr_put(pool_descr); +} + +static void *pool_malloc (int pool_idx) +{ +    page_descr_t *main_descr, *pool_head, *pool_descr; +    free_slot_t *first_free, *next_free; + +    main_descr = main_descr_get(); +    pool_head = pool_head_get(pool_idx); +    pool_descr = pool_head->addr; +    if (pool_descr == NULL || pool_descr->addr == NULL) { +        pool_descr = descr_find_free(pool_head, NULL); +        if (pool_descr == NULL) { +            pool_descr = page_descr_get(); +            if (pool_descr == NULL) { +                MEMOPS_PRINTF("%s: cannot get pool descr\n", __func__); +                return NULL; +            } +            pool_descr->addr = page_get(1); +            if (pool_descr->addr == NULL) { +                MEMOPS_PRINTF("%s: cannot allocate new page\n", __func__); +                page_descr_put(pool_descr); +                return NULL; +            } +            if (page_cache_add_page(pool_descr, pool_idx) < 0) { +                MEMOPS_PRINTF("%s: cannot add new page to cache\n", __func__); +                page_put(pool_descr->addr, 1); +                page_descr_put(pool_descr); +                return NULL; +            } +            free_slots_init(pool_descr->addr, +                            1 << (MIN_ELEM_BITS + pool_idx), PAGE_SIZE); +            pool_descr->nb = 0; +            pool_descr->prev = pool_head->prev; +            pool_descr->next = pool_head; +            pool_head->prev->next = pool_descr; +            pool_head->prev = pool_descr; +            pool_head->nb++; +        } +        pool_head->addr = pool_descr; +    } +    first_free = pool_descr->addr; +    next_free = first_free->next; +    //    memset(first_free, 0, 1 << (MIN_ELEM_BITS + pool_idx)); +    pool_descr->addr = next_free; +    if (pool_descr->nb == 0) +        pool_head->nb--; +    pool_descr->nb++; + +    return first_free; +} + +unused static void pool_free (page_descr_t *cache_descr, void *area) +{ +    page_descr_t *pool_head, *pool_descr, *pool_next, *free_pool; +    free_slot_t *first_free, *next_free; +    unsigned long size, pool_idx; +     +    pool_descr = page_cache_page_descr(cache_descr); +    first_free = area; +    next_free = pool_descr->addr; +    pool_idx = page_cache_pool_idx(cache_descr); +    size = 1 << (MIN_ELEM_BITS + pool_idx); +    first_free->next = next_free; +    pool_descr->addr = first_free; +    pool_descr->nb--; +    pool_head = pool_head_get(pool_idx); +    if (pool_descr->nb == 0) { +        if (pool_head->addr == pool_descr || +            pool_head->addr == NULL || +            pool_head->nb > 0) +            free_pool = descr_find_free(pool_head, pool_descr); +        else +            free_pool = pool_head->addr; +        if (free_pool != NULL) { +            /* Free page & descriptor */ +            pool_descr_free(cache_descr, pool_descr); +            pool_head->addr = free_pool; +        } else { +            pool_head->addr = pool_descr; +            pool_head->nb++; +        } +    } else if (next_free == NULL) { +        free_pool = pool_descr; +        for (pool_descr = pool_head->next; +             pool_head->nb > 0 && pool_descr != pool_head; +             pool_descr = pool_next) { +            pool_next = pool_descr->next; +            if (pool_descr->nb == 0) { +                if (pool_head->addr == pool_descr) +                    pool_head->addr = NULL; +                cache_descr = page_cache_get_descr(PAGE(pool_descr->addr)); +                if (cache_descr != NULL) { +                    pool_descr_free(cache_descr, pool_descr); +                    pool_head->nb--; +                } else { +                    /* Incoherency: what to do ? */ +                } +            } +        } +        if (pool_head->addr == NULL) +            pool_head->addr = free_pool; +    } +} + +/* Big area management (size > PAGE_SIZE / 2) */ +static void *big_malloc (int nb_pages) +{ +    page_descr_t *main_descr, *pool_head, *pool_descr; + +    main_descr = main_descr_get(); +    pool_head = pool_head_get(POOL_MAX); +    pool_descr = page_descr_get(); +    if (pool_descr == NULL) { +        MEMOPS_PRINTF("%s: cannot get pool descr\n", __func__); +        return NULL; +    } +    pool_descr->addr = page_get(nb_pages); +    if (pool_descr->addr == NULL) { +        page_descr_put(pool_descr); +        MEMOPS_PRINTF("%s: cannot get page\n", __func__); +        return NULL; +    } +    if (page_cache_add_page(pool_descr, POOL_MAX) < 0) { +        page_put(pool_descr->addr, nb_pages); +        page_descr_put(pool_descr); +        MEMOPS_PRINTF("%s: cannot get add page to cache\n", __func__); +        return NULL; +    } +    pool_descr->prev = pool_head->prev; +    pool_descr->next = pool_head; +    pool_descr->nb = nb_pages; +    pool_head->prev->next = pool_descr; +    pool_head->prev = pool_descr; + +    return pool_descr->addr; +} + +static void big_free (page_descr_t *cache_descr) +{ +    page_descr_t *pool_descr; + +    pool_descr = page_cache_page_descr(cache_descr); +    if (pool_descr->addr != NULL && pool_descr->nb != 0) { +        page_put(pool_descr->addr, pool_descr->nb); +        pool_descr->next->prev = pool_descr->prev; +        pool_descr->prev->next = pool_descr->next; +        page_descr_put(pool_descr); +        page_cache_remove_descr(cache_descr); +    } else { +        MEMOPS_PRINTF("%s: ERROR %p %d\n", +                      __func__, pool_descr->addr, (int)pool_descr->nb); +    } +} + +unused static void *big_realloc (page_descr_t *cache_descr, int new_size) +{ +    void *new_area; +    page_descr_t *pool_descr; +    unsigned long new_nb; + +    pool_descr = page_cache_page_descr(cache_descr); +    new_nb = (new_size + PAGE_SIZE - 1) / PAGE_SIZE; +    if (new_nb == pool_descr->nb) { +        new_area = cache_descr->addr; +    } else { +        new_area = big_malloc(new_size); +        memcpy(new_area, cache_descr->addr, pool_descr->nb * PAGE_SIZE); +        big_free(cache_descr); +    } + +    return new_area; +} + +/* Global entry points */ +int page_descrs_init (void) +{ +    page_descr_t *main_descr, *page_descr, *pool_head, *cache_head; +    int i; + +    /* Allocate first descriptor page */ +    malloc_base = page_get(1); +    if (malloc_base == NULL) { +        set_errno(ENOMEM); +        MEMOPS_PRINTF("%s: cannot get main descriptor\n", __func__); +        return -1; +    } +    /* Init free slots in this page */ +    free_slots_init(malloc_base, sizeof(page_descr_t), PAGE_SIZE); +    /* Init main descriptor */ +    page_descr = malloc_base; +    main_descr = main_descr_get(); +    main_descr->addr = page_descr; +    main_descr->nb = 0; +    main_descr->next = page_descr; +    main_descr->prev = page_descr; +    page_descr->nb = 1; +    page_descr->addr = page_descr + 2; +    page_descr->next = main_descr; +    page_descr->prev = main_descr; +    /* Init pool lists heads */ +    for (i = 0; i <= POOL_MAX; i++) { +        pool_head = page_descr_get(); +        if (pool_head == NULL) { +            page_put(malloc_base, 1); +            malloc_base = NULL; +            MEMOPS_PRINTF("%s: cannot get pool descriptor %d\n", __func__, i); +            return -1; +        } +        pool_head->prev = pool_head; +        pool_head->next = pool_head; +        pool_head->addr = NULL; +    } +    /* Init page caches lists heads */ +    for (i = 0; i < CACHE_MAX; i++) { +        cache_head = page_descr_get(); +        if (cache_head == NULL) { +            page_put(malloc_base, 1); +            malloc_base = NULL; +            MEMOPS_PRINTF("%s: cannot get page cache descriptor %d\n", +                          __func__, i); +            return -1; +        } +        cache_head->prev = cache_head; +        cache_head->next = cache_head; +    } + +    return 0; +} + +static inline int get_pool_idx (size_t size) +{ +    int pool_idx; +     +    pool_idx = 0; +    for (size /= MIN_ELEM_SIZE; size != 0; size = size / 2) +        pool_idx++; + +    return pool_idx; +} + +#if 1 +void *malloc (size_t size) +{ +    void *ret; +    int pool_idx; +     +    if (malloc_base == NULL || size == 0) { +        ret = NULL; +    } else if (size >= MAX_ELEM_SIZE) { +        ret = big_malloc((size + PAGE_SIZE - 1) / PAGE_SIZE); +    } else { +        if (size <= MIN_ELEM_SIZE) +            pool_idx = 0; +        else { +            pool_idx = get_pool_idx(size); +        } +        ret = pool_malloc(pool_idx); +    } +    if (ret != NULL) +        memset(ret, 0, size); +#if 0 +    memory_dump(); +    printf("%s(%d) => %p\n", __func__, size, ret); +#endif + +    return ret; +} +#endif + +#if 0 +void free (void *area) +{ +    page_descr_t *cache_descr; +    int pool_idx; + +    if (malloc_base == NULL || area == NULL) +        return; +    cache_descr = page_cache_get_descr(PAGE(area)); +    if (cache_descr != NULL) { +        pool_idx = page_cache_pool_idx(cache_descr); +        if (pool_idx == POOL_MAX) { +            big_free(cache_descr); +        } else { +            pool_free(cache_descr, area); +        } +    } else { +        /* Given area is not valid */ +        MEMOPS_PRINTF("ERROR: area to free not found: %p\n", area); +    } +} +#endif + +#if 0 +void *realloc (void *area, size_t new_size) +{ +    void *new_area; +    page_descr_t *pool_descr, *cache_descr; +    size_t size; +    int pool_idx, new_pool_idx; + +    if (malloc_base == NULL || new_size == 0) { +        free(area); +        return NULL; +    } +    if (area == NULL) +        return malloc(new_size); +    cache_descr = page_cache_get_descr(PAGE(area)); +    if (cache_descr == NULL) { +        /* Given area is not valid */ +        return NULL; +    } +    pool_idx = page_cache_pool_idx(cache_descr); +    if (new_size >= MAX_ELEM_SIZE) { +        new_pool_idx = POOL_MAX; +        if (pool_idx == POOL_MAX) +            return big_realloc(cache_descr, new_size); +    } else { +        if (new_size <= MIN_ELEM_SIZE) +            new_pool_idx = 0; +        else +            new_pool_idx = get_pool_idx(size); +        if (pool_idx == new_pool_idx) +            return area; +    } +    /* Common case: alloc, copy & free */ +    if (new_pool_idx == POOL_MAX) +        new_area = big_malloc((new_size + PAGE_SIZE - 1) / PAGE_SIZE); +    else +        new_area = pool_malloc(new_pool_idx); +    if (new_area == NULL) +        return NULL; +    if (pool_idx == POOL_MAX) { +        pool_descr = page_cache_page_descr(cache_descr); +        size = pool_descr->nb * PAGE_SIZE; +    } else { +        size = MIN_ELEM_SIZE << pool_idx; +    } +    memcpy(new_area, area, size); +    if (pool_idx == POOL_MAX) +        big_free(cache_descr); +    else +        pool_free(cache_descr, area); +     +    return new_area; +} +#endif + +void memory_dump (void) +{ +#if defined (DEBUG_MEMOPS) +    page_descr_t *main_descr, *page_descr; +    page_descr_t *pool_head, *pool_descr, *cache_head, *cache_descr; +    int i, n; + +    main_descr = main_descr_get(); +    /* Dump descriptor pages */ +    printf("Descriptor pages dump: %p max=%d %d pages with no alloc descrs\n", +           main_descr, (int)(PAGE_SIZE / sizeof(page_descr_t)), (int)main_descr->nb); +    n = 0; +    for (page_descr = main_descr->next; +         page_descr != main_descr; page_descr = page_descr->next) { +        printf("Descr %d : %p %p used: %d\n", +               n, page_descr, page_descr->addr, (int)page_descr->nb); +        n++; +    } +    /* Dump pool areas pages */ +    for (i = 0; i < POOL_MAX; i++) { +        n = 0; +        pool_head = pool_head_get(i); +        printf("Pool %d %p\n", i, pool_head); +        for (pool_descr = pool_head->next; +             pool_descr != pool_head; pool_descr = pool_descr->next) { +            printf("Pool %d descr %d : %p %p used: %d size %d free: %p %p\n", +                   i, n, pool_descr, PAGE(pool_descr->addr), (int)pool_descr->nb, +                   1 << (MIN_ELEM_BITS + i), pool_descr->addr, +                   ((free_slot_t *)pool_descr->addr)->next); +            n++; +        } +        printf(" => %d pages allocated\n", n); +    } +#if 0 +    /* Dump big area pages */ +    printf("Pool %d\n", POOL_MAX); +    n = 0; +    pool_head = pool_head_get(POOL_MAX); +    for (pool_descr = pool_head->next; +         pool_descr != pool_head; pool_descr = pool_descr->next) { +        printf("Pool %d descr %d : %p nb pages: %d\n", +               POOL_MAX, n, pool_descr->addr, (int)pool_descr->nb); +        n++; +    } +    printf(" => %d pages allocated\n", n); +    /* Dump page cache */ +    for (i = 0; i < CACHE_MAX; i++) { +        printf("Page cache 0x____%x___\n", i); +        n = 0; +        cache_head = cache_head_get(i); +        for (cache_descr = cache_head->next; +             cache_descr != cache_head; cache_descr = cache_descr->next) { +            pool_descr = page_cache_page_descr(cache_descr); +            printf("Cache %d descr %d : %p pool: %d descr: %p %p %d\n", +                   i, n, cache_descr->addr, +                   (int)page_cache_pool_idx(cache_descr), +                   pool_descr, pool_descr->addr, (int)pool_descr->nb); +            n++; +        } +        printf(" => %d pages allocated\n", n); +    } +#endif +#endif +} diff --git a/roms/openhackware/src/libc/src/mem.c b/roms/openhackware/src/libc/src/mem.c new file mode 100644 index 00000000..a75ff851 --- /dev/null +++ b/roms/openhackware/src/libc/src/mem.c @@ -0,0 +1,251 @@ +/* + * <mem.c> + * + * Open Hack'Ware BIOS: mem<xxx> functions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +/* functions prototypes are here */ +#include <string.h> +/* NULL is declared here */ +#include <stdlib.h> + +/* mem___ functions */ +#if defined (__USE_memcpy__) +void *memcpy (void *dest, const void *src, size_t n) +{ +    const char *p; +    char *q; + +    p = src; +    q = dest; +    for (; n != 0; n--) +        *q++ = *p++; + +    return dest; +} +#endif + +#if defined (__USE_memccpy__) +void *memccpy (void *dest, const void *src, int c, size_t n) +{ +    const char *p; +    char *q, *r; + +    p = src; +    q = dest; +    r = NULL; +    for (; n != 0; n--, q++) { +        *q = *p++; +        if (*q == c) { +            r = q; +            break; +        } +    } + +    return r; +} +#endif + +#if defined (__USE_mempcpy__) +/* GNU extension */ +void *mempcpy (void *dest, const void *src, size_t n) +{ +    const char *p; +    char *q; + +    p = src; +    q = dest; +    for (; n != 0; n--) +        *q++ = *p++; + +    return q; +} +#endif + +#if defined (__USE_memmove__) +void *memmove (void *dest, const void *src, size_t n) +{ +    const char *p; +    char *q; + +    p = src; +    q = dest; +    if (dest <= src) { +        for (; n != 0; n--) +            *q++ = *p++; +    } else { +        p += n; +        q += n; +        for (; n != 0; n--) +            *--q = *--p; +    } + +    return dest; +} +#endif + +#if defined (__USE_memcmove__) +/* OHW extension */ +void *memcmove (void *dest, const void *src, int c, size_t n) +{ +    const char *p; +    char *q, *r; + +    p = src; +    q = dest; +    r = NULL; +    if (dest <= src) { +        for (; n != 0; n--, q++) { +            *q++ = *p++; +            if (*q == c) { +                r = q; +                break; +            } +        } +    } else { +        p += n; +        q += n; +        for (; n != 0; n--, q--) { +            *--q = *--p; +            if (*q == c) { +                r = q; +                break; +            } +        } +    } + +    return dest; +} +#endif + +#if defined (__USE_mempmove__) +/* OHW extension */ +void *mempmove (void *dest, const void *src, size_t n) +{ +    const char *p; +    char *q, *r; + +    p = src; +    q = dest; +    r = q + n; +    if (dest <= src) { +        for (; n != 0; n--) +            *q++ = *p++; +    } else { +        p += n; +        q = r; +        for (; n != 0; n--) +            *--q = *--p; +    } + +    return r; +} +#endif + +#if defined (__USE_memset__) +void *memset (void *s, int c, size_t n) +{ +    char *p; + +    for (p = s; n != 0; n--) +        *p++ = c; + +    return s; +} +#endif + +#if defined (__USE_memcmp__) +int memcmp (const void *s1, const void *s2, size_t n) +{ +    const char *p, *q; +    int ret; + +    p = s1; +    q = s2; +    for (ret = 0; n != 0 && ret == 0; n--) +        ret = *p++ - *q++; + +    return ret; +} +#endif + +#if defined (__USE_memchr__) +void *memchr (const void *s, int c, size_t n) +{ +    const char *p, *r; + +    r = NULL; +    for (p = s; n != 0; n--, p++) { +        if (*p == c) { +            r = p; +            break; +        } +    } + +    return (void *)r; +} +#endif + +#if defined (__USE_rawmemchr__) +/* GNU extension */ +void *rawmemchr (const void *s, int c) +{ +    const char *p; + +    for (p = s; *p != c; p++) +        continue; + +    return (void *)p; +} +#endif + +#if defined (__USE_memrchr__) +void *memrchr (const void *s, int c, size_t n) +{ +    const char *p, *r; + +    r = NULL; +    for (p = s + n; n != 0; n--, p--) { +        if (*p == c) { +            r = p; +            break; +        } +    } + +    return (void *)r; +} +#endif + +#if defined (__USE_memmem__) +/* GNU extension */ +void *memmem (const void *haystack, size_t haystacklen, +              const void *needle, size_t neddlelen) +{ +    const char *p, *r; + +    r = NULL; +    for (p = haystack; haystacklen > neddlelen; haystacklen--, p++) { +        if (memcmp(p, needle, neddlelen) == 0) { +            r = p; +            break; +        } +    } + +    return (void *)r; +} +#endif diff --git a/roms/openhackware/src/libc/src/str.c b/roms/openhackware/src/libc/src/str.c new file mode 100644 index 00000000..24548fa0 --- /dev/null +++ b/roms/openhackware/src/libc/src/str.c @@ -0,0 +1,430 @@ +/* + * <str.c> + * + * Open Hack'Ware BIOS: str<xxx> functions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +/* functions prototypes are here */ +#include <string.h> +/* NULL is defined here */ +/* malloc is defined here */ +#include <stdlib.h> +/* toupper is defined here */ +#include <ctype.h> + +/* str___ functions */ +#if defined (__USE_strcpy__) +void *strcpy (char *dest, const char *src) +{ +    char *q; + +    q = dest; +    for (; ; q++) { +        *q = *src++; +        if (*q == '\0') +            break; +    } + +    return dest; +} +#endif + +#if defined (__USE_strncpy__) +void *strncpy (char *dest, const char *src, size_t n) +{ +    char *q; + +    q = dest; +    for (; n != 0; n--, q++) { +        *q = *src++; +        if (*q == '\0') +            break; +    } + +    return dest; +} +#endif + +#if defined (__USE_strdup__) +char *strdup (const char *s) +{ +    char *dest; +    size_t len; + +    len = strlen(s) + 1; +    dest = malloc(len); +    if (dest != NULL) +        memcpy(dest, s, len); + +    return dest; +} +#endif + +#if defined (__USE_strndup__) +/* GNU extension */ +char *strndup (const char *s, size_t n) +{ +    char *dest; +    size_t len; + +    len = strlen(s) + 1; +    if (len > n) +        len = n; +    dest = malloc(len); +    if (dest != NULL) { +        memcpy(dest, s, len - 1); +        dest[len - 1] = '\0'; +    } + +    return dest; +} +#endif + +#if defined (__USE_stpcpy__) +void *stpcpy (char *dest, const char *src) +{ +    char *q; + +    q = dest; +    for (; ; q++) { +        *q = *src++; +        if (*q == '\0') +            break; +    } + +    return q; +} +#endif + +#if defined (__USE_stpncpy__) +void *stpncpy (char *dest, const char *src, size_t n) +{ +    char *q; + +    q = dest; +    for (; n != 0; n--, q++) { +        *q = *src++; +        if (*q == '\0') +            break; +    } + +    return q; +} +#endif + +#if defined (__USE_strcat__) +char *strcat (char *dest, const char *src) +{ +    char *q; +     +    for (q = dest + strlen(dest); ; q++) { +        *q = *src++; +        if (*q == '\0') +            break; +    } + +    return dest; +} +#endif + +#if defined (__USE_strncat__) +char *strncat (char *dest, const char *src, size_t n) +{ +    char *q; +     +    for (q = dest + strlen(dest); n != 0; n--, q++) { +        *q = *src++; +        if (*q == '\0') +            break; +    } + +    return dest; +} +#endif + +#if defined (__USE_strcmp__) +int strcmp (const char *s1, const char *s2) +{ +    int ret; +     +    for (ret = 0; ret == 0; s1++) { +        ret = *s1 - *s2++; +        if (*s1 == '\0') +            break; +    } + +    return ret; +} +#endif + +#if defined (__USE_strcasecmp__) +int strcasecmp (const char *s1, const char *s2) +{ +    int ret; +     +    for (ret = 0; ret == 0; s1++) { +        ret = toupper(*s1) - toupper(*s2++); +        if (*s1 == '\0') +            break; +    } + +    return ret; +} +#endif + +#if defined (__USE_strncmp__) +int strncmp (const char *s1, const char *s2, size_t n) +{ +    int ret; +     +    for (ret = 0; ret == 0 && n != 0; n--, s1++) { +        ret = *s1 - *s2++; +        if (*s1 == '\0') +            break; +    } + +    return ret; +} +#endif + +#if defined (__USE_strncasecmp__) +int strncasecmp (const char *s1, const char *s2, size_t n) +{ +    int ret; +     +    for (ret = 0; ret == 0 && n != 0; n--, s1++) { +        ret = toupper(*s1) - toupper(*s2++); +        if (*s1 == '\0') +            break; +    } + +    return ret; +} +#endif + +#if defined (__USE_strchr__) +char *strchr (const char *s, int c) +{ +    const char *r; + +    for (r = NULL; *s != '\0'; s++) { +        if (*s == c) { +            r = s; +            break; +        } +    } + +    return (char *)r; +} +#endif + +#if defined (__USE_strchrnul__) +/* GNU extension */ +char *strchrnul (const char *s, int c) +{ +    for (; *s != '\0' && *s != c; s++) +        continue; + +    return (char *)s; +} +#endif + +#if defined (__USE_strrchr__) +char *strrchr (const char *s, int c) +{ +    const char *p, *r; + +    r = NULL; +    for (p = s + strlen(s); p != s; p--) { +        if (*p == c) { +            r = p; +            break; +        } +    } + +    return (char *)r; +} +#endif + +#if defined (__USE_strstr__) +char *strstr (const char *haystack, const char *needle) +{ +    const char *r; +    size_t hlen, nlen; + +    if (*needle == '\0') +        return (char *)haystack; +    r = NULL; +    hlen = strlen(haystack); +    nlen = strlen(needle); +    for (; hlen > nlen; hlen--, haystack++) { +        if (memcmp(haystack, needle, nlen) == 0) { +            r = haystack; +            break; +        } +    } + +    return (char *)r; +} +#endif + +#if defined (__USE_strcasestr__) +char *strcasestr (const char *haystack, const char *needle) +{ +    const char *p, *q, *r; +    size_t hlen, nlen, n; + +    if (*needle == '\0') +        return (char *)haystack; +    r = NULL; +    hlen = strlen(haystack); +    nlen = strlen(needle); +    for (; hlen > nlen; hlen--, haystack++) { +        p = haystack; +        q = needle; +        for (n = nlen; n != 0; n--) { +            if (toupper(*p++) != toupper(*q++)) +                break; +        } +        if (n == 0) { +            r = haystack; +            break; +        } +    } + +    return (char *)r; +} +#endif + +#if defined (__USE_strspn__) +#error "TODO" +size_t strspn (const char *s, const char *accept) +{ +} +#endif + +#if defined (__USE_strcspn__) +#error "TODO" +size_t strcspn (const char *s, const char *reject) +{ +} +#endif + +#if defined (__USE_strpbrk__) +#error "TODO" +char *strpbrk (const char *s, const char *accept) +{ +} +#endif + +#if defined (__USE_strtok__) +#error "TODO" +char *strtok (char *s, const char *delim) +{ +} +#endif + +#if defined (__USE_strtok_r__) +#error "TODO" +char *strtok_r (char *s, const char *delim, char **ptrptr) +{ +} +#endif + +#if defined (__USE_strsep__) +#error "TODO" +char *strsep (char **stringp, const char *delim) +{ +} +#endif + +#if defined (__USE_basename__) +char *basename (char *path) +{ +    char *sl; +    size_t len; + +    if (path == NULL || (len = strlen(path)) == 0) +        return strdup("."); +    sl = path + len - 1; +    if (*sl == '/') +        sl--; +    for (; sl != path; sl--) { +        if (*sl == '/') +            break; +    } +     +    return strdup(sl + 1); +} +#endif + +#if defined (__USE_dirname__) +char *dirname (char *path) +{ +    char *sl, *ret; +    size_t len; + +    if (path == NULL || (len = strlen(path)) == 0) { +        ret = strdup("."); +    } else { +        sl = path + len - 1; +        if (*sl == '/') +            sl--; +        for (; sl != path; sl--) { +            if (*sl == '/') +                break; +        } +        len = sl - path; +        if (len == 0) { +            ret = strdup("."); +        } else { +            ret = malloc(len + 1); +            if (ret != NULL) { +                memcpy(path, ret, len); +                path[len] = '\0'; +            } +        } +    } +     +    return ret; +} +#endif + +#if defined (__USE_strlen__) +size_t strlen (const char *s) +{ +    size_t len; + +    for (len = 0; *s != '\0'; len++) +        s++; + +    return len; +} +#endif + +#if defined (__USE_strnlen__) +size_t strnlen (const char *s, size_t maxlen) +{ +    size_t len; + +    for (len = 0; maxlen != 0 && *s != '\0'; maxlen--, len++) +        s++; + +    return len; +} +#endif diff --git a/roms/openhackware/src/libexec/chrp.c b/roms/openhackware/src/libexec/chrp.c new file mode 100644 index 00000000..9a2be2ea --- /dev/null +++ b/roms/openhackware/src/libexec/chrp.c @@ -0,0 +1,404 @@ +/* + * <chrp.c> + * + * Open Hack'Ware BIOS CHRP boot file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include "bios.h" +#include "exec.h" +#include "libfs/libfs.h" + +/* Simple XML parser */ +typedef struct XML_tag_t XML_tag_t; +struct XML_tag_t { +    unsigned char *name; +    XML_tag_t *up; +    int dlen; +    void *data; +}; + +enum { +    CHRP_TAG_UNKNOWN = 0, +    CHRP_TAG_CHRP_BOOT, +    CHRP_TAG_COMPATIBLE, +    CHRP_TAG_DESCRIPTION, +    CHRP_TAG_BOOT_SCRIPT, +    CHRP_TAG_OS_BADGE_ICONS, +    CHRP_TAG_ICON, +    CHRP_TAG_BITMAP, +    CHRP_TAG_LICENSE, +}; + +enum { +    CHRP_SCRIPT_IGNORE = 0, +    CHRP_SCRIPT_LOAD_BOOT, +    CHRP_SCRIPT_EMBEDDED, +}; + +enum { +    XML_STATE_OUT = 0, +    XML_STATE_TAG, +    XML_STATE_DATA, +}; + +static int XML_get_type (const unsigned char *name) +{ +    int ret; + +    if (strcmp(name, "CHRP-BOOT") == 0) +        ret = CHRP_TAG_CHRP_BOOT; +    else if (strcmp(name, "COMPATIBLE") == 0) +        ret = CHRP_TAG_COMPATIBLE; +    else if (strcmp(name, "DESCRIPTION") == 0) +        ret = CHRP_TAG_DESCRIPTION; +    else if (strcmp(name, "BOOT-SCRIPT") == 0) +        ret = CHRP_TAG_BOOT_SCRIPT; +    else if (strcmp(name, "OS-BADGE-ICONS") == 0) +        ret = CHRP_TAG_OS_BADGE_ICONS; +    else if (strcmp(name, "ICON") == 0) +        ret = CHRP_TAG_ICON; +    else if (strcmp(name, "BITMAP") == 0) +        ret = CHRP_TAG_BITMAP; +    else if (strcmp(name, "LICENSE") == 0) +        ret = CHRP_TAG_LICENSE; +    else +        ret = CHRP_TAG_UNKNOWN; + +    return ret; +} + +static unsigned char *strfind (const unsigned char *buf, const unsigned char *str) +{ +    const unsigned char *pos; +    int len = strlen(str); + +    //    DPRINTF("Look for '%s' in \n'%s'\n", str, buf); +    for (pos = buf; *pos != '\0'; pos++) { +        if (memcmp(pos, str, len) == 0) +            return (unsigned char *)pos; +    } + +    return NULL; +} + +int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end, +                    uint32_t loffset) +{ +#define TMPNAME_LEN 512 +    unsigned char tmpname[TMPNAME_LEN], *tmpp, *buf, *pos, *endc, c; +    XML_tag_t *tag, *tmp, *first; +    part_t *part; +    inode_t *inode; +    int state; +    int script_type = CHRP_SCRIPT_IGNORE; +    uint32_t crc, offset = 0; +    int ret, rel = 0; + +    buf = malloc(16384); +    /* Check the file head */ +    file_seek(file, loffset); +    fs_read(file, buf, 11); +    if (memcmp(buf, "<CHRP-BOOT>", 11) != 0) { +        ERROR("Not an Apple CHRP boot file !\n"); +        return -2; +    } +    /* Re-seek at start of the file and start parsing it */ +    file_seek(file, loffset); +    pos = buf; +    tag = NULL; +    first = NULL; +    ret = -1; +    fs_read(file, &c, 1); +    offset++; +    for (state = XML_STATE_TAG; state != XML_STATE_OUT;) { +        /* Get next char */ +        fs_read(file, &c, 1); +        offset++; +        if ((state == XML_STATE_TAG && c != '>') || +            (state == XML_STATE_DATA && c != '<')) { +            *pos++ = c; +            continue; +        } +        *pos++ = '\0'; +        switch (state) { +        case XML_STATE_TAG: +            if (*buf == '/') { +                if (tag == NULL || strcmp(buf + 1, tag->name) != 0) { +                    ERROR("XML error: open name: '%s' close name: '%s'\n", +                          buf + 1, tag->name); +                    goto out; +                } +                DPRINTF("Close tag: '%s'\n", tag->name); +                switch (XML_get_type(tag->name)) { +                case CHRP_TAG_CHRP_BOOT: +                    /* Nothing to do */ +                    break; +                case CHRP_TAG_COMPATIBLE: +                    /* Won't check... */ +                    pos = tag->data; +                    if (*(char *)tag->data == 0x0d) { +                        pos++; +                    } +                    DPRINTF("Compatible: '%s'\n", pos); +                    break; +                case CHRP_TAG_DESCRIPTION: +                    pos = tag->data; +                    if (*(char *)tag->data == 0x0d) { +                        pos++; +                    } +                    DPRINTF("Description: '%s'\n", pos); +                    break; +                case CHRP_TAG_BOOT_SCRIPT: +                    /* Here is the interresting part... */ +                    crc = crc32(0, tag->data, tag->dlen); +#if 0 +                    DPRINTF("Forth script: %08x\n%s\n", +                            crc, (char *)tag->data); +#endif +                    switch (crc) { +                    case 0x5464F92C: +                        /* Mandrake 9.1 CD1 boot script */ +                    case 0x4BC74ECF: +                        /* Mandrake 10.1 & 10.2 CD1 boot script */ +                    case 0x5B265246: +                        /* Gentoo 1.2-r1 */ +                        /* Gentoo 2004.1 minimal install CD */ +                        /* Gentoo 1.4 live CDROM */ +                        /* Knopix PPC beta-pre12 */ +                    case 0x75420D8A: +                        /* Debian woody */ +                        /* Debian 3.0r1 */ +                        script_type = CHRP_SCRIPT_LOAD_BOOT; +                        goto do_script; +                    case 0x633e4c9c: +                        /* Debian Sarge */ +                    case 0xbe3abf60: +                        /* Debian Sarge, installed on a hard disk drive */ +                        script_type = CHRP_SCRIPT_LOAD_BOOT; +                        goto do_script; +                    case 0x07b86bfe: +                        /* Linux Fedora Core 3 */ +                        script_type = CHRP_SCRIPT_LOAD_BOOT; +                        goto do_script; +                    case 0x9ccdf371: +                        script_type = CHRP_SCRIPT_LOAD_BOOT; +                        goto do_script; +                    case 0xEF423926: +                        /* OpenBSD 3.4 */ +                    case 0x68e4f265: +                        /* OpenBSD 3.5 */ +                    case 0x3b7ea9e1: +                        /* OpenBSD 3.6 */ +                        script_type = CHRP_SCRIPT_LOAD_BOOT; +                        goto do_script; +                    case 0xB7981DBC: +                        /* iBook 2 hw test CDROM */ +#if 1 +                        script_type = CHRP_SCRIPT_LOAD_BOOT; +                        goto do_script; +#endif +                         +                    case 0xEA06C1A7: +                        /* MacOS 9.2 boot script: +                         * the XCOFF loader is embedded in the file... +                         */ +                    case 0x53A95958: +                        /* iBook 2 restore CD (MacOS X 10.2) */ +                        script_type = CHRP_SCRIPT_EMBEDDED; +                        pos = strfind(tag->data, "elf-offset"); +                        if (pos != NULL) { +                            /* Go backward until we get the value */ +                            for (--pos; *pos < '0' || *pos > '9'; pos--) +                                continue; +                            for (; *pos >= '0' && *pos <= '9'; pos--) +                                continue; +                            offset = strtol(pos, NULL, 16); +                            goto do_script; +                        } +                        ERROR("Didn't find boot file offset\n"); +                        goto out; +                    case 0x8d5acb86: +                        /* Darwin-7.01 +                         * The executable file is embedded after the script +                         */ +                        script_type = CHRP_SCRIPT_EMBEDDED; +                        DPRINTF("Boot file embedded at the end of boot script\n"); +                        break; +                    default: +                        ERROR("XML error: unknown Forth script: %08x\n%s\n", +                              crc, (char *)tag->data); +                        goto out; +                    } +                    break; + +                do_script: +                    switch (script_type) { +                    case CHRP_SCRIPT_LOAD_BOOT: +                        pos = strfind(tag->data, "boot"); +                        if (pos != NULL) { +                            /* Eat everything until file name */ +                            for (pos += 4; *pos != ','; pos++) +                                continue; +                            /* Eat ',' */ +                            for (++pos; isspace(*pos) || *pos == '"'; pos++) +                                continue; +                            /* Find file name end */ +                        redo: +                            for (endc = pos; +                                 *endc != ' ' && *endc != '"' && +                                 *endc != '\n' && *endc != '\r'; +                                 endc++) { +                                if (*endc == '\\') +                                    *endc = '/'; +                            } +                            if (memcmp(pos, "ofwboot", 7) == 0) { +                                for (pos = endc + 1; *pos == ' '; pos++) +                                    continue; +                                goto redo; +                            } +                            *endc = '\0'; +                        } +                        DPRINTF("Real boot file is: '%s'\n", pos); +                        part = fs_inode_get_part(file); +                        /* check if it's a path or just a file */ +                        tmpp = pos; +                        if ((pos[0] == '/' && pos[1] == '/') || +                            pos[0] != '/') { +                            unsigned char *bootdir; +                            bootdir = fs_get_boot_dirname(part_fs(part)); +                            if (bootdir == NULL) { +                                ERROR("Cannot get boot directory name\n"); +                                bug(); +                            } +                            snprintf(tmpname, TMPNAME_LEN, +                                     "%s/%s", bootdir, pos); +                            tmpname[TMPNAME_LEN - 1] = '\0'; +                            rel++; +                            pos = tmpname; +                            DPRINTF("'%s' => '%s'\n", bootdir, pos); +                        } +                    retry: +                        inode = fs_open(part_fs(part), pos); +                        if (inode == NULL) { +                            ERROR("Real boot inode '%s' not found\n", pos); +                            /* Try in root directory */ +                            if (rel == 1) { +                                for (; *tmpp == '/'; tmpp++) +                                    continue; +                                snprintf(tmpname, TMPNAME_LEN, "/%s", tmpp); +                                tmpname[TMPNAME_LEN - 1] = '\0'; +                                rel++; +                                goto retry; +                            } +                             +                            bug(); +                        } +                        ret = _bootfile_load(inode, dest, entry, end, 0, -1); +                        fs_close(inode); +                        goto out; +                    case CHRP_SCRIPT_EMBEDDED: +                        DPRINTF("Exec offset: %d %08x\n", offset, offset); +                        ret = 0; +                        goto out; +                    case CHRP_SCRIPT_IGNORE: +                        break; +                    } +                    break; +                case CHRP_TAG_OS_BADGE_ICONS: +                case CHRP_TAG_ICON: +                    /* Ignore it */ +                    break; +                case CHRP_TAG_BITMAP: +                    /* Ignore it */ +                    break; +                case CHRP_TAG_LICENSE: +                    /* Ignore it */ +                    pos = tag->data; +                    if (*(char *)tag->data == 0x0d) { +                        pos++; +                    } +                    DPRINTF("License: '%s'\n", pos); +                    break; +                default: +                    ERROR("XML error: unknown tag: '%s'\n", tag->name); +                    goto out; +                } +                tmp = tag->up; +                if (tmp == NULL) +                    state = XML_STATE_OUT; +                else +                    state = XML_STATE_DATA; +                free(tag->name); +                free(tag->data); +                free(tag); +                tag = tmp; +            } else { +                tmp = malloc(sizeof(XML_tag_t)); +                if (tmp == NULL) { +                    ERROR("Cannot allocate new tag\n"); +                    goto out; +                } +                tmp->up = tag; +                /* Ignore tag attributes */ +                pos = strchr(buf, ' '); +                if (pos != NULL) +                    *pos = '\0'; +                tmp->name = strdup(buf); +                tag = tmp; +                if (first == NULL) +                    first = tag; +                DPRINTF("Open tag '%s'\n", tag->name); +                state = XML_STATE_DATA; +            } +            break; +        case XML_STATE_DATA: +            if (tag->data == NULL) { +                tag->dlen = pos - buf; +                tag->data = malloc(tag->dlen); +                memcpy(tag->data, buf, tag->dlen); +            } +            state = XML_STATE_TAG; +            break; +        } +        pos = buf; +    } +    ret = 0; +    fs_read(file, &c, 1); +    fs_read(file, &c, 1); +    offset += 2; + out: +#if 1 +    for (; tag != NULL; tag = tmp) { +        tmp = tag->up; +        free(tag->name); +        free(tag->data); +        free(tag); +    } +#endif +    if (ret == 0 && script_type == CHRP_SCRIPT_EMBEDDED) { +        DPRINTF("Load embedded file from offset %d (%d => %d)\n", +                offset, loffset, loffset + offset); +        ret = _bootfile_load(file, dest, entry, end, loffset + offset, -1); +    } +    DPRINTF("Done\n"); + +    return ret; +} diff --git a/roms/openhackware/src/libexec/core.c b/roms/openhackware/src/libexec/core.c new file mode 100644 index 00000000..222a29a8 --- /dev/null +++ b/roms/openhackware/src/libexec/core.c @@ -0,0 +1,151 @@ +/* + * <file.c> + * + * Open Hack'Ware BIOS executable file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +/*****************************************************************************/ +uint32_t file_seek (inode_t *file, uint32_t pos) +{ +    uint32_t blocsize, bloc, offset; + +    if (file == NULL) +        return -1; +    blocsize = part_blocsize(fs_inode_get_part(file)); +    bloc = pos / blocsize; +    offset = pos % blocsize; + +    return fs_seek(file, bloc, offset); +} + +/*****************************************************************************/ +/* Executable file loaders */ + +enum { +    FILE_TYPE_ELF = 0, +    FILE_TYPE_XCOFF, +    FILE_TYPE_MACHO, +    FILE_TYPE_PEF, +    FILE_TYPE_CHRP, +    FILE_TYPE_PREP, +    FILE_TYPE_FLAT, +}; + +uint32_t fs_inode_get_size (inode_t *inode); +unsigned int part_get_entry (part_t *part); +/*****************************************************************************/ +/* Generic boot file loader */ +int _bootfile_load (inode_t *file, void **dest, void **entry, void **end, +                    uint32_t loffset, int type) +{ +    int (*do_load)(inode_t *file, void **dest, void **entry, void **end, +                   uint32_t loffset); +    uint32_t size; +    int ret; +    int i; + +    if (type == -1) +        i = 0; +    else +        i = type; +    for (;; i++) { +        switch (i) { +        case FILE_TYPE_ELF: +            do_load = &exec_load_elf; +            break; +        case FILE_TYPE_XCOFF: +            do_load = &exec_load_xcoff; +            break; +        case FILE_TYPE_MACHO: +            do_load = &exec_load_macho; +            break; +        case FILE_TYPE_PEF: +            do_load = &exec_load_pef; +            break; +        case FILE_TYPE_CHRP: +            do_load = &exec_load_chrp; +            break; +        case FILE_TYPE_PREP: +            do_load = &exec_load_prep; +            break; +        default: +            if (*dest == NULL) +                *dest = (void *)DEFAULT_LOAD_DEST; +            if (*entry == NULL) { +                if (part_get_entry(fs_inode_get_part(file)) != 0 || 1) { +                    *entry = (char *)*dest + +                        part_get_entry(fs_inode_get_part(file)); +                    dprintf("dest %p entry %08x => %p\n", +                            *dest, part_get_entry(fs_inode_get_part(file)), +                            *entry); +                } else { +                    *entry = *dest + 0xC; +                } +            } +            size = fs_inode_get_size(file); +            *end = (char *)*dest + size - loffset; +            printf("Load raw file into memory at %p %d (%08x) %d (%08x)\n", +                   *dest, size, size, loffset, loffset); +            file_seek(file, loffset); +            set_loadinfo(*dest, size); +            if ((uint32_t)fs_read(file, *dest, size) != size) { +                ERROR("Error loading file...\n"); +                ret = -1; +            } else { +                ret = 0; +            } +            goto out; +        } +        DPRINTF("Check file type %d at offset %d %p\n", i, loffset, do_load); +        ret = (*do_load)(file, dest, entry, end, loffset); +        if (ret >= -1 || type == i) { +            if (type == i) +                ret = -2; +            break; +        } +    } + out: + +    return ret; +} + +int bootfile_load (void **dest, void **entry, void **end, +                   part_t *part, int type, const unsigned char *fname, +                   uint32_t loffset) +{ +    inode_t *file; +    int ret; + +    DPRINTF("Load file '%s' %p %p type: %d offset: %0x => %d %p\n", +            fname, part, part_fs(part), type, loffset, part_blocsize(part), *dest); +    if (fname == NULL) +        file = fs_get_bootfile(part_fs(part)); +    else +        file = fs_open(part_fs(part), fname); +    if (file == NULL) +        return -1; +    ret = _bootfile_load(file, dest, entry, end, loffset, type); +    fs_close(file); + +    return ret; +} diff --git a/roms/openhackware/src/libexec/elf.c b/roms/openhackware/src/libexec/elf.c new file mode 100644 index 00000000..ae9f8e00 --- /dev/null +++ b/roms/openhackware/src/libexec/elf.c @@ -0,0 +1,239 @@ +/* + * <elf.c> + * + * Open Hack'Ware BIOS ELF executable file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +uint32_t fs_inode_get_size (inode_t *inode); + +/* ELF executable loader */ +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Addr; + +#define EI_NIDENT	16 + +typedef struct elf32_hdr_t { +  unsigned char	e_ident[EI_NIDENT]; +  Elf32_Half	e_type; +  Elf32_Half	e_machine; +  Elf32_Word	e_version; +  Elf32_Addr	e_entry;  /* Entry point */ +  Elf32_Off	e_phoff; +  Elf32_Off	e_shoff; +  Elf32_Word	e_flags; +  Elf32_Half	e_ehsize; +  Elf32_Half	e_phentsize; +  Elf32_Half	e_phnum; +  Elf32_Half	e_shentsize; +  Elf32_Half	e_shnum; +  Elf32_Half	e_shstrndx; +} Elf32_Ehdr_t; + +typedef struct elf32_phdr_t { +  Elf32_Word	p_type; +  Elf32_Off	p_offset; +  Elf32_Addr	p_vaddr; +  Elf32_Addr	p_paddr; +  Elf32_Word	p_filesz; +  Elf32_Word	p_memsz; +  Elf32_Word	p_flags; +  Elf32_Word	p_align; +} Elf32_Phdr_t; + +#define	EI_MAG0		0		/* e_ident[] indexes */ +#define	EI_MAG1		1 +#define	EI_MAG2		2 +#define	EI_MAG3		3 +#define	EI_CLASS	4 +#define	EI_DATA		5 +#define	EI_VERSION	6 +#define	EI_OSABI	7 +#define	EI_PAD		8 + +#define	ELFMAG0		0x7f		/* EI_MAG */ +#define	ELFMAG1		'E' +#define	ELFMAG2		'L' +#define	ELFMAG3		'F' + +#define	ELFCLASSNONE	0		/* EI_CLASS */ +#define	ELFCLASS32	1 +#define	ELFCLASS64	2 +#define	ELFCLASSNUM	3 + +#define ELFDATANONE	0		/* e_ident[EI_DATA] */ +#define ELFDATA2LSB	1 +#define ELFDATA2MSB	2 + +#define EV_NONE		0		/* e_version, EI_VERSION */ +#define EV_CURRENT	1 +#define EV_NUM		2 + +/* These constants define the different elf file types */ +#define ET_NONE   0 +#define ET_REL    1 +#define ET_EXEC   2 +#define ET_DYN    3 +#define ET_CORE   4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* These constants define the various ELF target machines */ +#define EM_NONE  0 +#define EM_M32   1 +#define EM_SPARC 2 +#define EM_386   3 +#define EM_68K   4 +#define EM_88K   5 +#define EM_486   6   /* Perhaps disused */ +#define EM_860   7 +#define EM_MIPS		8	/* MIPS R3000 (officially, big-endian only) */ +#define EM_MIPS_RS4_BE 10	/* MIPS R4000 big-endian */ +#define EM_PARISC      15	/* HPPA */ +#define EM_SPARC32PLUS 18	/* Sun's "v8plus" */ +#define EM_PPC	       20	/* PowerPC */ +#define EM_PPC64       21       /* PowerPC64 */ +#define EM_SH	       42	/* SuperH */ +#define EM_SPARCV9     43	/* SPARC v9 64-bit */ +#define EM_IA_64	50	/* HP/Intel IA-64 */ +#define EM_X86_64	62	/* AMD x86-64 */ +#define EM_S390		22	/* IBM S/390 */ +#define EM_CRIS         76      /* Axis Communications 32-bit embedded processor */ +#define EM_V850		87	/* NEC v850 */ +#define EM_H8_300H      47      /* Hitachi H8/300H */ +#define EM_H8S          48      /* Hitachi H8S     */ +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA	0x9026 +/* Bogus old v850 magic number, used by old tools.  */ +#define EM_CYGNUS_V850	0x9080 +/* + * This is the old interim value for S/390 architecture + */ +#define EM_S390_OLD     0xA390 + +int exec_load_elf (inode_t *file, void **dest, void **entry, void **end, +                   uint32_t loffset) +{ +    Elf32_Ehdr_t ehdr; +    Elf32_Phdr_t phdr; +    void *address, *first, *last; +    uint32_t offset, fsize, msize; +    int i; + +    file_seek(file, loffset); +    if (fs_read(file, &ehdr, sizeof(Elf32_Ehdr_t)) < 0) { +        ERROR("Cannot load first bloc of file...\n"); +        return -1; +    } +    DPRINTF("Check ELF file\n"); +    /* Check ident */ +    if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || +        ehdr.e_ident[EI_MAG1] != ELFMAG1 || +        ehdr.e_ident[EI_MAG2] != ELFMAG2 || +        ehdr.e_ident[EI_MAG3] != ELFMAG3) { +        DPRINTF("Not an ELF file %0x\n", *(uint32_t *)ehdr.e_ident); +        return -2; +    } +    if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { +        ERROR("Not a 32 bits ELF file\n"); +        return -2; +    } +    if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { +        ERROR("Not a big-endian ELF file\n"); +        return -2; +    } +    if (ehdr.e_ident[EI_VERSION] != EV_CURRENT /*|| +        ehdr->e_version != EV_CURRENT*/) { +        ERROR("Invalid ELF executable version %d %08x\n", +              ehdr.e_ident[EI_VERSION], ehdr.e_version); +        return -2; +    } +    if (ehdr.e_type != ET_EXEC) { +        ERROR("Not an executable ELF file\n"); +        return -2; +    } +    if (ehdr.e_machine != EM_PPC) { +        ERROR("Not a PPC ELF executable\n"); +        return -2; +    } +    /* All right, seems to be a regular ELF program for PPC */ +    *entry = (void *)ehdr.e_entry; +    DPRINTF("ELF file found entry = %p\n", *entry); +    last = NULL; +    first = last - 4; +    fsize = msize = 0; +    offset = ehdr.e_phoff; +    for (i = 0; i < ehdr.e_phnum; i++) { +#if 0 +        if (offset > fs_inode_get_size(file)) { +            ERROR("ELF program header %d offset > file size %d %d\n", i, +                  offset, fs_inode_get_size(file)); +            return -1; +        } +#endif +        DPRINTF("Load program header %d from %08x\n", i, offset); +        file_seek(file, offset + loffset); +        if (fs_read(file, &phdr, sizeof(Elf32_Phdr_t)) < 0) { +            ERROR("Cannot load ELF program header %d...\n", i); +            return -1; +        } +        DPRINTF("Load program header %d %08x %08x %08x %08x\n", i, +                phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz); +#if 0 +        if (phdr.p_offset > fs_inode_get_size(file)) { +            ERROR("ELF program %d offset > file size %d %d\n", +                  i, phdr.p_offset, fs_inode_get_size(file)); +            return -1; +        } +#endif +        /* As we won't remap memory, load it at it's virtual address (!) */ +        address = (void *)phdr.p_vaddr; +        if (address < first) +            first = address; +        fsize = phdr.p_filesz; +        msize = phdr.p_memsz; +        if (address + msize > last) +            last = address + msize; +        file_seek(file, phdr.p_offset + loffset); +        set_loadinfo((void *)first, last - first); +        if (fs_read(file, address, fsize) < 0) { +            ERROR("Cannot load ELF program %d...\n", i); +            return -1; +        } +        if (msize > fsize) { +            memset(address + fsize, 0, msize - fsize); +        } +        offset += ehdr.e_phentsize; +    } +    *dest = (void *)first; +    *end = (void *)last; +    DPRINTF("ELF file loaded at %p => %p fsize %08x msize %08x " +            "(%08x %08x)\n", *dest, *entry, fsize, msize, +            *(uint32_t *)entry, *((uint32_t *)entry + 1)); + +    return 0; +} diff --git a/roms/openhackware/src/libexec/exec.h b/roms/openhackware/src/libexec/exec.h new file mode 100644 index 00000000..46f138fd --- /dev/null +++ b/roms/openhackware/src/libexec/exec.h @@ -0,0 +1,40 @@ +/* + * <exec.h> + * + * Open Hack'Ware BIOS: executable files loader definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined(__OHW_EXEC_H__) +#define __OHW_EXEC_H__ + +int _bootfile_load (inode_t *file, void **dest, void **entry, void **end, +                    uint32_t loffset, int type); +int exec_load_elf (inode_t *file, void **dest, void **entry, void **end, +                   uint32_t loffset); +int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end, +                     uint32_t loffset); +int exec_load_macho (inode_t *file, void **dest, void **entry, void **end, +                     uint32_t loffset); +int exec_load_pef (inode_t *file, void **dest, void **entry, void **end, +                   uint32_t loffset); +int exec_load_prep (inode_t *file, void **dest, void **entry, void **end, +                    uint32_t loffset); +int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end, +                    uint32_t loffset); + +#endif /* !defined(__OHW_EXEC_H__) */ diff --git a/roms/openhackware/src/libexec/macho.c b/roms/openhackware/src/libexec/macho.c new file mode 100644 index 00000000..f07c9214 --- /dev/null +++ b/roms/openhackware/src/libexec/macho.c @@ -0,0 +1,517 @@ +/* + * <macho.c> + * + * Open Hack'Ware BIOS MACH-O executable file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +/* MACH-O executable loader */ +/* FAT definitions */ +/* CPU type definitions */ +typedef enum cpu_type_t { +    CPU_TYPE_ANY     = -1, +    CPU_TYPE_VAX     = 1, +    CPU_TYPE_MC680x0 = 6, +    CPU_TYPE_I386    = 7, +    CPU_TYPE_MIPS    = 8, +    CPU_TYPE_MC98000 = 10, +    CPU_TYPE_HPPA    = 11, +    CPU_TYPE_ARM     = 12, +    CPU_TYPE_MC88000 = 13, +    CPU_TYPE_SPARC   = 14, +    CPU_TYPE_I860    = 15, +    CPU_TYPE_ALPHA   = 16, +    CPU_TYPE_POWERPC = 18, +} cpu_type_t; + +/* Any CPU */ +typedef enum cpu_subtype_any_t { +    CPU_SUBTYPE_MULTIPLE      = -1, +    CPU_SUBTYPE_LITTLE_ENDIAN = 0, +    CPU_SUBTYPE_BIG_ENDIAN    = 1, +} cpu_subtype_any_t; + +/* PowerPC */ +typedef enum cpu_subtype_ppc_t { +    CPU_SUBTYPE_PPC_ALL   = 0, +    CPU_SUBTYPE_PPC_601   = 1, +    CPU_SUBTYPE_PPC_602   = 2, +    CPU_SUBTYPE_PPC_603   = 3, +    CPU_SUBTYPE_PPC_603e  = 4, +    CPU_SUBTYPE_PPC_603ev = 5, +    CPU_SUBTYPE_PPC_604   = 6, +    CPU_SUBTYPE_PPC_604e  = 7, +    CPU_SUBTYPE_PPC_620   = 8, +    CPU_SUBTYPE_PPC_750   = 9, +    CPU_SUBTYPE_PPC_7400  = 10, +    CPU_SUBTYPE_PPC_7450  = 11, +} cpu_subtype_ppc_t; + +/* Fat header definition */ +#define FAT_MAGIC 0xCAFEBABE + +typedef struct fat_head_t { +    uint32_t magic; +    uint32_t nfat_arch; +} fat_head_t; + +typedef struct fat_arch_t { +    cpu_type_t    cpu_type; +    cpu_subtype_ppc_t cpu_subtype; +    uint32_t offset; +    uint32_t size; +    uint32_t align; +} fat_arch_t; + +/* Mach-O binary definitions */ +#define MACH_O_MAGIC 0xFEEDFACE + +typedef enum filetype_t { +    MH_OBJECT     = 0x1, +    MH_EXECUTE    = 0x2, +    MH_FVMLIB     = 0x3, +    MH_CORE       = 0x4, +    MH_PRELOAD    = 0x5, +    MH_DYLIB      = 0x6, +    MH_DYLINKER   = 0x7, +    MH_BUNDLE     = 0x8, +} filetype_t; + +enum { +    MH_NOUNDEFS   = 0x01, +    MH_INCRLINK   = 0x02, +    MH_DYLDLINK   = 0x04, +    MH_BINDATLOAD = 0x08, +    MH_PREBOUND   = 0x10, +}; + +typedef struct mach_head_t { +    uint32_t magic; +    cpu_type_t cpu_type; +    cpu_subtype_ppc_t subtype; +    filetype_t file_type; +    uint32_t nb_cmds; +    uint32_t cmds_size; +    uint32_t flags; +} mach_head_t; + +typedef enum load_cmd_t { +    LC_SEGMENT        = 0x01, +    LC_SYMTAB         = 0x02, +    LC_SYMSEG         = 0x03, +    LC_THREAD         = 0x04, +    LC_UNIXTHREAD     = 0x05, +    LC_LOADFVMLIB     = 0x06, +    LC_IDFVMLIB       = 0x07, +    LC_IDENT          = 0x08, +    LC_FVMFILE        = 0x09, +    LC_PREPAGE        = 0x0A, +    LC_DYSYMTAB       = 0x0B, +    LC_LOAD_DYLIB     = 0x0C, +    LC_ID_DYLIB       = 0x0D, +    LC_LOAD_DYLINKER  = 0x0E, +    LC_ID_DYLINKER    = 0x0F, +    LC_PREBOUND_DYLIB = 0x10, +    LC_0x17           = 0x17, +} load_cmd_t; + +typedef struct mach_load_cmd_t { +    load_cmd_t cmd; +    uint32_t cmd_size; +} mach_load_cmd_t; + +typedef struct mach_string_t { +    uint32_t offset; +} mach_string_t; + +enum { +    SG_HIGHVM  = 0x1, +    SG_FVMLIB  = 0x2, +    SG_NORELOC = 0x4, +}; + +typedef struct mach_segment_t { +    unsigned char segname[16]; +    uint32_t vmaddr; +    uint32_t vmsize; +    uint32_t file_offset; +    uint32_t file_size; +    uint32_t max_prot; +    uint32_t init_prot; +    uint32_t nsects; +    uint32_t flags; +} mach_segment_t; + +enum { +    SECTION_TYPE               = 0xFF, +    S_REGULAR                  = 0x0, +    S_ZEROFILL                 = 0x1, +    S_CSTRING_LITERALS         = 0x2, +    S_4BYTE_LITERALS           = 0x3, +    S_8BYTE_LITERALS           = 0x4, +    S_LITERAL_POINTERS         = 0x5, +    S_NON_LAZY_SYMBOL_POINTERS = 0x6, +    S_LAZY_SYMBOL_POINTERS     = 0x7, +    S_SYMBOL_STUBS             = 0x8, +    S_MOD_INIT_FUNC_POINTERS   = 0x9, +}; + +enum { +    S_ATTR_PURE_INSTRUCTIONS   = 0x80000000, +    S_ATTR_SOME_INSTRUCTIONS   = 0x00000400, +    S_ATTR_EXT_RELOC           = 0x00000200, +    S_ATTR_LOC_RELOC           = 0x00000100, +}; + +typedef struct mach_section_t { +    unsigned char sectname[16]; +    unsigned char segname[16]; +    uint32_t vmaddr; +    uint32_t size; +    uint32_t offset; +    uint32_t align; +    uint32_t reloc_offset; +    uint32_t nreloc; +    uint32_t flags; +    uint32_t res1; +    uint32_t res2; +} mach_section_t; + +typedef struct mach_symtab_t { +    uint32_t offset; +    uint32_t nsyms; +    uint32_t str_offset; +    uint32_t str_size; +} mach_symtab_t; + +typedef struct mach_symseg_t { +    uint32_t offset; +    uint32_t size; +} mach_symseg_t; + +typedef struct mach_unixth_t { +    uint32_t flavor; +    uint32_t count; +    /* This is supposed to be a stack. +     * Let's assume it's less than 1kB (arbitrary !) +     */ +    uint32_t data[256]; +} mach_unixth_t; + +typedef struct mach_fvmlib_t { +    uint32_t str_offset; +    uint32_t minor_version; +    uint32_t header_addr; +} mach_fvmlib_t; + +typedef struct mach_fvmfile_t { +    uint32_t str_offset; +    uint32_t vmaddr; +} mach_fvmfile_t; + +typedef struct mach_dysymtab_t { +    uint32_t ilocal_syms; +    uint32_t nlocal_syms; +    uint32_t iext_syms; +    uint32_t next_syms; +    uint32_t iundef_syms; +    uint32_t nundef_syms; +    uint32_t toc_offset; +    uint32_t ntoc; +    uint32_t modtab_offset; +    uint32_t nmodtab; +    uint32_t extsym_offset; +    uint32_t nextsym; +    uint32_t indirect_offset; +    uint32_t nindirect; +    uint32_t ext_reloc_offset; +    uint32_t next_reloc; +    uint32_t local_reloc_offset; +    uint32_t nlocal_reloc; +} mach_dysymtab_t; + +typedef struct mach_dylib_t { +    uint32_t str_offset; +    uint32_t timestamp; +    uint32_t cur_version; +    uint32_t compat_version; +} mach_dylib_t; + +typedef struct mach_prebound_t { +    uint32_t str_offset; +    uint32_t nb_modules; +    unsigned char linked_modules[256]; +} mach_prebound_t; + +int exec_load_macho (inode_t *file, void **dest, void **entry, void **end, +                     uint32_t loffset) +{ +    mach_head_t mhdr; +    mach_load_cmd_t lcmd; +    fat_head_t fhdr; +    fat_arch_t fahdr; +    void *address, *first, *last; +    uint32_t k, j, best, offset; +    int entry_set; + +    /* Probe FAT */ +    file_seek(file, loffset); +    if (fs_read(file, &fhdr, sizeof(fat_head_t)) < 0) { +        ERROR("Cannot load fat header...\n"); +        return -1; +    } +    fhdr.magic = get_be32(&fhdr.magic); +    if (fhdr.magic != FAT_MAGIC) +        goto macho_probe; +    fhdr.nfat_arch = get_be32(&fhdr.nfat_arch); +    DPRINTF("FAT file: %d archs\n", fhdr.nfat_arch); +    /* Find the best architecture */ +    best = -1; +    offset = 0; +    for (k = 0; k < fhdr.nfat_arch; k++) { +        if (fs_read(file, &fahdr, sizeof(fat_arch_t)) < 0) { +            ERROR("Cannot load fat arch header\n"); +            return -1; +        } +        fahdr.cpu_type = get_be32(&fahdr.cpu_type); +        if (fahdr.cpu_type != CPU_TYPE_POWERPC) +            continue; +        fahdr.cpu_subtype = get_be32(&fahdr.cpu_subtype); +        fahdr.offset = get_be32(&fahdr.offset); +        fahdr.size = get_be32(&fahdr.size); +        fahdr.align = get_be32(&fahdr.align); +        switch (fahdr.cpu_subtype) { +        case CPU_SUBTYPE_PPC_750: +            best = k; +            offset = fahdr.offset; +            goto fat_cpu_ok; +        case CPU_SUBTYPE_PPC_ALL: +            if (best == (uint32_t)-1) { +                offset = fahdr.offset; +                best = k; +            } +            break; +        case CPU_SUBTYPE_PPC_603: +        case CPU_SUBTYPE_PPC_603e: +        case CPU_SUBTYPE_PPC_603ev: +        case CPU_SUBTYPE_PPC_604: +        case CPU_SUBTYPE_PPC_604e: +            best = k; +            offset = fahdr.offset; +            break; +        default: +            break; +        } +    } +    if (best == (uint32_t)-1) { +        ERROR("No matching PPC FAT arch\n"); +        return -1; +    } +    DPRINTF("Use FAT arch %d at %08x %08x\n", best, offset, loffset); + fat_cpu_ok: +    loffset += offset; + +    /* Probe macho */ + macho_probe: +    file_seek(file, loffset); +    if (fs_read(file, &mhdr, sizeof(mach_head_t)) < 0) { +        ERROR("Cannot load MACH-O header...\n"); +        return -1; +    } +    mhdr.magic = get_be32(&mhdr.magic); +    if (mhdr.magic != MACH_O_MAGIC) { +        ERROR("Not a MACH-O file\n"); +        return -2; +    } +    mhdr.cpu_type = get_be32(&mhdr.cpu_type); +    mhdr.subtype = get_be32(&mhdr.subtype); +    mhdr.file_type = get_be32(&mhdr.file_type); +    mhdr.nb_cmds = get_be32(&mhdr.nb_cmds); +    mhdr.cmds_size = get_be32(&mhdr.cmds_size); +    mhdr.flags = get_be32(&mhdr.flags); +    DPRINTF("MACHO-O file cpu %d %d file type %08x %d cmds size %08x flags " +            "%08x\n", mhdr.cpu_type, mhdr.subtype, mhdr.file_type, +            mhdr.nb_cmds, mhdr.cmds_size, mhdr.flags); +    offset = sizeof(mach_head_t); +    first = (void *)-1; +    last = NULL; +    entry_set = 0; +    for (k = 0; k < mhdr.nb_cmds; k++) { +        file_seek(file, loffset + offset); +        if (fs_read(file, &lcmd, sizeof(mach_load_cmd_t)) < 0) { +            ERROR("Unable to load MACH-O cmd %d\n", k); +            return -1; +        } +        lcmd.cmd = get_be32(&lcmd.cmd); +        lcmd.cmd_size = get_be32(&lcmd.cmd_size); +        DPRINTF("Cmd %d : %08x size %08x (%08x %08x)\n", k, lcmd.cmd, +                lcmd.cmd_size, offset, offset + loffset); +        switch (lcmd.cmd) { +        case LC_SEGMENT: +            /* To be loaded for execution */ +            { +                mach_segment_t segment; +                mach_section_t section; +                uint32_t pos; +                 +                pos = offset + sizeof(mach_load_cmd_t); +                if (fs_read(file, &segment, sizeof(mach_segment_t)) < 0) { +                    ERROR("Cannot load MACH-O segment\n"); +                    return -1; +                } +                pos += sizeof(mach_segment_t); +                segment.vmaddr = get_be32(&segment.vmaddr); +                segment.vmsize = get_be32(&segment.vmsize); +                segment.file_offset = get_be32(&segment.file_offset); +                segment.file_size = get_be32(&segment.file_size); +                segment.max_prot = get_be32(&segment.max_prot); +                segment.init_prot = get_be32(&segment.init_prot); +                segment.nsects = get_be32(&segment.nsects); +                segment.flags = get_be32(&segment.flags); +                DPRINTF("MACH-O segment addr %08x size %08x off %08x fsize " +                        "%08x ns %d fl %08x\n", segment.vmaddr, segment.vmsize, +                        segment.file_offset, segment.file_size, +                        segment.nsects, segment.flags); +                for (j = 0; j < segment.nsects; j++) { +                    file_seek(file, loffset + pos); +                    if (fs_read(file, §ion, sizeof(mach_section_t)) < 0) { +                        ERROR("Cannot load MACH-O section\n"); +                        return -1; +                    } +                    pos += sizeof(mach_section_t); +                    section.vmaddr = get_be32(§ion.vmaddr); +                    section.size = get_be32(§ion.size); +                    section.offset = get_be32(§ion.offset); +                    section.align = get_be32(§ion.align); +                    section.reloc_offset = get_be32(§ion.reloc_offset); +                    section.nreloc = get_be32(§ion.nreloc); +                    section.flags = get_be32(§ion.flags); +                    section.res1 = get_be32(§ion.res1); +                    section.res2 = get_be32(§ion.res2); +                    DPRINTF("MACH-O section vmaddr %08x size %08x off %08x " +                            "flags %08x\n", section.vmaddr, section.size, +                            section.offset, section.flags); +                    switch (section.flags & SECTION_TYPE) { +                    case S_REGULAR: +                    case S_CSTRING_LITERALS: +                    case S_4BYTE_LITERALS: +                    case S_8BYTE_LITERALS: +                    case S_LITERAL_POINTERS: +                    case S_NON_LAZY_SYMBOL_POINTERS: +                    case S_LAZY_SYMBOL_POINTERS: +                    case S_SYMBOL_STUBS: +                    case S_MOD_INIT_FUNC_POINTERS: +                        DPRINTF("Load section of type %d from %08x to %08x" +                                " %08x\n", section.flags, section.offset, +                                section.vmaddr, section.size); +                        file_seek(file, section.offset + loffset); +                        address = (void *)section.vmaddr; +                        if (address < first && address != NULL) +                            first = address; +                        if (address + section.size > last) +                            last = address + section.size; +                        if (fs_read(file, address, section.size) < 0) { +                            ERROR("Cannot load MACH-O section %d %d...\n", +                                  k, j); +                            return -1; +                        } +                        break; +                    case S_ZEROFILL: +                        DPRINTF("Fill zero section to %08x %08x\n", +                                section.vmaddr, section.size); +                        address = (void *)section.vmaddr; +                        if (address < first && address != NULL) +                            first = address; +                        if (address + section.size > last) +                            last = address + section.size; +                        memset(address, 0, section.size); +                        break; +                    default: +                        ERROR("Unknown MACH-O section type: %d\n", +                              section.flags); +                        return -1; +                    } +                } +            } +            break; +        case LC_SYMTAB: +            /* Don't care */ +            break; +        case LC_SYMSEG: +            /* Don't care */ +            break; +        case LC_UNIXTHREAD: +            /* To be loaded for execution */ +            { +                mach_unixth_t unixth; + +                if (fs_read(file, &unixth, sizeof(mach_unixth_t)) < 0) { +                    ERROR("Cannot load MACH-O UNIX thread\n"); +                    return -1; +                } +                DPRINTF("Set entry point to %08x\n", unixth.data[0]); +                *entry = (void *)unixth.data[0]; +                entry_set = 1; +            } +            break; +        case LC_THREAD: +            break; +        case LC_LOADFVMLIB: +            break; +        case LC_IDFVMLIB: +            break; +        case LC_IDENT: +            break; +        case LC_FVMFILE: +            break; +        case LC_PREPAGE: +            printf("Prepage command\n"); +            break; +        case LC_DYSYMTAB: +            break; +        case LC_LOAD_DYLIB: +            break; +        case LC_ID_DYLIB: +            break; +        case LC_LOAD_DYLINKER: +            /* To be loaded for execution */ +            break; +        case LC_ID_DYLINKER: +            break; +        case LC_PREBOUND_DYLIB: +            break; +        case LC_0x17: +            /* ? */ +            break; +        default: +            printf("unknown MACH-O command (%d %d)\n", k, lcmd.cmd); +            return -1; +        } +        offset += lcmd.cmd_size; +    } +    *dest = first; +    *end = last; +    //    if (entry_set == 0) +        *entry = *dest; + +    return 0; +} diff --git a/roms/openhackware/src/libexec/pef.c b/roms/openhackware/src/libexec/pef.c new file mode 100644 index 00000000..2c580147 --- /dev/null +++ b/roms/openhackware/src/libexec/pef.c @@ -0,0 +1,307 @@ +/* + * <pef.c> + * + * Open Hack'Ware BIOS Classic MacOS executable file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +/* PEF (old MacOS executable format) */ +typedef struct PEF_container_t PEF_container_t; +struct PEF_container_t { +    uint32_t tag1; +    uint32_t tag2; +    uint32_t arch; +    uint32_t version; +    uint32_t timestamp; +    uint32_t oldDefVersion; +    uint32_t oldImpVersion; +    uint32_t currentVersion; +    uint16_t nb_sections; +    uint16_t nb_inst_sections; +    uint32_t pad; +} __attribute__ (( packed )); + +typedef struct PEF_section_t PEF_section_t; +struct PEF_section_t { +    int32_t name_offset; +    uint32_t address; +    uint32_t total_size; +    uint32_t unpacked_size; +    uint32_t packed_size; +    uint32_t container_offset; +    uint8_t  section_kind; +    uint8_t  share_kind; +    uint8_t  align; +    uint8_t  pad; +} __attribute__ (( packed )); + +typedef struct PEF_loader_t PEF_loader_t; +struct PEF_loader_t { +    int32_t  main_section; +    uint32_t main_offset; +    int32_t  init_section; +    uint32_t init_offset; +    int32_t  term_section; +    uint32_t term_offset; +    uint32_t nb_import_libs; +    uint32_t nb_import_symbols; +    uint32_t nb_reloc_sections; +    uint32_t reloc_instr_offset; +    uint32_t loader_strings_offset; +    uint32_t export_hash_offset; +    uint32_t export_hashtable_power; +    uint32_t nb_export_symbols; +} __attribute__ (( packed )); + +enum { +    PEF_SECTION_CODE     = 0, +    PEF_SECTION_UNPDATA  = 1, +    PEF_SECTION_INIDATA  = 2, +    PEF_SECTION_CONSTANT = 3, +    PEF_SECTION_LOADER   = 4, +    PEF_SECTION_DEBUG    = 5, +    PEF_SECTION_EXEC     = 6, +    PEF_SECTION_EXCP     = 7, +    PEF_SECTION_TRACE    = 8, +}; + +enum { +    PEF_SHARE_PROCESS    = 1, +    PEF_SHARE_GLOBAL     = 4, +    PEF_SHARE_PROTECTED  = 5, +}; + +int exec_load_pef (inode_t *file, void **dest, void **entry, void **end, +                   uint32_t loffset) +{ +    PEF_container_t container; +    PEF_section_t section; +    PEF_loader_t loader; +    void *first, *last, *addr, **sections; +    uint32_t pos, padsize, size, lpos, main_offset; +    uint8_t opcode; +    int nb_sections, nb_inst_sections, main_section, i, n; + +    file_seek(file, loffset); +    if (fs_read(file, &container, sizeof(PEF_container_t)) < 0) { +        ERROR("Cannot load container header\n"); +        return -1; +    } +    pos = sizeof(PEF_container_t); +    /* Check tags and architecture */ +    if (memcmp(&container.tag1, "Joy!", 4) != 0) { +        DPRINTF("No joy, no PEF\n"); +        return -2; +    } +    if (memcmp(&container.tag2, "peff", 4) != 0) { +        DPRINTF("No PEFF file\n"); +        return -2; +    } +    if (memcmp(&container.arch, "pwpc", 4) != 0) { +        DPRINTF("PEFF file not for PPC\n"); +        return -2; +    } +    if (get_be32(&container.version) != 1) { +        DPRINTF("Unknown PEFF container version\n"); +        return -2; +    } +    nb_sections = get_be32(&container.nb_sections); +    sections = malloc(nb_sections * sizeof(void *)); +    if (sections == NULL) { +        ERROR("Cannot allocate sections\n"); +        return -1; +    } +    nb_inst_sections = get_be32(&container.nb_inst_sections); +    first = (void *)0xFFFFFFFF; +    last = NULL; +    main_section = -1; +    main_offset = 0; +    for (i = 0, n = 0; i < nb_sections; i++) { +        file_seek(file, loffset + pos); +        if (fs_read(file, §ion, sizeof(PEF_section_t)) < 0) { +            ERROR("Cannot read section %d\n", i); +            return -1; +        } +        pos += sizeof(PEF_section_t); +        addr = (void *)get_be32(§ion.address); +        sections[i] = addr; +        if (addr < first) +            first = addr; +        size = get_be32(§ion.total_size); +        lpos = get_be32(§ion.container_offset); +        file_seek(file, loffset + lpos); +        switch (section.section_kind) { +        case PEF_SECTION_CODE: +        case PEF_SECTION_UNPDATA: +            /* Load as raw data */ +            padsize = get_be32(§ion.unpacked_size) - size; +            file_seek(file, loffset + lpos); +            if (fs_read(file, addr, size) < 0) { +                ERROR("Cannot load section %d\n", i); +                return -1; +            } +            addr = (char *)addr + size; +            memset(addr, 0, padsize); +            addr = (char *)addr + padsize; +            break; +        case PEF_SECTION_INIDATA: +        case PEF_SECTION_CONSTANT: +        case PEF_SECTION_EXEC: +            /* Load as compressed data */ +            for (;;) { +                void *ref; +                uint32_t total; +                uint8_t bsize, csize, count, j; + +                if (fs_read(file, &opcode, 1) < 0) { +                    ERROR("Cannot get opcode\n"); +                    return -1; +                } +                bsize = opcode & 0x1F; +                switch (opcode >> 5) { +                case 0x0: +                    /* Initialize size bytes to zero */ +                    memset(addr, 0, bsize); +                    addr = (char *)addr + bsize; +                    total = bsize; +                    break; +                case 0x1: +                    /* Copy bloc */ +                    if (fs_read(file, addr, bsize) < 0) { +                        ERROR("Cannot copy bloc\n"); +                        return -1; +                    } +                    addr = (char *)addr + bsize; +                    total = bsize; +                    break; +                case 0x2: +                    /* Repeat bloc */ +                    if (fs_read(file, &count, 1) < 0) { +                        ERROR("Cannot read bloc size\n"); +                        return -1; +                    } +                    total = 0; +                    if (count == 0) { +                        break; +                    } +                    if (fs_read(file, addr, bsize) < 0) { +                        ERROR("Cannot read repeat bloc\n"); +                        return -1; +                    } +                    ref = addr; +                    addr = (char *)addr + bsize; +                    for (j = 1; j < count; j++) { +                        memcpy(addr, ref, bsize); +                        total += bsize; +                        addr = (char *)addr + bsize; +                    } +                    break; +                case 0x3: +                    /* Interleave repeat bloc with bloc copy */ +                    if (fs_read(file, &csize, 1) < 0 || +                        fs_read(file, &count, 1) < 0) { +                        ERROR("Cannot read repeat params\n"); +                        return -1; +                    } +                    ref = addr; +                    if (fs_read(file, addr, bsize) < 0) { +                        ERROR("Cannot read common data\n"); +                        return -1; +                    } +                    addr = (char *)addr + bsize; +                    total = bsize; +                    for (j = 0; j < count; j++) { +                        if (fs_read(file, addr, csize) < 0) { +                            ERROR("Cannot read custom data\n"); +                            return -1; +                        } +                        addr = (char *)addr + csize; +                        memcpy(addr, ref, bsize); +                        addr = (char *)addr + bsize; +                        total += csize + bsize; +                    } +                    break; +                case 0x4: +                    /* Interleave repeat bloc with zero */ +                    if (fs_read(file, &csize, 1) < 0 || +                        fs_read(file, &count, 1) < 0) { +                        ERROR("Cannot read repeat params\n"); +                        return -1; +                    } +                    total = 0; +                    for (j = 0; j < count; j++) { +                        memset(addr, 0, bsize); +                        addr = (char *)addr + bsize; +                        if (fs_read(file, addr, csize) < 0) { +                            ERROR("Cannot read repeat data\n"); +                            return -1; +                        } +                        addr = (char *)addr + csize; +                        total += csize + bsize; +                    } +                    memset(addr, 0, bsize); +                    addr = (char *)addr + bsize; +                    total += bsize; +                    break; +                default: +                    ERROR("Unknown opcode\n"); +                    return -1; +                } +                if (addr > last) +                    last = addr; +                if (total >= size) +                    break; +                size -= total; +            } +            break; +        case PEF_SECTION_LOADER: +            /* find entry point */ +            if (fs_read(file, &loader, sizeof(PEF_loader_t)) < 0) { +                ERROR("Cannot read loader header\n"); +                return -1; +            } +            main_section = get_be32(&loader.main_section); +            main_offset = get_be32(&loader.main_offset); +            if (main_section >= nb_sections) { +                ERROR("Invalid main section\n"); +                return -1; +            } +            break; +        case PEF_SECTION_DEBUG: +        case PEF_SECTION_EXCP: +        case PEF_SECTION_TRACE: +            break; +        default: +            return -2; +        } +    } +    *dest = first; +    *end = last; +    if (main_section == -1) { +        *entry = first; +    } else { +        *entry = (char *)sections[main_section] + main_offset; +    } +    free(sections); + +    return 0; +} diff --git a/roms/openhackware/src/libexec/prep.c b/roms/openhackware/src/libexec/prep.c new file mode 100644 index 00000000..15b6ea67 --- /dev/null +++ b/roms/openhackware/src/libexec/prep.c @@ -0,0 +1,45 @@ +/* + * <prep.c> + * + * Open Hack'Ware BIOS PREP executable file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +/* PREP boot loader */ +int exec_load_prep (inode_t *file, unused void **dest, +                    unused void **entry, unused void **end, +                    unused uint32_t loffset) +{ +    unsigned char buffer[512]; + +    file_seek(file, loffset); +    if (fs_read(file, buffer, 512) < 0) { +        ERROR("Cannot load first bloc of file...\n"); +        return -2; +    } +    if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) { +        DPRINTF("Not a PREP file\n"); +        return -2; +    } + +    return -2; +} diff --git a/roms/openhackware/src/libexec/xcoff.c b/roms/openhackware/src/libexec/xcoff.c new file mode 100644 index 00000000..a9a6da48 --- /dev/null +++ b/roms/openhackware/src/libexec/xcoff.c @@ -0,0 +1,216 @@ +/* + * <xcoff.c> + * + * Open Hack'Ware BIOS XCOFF executable file loader + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +uint32_t fs_inode_get_size (inode_t *inode); + +/* XCOFF executable loader */ +typedef struct COFF_filehdr_t { +    uint16_t f_magic;	/* magic number			*/ +    uint16_t f_nscns;	/* number of sections		*/ +    uint32_t f_timdat;	/* time & date stamp		*/ +    uint32_t f_symptr;	/* file pointer to symtab	*/ +    uint32_t f_nsyms;	/* number of symtab entries	*/ +    uint16_t f_opthdr;	/* sizeof(optional hdr)		*/ +    uint16_t f_flags;	/* flags			*/ +} COFF_filehdr_t; + +/* IBM RS/6000 */ +#define U802WRMAGIC     0730    /* writeable text segments **chh**      */ +#define U802ROMAGIC     0735    /* readonly sharable text segments      */ +#define U802TOCMAGIC    0737    /* readonly text segments and TOC       */ + +/* + *   Bits for f_flags: + * + *	F_RELFLG	relocation info stripped from file + *	F_EXEC		file is executable  (i.e. no unresolved external + *			references) + *	F_LNNO		line numbers stripped from file + *	F_LSYMS		local symbols stripped from file + *	F_MINMAL	this is a minimal object file (".m") output of fextract + *	F_UPDATE	this is a fully bound update file, output of ogen + *	F_SWABD		this file has had its bytes swabbed (in names) + *	F_AR16WR	this file has the byte ordering of an AR16WR + *			(e.g. 11/70) machine + *	F_AR32WR	this file has the byte ordering of an AR32WR machine + *			(e.g. vax and iNTEL 386) + *	F_AR32W		this file has the byte ordering of an AR32W machine + *			(e.g. 3b,maxi) + *	F_PATCH		file contains "patch" list in optional header + *	F_NODF		(minimal file only) no decision functions for + *			replaced functions + */ + +#define  COFF_F_RELFLG		0000001 +#define  COFF_F_EXEC		0000002 +#define  COFF_F_LNNO		0000004 +#define  COFF_F_LSYMS		0000010 +#define  COFF_F_MINMAL		0000020 +#define  COFF_F_UPDATE		0000040 +#define  COFF_F_SWABD		0000100 +#define  COFF_F_AR16WR		0000200 +#define  COFF_F_AR32WR		0000400 +#define  COFF_F_AR32W		0001000 +#define  COFF_F_PATCH		0002000 +#define  COFF_F_NODF		0002000 + +typedef struct COFF_aouthdr_t { +    uint16_t magic;      /* type of file			  */ +    uint16_t vstamp;     /* version stamp		          */ +    uint32_t tsize;      /* text size in bytes, padded to FW bdry */ +    uint32_t dsize;      /* initialized data "  "	          */ +    uint32_t bsize;      /* uninitialized data "   "	          */ +    uint32_t entry;	 /* entry pt.			          */ +    uint32_t text_start; /* base of text used for this file       */ +    uint32_t data_start; /* base of data used for this file       */ +    uint32_t o_toc;	 /* address of TOC                        */ +    uint16_t o_snentry;	 /* section number of entry point         */ +    uint16_t o_sntext;	 /* section number of .text section       */ +    uint16_t o_sndata;	 /* section number of .data section       */ +    uint16_t o_sntoc;	 /* section number of TOC                 */ +    uint16_t o_snloader; /* section number of .loader section     */ +    uint16_t o_snbss;	 /* section number of .bss section        */ +    uint16_t o_algntext; /* .text alignment                       */ +    uint16_t o_algndata; /* .data alignment                       */ +    uint16_t o_modtype;	 /* module type (??)                      */ +    uint16_t o_cputype;	 /* cpu type                              */ +    uint32_t o_maxstack; /* max stack size (??)                   */ +    uint32_t o_maxdata;	 /* max data size (??)                    */ +    char o_resv2[12];	 /* reserved                              */ +} COFF_aouthdr_t; + +#define AOUT_MAGIC	0x010b + +typedef struct COFF_scnhdr_t { +    char s_name[8];	/* section name			    */ +    uint32_t s_paddr;	/* physical address, aliased s_nlib */ +    uint32_t s_vaddr;	/* virtual address		    */ +    uint32_t s_size;	/* section size			    */ +    uint32_t s_scnptr;	/* file ptr to raw data for section */ +    uint32_t s_relptr;	/* file ptr to relocation	    */ +    uint32_t s_lnnoptr;	/* file ptr to line numbers	    */ +    uint16_t s_nreloc;	/* number of relocation entries	    */ +    uint16_t s_nlnno;	/* number of line number entries    */ +    uint32_t s_flags;	/* flags			    */ +} COFF_scnhdr_t; + +int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end, +                     uint32_t loffset) +{ +    COFF_filehdr_t fhdr; +    COFF_aouthdr_t ahdr; +    COFF_scnhdr_t shdr; +    void *first, *last; +    uint32_t offset; +    int i; + +    file_seek(file, loffset); +    if (fs_read(file, &fhdr, sizeof(COFF_filehdr_t)) < 0) { +        ERROR("Cannot load first bloc of file...\n"); +        return -1; +    } +    if (fhdr.f_magic != U802WRMAGIC && fhdr.f_magic != U802ROMAGIC && +        fhdr.f_magic != U802TOCMAGIC && fhdr.f_magic != 0x01DF) { +        DPRINTF("Not a XCOFF file %02x %08x\n", fhdr.f_magic, +                *(uint32_t *)&fhdr.f_magic); +        return -2; +    } +    if (fhdr.f_magic != 0x01DF && (fhdr.f_flags & COFF_F_EXEC) == 0) { +        ERROR("Not an executable XCOFF file %02x\n", fhdr.f_flags); +        return -2; +    } +    if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) { +        ERROR("AOUT optional error size missmactch in XCOFF file\n"); +        return -2; +    } +    if (fs_read(file, &ahdr, sizeof(COFF_aouthdr_t)) < 0) { +        ERROR("Cannot load XCOFF AOUT header...\n"); +        return -1; +    } +    if (ahdr.magic != AOUT_MAGIC) { +        ERROR("Invalid AOUT optional header\n"); +        return -2; +    } +#if 0 // XXX: buggy: this makes NetBSD fail to boot +    if (fhdr.f_magic == 0x01DF) { +        /* Load embedded file */ +        return _bootfile_load(file, dest, entry, end, loffset + +                              sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t) + +                              (fhdr.f_nscns * sizeof(COFF_scnhdr_t)), +                              -1); +    } +#endif +    *entry = (void *)ahdr.entry + 0xC; +    last = NULL; +    first = last - 4; +    offset = sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t); +    DPRINTF("XCOFF file with %d sections entry:%p\n", fhdr.f_nscns, *entry); +    for (i = 0; i < fhdr.f_nscns; i++) { +        DPRINTF("Read next header (%0x)\n", offset); +        file_seek(file, offset + loffset); +        if (fs_read(file, &shdr, sizeof(COFF_scnhdr_t)) < 0) { +            ERROR("Cannot load section header %d...\n", i); +            return -1; +        } +	if (strcmp(shdr.s_name, ".text") == 0 || +            strcmp(shdr.s_name, ".data") == 0) { +            if ((void *)shdr.s_vaddr < first) +                first = (void *)shdr.s_vaddr; +            if ((void *)shdr.s_vaddr > last) +                last = (void *)shdr.s_vaddr; +            DPRINTF("Load '%s' section from %0x %0x to %0x (%0x)\n", +                    shdr.s_name, offset, shdr.s_scnptr, +                    shdr.s_vaddr, shdr.s_size); +#if 0 +            if (shdr.s_scnptr + shdr.s_size > fs_inode_get_size(file)) { +                ERROR("Section %d data offset > file size\n", i); +                return -1; +            } +#endif +            file_seek(file, shdr.s_scnptr + loffset); +            set_loadinfo((void *)first, last - first); +            if (fs_read(file, (void *)shdr.s_vaddr, shdr.s_size) < 0) { +                ERROR("Cannot load section %d...\n", i); +                return -1; +            } +        } else if (strcmp(shdr.s_name, ".bss") == 0) { +            if ((void *)shdr.s_vaddr < first) +                first = (void *)shdr.s_vaddr; +            if ((void *)shdr.s_vaddr > last) +                last = (void *)shdr.s_vaddr; +            DPRINTF("Erase '%s' section at %0x size: %0x\n", +                    shdr.s_name, shdr.s_vaddr, shdr.s_size); +            memset((void *)shdr.s_vaddr, 0, shdr.s_size); +        } else { +            DPRINTF("Skip '%s' section\n", shdr.s_name); +        } +        offset += sizeof(COFF_scnhdr_t); +    } +    *dest = first; +    *end = last; + +    return 0; +} diff --git a/roms/openhackware/src/libfs/core.c b/roms/openhackware/src/libfs/core.c new file mode 100644 index 00000000..9743a64a --- /dev/null +++ b/roms/openhackware/src/libfs/core.c @@ -0,0 +1,562 @@ +/* + * <fs.c> + * + * Open Hack'Ware BIOS file systems management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "libfs.h" +#undef FS_DPRINTF +#define FS_DPRINTF(fmt, args...) do { } while (0) + +static int special_file_get_type (const unsigned char *name) +{ +    int ret; + +    if (strcmp(name, "root") == 0) +        ret = FILE_ROOT; +    else if (strcmp(name, "boot") == 0) +        ret = FILE_BOOT; +    else if (strcmp(name, "bootdir") == 0) +        ret = FILE_BOOTDIR; +    else +        ret = FILE_UNKNOWN; + +    return ret; +} + +void fs_cache_add_inode (inode_t *parent, inode_t *inode) +{ +    inode_t **cur; + +    if (parent == NULL || inode == NULL) +        return; +    FS_DPRINTF("Add inode '%s' to '%s' cache\n", inode->name, parent->name); +    for (cur = &parent->child; *cur != NULL; cur = &((*cur)->next)) { +        if (strcmp((*cur)->name, inode->name) == 0) { +            return; +        } +    } +    *cur = inode; +} + +static inode_t *fs_cache_get_inode (inode_t *parent, +                                    const unsigned char *name) +{ +    inode_t *cur, *rec; +    int dec; + +    FS_DPRINTF("Look for '%s' into '%s' cache\n", name, parent->name); +    if (name == NULL || parent == NULL) +        return NULL; +    if (name[0] == '/' && name[1] == '\0') +        return parent->fs->root; +    if (is_special_file(name)) +        dec = strlen(FS_SPECIAL) + 2; +    else +        dec = 0; +    for (cur = parent->child; cur != NULL; cur = cur->next) { +        if (strcmp(cur->name + dec, name + dec) == 0) { +            cur->refcount++; +            for (rec = parent; rec != NULL; rec = rec->parent) +                rec->refcount++; +            break; +        } +    } +    cur = NULL; + +    return cur; +} + +static void fs_cache_put_inode (inode_t *inode) +{ +    void (*put_inode)(inode_t *inode); +    inode_t *cur, **upd; + +    if (inode != NULL && --inode->refcount == 0) { +        if (inode->parent == NULL) +            return; +        fs_cache_put_inode(inode->parent); +        upd = &inode->parent->child; +        for (cur = *upd; cur != NULL; cur = cur->next) { +            if (cur == inode) { +                (*upd) = cur->next; +                put_inode = inode->fs->fs_ops->put_inode; +                (*put_inode)(cur); +                FS_DPRINTF("Free inode '%s' from '%s' cache\n", +                           inode->name, inode->parent->name); +                free(cur); +                return; +            } +            upd = &cur; +        } +        FS_ERROR("didn't find inode in list !\n"); +    } +} + +static inode_t *fs_get_inode (inode_t *parent, const unsigned char *name) +{ +    inode_t *(*get_inode)(inode_t *parent, const unsigned char *name); +    inode_t *cur; + +    if (parent == NULL) { +        FS_ERROR("Invalide inode '%s' (NULL)\n", name); +        return NULL; +    } else { +        if (fs_inode_get_type(parent) != INODE_TYPE_DIR) { +            FS_ERROR("Try to recurse in a non-directory inode (%d)\n", +                     parent->flags); +            return NULL; +        } +    } +    if (is_special_file(name)) { +        int type; +        /* Special files */ +        FS_DPRINTF("look for special file '%s'\n", +                   name + strlen(FS_SPECIAL) + 2); +        type = special_file_get_type(name + strlen(FS_SPECIAL) + 2); +        if (type == FILE_UNKNOWN) { +            FS_ERROR("Unknown special file '%s'\n", +                     name + strlen(FS_SPECIAL) + 2); +            return NULL; +        } +        cur = (*parent->fs->fs_ops->get_special_inode)(parent->fs, type); +        FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n", +                   parent->fs->bootfile, parent->fs->bootfile->name, +                   &parent->fs->bootfile, +                   parent->fs->bootdir, parent->fs->bootdir->name, +                   &parent->fs->bootdir); +        switch (type) { +        case FILE_ROOT: +            parent->fs->root = cur; +            cur->parent = NULL; +            cur->fs = parent->fs; +            cur->name = strdup(""); +            return cur; +        case FILE_BOOT: +            parent->fs->bootfile = cur; +            break; +        case FILE_BOOTDIR: +            parent->fs->bootdir = cur; +            break; +        } +#if 0 +        parent = cur->parent; +#else +        cur->fs = parent->fs; +        return cur; +#endif +    } else { +        FS_DPRINTF("look for file '%s' in %p '%s'\n", name, parent, +                   parent->name); +        DPRINTF("look for file '%s' in %p '%s'\n", name, parent, +                   parent->name); +        cur = fs_cache_get_inode(parent, name); +        if (cur != NULL) { +            FS_DPRINTF("found inode '%s' %p in cache\n", name, cur); +            DPRINTF("found inode '%s' %p in cache\n", name, cur); +            return cur; +        } +        get_inode = parent->fs->fs_ops->get_inode; +        cur = (*get_inode)(parent, name); +        cur->name = strdup(name); +    } +    if (cur != NULL) { +        cur->parent = parent; +        cur->fs = parent->fs; +        fs_cache_add_inode(parent, cur); +        FS_DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n", +                   name, parent->name, cur->nb_blocs, cur->size.bloc, +                   cur->size.offset); +        DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n", +                name, parent->name, cur->nb_blocs, cur->size.bloc, +                cur->size.offset); +    } else { +        FS_ERROR("Inode '%s' not found in '%s'\n", name, parent->name); +    } + +    return cur; +} + +static inline void fs_put_inode (inode_t *inode) +{ +    fs_cache_put_inode(inode); +} + +static inode_t *_fs_walk (inode_t *parent, const unsigned char *name) +{ +    unsigned char tmpname[MAXNAME_LEN], *sl; +    inode_t *new, *subdir; +     +    FS_DPRINTF("'%s' %p\n", name, parent); +    DPRINTF("'%s' %p\n", name, parent); +    for (; *name == '/'; name++) +        continue; +    DPRINTF("'%s' %p\n", name, parent); +    strcpy(tmpname, name); +    sl = strchr(tmpname, '/'); +    if (sl != NULL) { +        *sl = '\0'; +        subdir = fs_get_inode(parent, tmpname); +        if (subdir == NULL) +            return NULL; +        new = _fs_walk(subdir, sl + 1); +    } else { +        new = fs_get_inode(parent, tmpname); +    } + +    return new; +} + +static inode_t *fs_walk (inode_t *parent, const unsigned char *name) +{ +    unsigned char tmpname[MAXNAME_LEN]; +    int len; +     +    FS_DPRINTF("'%s' %p\n", name, parent); +    DPRINTF("'%s' %p %p\n", name, parent, parent->fs->root); +    len = strlen(name); +    memcpy(tmpname, name, len + 1); +    if (tmpname[len - 1] == '/') +        tmpname[--len] = '\0'; +    if (parent == parent->fs->root && tmpname[0] == '\0') +        return parent->fs->root; + +    return _fs_walk(parent, tmpname); +} + +static unsigned char *fs_inode_get_path (inode_t *inode) +{ +    unsigned char tmpname[MAXNAME_LEN], *pname; +    int len; +    inode_t *parent; + +    parent = inode->parent; +    if (parent == NULL || (inode->name[0] == '/' && inode->name[1] == '\0')) { +        FS_DPRINTF("Reached root node '/'\n"); +        return strdup("/"); +    } +    FS_DPRINTF("Recurse to root '%s'...\n", inode->name); +    pname = fs_inode_get_path(parent); +    FS_DPRINTF("'%s' '%s'\n", pname, inode->name); +    len = strlen(pname); +    memcpy(tmpname, pname, len); +    if (tmpname[len - 1] != '/') +        tmpname[len++] = '/'; +    strcpy(tmpname + len, inode->name); +    free(pname); +    FS_DPRINTF(" => '%s'\n", tmpname); + +    return strdup(tmpname); +} + +static inline uint32_t fs_map_bloc (inode_t *inode, uint32_t bloc) +{ +    FS_DPRINTF("%s: inode %p bloc %d %p %p %p\n", __func__, inode, bloc, +               inode->fs, inode->fs->fs_ops, inode->fs->fs_ops->map_bloc); +    return (*inode->fs->fs_ops->map_bloc)(inode, bloc); +} + +fs_t *fs_probe (part_t *part, int set_raw) +{ +    fs_t *new; +    inode_t fake_inode; +    fs_ops_t *fs_ops = NULL; +    unsigned char *name = NULL; +    void *private = NULL; +    uint32_t size = 0; +    int type = FS_TYPE_UNKNOWN; + +    FS_DPRINTF("\n"); +    if (set_raw == 2) { +        DPRINTF("Check raw only\n"); +        goto raw_only; +    } +    DPRINTF("Probe ext2\n"); +    type = fs_ext2_probe(part, &size, &fs_ops, &name, &private); +    if (type == FS_TYPE_UNKNOWN) { +        DPRINTF("Probe isofs\n"); +        type = fs_isofs_probe(part, &size, &fs_ops, &name, &private); +        if (type == FS_TYPE_UNKNOWN) { +            DPRINTF("Probe HFS\n"); +            type = fs_hfs_probe(part, &size, &fs_ops, &name, &private); +            if (set_raw) { +                DPRINTF("Probe raw\n"); +            raw_only: +                type = fs_raw_probe(part, &size, &fs_ops, &name, &private); +            } +            if (type == FS_TYPE_UNKNOWN) { +                FS_ERROR("FS not identified\n"); +                return NULL; +            } +        } +    } +    if (fs_ops == NULL || size == 0) { +        FS_ERROR("Missing param: %p %d\n", fs_ops, size); +        return NULL; +    } +    new = malloc(sizeof(fs_t)); +    if (new == NULL) +        return NULL; +    new->type = type; +    new->part = part; +    new->size = size; +    new->fs_ops = fs_ops; +    new->name = name; +    new->private = private; +    /* Get root inode */ +    memset(&fake_inode, 0, sizeof(inode_t)); +    fake_inode.name = "fake_root"; +    fake_inode.fs = new; +    fake_inode.refcount = 1; +    fs_get_inode(&fake_inode, "\0" FS_SPECIAL "\0root"); +    if (new->root == NULL) { +        FS_ERROR("Didn't find root inode\n"); +        free(new); +        return NULL; +    } +    FS_DPRINTF("fs: %p root: %p root fs: %p\n", new, new->root, new->root->fs); +    FS_DPRINTF("OK\n"); + +    return new; +} + +dir_t *fs_opendir (fs_t *fs, const unsigned char *name) +{ +    inode_t *inode; +    dir_t *new; + +    FS_DPRINTF("'%s'\n", name); +    inode = fs_walk(fs->root, name); +    if (inode == NULL) +        return NULL; +    new = malloc(sizeof(dir_t)); +    new->inode = inode; + +    return new; +} + +dirent_t *fs_readdir (dir_t *dir) +{ +    void (*put_inode)(inode_t *inode); +    inode_t *inode; + +    inode = fs_get_inode(dir->inode, NULL); +    if (inode == NULL) +        return NULL; +    if (dir->cur == NULL) { +        dir->cur = malloc(sizeof(dirent_t)); +        dir->cur->dir = dir; +    } else { +        put_inode = dir->inode->fs->fs_ops->put_inode; +        (*put_inode)(dir->cur->inode); +    } +    dir->cur->inode = inode; +    dir->cur->dname = inode->name; + +    return dir->cur; +} + +unsigned char *fs_get_path (dirent_t *dirent) +{ +    return fs_inode_get_path(dirent->inode); +} + +void fs_closedir (dir_t *dir) +{ +    void (*put_inode)(inode_t *inode); + +    if (dir->cur != NULL) { +        put_inode = dir->inode->fs->fs_ops->put_inode; +        (*put_inode)(dir->cur->inode); +        free(dir->cur); +    } +    free(dir); +} + +inode_t *fs_open (fs_t *fs, const unsigned char *name) +{ +    inode_t *inode; + +    FS_DPRINTF("'%s'\n", name); +    inode = fs_walk(fs->root, name); +    if (inode != NULL) +        fs_seek(inode, 0, 0); + +    return inode; +} + +int fs_seek (inode_t *inode, uint32_t bloc, uint32_t pos) +{ +    if (inode == NULL || inode->fs == NULL) { +        ERROR("%s: no inode / fs ! %p %p\n", __func__, inode, +              inode == NULL ? NULL : inode->fs); +        return -1; +    } +    FS_DPRINTF("%08x %08x\n", bloc, pos); +    if (part_seek(inode->fs->part, fs_map_bloc(inode, bloc), pos) == -1) +        return -1; +    inode->vbloc = bloc; +    inode->vpos = pos; + +    return 0; +} + +int fs_read (inode_t *inode, void *buffer, int len) +{ +    uint32_t bsize, total; +    int done, tmp; +     +    bsize = part_blocsize(inode->fs->part); +    total = 0; +    if (fs_seek(inode, inode->vbloc, inode->vpos) < 0) +        return -1; +    for (; len != 0; len -= done) { +        tmp = bsize - inode->vpos; +        if (len < tmp) +            tmp = len; +        done = part_read(inode->fs->part, buffer, tmp); +        if (done < 0) +            return -1; +        inode->vpos += done; +        if (inode->vpos >= bsize) { +            inode->vbloc++; +            inode->vpos -= bsize; +        } +        buffer += done; +        total += done; +    } + +    return total; +} + +int fs_write (inode_t *inode, const void *buffer, unused int len) +{ +    uint32_t bsize, total; +    int done, tmp; +     +    bsize = part_blocsize(inode->fs->part); +    total = 0; +    for (; len != 0; len -= done) { +        tmp = bsize - inode->vpos; +        if (len < tmp) +            tmp = len; +        done = part_write(inode->fs->part, buffer, tmp); +        if (done < 0) +            return -1; +        inode->vpos += done; +        if (inode->vpos >= bsize) { +            inode->vbloc++; +            inode->vpos -= bsize; +            if (fs_seek(inode, inode->vbloc, inode->vpos) < 0) +                return -1; +        } +        buffer += done; +        total += done; +    } + +    return total; +} + +void fs_close (inode_t *inode) +{ +    fs_put_inode(inode); +} + +uint32_t fs_inode_get_type (inode_t *inode) +{ +    return inode->flags & INODE_TYPE_MASK; +} + +uint32_t fs_inode_get_flags (inode_t *inode) +{ +    return inode->flags & INODE_FLAG_MASK; +} + +uint32_t fs_inode_get_size (inode_t *inode) +{ +    DPRINTF("%s: (%d * %d) + %d\n", __func__, inode->size.bloc, +            part_blocsize(inode->fs->part), inode->size.offset); +    return (inode->size.bloc * part_blocsize(inode->fs->part)) + +        inode->size.offset; +} + +part_t *fs_part (fs_t *fs) +{ +    return fs->part; +} + +uint32_t fs_get_type (fs_t *fs) +{ +    return fs->type; +} + +part_t *fs_inode_get_part (inode_t *inode) +{ +    return inode->fs->part; +} + +inode_t *fs_get_bootdir (fs_t *fs) +{ +    FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs); +    if (fs->bootdir == NULL) { +        fs->bootdir = fs_get_inode(fs->root, "\0" FS_SPECIAL "\0bootdir"); +    } +    FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs); +    FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n", +               fs->bootfile, fs->bootfile->name, &fs->bootfile, +               fs->bootdir, fs->bootdir->name, &fs->bootdir); + +    return fs->bootdir; +} +unsigned char *fs_get_boot_dirname (fs_t *fs) +{ +    if (fs->bootdir == NULL) { +        fs_get_bootdir(fs); +        if (fs->bootdir == NULL) +            return NULL; +    } +    FS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n", +               fs->bootfile, fs->bootfile->name, +               fs->bootdir, fs->bootdir->name); + +    return fs_inode_get_path(fs->bootdir); +} + +inode_t *fs_get_bootfile (fs_t *fs) +{ +    FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs); +    FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n", +               fs->bootfile, fs->bootfile->name, &fs->bootfile, +               fs->bootdir, fs->bootdir->name, &fs->bootdir); +    if (fs->bootfile == NULL) { +        if (fs->bootdir == NULL) +            fs_get_bootdir(fs); +        if (fs->bootdir == NULL) +            return NULL; +        fs->bootfile = fs_get_inode(fs->bootdir, "\0" FS_SPECIAL "\0boot"); +    } +    FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs); +    FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n", +               fs->bootfile, fs->bootfile->name, &fs->bootfile, +               fs->bootdir, fs->bootdir->name, &fs->bootdir); + +    return fs->bootfile; +} diff --git a/roms/openhackware/src/libfs/ext2.c b/roms/openhackware/src/libfs/ext2.c new file mode 100644 index 00000000..122f4089 --- /dev/null +++ b/roms/openhackware/src/libfs/ext2.c @@ -0,0 +1,32 @@ +/* + * <ext2.c> + * + * Open Hack'Ware BIOS ext2 file system management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include "bios.h" +#include "libfs.h" + +/* ext2 filesystem */ +int fs_ext2_probe (unused part_t *part, unused uint32_t *size, +                   unused fs_ops_t **fs_ops, unused unsigned char **name, +                   unused void **private) +{ +    return -1; +} diff --git a/roms/openhackware/src/libfs/hfs.c b/roms/openhackware/src/libfs/hfs.c new file mode 100644 index 00000000..b2420ebe --- /dev/null +++ b/roms/openhackware/src/libfs/hfs.c @@ -0,0 +1,2007 @@ +/* + * <hfs.c> + * + * Open Hack'Ware BIOS HFS file system management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + * Major rework and debug by Thayne Harbaugh <thayne@realmsys.com> + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "libfs.h" + +//#define DEBUG_HFS 1 + +/* HFS / HFSplus */ +#if defined (DEBUG_HFS) +#define HFS_DPRINTF(fmt, args...) \ +do { dprintf("%s: " fmt, __func__ , ##args); } while (0) +#else +#define HFS_DPRINTF(fmt, args...) \ +do { } while (0) +#endif +#define HFS_ERROR(fmt, args...) \ +do { dprintf("HFS ERROR in %s: " fmt, __func__ , ##args); } while (0) + +/* HFS/HFS+ common definitions */ +#define HFS_SECTOR_SIZE        512 +#define HFS_VOLHEAD_SECTOR       2 +#define HFS_NODE_SIZE          0x200 + +/* HFS signature */ +#define HFS_VOLHEAD_SIG         0x4244 +/* HFS+ signature */ +#define HFSPLUS_VOLHEAD_SIG     0x482b + +/* HFS+ filesystem support */ +/* Files CNID */ +enum { +    HFS_ROOT_PARENT  = 1,  /* Parent of root folder */ +    HFS_ROOT_FOLDER  = 2,  /* root folder */ +    HFS_EXTENT_FILE  = 3,  /* file extents file */ +    HFS_CATALOG_FILE = 4,  /* catalog file */ +    HFS_BBLOCS_FILE  = 5,  /* badblocks file */ +    HFS_ALLOC_FILE   = 6,  /* allocation file (HFSplus) */ +    HFS_STARTUP_FILE = 7,  /* startup file (HFSplus) */ +    HFS_ATTR_FILE    = 8,  /* attribute file (HFSplus) */ +    HFS_BEXTENT_FILE = 15, /* file extents temporary file */ +    HFS_FIRST_USERID = 16, +}; + +typedef uint32_t HFS_cnid_t; + +static inline HFS_cnid_t HFS_get_cnid (HFS_cnid_t *cnidp) +{ +    return get_be32(cnidp); +} + +typedef uint16_t HFSP_unichr_t; + +static inline HFSP_unichr_t HFSP_get_unichr (HFSP_unichr_t *chrp) +{ +    return get_be16(chrp); +} + +/* A single contiguous area of a file */ +typedef struct HFSP_extent_t HFSP_extent_t; +struct HFSP_extent_t { +    uint32_t start_block; +    uint32_t block_count; +} __attribute__ ((packed)); + +static inline HFSP_extent_t *HFSP_get_extent (HFSP_extent_t *extp) +{ +    extp->start_block = get_be32(&extp->start_block); +    extp->block_count = get_be32(&extp->block_count); + +    return extp; +} + +/* Information for a "Fork" in a file */ +typedef struct HFSP_fork_t HFSP_fork_t; +struct HFSP_fork_t { +    /* 0x00 */ +    uint64_t total_size; +    uint32_t clump_size; +    uint32_t total_blocks; +    /* 0x10 */ +    HFSP_extent_t extents[8]; +    /* 0x50 */ +} __attribute__ ((packed)); + +static inline HFSP_fork_t *HFSP_get_fork (HFSP_fork_t *forkp) +{ +    int i; + +    forkp->total_size = get_be64(&forkp->total_size); +    forkp->clump_size = get_be32(&forkp->clump_size); +    forkp->total_blocks = get_be32(&forkp->total_blocks); +    for (i = 0; i < 8; i++) { +        HFSP_get_extent(&forkp->extents[i]); +    } + +    return forkp; +} + +/* HFS+ Volume Header */ +typedef struct HFSP_vh_t HFSP_vh_t; +struct HFSP_vh_t { +    /* 0x000 */ +    uint16_t signature; +    uint16_t version; +    uint32_t attributes; +    uint32_t last_mount_vers; +    uint32_t reserved; +     +    /* 0x010 */ +    uint32_t create_date; +    uint32_t modify_date; +    uint32_t backup_date; +    uint32_t checked_date; +     +    /* 0x020 */ +    uint32_t file_count; +    uint32_t folder_count; +    uint32_t blocksize; +    uint32_t total_blocks; + +    /* 0x030 */ +    uint32_t free_blocks; +    uint32_t next_alloc; +    uint32_t rsrc_clump_sz; +    uint32_t data_clump_sz; + +    /* 0x040 */ +    HFS_cnid_t next_cnid; +    uint32_t write_count; +    uint64_t encodings_bmp; +     +    /* 0x050 */ +    uint32_t finder_info[8]; +     +    /* 0x070 */ +    HFSP_fork_t alloc_file; +    /* 0x0C0 */ +    HFSP_fork_t ext_file; +    /* 0x110 */ +    HFSP_fork_t cat_file; +    /* 0x160 */ +    HFSP_fork_t attr_file; +    /* 0x1B0 */ +    HFSP_fork_t start_file; +    /* 0x1F0 */ +    uint8_t pad[16]; +} __attribute__ ((packed)); + +static HFSP_vh_t *HFSP_read_volhead (part_t *part, uint32_t bloc, +                                     uint32_t offset, void *buffer, int size) +{ +    HFSP_vh_t *vh; +    int i; +     +    if (part_seek(part, bloc, offset) == -1) +        return NULL; +    if (part_read(part, buffer, size) < 0) +        return NULL; +    vh = buffer; +    vh->signature = get_be16(&vh->signature); +    vh->version = get_be16(&vh->version); +    vh->attributes = get_be32(&vh->attributes); +    vh->last_mount_vers = get_be32(&vh->last_mount_vers); +    vh->create_date = get_be32(&vh->create_date); +    vh->modify_date = get_be32(&vh->modify_date); +    vh->backup_date = get_be32(&vh->backup_date); +    vh->checked_date = get_be32(&vh->checked_date); +    vh->file_count = get_be32(&vh->file_count); +    vh->folder_count = get_be32(&vh->folder_count); +    vh->blocksize = get_be32(&vh->blocksize); +    vh->total_blocks = get_be32(&vh->total_blocks); +    vh->free_blocks = get_be32(&vh->free_blocks); +    vh->next_alloc = get_be32(&vh->next_alloc); +    vh->rsrc_clump_sz = get_be32(&vh->rsrc_clump_sz); +    vh->data_clump_sz = get_be32(&vh->data_clump_sz); +    HFS_get_cnid(&vh->next_cnid); +    vh->write_count = get_be32(&vh->write_count); +    vh->encodings_bmp = get_be32(&vh->encodings_bmp); +    for (i = 0; i < 8; i++) { +        vh->finder_info[i] = get_be32(&vh->finder_info[i]); +    } +    HFSP_get_fork(&vh->alloc_file); +    HFSP_get_fork(&vh->ext_file); +    HFSP_get_fork(&vh->cat_file); +    HFSP_get_fork(&vh->attr_file); +    HFSP_get_fork(&vh->start_file); + +    return vh; +} + +/* HFS support */ +/* A single contiguous area of a file */ +typedef struct HFS_extent_t HFS_extent_t; +struct HFS_extent_t { +    uint16_t start_block; +    uint16_t block_count; +} __attribute__ ((packed)); + +static inline HFS_extent_t *HFS_get_extent (HFS_extent_t *extp) +{ +    extp->start_block = get_be16(&extp->start_block); +    extp->block_count = get_be16(&extp->block_count); + +    return extp; +} + +/* HFS Volume Header */ +typedef struct HFS_vh_t HFS_vh_t; +struct HFS_vh_t { +    /* 0x000 */ +    uint16_t signature; +    uint32_t create_date; +    uint32_t modify_date; +    uint16_t attributes; +    uint16_t root_file_count; +    uint16_t bitmap_start; + +    /* 0x010 */ +    uint16_t alloc_ptr; +    uint16_t alloc_blocs; +    uint32_t alloc_size; + +    /* 0x018 */ +    uint32_t clump_size; +    uint16_t alloc_start; +    HFS_cnid_t next_cnid; +    uint16_t free_blocs; + +    /* 0x024 */ +    uint8_t  label[28]; + +    /* 0x040 */ +    uint32_t backup_tmsp; +    uint16_t backup_seq; +    uint32_t write_count; + +    /* 0x04A */ +    uint32_t ext_clump_size; +    /* 0x04E */ +    uint32_t cat_clump_size; + +    /* 0x052 */ +    uint16_t root_dir_cnt; +    /* 0x054 */ +    uint32_t file_cnt; +    uint32_t dir_cnt; +    /* 0x05C */ +    uint32_t finder_info[8]; + +    /* 0x07C */ +    uint16_t embed_sig; +    HFS_extent_t embed_ext; + +    /* 0x082 */ +    uint32_t ext_size; +    HFS_extent_t ext_rec[3]; + +    /* 0x092 */ +    uint32_t cat_size; +    HFS_extent_t cat_rec[3]; + +    /* 0x0A2 */ +} __attribute__(( __packed__ )); + +static HFS_vh_t *HFS_read_volhead (part_t *part, uint32_t bloc, +                                   uint32_t offset, void *buffer, int size) +{ +    HFS_vh_t *vh; +    int i; +     +    if (part_seek(part, bloc, offset) == -1) +        return NULL; +    if (part_read(part, buffer, size) < 0) +        return NULL; +    vh = buffer; +    vh->signature = get_be16(&vh->signature); +    vh->create_date = get_be32(&vh->create_date); +    vh->modify_date = get_be32(&vh->modify_date); +    vh->attributes = get_be16(&vh->attributes); +    vh->root_file_count = get_be16(&vh->root_file_count); +    vh->bitmap_start = get_be16(&vh->bitmap_start); +    vh->alloc_ptr = get_be16(&vh->alloc_ptr); +    vh->alloc_blocs = get_be16(&vh->alloc_blocs); +    vh->alloc_size = get_be32(&vh->alloc_size); +    vh->clump_size = get_be32(&vh->clump_size); +    vh->alloc_start = get_be16(&vh->alloc_start); +    HFS_get_cnid(&vh->next_cnid); +    vh->free_blocs = get_be16(&vh->free_blocs); +    vh->backup_tmsp = get_be32(&vh->backup_tmsp); +    vh->backup_seq = get_be16(&vh->backup_seq); +    vh->write_count = get_be32(&vh->write_count); +    vh->ext_clump_size = get_be32(&vh->ext_clump_size); +    vh->cat_clump_size = get_be32(&vh->cat_clump_size); +    vh->root_dir_cnt = get_be16(&vh->root_dir_cnt); +    vh->file_cnt = get_be32(&vh->file_cnt); +    vh->dir_cnt = get_be32(&vh->dir_cnt); +    for (i = 0; i < 8; i++) { +        vh->finder_info[i] = get_be32(&vh->finder_info[i]); +    } +    vh->embed_sig = get_be16(&vh->embed_sig); +    HFS_get_extent(&vh->embed_ext); +    vh->ext_size = get_be16(&vh->ext_size); +    for (i = 0; i < 3; i++) { +        HFS_get_extent(&vh->ext_rec[i]); +    } +    vh->cat_size = get_be16(&vh->cat_size); +    for (i = 0; i < 3; i++) { +        HFS_get_extent(&vh->cat_rec[i]); +    } + +    return vh; +} + +enum { +    HFS_NODE_LEAF = 0xFF, +    HFS_NODE_IDX  = 0x00, +    HFS_NODE_HEAD = 0x01, +    HFS_NODE_MAP  = 0x02, +}; + +/* HFS B-tree structures */ +typedef struct HFS_bnode_t HFS_bnode_t; +struct HFS_bnode_t { +    uint32_t next; +    uint32_t prev; +    uint8_t  type; +    uint8_t  height; +    uint16_t nrecs; +    uint16_t pad; +} __attribute__ ((packed)); + +static HFS_bnode_t *HFS_read_Hnode (part_t *part, uint32_t bloc, +                                    uint32_t offset, void *buffer, int nsize) +{ +    HFS_bnode_t *Hnode; +     +    if (part_seek(part, bloc, offset) == -1) { +        HFS_DPRINTF("seek failed\n"); +        return NULL; +    } +    if (part_read(part, buffer, nsize) < 0) { +        HFS_DPRINTF("read failed\n"); +        return NULL; +    } +    Hnode = (void *)buffer; +    Hnode->next = get_be32(&Hnode->next); +    Hnode->prev = get_be32(&Hnode->prev); +    Hnode->nrecs = get_be16(&Hnode->nrecs); + +    return Hnode; +} + +typedef struct HFS_headrec_t HFS_headrec_t; +struct HFS_headrec_t { +    /* 0x00 */ +    uint16_t depth; +    uint32_t rootnode; +    /* 0x06 */ +    uint32_t nbleaves; +    uint32_t firstleaf; +    /* 0x0E */ +    uint32_t lastleaf; +    uint16_t nodesize; +    /* 0x14 */ +    uint16_t maxkeylen; +    uint32_t nbnodes; +    /* 0x18 */ +    uint32_t freenodes; +    uint16_t pad0; +    /* 0x1E */ +    uint32_t clump_size; +    uint8_t  type; +    uint8_t  pad1; +    /* 0x24 */ +    uint32_t attr; +    /* 0x28 */ +    uint32_t pad2[16]; +    /* 0x68 */ +} __attribute__ ((packed)); + +static HFS_headrec_t *HFS_get_headrec (void *pos) +{ +    HFS_headrec_t *head = pos; + +    head->depth = get_be16(&head->depth); +    head->rootnode = get_be32(&head->rootnode); +    head->nbleaves = get_be32(&head->nbleaves); +    head->firstleaf = get_be32(&head->firstleaf); +    head->lastleaf = get_be32(&head->lastleaf); +    head->maxkeylen = get_be16(&head->maxkeylen); +    head->nbnodes = get_be32(&head->nbnodes); +    head->freenodes = get_be32(&head->freenodes); +    head->clump_size = get_be32(&head->clump_size); +    head->attr = get_be32(&head->attr); + +    return head; +} + +typedef struct HFS_catkey_t HFS_catkey_t; +struct HFS_catkey_t { +    uint8_t len; +    uint8_t pad; +    HFS_cnid_t pID; +    uint8_t nlen; +    unsigned char name[0x1F]; +} __attribute__ ((packed)); + +typedef struct HFSP_catkey_t HFSP_catkey_t; +struct HFSP_catkey_t { +    uint16_t len; +    HFS_cnid_t pID; +    uint16_t nlen; +    HFSP_unichr_t uniname[255]; +} __attribute__ ((packed)); + +enum { +    HFS_CAT_FOLDER  = 0x0100, +    HFS_CAT_FILE    = 0x0200, +    HFS_CAT_FOLDTH  = 0x0300, +    HFS_CAT_FILETH  = 0x0400, +    HFSP_CAT_FOLDER = 0x0001, +    HFSP_CAT_FILE   = 0x0002, +    HFSP_CAT_FOLDTH = 0x0003, +    HFSP_CAT_FILETH = 0x0004, +}; + +typedef struct HFS_win_t HFS_win_t; +struct HFS_win_t { +    uint16_t top; +    uint16_t left; +    uint16_t bot; +    uint16_t right; +}  __attribute__ ((packed)); + +typedef struct HFS_pos_t HFS_pos_t; +struct HFS_pos_t { +    uint16_t y; +    uint16_t x; +} __attribute__ ((packed)); + +typedef struct HFS_fdir_info_t HFS_fdir_info_t; +struct HFS_fdir_info_t { +    HFS_win_t win; +    uint16_t  flags; +    HFS_pos_t pos; +    uint16_t  pad; +} __attribute__ ((packed)); + +typedef struct HFS_file_info_t HFS_file_info_t; +struct HFS_file_info_t { +    uint32_t  ftype; +    uint32_t  owner; +    uint16_t  flags; +    HFS_pos_t pos; +    uint16_t  pad; +} __attribute__ ((packed)); + +typedef struct HFSP_BSD_info_t HFSP_BSD_info_t; +struct HFSP_BSD_info_t { +    uint32_t owner; +    uint32_t group; +    uint8_t aflags; +    uint8_t oflags; +    uint16_t mode; +    union { +        uint32_t inum; +        uint32_t lcount; +        uint32_t device; +    } u; +} __attribute__ ((packed)); + +typedef struct HFS_fold_t HFS_fold_t; +struct HFS_fold_t { +    uint16_t type; +    uint16_t flags; +    uint16_t valence; +    HFS_cnid_t ID; +    uint32_t created; +    uint32_t modifd; +    uint32_t backupd; +    HFS_fdir_info_t finder_dir; +    uint8_t  finder_pad[16]; +    uint32_t pad[4]; +} __attribute__ ((packed)); + +typedef struct HFSP_fold_t HFSP_fold_t; +struct HFSP_fold_t { +    uint16_t type; +    uint16_t flags; +    uint32_t valence; +    HFS_cnid_t ID; +    uint32_t created; +    uint32_t modifd; +    uint32_t attrd; +    uint32_t accessd; +    uint32_t attrmd; +    HFSP_BSD_info_t BSD_infos; +    HFS_fdir_info_t finder_dir; +    uint8_t  finder_pad[16]; +    uint32_t encoding; +    uint32_t pad; +} __attribute__ ((packed)); + +typedef struct HFS_file_t HFS_file_t; +struct HFS_file_t { +    /* 0x00 */ +    uint16_t type; +    uint8_t  flags; +    uint8_t  ftype; +    /* 0x04 */ +    HFS_file_info_t finder_file; +    /* 0x14 */ +    HFS_cnid_t ID; +    /* 0x18 */ +    uint16_t dstart; +    uint32_t dlsize; +    uint32_t dpsize; +    uint16_t rstart; +    /* 0x24 */ +    uint32_t rlsize; +    uint32_t rpsize; +    /* 0x2C */ +    uint32_t created; +    /* 0x30 */ +    uint32_t modifd; +    uint32_t backupd; +    /* 0x38 */ +    uint8_t  finder_pad[16]; +    /* 0x48 */ +    uint16_t clump_size; +    /* 0x4C */ +    HFS_extent_t extents[3]; +    /* 0x54 */ +} __attribute__ ((packed)); + +typedef struct HFSP_file_t HFSP_file_t; +struct HFSP_file_t { +    /* 0x00 */ +    uint16_t type; +    uint16_t flags; +    uint32_t pad; +    /* 0x08 */ +    HFS_cnid_t ID; +    uint32_t created; +    /* 0x10 */ +    uint32_t modifd; +    uint32_t attrd; +    uint32_t accessd; +    uint32_t backupd; +    /* 0x20 */ +    HFSP_BSD_info_t BSD_infos; +    /* 0x30 */ +    HFS_file_info_t finder_file; +    /* 0x40 */ +    uint8_t  finder_pad[16]; +    /* 0x50 */ +    uint32_t encoding; +    uint32_t pad1[3]; +    HFSP_fork_t data; +    HFSP_fork_t ressources; +} __attribute__ ((packed)); + +typedef struct HFS_thread_t HFS_thread_t; +struct HFS_thread_t { +    uint16_t type; +    uint32_t pad[2]; +    HFS_cnid_t pid; +    uint8_t pad0; +    unsigned char name[32]; +} __attribute__ ((packed)); + +typedef struct HFSP_thread_t HFSP_thread_t; +struct HFSP_thread_t { +    uint16_t type; +    uint16_t pad; +    HFS_cnid_t pid; +    uint16_t nlen; +    HFSP_unichr_t uniname[255]; +} __attribute__ ((packed)); + +/* in memory structures */ +typedef struct hfs_vol_t hfs_vol_t; +typedef struct hfs_btree_t hfs_btree_t; +typedef struct hfs_rec_t hfs_rec_t; + +/* Volume/file structures */ +typedef struct hfs_extent_t { +    uint32_t start; +    uint32_t count; +} hfs_extent_t; + +typedef struct hfs_fork_t { +    hfs_vol_t *volume; +    uint32_t nb_blocs; +    hfs_extent_t extents[8]; +    hfs_rec_t *catrec; +    hfs_rec_t *extrec; +} hfs_fork_t; + +struct hfs_vol_t { +    part_t *part; +    int type; +    HFS_cnid_t boot_id; +    uint32_t embed_offset; +    uint32_t start_offset; +    uint32_t bsize; +    hfs_fork_t alloc_file; +    hfs_fork_t cat_file; +    hfs_fork_t ext_file; +    hfs_fork_t *boot_file; +    hfs_btree_t *cat_tree; +    hfs_btree_t *ext_tree; +}; + +/* Btree structures */ +/* Btree node */ +typedef struct hfs_bnode_t { +    hfs_btree_t *tree; +    uint32_t prev; +    uint32_t next; +    int type; +    uint32_t nrecs; +    hfs_rec_t *recs; +} hfs_bnode_t; + +/* Cached Btree node */ +typedef struct hfs_cbnode_t hfs_cbnode_t; +struct hfs_cbnode_t { +    uint32_t location; +    hfs_cbnode_t *next; +    hfs_bnode_t bnode; +}; + +/* Bnode records */ +enum { +    RECORD_HEAD = 0, +    RECORD_IDX, +    RECORD_CAT, +    RECORD_EXT, +}; + +/* Header record */ +typedef struct hfs_headrec_t { +    uint32_t rootnode; +    uint32_t firstleaf; +    uint32_t lastleaf; +    uint32_t nodesize; +} hfs_headrec_t; + +/* Index record */ +typedef struct hfs_idxrec_t { +    HFS_cnid_t pid; +    HFS_cnid_t uid; +    unsigned char name[0x20]; +} hfs_idxrec_t; + +/* File extent records */ +/* TODO */ +typedef struct hfs_extrec_t { +    HFS_cnid_t ID; +} hfs_extrec_t; + +/* Catalog records */ +typedef struct hfs_catrec_t { +    HFS_cnid_t ID; +    HFS_cnid_t pid; +    int type; +    unsigned char name[0x20]; +    unsigned char finfo[9]; +    hfs_fork_t fork; +} hfs_catrec_t; + +/* Generic record */ +struct hfs_rec_t { +    hfs_bnode_t *node; +    int type; +    int num; +    union { +        hfs_headrec_t headrec; +        hfs_idxrec_t  idxrec; +        hfs_catrec_t  catrec; +        hfs_extrec_t  extrec; +    } u; +}; + +struct hfs_btree_t { +    hfs_fork_t *file; +    hfs_cbnode_t *cache; +    hfs_rec_t *head_rec; +    hfs_bnode_t *root_node; +    hfs_rec_t *root_catrec; +    hfs_rec_t *root_extrec; +    uint32_t nodesize; +    unsigned char *buf; +    int type; +    int (*compare)(int type, HFS_cnid_t cnid, +                   const void *more, hfs_rec_t *rec, int rectype); +}; + +/* Unicode to ISO-8859-15, stolen from Linux nls */ +static unsigned char page00[256] = { +    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ +    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ +    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ +    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ +    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ +    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ +    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ +    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ +    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ +    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ +    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ +    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ +    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ +    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ +    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ +    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ +    0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */ +    0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ +    0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ +    0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */ +    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ +    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ +    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ +    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ +    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ +    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ +    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ +    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static unsigned char page01[256] = { +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ +    0x00, 0x00, 0xbc, 0xbd, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ +    0xa6, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ +    0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */ +}; + +static unsigned char page20[256] = { +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ +    0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ +}; + +static unsigned char *page_uni2charset[256] = { +    page00, page01, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,    +    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL, +     +    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL, +    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL, +     +    page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL, +    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL, +}; + +static int uni2char (uint16_t uni, unsigned char *out) +{ +    unsigned char *uni2charset; +    unsigned char cl = uni & 0x00ff; +    unsigned char ch = (uni & 0xff00) >> 8; + +    uni2charset = page_uni2charset[ch]; +    if (uni2charset && uni2charset[cl]) +        *out = uni2charset[cl]; +    else +        return -1; + +    return 0; +} + +static void hfs_get_str (unsigned char *out, int len, uint16_t *hfs_str) +{ +    int i; +    char c; +  +    for (i = 0; i < len; i++) { +        if (uni2char(*hfs_str++, &c) < 0) +            c = '?'; +        out[i] = c; +    } +    out[i] = '\0'; +} + +/* Locate a bloc in the partition given a file and an offset */ +static uint32_t hfs_get_bloc (hfs_fork_t *file, uint32_t bloc) +{ +    hfs_vol_t *volume; +    hfs_extent_t *extent; +    uint32_t abloc, aoffset; +    int i; +     +    volume = file->volume; +    abloc = bloc / volume->bsize; +    aoffset = bloc - (abloc * volume->bsize); +    extent = file->extents; +#if 0 +    HFS_DPRINTF("Look for bloc %08x => %08x %08x (%08x)\n", +                bloc, abloc, aoffset, volume->bsize); +#endif +    for (i = 0; i < 8; i++) { +#if 0 +        HFS_DPRINTF("Check extent %d %08x %08x (%08x)\n", +                    i, extent->start, extent->count, abloc); +#endif +        if (extent->count == 0) +            break; +        if (abloc < extent->count) { +            return volume->start_offset + /*volume->embed_offset +*/ +                ((extent->start + abloc) * volume->bsize) + aoffset; +        } +        abloc -= extent->count; +        extent++; +    } +    HFS_ERROR("Block %d not found\n", bloc); + +    return -1; +} + +/* Convert HFS/HFS plus extent/fork records to memory structure */ +static inline void hfs_get_extent (hfs_extent_t *dst, HFS_extent_t *src) +{ +    dst->start = src->start_block; +    dst->count = src->block_count; +} + +static void hfs_get_fork (hfs_fork_t *dst, uint32_t blocs, +                          HFS_extent_t *extents) +{ +    int i; + +    dst->nb_blocs = blocs; +    for (i = 0; i < 3; i++) { +        hfs_get_extent(&dst->extents[i], &extents[i]); +    } +    memset(&dst->extents[3], 0, 5 * sizeof(hfs_extent_t)); +} + +static inline void hfsp_get_extent (hfs_extent_t *dst, HFSP_extent_t *src) +{ +    dst->start = src->start_block; +    dst->count = src->block_count; +} + +static void hfsp_get_fork (hfs_fork_t *dst, uint32_t blocs, +                           HFSP_extent_t *extents) +{ +    int i; + +    dst->nb_blocs = blocs; +    for (i = 0; i < 8; i++) { +        hfsp_get_extent(&dst->extents[i], &extents[i]); +    } +} + +static void hfs_dump_fork (hfs_fork_t *fork) +{ +    int i; + +    HFS_DPRINTF("Nb blocs: %d\n", fork->nb_blocs); +    for (i = 0; i < 8; i++) { +        if (fork->extents[i].count == 0) +            break; +        HFS_DPRINTF("  extent %d: start: %08x count: %08x\n", +                    i, fork->extents[i].start, fork->extents[i].count); +    } +} + +/* Btree nodes cache */ +static inline void *hfs_brec_get (HFS_bnode_t *node, uint32_t nodesize, int nb) +{ +    uint16_t *off; + +    if (nb < 1 || nb > node->nrecs) { +        HFS_ERROR("nb=%d nrec=%d\n", nb, node->nrecs); +        return NULL; +    } +    off = (void *)((char *)node + nodesize); +    off -= nb; +    HFS_DPRINTF("%d => %02x node %p off %p %p %d\n", +                nb, *off, node, off, (char *)node + nodesize, nodesize); +     +    return (char *)node + *off; +} + +static hfs_bnode_t *hfs_bnode_get (hfs_btree_t *tree, uint32_t location) +{ +    unsigned char *buffer, tmpbuf[HFS_NODE_SIZE]; +    void *HFS_recp; +    HFS_bnode_t *Hnode; +    HFS_headrec_t *Hhead; +    HFSP_catkey_t *HPkey = NULL; +    HFS_catkey_t *Hkey = NULL; +    HFSP_thread_t *HPthread; +    HFS_thread_t *Hthread; +    HFSP_fold_t *HPdir; +    HFS_fold_t *Hdir; +    HFSP_file_t *HPfile; +    HFS_file_t *Hfile; +    hfs_headrec_t *head; +    hfs_cbnode_t **cur; +    hfs_bnode_t *node; +    hfs_rec_t *rec; +    uint32_t bloc, offset, bsize, *upID, nsize; +    uint16_t *ptype; +    int i, j, is_hfs; +     +#if 1 +    for (cur = &tree->cache; *cur != NULL; cur = &((*cur)->next)) { +        if ((*cur)->location == location) { +            HFS_DPRINTF("found node %08x in cache (%08x %08x)\n", +                        location, (*cur)->bnode.prev, (*cur)->bnode.next); +            return &(*cur)->bnode; +        } +    } +#endif +    /* Not found in cache, get it from disk */ +    head = &tree->head_rec->u.headrec; +    if (tree->nodesize != 0) { +        nsize = tree->nodesize; +        buffer = tree->buf; +    } else { +        nsize = HFS_NODE_SIZE; +        buffer = tmpbuf; +    } +    bsize = part_blocsize(tree->file->volume->part); +    bloc = location * nsize / 512; +    HFS_DPRINTF("Get node from %08x %08x %p\n", +                bloc, nsize, tree->file->volume->part); +    bloc = hfs_get_bloc(tree->file, bloc); +    if (bloc == (uint32_t)-1) +        return NULL; +    HFS_DPRINTF("  => %08x\n", bloc); +#if 0 +    offset = bloc % bsize; +    bloc /= bsize; +#else +    offset = 0; +#endif +    HFS_DPRINTF("  => %08x %08x (%d)\n", bloc, offset, bsize); +    Hnode = HFS_read_Hnode(tree->file->volume->part, +                           bloc, offset, buffer, nsize); +    if (Hnode == NULL) { +        HFS_DPRINTF("No Hnode !\n"); +        return NULL; +    } +    *cur = malloc(sizeof(hfs_cbnode_t) + (Hnode->nrecs * sizeof(hfs_rec_t))); +    if (*cur == NULL) +        return NULL; +    memset(*cur, 0, sizeof(hfs_cbnode_t) + (Hnode->nrecs * sizeof(hfs_rec_t))); +    (*cur)->location = location; +    node = &(*cur)->bnode; +    node->tree = tree; +    node->prev = Hnode->prev; +    node->next = Hnode->next; +    node->type = Hnode->type; +    node->nrecs = Hnode->nrecs; +    node->recs = (void *)(node + 1); +    if (tree->nodesize == 0 && node->type != HFS_NODE_HEAD) { +        HFS_ERROR("first node should be a header !\n"); +        return NULL; +    } +    if (node->type == HFS_NODE_HEAD) { +        Hhead = HFS_get_headrec(Hnode + 1); +        nsize = Hhead->nodesize; +        if (nsize == 0) +            nsize = HFS_NODE_SIZE; +        HFS_DPRINTF("Set node size to %d\n", nsize); +        tree->nodesize = nsize; +        tree->buf = malloc(nsize); +        if (tree->buf == NULL) +            return NULL; +        memset(tree->buf, 0, nsize); +        buffer = tree->buf; +        Hnode = HFS_read_Hnode(tree->file->volume->part, +                               bloc, offset, buffer, nsize); +        if (Hnode == NULL) +            return NULL; +    } +    HFS_DPRINTF("New node %08x prev: %08x next: %08x type: %d nrecs: %d\n", +                location, node->prev, node->next, node->type, node->nrecs); +    is_hfs = tree->file->volume->type == FS_TYPE_HFS; +    for (i = 0; i < (int)node->nrecs; i++) { +        rec = &node->recs[i]; +        rec->node = node; +        rec->num = i + 1; +        HFS_recp = hfs_brec_get(Hnode, nsize, i + 1); +        if (HFS_recp == NULL) { +            HFS_ERROR("can't get record %d\n", i + 1); +            continue; +        } +        if (is_hfs) { +            Hkey = HFS_recp; +#if 0 +            upID = (void *)(((uint32_t)Hkey + 2 + Hkey->len)); +#else +            upID = (void *)(((uint32_t)Hkey + 2 + Hkey->len) & ~1); +#endif +        } else { +            HPkey = HFS_recp; +            upID = (void *)(((uint32_t)HPkey + 2 + HPkey->len) & ~1); +        } +        switch (node->type) { +        case HFS_NODE_LEAF: +            HFS_DPRINTF("record %d: leaf %p %p %d\n", i + 1, upID, HFS_recp, +                        (char *)upID - (char *)HFS_recp); +            rec->type = tree->type; +            switch (rec->type) { +            case RECORD_CAT: +                ptype = (void *)upID; +                if (is_hfs) { +                    memcpy(rec->u.catrec.name, Hkey->name, Hkey->nlen); +                    rec->u.catrec.name[Hkey->nlen] = '\0'; +                    rec->u.catrec.pid = Hkey->pID; +                } else { +                    hfs_get_str(rec->u.catrec.name, +                                HPkey->nlen, HPkey->uniname); +                    rec->u.catrec.pid = HPkey->pID; +                } +                rec->u.catrec.type = *ptype; +                rec->u.catrec.fork.volume = tree->file->volume; +                rec->u.catrec.fork.catrec = rec; +                switch (*ptype) { +                case HFS_CAT_FOLDER: +                    Hdir = (void *)ptype; +                    rec->u.catrec.ID = Hdir->ID; +                    HFS_DPRINTF("HFS Catalog folder ID: %08x name '%s' %08x\n", +                                rec->u.catrec.ID, rec->u.catrec.name, +                                rec->u.catrec.pid); +                    break; +                case HFS_CAT_FILE: +                    Hfile = (void *)ptype; +                    rec->u.catrec.ID = Hfile->ID; +                    memcpy(rec->u.catrec.finfo, &Hfile->finder_file, 8); +                    rec->u.catrec.finfo[8] = '\0'; +                    for (j = 0; j < 3; j++) { +                        hfs_get_extent(&rec->u.catrec.fork.extents[j], +                                       &Hfile->extents[j]); +#if 0 +                        HFS_DPRINTF("Extent %04x %04x => %08x %08x\n", +                                    Hfile->extents[j].start_block, +                                    Hfile->extents[j].block_count, +                                    rec->u.catrec.fork.extents[j].start, +                                    rec->u.catrec.fork.extents[j].count); +#endif +                    } +                    memset(&rec->u.catrec.fork.extents[3], 0, +                           5 * sizeof(hfs_extent_t)); +                    HFS_DPRINTF("HFS Catalog file ID: %08x name '%s' '%s' %08x\n", +                                rec->u.catrec.ID, rec->u.catrec.name, +                                rec->u.catrec.finfo, rec->u.catrec.pid); +#if 0 +                    HFS_DPRINTF("Extent %08x %08x\n", +                                rec->u.catrec.fork.extents[0].start, +                                rec->u.catrec.fork.extents[0].count); +#endif +                    break; +                case HFS_CAT_FOLDTH: +                    Hthread = (void *)ptype; +                    strcpy(rec->u.catrec.name, Hthread->name); +                    rec->u.catrec.ID = rec->u.catrec.pid; +                    rec->u.catrec.pid = Hthread->pid; +                    HFS_DPRINTF("HFS Catalog folder thread '%s' %08x %08x\n", +                                rec->u.catrec.name, rec->u.catrec.ID, +                                rec->u.catrec.pid); +                    continue; +                case HFS_CAT_FILETH: +                    Hthread = (void *)ptype; +                    strcpy(rec->u.catrec.name, Hthread->name); +                    rec->u.catrec.ID = rec->u.catrec.pid; +                    rec->u.catrec.pid = Hthread->pid; +                    HFS_DPRINTF("HFS Catalog file thread '%s' %08x %08x\n", +                                rec->u.catrec.name, rec->u.catrec.ID, +                                rec->u.catrec.pid); +                    continue; +                case HFSP_CAT_FOLDER: +                    HPdir = (void *)ptype; +                    rec->u.catrec.ID = HPdir->ID; +                    HFS_DPRINTF("HFSplus Catalog folder ID: %08x name '%s'\n", +                                rec->u.catrec.ID, rec->u.catrec.name); +                    break; +                case HFSP_CAT_FILE: +                    HPfile = (void *)ptype; +                    rec->u.catrec.ID = HPfile->ID; +                    memcpy(rec->u.catrec.finfo, &HPfile->finder_file, 8); +                    rec->u.catrec.finfo[8] = '\0'; +                    memcpy(&rec->u.catrec.fork, &HPfile->data, +                           sizeof(HFSP_fork_t)); +                    HFS_DPRINTF("HFSPlus Catalog file ID: %08x name '%s' '%s'\n", +                                rec->u.catrec.ID, rec->u.catrec.name, +                                rec->u.catrec.finfo); +                    HFS_DPRINTF("Extent %08x %08x\n", +                                rec->u.catrec.fork.extents[0].start, +                                rec->u.catrec.fork.extents[0].count); +                    break; +                case HFSP_CAT_FOLDTH: +                    HPthread = (void *)ptype; +                    rec->u.catrec.ID = rec->u.catrec.pid; +                    rec->u.catrec.pid = HPthread->pid; +                    hfs_get_str(rec->u.catrec.name, +                                HPthread->nlen, HPthread->uniname); +                    HFS_DPRINTF("HFSplus Catalog folder thread '%s'...\n", +                                rec->u.catrec.name); +                    break; +                case HFSP_CAT_FILETH: +                    HPthread = (void *)ptype; +                    hfs_get_str(rec->u.catrec.name, +                                HPthread->nlen, HPthread->uniname); +                    rec->u.catrec.ID = rec->u.catrec.pid; +                    rec->u.catrec.pid = HPthread->pid; +                    HFS_DPRINTF("HFSplus Catalog file thread '%s'...\n", +                                rec->u.catrec.name); +                    break; +                default: +                    printf("Unknown catalog entry %d %d '%s' %d\n", rec->type, +                           *ptype, rec->u.catrec.name, (char *)ptype - (char *)Hkey); +                    continue; +                } +                break; +            case RECORD_EXT: +                /* TODO */ +                HFS_DPRINTF("Extent file entry\n"); +                continue; +            default: +                HFS_ERROR("Unknown entry\n"); +                continue; +            } +            break; +        case HFS_NODE_IDX: +            rec->type = RECORD_IDX; +            rec->u.idxrec.uid = *upID; +            if (is_hfs) { +                rec->u.idxrec.pid = Hkey->pID; +                memcpy(rec->u.idxrec.name, Hkey->name, Hkey->nlen); +                rec->u.idxrec.name[Hkey->nlen] = '\0'; +                HFS_DPRINTF("HFS IDX record %d parent: %08x up: %08x name '%s'\n", +                            i + 1, rec->u.idxrec.pid, rec->u.idxrec.uid, +                            rec->u.idxrec.name); +                HFS_DPRINTF("uidp : %d %d\n", (char *)upID - (char *)Hkey, +                            (char *)(Hkey + 1) - (char *)Hkey); +            } else { +                rec->u.idxrec.pid = HPkey->pID; +                hfs_get_str(rec->u.idxrec.name, +                            HPkey->nlen, HPkey->uniname); +                HFS_DPRINTF("HFSplus IDX record %d parent: %08x up: %08x " +                            "name '%s'\n", i + 1, rec->u.idxrec.pid, +                            rec->u.idxrec.uid, rec->u.idxrec.name); +            } +            break; +        case HFS_NODE_HEAD: +            Hhead = HFS_get_headrec(HFS_recp); +            rec->type = RECORD_HEAD; +            rec->u.headrec.rootnode = Hhead->rootnode; +            rec->u.headrec.firstleaf = Hhead->firstleaf; +            rec->u.headrec.lastleaf = Hhead->lastleaf; +            rec->u.headrec.nodesize = Hhead->nodesize; +            HFS_DPRINTF("Header record %d root: %08x first: %08x last: %08x " +                        "size: %08x\n", i + 1, rec->u.headrec.rootnode, +                        rec->u.headrec.firstleaf, rec->u.headrec.lastleaf, +                        rec->u.headrec.nodesize); +            node->nrecs = 1; +            goto out; +        case HFS_NODE_MAP: +            /* TODO */ +        default: +            continue; +        } +    } + + out: +    return node; +} + +static inline hfs_rec_t *hfs_rec_get (hfs_bnode_t *node, int nb) +{ +    if (nb < 1 || nb > (int)node->nrecs) { +        HFS_ERROR("nb: %d min: %d max: %d\n", nb, 1, node->nrecs); +        return NULL; +    } + +    return &node->recs[nb - 1]; +} + +static inline hfs_bnode_t *hfs_bnode_prev (hfs_bnode_t *cur) +{ +    if (cur->prev == 0x00000000) +        return NULL; + +    return hfs_bnode_get(cur->tree, cur->prev); +} + +static inline hfs_bnode_t *hfs_bnode_next (hfs_bnode_t *cur) +{ +    if (cur->next == 0x00000000) +        return NULL; + +    return hfs_bnode_get(cur->tree, cur->next); +} + +unused static hfs_rec_t *hfs_rec_prev (hfs_rec_t *cur) +{ +    hfs_bnode_t *curn; +    int num; + +    num = cur->num; +    curn = cur->node; +    if (num == 1) { +        curn = hfs_bnode_prev(curn); +        if (curn == NULL) +            return NULL; +        num = curn->nrecs + 1; +    } +     +    return hfs_rec_get(curn, num - 1); +} + +unused static hfs_rec_t *hfs_rec_next (hfs_rec_t *cur) +{ +    hfs_bnode_t *curn; +    int num; + +    num = cur->num; +    curn = cur->node; +    if (num == (int)curn->nrecs) { +        curn = hfs_bnode_next(curn); +        if (curn == NULL) +            return NULL; +        num = 1; +    } +     +    return hfs_rec_get(curn, num - 1); +} + +static int hfs_cat_compare (int type, HFS_cnid_t cnid, +                            const void *more, hfs_rec_t *rec, int rectype); + +/* Simplified Btree recurse function from Linux */ +static hfs_rec_t *hfs_rec_find (hfs_btree_t *tree, +                                HFS_cnid_t cnid, const char *name, int rectype) +{ +    hfs_bnode_t *curn; +    hfs_rec_t *cur; +    unsigned int i; +    int ret; + +    /* +     * This is an ugly scattering of #if, but it's wonderful for debugging +     * hfs_rec_find().  If you set this to 1, then the loop will traverse +     * and show all of the records in a node before descending the correct +     * record. +     */ +#define DEBUG_HFS_REC_FIND 0 +#if DEBUG_HFS_REC_FIND +    hfs_rec_t *idx_cur; +    unsigned int idx; +    int idx_ret; +#endif /* DEBUG_HFS_REC_FIND */ + +    HFS_DPRINTF("look for ID: %08x '%s'\n", cnid, name); +    cur = NULL; +    ret = -1; +    i = 0; +    for (curn = tree->root_node; curn != NULL;) { +#if DEBUG_HFS_REC_FIND +        idx = 0; +        idx_ret = 0; +        idx_cur = NULL; +#endif /* DEBUG_HFS_REC_FIND */ +        for (i = curn->nrecs; i != 0; i--) { +            cur = hfs_rec_get(curn, i); +            if (cur == NULL) { +                HFS_ERROR("Cannot get record %d\n", i); +                return NULL; +            } +            HFS_DPRINTF("Check record %d %d %p %p %p\n", i, cur->type, cur, +                        curn->tree->compare, &hfs_cat_compare); +            ret = (*curn->tree->compare)(cur->type, cnid, name, cur, rectype); +            HFS_DPRINTF("\t%u:%d\n", i, ret); +            if (ret >= 0) { +#if !DEBUG_HFS_REC_FIND +                break; +#else +                if (!idx) { +                    idx = i; +                    idx_ret = ret; +                    idx_cur = cur; +                } +#endif /* DEBUG_HFS_REC_FIND */ +            } +        } +#if DEBUG_HFS_REC_FIND +        if (idx) { +            i = idx; +            ret = idx_ret; +            cur = idx_cur; +        } +#endif /* DEBUG_HFS_REC_FIND */ +        HFS_DPRINTF("ret=%d HFS_NODE=%02x RECORD=%02x\n", +                    ret, curn->type, cur->type); +        if (i == 0 ||                          /* exhausted all the records */ +            curn->type == HFS_NODE_LEAF) {     /* Can't descend any lower */ +            break; +        } +        HFS_DPRINTF("Recurse to record: %d %08x => %08x\n", +                    i, cnid, cur->u.idxrec.uid); +        curn = hfs_bnode_get(curn->tree, cur->u.idxrec.uid); +    } +    if (ret != 0 || curn == NULL) { +        /* We won't find what we're looking for... */ +        HFS_DPRINTF("NOT FOUND\n"); +        return NULL; +    } +#if 0 +    if (ret != 0 && cur->u.catrec.ID != cnid) { +        HFS_ERROR("%d %d\n", cur->u.catrec.ID, cnid); +        return NULL; +    } +#endif +    HFS_DPRINTF("found %p %p %d %p\n", cur, curn, i, hfs_rec_get(curn, i)); +     +    return cur; +} + +static inline hfs_rec_t *hfs_get_dir (hfs_btree_t *tree, HFS_cnid_t cnid, +                                      const unsigned char *name) +{ +    return hfs_rec_find(tree, cnid, name, 1); +} + +static hfs_rec_t *hfs_get_dirfile (hfs_rec_t *dir, HFS_cnid_t cnid, +                                   const unsigned char *name, +                                   const unsigned char *info) +{ +    hfs_btree_t *tree; +    hfs_bnode_t *cur; +    hfs_rec_t *rec; +    hfs_catrec_t *frec; +    int idx; + +    cur = dir->node; +    tree = cur->tree; +    for (idx = dir->num + 1;; idx++) { +        if (idx > (int)cur->nrecs) { +            HFS_DPRINTF("Go to next node %08x\n", cur->next); +            cur = hfs_bnode_next(cur); +            if (cur == NULL) { +                HFS_ERROR("Node %08x not found\n", cur->next); +                break; +            } +            idx = 1; +        } +        rec = hfs_rec_get(cur, idx); +        if (rec == NULL) { +            HFS_ERROR("Cannot get record %d\n", idx); +            return NULL; +        } +        HFS_DPRINTF("Check record %d '%s' '%s' '%s' '%s'\n", +                   idx, rec->u.catrec.name, rec->u.catrec.finfo, name, info); +        if (rec->type == RECORD_IDX) { +            continue; +        } +        frec = &rec->u.catrec; +        if (frec->type != HFS_CAT_FILE && frec->type != HFS_CAT_FILETH && +            frec->type != HFSP_CAT_FILE && frec->type != HFSP_CAT_FILETH) +            continue; +        if (frec->pid != cnid) { +            HFS_ERROR("Out of directory %08x %08x\n", cnid, frec->pid); +            break; +        } +        if (info != NULL && memcmp(frec->finfo, info, strlen(info)) != 0) +            continue; +        /* Beware: HFS is case insensitive ! */ +        if (name != NULL && strcasecmp(frec->name, name) != 0) +            continue; +        return rec; +    } + +    return NULL; +} + +static hfs_btree_t *hfs_btree_open (hfs_fork_t *fork, int type, +                                    int (*compare)(int type, +                                                   HFS_cnid_t cnid, +                                                   const void *more, +                                                   hfs_rec_t *rec, +                                                   int rectype)) +{ +    hfs_bnode_t *node; +    hfs_rec_t *rec; +    hfs_headrec_t *head; +    hfs_btree_t *newt; +    uint32_t bloc; + +    bloc = hfs_get_bloc(fork, 0); +    if (bloc == (uint32_t)-1) +        return NULL; +    HFS_DPRINTF("Open btree: bloc=%08x\n", bloc); +    /* Allocate tree */ +    newt = malloc(sizeof(hfs_btree_t)); +    if (newt == NULL) +        return NULL; +    memset(newt, 0, sizeof(hfs_btree_t)); +    newt->file = fork; +    newt->cache = NULL; +    newt->type = type; +    newt->compare = compare; +    /* Get tree header */ +    HFS_DPRINTF("Get first node\n"); +    node = hfs_bnode_get(newt, 0); +    if (node == NULL) { +        HFS_ERROR("Cannot get tree head\n"); +        return NULL; +    } +    HFS_DPRINTF("Get first record\n"); +    rec = hfs_rec_get(node, 1); +    if (rec == NULL) { +        HFS_ERROR("Cannot get first record\n"); +        return NULL; +    } +    if (rec->type != RECORD_HEAD) { +        HFS_ERROR("Not an header record !\n"); +        return NULL; +    } +    head = &rec->u.headrec; +    newt->head_rec = rec; +    /* Get root node */ +    HFS_DPRINTF("Get root entry node: %08x\n", head->rootnode); +    newt->root_node = hfs_bnode_get(newt, head->rootnode); +    if (newt->root_node == NULL) +        return NULL; +    /* Get root directory record */ +    HFS_DPRINTF("Get root folder record\n"); +    newt->root_catrec = hfs_get_dir(newt, HFS_ROOT_FOLDER, ""); +    HFS_DPRINTF("Found root folder record: %p\n", newt->root_catrec); +    if (newt->root_catrec == NULL) +        return NULL; +     +    return newt; +} + +static int hfs_cat_compare (int type, HFS_cnid_t cnid, +                            const void *more, hfs_rec_t *rec, int rectype) +{ +    hfs_idxrec_t *idxrec; +    hfs_catrec_t *catrec; +    const unsigned char *name; +    HFS_cnid_t id; +    int ret; +     +    if (type == RECORD_IDX) { +        idxrec = &rec->u.idxrec; +        id = idxrec->pid; +        name = idxrec->name; +        catrec = NULL; +    } else { +        catrec = &rec->u.catrec; +        name = catrec->name; +        if (type != RECORD_IDX && +            (catrec->type == HFS_CAT_FOLDTH || +             catrec->type == HFS_CAT_FILETH || +             catrec->type == HFSP_CAT_FOLDTH || +             catrec->type == HFSP_CAT_FILETH)) { +            HFS_DPRINTF("CHECK FOLDER %08x %08x!\n", catrec->ID, catrec->pid); +            id = catrec->ID; +        } else { +            id = catrec->pid; +        } +    } +    HFS_DPRINTF("Compare cnid (%08x '%s') vs (%08x '%s') %08x %d\n", +                cnid, (char *)more, id, name, catrec->type, rectype); +     +    /* +     * Always diff Record_IDXs, but diff RECORDS_CATs iff they match the type +     * being looked for: THREAD vs NON-THREAD (rectype). +     */ +    ret = cnid - id; +     +    if (ret == 0 && type != RECORD_IDX) { +        /* out on a leaf - don't compare different types */ +        if (rectype && +            (catrec->type == HFS_CAT_FILE || +             catrec->type == HFS_CAT_FOLDER || +             catrec->type == HFSP_CAT_FILE || +             catrec->type == HFSP_CAT_FOLDER)) { +            /* looking for thread and this is a file/folder - keep looking */ +            ret = -1; +        } else if (!rectype && +                   (catrec->type == HFS_CAT_FILETH || +                    catrec->type == HFS_CAT_FOLDTH || +                    catrec->type == HFSP_CAT_FILETH || +                    catrec->type == HFSP_CAT_FOLDTH)) { +            /* looking for file/folder and this is a thread - keep looking */ +            ret = -1; +        } +    } + +    if (ret == 0 && +       /* Apparently there is still a match - further constrain it by +        * checking if the name matches.  Name matchs should be +        * skipped if we're looking for a thread and we've reached a +        * leaf record (that case will match solely on the record +        * type and the cnid which has already been done). +        */ +        (type == RECORD_IDX || +         (!rectype && +          (catrec->type == HFS_CAT_FILE || +           catrec->type == HFS_CAT_FOLDER || +           catrec->type == HFSP_CAT_FILE || +           catrec->type == HFSP_CAT_FOLDER)))) { +        /* HFS is case insensitive - HFSP *can* be case sensitive */ +        ret = strcasecmp(more, name); +    } +     +    HFS_DPRINTF("ret %d catrec %p catrec->type %08x\n", +                ret, catrec, catrec ? catrec->type : 0); +    return ret; +} + +static hfs_btree_t *hfs_cat_open (hfs_vol_t *volume) +{ +    HFS_DPRINTF("Open HFS catalog\n"); +    return hfs_btree_open(&volume->cat_file, RECORD_CAT, &hfs_cat_compare); +} + +unused static int hfs_ext_compare (unused int type, unused HFS_cnid_t cnid, +                                   unused const void *more, +                                   unused hfs_rec_t *rec) +{ +    /* TODO */ +    return -1; +} + +static hfs_btree_t *hfs_ext_open (unused hfs_vol_t *volume) +{ +    HFS_DPRINTF("Open HFS extents file\n"); +#if 0 +    return hfs_btree_open(&volume->ext_file, RECORD_EXT, &hfs_ext_compare); +#else +    return NULL; +#endif +} + +static void hfs_map_boot_file (part_t *part, hfs_vol_t *volume, +                               uint32_t *boot_start, uint32_t *boot_offset, +                               uint32_t *boot_size) +{ +    uint32_t bloc, size; + +    /* Now, patch the partition to register the boot file +     * XXX: we "know" that only one extent is used... +     *      this may not be true if booting from a hard drive... +     */ +    volume->boot_file->volume = volume; +    bloc = hfs_get_bloc(volume->boot_file, 0); +    if (bloc == (uint32_t)(-1)) { +        printf("Cannot get boot file start bloc\n"); +        return; +    } +    size = volume->boot_file->extents[0].count * volume->bsize; +    //    printf("Map boot file bloc 0 to %08x\n", bloc); +    part_set_boot_file(part, bloc, 0, size); +    *boot_start = bloc; +    *boot_size = size; +    *boot_offset = 0; +} + +static inode_t *fs_hfs_get_inode (inode_t *parent, const unsigned char *name) +{ +    inode_t *new; +    hfs_fork_t *pfile, *file; +    hfs_rec_t *catrec, *extrec; +    uint32_t size; +    int i; + +    pfile = parent->private; +    HFS_DPRINTF("Get inode '%s' %p %p %p %08x\n", name, pfile, pfile->catrec, +                pfile->catrec->node->tree, pfile->catrec->u.catrec.pid); +    catrec = hfs_rec_find(pfile->catrec->node->tree, +                          pfile->catrec->u.catrec.ID, name, 0); +#if 0 +    extrec = hfs_rec_find(pfile->extrec->node->tree, +                          pfile->extrec->u.extrec.pid, name, 0); +#else +    extrec = NULL; +#endif +    if (catrec == NULL /* || extrec == NULL */) +        return NULL; +    new = malloc(sizeof(inode_t)); +    if (new == NULL) +        return NULL; +    memset(new, 0, sizeof(inode_t)); +    new->flags = 0; +    file = &catrec->u.catrec.fork; +    new->private = file; +    size = 0; +    for (i = 0; i < 8; i++) { +        if (file->extents[i].count == 0) +            break; +        size += file->extents[i].count; +    } +    size *= file->volume->bsize; +    new->size.bloc = size; +    new->size.offset = 0; +    HFS_DPRINTF("File: '%s'\n", name); +    hfs_dump_fork(new->private);  +    +    return new; +} + +static void fs_hfs_put_inode (unused inode_t *inode) +{ +} + +static uint32_t fs_hfs_map_bloc (inode_t *inode, uint32_t bloc) +{ +    return hfs_get_bloc(inode->private, bloc); +} + +static inode_t *fs_hfs_get_special_inode (fs_t *fs, int type) +{ +    hfs_vol_t *volume; +    inode_t *bfile, *bdir, *cur; +    hfs_rec_t *drec, *rec; +    hfs_fork_t *fork; +    uint32_t boot_start, boot_size, boot_offset; +    HFS_cnid_t id; + +    volume = fs->private; +    switch (type) { +    case FILE_ROOT: +        if (fs->root == NULL) { +            volume->cat_tree = hfs_cat_open(volume); +            volume->ext_tree = hfs_ext_open(volume); +            if (volume->cat_tree == NULL /*|| volume->ext_tree == NULL*/) { +                HFS_ERROR("Can't open volume catalog/extent files\n"); +                return NULL; +            } +            cur = malloc(sizeof(inode_t)); +            if (cur == NULL) +                return NULL; +            memset(cur, 0, sizeof(inode_t)); +            cur->flags = INODE_TYPE_DIR; +            cur->private = &volume->cat_tree->root_catrec->u.catrec.fork; +            cur->parent = NULL; +        } else { +            cur = fs->root; +        } +        return cur; +    case FILE_BOOT: +        if (fs->bootfile != NULL) +            return fs->bootfile; +        break; +    case FILE_BOOTDIR: +        if (fs->bootdir != NULL) +            return fs->bootdir; +        if (volume->boot_file != NULL) { +            bfile = malloc(sizeof(inode_t)); +            if (bfile == NULL) +                return NULL; +            memset(bfile, 0, sizeof(inode_t)); +            fs->bootfile = bfile; +            rec = volume->boot_file->catrec; +            bfile->name = strdup(rec->u.catrec.name); +            if (bfile->name == NULL) { +                free(bfile); +                fs->bootfile = NULL; +                return NULL; +            } +            bfile->private = volume->boot_file; +            bfile->flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT; +            fs->bootdir = fs->root; +            hfs_map_boot_file(fs->part, volume, +                              &boot_start, &boot_offset, &boot_size); +        } +        break; +    default: +        return NULL; +    } +    HFS_DPRINTF("Look for boot file (%d)\n", volume->boot_id); +    if (volume->boot_file == NULL || +        volume->boot_file->extents[0].count == 0) { +        if (volume->boot_id != 0x00000000) { +            /* Try to find regular MacOS bootfile */ +            drec = hfs_get_dir(volume->cat_tree, volume->boot_id, ""); +            if (drec == NULL) { +                HFS_ERROR("Didn't find boot directory %d\n", volume->boot_id); +                return NULL; +            } +            HFS_DPRINTF("Found boot directory '%s'\n", drec->u.catrec.name); +            rec = hfs_get_dirfile(drec, volume->boot_id, NULL, "tbxi"); +        } else { +            /* Try NetBSD boot */ +            drec = hfs_get_dir(volume->cat_tree, HFS_ROOT_FOLDER, ""); +            if (drec == NULL) +                return NULL; +            rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER, "ofwboot", NULL); +            if (rec == NULL) { +                rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER, +                                      "ofwboot.xcf", NULL); +                if (rec == NULL) { +                    rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER, +                                          "ofwboot.elf", NULL); +                } +            } +            if (rec != NULL) { +                volume->boot_id = rec->u.catrec.pid; +                drec = hfs_get_dir(volume->cat_tree, volume->boot_id, ""); +            } +        } +        if (rec == NULL) { +            HFS_ERROR("Didn't find boot file\n"); +            return NULL; +        } +        volume->boot_file = &rec->u.catrec.fork; +        hfs_map_boot_file(fs->part, volume, +                          &boot_start, &boot_offset, &boot_size); +        HFS_DPRINTF("boot file mapped: %08x-%08x %08x\n", +                    boot_start, boot_offset, boot_size); +#if 0 +        hfs_treat_boot_file(fs->part, volume, +                            &boot_start, &boot_offset, &boot_size); +#endif +        HFS_DPRINTF("Dump boot file\n"); +        hfs_dump_fork(volume->boot_file); +        HFS_DPRINTF("boot file mapped: %08x-%08x %08x\n", +                    boot_start, boot_offset, boot_size); +    } else { +        drec = hfs_get_dir(volume->cat_tree, HFS_ROOT_FOLDER, ""); +        if (drec == NULL) +            return NULL; +    } +    rec = volume->boot_file->catrec; +    fork = volume->boot_file; +    HFS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n", +                rec, rec->u.catrec.name, drec, drec->u.catrec.name); +    bfile = malloc(sizeof(inode_t)); +    if (bfile == NULL) +        return NULL; +    memset(bfile, 0, sizeof(inode_t)); +    fs->bootfile = bfile; +    bfile->name = strdup(rec->u.catrec.name); +    if (bfile->name == NULL) { +        free(bfile); +        return NULL; +    } +    bfile->private = fork; +    bfile->flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT; +    bfile->size.bloc = boot_size / part_blocsize(volume->part); +    bfile->size.offset = boot_size % part_blocsize(volume->part); +    HFS_DPRINTF("%s: look for parent ID: %08x\n", __func__, volume->boot_id); +    bdir = NULL; +    cur = NULL; +    if (type == FILE_BOOT) { +        cur = bfile; +    } +    for (id = volume->boot_id; id != HFS_ROOT_FOLDER; +         id = drec->u.catrec.pid) { +        drec = hfs_get_dir(volume->cat_tree, id, ""); +        if (drec == NULL) +            return NULL; +        bdir = malloc(sizeof(inode_t)); +        if (bdir == NULL) +            return NULL; +        memset(bdir, 0, sizeof(inode_t)); +        if (id == volume->boot_id) { +            if (type == FILE_BOOTDIR) +                cur = bdir; +            fs->bootdir = bdir; +        } +        bdir->name = strdup(drec->u.catrec.name); +        if (bdir->name == NULL) { +            free(bdir); +            return NULL; +        } +        bdir->private = &drec->u.catrec.fork; +        bdir->flags = INODE_TYPE_DIR; +        bfile->parent = bdir; +        HFS_DPRINTF("%s: cache '%s' into '%s'\n", +                    __func__, bfile->name, bdir->name); +        fs_cache_add_inode(bdir, bfile); +        bfile = bdir; +    } +    bfile->parent = fs->root; +    HFS_DPRINTF("%s: cache '%s' into root dir\n", __func__, bfile->name); +    fs_cache_add_inode(fs->root, bfile); +    if (bdir == NULL) { +        bdir = fs->root; +        fs->bootdir = bdir; +        if (type == FILE_BOOTDIR) +            cur = bdir; +    } +    cur->fs = fs; +    HFS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n", +                fs->bootfile, fs->bootfile->name, +                fs->bootdir, fs->bootdir->name); +    HFS_DPRINTF("boot fork %p rec %p %p %08x\n", +                bfile->private, rec, rec->u.catrec.fork.catrec, +                rec->u.catrec.ID); +    HFS_DPRINTF("boot dir fork %p rec %p %p %08x %08x\n", +                bdir->private, drec, drec->u.catrec.fork.catrec, +                drec->u.catrec.ID, volume->boot_id); +    HFS_DPRINTF("FS cat tree: %p\n", volume->cat_tree); + +    return cur; +} + +static fs_ops_t hfs_fs_ops = { +    &fs_hfs_get_inode, +    &fs_hfs_put_inode, +    &fs_hfs_map_bloc, +    &fs_hfs_get_special_inode, +}; + +int fs_hfs_probe (part_t *part, uint32_t *size, +                  fs_ops_t **fs_ops, unsigned char **name, +                  void **private) +{ +    unsigned char buffer[512]; +    HFSP_vh_t *hfsp_vh; +    HFS_vh_t *hfs_vh; +    hfs_vol_t *volume; +    uint32_t embed_offset = 0, boot_id; +    int type; + +    hfs_vh = HFS_read_volhead(part, HFS_VOLHEAD_SECTOR, 0, buffer, 512); +    hfsp_vh = NULL; +    if (hfs_vh == NULL) { +        DPRINTF("Can't read HFS volume header\n"); +        return -1; +    } +    type = -1; +    if (hfs_vh->signature == HFS_VOLHEAD_SIG) { +        /* HFS volume */ +        printf("HFS volume\n"); +        if (hfs_vh->embed_sig == HFSPLUS_VOLHEAD_SIG) { +            embed_offset = hfs_vh->embed_ext.start_block * +                hfs_vh->alloc_size / HFS_SECTOR_SIZE; +            embed_offset += hfs_vh->alloc_start; +            printf("HFSplus embedded volume offset=%08x\n", embed_offset); +            hfsp_vh = HFSP_read_volhead(part, +                                        HFS_VOLHEAD_SECTOR + embed_offset, +                                        0, buffer, 512); +            goto handle_hfsp; +        } +        boot_id = hfs_vh->finder_info[0]; +        DPRINTF("HFS boot id : %d %04x\n", boot_id, boot_id); +        volume = malloc(sizeof(hfs_vol_t)); +        if (volume == NULL) +            return -1; +        memset(volume, 0, sizeof(hfs_vol_t)); +        HFS_DPRINTF("sig: %x %x %x\n", hfs_vh->signature, +                    hfs_vh->embed_sig, HFSPLUS_VOLHEAD_SIG); +        HFS_DPRINTF("cr: %08x mod: %08x attr: %04x count: %04x\n", +                    hfs_vh->create_date, hfs_vh->modify_date, +                    hfs_vh->attributes, hfs_vh->root_file_count); +        HFS_DPRINTF("alloc ptr: %04x blocs: %04x size: %08x bmap %04x\n", +                    hfs_vh->alloc_ptr, hfs_vh->alloc_blocs, hfs_vh->alloc_size, +                    hfs_vh->bitmap_start); +        volume->bsize = hfs_vh->alloc_size / HFS_SECTOR_SIZE; +        volume->start_offset = hfs_vh->alloc_start; +        /* Alloc file */ +        volume->alloc_file.volume = volume; +        volume->alloc_file.nb_blocs = hfs_vh->alloc_size * volume->bsize; +        volume->alloc_file.extents[0].start = 0; +        volume->alloc_file.extents[0].count = hfs_vh->alloc_size; +        /* Catalog file */ +        volume->cat_file.volume = volume; +        hfs_get_fork(&volume->cat_file, hfs_vh->cat_size, hfs_vh->cat_rec); +        /* Extents file */ +        volume->ext_file.volume = volume; +        hfs_get_fork(&volume->ext_file, hfs_vh->ext_size, hfs_vh->ext_rec); +        *size = hfs_vh->alloc_blocs * volume->bsize; +        *name = strdup(hfs_vh->label); +        if (*name == NULL) +            return -1; +        type = FS_TYPE_HFS; +    } else { +        hfsp_vh = HFSP_read_volhead(part, HFS_VOLHEAD_SECTOR, 0, buffer, 512); +    handle_hfsp: +        if (hfsp_vh == NULL) { +            DPRINTF("Can't read HFS+ volume header\n"); +            return -1; +        } +        if (hfsp_vh->signature != HFSPLUS_VOLHEAD_SIG) { +            DPRINTF("Bad HFS+ signature %02x %02x\n", +                    hfsp_vh->signature, HFSPLUS_VOLHEAD_SIG); +            return -1; +        } +        /* HFS+ volume */ +        printf("HFSplus volume\n"); +        volume = malloc(sizeof(hfs_vol_t)); +        if (volume == NULL) +            return -1; +        memset(volume, 0, sizeof(hfs_vol_t)); +        volume->embed_offset = embed_offset; +        volume->start_offset = embed_offset; +        volume->bsize = hfsp_vh->blocksize / HFS_SECTOR_SIZE; +        //        volume->bsize = 2048; +        /* Boot file */ +        HFS_DPRINTF("Boot file: %d %d\n", +                    hfsp_vh->start_file.total_blocks, +                    hfsp_vh->start_file.extents[0].block_count); +        if (hfsp_vh->start_file.total_blocks != 0) { +            volume->boot_file = malloc(sizeof(hfs_fork_t)); +            memset(volume->boot_file, 0, sizeof(hfs_fork_t)); +            volume->boot_file->volume = volume; +            hfsp_get_fork(volume->boot_file, +                          hfsp_vh->start_file.total_blocks, +                          hfsp_vh->start_file.extents); +            boot_id = 2; +        } else { +            boot_id = hfsp_vh->finder_info[0]; +        } +            DPRINTF("HFS+ boot id : %d %04x %d\n", boot_id, boot_id, +                    hfsp_vh->start_file.total_blocks); +        /* Catalog file */ +        volume->cat_file.volume = volume; +        hfsp_get_fork(&volume->cat_file, +                      hfsp_vh->cat_file.total_blocks, +                      hfsp_vh->cat_file.extents); +        /* Extents file */ +        volume->ext_file.volume = volume; +        hfsp_get_fork(&volume->ext_file, +                      hfsp_vh->ext_file.total_blocks, +                      hfsp_vh->ext_file.extents); +        *size = hfsp_vh->total_blocks * volume->bsize; +        type = FS_TYPE_HFSP; +    } +    volume->boot_id = boot_id; +    volume->type = type; +    HFS_DPRINTF("%s volume: type: %d bsize: %d start_offset: %d\n", +                type == FS_TYPE_HFS ? "HFS" : "HFSplus", +                volume->type, volume->bsize, volume->start_offset); +    HFS_DPRINTF("Catalog file:\n"); +    hfs_dump_fork(&volume->cat_file); +    HFS_DPRINTF("Extents file:\n"); +    hfs_dump_fork(&volume->ext_file); +    if (volume->boot_file != NULL) { +        HFS_DPRINTF("Boot file:\n"); +        hfs_dump_fork(volume->boot_file); +    } +    *fs_ops = &hfs_fs_ops; +    HFS_DPRINTF("Set part to %p\n", part); +    volume->part = part; +    *private = volume; + +    return type; +} diff --git a/roms/openhackware/src/libfs/isofs.c b/roms/openhackware/src/libfs/isofs.c new file mode 100644 index 00000000..0e09094e --- /dev/null +++ b/roms/openhackware/src/libfs/isofs.c @@ -0,0 +1,32 @@ +/* + * <isofs.c> + * + * Open Hack'Ware BIOS ISO file system management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include "bios.h" +#include "libfs.h" + +/* ISOFS filesystem */ +int fs_isofs_probe (unused part_t *part, unused uint32_t *size, +                    unused fs_ops_t **fs_ops, unused unsigned char **name, +                    unused void **private) +{ +    return -1; +} diff --git a/roms/openhackware/src/libfs/libfs.h b/roms/openhackware/src/libfs/libfs.h new file mode 100644 index 00000000..1c05bcbb --- /dev/null +++ b/roms/openhackware/src/libfs/libfs.h @@ -0,0 +1,129 @@ +/* + * <libfs.h> + * + * Open Hack'Ware BIOS: file system library definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined(__OHW_LIBFS_H__) +#define __OHW_LIBFS_H__ + +//#define DEBUG_FS 1 +#define FS_SPECIAL "<special>" + +static inline int is_special_file (const unsigned char *name) +{ +    int splen = strlen(FS_SPECIAL); + +    return name[0] == '\0' && memcmp(name + 1, FS_SPECIAL, splen) == 0 && +        name[splen + 1] == '\0'; +} + +#if defined (DEBUG_FS) +#define FS_DPRINTF(fmt, args...) \ +do { dprintf("%s: " fmt, __func__ , ##args); } while (0) +#else +#define FS_DPRINTF(fmt, args...) \ +do { } while (0) +#endif +#define FS_ERROR(fmt, args...) \ +do { printf("ERROR in %s: " fmt, __func__ , ##args); } while (0) + +typedef struct fs_ops_t { +    inode_t *(*get_inode)(inode_t *parent, const unsigned char *name); +    void (*put_inode)(inode_t *inode); +    uint32_t (*map_bloc)(inode_t *inode, uint32_t bloc); +    inode_t *(*get_special_inode)(fs_t *fs, int type); +} fs_ops_t; + +#define MAXNAME_LEN 1024 + +struct fs_t { +    int type; +    part_t *part; +    inode_t *root; +    fs_ops_t *fs_ops; +    uint32_t size; +    unsigned char *name; +    inode_t *bootfile; +    inode_t *bootdir; +    void *private; +}; + +struct dir_t { +    inode_t *inode; +    dirent_t *cur; +    int pos; +}; + +/* All internals use inodes */ +struct inode_t { +    fs_t *fs; +    /* parent inode */ +    inode_t *parent; +    /* Next inode at the same level */ +    inode_t *next; +    /* First child inode */ +    inode_t *child; +    /* Private data */ +    int refcount; +    uint32_t flags; +    unsigned char *name; +    int nb_blocs; +    pos_t *blocs; +    pos_t size; +    void *private; +    uint32_t vbloc; +    uint32_t vpos; +}; + +/* Low-level helpers */ +enum { +    FILE_UNKNOWN = -1, +    FILE_ROOT    = 0, +    FILE_BOOT, +    FILE_BOOTDIR, +}; + +void fs_cache_add_inode (inode_t *parent, inode_t *inode); + +int fs_raw_probe (part_t *part, uint32_t *size, +                  fs_ops_t **fs_ops, unsigned char **name, +                  void **private); +int fs_ext2_probe (part_t *part, uint32_t *size, +                   fs_ops_t **fs_ops, unsigned char **name, +                   void **private); +int fs_isofs_probe (part_t *part, uint32_t *size, +                    fs_ops_t **fs_ops, unsigned char **name, +                    void **private); +int fs_hfs_probe (part_t *part, uint32_t *size, +                  fs_ops_t **fs_ops, unsigned char **name, +                  void **private); +int fs_raw_set_bootfile (part_t *part, +                         uint32_t start_bloc, uint32_t start_offset, +                         uint32_t size_bloc, uint32_t size_offset); + +enum { +    FS_TYPE_UNKNOWN = -1, +    FS_TYPE_RAW     = 0, +    FS_TYPE_EXT2, +    FS_TYPE_ISOFS, +    FS_TYPE_HFS, +    FS_TYPE_HFSP, +}; + +#endif /* !defined(__OHW_LIBFS_H__) */ diff --git a/roms/openhackware/src/libfs/raw.c b/roms/openhackware/src/libfs/raw.c new file mode 100644 index 00000000..9ecd23ad --- /dev/null +++ b/roms/openhackware/src/libfs/raw.c @@ -0,0 +1,178 @@ +/* + * <raw.c> + * + * Open Hack'Ware BIOS raw file system management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "../libpart/libpart.h" +#include "libfs.h" + +/* Raw filesystem (ie no filesystem) */ +static inode_t *fs_raw_get_inode (inode_t *parent, const unsigned char *name) +{ +    inode_t *new; +    fs_t *fs; +    int flags; + +    if (parent != NULL) { +        return NULL; +    } +    /* Open root inode */ +    flags = INODE_TYPE_DIR; +    fs = NULL; +    new = malloc(sizeof(inode_t)); +    memset(new, 0, sizeof(inode_t)); +    new->flags = flags; +    new->name = strdup(name); + +    return new; +} + +static void fs_raw_put_inode (inode_t *inode) +{ +    free(inode); +} + +static uint32_t fs_raw_map_bloc (unused inode_t *inode, uint32_t bloc) +{ +    if (inode != NULL +        /* XXX: can't figure out why I did this... */ +        /* && inode == inode->fs->bootfile*/ +        ) +         bloc += inode->blocs[0].bloc; + +    return bloc; +} + +static inode_t *fs_raw_get_special_inode (fs_t *fs, int type) +{ +    const unsigned char *name; +    inode_t *new, *parent, **inp; +    int flags; + +    new = NULL; +    name = NULL; +    parent = NULL; +    inp = NULL; +    flags = 0; +    switch (type) { +    case FILE_ROOT: +        if (fs->root != NULL) { +            new = fs->root; +        } else { +            flags = INODE_TYPE_DIR; +            parent = NULL; +            name = NULL; +            inp = &fs->root; +        } +        break; +    case FILE_BOOT: +        if (fs->bootfile != NULL) { +            dprintf("bootfile already exists\n"); +            new = fs->bootfile; +        } else { +            new = part_private_get(fs_part(fs)); +            if (fs->bootdir == NULL) { +                dprintf("Get boot directory\n"); +                fs->bootdir = fs_raw_get_special_inode(fs, FILE_BOOTDIR); +            } +            parent = fs->bootdir; +            if (new != NULL) { +                dprintf("Fix bootfile\n"); +                new->parent = parent; +                new->fs = fs; +            } else { +                dprintf("New bootfile\n"); +                flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT; +                name = "ofwboot"; +                inp = &fs->bootfile; +            } +        } +        break; +    case FILE_BOOTDIR: +        if (fs->bootdir != NULL) { +            new = fs->bootdir; +        } else { +            flags = INODE_TYPE_DIR; +            parent = fs->root; +            name = "boot"; +            inp = &fs->bootdir; +        } +        break; +    default: +        return NULL; +    } +    if (new == NULL) { +        new = malloc(sizeof(inode_t)); +        memset(new, 0, sizeof(inode_t)); +        new->flags = flags; +        new->parent = parent; +        if (name != NULL) +            new->name = strdup(name); +        new->fs = fs; +        *inp = new; +    } +     +    return new; +} + +static fs_ops_t fs_ops_raw = { +    &fs_raw_get_inode, +    &fs_raw_put_inode, +    &fs_raw_map_bloc, +    &fs_raw_get_special_inode, +}; + +int fs_raw_set_bootfile (part_t *part, +                         uint32_t start_bloc, uint32_t start_offset, +                         uint32_t size_bloc, uint32_t size_offset) +{ +    inode_t *new; + +    new = malloc(sizeof(inode_t)); +    if (new == NULL) +        return -1; +    DPRINTF("%s: pos %d %d size %d %d\n", __func__, start_bloc, start_offset, +            size_bloc, size_offset); +    memset(new, 0, sizeof(inode_t)); +    new->flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT; +    new->name = "ofwboot"; +    new->blocs[0].bloc = start_bloc; +    new->blocs[0].offset = start_offset; +    new->size.bloc = size_bloc; +    new->size.offset = size_offset; +    new->nb_blocs = size_bloc; +    part_private_set(part, new); + +    return 0; +} + +int fs_raw_probe (part_t *part, uint32_t *size, +                  fs_ops_t **fs_ops, unsigned char **name, +                  unused void **private) +{ +    DPRINTF("%s: %p map_bloc %p\n", __func__, &fs_ops_raw, &fs_raw_map_bloc); +    *fs_ops = &fs_ops_raw; +    *name = "Raw FS"; +    *size = part_size(part); + +    return FS_TYPE_RAW; +} diff --git a/roms/openhackware/src/libpart/apple.c b/roms/openhackware/src/libpart/apple.c new file mode 100644 index 00000000..1d72f67d --- /dev/null +++ b/roms/openhackware/src/libpart/apple.c @@ -0,0 +1,314 @@ +/* + * <apple.c> + * + * Open Hack'Ware BIOS Apple partition type management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "libpart.h" + +/* Apple partitions handler */ +#define HFS_BLOCSIZE (512) + +typedef struct Mac_head_t Mac_head_t; +struct Mac_head_t { +    /* 0x000 */ +    uint8_t signature[2]; +    uint16_t bloc_size; +    uint32_t bloc_count; +    /* 0x008 */ +    uint16_t dev_type; +    uint16_t dev_ID; +    uint32_t data; +    /* 0x010 */ +    uint16_t driver_cnt; +    uint8_t pad[428]; +    /* 0x01BE */ +    uint8_t part_table[0x40]; +    /* 0x1FE */ +    uint8_t magic[2]; +    /* 0x0200 */ +} __attribute__ ((packed)); + +typedef struct Mac_driver_entry_t Mac_driver_entry_t; +struct Mac_driver_entry_t { +    uint32_t start; +    uint16_t size; +    uint16_t type; +} __attribute__ ((packed)); + +typedef enum Mac_partflags_t Mac_partflags_t; +enum Mac_partflags_t { +    MACPART_SPEC2     = 0x0100, +    MACPART_SPEC1     = 0x0080, +    MACPART_PIC       = 0x0040, +    MACPART_WRITABLE  = 0x0020, +    MACPART_READABLE  = 0x0010, +    MACPART_BOOTABLE  = 0x0008, +    MACPART_INUSE     = 0x0004, +    MACPART_ALLOCATED = 0x0002, +    MACPART_VALID     = 0x0001, +}; + +#define MAC_BOOTABLE_PART (MACPART_VALID | MACPART_INUSE | MACPART_BOOTABLE) + +typedef struct Mac_partmap_t Mac_partmap_t; +struct Mac_partmap_t { +    /* 0x000 */ +    uint8_t signature[2]; +    uint8_t res0[2]; +    uint32_t map_cnt; +    /* 0x008 */ +    uint32_t start_bloc; +    uint32_t bloc_cnt; +    /* 0x010 */ +    uint8_t name[32]; +    /* 0x030 */ +    uint8_t type[32]; +    /* 0x050 */ +    uint32_t data_start; +    uint32_t data_cnt; +    /* 0x058 */ +    uint32_t flags; +    uint32_t boot_start; +    /* 0x060 */ +    uint32_t boot_size; +    uint32_t boot_load; +    /* 0x068 */ +    uint32_t boot_load2; +    uint32_t boot_entry; +    /* 0x070 */ +    uint32_t boot_entry2; +    uint32_t boot_csum; +    /* 0x078 */ +    uint8_t CPU[16]; +    /* 0x088 */ +    uint8_t boot_args[0x80]; +    /* 0x108 */ +    uint8_t pad0[0xC8]; +    /* 0x1D4  */ +    uint16_t ntype; +    uint8_t ff[2]; +    /* 0x1D8 */ +    uint8_t pad1[0x24]; +    /* 0x1FC */ +    uint8_t mark[4]; +    /* 0x200 */ +} __attribute__ ((packed)); + +int fs_raw_set_bootfile (part_t *part, +                         uint32_t start_bloc, uint32_t start_offset, +                         uint32_t size_bloc, uint32_t size_offset); + +part_t *Apple_probe_partitions (bloc_device_t *bd) +{ +    unsigned char tmp[33], *name; +    Mac_head_t *head; +    Mac_partmap_t *partmap; +    part_t *part, *boot_part; +    unsigned char *type; +    uint8_t *buffer; +    uint32_t pos, bloc, start, count; +    uint32_t bloc_size, flags; +    int map_count, i, n, len; + +    part = NULL; +    boot_part = NULL; +    n = 1; +    buffer = malloc(HFS_BLOCSIZE); +    /* Read first sector */ +    bd_seek(bd, 0, 0); +    if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) { +        ERROR("Unable to read boot sector from boot device. Aborting...\n"); +        goto error; +    } +    head = (Mac_head_t *)buffer; +    if (head->signature[0] != 'E' || head->signature[1] != 'R') { +        //        MSG("\rNo Apple boot bloc signature...\n"); +        goto error; +    } +    MSG("\rFound Apple partition map...\n"); +    bloc = 0; +    bloc_size = bd_seclen(bd); +    map_count = 1; +#if 0 +    if (head->magic[0] == 0x55 && head->magic[1] == 0xAA) { +        /* PREP boot image ! Must parse it as MS-DOS boot bloc */ +        ERROR("%s PREP head magic\n", __func__); +        goto error; +    } +#endif +    /* Partition table starts in sector 1 */ +    for (i = 1; i < (map_count + 1); i++) { +        bloc = (i * HFS_BLOCSIZE) / bloc_size; +        pos = (i * HFS_BLOCSIZE) % bloc_size; +        DPRINTF("Check part %d of %d (%d %d %d)\n", +                i, map_count, bloc, pos, bloc_size); +        bd_seek(bd, bloc, pos); +        if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) { +            ERROR("%s sector_read failed (%d)\n", __func__, i); +            goto error; +        } +        partmap = (Mac_partmap_t *)buffer; +        if (partmap->signature[0] != 'P' || partmap->signature[1] != 'M' ) { +            ERROR("%s bad partition signature (%c %c)\n", +                  __func__, partmap->signature[0], partmap->signature[1]); +            goto error; +        } +        /* We found at least one Apple partition map, +         * so we won't have to try to parse with other partition mappings. +         */ +        for (type = partmap->type; (type - partmap->type) < 32; type++) { +            if (*type != '\0') +                break; +        } +        if (partmap->name[0] == '\0') { +            sprintf(tmp, "part%d", i); +            name = tmp; +        } else { +            name = partmap->name; +        } +        /* Regular Apple partition */ +        part = malloc(sizeof(part_t)); +        if (part == NULL) { +            ERROR("%s: can't allocate partition\n", __func__); +            return NULL; +        } +        memset(part, 0, sizeof(part_t)); +        part->start = partmap->start_bloc; +        part->size = partmap->bloc_cnt; +        part_set_blocsize(bd, part, HFS_BLOCSIZE); +        len = 32 - (type - partmap->type); +        if (len == 0) { +            /* Place holder. Skip it */ +            DPRINTF("%s placeholder part\t%d\n", __func__, i); +            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +            part_register(bd, part, name, i); +        } else if (strncmp("Apple_Void", type, 32) == 0) { +            /* Void partition. Skip it */ +            DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type); +            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +            part_register(bd, part, name, i); +        } else if (strncmp("Apple_Free", type, 32) == 0) { +            /* Free space. Skip it */ +            DPRINTF("%s Free part (%d)\n", __func__, i); +            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +            part_register(bd, part, name, i); +        } else if (strncmp("Apple_partition_map", type, 32) == 0 || +                   strncmp("Apple_Partition_Map", type, 32) == 0 +#if 0 // Is this really used or is it just a mistake ? +                || strncmp("Apple_patition_map", type, 32) == 0 +#endif +                   ) { +            DPRINTF("%s Partition map\t%d [%s]\n", __func__, i, type); +            /* We are in the partition map descriptor */ +            if (i == 1) { +                /* Get the real map blocs count */ +                map_count = partmap->map_cnt; +                DPRINTF("%s: map_count: %d\n", __func__, map_count); +            } else { +                /* Don't about about secondary partition map +                 * Seems to be used, at least on CDROMs, to describe +                 * the same partition map with bloc_size = 2048 +                 */ +            } +            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +            part_register(bd, part, name, i); +        } else if (strncmp("Apple_Driver", type, 32) == 0 || +                   strncmp("Apple_Driver43", type, 32) == 0 || +                   strncmp("Apple_Driver43_CD", type, 32) == 0 || +                   strncmp("Apple_Driver_ATA", type, 32) == 0 || +                   strncmp("Apple_Driver_ATAPI", type, 32) == 0 || +                   strncmp("Apple_FWDriver", type, 32) == 0 || +                   strncmp("Apple_Driver_IOKit", type, 32) == 0) { +            /* Drivers. don't care for now */ +            DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type); +            part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER; +            part_register(bd, part, name, i); +        } else if (strncmp("Apple_Patches", type, 32) == 0) { +            /* Patches: don't care for now */ +            part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH; +            part_register(bd, part, name, i); +            DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type); +        } else if (strncmp("Apple_HFS", type, 32) == 0 || +                   strncmp("Apple_MFS", type, 32) == 0 || +                   strncmp("Apple_UFS", type, 32) == 0 || +                   strncmp("Apple_PRODOS", type, 32) == 0 || +                   strncmp("Apple_UNIX_SVR2", type, 32) == 0 || +                   strncmp("Linux", type, 32) == 0 || +                   strncmp("NetBSD/macppc", type, 32) == 0 || +                   strncmp("Apple_boot", type, 32) == 0 || +                   strncmp("Apple_bootstrap", type, 32) == 0 || +                   strncmp("Apple_Bootstrap", type, 32) == 0) { +            DPRINTF("%s Fs part\t%d [%s]\n", __func__, i, type); +            /* Filesystems / boot partitions */ +            flags = partmap->flags; +            start = partmap->start_bloc * HFS_BLOCSIZE; +            count = partmap->bloc_cnt * HFS_BLOCSIZE; +            if (partmap->boot_size == 0 || partmap->boot_load == 0) { +                printf("Not a bootable partition %d %d (%p %p)\n", +                       partmap->boot_size, partmap->boot_load, +                       boot_part, part); +                part->flags = PART_TYPE_APPLE | PART_FLAG_FS; +            } else { +                part->boot_start.bloc = partmap->boot_start; +                part->boot_start.offset = 0; +                part->boot_size.bloc = partmap->boot_size / HFS_BLOCSIZE; +#if 0 +                printf("%0x %0x %0x\n", partmap->boot_size, HFS_BLOCSIZE, +                       part->boot_size.bloc); +#endif +                part->boot_size.offset = (partmap->boot_size) % HFS_BLOCSIZE; +                part->boot_load = partmap->boot_load; +                part->boot_entry = partmap->boot_entry; +                fs_raw_set_bootfile(part, part->boot_start.bloc, +                                    part->boot_start.offset, +                                    part->boot_size.bloc, +                                    part->boot_size.offset); +                boot_part = part; +                part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT; +            } +            printf("Partition: %d '%s' '%s' st %0x size %0x", +                    i, name, type, partmap->start_bloc, partmap->bloc_cnt); +#ifndef DEBUG +            printf("\n"); +#endif +            DPRINTF(" - %0x %0x %p %p\n", +                    partmap->boot_start, partmap->boot_size, part, part->fs); +            DPRINTF("    boot %0x %0x load %0x entry %0x\n", +                    part->boot_start.bloc, part->boot_size.bloc, +                    part->boot_load, part->boot_entry); +            DPRINTF("                           load %0x entry %0x %0x\n", +                    partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE); +            part_register(bd, part, name, i); +        } else { +            memcpy(tmp, type, 32); +            tmp[32] = '\0'; +            ERROR("Unknown partition type [%s]\n", tmp); +            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +            part_register(bd, part, name, i); +        } +    } + error: +    free(buffer); + +    return boot_part; + +} diff --git a/roms/openhackware/src/libpart/core.c b/roms/openhackware/src/libpart/core.c new file mode 100644 index 00000000..bc2feb0a --- /dev/null +++ b/roms/openhackware/src/libpart/core.c @@ -0,0 +1,288 @@ +/* + * <part.c> + * + * Open Hack'Ware BIOS partitions management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "libpart.h" + +/* Bootable partitions detection and management */ +part_t *part_open (bloc_device_t *bd, +                   uint32_t start, uint32_t size, uint32_t spb) +{ +    part_t *part; + +    if (bd_seek(bd, (start + size) * spb, 0) < 0) +        return NULL; +    part = malloc(sizeof(part_t)); +    if (part == NULL) +        return NULL; +    part->bd = bd; +    part->start = start; +    part->size = size; +    part->spb = spb; + +    return part; +} + +int part_seek (part_t *part, uint32_t bloc, uint32_t pos) +{ +    if (bloc > part->size) { +        ERROR("bloc: %d part size: %d %p\n", bloc, part->size, part); +        return -1; +    } +    bloc += part->start; +    if (part->spb != 0) { +        bloc *= part->spb; +        pos = pos % part->bloc_size; +    } else { +        pos += (bloc % part->bps) * part->bloc_size; +        bloc /= part->bps; +    } + +    return bd_seek(part->bd, bloc, pos); +} + +int part_read (part_t *part, void *buffer, int len) +{ +    return bd_read(part->bd, buffer, len); +} + +int part_write (part_t *part, const void *buffer, int len) +{ +    return bd_write(part->bd, buffer, len); +} + +void part_close (part_t *part) +{ +    part->size = 0; +} + +uint32_t part_blocsize (part_t *part) +{ +    return part->bloc_size; +} + +uint32_t part_flags (part_t *part) +{ +    return part->flags; +} + +uint32_t part_size (part_t *part) +{ +    return part->size; +} + +fs_t *part_fs (part_t *part) +{ +    return part->fs; +} + +void part_private_set (part_t *part, void *private) +{ +    part->private = private; +} + +void *part_private_get (part_t *part) +{ +    return part->private; +} + +void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize) +{ +    uint32_t seclen; + +    part->bloc_size = blocsize; +    seclen = bd_seclen(bd); +    if (blocsize < seclen) { +        part->spb = 0; +        part->bps = bd_seclen(bd) / part->bloc_size; +        DPRINTF("%d part blocs in one sector (%d %d)\n", part->bps, +                part->bloc_size, bd_seclen(bd)); +    } else { +        part->spb = part->bloc_size / bd_seclen(bd); +        part->bps = 0; +        DPRINTF("%d sectors in one part bloc (%d %d)\n", part->spb, +                part->bloc_size, bd_seclen(bd)); +    } +} + +int part_register (bloc_device_t *bd, part_t *partition, +                   const unsigned char *name, int partnum) +{ +    part_t **cur; + +    DPRINTF("Register partition '%s'\n", name); +    partition->bd = bd; +    partition->next = NULL; +    partition->name = strdup(name); +    partition->partnum = partnum; +    for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) +        continue; +    *cur = partition; + +    return 0; +} + +part_t *part_get (bloc_device_t *bd, int partnum) +{ +    part_t **listp, *cur; + +    listp = _bd_parts(bd); +     +    for (cur = *listp; cur != NULL; cur = cur->next) { +        if (cur->partnum == partnum) +            break; +    } +     +    return cur; +} + +part_t *part_get_raw (bloc_device_t *bd) +{ +    part_t *part; +    uint32_t seclen; + +    part = malloc(sizeof(part_t)); +    part->start = 0; +    seclen = bd_seclen(bd); +    part->size = bd_maxbloc(bd); +    if (seclen > 512) { +        part->size *= seclen / 512; +    } else { +        part->size *= 512 / seclen; +    } +    part->boot_start.bloc = 0; +    part->boot_start.offset = 0; +    part->boot_size.bloc = part->size; +    part->boot_size.offset = 0; +    part->boot_load = 0; +    part->boot_entry = 0; +    part_set_blocsize(bd, part, 512); +    part->bd = bd; +    part->flags = PART_TYPE_RAW | PART_FLAG_BOOT; +    part_register(bd, part, "Raw", 0); + +    return part; +} + +bloc_device_t *part_get_bd (part_t *part) +{ +    return part->bd; +} + +part_t *part_probe (bloc_device_t *bd, int set_raw) +{ +    part_t *part0 = NULL, *boot_part, **cur; + +    /* Try to find a valid boot partition */ +    boot_part = Apple_probe_partitions(bd); +    if (boot_part == NULL) { +        boot_part = isofs_probe_partitions(bd); +        if (boot_part == NULL && arch == ARCH_PREP) +            boot_part = PREP_find_partition(bd); +        if (boot_part == NULL && set_raw != 0) { +            dprintf("Use bloc device as raw partition\n"); +        } +    } +    if (_bd_parts(bd) == NULL) { +        /* Register the 0 partition: raw partition containing the whole disk */ +        part0 = part_get_raw(bd); +    } +    /* Probe filesystem on each found partition */ +    for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) { +        const unsigned char *map, *type; +        switch ((*cur)->flags & 0x0F) { +        case PART_TYPE_PREP: +            map = "PREP"; +            break; +        case PART_TYPE_APPLE: +            map = "Apple"; +            break; +        case PART_TYPE_ISO9660: +            map = "ISO9660"; +            break; +        default: +            map = "Raw"; +            break; +        } +        switch ((*cur)->flags & 0xF0) { +        case PART_FLAG_DUMMY: +            type = "dummy"; +            break; +        case PART_FLAG_DRIVER: +            type = "driver"; +            break; +        case PART_FLAG_PATCH: +            type = "patches"; +            break; +        case PART_FLAG_FS: +            type = "filesystem"; +            break; +        default: +            type = "unknown"; +            break; +        } +        dprintf("Probe filesystem on %s %s partition '%s' %s %p\n", +                type, map, (*cur)->name, +                ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "", *cur); +        if (((*cur)->flags) & PART_FLAG_FS) { +            if (((*cur)->flags) & PART_FLAG_BOOT) +                (*cur)->fs = fs_probe(*cur, 1); +            else +                (*cur)->fs = fs_probe(*cur, 0); +        } else if (((*cur)->flags) & PART_TYPE_RAW) { +            (*cur)->fs = fs_probe(*cur, 2); +        } else { +            (*cur)->fs = fs_probe(*cur, 2); +        } +            fs_get_bootfile((*cur)->fs); +        if (((*cur)->flags) & PART_FLAG_BOOT) { +            dprintf("Partition is bootable (%d)\n", (*cur)->partnum); +            bd_set_boot_part(bd, *cur, (*cur)->partnum); +            if (boot_part == NULL) +                boot_part = *cur; +        } +    } +    dprintf("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs, +            part_fs(boot_part), part0); + +    return boot_part; +} + +int part_set_boot_file (part_t *part, uint32_t start, uint32_t offset, +                        uint32_t size) +{ +    part->boot_start.bloc = start; +    part->boot_start.offset = offset; +    part->boot_size.bloc = size; +    part->boot_size.offset = 0; +    part->boot_load = 0; +    part->boot_entry = 0; +    part->flags |= PART_FLAG_BOOT; + +    return 0; +} + +unsigned int part_get_entry (part_t *part) +{ +    return part->boot_entry; +} diff --git a/roms/openhackware/src/libpart/isofs.c b/roms/openhackware/src/libpart/isofs.c new file mode 100644 index 00000000..6e0adae3 --- /dev/null +++ b/roms/openhackware/src/libpart/isofs.c @@ -0,0 +1,257 @@ +/* + * <isofs.c> + * + * Open Hack'Ware BIOS ISOFS partition type management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "libpart.h" + +/* ISO FS partitions handlers */ +#define ISOFS_BLOCSIZE (2048) + +/* Generic ISO fs descriptor */ +typedef struct isofs_desc_t isofs_desc_t; +struct isofs_desc_t { +    uint8_t type; +    uint8_t ID[5]; +    uint8_t version; +    uint8_t data[2041]; +} __attribute__ ((packed)); + +typedef struct iso_primary_desc_t iso_primary_desc_t; +struct iso_primary_desc_t { +    uint8_t type; +    uint8_t ID[5]; +    uint8_t version; +    uint8_t pad0; +    uint8_t system_id[32]; +    uint8_t volume_id[32]; +    uint8_t pad1[8]; +    uint32_t volume_size; +} __attribute__ ((packed)); + +/* The only descriptor we're interrested in here + * is El-torito boot descriptor + */ +typedef struct isofs_bootdesc_t isofs_bootdesc_t; +struct isofs_bootdesc_t { +    uint8_t type; +    uint8_t ID[5]; +    uint8_t version; +    uint8_t sys_ID[32]; +    uint8_t pad[32]; +    uint32_t catalog; +    uint8_t data[1973]; +} __attribute__ ((packed)); + +#define ISO_BOOTABLE 0x88 +enum { +    ISOBOOT_IX86 = 0, +    ISOBOOT_PPC  = 1, +    ISOBOOT_MAC  = 2, +}; + +enum { +    ISOMEDIA_NOEMUL = 0, +    ISOMEDIA_FL12   = 1, +    ISOMEDIA_FL144  = 2, +    ISOMEDIA_FL288  = 3, +    ISOMEDIA_HD     = 4, +}; + +typedef struct isofs_validdesc_t isofs_validdesc_t; +struct isofs_validdesc_t { +    uint8_t ID; +    uint8_t arch; +    uint8_t pad[2]; +    uint8_t name[24]; +    uint8_t csum[2]; +    uint16_t key; +} __attribute__ ((packed)); + +typedef struct isofs_bootcat_t isofs_bootcat_t; +struct isofs_bootcat_t { +    uint8_t bootable; +    uint8_t media; +    uint8_t segment[2]; +    uint8_t sys_type; +    uint8_t pad; +    uint16_t nsect; +    uint32_t offset; +    uint8_t data[20]; +} __attribute__ ((packed)); + +part_t *isofs_probe_partitions (bloc_device_t *bd) +{ +    unsigned char name[32]; +    void *buffer; +    union { +        isofs_desc_t desc; +        isofs_bootdesc_t bootdesc; +        iso_primary_desc_t primdesc; +    } *desc; +    isofs_validdesc_t *valid; +    isofs_bootcat_t *bootcat; +    part_t *part; +    uint32_t boot_desc; +    uint32_t nsect, bloc, offset, length; +    int i, end_reached; + +    part = NULL; +    buffer = malloc(ISOFS_BLOCSIZE); +    end_reached = 0; +    desc = buffer; +    boot_desc = -1; +    /* The descriptors start at offset 0x8000 */ +    for (bloc = 0x8000 / ISOFS_BLOCSIZE; end_reached == 0; bloc++) { +        bd_seek(bd, bloc, 0); +        if (bd_read(bd, buffer, ISOFS_BLOCSIZE) < 0) { +            ERROR("%s bloc_read %d failed\n", __func__, bloc); +            goto error; +        } +        if (strncmp("CD001", desc->desc.ID, 5) != 0) { +            //            MSG("\rNo ISO9660 signature\n"); +            goto error; +        } +        /* We found at least one valid descriptor */ +        switch (desc->desc.type) { +        case 0x00: +            /* El-torito descriptor, great ! */ +            DPRINTF("El-torito descriptor: %08x %d\n", desc->bootdesc.catalog, +                    (char *)&desc->bootdesc.catalog - (char *)desc); +            boot_desc = get_le32(&desc->bootdesc.catalog); +            break; +        case 0x01: +            /* ISOFS primary descriptor */ +            DPRINTF("ISOFS primary descriptor (%d %d)\n", +                    get_le32(&desc->primdesc.volume_size) * 2048, +                    get_le32(&desc->primdesc.volume_size)); +            break; +        case 0x02: +            /* ISOFS suplementary descriptor */ +            DPRINTF("ISOFS suplementary descriptor\n"); +            break; +        case 0xFF: +            /* End of descriptor list */ +            DPRINTF("End of descriptor list\n"); +            end_reached = 1; +            break; +        } +    } +    if (boot_desc != (uint32_t)(-1)) { +        /* Find the validation descriptor */ +        bd_seek(bd, boot_desc, 0); +        for (i = 0; i < (ISOFS_BLOCSIZE / 64); i++) { +            DPRINTF("ISO catalog...\n"); +            bd_read(bd, buffer, 64); +            valid = buffer; +#if 1 +            if (valid->ID != 0x01 || get_le16(&valid->key) != 0xAA55) { +                ERROR("ISO catalog with invalid ID/key: %x %x\n", +                      valid->ID, valid->key); +                continue; +            } +#endif +#if 0 +#if defined (__i386__) +            if (valid->arch != ISOBOOT_IX86) { +                ERROR("ISO catalog not for x86: %d\n", valid->arch); +                continue; +            } +#elif defined (__powerpc__) || defined (_ARCH_PPC) +            if (valid->arch != ISOBOOT_PPC && valid->arch != ISOBOOT_MAC) { +                ERROR("ISO catalog not for PPC: %d\n", valid->arch); +                continue; +            } +#else +            ERROR("Unknown host architecture !\n"); +            continue; +#endif +#endif +            bootcat = (void *)(valid + 1); +            if (bootcat->bootable != ISO_BOOTABLE) { +                ERROR("Non bootable ISO catalog\n"); +                continue; +            } +            nsect = get_le16(&bootcat->nsect); +            switch (bootcat->media) { +            case ISOMEDIA_NOEMUL: +                length = nsect * ISOFS_BLOCSIZE; +                dprintf("No emulation\n"); +                break; +            case ISOMEDIA_FL12: +                length = 1200 * 1024; +                dprintf("1.2 MB floppy\n"); +                break; +            case ISOMEDIA_FL144: +                length = 1440 * 1024; +                dprintf("1.44 MB floppy\n"); +                break; +            case ISOMEDIA_FL288: +                length = 2880 * 1024; +                dprintf("2.88 MB floppy\n"); +                break; +            case ISOMEDIA_HD: +                length = nsect * ISOFS_BLOCSIZE; +                dprintf("HD image\n"); +                break; +            default: +                ERROR("Unknown media type: %d\n", bootcat->media); +                continue; +            } +            offset = get_le32(&bootcat->offset); +            /* Register boot disc */ +            part = malloc(sizeof(part_t)); +            part->bd = bd; +            part_set_blocsize(bd, part, ISOFS_BLOCSIZE); +            part->start = offset; +            part->size = (length + ISOFS_BLOCSIZE - 1) / ISOFS_BLOCSIZE; +            part->boot_start.bloc = 0; +            part->boot_start.offset = 0; +            part->boot_size.bloc = length / ISOFS_BLOCSIZE; +            part->boot_size.offset = length % ISOFS_BLOCSIZE; +            part->boot_load = 0; +            part->boot_entry = 0; +            if (valid->name[0] == '\0') { +                strcpy(name, "ISOFS"); +            } else { +                memcpy(name, valid->name, sizeof(valid->name)); +                name[sizeof(valid->name)] = '\0'; +            } +            printf("Partition '%s': %p st %0x size %0x %d\n", +                   name, part, offset, length, bootcat->media); +            printf("    boot %0x %0x load %0x entry %0x\n", +                   part->boot_start.bloc, part->boot_size.bloc, +                   part->boot_load, part->boot_entry); +            part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT; +            part_register(bd, part, name, i + 1); +            fs_raw_set_bootfile(part, part->boot_start.bloc, +                                part->boot_start.offset, +                                part->boot_size.bloc, +                                part->boot_size.offset); +            break; +        } +    } +error: +    free(buffer); + +    return part; +} diff --git a/roms/openhackware/src/libpart/libpart.h b/roms/openhackware/src/libpart/libpart.h new file mode 100644 index 00000000..a982b8f2 --- /dev/null +++ b/roms/openhackware/src/libpart/libpart.h @@ -0,0 +1,67 @@ +/* + * <libpart.h> + * + * Open Hack'Ware BIOS partitions management definitions + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#if !defined (__OHW_LIBPART_H__) +#define __OHW_LIBPART_H__ + +/* LBA for IDE is 48 bits long. + * For now, I'll use 32 bits to store bloc nr + * and 32 bits to store offsets in blocs and will only handle LBA 28. + * So, I'll be affected with the well known 128 GB disk barrier bug... + */ + +struct part_t { +    bloc_device_t *bd; +    int partnum; +    uint32_t start;      /* Partition first bloc             */ +    uint32_t size;       /* Partition size, in blocs         */ +    uint32_t spb; +    uint32_t bps; +    uint32_t flags; + +    uint32_t bloc_size;  /* Bloc size (may be != bd->seclen) */ +    /* XXX: broken: to be reworked */ +    pos_t boot_start;    /* Boot program start bloc & offset */ +    pos_t boot_size;     /* Boot program size                */ +    uint32_t boot_load;  /* Boot program address load        */ +    uint32_t boot_entry; /* Boot program entry point         */ + +    unsigned char *name; +    inode_t *boot_file; +    fs_t *fs; + +    void *private; + +    part_t *next; +    part_t *bnext; +}; + +int part_register (bloc_device_t *bd, part_t *partition, +                   const unsigned char *name, int partnum); +void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize); +void part_private_set (part_t *part, void *private); +void *part_private_get (part_t *part); + +part_t *PREP_find_partition (bloc_device_t *bd); +part_t *Apple_probe_partitions (bloc_device_t *bd); +part_t *isofs_probe_partitions (bloc_device_t *bd); + +#endif /* !defined (__OHW_LIBPART_H__) */ diff --git a/roms/openhackware/src/libpart/prep.c b/roms/openhackware/src/libpart/prep.c new file mode 100644 index 00000000..b957bb90 --- /dev/null +++ b/roms/openhackware/src/libpart/prep.c @@ -0,0 +1,216 @@ +/* + * <prep.c> + * + * Open Hack'Ware PREP BIOS partition type management + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "libpart.h" + +/* PREP image management */ +typedef struct MSDOS_part_t MSDOS_part_t; +struct MSDOS_part_t { +    uint8_t  boot_ind; +    uint8_t  start_head; +    uint8_t  start_sect; +    uint8_t  start_cyl; +    uint8_t  sys_ind; +    uint8_t  end_head; +    uint8_t  end_sect; +    uint8_t  end_cyl; +    uint32_t LBA_start; +    uint32_t LBA_end; +}  __attribute__ ((packed)); + +part_t *PREP_find_partition (bloc_device_t *bd) +{ +    MSDOS_part_t *p; +    part_t *part; +    uint8_t *buffer; +    uint32_t boot_offset, boot_size; +    int i; + +    part = NULL; +    buffer = malloc(0x200); +    bd_seek(bd, 0, 0); +    if (bd_read(bd, buffer, 0x200) < 0) { +        ERROR("Unable to read boot sector from boot device. Aborting...\n"); +        goto error; +    } +    if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) { +        ERROR("No MSDOS signature (%x %x %x %x)\n", +              buffer[0x000], buffer[0x001], buffer[0x1FE], buffer[0x1FF]); +        goto error; +    } +    for (i = 0; i < 4; i++) { +        p = (void *)(&buffer[0x1BE + (0x10 * i)]); +        DPRINTF("partition %d: %x is %sbootable - ", i, p->boot_ind, +                (p->boot_ind & 0x80) ? "" : "not "); +        DPRINTF("start %0x end %0x type %x\n", +                get_le32(&p->LBA_start), get_le32(&p->LBA_end), p->sys_ind); +#if 0 +        if (p->boot_ind != 0x80) +            continue; +#endif +        switch (p->sys_ind) { +        case 0x07: /* HPFS/NTFS */ +            goto register_nonboot; +        case 0x08: /* AIX */ +            goto register_nonboot; +        case 0x09: /* AIX bootable */ +            /* Not supported by now */ +            break; +        case 0x0A: /* OS/2 boot manager */ +            /* Not supported by now */ +            break; +        case 0x41: /* PREP boot */ +            part = malloc(sizeof(part_t)); +            memset(part, 0, sizeof(part_t)); +            part->bd = bd; +            part_set_blocsize(bd, part, 0x200); +            /* Convert start and size into LBA */ +            if ((p->start_head != 0 || p->start_cyl != 0 || +                 p->start_sect != 0) && p->LBA_start == 0) { +                DPRINTF("start: use CHS\n"); +                part->start = bd_CHS2sect(bd, p->start_cyl, +                                          p->start_head, +                                          p->start_sect); +            } else { +                DPRINTF("start: use LBA\n"); +                part->start = get_le32(&p->LBA_start); +            } +            if ((p->end_head != 0 || p->end_cyl != 0 || +                 p->end_sect != 0) && p->LBA_end == 0) { +                DPRINTF("end: use CHS\n"); +                part->size = bd_CHS2sect(bd, p->end_cyl, +                                         p->end_head, p->end_sect); +            } else { +                DPRINTF("end: use LBA\n"); +                part->size = get_le32(&p->LBA_end); +            } +            /* XXX: seems that some (AIX !) +             * code the size here instead of partition end +             */ +            if (part->size > part->start) +                part->size -= part->start; +            DPRINTF("LBA: start %0x size: %0x\n", part->start, part->size); +            /* Now, find and check boot record */ +            part_seek(part, 0, 0); +            if (bd_read(bd, buffer, part->bloc_size) < 0) { +                ERROR("%s sector_read failed (%d)\n", __func__, i); +                freep(&part); +                goto error; +            } +#if 0 +            if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) { +                ERROR("No MSDOS signature on PREP boot record\n"); +                freep(&part); +                goto error; +            } +#endif +            boot_offset = get_le32(buffer); +            boot_size =  get_le32(buffer + 4); +            if ((boot_offset & 3) || /*(boot_size & 3) ||*/ +                boot_offset == 0 || boot_size == 0) { +                DPRINTF("Suspicious PREP boot parameters: %08x %08x %08x %08x\n", +                    part->start, part->start * 0x200, boot_offset, boot_size); +#if 0 +                freep(&part); +                goto error; +#else +                /* IBM boot blocs respect the norm better than others... */ +                part->start++; +                part_seek(part, 0, 0); +                if (bd_read(bd, buffer, part->bloc_size) < 0) { +                    ERROR("%s sector_read failed (%d)\n", __func__, i); +                    freep(&part); +                    goto error; +                } +                boot_offset = get_le32(buffer); +                boot_size =  get_le32(buffer + 4); +#endif +            } +            DPRINTF("PREP boot parameters: %08x %08x %08x %08x\n", +                    part->start, part->start * 0x200, boot_offset, boot_size); +            if (boot_size > (part->size * part->bloc_size)) { +                ERROR("PREP boot image greater than boot partition: %0x %0x\n", +                      boot_size, part->size * part->bloc_size); +#if 0 +                freep(&part); +                goto error; +#endif +            } +            part->boot_start.bloc = 0; +            part->boot_start.offset = 0; +            part->boot_size.bloc = boot_size / part->bloc_size; +            part->boot_size.offset = boot_size % part->bloc_size; +            part->boot_load = 0; +            part->boot_entry = boot_offset - part->bloc_size; +            part->flags = PART_TYPE_PREP | PART_FLAG_BOOT; +            part_register(bd, part, "PREP boot", i); +            fs_raw_set_bootfile(part, part->boot_start.bloc, +                                part->boot_start.offset, +                                part->boot_size.bloc, +                                part->boot_size.offset); +            break; +        case 0x63: /* GNU Hurd */ +            goto register_nonboot; +        case 0x83: /* Linux */ +            goto register_nonboot; +        case 86 ... 87: /* NFTS volume set */ +            /* Not supported by now */ +            break; +        case 0x8E: /* Linux LVM */ +            /* Not supported by now */ +            break; +        case 0x96: /* AIX seems to use this to identify ISO 9660 'partitions' */ +            break; +        case 0xA5: /* FreeBSD */ +            goto register_nonboot; +        case 0xA6: /* OpenBSD */ +            goto register_nonboot; +        case 0xA7: /* NeXTSTEP */ +            goto register_nonboot; +        case 0xA8: /* Darwin UFS */ +            goto register_nonboot; +        case 0xA9: /* NetBSD */ +            goto register_nonboot; +        case 0xAB: /* Darwin boot */ +            /* Not supported by now */ +            break; +        case 0xBE: /* Solaris boot */ +            /* Not supported by now */ +            break; +        case 0xEB: /* BeOS fs */ +            goto register_nonboot; +        case 0xFD: /* Linux RAID */ +            /* Not supported by now */ +            break; +        default: +            break; +        register_nonboot: +            break; +        } +    } + error: +    free(buffer); + +    return part; +} diff --git a/roms/openhackware/src/main.c b/roms/openhackware/src/main.c new file mode 100644 index 00000000..2d61d64f --- /dev/null +++ b/roms/openhackware/src/main.c @@ -0,0 +1,564 @@ +/* + * Open Hack'Ware BIOS main. + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +/* + * Status: + * - boots Linux 2.4 from floppy and IDE + * - preliminary residual data support + * - can find PREP boot images and Apple boot blocs + * + * TODO: + * 1/ Cleanify boot partitions: + *    allow more than one boot bloc + fix PREP load again + * 2/ add ATAPI driver + * 3/ add a prompt to let the user choose its boot device / PREP image + * 4/ add POST + * 5/ add VGA driver (SVGA/VESA ?) + * 6/ add a user accessible setup + * 7/ add netboot + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" + +#include "char.h" + +//#define DEBUG_MEMORY 1 + +/* Version string */ +const unsigned char *BIOS_str = +"PPC Open Hack'Ware BIOS for qemu version " BIOS_VERSION "\n"; +const unsigned char *copyright = "Copyright 2003-2005 Jocelyn Mayer\n"; + +uint32_t isa_io_base = ISA_IO_BASE; + +/* Temporary hack: boots only from floppy */ +int boot_device = 'a'; + +/* Some other PPC helper */ +/* Setup a memory mapping, using BAT0 + * BATU: + * BEPI  : bloc virtual address + * BL    : area size bits (128 kB is 0, 256 1, 512 3, ... + * Vs/Vp + * BATL: + * BPRN  : bloc real address align on 4MB boundary + * WIMG  : cache access mode : not used + * PP    : protection bits + */ +static void BAT_setup (int nr, uint32_t virtual, uint32_t physical, +                       uint32_t size, int Vs, int Vp, int PP) +{ +    uint32_t sz_bits, tmp_sz, align, tmp; +     +    sz_bits = 0; +    align = 131072; +    DPRINTF("Set BAT %d v=%0x p=%0x size=%0x\n", nr, virtual, physical, size); +    if (size < 131072) +        size = 131072; +    for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { +        sz_bits = (sz_bits << 1) + 1; +        align = align << 1; +    } +    tmp = virtual & ~(align - 1);  /* Align virtual area start */ +    tmp |= sz_bits << 2;           /* Fix BAT size             */ +    tmp |= Vs << 1;                /* Supervisor access        */ +    tmp |= Vp;                     /* User access              */ +    DPRINTF("Set BATU%d to %0x\n", nr, tmp); +    switch (nr) { +    case 0: +        /* Setup IBAT0U */ +        MTSPR(528, tmp); +        /* Setup DBAT0U */ +        MTSPR(536, tmp); +        break; +    case 1: +        /* Setup DBAT1U */ +        MTSPR(538, tmp); +        break; +    case 2: +        /* Setup DBAT2U */ +        MTSPR(540, tmp); +        break; +    } +    tmp = physical & ~(align - 1); /* Align physical area start */ +    tmp |= 0;                      /* Don't care about WIMG     */ +    tmp |= PP;                     /* Protection                */ +    DPRINTF("Set BATL%d to %0x\n", nr, tmp); +    switch (nr) { +    case 0: +        /* Setup IBAT0L */ +        MTSPR(529, tmp); +        /* Setup DBAT0L */ +        MTSPR(537, tmp); +        break; +    case 1: +        /* Setup DBAT1L */ +        MTSPR(539, tmp); +        break; +    case 2: +        /* Setup DBAT2L */ +        MTSPR(541, tmp); +        break; +    } +} + +typedef struct PPC_CPU_t { +    uint32_t pvr; +    uint32_t mask; +    unsigned char *name; +} PPC_CPU_t; + +static const PPC_CPU_t CPU_PPC[] = { +    /* For now, know only G3 */ +    { +        0x00080000, +        0xFFFF0000, +        "PowerPC,G3", +    }, +    { +        0x00000000, +        0x00000000, +        "PowerPC,generic", +    }, +}; + +static const unsigned char *CPU_get_name (uint32_t pvr) +{ +    int i; + +    for (i = 0;; i++) { +        if ((pvr & CPU_PPC[i].mask) == CPU_PPC[i].pvr) +            return CPU_PPC[i].name; +    } + +    return NULL; +} + +#define TB_FREQ (10 * 1000 * 1000) // XXX: should calibrate +void usleep (uint32_t usec) +{ +#if 0 // Buggy: makes OpenDarwin crash (!) +    uint32_t tb0[2], tb1[2], count[2]; +    uint32_t tpu; +    int wrap = 0; + +    tpu = TB_FREQ / (1000 * 1000); +    mul64(count, usec, tpu); +    mftb(tb0); +    add64(count, count, tb0); +    if (count[0] < tb0[0]) +        wrap = 1; +    while (1) { +        mftb(tb1); +        if (wrap == 1 && tb1[0] < tb0[0]) +            wrap = 0; +        if (wrap == 0 && +            (tb1[0] > count[0] || +             (tb1[0] == count[0] && tb1[1] >= count[1]))) +            break; +        tb0[0] = tb1[0]; +    } +#else +    uint32_t i, j; +     +    for (i = 0; i < (usec >> 16) * 50; i++) { +        for (j = 0; j < (usec & 0xFFFF) * 50; j++) { +            continue; +        } +    } +#endif +} + +void sleep (int sec) +{ +    int i; + +    for (i = 0; i < sec; i++) +        usleep(1 * 1000 * 1000); +} + +/* Stolen from Linux code */ +#define CRCPOLY_LE 0xedb88320 + +uint32_t crc32 (uint32_t crc, const uint8_t *p, int len) +{ +    int i; + +    while (len--) { +        crc ^= *p++; +        for (i = 0; i < 8; i++) +            crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); +    } + +    return crc; +} + +/* Fake write */ +int write (unused int fd, unused const char *buf, int len) +{ +    return len; +} + +/* BIOS library functions */ +/* Fake memory management (to be removed) */ +void *mem_align (unused int align) +{ +    return malloc(0); +} +#if 1 +void free (unused void *p) +{ +} +#endif + +void freep (void *p) +{ +    void **_p = p; + +    free(*_p); +    *_p = NULL; +} + +static inline int in_area (const void *buf, +                           const void *start, const void *end) +{ +    return buf >= start && buf <= end; +} + +#ifdef DEBUG_MEMORY +static void *load_dest, *load_end; +static int relax_check; +#endif + +void set_loadinfo (unused void *load_base, unused uint32_t size) +{ +#ifdef DEBUG_MEMORY +    load_dest = load_base; +    load_end = (char *)load_dest + size; +#endif +} + +void set_check (unused int do_it) +{ +#ifdef DEBUG_MEMORY +    relax_check = do_it == 0 ? 1 : 0; +#endif +} + +void check_location (unused const void *buf, +                     unused const char *func, +                     unused const char *name) +{ +#ifdef DEBUG_MEMORY +    if (relax_check != 0) +        return; +    if (!in_area(buf, &_data_start, &_data_end) && +        !in_area(buf, &_OF_vars_start, &_OF_vars_end) && +        !in_area(buf, &_sdata_start, &_sdata_end) && +        !in_area(buf, &_ro_start, &_ro_end) && +        !in_area(buf, &_RTAS_data_start, &_RTAS_data_end) && +        !in_area(buf, &_bss_start, &_bss_end) && +        !in_area(buf, &_ram_start, malloc_base) && +        /* Let's say 64 kB of stack is enough */ +        !in_area(buf, (void *)0x5ff0000, (void *)0x6000000) && +        !in_area(buf, load_dest, load_end) && +        /* IO area */ +        !in_area(buf, (void *)0x80000000, (void *)0x88000000)) { +        printf("**************************************************************" +               "**************\n"); +        printf("%s: %s: %p\n", func, name, buf); +        printf("    data:       %p %p\n", &_data_start, &_data_end); +        printf("    OF_vars:    %p %p\n", &_OF_vars_start, &_OF_vars_end); +        printf("    sdata:      %p %p\n", &_sdata_start, &_sdata_end); +        printf("    rodata:     %p %p\n", &_ro_start, &_ro_end); +        printf("    RTAS_data:  %p %p\n", &_RTAS_data_start, &_RTAS_data_end); +        printf("    bss:        %p %p\n", &_bss_start, &_bss_end); +        printf("    mallocated: %p %p\n", &_ram_start, malloc_base); +        printf("    stack     : %p %p\n", (void *)0x5ff0000, +               (void *)0x6000000); +        printf("    load image: %p %p\n", load_dest, load_end); +        printf("**************************************************************" +               "**************\n"); +        bug(); +    } +#endif +} + +/* No overflow check here... */ +long strtol (const unsigned char *str, unsigned char **end, int base) +{ +    long ret = 0, tmp, sign = 1; + +    check_location(str, __func__, "str"); +    if (base < 0 || base > 36) +        return 0; +    for (; *str == ' '; str++) +        continue; +    if (*str == '-') { +        sign = -1; +        str++; +    } +    for (;; str++) { +        tmp = *str; +        if (tmp < '0') +            break; +        if (base <= 10) { +            if (tmp > '0' + base - 1) +                break; +            tmp -= '0'; +        } else { +            if (tmp <= '9') { +                tmp -= '0'; +            } else { +                tmp &= ~0x20; +                if (tmp < 'A' || tmp > 'A' + base - 11) +                    break; +                tmp += 10 - 'A'; +            } +        } +        ret = (ret * base) + tmp; +    } +    if (sign == -1) +        ret = -ret; +    if (end != NULL) +        *end = (unsigned char *)str; + +    return ret; +} + +nvram_t *nvram; +int arch; +/* HACK... */ +int vga_width, vga_height, vga_depth; + +part_t *boot_part; + +/* XXX: to fix */ +void mm_init (uint32_t memsize); +int page_descrs_init (void); + +int main (void) +{ +    bloc_device_t *bd; +    pci_host_t *pci_main; +    void *res, *bootinfos; +    void *boot_image, *cmdline, *ramdisk; +    void *load_base, *load_entry, *last_alloc, *load_end; +    uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size; +    uint32_t boot_nb; +    int boot_device, i; +    static const uint32_t isa_base_tab[3] = { +        0x80000000, /* PREP */ +        0xFE000000, /* Grackle (Heathrow) */ +        0xF2000000, /* UniNorth (Mac99)  */ +    }; + +    /* Retrieve NVRAM configuration */ +    for(i = 0; i < 3; i++) { +        isa_io_base = isa_base_tab[i]; +    nvram = NVRAM_get_config(&memsize, &boot_device, +                             &boot_image, &boot_image_size, +                             &cmdline, &cmdline_size, +                             &ramdisk, &ramdisk_size); +        if (nvram) +            break; +        } +    if (i == 3) { +        ERROR("Unable to load configuration from NVRAM. Aborting...\n"); +        return -1; +    } +#if 1 +    mm_init(memsize); +#endif +#if 1 +    page_descrs_init(); +#endif +#ifdef USE_OPENFIRMWARE +    OF_init(); +#endif +    pci_main = pci_init(); +    if (pci_main == NULL) +        ERROR("Unable to configure PCI\n"); +#ifdef USE_OPENFIRMWARE +    /* XXX: this mess needs a serious cleanup... */ +    { +        const unsigned char *cpu_name; +        uint32_t pvr = mfpvr(); + +        cpu_name = CPU_get_name(pvr); +        OF_register_cpu(cpu_name, 0, pvr, +                        200 * 1000 * 1000, 200 * 1000 * 1000, +                        100 * 1000 * 1000, 100 * 1000 * 1000, +                        0x0092); +    } +    OF_register_memory(memsize, 512 * 1024 /* TOFIX */); +    /* Claim memory used by the BIOS */ +    OF_claim_virt(0x05800000, 0x00080000, NULL); +    OF_register_bootargs(cmdline); +#endif +    if (isa_io_base == 0x80000000 || 1) { +        pc_serial_register(0x3F8); +#ifdef USE_OPENFIRMWARE +        OF_register_bus("isa", isa_io_base, "ISA"); +        OF_register_serial("isa", "com1", 0x3F8, 4); +        OF_register_stdio("com1", "com1"); +#endif +    } +#ifdef USE_OPENFIRMWARE +    RTAS_init(); +#endif +    /* Get a console */ +    console_open(); +    printf("%s", BIOS_str); +    printf("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n"); +    printf("%s\n", copyright); +    printf("Memory size: %d MB. \nBooting from device %c\n", +           memsize >> 20, boot_device); +    vga_puts(BIOS_str); +    vga_puts("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n"); +    vga_puts(copyright); +    vga_puts("\n"); + +#if 0 +    /* QEMU is quite incoherent: d is cdrom, not second drive */ +    /* XXX: should probe CD-ROM position */ +    if (boot_device == 'd') +        boot_device = 'e'; +#endif +    /* Open boot device */ +    boot_part = bd_probe(boot_device); +    if (boot_device == 'm') { +        bd = bd_get('m'); +        if (bd == NULL) { +            ERROR("Unable to get memory bloc device\n"); +            return -1; +        } +        printf("boot device: %p image %p size %d\n", +               bd, boot_image, boot_image_size); +        bd_ioctl(bd, MEM_SET_ADDR, boot_image); +        bd_ioctl(bd, MEM_SET_SIZE, &boot_image_size); +        boot_part = part_probe(bd, 1); +        bd_put(bd); +        printf("boot device: %p\n", bd); +    } +    if (boot_part == NULL) { +        ERROR("Found no boot partition!\n"); +        return -1; +    } +    ERROR("Found boot partition : %p %p\n", boot_part, part_fs(boot_part)); +    mem_align(0x00001000); +    res = malloc(0x4000); +    last_alloc = malloc(0); +    boot_nb = 0; +    DPRINTF("Load base: %p - residual data: %p %p %p %p\n", +            load_base, res, last_alloc, boot_part, part_fs(boot_part)); +    /* Load the whole boot image */ +    if (bootfile_load((void *)&load_base, (void *)&load_entry, +                      (void *)&load_end, boot_part, -1, NULL, 0) < 0) { +        printf("Unable to load boot file\n"); +        return -1; +    } +#ifdef USE_OPENFIRMWARE +    DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n", +            res, load_base, &OF_entry, load_entry); +#else +    DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n", +            res, load_base, NULL, load_entry); +#endif +    DPRINTF("Boot: %0x %0x %0x %0x\n", *(uint32_t *)load_entry, +            *((uint32_t *)load_entry + 1), +            *((uint32_t *)load_entry + 2), +            *((uint32_t *)load_entry + 3)); +    /* Fill residual data structure */ +    residual_build(res, memsize, (uint32_t)load_base, +                   (uint32_t)boot_nb * part_blocsize(boot_part), +                   (uint32_t)last_alloc); +    /* Fill bootinfos */ +    bootinfos = (void *)(((uint32_t)load_end + (1 << 20) - 1) & ~((1 << 20) - 1)); +    if (boot_image != NULL && cmdline == NULL) { +        cmdline = bootinfos + 0x1000; +        *(char *)cmdline = '\0'; +    } +    set_check(0); +    prepare_bootinfos(bootinfos, memsize, cmdline, ramdisk, ramdisk_size); +    set_check(1); +    if (part_flags(boot_part) & PART_PREP) { +        vga_prep_init(); +    } +    /* Format NVRAM */ +    NVRAM_format(nvram); +    /* Setup MMU and boot the loaded image */ +    DPRINTF("\nSet up MMU context\n"); +    /* Map all memory with transparent mapping */ +    BAT_setup(0, 0x00000000, 0x00000000, memsize, 1, 0, 2); +    /* Open IO ports */ +    BAT_setup(1, isa_io_base, isa_io_base, 0x00800000, 1, 1, 2); +#if 0 +    /* Open the frame-buffer area */ +    BAT_setup(2, vga_fb_phys_addr, vga_fb_phys_addr, 0x00200000, 1, 1, 2); +#else +    if (pci_main != NULL) { +        uint32_t mem_start, mem_size; +        pci_get_mem_range(pci_main, &mem_start, &mem_size); +        BAT_setup(2, mem_start, mem_start, mem_size, 1, 1, 2); +    } +#endif +    /* Enable MMU */ +    MMU_on(); +    usleep(500); +    dprintf("Boot: %08x %08x %08x %08x\n", *(uint32_t *)load_base, +            *(uint32_t *)(load_base + 4), *(uint32_t *)(load_base + 8), +            *(uint32_t *)(load_base + 12)); +    dprintf("Bootinfos at : %p\n", bootinfos); +    printf("\nNow boot it... (%p)\n\n", malloc(0)); +    usleep(500); +    { +        register uint32_t r1 __asm__ ("r1"); +        printf("stack: %0x malloc_base: %p 0x05800000 0x06000000\n", +               r1, malloc(0)); +    } +     +    if (part_flags(boot_part) & PART_PREP) { +        printf("PREP boot... %p %p\n", load_entry, load_base); +        /* Hack for Linux to boot without OpenFirmware */ +        put_be32(load_base, 0xdeadc0de); +    } +    transfer_handler(res                      /* residual data          */, +                     load_base                /* load address           */, +#ifdef USE_OPENFIRMWARE +                     &OF_entry                /* OF entry point         */, +#else +                     NULL, +#endif +                     bootinfos                /* bootinfos for Linux    */, +                     cmdline                  /* command line for Linux */, +                     NULL                     /* unused for now         */, +                     load_entry               /* start address     */, +#if 0 +                     mem_align(0x00100000)    /* Stack base             */ +#else +                     (void *)0x05800000 +#endif +                     ); +    /* Should never come here */ + +    return 0; +} diff --git a/roms/openhackware/src/main.ld b/roms/openhackware/src/main.ld new file mode 100644 index 00000000..453d5fd2 --- /dev/null +++ b/roms/openhackware/src/main.ld @@ -0,0 +1,79 @@ +/* + * Open Hack'Ware BIOS main. + *  + *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) + *    + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +OUTPUT_ARCH(powerpc:common) + +MEMORY +{ +        start (rwx) : ORIGIN = 0x05800000, LENGTH = 0x00000400 +        bios (rwx)  : ORIGIN = 0x05800400, LENGTH = 0x0007FC00 +        ram  (rw)   : ORIGIN = 0x06000000, LENGTH = 0x00200000 +} + +SECTIONS +{ +        .start    : { *(.start)   } > start +        . = ALIGN(4) ; +        .text     : { *(.text*)   } > bios +        . = ALIGN(4) ; +        .OpenFirmware : { *(.OpenFirmware) } > bios +        . = ALIGN(4) ; +        _data_start = . ; +        .data     : { *(.data)    } > bios +        _data_end = . ; +        . = ALIGN(4) ; +        _OF_vars_start = . ; +        .OpenFirmware_vars : { *(.OpenFirmware_vars) } > bios +        _OF_vars_end = . ; +        . = ALIGN(4) ; +        _sdata_start = . ; +        .sdata    : { *(.sdata)   } > bios +        . = ALIGN(4) ; +        .sdata2   : { *(.sdata2)  } > bios +        _sdata_end = . ; +        . = ALIGN(4) ; +        _ro_start = . ; +        .rodata    : { *(.rodata*) } > bios +        _ro_end = . ; +        . = ALIGN(4) ; +        _RTAS_start = .; +        .RTAS     : { *(.RTAS)    } > bios +        _RTAS_end = .; +        . = ALIGN(4) ; +        _RTAS_data_start = .; +        .RTAS_vars : { *(.RTAS_vars) } > bios +        . = ALIGN(4) ; +        _RTAS_data_end = .; +        _bss_start = . ; +        .sbss     : { +          *(.sbss) *(.scommon) +        } > bios +        . = ALIGN(4) ; +        .bss      : { *(.bss) *(COMMON) } > bios +        _bss_end = . ; +        . = ALIGN(4) ; +        _ram_start = . ; +        .ram      : { +          *(.ram) +        } > ram +        /DISCARD/ : { *(.stab)    } +        /DISCARD/ : { *(.stabstr) } +        /DISCARD/ : { *(.comment) } +        /DISCARD/ : { *(.note)    } +} diff --git a/roms/openhackware/src/mm.c b/roms/openhackware/src/mm.c new file mode 100644 index 00000000..e7fa067c --- /dev/null +++ b/roms/openhackware/src/mm.c @@ -0,0 +1,145 @@ +/* + * Open Hack'Ware BIOS memory management. + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include "bios.h" + +#if 0 +static uint8_t *page_bitmap; +static uint32_t memory_size; + +static void mark_page_in_use (uint32_t page_nb) +{ +    uint32_t offset, bit; + +    offset = page_nb >> 3; +    bit = page_nb & 7; +    page_bitmap[offset] |= 1 << bit; +} + +static void mark_page_free (uint32_t page_nb) +{ +    uint32_t offset, bit; + +    offset = page_nb >> 3; +    bit = page_nb & 7; +    page_bitmap[offset] &= ~(1 << bit); +} + +static int is_page_in_use (uint32_t page_nb) +{ +    uint32_t offset, bit; + +    offset = page_nb >> 3; +    bit = page_nb & 7; +     +    return (page_bitmap[offset] & (~(1 << bit))) != 0; +} + +void mm_init (uint32_t memsize) +{ +    uint32_t page_start, page_ram_start, page, ram_start; +    uint32_t nb_pages, bitmap_size; +     +    /* Init bitmap */ +    ram_start = (uint32_t)(&_ram_start); +    ram_start = (ram_start + (1 << 12) - 1) & ~((1 << 12) - 1); +    page_bitmap = (void *)ram_start; +    nb_pages = (memsize + (1 << 12) - 1) >> 12; +    bitmap_size = (nb_pages + 7) >> 3; +    /* First mark all pages as free */ +    memset(page_bitmap, 0, bitmap_size); +    /* Mark all pages used by the BIOS as used (code + data + bitmap) */ +    page_start = (uint32_t)(0x05800000) >> 12; /* TO FIX */ +    ram_start += bitmap_size; +    ram_start = (ram_start + (1 << 12) - 1) & ~((1 << 12) - 1); +    page_ram_start = ram_start >> 12; +    for (page = page_start; page < page_ram_start; page++) +        mark_page_in_use(page); +    memory_size = memsize; +} + +void *page_get (int nb_pages) +{ +    uint32_t page_start, page_end, page; +    int nb; + +    page_start = (uint32_t)(0x05800000) >> 12; /* TO FIX */ +    page_end = memory_size >> 12; +    for (page = page_start; page < page_end; ) { +        /* Skip all full "blocs" */ +        for (; page < page_end; page += 8) { +            if (page_bitmap[page >> 3] != 0xFF) +                break; +        } +        for (nb = 0; page < page_end; page++) { +            if (!is_page_in_use(page)) { +                nb++; +                if (nb == nb_pages) { +                    /* Found ! */ +                    for (; nb >= 0; nb--, page--) +                        mark_page_in_use(page); + +                    return (void *)(page << 12); +                } +            } +        } +    } + +    return NULL; +} + +void page_put (void *addr, int nb_pages) +{ +    uint32_t page_start, page_end, page; + +    page_start = (uint32_t)addr >> 12; +    page_end = page_start + nb_pages; +    for (page = page_start; page < page_end; page++) { +        if (!is_page_in_use(page)) +            printf("ERROR: page %u has already been freed !\n", page); +        mark_page_free(page); +    } +} +#else +static uint8_t *page_alloc; + +void mm_init (unused uint32_t memsize) +{ +    uint32_t ram_start; +    ram_start = (uint32_t)(&_ram_start); +    ram_start = (ram_start + (1 << 12) - 1) & ~((1 << 12) - 1); +    page_alloc = (void *)ram_start; +} + +void *page_get (unused int nb_pages) +{ +    void *ret; + +    ret = page_alloc; +    page_alloc += nb_pages << 12; +    memset(ret, 0, nb_pages << 12); + +    return ret; +} + +void page_put (unused void *addr, unused int nb_pages) +{ +} +#endif diff --git a/roms/openhackware/src/nvram.c b/roms/openhackware/src/nvram.c new file mode 100644 index 00000000..c78a0797 --- /dev/null +++ b/roms/openhackware/src/nvram.c @@ -0,0 +1,450 @@ +/* + * <nvram.c> + * + * Open Hack'Ware BIOS NVRAM management routines. + *  + * Copyright (c) 2004-2005 Jocelyn Mayer + *  + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" + +#define NVRAM_MAX_SIZE 0x2000 +#define NVRAM_IO_BASE 0x0074 + +struct nvram_t { +    uint16_t io_base; +    uint16_t size; +}; + +/* NVRAM access */ +static void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value) +{ +    NVRAM_write(nvram, addr, value); +} + +static uint8_t NVRAM_get_byte (nvram_t *nvram, uint16_t addr) +{ +    return NVRAM_read(nvram, addr); +} + +static void NVRAM_set_word (nvram_t *nvram, uint16_t addr, uint16_t value) +{ +    NVRAM_write(nvram, addr, value >> 8); +    NVRAM_write(nvram, addr + 1, value); +} + +static uint16_t NVRAM_get_word (nvram_t *nvram, uint16_t addr) +{ +    uint16_t tmp; + +    tmp = NVRAM_read(nvram, addr) << 8; +    tmp |= NVRAM_read(nvram, addr + 1); + +    return tmp; +} + +static void NVRAM_set_lword (nvram_t *nvram, uint16_t addr, uint32_t value) +{ +    NVRAM_write(nvram, addr, value >> 24); +    NVRAM_write(nvram, addr + 1, value >> 16); +    NVRAM_write(nvram, addr + 2, value >> 8); +    NVRAM_write(nvram, addr + 3, value); +} + +static uint32_t NVRAM_get_lword (nvram_t *nvram, uint16_t addr) +{ +    uint32_t tmp; + +    tmp = NVRAM_read(nvram, addr) << 24; +    tmp |= NVRAM_read(nvram, addr + 1) << 16; +    tmp |= NVRAM_read(nvram, addr + 2) << 8; +    tmp |= NVRAM_read(nvram, addr + 3); + +    return tmp; +} + +static void NVRAM_set_string (nvram_t *nvram, uint32_t addr, +                              const unsigned char *str, uint32_t max) +{ +    uint32_t i; + +    for (i = 0; i < max && str[i] != '\0'; i++) { +        NVRAM_write(nvram, addr + i, str[i]); +    } +    NVRAM_write(nvram, addr + i, '\0'); +} + +static int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, +                             uint16_t addr, int max) +{ +    int i; + +    memset(dst, 0, max); +    for (i = 0; i < max; i++) { +        dst[i] = NVRAM_get_byte(nvram, addr + i); +        if (dst[i] == '\0') +            break; +    } + +    return i; +} + +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) +{ +    uint16_t tmp; +    uint16_t pd, pd1, pd2; + +    tmp = prev >> 8; +    pd = prev ^ value; +    pd1 = pd & 0x000F; +    pd2 = ((pd >> 4) & 0x000F) ^ pd1; +    tmp ^= (pd1 << 3) | (pd1 << 8); +    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + +    return tmp; +} + +static uint16_t NVRAM_compute_crc (nvram_t *nvram, +                                   uint32_t start, uint32_t count) +{ +    uint32_t i; +    uint16_t crc = 0xFFFF; +    int odd; + +    odd = count & 1; +    count &= ~1; +    for (i = 0; i != count; i++) { +        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); +    } +    if (odd) { +        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); +    } + +    return crc; +} + +/* Format NVRAM for PREP target */ +static int NVRAM_prep_format (nvram_t *nvram) +{ +#define NVRAM_PREP_OSAREA_SIZE 512 +#define NVRAM_PREP_CONFSIZE    1024 +    uint16_t crc; +     +    /* NVRAM header */ +    /* 0x00: NVRAM size in kB */ +    NVRAM_set_word(nvram, 0x00, nvram->size >> 10); +    /* 0x02: NVRAM version */ +    NVRAM_set_byte(nvram, 0x02, 0x01); +    /* 0x03: NVRAM revision */ +    NVRAM_set_byte(nvram, 0x03, 0x01); +    /* 0x08: last OS */ +    NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */ +    /* 0x09: endian */ +    NVRAM_set_byte(nvram, 0x09, 'B');  /* Big-endian */ +    /* 0x0A: OSArea usage */ +    NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */ +    /* 0x0B: PM mode */ +    NVRAM_set_byte(nvram, 0x0B, 0x00); /* Normal */ +    /* Restart block description record */ +    /* 0x0C: restart block version */ +    NVRAM_set_word(nvram, 0x0C, 0x01); +    /* 0x0E: restart block revision */ +    NVRAM_set_word(nvram, 0x0E, 0x01); +    /* 0x20: restart address */ +    NVRAM_set_lword(nvram, 0x20, 0x00); +    /* 0x24: save area address */ +    NVRAM_set_lword(nvram, 0x24, 0x00); +    /* 0x28: save area length */ +    NVRAM_set_lword(nvram, 0x28, 0x00); +    /* 0x1C: checksum of restart block */ +    crc = NVRAM_compute_crc(nvram, 0x0C, 32); +    NVRAM_set_word(nvram, 0x1C, crc); + +    /* Security section */ +    /* Set all to zero */ +    /* 0xC4: pointer to global environment area */ +    NVRAM_set_lword(nvram, 0xC4, 0x0100); +    /* 0xC8: size of global environment area */ +    NVRAM_set_lword(nvram, 0xC8, nvram->size - NVRAM_PREP_OSAREA_SIZE - +                    NVRAM_PREP_CONFSIZE - 0x0100); +    /* 0xD4: pointer to configuration area */ +    NVRAM_set_lword(nvram, 0xD4, nvram->size - NVRAM_PREP_CONFSIZE); +    /* 0xD8: size of configuration area */ +    NVRAM_set_lword(nvram, 0xD8, NVRAM_PREP_CONFSIZE); +    /* 0xE8: pointer to OS specific area */ +    NVRAM_set_lword(nvram, 0xE8, nvram->size - NVRAM_PREP_CONFSIZE +                    - NVRAM_PREP_OSAREA_SIZE); +    /* 0xD8: size of OS specific area */ +    NVRAM_set_lword(nvram, 0xEC, NVRAM_PREP_OSAREA_SIZE); + +    /* Configuration area */ + +    /* 0x04: checksum 0 => OS area   */ +    crc = NVRAM_compute_crc(nvram, 0x00, nvram->size - NVRAM_PREP_CONFSIZE - +                            NVRAM_PREP_OSAREA_SIZE); +    NVRAM_set_word(nvram, 0x04, crc); +    /* 0x06: checksum of config area */ +    crc = NVRAM_compute_crc(nvram, nvram->size - NVRAM_PREP_CONFSIZE, +                            NVRAM_PREP_CONFSIZE); +    NVRAM_set_word(nvram, 0x06, crc); + +    return 0; +} + +static uint8_t NVRAM_chrp_chksum (nvram_t *nvram, uint16_t pos) +{ +    uint16_t sum, end; + +    end = pos + 0x10; +    sum = NVRAM_get_byte(nvram, pos); +    for (pos += 2; pos < end; pos++) { +        sum += NVRAM_get_byte(nvram, pos); +    } +    while (sum > 0xFF) { +        sum = (sum & 0xFF) + (sum >> 8); +    } + +    return sum; +} + +static int NVRAM_chrp_format (unused nvram_t *nvram) +{ +    uint8_t chksum; + +    /* Mark NVRAM as free */ +    NVRAM_set_byte(nvram, 0x00, 0x5A); +    NVRAM_set_byte(nvram, 0x01, 0x00); +    NVRAM_set_word(nvram, 0x02, 0x2000); +    NVRAM_set_string(nvram, 0x04, "wwwwwwwwwwww", 12); +    chksum = NVRAM_chrp_chksum(nvram, 0x00); +    NVRAM_set_byte(nvram, 0x01, chksum); + +    return 0; +} + +#if 0 +static uint16_t NVRAM_mac99_chksum (nvram_t *nvram, +                                   uint16_t start, uint16_t len) +	int cnt; +	u32 low, high; + +   	buffer += CORE99_ADLER_START; +	low = 1; +	high = 0; +	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { +		if ((cnt % 5000) == 0) { +			high  %= 65521UL; +			high %= 65521UL; +		} +		low += buffer[cnt]; +		high += low; +	} +	low  %= 65521UL; +	high %= 65521UL; + +	return (high << 16) | low; +{ +    uint16_t pos; +    uint8_t tmp, sum; + +    sum = 0; +    for (pos = start; pos < (start + len); pos++) { +        tmp = sum + NVRAM_get_byte(nvram, pos); +        if (tmp < sum) +            tmp++; +        sum = tmp; +    } + +    return sum; +} +#endif + +static int NVRAM_mac99_format (nvram_t *nvram) +{ +    uint8_t chksum; + +    /* Mark NVRAM as free */ +    NVRAM_set_byte(nvram, 0x00, 0x5A); +    NVRAM_set_byte(nvram, 0x01, 0x00); +    NVRAM_set_word(nvram, 0x02, 0x2000); +    NVRAM_set_string(nvram, 0x04, "wwwwwwwwwwww", 12); +    chksum = NVRAM_chrp_chksum(nvram, 0x00); +    NVRAM_set_byte(nvram, 0x01, chksum); + +    return 0; +} + +static int NVRAM_pop_format (unused nvram_t *nvram) +{ +    /* TODO */ +    return -1; +} + +/* Interface */ +uint8_t NVRAM_read (nvram_t *nvram, uint32_t addr) +{ +    outb(nvram->io_base + 0x00, addr); +    outb(nvram->io_base + 0x01, addr >> 8); + +    return inb(NVRAM_IO_BASE + 0x03); +} + +void NVRAM_write (nvram_t *nvram, uint32_t addr, uint8_t value) +{ +    outb(nvram->io_base + 0x00, addr); +    outb(nvram->io_base + 0x01, addr >> 8); +    outb(nvram->io_base + 0x03, value); +} + +uint16_t NVRAM_get_size (nvram_t *nvram) +{ +    return nvram->size; +} + +int NVRAM_format (nvram_t *nvram) +{ +    int ret; + +    { +        uint16_t pos; +         +        for (pos = 0; pos < nvram->size; pos += 4) +            NVRAM_set_lword(nvram, pos, 0); +    } +    switch (arch) { +    case ARCH_PREP: +        ret = NVRAM_prep_format(nvram); +        break; +    case ARCH_CHRP: +        ret = NVRAM_chrp_format(nvram); +        break; +    case ARCH_MAC99: +    case ARCH_HEATHROW: /* XXX: may be incorrect */ +        ret = NVRAM_mac99_format(nvram); +        break; +    case ARCH_POP: +        ret = NVRAM_pop_format(nvram); +        break; +    default: +        ret = -1; +        break; +    } + +    return ret; +} + +/* HACK... */ +extern int vga_width, vga_height, vga_depth; + +static nvram_t global_nvram; + +nvram_t *NVRAM_get_config (uint32_t *RAM_size, int *boot_device, +                           void **boot_image, uint32_t *boot_size, +                           void **cmdline, uint32_t *cmdline_size, +                           void **ramdisk, uint32_t *ramdisk_size) +{ +    unsigned char sign[16]; +    nvram_t *nvram; +    uint32_t lword; +    uint16_t NVRAM_size, crc; +    uint8_t byte; + +#if 0 +    nvram = malloc(sizeof(nvram_t)); +    if (nvram == NULL) +        return NULL; +#else +    nvram = &global_nvram; +#endif +    nvram->io_base = NVRAM_IO_BASE; +    /* Pre-initialised NVRAM is not supported any more */ +    if (NVRAM_get_string(nvram, sign, 0x00, 0x10) <= 0 || +        strcmp(sign, "QEMU_BIOS") != 0) { +        ERROR("Wrong NVRAM signature %s\n", sign); +        return NULL; +    } +    /* Check structure version */ +    lword = NVRAM_get_lword(nvram, 0x10); +    if (lword != 0x00000002) { +        ERROR("Wrong NVRAM structure version: %0x\n", lword); +        return NULL; +    } +    /* Check CRC */ +    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); +    if (NVRAM_get_word(nvram, 0xFC) != crc) { +        ERROR("Invalid NVRAM structure CRC: %0x <=> %0x\n", crc, +              NVRAM_get_word(nvram, 0xFC)); +        return NULL; +    } +    NVRAM_size = NVRAM_get_word(nvram, 0x14); +    if ((NVRAM_size & 0x100) != 0x00 || NVRAM_size < 0x400 || +        NVRAM_size > 0x2000) { +        ERROR("Invalid NVRAM size: %d\n", NVRAM_size); +        return NULL; +    } +    nvram->size = NVRAM_size; +    if (NVRAM_get_string(nvram, sign, 0x20, 0x10) < 0) { +        ERROR("Unable to get architecture from NVRAM\n"); +        return NULL; +    } +    if (strcmp(sign, "PREP") == 0) { +        arch = ARCH_PREP; +    } else if (strcmp(sign, "CHRP") == 0) { +        arch = ARCH_CHRP; +    } else if (strcmp(sign, "MAC99") == 0) { +        arch = ARCH_MAC99; +    } else if (strcmp(sign, "POP") == 0) { +        arch = ARCH_POP; +    } else if (strcmp(sign, "HEATHROW") == 0) { +        arch = ARCH_HEATHROW; +    } else { +        ERROR("Unknown PPC architecture: '%s'\n", sign); +        return NULL; +    } +    lword = NVRAM_get_lword(nvram, 0x30); +    *RAM_size = lword; +    byte = NVRAM_get_byte(nvram, 0x34); +    *boot_device = byte; +    /* Preloaded boot image */ +    lword = NVRAM_get_lword(nvram, 0x38); +    *boot_image = (void *)lword; +    lword = NVRAM_get_lword(nvram, 0x3C); +    *boot_size = lword; +    /* Preloaded cmdline */ +    lword = NVRAM_get_lword(nvram, 0x40); +    *cmdline = (void *)lword; +    lword = NVRAM_get_lword(nvram, 0x44); +    *cmdline_size = lword; +    /* Preloaded RAM disk */ +    lword = NVRAM_get_lword(nvram, 0x48); +    *ramdisk = (void *)lword; +    lword = NVRAM_get_lword(nvram, 0x4C); +    *ramdisk_size = lword; +    /* Preloaded NVRAM image */ +    lword = NVRAM_get_lword(nvram, 0x50); +    /* Display init geometry */ +    lword = NVRAM_get_word(nvram, 0x54); +    vga_width = lword; +    lword = NVRAM_get_word(nvram, 0x56); +    vga_height = lword; +    lword = NVRAM_get_word(nvram, 0x58); +    vga_depth = lword; +    /* TODO: write it into NVRAM */ + +    return nvram; +} diff --git a/roms/openhackware/src/of.c b/roms/openhackware/src/of.c new file mode 100644 index 00000000..33582c30 --- /dev/null +++ b/roms/openhackware/src/of.c @@ -0,0 +1,5450 @@ +/* Open firmware emulation. + * + * This is really simplistic. The first goal is to implement all stuff + * needed to boot Linux. Then, I'll try Darwin. + * Note that this emulation run in the host environment. + * There is no Forth interpreter, so standard bootloader cannot be launched. + * In the future, it will be nice to get a complete OpenFirmware implementation + * so that OSes can be launched exactly the way they are in the real world... + * + *  Copyright (c) 2003-2005 Jocelyn Mayer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" + +//#define DEBUG_OF 1 + +#if defined (DEBUG_OF) +#define OF_DPRINTF(fmt, args...) \ +do { dprintf("%s: " fmt, __func__ , ##args); } while (0) +#else +#define OF_DPRINTF(fmt, args...) \ +do { } while (0) +#endif + +#define PROT_READ  1 +#define PROT_WRITE 2 + +typedef struct OF_transl_t OF_transl_t; +struct OF_transl_t { +    uint32_t virt; +    uint32_t size; +    uint32_t phys; +    uint32_t mode; +}; + +typedef struct OF_env_t OF_env_t; +struct OF_env_t { +    uint32_t *stackp; /* Stack pointer          */ +    uint32_t *stackb; /* Stack base             */ +    uint32_t *funcp;  /* Function stack pointer */ +    uint32_t *funcb;  /* Function stack base    */ +}; + +typedef struct OF_bustyp_t OF_bustyp_t; +struct OF_bustyp_t { +    const char *name; +    int type; +}; + +typedef struct pci_address_t pci_address_t; +struct pci_address_t { +	uint32_t hi; +	uint32_t mid; +	uint32_t lo; +}; + +typedef struct pci_reg_prop_t pci_reg_prop_t; +struct pci_reg_prop_t { +	pci_address_t addr; +	uint32_t size_hi; +	uint32_t size_lo; +}; + +typedef struct pci_range_t pci_range_t; +struct pci_range_t { +	pci_address_t addr; +	uint32_t phys; +	uint32_t size_hi; +	uint32_t size_lo; +}; + +/*****************************************************************************/ +__attribute__ (( section (".OpenFirmware") )) +static void OF_lds (uint8_t *dst, const void *address) +{ +    const uint8_t *p; +    uint8_t *_d = dst; + +    for (p = address; *p != '\0'; p++) { +        *_d++ = *p; +    } +    *_d = '\0'; +    OF_DPRINTF("Loaded string %s\n", dst);  +} + +__attribute__ (( section (".OpenFirmware") )) +static void OF_sts (void *address, const uint8_t *src) +{ +    const uint8_t *_s; +    uint8_t *p = address; + +    OF_DPRINTF("Store string %s\n", src); +    for (_s = src; *_s != '\0'; _s++) { +        *p++ = *_s; +    } +    *p = '\0'; +} + +#define OF_DUMP_STRING(env, buffer)    \ +do {                                   \ +    unsigned char tmp[OF_NAMELEN_MAX]; \ +    OF_lds(tmp, buffer);               \ +    OF_DPRINTF("[%s]\n", tmp);         \ +} while (0) + +/*****************************************************************************/ +/* Forth like environmnent */ +#define OF_CHECK_NBARGS(env, nb)                                              \ +do {                                                                          \ +    int nb_args;                                                              \ +    nb_args = stackd_depth((env));                                            \ +    if (nb_args != (nb)) {                                                    \ +        printf("%s: Bad number of arguments (%d - %d)\n",                     \ +               __func__, nb_args, (nb));                                      \ +        bug();                                                                \ +        popd_all((env), nb_args);                                             \ +        pushd((env), -1);                                                     \ +        return;                                                               \ +    }                                                                         \ +} while (0) + +#define OF_STACK_SIZE 0x1000 +#define OF_FSTACK_SIZE 0x100 +__attribute__ (( section (".OpenFirmware_vars") )) +uint8_t OF_stack[OF_STACK_SIZE]; +__attribute__ (( section (".OpenFirmware_vars") )) +uint8_t OF_fstack[OF_FSTACK_SIZE]; + +typedef void (*OF_cb_t)(OF_env_t *OF_env); + +static inline void _push (uint32_t **stackp, uint32_t data) +{ +    //    OF_DPRINTF("%p 0x%0x\n", *stackp, data); +    **stackp = data; +    (*stackp)--; +} + +static inline uint32_t _pop (uint32_t **stackp) +{ +    (*stackp)++; +    //    OF_DPRINTF("%p 0x%0x\n", *stackp, **stackp); +    return **stackp; +} + +static inline void _pop_all (uint32_t **stackp, int nb) +{ +    int i; + +    for (i = 0; i < nb; i++) +        (*stackp)++; +} + +static inline int _stack_depth (uint32_t *stackp, uint32_t *basep) +{ +    return basep - stackp; +} + +static inline void pushd (OF_env_t *OF_env, uint32_t data) +{ +    _push(&OF_env->stackp, data); +} + +static inline uint32_t popd (OF_env_t *OF_env) +{ +    return _pop(&OF_env->stackp); +} + +static inline void popd_all (OF_env_t *OF_env, int nb) +{ +    _pop_all(&OF_env->stackp, nb); +} + +static inline int stackd_depth (OF_env_t *OF_env) +{ +    return _stack_depth(OF_env->stackp, OF_env->stackb); +} + +static inline void pushf (OF_env_t *OF_env, OF_cb_t *func) +{ +    _push(&OF_env->funcp, (uint32_t)func); +} + +static inline OF_cb_t *popf (OF_env_t *OF_env) +{ +    return (OF_cb_t *)_pop(&OF_env->funcp); +} + +static inline void popf_all (OF_env_t *OF_env, int nb) +{ +    _pop_all(&OF_env->funcp, nb); +} + +static inline int stackf_depth (OF_env_t *OF_env) +{ +    return _stack_depth(OF_env->funcp, OF_env->funcb); +} + +static inline void OF_env_init (OF_env_t *OF_env) +{ +    OF_env->stackb = (uint32_t *)(OF_stack + OF_STACK_SIZE - 4); +    OF_env->stackp = OF_env->stackb; +    OF_env->funcb = (uint32_t *)(OF_fstack + OF_FSTACK_SIZE - 4); +    OF_env->funcp = OF_env->funcb; +} + +/* Forth run-time */ +__attribute__ (( section (".OpenFirmware") )) +static void C_to_Forth (OF_env_t *env, void *p, OF_cb_t *cb) +{ +    OF_cb_t *_cb; +    uint32_t *u, *rets; +    uint32_t i, n_args, n_rets, tmp; + +    //    OF_DPRINTF("enter\n"); +    /* Fill argument structure */ +    u = p; +    n_args = *u++; +    n_rets = *u++; +    u += n_args; +    rets = u; +    //    OF_DPRINTF("n_args=%d n_rets=%d\n", n_args, n_rets); +    /* Load arguments */ +    for (i = 0; i < n_args; i++) +        pushd(env, *(--u)); +    pushf(env, cb); +    while (stackf_depth(env) != 0) { +        //        OF_DPRINTF("func stack: %p %p\n", env->funcb, env->funcp); +        _cb = popf(env); +        //        OF_DPRINTF("Next func: %p %d\n", cb, stackf_depth(env)); +        (*_cb)(env); +    } +    //    OF_DPRINTF("Back to C: n_args=%d n_rets=%d\n", n_args, n_rets); +    /* Copy returned values */ +    for (i = 0; stackd_depth(env) != 0; i++) { +        tmp = popd(env); +        //        OF_DPRINTF("Store 0x%0x (%d)\n", tmp, tmp); +        *rets++ = tmp; +    } +    for (; i < n_rets; i++) +        *rets++ = 0; +    OF_CHECK_NBARGS(env, 0); +    //    OF_DPRINTF("done\n"); +} + +/*****************************************************************************/ +/* Memory pool (will be needed when it'll become native) */ +#if 0 +#define OF_INTBITS_LEN 128 +#define OF_INTPOOL_LEN (OF_INTBITS_LEN * 8) +__attribute__ (( section (".OpenFirmware_vars") )) +static uint32_t OF_int_pool[OF_INTPOOL_LEN]; +__attribute__ (( section (".OpenFirmware_vars") )) +static uint8_t  OF_int_bits[OF_INTBITS_LEN]; + +__attribute__ (( section (".OpenFirmware") )) +static uint32_t *OF_int_alloc (unused OF_env_t *env) +{ +    uint8_t tmp; +    int i, j; + +    for (i = 0; i < OF_INTBITS_LEN; i++) { +        tmp = OF_int_bits[i]; +        if (tmp == 0xFF) +            continue; +        for (j = 0; j < 7; j++) { +            if ((tmp & 1) == 0) { +                OF_int_bits[i] |= 1 << j; +                return &OF_int_pool[(i << 3) | j]; +            } +            tmp = tmp >> 1; +        } +    } +    printf("ALERT: unable to \"allocate\" new integer\n"); +     +    return NULL; +} + +__attribute__ (( section (".OpenFirmware") )) +static void OF_int_free (unused OF_env_t *env, +                         uint32_t *area) +{ +    int i, j; + +    i = area - OF_int_pool; +    j = i & 7; +    i = i >> 3; +    OF_int_bits[i] &= ~(1 << j); +} + +__attribute__ (( section (".OpenFirmware") )) +static void OF_free (unused OF_env_t *env, void *area) +{ +    uint32_t *check; + +    /* Check if it's in our int pool */ +    check = area; +    if (check >= OF_int_pool && check < (OF_int_pool + OF_INTPOOL_LEN)) { +        OF_int_free(env, check); +        return; +    } +#if 0 +    free(area); +#endif +} +#endif + +/*****************************************************************************/ +/*                          Internal structures                              */ +/* Property value types */ +typedef struct OF_node_t OF_node_t; +typedef struct OF_prop_t OF_prop_t; +typedef struct OF_method_t OF_method_t; +typedef struct OF_inst_t OF_inst_t; + +#define OF_ADDRESS_NONE ((uint32_t)(-1)) + +/* Tree node */ +struct OF_node_t { +    /* Parent node */ +    OF_node_t *parent; +    /* Link to next node at the same level */ +    OF_node_t *next; +    /* Link to children, if any */ +    OF_node_t *children, *child_last; +    /* refcount */ +    int refcount; +    /* The following ones belong to the package */ +    /* Package */ +    uint16_t pack_id; +    /* links count */ +    uint16_t link_count; +    uint16_t link_cur; +    OF_node_t *link_ref; +    /* Properties */ +    OF_prop_t *properties, *prop_last, *prop_name, *prop_address; +    /* Methods */ +    OF_method_t *methods, *method_last; +    /* private data */ +    void *private_data; +    /* static data */ +    void *static_data; +    /* instances */ +    OF_inst_t *instances, *inst_last; +}; + +/* Node property */ +struct OF_prop_t { +    /* Link to next property */ +    OF_prop_t *next; +    /* The node it belongs to */ +    OF_node_t *node; +    /* property name */ +    const unsigned char *name; +    /* property value len */ +    int vlen; +    /* property value buffer */ +    char *value; +    /* Property change callback */ +    void (*cb)(OF_env_t *OF_env, OF_prop_t *prop, const void *data, int len); +}; + +/* Node method */ +enum { +    OF_METHOD_INTERNAL = 0, +    OF_METHOD_EXPORTED, +}; + +struct OF_method_t { +    /* Link to next method */ +    OF_method_t *next; +    /* The package it belongs to */ +    OF_node_t *node; +    /* method name */ +    unsigned char *name; +    /* Method function pointer */ +    OF_cb_t func; +}; + +/* Package instance */ +struct OF_inst_t { +    /* Link to next instance of the same package */ +    OF_inst_t *next; +    /* Link to the parent instance */ +    OF_inst_t *parent; +    /* The package it belongs to */ +    OF_node_t *node; +    /* Instance identifier */ +    uint16_t inst_id; +    /* Instance data */ +    void *data; +}; + +/* reg property */ +typedef struct OF_regprop_t OF_regprop_t; +struct OF_regprop_t { +    uint32_t address; +    uint32_t size; +}; + +/* range property */ +typedef struct OF_range_t OF_range_t; +struct OF_range_t { +    uint32_t virt; +    uint32_t size; +    uint32_t phys; +}; + +/* Open firmware tree */ +#define OF_MAX_PACKAGE 256 +/* nodes and packages */ +__attribute__ (( section (".OpenFirmware_vars") )) +static OF_node_t *OF_node_root; +__attribute__ (( section (".OpenFirmware_vars") )) +static uint16_t OF_pack_last_id = 0; +__attribute__ (( section (".OpenFirmware_vars") )) +static uint16_t inst_last_id = 0; +/* To speed up lookup by id, we get a package table */ +__attribute__ (( section (".OpenFirmware_vars") )) +static OF_node_t *OF_packages[OF_MAX_PACKAGE]; +__attribute__ (( section (".OpenFirmware_vars") )) +static OF_node_t *OF_pack_active; + +static OF_prop_t *OF_prop_string_new (OF_env_t *env, OF_node_t *node, +                                      const unsigned char *name, +                                      const unsigned char *string); +static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name, uint32_t value); +static OF_prop_t *OF_property_get (OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name); +static uint16_t OF_pack_handle (OF_env_t *env, OF_node_t *node); + +__attribute__ (( section (".OpenFirmware_vars") )) +static uint8_t *RTAS_memory; + +/*****************************************************************************/ +/*                           Node management                                 */ +/* Insert a new node */ +__attribute__ (( section (".OpenFirmware") )) +static uint16_t OF_pack_new_id (unused OF_env_t *env, OF_node_t *node) +{ +    uint16_t cur_id; + +    for (cur_id = OF_pack_last_id + 1; cur_id != OF_pack_last_id; cur_id++) { +        if (cur_id == (uint16_t)(OF_MAX_PACKAGE)) +            cur_id = 1; +        if (OF_packages[cur_id] == NULL) { +            OF_packages[cur_id] = node; +            OF_pack_last_id = cur_id; +            return cur_id; +        } +    } + +    return (uint16_t)(-1); +} + +static OF_node_t *OF_node_create (OF_env_t *env, OF_node_t *parent, +                                  const unsigned char *name, uint32_t address) +{ +    OF_node_t *new; + +    OF_DPRINTF("New node: %s\n", name); +    new = malloc(sizeof(OF_node_t)); +    if (new == NULL) { +        ERROR("%s can't alloc new node '%s'\n", __func__, name); +        return NULL; +    } +    memset(new, 0, sizeof(OF_node_t)); +    new->parent = parent; +    new->refcount = 1; +    new->link_count = 1; +    new->prop_name = OF_prop_string_new(env, new, "name", name); +    if (new->prop_name == NULL) { +        free(new); +        ERROR("%s can't alloc new node '%s' name\n", __func__, name); +        return NULL; +    } +    new->prop_address = OF_prop_int_new(env, new, "unit-address", address); +    if (new->prop_address == NULL) { +        free(new->prop_name->value); +        free(new->prop_name); +        free(new); +        ERROR("%s can't alloc new node '%s' address\n", __func__, name); +        return NULL; +    } +    /* Link it in parent tree */ +    if (parent != NULL) { +        /* SHOULD LOCK */ +        if (parent->children == NULL) { +            parent->children = new; +        } else { +            parent->child_last->next = new; +        } +        parent->child_last = new; +    } else { +        /* This is a bug and should never happen, but for root node */ +        if (strcmp(name, "device-tree") != 0) +            ERROR("WARNING: parent of '%s' is NULL!\n", name); +    } +    //    OF_DPRINTF("New node: %s get id\n", name); + +    return new; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_node_new (OF_env_t *env, OF_node_t *parent, +                               const unsigned char *name, uint32_t address) +{ +    OF_node_t *new; + +    new = OF_node_create(env, parent, name, address); +    if (new == NULL) +        return NULL; +    new->pack_id = OF_pack_new_id(env, new); +    //    OF_DPRINTF("New node: %s id=0x%0x\n", name, new->pack_id); +    OF_pack_active = new; + +    return new; +} + +static inline OF_node_t *OF_node_parent (unused OF_env_t *env, OF_node_t *node) +{ +    return node->parent; +} + +/* Look for a node, given its name */ +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_node_get_child (OF_env_t *env, OF_node_t *parent, +                                     const unsigned char *name, +                                     uint32_t address) +{ +    unsigned char tname[OF_NAMELEN_MAX]; +    OF_node_t *parse, *tmp; +    OF_prop_t *prop_name, *prop_address; +    uint32_t *addr_valp; +    int len, i; + +    if (parent == OF_node_root) { +       OF_DPRINTF("Look for node [%s]\n", name); +    } +    len = strlen(name); +    memcpy(tname, name, len + 1); +    for (i = len; i > 0; i--) { +        if (tname[i - 1] == ',') { +            tname[i - 1] = '\0'; +            len = i; +            break; +        } +    } +    for (parse = parent->children; parse != NULL; parse = parse->next) { +        prop_name = parse->prop_name; +        prop_address = parse->prop_address; +        if (prop_address == NULL) +            addr_valp = NULL; +        else +            addr_valp = (void *)prop_address->value; +#if 0 +        OF_DPRINTF("node [%s] <=> [%s]\n", prop_name->value, tname); +#endif +        if (prop_name != NULL && strncmp(prop_name->value, tname, len) == 0 && +            (prop_name->value[len] == '\0') && +            (address == OF_ADDRESS_NONE || addr_valp == NULL || +             address == *addr_valp)) { +            parse->refcount++; +            return parse; +        } +#if 1 +        OF_DPRINTF("look in children [%s]\n", prop_name->value); +#endif +        tmp = OF_node_get_child(env, parse, tname, address); +        if (tmp != NULL) +            return tmp; +#if 0 +        OF_DPRINTF("didn't find in children [%s]\n", prop_name->value); +#endif +    } +    if (parent == OF_node_root) { +        OF_DPRINTF("node [%s] not found\n", name); +    } + +    return NULL; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_node_get (OF_env_t *env, const unsigned char *name) +{ +    unsigned char tname[OF_NAMELEN_MAX]; +    unsigned char *addrp; +    uint32_t address; + +    if (strcmp(name, "device_tree") == 0) +        return OF_node_root; + +    strcpy(tname, name); +    addrp = strchr(tname, '@'); +    if (addrp == NULL) { +        address = OF_ADDRESS_NONE; +    } else { +        *addrp++ = '\0'; +        address = strtol(addrp, NULL, 16); +    } + +    /* SHOULD LOCK */ +    return OF_node_get_child(env, OF_node_root, name, address); +} + +/* Release a node */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_node_put (unused OF_env_t *env, OF_node_t *node) +{ +    if (--node->refcount < 0) +        node->refcount = 0; +} + +/*****************************************************************************/ +/*                           Packages tree walk                              */ +__attribute__ (( section (".OpenFirmware") )) +static uint16_t OF_pack_handle (unused OF_env_t *env, OF_node_t *node) +{ +    if (node == NULL) +        return 0; + +    return node->pack_id; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_pack_find_by_name (OF_env_t *env, OF_node_t *base, +                                        const unsigned char *name) +{ +    unsigned char tmp[OF_NAMELEN_MAX], *addrp; +    const unsigned char *sl, *st; +    OF_node_t *parse; +    OF_prop_t *prop_name, *prop_address; +    uint32_t address, *addr_valp; +    int len; + +    OF_DPRINTF("Path [%s] in '%s'\n", name, base->prop_name->value); +    st = name; +    if (*st == '/') { +        st++; +    } +    if (*st == '\0') { +        /* Should never happen */ +        OF_DPRINTF("Done\n"); +        return base; +    } +    sl = strchr(st, '/'); +    if (sl == NULL) { +        len = strlen(st); +    } else { +        len = sl - st; +    } +    memcpy(tmp, st, len); +    tmp[len] = '\0'; +    addrp = strchr(tmp, '@'); +    if (addrp == NULL) { +        address = OF_ADDRESS_NONE; +    } else { +        len = addrp - tmp; +        *addrp++ = '\0'; +        address = strtol(addrp, NULL, 16); +    } +    OF_DPRINTF("Look for [%s] '%s' %08x\n", tmp, sl, address); +    for (parse = base->children; parse != NULL; parse = parse->next) { +        prop_name = parse->prop_name; +        prop_address = parse->prop_address; +        if (prop_address == NULL) +            addr_valp = NULL; +        else +            addr_valp = (void *)prop_address->value; +#if 0 +        OF_DPRINTF("Check [%s]\n", prop_name->value); +#endif +        if (prop_name == NULL) { +            printf("ERROR: missing address in node, parent: '%s'\n", +                   base->prop_name->value); +            bug(); +        } +        if (strncmp(prop_name->value, tmp, len) == 0 && +            prop_name->value[len] == '\0' && +            (address == OF_ADDRESS_NONE || addr_valp == NULL || +             address == *addr_valp)) { +            OF_pack_active = parse; +            if (sl == NULL) { +                OF_DPRINTF("Done\n"); +                return parse; +            } +            OF_DPRINTF("Recurse: '%s'\n", sl + 1); +            return OF_pack_find_by_name(env, parse, sl + 1); +        } +    } +    OF_DPRINTF("Didn't found [%s]\n", tmp); + +    return NULL; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_pack_find (unused OF_env_t *env, uint16_t phandle) +{ +    if (phandle > OF_MAX_PACKAGE) +        return NULL; +    if (OF_packages[phandle] == NULL) { +        OF_DPRINTF("No package %0x\n", phandle); +    } else { +        OF_DPRINTF("return package: %0x %p [%s]\n", phandle, +                   OF_packages[phandle], +                   OF_packages[phandle]->prop_name->value); +    } + +    return OF_packages[phandle]; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_pack_next (OF_env_t *env, uint16_t phandle) +{ +    OF_node_t *node; + +    for (node = OF_pack_find(env, phandle); node != NULL; node = node->next) { +        if (OF_pack_handle(env, node) != phandle) +            break; +    } +#if 0 +    OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value); +#endif + +    return node; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_pack_child (OF_env_t *env, uint16_t phandle) +{ +    OF_node_t *node; + +    node = OF_pack_find(env, phandle); +    if (node == NULL) { +        ERROR("%s didn't find pack %04x\n", __func__, phandle); +        return NULL; +    } +    node = node->children; +#if 0 +    OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value); +#endif + +    return node; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_pack_parent (OF_env_t *env, uint16_t phandle) +{ +    OF_node_t *node; + +    node = OF_pack_find(env, phandle); +    if (node == NULL) { +        ERROR("%s didn't find pack %04x\n", __func__, phandle); +        return NULL; +    } +    node = OF_node_parent(env, node); +#if 0 +    OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value); +#endif + +    return node; +} + +/*****************************************************************************/ +/*                      Package properties management                        */ +/* Insert a new property */ +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_property_new (unused OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name, +                                   const void *data, int len) +{ +    OF_prop_t *prop; + +#ifdef DEBUG_OF +    { +        OF_prop_t *_prop; +        _prop = OF_property_get(env, node, name); +        if (_prop != NULL) { +            printf("Property '%s' already present !\n", name); +            bug(); +        } +    } +#endif +    /* Allocate a new property */ +    prop = malloc(sizeof(OF_prop_t)); +    if (prop == NULL) { +        ERROR("%s cannot allocate property '%s'\n", __func__, name); +        return NULL; +    } +    memset(prop, 0, sizeof(OF_prop_t)); +    prop->name = strdup(name); +    if (prop->name == NULL) { +        free(prop); +        ERROR("%s cannot allocate property '%s' name\n", __func__, name); +        return NULL; +    } +    /* Fill it */ +    if (data != NULL && len > 0) { +        prop->value = malloc(len); +        if (prop->value == NULL) { +            free(prop); +            ERROR("%s cannot allocate property '%s' value\n", __func__, name); +            return NULL; +        } +        prop->vlen = len; +        memcpy(prop->value, data, len); +    } +    OF_DPRINTF("New property [%s] '%s'\n\t%p %p %d %p\n", name, prop->name, prop->name, data, len, prop->value); +    /* Link it */ +    /* SHOULD LOCK */ +    if (node->properties == NULL) +        node->properties = prop; +    else +        node->prop_last->next = prop; +    node->prop_last = prop; +     +    return prop; +} + +/* Find a property given its name */ +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_property_get (unused OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name) +{ +    OF_prop_t *prop; +     +#if 0 +    OF_DPRINTF("Look for property [%s] in 0x%0x '%s'\n", name, +               node->pack_id, node->prop_name->value); +#endif +    if (node == NULL) +        return NULL; +    /* *SHOULD LOCK* */ +    for (prop = node->properties; prop != NULL; prop = prop->next) { +#if 0 +        OF_DPRINTF("property [%s] <=> [%s]\n", prop->name, name); +#endif +        if (strcmp(prop->name, name) == 0) { +            return prop; +        } +    } +#if 0 +    OF_DPRINTF("property [%s] not found in 0x%08x '%s'\n", name, +               node->pack_id, node->prop_name->value); +#endif + +    return NULL; +} + +/* Change a property */ +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_property_set (OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name, +                                   const void *data, int len) +{ +    OF_prop_t *prop; +    void *tmp; + +    if (node == NULL) +        return NULL; +    prop = OF_property_get(env, node, name); +    if (prop != NULL) { +        OF_DPRINTF("change property [%s]\n", name); +        tmp = malloc(len); +        if (tmp == NULL && len != 0) { +            ERROR("%s cannot set property '%s'\n", __func__, name); +            return NULL; +        } +        free(prop->value); +        prop->value = tmp; +        prop->vlen = len; +        memcpy(prop->value, data, len); +        if (prop->cb != NULL) { +            (*prop->cb)(env, prop, data, len); +        } +    } else { +        OF_DPRINTF("new property [%s]\n", name); +        prop = OF_property_new(env, node, name, data, len); +    } + +    return prop; +} + +__attribute__ (( section (".OpenFirmware") )) +static int OF_property_len (OF_env_t *env, OF_node_t *node, +                            const unsigned char *name) +{ +    OF_prop_t *prop; + +    prop = OF_property_get(env, node, name); +    if (prop == NULL) +        return -1; +     +    return prop->vlen; +} + +__attribute__ (( section (".OpenFirmware") )) +static unsigned char *hex2buf (unsigned char *buf, uint32_t value, int fill) +{ +    int pos, d; +     +    buf[8] = '\0'; +    pos = 7; +    if (value == 0) { +        buf[pos--] = '0'; +    } else { +        for (; value != 0; pos--) { +            d = value & 0xF; +            if (d > 9) +            d += 'a' - '0' - 10; +            buf[pos] = d + '0'; +            value = value >> 4; +        } +    } +    if (fill != 0) { +        for (; pos != -1; pos--) { +            buf[pos] = '0'; +        } +    } + +    return &buf[pos]; +} + +__attribute__ (( section (".OpenFirmware") )) +static int OF_property_copy (OF_env_t *env, void *buffer, int maxlen, +                             OF_node_t *node, const unsigned char *name) +{ +    unsigned char tmp[OF_PROPLEN_MAX]; +    OF_prop_t *prop; +    int len; + +    prop = OF_property_get(env, node, name); +    if (prop == NULL) { +        ERROR("%s cannot get property '%s' for %s\n", __func__, name, +              node->prop_name->value); +        return -1; +    } +    len = prop->vlen > maxlen ? maxlen : prop->vlen; +    if (prop->value != NULL) { +        tmp[0] = '0'; +        tmp[1] = 'x'; +        hex2buf(tmp + 2, *((uint32_t *)prop->value), 1); +    } else { +        *tmp = '\0'; +    } +    OF_DPRINTF("copy property [%s] len=%d to %p len=%d\n", +               name, prop->vlen, buffer, maxlen); +    if (strcmp(name, "name") == 0) { +        OF_DPRINTF("=> '%s'\n", prop->value); +    } +    memcpy(buffer, prop->value, len); +    //    OF_DPRINTF("done\n"); + +    return len; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_property_next (OF_env_t *env, OF_node_t *node, +                                    const unsigned char *name) +{ +    OF_prop_t *prop, *next; + +    if (name == NULL || *name == '\0') { +        next = node->properties; +    } else { +        prop = OF_property_get(env, node, name); +        if (prop == NULL) { +            OF_DPRINTF("Property [%s] not found\n", name); +            next = NULL; +        } else { +            next = prop->next; +            /* Skip address if not set */ +            if (next == node->prop_address && +                *((uint32_t *)next->value) == OF_ADDRESS_NONE) +                next = next->next; +        } +    } +#if 0 +    OF_DPRINTF("Found property %p\n", next); +#endif + +    return next; +} + +/* Simplified helpers */ +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_prop_string_new (OF_env_t *env, OF_node_t *node, +                                      const unsigned char *name, +                                      const unsigned char *string) +{ +#ifdef DEBUG_OF +    { +        OF_prop_t *prop; +        prop = OF_property_get(env, node, name); +        if (prop != NULL) { +            printf("Property '%s' already present !\n", name); +            bug(); +        } +    } +#endif +    return OF_property_new(env, node, name, +                           string, strlen(string) + 1); +} + +/* convert '\1' char to '\0' */ +static OF_prop_t *OF_prop_string_new1 (OF_env_t *env, OF_node_t *node, +                                       const unsigned char *name, +                                       const unsigned char *string) +{ +    int len, i; +    OF_prop_t *ret; +    unsigned char *str; + +    if (strchr(string, '\1') == NULL) { +        return OF_prop_string_new(env, node, name, string); +    } else { +        len = strlen(string) + 1; +        str = malloc(len); +        if (!str) +            return NULL; +        memcpy(str, string, len); +        for(i = 0; i < len; i++) +            if (str[i] == '\1') +                str[i] = '\0'; +        ret = OF_property_new(env, node, name, +                              str, len); +        free(str); +        return ret; +    } +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name, uint32_t value) +{ +#ifdef DEBUG_OF +    { +        OF_prop_t *prop; +        prop = OF_property_get(env, node, name); +        if (prop != NULL) { +            printf("Property '%s' already present !\n", name); +            bug(); +        } +    } +#endif +    return OF_property_new(env, node, name, &value, sizeof(uint32_t)); +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_prop_string_set (OF_env_t *env, OF_node_t *node, +                                      const unsigned char *name, +                                      const unsigned char *string) +{ +    const unsigned char *tmp; + +    tmp = strdup(string); +    if (tmp == NULL) { +        ERROR("%s cannot duplicate property '%s'\n", __func__, name); +        return NULL; +    } + +    return OF_property_set(env, node, name, tmp, strlen(string) + 1); +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_prop_t *OF_prop_int_set (OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name, uint32_t value) +{ +    return OF_property_set(env, node, name, &value, sizeof(uint32_t)); +} + +__attribute__ (( section (".OpenFirmware") )) +unused +static OF_prop_t *OF_set_compatibility (OF_env_t *env, OF_node_t *node, +                                        const unsigned char *compat) +{ +    return OF_prop_string_new(env, node, "compatible", compat); +} + +__attribute__ (( section (".OpenFirmware") )) +static inline void OF_property_set_cb (unused OF_env_t *OF_env, +                                       OF_prop_t *prop, +                                       void (*cb)(OF_env_t *OF_env, +                                                  OF_prop_t *prop, +                                                  const void *data, int len)) +{ +    prop->cb = cb; +} + +/*****************************************************************************/ +/*                       Packages methods management                         */ +__attribute__ (( section (".OpenFirmware") )) +static OF_method_t *OF_method_new (unused OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name, OF_cb_t cb) +{ +    OF_method_t *new; + +    new = malloc(sizeof(OF_method_t)); +    if (new == NULL) { +        ERROR("%s cannot allocate method '%s'\n", __func__, name); +        return NULL; +    } +    memset(new, 0, sizeof(OF_method_t)); +    new->node = node; +    new->name = strdup(name); +    if (new->name == NULL) { +        free(new); +        ERROR("%s cannot allocate method '%s' name\n", __func__, name); +        return NULL; +    } +    OF_DPRINTF("new method name %p %s\n", new, new->name); +    new->func = cb; +    /* Link it */ +    /* *SHOULD LOCK* */ +    if (node->method_last == NULL) +        node->methods = new; +    else +        node->method_last->next = new; +    node->method_last = new; + +    return new; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_method_t *OF_method_get (unused OF_env_t *env, OF_node_t *node, +                                   const unsigned char *name) +{ +    OF_method_t *parse; + +    if (node == NULL) { +        OF_DPRINTF("No method in NULL package !\n"); +        return NULL; +    } +#if 0 +    OF_DPRINTF("Look for method %s in package %0x\n", +               name, node->pack_id); +#endif +    for (parse = node->methods; parse != NULL; parse = parse->next) { +#if 0 +        OF_DPRINTF("check %p %p\n", parse, parse->name); +        OF_DPRINTF("name=%s\n", parse->name); +#endif +        if (strcmp(parse->name, name) == 0) +            return parse; +    } + +    return NULL; +} + +/*****************************************************************************/ +/*                     Packages instances management                         */ +__attribute__ (( section (".OpenFirmware") )) +static uint16_t OF_inst_new_id (unused OF_env_t *env, OF_node_t *node) +{ +    OF_inst_t *tmp_inst; +    uint16_t cur_id; + +#if 0 +    OF_DPRINTF("[%s] %d\n", node->prop_name->value, +               inst_last_id); +#endif +    for (cur_id = inst_last_id + 1; +         cur_id != inst_last_id; cur_id++) { +        if (cur_id == (uint16_t)(OF_MAX_PACKAGE)) +            cur_id = 0; +        for (tmp_inst = node->instances; tmp_inst != NULL; +             tmp_inst = tmp_inst->next) { +            if (tmp_inst->inst_id == cur_id) +                continue; +        } +        inst_last_id = cur_id; +#if 1 +        OF_DPRINTF("0x%0x\n", cur_id); +#endif +        return cur_id; +    } +    OF_DPRINTF("no ID found\n"); + +    return (uint16_t)(-1); +} + +/* Create a new package's instance */ +__attribute__ (( section (".OpenFirmware") )) +static OF_inst_t *OF_instance_new (OF_env_t *env, OF_node_t *node) +{ +    OF_inst_t *new, *parent; +    uint16_t new_id; + +    /* TODO: recurse to root... */ +    new = malloc(sizeof(OF_inst_t)); +    if (new == NULL) { +        ERROR("%s cannot allocate instance of '%s'\n", __func__, +              node->prop_name->value); +        return NULL; +    } +    memset(new, 0, sizeof(OF_inst_t)); +    if (OF_node_parent(env, node) != NULL) { +        parent = OF_instance_new(env, OF_node_parent(env, node)); +        if (parent == NULL) { +            free(new); +            ERROR("%s cannot allocate instance of '%s' parent\n", __func__, +                  node->prop_name->value); +            return NULL; +        } +        new->parent = parent; +    } else { +        new->parent = NULL; +    } +    new_id = OF_inst_new_id(env, node); +    if (new_id == (uint16_t)(-1)) { +        free(new); +        return NULL; +    } +    new->inst_id = new_id; +    new->node = node; +    /* Link it */ +    /* SHOULD LOCK */ +    if (node->inst_last == NULL) +        node->instances = new; +    else +        node->inst_last->next = new; +    node->inst_last = new; + +    return new; +} + +__attribute__ (( section (".OpenFirmware") )) +static uint32_t OF_instance_get_id (unused OF_env_t *env, OF_inst_t *instance) +{ +    OF_DPRINTF("p: %0x i: %0x\n", instance->node->pack_id, instance->inst_id); +    return (instance->node->pack_id << 16) | instance->inst_id; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_inst_t *OF_inst_find (OF_env_t *env, uint32_t ihandle) +{ +    OF_node_t *node; +    OF_inst_t *parse; +    uint16_t phandle = ihandle >> 16; + +    ihandle &= 0xFFFF; +    OF_DPRINTF("p: %0x i: %0x\n", phandle, ihandle); +    if (ihandle > OF_MAX_PACKAGE) +        return NULL; +    node = OF_pack_find(env, phandle); +    if (node == NULL) +        return NULL; +    for (parse = node->instances; parse != NULL; parse = parse->next) { +        if (parse->inst_id == ihandle) +            return parse; +    } + +    return NULL; +} + +#if 0 +__attribute__ (( section (".OpenFirmware") )) +static OF_inst_t *OF_inst_get_child (OF_env_t *env, OF_node_t *parent, +                                     const uint32_t handle) +{ +    OF_node_t *parse, *tmp; + +    for (parse = parent->children; parse != NULL; parse = parse->next) { +        if (parse->pack_id == (handle >> 16)) { +            return NULL; +        } +        tmp = OF_inst_get_child(env, parse, handle); +        if (tmp != NULL) +            return tmp; +    } + +    return NULL; +} + +__attribute__ (( section (".OpenFirmware") )) +static OF_inst_t *OF_inst_get (OF_env_t *env, const unsigned char *name) +{ +    return _OF_node_get(env, &OF_node_root); +     +} +#endif + +#if 0 +__attribute__ (( section (".OpenFirmware") )) +int get_node_name (OF_env_t *env, unsigned char *name, +                   int len, OF_node_t *node) +{ +    int tmp, total; +    int i; + +    /* Set up manufacturer name */ +    total = 0; +    tmp = 0; +#if 0 +    if (OF_node_parent(env, node) == NULL || +        node->manufct != OF_node_parent(env, node)->manufct) { +        tmp = strlen(node->manufct); +        if ((tmp + 2) > len) +            return -1; +        memcpy(name, node->manufct, tmp); +        name += tmp; +    } else if (len < 2) { +        return -1; +    } +    *name++ = ','; +    len -= tmp + 1; +    total += tmp + 1; +#endif +    /* Set up device model */ +    tmp = strlen(node->name); +    if ((tmp + 2) > len) +        return -1; +    memcpy(name, node->model, tmp); +    name += tmp; +    *name++ = '@'; +    len -= tmp + 1; +    total += tmp + 1; +    /* Set up unit address */ +    tmp = strlen(node->address); +    if ((tmp + 2) > len) +        return -1; +    memcpy(name, node->address, tmp); +    name += tmp; +    *name++ = ':'; +    len -= tmp + 1; +    total += tmp + 1; +    for (i = 0; node->arguments[i] != NULL; i++) { +        if (i != 0) +            *name++ = ','; +        tmp = strlen(node->arguments[i]); +        if ((tmp + 2) > len) +            return -1; +        memcpy(name, node->arguments[i], tmp); +        name += tmp; +        len -= tmp + 1; +        total += tmp + 1; +    } +    *name = '\0'; + +    return total; +} +#endif + +__attribute__ (( section (".OpenFirmware") )) +static int OF_pack_get_path (OF_env_t *env, unsigned char *name, +                             int len, OF_node_t *node) +{ +    OF_prop_t *prop_name, *prop_address; +    uint32_t address; +    int tmp, nlen; + +    /* Recurse until we reach the root node */ +    OF_DPRINTF("look for [%s]\n", node->prop_name->value); +    if (OF_node_parent(env, node) == NULL) { +        name[0] = '/'; +        tmp = 0; +        nlen = 1; +    } else { +        tmp = OF_pack_get_path(env, name, len, OF_node_parent(env, node)); +        /* Add node name */ +        prop_name = node->prop_name; +        prop_address = node->prop_address; +#if 1 +        OF_DPRINTF("Found [%s]\n", prop_name->value); +#endif +        if ((len - tmp) < 2) { +            OF_DPRINTF("Buffer too short (%d 2)\n", len - tmp); +            return 0; +        } +        if (prop_name == NULL) { +            printf("No name in node !\n"); +            bug(); +        } +        nlen = strlen(prop_name->value); +#if 1 +        OF_DPRINTF("got '%s' for '%s' parent (%d %d)\n", +                   name, prop_name->value, tmp, nlen); +#endif +        if (name[tmp - 1] != '/') { +            name[tmp] = '/'; +            tmp++; +        } +        address = *((uint32_t *)prop_address->value); +        if (address != OF_ADDRESS_NONE) { +            if ((len - tmp - nlen) < 10) { +                OF_DPRINTF("Buffer too short (%d %d)\n", len - tmp, nlen + 10); +                return 0; +            } +        } else { +            if ((len - tmp - nlen) < 1) { +                OF_DPRINTF("Buffer too short (%d %d)\n", len - tmp, nlen + 1); +                return 0; +            } +        } +        memcpy(name + tmp, prop_name->value, nlen); +        if (address != OF_ADDRESS_NONE) { +            OF_DPRINTF("Add address 0x%08x\n", address); +            sprintf(name + tmp + nlen, "@%x", address); +            nlen += strlen(name + tmp + nlen); +        } else { +            OF_DPRINTF("No address....\n"); +        } +    } +    name[tmp + nlen] = '\0'; +    OF_DPRINTF("stored [%d]\n", tmp + nlen); +    OF_DUMP_STRING(env, name); +#if 1 +    OF_DPRINTF("name '%s' => '%s' %d\n", +               node->properties->value, name, tmp + nlen); +#endif + +    return tmp + nlen; +} + +__attribute__ (( section (".OpenFirmware") )) +static int OF_inst_get_path (OF_env_t *env, unsigned char *name, +                             int len, OF_inst_t *inst) +{ +    return OF_pack_get_path(env, name, len, inst->node); +} + +/*****************************************************************************/ +/*                       Open firmware C interface                           */ +static void OF_serial_write (OF_env_t *OF_env); +static void OF_serial_read (OF_env_t *OF_env); +static void OF_mmu_translate (OF_env_t *OF_env); +static void OF_mmu_map (OF_env_t *OF_env); +static void RTAS_instantiate (OF_env_t *RTAS_env); + +static OF_env_t *OF_env_main; + +/* Init standard OF structures */ +__attribute__ (( section (".OpenFirmware") )) +int OF_init (void) +{ +#if 0 +        "PowerMac3,1\0MacRISC\0Power Macintosh\0"; +        "PowerMac1,2\0MacRISC\0Power Macintosh\0"; +        "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0"; +        "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0"; +        "AAPL,Gossamer\0MacRISC\0Power Macintosh\0"; +#endif +    OF_env_t *OF_env; +    OF_node_t *als, *opt, *chs, *pks; +    OF_inst_t *inst; +    OF_range_t range; + +    OF_DPRINTF("start\n"); +    OF_env_main = malloc(sizeof(OF_env_t)); +    if (OF_env_main == NULL) { +        ERROR("%s cannot allocate main OF env\n", __func__); +        return -1; +    } +    //    memset(OF_env_main, 0, sizeof(OF_env_t)); +    OF_env = OF_env_main; +    //    OF_env_init(OF_env); + +    OF_DPRINTF("start\n"); +    /* Set up standard IEEE 1275 nodes */ +    /* "/device-tree" */ +    OF_node_root = OF_node_new(OF_env, NULL, "device-tree", OF_ADDRESS_NONE); +    if (OF_node_root == NULL) { +        ERROR("Cannot create 'device-tree'\n"); +        return -1; +    } +    OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom"); +    if (arch == ARCH_HEATHROW) { +        const unsigned char compat_str[] = +            "PowerMac1,1\0MacRISC\0Power Macintosh"; +        OF_property_new(OF_env, OF_node_root, "compatible", +                        compat_str, sizeof(compat_str)); +    OF_prop_string_new(OF_env, OF_node_root, +                           "model", "Power Macintosh"); +    } else { +        const unsigned char compat_str[] = +            "PowerMac3,1\0MacRISC\0Power Macintosh"; +    OF_property_new(OF_env, OF_node_root, "compatible", +                    compat_str, sizeof(compat_str)); +        OF_prop_string_new(OF_env, OF_node_root, +                           "model", "PowerMac3,1"); +    } +#if 0 +    OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright); +#else +    OF_prop_string_new(OF_env, OF_node_root, "copyright", +            "Copyright 1983-1999 Apple Computer, Inc. All Rights Reserved"); +#endif +    OF_prop_string_new(OF_env, OF_node_root, "system-id", "42"); +    OF_prop_int_new(OF_env, OF_node_root, "#address-cells", 1); +    OF_prop_int_new(OF_env, OF_node_root, "#size-cells", 1); +    OF_prop_int_new(OF_env, OF_node_root, "clock-frequency", 0x05F03E4D); +    /* "/aliases" node */ +    als = OF_node_new(OF_env, OF_node_root, "aliases", OF_ADDRESS_NONE); +    if (als == NULL) { +        ERROR("Cannot create 'aliases'\n"); +        return -1; +    } +    /* "/chosen" node */ +    chs = OF_node_new(OF_env, OF_node_root, "chosen", OF_ADDRESS_NONE); +    if (chs == NULL) { +        ERROR("Cannot create 'choosen'\n"); +        return -1; +    } +    /* "/packages" node */ +    pks = OF_node_new(OF_env, OF_node_root, "packages", OF_ADDRESS_NONE); +    if (pks == NULL) { +        ERROR("Cannot create 'packages'\n"); +        return -1; +    } +    /* "/cpus" node */ +    { +        OF_node_t *cpus; +        cpus = OF_node_new(OF_env, OF_node_root, "cpus", OF_ADDRESS_NONE); +        if (cpus == NULL) { +            ERROR("Cannot create 'cpus'\n"); +            return -1; +        } +        OF_prop_int_new(OF_env, cpus, "#address-cells", 1); +        OF_prop_int_new(OF_env, cpus, "#size-cells", 0); +        OF_node_put(OF_env, cpus); +    } +    /* "/memory@0" node */ +    { +        OF_node_t *mem; +        mem = OF_node_new(OF_env, OF_node_root, "memory", 0); +        if (mem == NULL) { +            ERROR("Cannot create 'memory'\n"); +            return -1; +        } +        OF_prop_string_new(OF_env, mem, "device_type", "memory"); +        OF_prop_int_new(OF_env, chs, "memory", OF_pack_handle(OF_env, mem)); +        OF_node_put(OF_env, mem); +    } +    /* "/openprom" node */ +    { +        OF_node_t *opp; +        opp = OF_node_new(OF_env, OF_node_root, "openprom", OF_ADDRESS_NONE); +        if (opp == NULL) { +            ERROR("Cannot create 'openprom'\n"); +            return -1; +        } +        OF_prop_string_new(OF_env, opp, "device_type", "BootROM"); +        OF_prop_string_new(OF_env, opp, "model", "OpenFirmware 3"); +        OF_prop_int_new(OF_env, opp, "boot-syntax", 0x0001); +        OF_property_new(OF_env, opp, "relative-addressing", NULL, 0); +        OF_property_new(OF_env, opp, "supports-bootinfo", NULL, 0); +        OF_prop_string_new(OF_env, opp, "built-on", stringify(BUILD_DATE)); +        OF_prop_string_new(OF_env, als, "rom", "/openprom"); +        OF_node_put(OF_env, opp); +    } +    /* "/options" node */ +    opt = OF_node_new(OF_env, OF_node_root, "options", OF_ADDRESS_NONE); +    if (opt == NULL) { +        ERROR("Cannot create 'options'\n"); +        return -1; +    } +    OF_prop_string_new(OF_env, opt, "little-endian?", "false"); +    OF_prop_string_new(OF_env, opt, "real-mode?", "false"); +    // Will play with this... +    OF_prop_string_new(OF_env, opt, "security-mode", "none"); +    /* "/rom@ff800000" node */ +    { +        OF_regprop_t regs; +        OF_node_t *rom, *brom; + +        rom = OF_node_new(OF_env, OF_node_root, "rom", 0xff800000); +        if (rom == NULL) { +            ERROR("Cannot create 'rom'\n"); +            return -1; +        } +        regs.address = 0xFF800000; +        regs.size = 0x00000000; +        OF_property_new(OF_env, rom, "reg", ®s, sizeof(OF_regprop_t)); +        range.virt = 0xFF800000; +        range.phys = 0xFF800000; +        range.size = 0x00800000; +        OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t)); +        OF_prop_int_new(OF_env, rom, "#address-cells", 1); + +        /* "/rom/boot-rom@fff00000" node */ +        brom = OF_node_new(OF_env, rom, "boot-rom", 0xfff00000); +        if (brom == NULL) { +            ERROR("Cannot create 'boot-rom'\n"); +            return -1; +        } +        regs.address = 0xFFF00000; +        regs.size = 0x00100000; +        OF_property_new(OF_env, brom, "reg", ®s, sizeof(OF_regprop_t)); +        OF_prop_string_new(OF_env, brom, "write-characteristic", "flash"); +        OF_prop_string_new(OF_env, brom, "BootROM-build-date", +                           stringify(BUILD_DATE) " at " stringify(BUILD_TIME)); +        OF_prop_string_new(OF_env, brom, "BootROM-version", BIOS_VERSION); +        OF_prop_string_new(OF_env, brom, "copyright", copyright); +        OF_prop_string_new(OF_env, brom, "model", BIOS_str); +        OF_prop_int_new(OF_env, brom, "result", 0); +#if 1 +        { +            /* Hack taken 'as-is' from PearPC */ +            unsigned char info[] = { +                0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, +                0x00, 0x01, 0x12, 0xf2, 0x19, 0x99, 0x08, 0x19, +                0x94, 0x4e, 0x73, 0x27, 0xff, 0xf0, 0x80, 0x00, +                0x00, 0x07, 0x80, 0x01, 0x00, 0x01, 0x12, 0xf2, +                0x19, 0x99, 0x08, 0x19, 0xd7, 0xf3, 0xfc, 0x17, +                0xff, 0xf8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, +                0x00, 0x01, 0x12, 0xf2, 0x19, 0x99, 0x08, 0x19, +                0xbb, 0x10, 0xfc, 0x17, +            }; +            OF_property_new(OF_env, brom, "info", info, sizeof(info)); +        } +#endif +        OF_node_put(OF_env, brom); +        OF_node_put(OF_env, rom); +    } +#if 0 +    /* From here, hardcoded hacks to get a Mac-like machine */ +    /* XXX: Core99 does not seem to like this NVRAM tree */ +    /* "/nvram@fff04000" node */ +    { +        OF_regprop_t regs; +        OF_node_t *nvr; + +        nvr = OF_node_new(OF_env, OF_node_root, "nvram", 0xfff04000); +        if (nvr == NULL) { +            ERROR("Cannot create 'nvram'\n"); +            return -1; +        } +        OF_prop_string_new(OF_env, nvr, "device_type", "nvram"); +        /* XXX: use real NVRAM size instead */ +        OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000); +        OF_prop_string_new(OF_env, nvr, "compatible", "nvram,flash"); +        regs.address = 0xFFF04000; +        regs.size = 0x00004000; /* Strange, isn't it ? */ +        OF_property_new(OF_env, nvr, "reg", ®s, sizeof(regs)); +        OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr)); +        OF_node_put(OF_env, nvr); +    } +#endif +    /* "/pseudo-hid" : hid emulation as Apple does */ +    { +        OF_node_t *hid; + +        hid = OF_node_new(OF_env, OF_node_root, +                          "pseudo-hid", OF_ADDRESS_NONE); +        if (hid == NULL) { +            ERROR("Cannot create 'pseudo-hid'\n"); +            return -1; +        } +         +        /* "keyboard" node */ +        { +            OF_node_t *kbd; +            kbd = OF_node_new(OF_env, hid, "keyboard", OF_ADDRESS_NONE); +            if (kbd == NULL) { +                ERROR("Cannot create 'keyboard'\n"); +                return -1; +            } +            OF_prop_string_new(OF_env, kbd, "device_type", "keyboard"); +            OF_node_put(OF_env, kbd); +        } +        /* "mouse" node */ +        { +            OF_node_t *mouse; +            mouse = OF_node_new(OF_env, hid, "mouse", OF_ADDRESS_NONE); +            if (mouse == NULL) { +                ERROR("Cannot create 'mouse'\n"); +                return -1; +            } +            OF_prop_string_new(OF_env, mouse, "device_type", "mouse"); +            OF_node_put(OF_env, mouse); +        } +        /* "eject-key" node */ +        { +            OF_node_t *ejk; +            ejk = OF_node_new(OF_env, hid, "eject-key", OF_ADDRESS_NONE); +            if (ejk == NULL) { +                ERROR("Cannot create 'eject-key'\n"); +                return -1; +            } +            OF_prop_string_new(OF_env, ejk, "device_type", "eject-key"); +            OF_node_put(OF_env, ejk); +        } +        OF_node_put(OF_env, hid); +    } +    if (arch == ARCH_MAC99) { +        OF_node_t *unin; +        OF_regprop_t regs; + +        unin = OF_node_new(OF_env, OF_node_root, +                           "uni-n", 0xf8000000); +        if (unin == NULL) { +            ERROR("Cannot create 'uni-n'\n"); +            return -1; +        } +        OF_prop_string_new(OF_env, unin, "device-type", "memory-controller"); +        OF_prop_string_new(OF_env, unin, "model", "AAPL,UniNorth"); +        OF_prop_string_new(OF_env, unin, "compatible", "uni-north"); +        regs.address = 0xf8000000; +        regs.size = 0x01000000; +        OF_property_new(OF_env, unin, "reg", ®s, sizeof(regs)); +        OF_prop_int_new(OF_env, unin, "#address-cells", 1); +        OF_prop_int_new(OF_env, unin, "#size-cells", 1); +        OF_prop_int_new(OF_env, unin, "device-rev", 3); +        OF_node_put(OF_env, unin); +    } +     +#if 1 /* This is mandatory for claim to work +       * but I don't know where it should really be (in cpu ?) +       */ +    { +        OF_node_t *mmu; + +        /* "/mmu" node */ +        mmu = OF_node_new(OF_env, OF_node_root, "mmu", OF_ADDRESS_NONE); +        if (mmu == NULL) { +            ERROR("Cannot create 'mmu'\n"); +            return -1; +        } +        inst = OF_instance_new(OF_env, mmu); +        if (inst == NULL) { +            OF_node_put(OF_env, mmu); +            ERROR("Cannot create 'mmu' instance\n"); +            return -1; +        } +        OF_prop_int_new(OF_env, chs, "mmu", +                        OF_instance_get_id(OF_env, inst)); +        OF_method_new(OF_env, mmu, "translate", &OF_mmu_translate); +        OF_method_new(OF_env, mmu, "map", &OF_mmu_map); +        OF_node_put(OF_env, mmu); +    } +#endif + +    /* "/options/boot-args" node */ +    { +        //        const unsigned char *args = "-v rootdev cdrom"; +        //const unsigned char *args = "-v io=0xffffffff"; +        const unsigned char *args = "-v"; +        /* Ask MacOS X to print debug messages */ +        //        OF_prop_string_new(OF_env, chs, "machargs", args); +        //        OF_prop_string_new(OF_env, opt, "boot-command", args); +        OF_prop_string_new(OF_env, opt, "boot-args", args); +    } +     +    /* Release nodes */ +    OF_node_put(OF_env, opt); +    OF_node_put(OF_env, pks); +    OF_node_put(OF_env, chs); +    OF_node_put(OF_env, als); +    OF_node_put(OF_env, OF_node_root); +    OF_DPRINTF("done\n"); +     +    return 0; +} + +/* Motherboard */ +#if 0 // For now, static values are used +__attribute__ (( section (".OpenFirmware") )) +int OF_register_mb (const unsigned char *model, const unsigned char **compats) +{ +    OF_env_t *OF_env; +    OF_node_t *root; +    int i; +     +    OF_env = OF_env_main; +    OF_DPRINTF("start\n"); +    root = OF_node_get(OF_env, "device_tree"); +    if (root == NULL) { +        ERROR("Cannot get 'device-tree'\n"); +        return -1; +    } +    OF_DPRINTF("add model\n"); +    OF_prop_string_new(OF_env, OF_node_root, "model", model); +    for (i = 0; i < 1 && compats[i] != NULL; i++) { +        OF_DPRINTF("add compats %s\n", compats[i]); +        OF_set_compatibility(OF_env, OF_node_root, compats[i]); +    } +    /* we don't implement neither "l2-cache" nor "cache" nodes */ +    OF_node_put(OF_env, root); +    OF_DPRINTF("done\n"); + +    return 0; +} +#endif + +/* CPU */ +__attribute__ (( section (".OpenFirmware") )) +int OF_register_cpu (const unsigned char *name, int num, uint32_t pvr, +                     uint32_t min_freq, uint32_t max_freq, uint32_t bus_freq, +                     uint32_t tb_freq, uint32_t reset_io) +{ +    unsigned char tmp[OF_NAMELEN_MAX]; +    OF_env_t *OF_env; +    OF_node_t *cpus, *cpu, *l2c, *chs, *als; + +    OF_env = OF_env_main; +    OF_DPRINTF("start\n"); +    cpus = OF_node_get(OF_env, "cpus"); +    if (cpus == NULL) { +        ERROR("Cannot get 'cpus'\n"); +        return -1; +    } +    cpu = OF_node_new(OF_env, cpus, name, OF_ADDRESS_NONE); +    if (cpu == NULL) { +        OF_node_put(OF_env, cpus); +        ERROR("Cannot create cpu '%s'\n", name); +        return -1; +    } +    OF_prop_string_new(OF_env, cpu, "device_type", "cpu"); +    OF_prop_int_new(OF_env, cpu, "#address-cells", 0x00000001); +    OF_prop_int_new(OF_env, cpu, "#size-cells", 0x00000000); +    OF_prop_int_new(OF_env, cpu, "reg", num); +    OF_prop_int_new(OF_env, cpu, "cpu-version", pvr); +    OF_prop_int_new(OF_env, cpu, "clock-frequency", max_freq); +    OF_prop_int_new(OF_env, cpu, "timebase-frequency", tb_freq); +    OF_prop_int_new(OF_env, cpu, "bus-frequency", bus_freq); +    OF_prop_int_new(OF_env, cpu, "min-clock-frequency", min_freq); +    OF_prop_int_new(OF_env, cpu, "max-clock-frequency", max_freq); +    OF_prop_int_new(OF_env, cpu, "tlb-size", 0x80); +    OF_prop_int_new(OF_env, cpu, "tlb-sets", 0x40); +    OF_prop_int_new(OF_env, cpu, "i-tlb-size", 0x40); +    OF_prop_int_new(OF_env, cpu, "i-tlb-sets", 0x20); +    OF_prop_int_new(OF_env, cpu, "i-cache-size", 0x8000); +    OF_prop_int_new(OF_env, cpu, "i-cache-sets", 0x80); +    OF_prop_int_new(OF_env, cpu, "i-cache-bloc-size", 0x20); +    OF_prop_int_new(OF_env, cpu, "i-cache-line-size", 0x20); +    OF_prop_int_new(OF_env, cpu, "d-tlb-size", 0x40); +    OF_prop_int_new(OF_env, cpu, "d-tlb-sets", 0x20); +    OF_prop_int_new(OF_env, cpu, "d-cache-size", 0x8000); +    OF_prop_int_new(OF_env, cpu, "d-cache-sets", 0x80); +    OF_prop_int_new(OF_env, cpu, "d-cache-bloc-size", 0x20); +    OF_prop_int_new(OF_env, cpu, "d-cache-line-size", 0x20); +    OF_prop_int_new(OF_env, cpu, "reservation-granule-size", 0x20); +    OF_prop_int_new(OF_env, cpus, "soft-reset", reset_io); +    OF_prop_string_new(OF_env, cpus, "graphics", ""); +    OF_prop_string_new(OF_env, cpus, "performance-monitor", ""); +    OF_prop_string_new(OF_env, cpus, "data-streams", ""); +    OF_prop_string_new(OF_env, cpu, "state", "running"); +    /* We don't implement: +     * "dynamic-powerstep" & "reduced-clock-frequency" +     * "l2cr-value" +     */ +    /* Add L2 cache */ +    l2c = OF_node_new(OF_env, cpu, "l2cache", OF_ADDRESS_NONE); +    if (l2c == NULL) { +        ERROR("Cannot create 'l2cache'\n"); +        return -1; +    } +    OF_prop_string_new(OF_env, l2c, "device_type", "cache"); +    OF_prop_int_new(OF_env, l2c, "i-cache-size", 0x100000); +    OF_prop_int_new(OF_env, l2c, "i-cache-sets", 0x2000); +    OF_prop_int_new(OF_env, l2c, "i-cache-line-size", 0x40); +    OF_prop_int_new(OF_env, l2c, "d-cache-size", 0x100000); +    OF_prop_int_new(OF_env, l2c, "d-cache-sets", 0x2000); +    OF_prop_int_new(OF_env, l2c, "d-cache-line-size", 0x40); +    /* Register it in the cpu node */ +    OF_prop_int_new(OF_env, cpu, "l2-cache", OF_pack_handle(OF_env, l2c)); +    OF_node_put(OF_env, l2c); +    /* Set it in "/chosen" and "/aliases" */ +    if (num == 0) { +        OF_pack_get_path(OF_env, tmp, 512, cpu); +        chs = OF_node_get(OF_env, "chosen"); +        if (chs == NULL) { +            OF_node_put(OF_env, cpus); +            ERROR("Cannot get 'chosen'\n"); +            return -1; +        } +        OF_prop_int_new(OF_env, chs, "cpu", OF_pack_handle(OF_env, cpu)); +        OF_node_put(OF_env, chs); +        als = OF_node_get(OF_env, "aliases"); +        if (als == NULL) { +            OF_node_put(OF_env, cpus); +            ERROR("Cannot get 'aliases'\n"); +            return -1; +        } +        OF_prop_string_new(OF_env, als, "cpu", tmp); +        OF_node_put(OF_env, als); +    } +    OF_node_put(OF_env, cpu); +    OF_node_put(OF_env, cpus); +    OF_DPRINTF("done\n"); + +    return 0; +} + +__attribute__ (( section (".OpenFirmware") )) +int OF_register_translations (int nb, OF_transl_t *translations) +{ +    OF_env_t *OF_env; +    OF_node_t *cpus, *cpu; +    OF_transl_t *new; +    int i; + +    OF_env = OF_env_main; +    OF_DPRINTF("start\n"); +    cpus = OF_node_get(OF_env, "cpus"); +    if (cpus == NULL) { +        OF_node_put(OF_env, cpus); +        ERROR("Cannot get 'cpus'\n"); +        return -1; +    } +    cpu = cpus->children; +    new = malloc(nb * sizeof(OF_transl_t)); +    if (new == NULL) { +        ERROR("Cannot create new translation\n"); +        return -1; +    } +    for (i = 0; i < nb; i++) { +        new->virt = translations[i].virt; +        new->size = translations[i].size; +        new->phys = translations[i].phys; +        new->mode = translations[i].mode; +        OF_DPRINTF("%d\n", i); +    } +    OF_property_new(OF_env, cpu, "translations", +                    new, nb * sizeof(OF_transl_t)); +    OF_node_put(OF_env, cpus); +    OF_DPRINTF("done\n"); +     +    return 0; +} + +/* Memory ranges */ +typedef struct OF_mem_t OF_mem_t; +struct OF_mem_t { +    uint32_t start; +    uint32_t size; +}; + +#define OF_MAX_MEMRANGES 16 +/* First entry is the whole known memory space */ +static OF_mem_t OF_mem_ranges[OF_MAX_MEMRANGES + 1]; + +__attribute__ (( section (".OpenFirmware") )) +int OF_register_memory (uint32_t memsize, unused uint32_t bios_size) +{ +    OF_env_t *OF_env; +    OF_node_t *mem; +    OF_regprop_t regs[4]; +    int i; + +    OF_env = OF_env_main; +    OF_DPRINTF("find node\n"); +    mem = OF_node_get(OF_env, "memory"); +    if (mem == NULL) { +        ERROR("Cannot get 'memory'\n"); +        return -1; +    } +    OF_DPRINTF("Memory package: %04x\n", OF_pack_handle(OF_env, mem)); +    regs[0].address = 0x00000000; +    regs[0].size = memsize; +    regs[1].address = 0x00000000; +    regs[1].size = 0x00000000; +    regs[2].address = 0x00000000; +    regs[2].size = 0x00000000; +    regs[3].address = 0x00000000; +    regs[3].size = 0x00000000; +    OF_property_new(OF_env, mem, "reg", regs, 4 * sizeof(OF_regprop_t)); +#if 0 +#if 1 +    regs[0].address = 0x00000000; +    regs[0].size = 0x05800000; +    regs[1].address = 0x06000000; +    regs[1].size = memsize - 0x06000000; +    regs[2].address = 0x00000000; +    regs[2].size = 0x00000000; +    OF_property_new(OF_env, mem, "available", +                    regs, 3 * sizeof(OF_regprop_t)); +#else +    regs[0].address = 0x06000000; +    regs[0].size = memsize - 0x06000000; +    regs[1].address = 0x00000000; +    regs[1].size = 0x00000000; +    OF_property_new(OF_env, mem, "available", +                    regs, 2 * sizeof(OF_regprop_t)); +#endif +#endif +    OF_node_put(OF_env, mem); +#if 0 +    { +        OF_node_t *mmu; +        mmu = OF_node_get(OF_env, "mmu"); +        if (mmu == NULL) { +            ERROR("Cannot get 'mmu'\n"); +            return -1; +        } +        regs[0].address = 0x00000000; +        regs[0].size = memsize; +        OF_property_new(OF_env, mmu, "reg", regs, sizeof(OF_regprop_t)); +        regs[0].address = 0x00000000; +        regs[0].size = 0x05800000; +        regs[1].address = 0x06000000; +        regs[1].size = memsize - 0x06000000; +        regs[2].address = 0x00000000; +        regs[2].size = 0x00000000; +        OF_property_new(OF_env, mmu, "available", +                        regs, 3 * sizeof(OF_regprop_t)); +        OF_node_put(OF_env, mmu); +    } +#endif +    /* Also update the claim areas */ +    OF_mem_ranges[0].start = 0x00000000; +    OF_mem_ranges[0].size = memsize; +    OF_mem_ranges[1].start = 0x58000000; +    OF_mem_ranges[1].size = 0x08000000; +    for (i = 2; i < OF_MAX_MEMRANGES + 1; i++) { +        OF_mem_ranges[i].start = -1; +        OF_mem_ranges[i].size = -1; +    } +    OF_DPRINTF("done\n"); + +    return 0; +} + +/* Linux kernel command line */ +__attribute__ (( section (".OpenFirmware") )) +int OF_register_bootargs (const unsigned char *bootargs) +{ +    OF_env_t *OF_env; +    OF_node_t *chs; + +    OF_env = OF_env_main; +    if (bootargs == NULL) +        bootargs = ""; +    chs = OF_node_get(OF_env, "chosen"); +    if (chs == NULL) { +        ERROR("Cannot get 'chosen'\n"); +        return -1; +    } +    OF_prop_string_set(OF_env, chs, "bootargs", bootargs); +    //        OF_prop_string_set(OF_env, OF_node_root, "bootargs", ""); +    OF_node_put(OF_env, chs); + +    return 0; +} + +__attribute__ (( section (".OpenFirmware") )) +static void *OF_pci_device_new (OF_env_t *OF_env, OF_node_t *parent, +                                pci_dev_t *dev, uint32_t address, +                                uint16_t rev, uint32_t ccode, +                                uint16_t min_grant, uint16_t max_latency) +{ +    OF_node_t *node; + +    dprintf("register '%s' '%s' '%s' '%s' 0x%08x in '%s' 0x%08x\n", +           dev->name, dev->type, dev->compat, dev->model, address, +           parent->prop_name->value, *(uint32_t *)parent->prop_address->value); +    node = OF_node_new(OF_env, parent, dev->name, address); +    if (node == NULL) +        return NULL; +    OF_prop_int_new(OF_env, node, "vendor-id", dev->vendor); +    OF_prop_int_new(OF_env, node, "device-id", dev->product); +    OF_prop_int_new(OF_env, node, "revision-id", rev); +    OF_prop_int_new(OF_env, node, "class-code", ccode); +    OF_prop_int_new(OF_env, node, "min-grant", min_grant); +    OF_prop_int_new(OF_env, node, "max-latency", max_latency); +    if (dev->type != NULL) +        OF_prop_string_new1(OF_env, node, "device_type", dev->type); +    if (dev->compat != NULL) +        OF_prop_string_new1(OF_env, node, "compatible", dev->compat); +    if (dev->model != NULL) +        OF_prop_string_new1(OF_env, node, "model", dev->model); +    if (dev->acells != 0) +        OF_prop_int_new(OF_env, node, "#address-cells", dev->acells); +    if (dev->scells != 0) +        OF_prop_int_new(OF_env, node, "#size-cells", dev->scells); +    if (dev->icells != 0) +        OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->icells); +    dprintf("Done %p %p\n", parent, node); +     +    return node; +} + +__attribute__ (( section (".OpenFirmware") )) +void *OF_register_pci_host (pci_dev_t *dev, uint16_t rev, uint32_t ccode, +                            uint32_t cfg_base, uint32_t cfg_len, +                            uint32_t mem_base, uint32_t mem_len, +                            uint32_t io_base, uint32_t io_len, +                            uint32_t rbase, uint32_t rlen, +                            uint16_t min_grant, uint16_t max_latency) +{ +    OF_env_t *OF_env; +    pci_range_t ranges[3]; +    OF_regprop_t regs[1]; +    OF_node_t *pci_host, *als; +    int nranges; +    unsigned char buffer[OF_NAMELEN_MAX]; + +    OF_env = OF_env_main; +    dprintf("register PCI host '%s' '%s' '%s' '%s'\n", +            dev->name, dev->type, dev->compat, dev->model); +    pci_host = OF_pci_device_new(OF_env, OF_node_root, dev, cfg_base, +                                 rev, ccode, min_grant, max_latency); +    if (pci_host == NULL) { +        ERROR("Cannot create pci host\n"); +        return NULL; +    } +     +    als = OF_node_get(OF_env, "aliases"); +    if (als == NULL) { +        ERROR("Cannot get 'aliases'\n"); +        return NULL; +    } +    sprintf(buffer, "/%s", dev->name); +    OF_prop_string_set(OF_env, als, "pci", buffer); +    OF_node_put(OF_env, als); +     + +    regs[0].address = cfg_base; +    regs[0].size = cfg_len; +    OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t)); +    nranges = 0; +    if (rbase != 0x00000000) { +        ranges[nranges].addr.hi  = 0x02000000; +        ranges[nranges].addr.mid = 0x00000000; +        ranges[nranges].addr.lo  = rbase; +        ranges[nranges].phys     = rbase; +        ranges[nranges].size_hi  = 0x00000000; +        ranges[nranges].size_lo  = rlen; +        nranges++; +    } +    if (io_base != 0x00000000) { +        ranges[nranges].addr.hi  = 0x01000000; +        ranges[nranges].addr.mid = 0x00000000; +        ranges[nranges].addr.lo  = 0x00000000; +        ranges[nranges].phys     = io_base; +        ranges[nranges].size_hi  = 0x00000000; +        ranges[nranges].size_lo  = io_len; +        nranges++; +    } +    if (mem_base != 0x00000000) { +        ranges[nranges].addr.hi  = 0x02000000; +        ranges[nranges].addr.mid = 0x00000000; +        ranges[nranges].addr.lo  = mem_base; +        ranges[nranges].phys     = mem_base; +        ranges[nranges].size_hi  = 0x00000000; +        ranges[nranges].size_lo  = mem_len; +        nranges++; +    } +    OF_property_new(OF_env, pci_host, "ranges", ranges, +                    nranges * sizeof(pci_range_t)); + +    return pci_host; +} + +__attribute__ (( section (".OpenFirmware") )) +void *OF_register_pci_bridge (void *parent, pci_dev_t *dev, +                              uint32_t cfg_base, uint32_t cfg_len, +                              uint8_t devfn, uint8_t rev, uint32_t ccode, +                              uint16_t min_grant, uint16_t max_latency) +{ +    OF_env_t *OF_env; +    OF_regprop_t regs[1]; +    OF_node_t *pci_bridge; + +    OF_env = OF_env_main; +    OF_DPRINTF("register '%s' %08x '%s' '%s' '%s'\n", +               dev->name, devfn >> 3, dev->type, dev->compat, dev->model); +    dprintf("register PCI bridge '%s' %08x '%s' '%s' '%s'\n", +            dev->name, devfn >> 3, dev->type, dev->compat, dev->model); +    pci_bridge = OF_pci_device_new(OF_env, parent, dev, devfn >> 3, +                                   rev, ccode, min_grant, max_latency); +    if (pci_bridge == NULL) { +        ERROR("Cannot create pci bridge\n"); +        return NULL; +    } +    regs[0].address = cfg_base; +    regs[0].size = cfg_len; +    OF_property_new(OF_env, pci_bridge, "reg", regs, sizeof(OF_regprop_t)); + +    return pci_bridge; +} + +__attribute__ (( section (".OpenFirmware") )) +void *OF_register_pci_device (void *parent, pci_dev_t *dev, +                              uint8_t devfn, uint8_t rev, uint32_t ccode, +                              uint16_t min_grant, uint16_t max_latency) +{ +    OF_env_t *OF_env; +    OF_node_t *pci_dev; + +    OF_env = OF_env_main; +    OF_DPRINTF("register '%s' %08x '%s' '%s' '%s'\n", +               dev->name, devfn >> 3, dev->type, dev->compat, dev->model); +    dprintf("register pci device '%s' %08x '%s' '%s' '%s'\n", +               dev->name, devfn >> 3, dev->type, dev->compat, dev->model); +    pci_dev = OF_pci_device_new(OF_env, parent, dev, devfn >> 3, +                                rev, ccode, min_grant, max_latency); + +    return pci_dev; +} + +/* XXX: suppress that, used for interrupt map init */ +OF_node_t *pci_host_node; +uint32_t pci_host_interrupt_map[7 * 32]; +int pci_host_interrupt_map_len = 0; + +void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses) +{ +    OF_env_t *OF_env; +    OF_regprop_t regs[1]; +     +    OF_env = OF_env_main; +    regs[0].address = first_bus; +    regs[0].size = nb_busses; +    OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t)); +    pci_host_node = dev; +} + +void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, +                             uint32_t *regions, uint32_t *sizes, +                             int irq_line) +{ +    OF_env_t *OF_env; +    pci_reg_prop_t pregs[6], rregs[6]; +    uint32_t mask; +    int i, j, k; + +    OF_env = OF_env_main; +    /* XXX: only useful for VGA card in fact */ +    if (regions[0] != 0x00000000) +        OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F); +    for (i = 0, j = 0, k = 0; i < 6; i++) { +        if (regions[i] != 0x00000000 && sizes[i] != 0x00000000) { +            /* Generate "reg" property +             */ +            if (regions[i] & 1) { +                /* IO space */ +                rregs[j].addr.hi = 0x01000000; +                mask = 0x00000001; +            } else if (regions[i] & 4) { +                /* 64 bits address space */ +                rregs[j].addr.hi = 0x83000000; +                mask = 0x0000000F; +#if 0 +            } else if ((regions[i] & 0xF) == 0x00) { /* ? */ +                /* Configuration space */ +                rregs[j].addr.hi = 0x00000000; +                mask = 0x0000000F; +#endif +            } else { +                /* 32 bits address space */ +                rregs[j].addr.hi = 0x82000000; +                mask = 0x0000000F; +            } +            /* Set bus number */ +            rregs[j].addr.hi |= bus << 16; +            /* Set device/function */ +            rregs[j].addr.hi |= devfn << 8; +            /* Set register */ +#if 1 +            rregs[j].addr.hi |= 0x10 + (i * sizeof(uint32_t)); /* ? */ +#endif +            /* Set address */ +            rregs[j].addr.mid = 0x00000000; +            rregs[j].addr.lo = regions[i] & ~mask; +            /* Set size */ +            rregs[j].size_hi = 0x00000000; +            rregs[j].size_lo = sizes[i]; +#if 0 +            if ((rregs[j].addr.hi & 0x03000000) != 0x00000000) +#endif +            { +                /* No assigned address for configuration space */ +                pregs[k].addr.hi = rregs[j].addr.hi; /* ? */ +                pregs[k].addr.mid = rregs[j].addr.mid; +                pregs[k].addr.lo = rregs[j].addr.lo; /* ? */ +                pregs[k].size_hi = rregs[j].size_hi; +                pregs[k].size_lo = rregs[j].size_lo; +                k++; +            } +            j++; +        } +    } +    if (j > 0) { +        OF_property_new(OF_env, dev, "reg", +                        rregs, j * sizeof(pci_reg_prop_t)); +    } else { +        OF_property_new(OF_env, dev, "reg", NULL, 0); +    } +    if (k > 0) { +        OF_property_new(OF_env, dev, "assigned-addresses", +                        pregs, k * sizeof(pci_reg_prop_t)); +    } else { +        OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0); +    } +    if (irq_line >= 0) { +        int i; +        OF_prop_int_new(OF_env, dev, "interrupts", 1); +        i = pci_host_interrupt_map_len; +        pci_host_interrupt_map[i++] = (devfn << 8) & 0xf800; +        pci_host_interrupt_map[i++] = 0; +        pci_host_interrupt_map[i++] = 0; +        pci_host_interrupt_map[i++] = 0; +        pci_host_interrupt_map[i++] = 0; /* pic handle will be patched later */ +        pci_host_interrupt_map[i++] = irq_line; +        if (arch != ARCH_HEATHROW) { +            pci_host_interrupt_map[i++] = 1; +        } +        pci_host_interrupt_map_len = i; +    } +#if 1 +    { +        OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name; + +        if (j > 0) { +            dprintf("PCI device '%s' %d %d %d reg properties:\n", +                    prop_name->value, bus, devfn >> 3, devfn & 7); +            for (i = 0; i < j; i++) { +                dprintf("  addr: %08x %08x %08x size: %08x %08x\n", +                        rregs[i].addr.hi, rregs[i].addr.mid, rregs[i].addr.lo, +                        rregs[i].size_hi, rregs[i].size_lo); +            } +        } else { +            dprintf("PCI device '%s' %d %d %d has no reg properties:\n", +                    prop_name->value, bus, devfn >> 3, devfn & 7); +        } +        if (k > 0) { +            dprintf("PCI device '%s' %d %d %d " +                    "assigned addresses properties:\n", +                    prop_name->value, bus, devfn >> 3, devfn & 7); +            for (i = 0; i < j; i++) { +                dprintf("  addr: %08x %08x %08x size: %08x %08x\n", +                        pregs[i].addr.hi, pregs[i].addr.mid, pregs[i].addr.lo, +                        pregs[i].size_hi, pregs[i].size_lo); +            } +        } else { +            dprintf("PCI device '%s' %d %d %d has no " +                    "assigned addresses properties:\n", +                    prop_name->value, bus, devfn >> 3, devfn & 7); +        } +    } +#endif +} + +__attribute__ (( section (".OpenFirmware") )) +int OF_register_bus (const unsigned char *name, uint32_t address, +                     const unsigned char *type) +{ +    unsigned char buffer[OF_NAMELEN_MAX]; +    OF_env_t *OF_env; +    OF_node_t *bus, *als; +     +    OF_env = OF_env_main; +    als = OF_node_get(OF_env, "aliases"); +    if (als == NULL) { +        ERROR("Cannot get 'aliases'\n"); +        return -1; +    } +    bus = OF_node_new(OF_env, OF_node_root, name, address); +    if (bus == NULL) { +        OF_node_put(OF_env, als); +        ERROR("Cannot create bus '%s'\n", name); +        return -1; +    } +    OF_prop_string_set(OF_env, bus, "type", type); +    sprintf(buffer, "/%s", name); +    OF_prop_string_set(OF_env, als, name, buffer); +    /* For ISA, should add DMA ranges */ +    OF_node_put(OF_env, bus); +    OF_node_put(OF_env, als); + +    return 0; +} + +// We will need to register stdin & stdout via the serial port +__attribute__ (( section (".OpenFirmware") )) +int OF_register_serial (const unsigned char *bus, const unsigned char *name, +                        uint32_t io_base, unused int irq) +{ +    unsigned char tmp[OF_NAMELEN_MAX]; +    OF_env_t *OF_env; +    OF_node_t *busn, *srl, *als; + +    OF_env = OF_env_main; +    als = OF_node_get(OF_env, "aliases"); +    if (als == NULL) { +        ERROR("Cannot get 'aliases'\n"); +        return -1; +    } +    busn = OF_node_get(OF_env, bus); +    srl = OF_node_new(OF_env, busn, name, io_base); +    if (srl == NULL) { +        OF_node_put(OF_env, als); +        ERROR("Cannot create serial '%s'\n", name); +        return -1; +    } +    OF_prop_string_set(OF_env, srl, "device_type", "serial"); +    OF_prop_string_set(OF_env, srl, "compatible", "pnpPNP,501"); +    switch (io_base) { +    case 0x3F8: +        OF_pack_get_path(OF_env, tmp, 512, srl); +        OF_prop_string_new(OF_env, als, "com1", tmp); +        break; +    case 0x2F8: +        OF_pack_get_path(OF_env, tmp, 512, srl); +        OF_prop_string_new(OF_env, als, "com2", tmp); +        break; +    default: +        break; +    } +    /* register read/write methods and create an instance of the package */ +    OF_method_new(OF_env, srl, "write", &OF_serial_write); +    OF_method_new(OF_env, srl, "read", &OF_serial_read); +    OF_node_put(OF_env, srl); +    OF_node_put(OF_env, busn); +    OF_node_put(OF_env, als); + +    return 0; +} + +/* We will also need /isa/rtc */ + +__attribute__ (( section (".OpenFirmware") )) +int OF_register_stdio (const unsigned char *dev_in, +                       const unsigned char *dev_out) +{ +    OF_env_t *OF_env; +    OF_node_t *chs, *ndev_in, *ndev_out, *kbd; +    OF_inst_t *in_inst, *out_inst; +     +    OF_env = OF_env_main; +    chs = OF_node_get(OF_env, "chosen"); +    if (chs == NULL) { +        ERROR("Cannot get 'chosen'\n"); +        return -1; +    } +    ndev_in = OF_node_get(OF_env, dev_in); +    ndev_out = OF_node_get(OF_env, dev_out); +    in_inst = OF_instance_new(OF_env, ndev_in); +    if (in_inst == NULL) { +        OF_node_put(OF_env, ndev_out); +        OF_node_put(OF_env, ndev_in); +        OF_node_put(OF_env, chs); +        ERROR("Cannot create in_inst\n"); +        return -1; +    } +    out_inst = OF_instance_new(OF_env, ndev_out); +    if (out_inst == NULL) { +        OF_node_put(OF_env, ndev_out); +        OF_node_put(OF_env, ndev_in); +        OF_node_put(OF_env, chs); +        ERROR("Cannot create out_inst\n"); +        return -1; +    } +    OF_prop_int_set(OF_env, chs, "stdin", +                    OF_instance_get_id(OF_env, in_inst)); +    OF_prop_int_set(OF_env, chs, "stdout", +                    OF_instance_get_id(OF_env, out_inst)); +    kbd = OF_node_new(OF_env, ndev_in, "keyboard", OF_ADDRESS_NONE); +    if (kbd == NULL) { +        OF_node_put(OF_env, ndev_out); +        OF_node_put(OF_env, ndev_in); +        OF_node_put(OF_env, chs); +        ERROR("Cannot create 'keyboard' for stdio\n"); +        return -1; +    } +    OF_prop_string_new(OF_env, kbd, "device_type", "keyboard"); +    OF_node_put(OF_env, kbd); +    OF_DPRINTF("stdin h: 0x%0x out : 0x%0x\n", +               OF_instance_get_id(OF_env, in_inst), +               OF_instance_get_id(OF_env, out_inst)); +    OF_node_put(OF_env, ndev_out); +    OF_node_put(OF_env, ndev_in); +    OF_node_put(OF_env, chs); + +    return 0; +} + +static void keylargo_ata(OF_node_t *mio, uint32_t base_address, +                         uint32_t base, int irq1, int irq2,  +                         uint16_t pic_phandle) +{ +    OF_env_t *OF_env = OF_env_main; +    OF_node_t *ata; +    OF_regprop_t regs[2]; + +    ata = OF_node_new(OF_env, mio, "ata-4", base); +    if (ata == NULL) { +        ERROR("Cannot create 'ata-4'\n"); +        return; +    } +    OF_prop_string_new(OF_env, ata, "device_type", "ata"); +#if 1 +    OF_prop_string_new(OF_env, ata, "compatible", "key2largo-ata"); +    OF_prop_string_new(OF_env, ata, "model", "ata-4"); +    OF_prop_string_new(OF_env, ata, "cable-type", "80-conductor"); +#else +    OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); +    OF_prop_string_new(OF_env, ata, "model", "ata-4"); +#endif +    OF_prop_int_new(OF_env, ata, "#address-cells", 1); +    OF_prop_int_new(OF_env, ata, "#size-cells", 0); +    regs[0].address = base; +    regs[0].size = 0x00001000; +#if 0 // HACK: Don't set up DMA registers +    regs[1].address = 0x00008A00; +    regs[1].size = 0x00001000; +    OF_property_new(OF_env, ata, "reg", +                    regs, 2 * sizeof(OF_regprop_t)); +#else +    OF_property_new(OF_env, ata, "reg", +                    regs, sizeof(OF_regprop_t)); +#endif +    OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); +    regs[0].address = irq1; +    regs[0].size = 0x00000001; +    regs[1].address = irq2; +    regs[1].size = 0x00000000; +    OF_property_new(OF_env, ata, "interrupts", +                    regs, 2 * sizeof(OF_regprop_t)); +    if (base == 0x1f000) +        ide_pci_pmac_register(base_address + base, 0x00000000, ata); +    else +        ide_pci_pmac_register(0x00000000, base_address + base, ata); +} + +void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, +                            void *private_data) +{ +    unsigned char tmp[OF_NAMELEN_MAX]; +    OF_env_t *OF_env; +    pci_reg_prop_t pregs[2]; +    OF_node_t *mio, *chs, *als; +    uint16_t pic_phandle; +    int rec_len; +    OF_prop_t *mio_reg; + +    OF_DPRINTF("mac-io: %p\n", dev); +    OF_env = OF_env_main; +    chs = OF_node_get(OF_env, "chosen"); +    if (chs == NULL) { +        ERROR("Cannot get 'chosen'\n"); +        return; +    } +    als = OF_node_get(OF_env, "aliases"); +    if (als == NULL) { +        OF_node_put(OF_env, als); +        ERROR("Cannot get 'aliases'\n"); +        return; +    } +    /* Mac-IO is mandatory for OSX to boot */ +    mio = dev; +    mio->private_data = private_data; +    pregs[0].addr.hi = 0x00000000; +    pregs[0].addr.mid = 0x00000000; +    pregs[0].addr.lo = 0x00000000; +    pregs[0].size_hi = base_address; +    pregs[0].size_lo = size; +    mio_reg = OF_property_get(OF_env, mio, "reg"); +    if (mio_reg && mio_reg->vlen >= 5 * 4) { +        pregs[0].addr.mid = ((pci_reg_prop_t *)mio_reg->value)->addr.hi; +    } +    OF_property_new(OF_env, mio, "ranges", +                    &pregs, sizeof(pci_reg_prop_t)); +#if 0 +    pregs[0].addr.hi = 0x82013810; +    pregs[0].addr.mid = 0x00000000; +    pregs[0].addr.lo = 0x80800000; +    pregs[0].size_hi = 0x00000000; +    pregs[0].size_lo = 0x00080000; +    OF_property_new(OF_env, mio, "assigned-addresses", +                    &pregs, sizeof(pci_reg_prop_t)); +#endif + +    if (arch == ARCH_HEATHROW) { +        /* Heathrow PIC */ +        OF_regprop_t regs; +        OF_node_t *mpic; +        const char compat_str[] = "heathrow\0mac-risc"; + +        mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x10); +        if (mpic == NULL) { +            ERROR("Cannot create 'mpic'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, mpic, "device_type", "interrupt-controller"); +        OF_property_new(OF_env, mpic, "compatible", compat_str, sizeof(compat_str)); +        OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 1); +        regs.address = 0x10; +        regs.size = 0x20; +        OF_property_new(OF_env, mpic, "reg", +                        ®s, sizeof(regs)); +        OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0); +        pic_phandle = OF_pack_handle(OF_env, mpic); +        OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); +        OF_node_put(OF_env, mpic); +        rec_len = 6; +    } else { +    /* OpenPIC */ +        OF_regprop_t regs[4]; +        OF_node_t *mpic; +        mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000); +        if (mpic == NULL) { +            ERROR("Cannot create 'mpic'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, mpic, "device_type", "open-pic"); +        OF_prop_string_new(OF_env, mpic, "compatible", "chrp,open-pic"); +        OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0); +        OF_property_new(OF_env, mpic, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, mpic, "clock-frequency", 0x003F7A00); +        OF_prop_int_new(OF_env, mpic, "#address-cells", 0); +        OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 2); +        memset(regs, 0, 4 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00040000; +        regs[0].size = 0x00040000; +        OF_property_new(OF_env, mpic, "reg", +                        ®s, 1 * sizeof(OF_regprop_t)); +        pic_phandle = OF_pack_handle(OF_env, mpic); +        OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); +        OF_node_put(OF_env, mpic); +        rec_len = 7; +    } + +    /* patch pci host table */ +    /* XXX: do it after the PCI init */ +    { +        int i; +        uint32_t tab[4]; + +        for(i = 0; i < pci_host_interrupt_map_len; i += rec_len) +            pci_host_interrupt_map[i + 4] = pic_phandle; +#if 0 +        dprintf("interrupt-map:\n"); +        for(i = 0; i < pci_host_interrupt_map_len; i++) { +            dprintf(" %08x", pci_host_interrupt_map[i]); +            if ((i % rec_len) == (rec_len - 1)) +                dprintf("\n"); +        } +        dprintf("\n"); +#endif +        OF_property_new(OF_env, pci_host_node, "interrupt-map",  +                        pci_host_interrupt_map,  +                        pci_host_interrupt_map_len * sizeof(uint32_t)); +        tab[0] = 0xf800; +        tab[1] = 0; +        tab[2] = 0; +        tab[3] = 0; +        OF_property_new(OF_env, pci_host_node, "interrupt-map-mask",  +                        tab, 4 * sizeof(uint32_t)); +    } +#if 0 +    /* escc is useful to get MacOS X debug messages */ +    { +        OF_regprop_t regs[8]; +        uint32_t irqs[6]; +        OF_node_t *scc, *chann; +        scc = OF_node_new(OF_env, mio, "escc", 0x13000); +        if (scc == NULL) { +            ERROR("Cannot create 'escc'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, scc, "device_type", "escc"); +        OF_prop_string_new(OF_env, scc, "compatible", "chrp,es0"); +        OF_property_new(OF_env, scc, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, scc, "#address-cells", 1); +        memset(regs, 0, 8 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00013000; +        regs[0].size = 0x00001000; +        regs[1].address = 0x00008400; +        regs[1].size = 0x00000100; +        regs[2].address = 0x00008500; +        regs[2].size = 0x00000100; +        regs[3].address = 0x00008600; +        regs[3].size = 0x00000100; +        regs[4].address = 0x00008700; +        regs[4].size = 0x00000100; +        OF_property_new(OF_env, scc, "reg", +                        regs, 5 * sizeof(OF_regprop_t)); +        OF_property_new(OF_env, scc, "ranges", NULL, 0); +        /* Set up two channels */ +        chann = OF_node_new(OF_env, scc, "ch-a", 0x13020); +        if (chann == NULL) { +            ERROR("Cannot create 'ch-a'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, chann, "device_type", "serial"); +        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es2"); +        OF_property_new(OF_env, chann, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, chann, "slot-names", 0); +        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle); +        memset(regs, 0, 8 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00013020; +        regs[0].size = 0x00000001; +        regs[1].address = 0x00013030; +        regs[1].size = 0x00000001; +        regs[2].address = 0x00013050; +        regs[2].size = 0x00000001; +        regs[3].address = 0x00008400; +        regs[3].size = 0x00000100; +        regs[4].address = 0x00008500; +        regs[4].size = 0x00000100; +        OF_property_new(OF_env, chann, "reg", +                        regs, 5 * sizeof(OF_regprop_t)); +        /* XXX: tofix: those are regprops */ +        irqs[0] = 0x16; +        irqs[1] = 0x01; +        irqs[2] = 0x05; +        irqs[3] = 0x00; +        irqs[4] = 0x06; +        irqs[5] = 0x00; +        OF_property_new(OF_env, chann, "interrupts", +                        irqs, 6 * sizeof(uint32_t)); +        OF_node_put(OF_env, chann); +        chann = OF_node_new(OF_env, scc, "ch-b", 0x13000); +        if (chann == NULL) { +            ERROR("Cannot create 'ch-b'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, chann, "device_type", "serial"); +        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es3"); +        OF_property_new(OF_env, chann, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, chann, "slot-names", 0); +        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle); +        memset(regs, 0, 8 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00013000; +        regs[0].size = 0x00000001; +        regs[1].address = 0x00013010; +        regs[1].size = 0x00000001; +        regs[2].address = 0x00013040; +        regs[2].size = 0x00000001; +        regs[3].address = 0x00008600; +        regs[3].size = 0x00000100; +        regs[4].address = 0x00008700; +        regs[4].size = 0x00000100; +        OF_property_new(OF_env, chann, "reg", +                        regs, 5 * sizeof(OF_regprop_t)); +        /* XXX: tofix: those are regprops */ +        irqs[0] = 0x17; +        irqs[1] = 0x01; +        irqs[2] = 0x07; +        irqs[3] = 0x00; +        irqs[4] = 0x08; +        irqs[5] = 0x00; +        OF_property_new(OF_env, chann, "interrupts", +                        irqs, 6 * sizeof(uint32_t)); +        OF_node_put(OF_env, chann); +        OF_node_put(OF_env, scc); +        /* MacOS likes escc-legacy */ +        scc = OF_node_new(OF_env, mio, "escc-legacy", 0x12000); +        if (scc == NULL) { +            ERROR("Cannot create 'escc-legacy'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, scc, "device_type", "escc-legacy"); +        OF_prop_string_new(OF_env, scc, "compatible", "chrp,es1"); +        OF_property_new(OF_env, scc, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, scc, "#address-cells", 1); +        memset(regs, 0, 8 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00012000; +        regs[0].size = 0x00001000; +        regs[1].address = 0x00008400; +        regs[1].size = 0x00000100; +        regs[2].address = 0x00008500; +        regs[2].size = 0x00000100; +        regs[3].address = 0x00008600; +        regs[3].size = 0x00000100; +        regs[4].address = 0x00008700; +        regs[4].size = 0x00000100; +        OF_property_new(OF_env, scc, "reg", +                        regs, 8 * sizeof(OF_regprop_t)); +        OF_property_new(OF_env, scc, "ranges", NULL, 0); +        /* Set up two channels */ +        chann = OF_node_new(OF_env, scc, "ch-a", 0x12004); +        if (chann == NULL) { +            ERROR("Cannot create 'ch-a'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, chann, "device_type", "serial"); +        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es4"); +        OF_property_new(OF_env, chann, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle); +        memset(regs, 0, 8 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00012004; +        regs[0].size = 0x00000001; +        regs[1].address = 0x00012006; +        regs[1].size = 0x00000001; +        regs[2].address = 0x0001200A; +        regs[2].size = 0x00000001; +        regs[3].address = 0x00008400; +        regs[3].size = 0x00000100; +        regs[4].address = 0x00008500; +        regs[4].size = 0x00000100; +        OF_property_new(OF_env, chann, "reg", +                        regs, 8 * sizeof(OF_regprop_t)); +        /* XXX: tofix: those are regprops */ +        irqs[0] = 0x16; +        irqs[1] = 0x01; +        irqs[2] = 0x05; +        irqs[3] = 0x00; +        irqs[4] = 0x06; +        irqs[5] = 0x00; +        OF_property_new(OF_env, chann, "interrupts", +                        irqs, 6 * sizeof(uint32_t)); +        OF_node_put(OF_env, chann); +        chann = OF_node_new(OF_env, scc, "ch-b", 0x12000); +        if (chann == NULL) { +            ERROR("Cannot create 'ch-b'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, chann, "device_type", "serial"); +        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es5"); +        OF_property_new(OF_env, chann, "built-in", NULL, 0); +        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle); +        memset(regs, 0, 8 * sizeof(OF_regprop_t)); +        regs[0].address = 0x00012000; +        regs[0].size = 0x00000001; +        regs[1].address = 0x00012002; +        regs[1].size = 0x00000001; +        regs[2].address = 0x00012008; +        regs[2].size = 0x00000001; +        regs[3].address = 0x00008600; +        regs[3].size = 0x00000100; +        regs[4].address = 0x00008700; +        regs[4].size = 0x00000100; +        OF_property_new(OF_env, chann, "reg", +                        regs, 8 * sizeof(OF_regprop_t)); +        /* XXX: tofix: those are regprops */ +        irqs[0] = 0x17; +        irqs[1] = 0x01; +        irqs[2] = 0x07; +        irqs[3] = 0x00; +        irqs[4] = 0x08; +        irqs[5] = 0x00; +        OF_property_new(OF_env, chann, "interrupts", +                        irqs, 6 * sizeof(uint32_t)); +        OF_node_put(OF_env, chann); +        OF_node_put(OF_env, scc); +    } +#endif +    /* Keylargo IDE controller: need some work (DMA problem ?) */ +    if (arch == ARCH_MAC99) { +        keylargo_ata(mio, base_address, 0x1f000, 0x13, 0xb, pic_phandle); +        keylargo_ata(mio, base_address, 0x20000, 0x14, 0xb, pic_phandle); +    } +#if 0 +    /* Timer */ +    { +        OF_node_t *tmr; +        OF_regprop_t regs[1]; +        tmr = OF_node_new(OF_env, mio, "timer", 0x15000); +        if (tmr == NULL) { +            ERROR("Cannot create 'timer'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, tmr, "device_type", "timer"); +        OF_prop_string_new(OF_env, tmr, "compatible", "keylargo-timer"); +        OF_prop_int_new(OF_env, tmr, "clock-frequency", 0x01194000); +        regs[0].address = 0x00015000; +        regs[0].size = 0x00001000; +        OF_property_new(OF_env, tmr, "reg", regs, sizeof(OF_regprop_t)); +        OF_prop_int_new(OF_env, tmr, "interrupt-parent", pic_phandle); +        regs[0].address = 0x00000020; +        regs[0].size = 0x00000001; +        OF_property_new(OF_env, tmr, "interrupts", +                        regs, sizeof(OF_regprop_t)); +        OF_node_put(OF_env, tmr); +    } +#endif +    /* VIA-PMU */ +    { +        /* Controls adb, RTC and power-mgt (forget it !) */ +        OF_node_t *via, *adb; +        OF_regprop_t regs[1]; +#if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD ! +      // (but needed has Qemu doesn't emulate via-pmu). +        via = OF_node_new(OF_env, mio, "via-pmu", 0x16000); +        if (via == NULL) { +            ERROR("Cannot create 'via-pmu'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, via, "device_type", "via-pmu"); +        OF_prop_string_new(OF_env, via, "compatible", "pmu"); +#else +        via = OF_node_new(OF_env, mio, "via-cuda", 0x16000); +        if (via == NULL) { +            ERROR("Cannot create 'via-cuda'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, via, "device_type", "via-cuda"); +        OF_prop_string_new(OF_env, via, "compatible", "cuda"); +#endif +        regs[0].address = 0x00016000; +        regs[0].size = 0x00002000; +        OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t)); +        OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle); +        if (arch == ARCH_HEATHROW) { +            OF_prop_int_new(OF_env, via, "interrupts", 0x12); +        } else { +        regs[0].address = 0x00000019; +        regs[0].size = 0x00000001; +        OF_property_new(OF_env, via, "interrupts", +                        regs, sizeof(OF_regprop_t)); +        } +        /* force usage of OF bus speeds */ +        OF_prop_int_new(OF_env, via, "BusSpeedCorrect", 1); +#if 0 +        OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C); +#endif +        { +            OF_node_t *kbd, *mouse; +        /* ADB pseudo-device */ +        adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE); +        if (adb == NULL) { +            ERROR("Cannot create 'adb'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, adb, "device_type", "adb"); +#if 0 +        OF_prop_string_new(OF_env, adb, "compatible", "pmu-99"); +#else +        OF_prop_string_new(OF_env, adb, "compatible", "adb"); +#endif +        OF_prop_int_new(OF_env, adb, "#address-cells", 1); +        OF_prop_int_new(OF_env, adb, "#size-cells", 0); +        OF_pack_get_path(OF_env, tmp, 512, adb); +        OF_prop_string_new(OF_env, als, "adb", tmp); + +            kbd = OF_node_new(OF_env, adb, "keyboard", 2); +            if (kbd == NULL) { +                ERROR("Cannot create 'kbd'\n"); +                goto out; +            } +            OF_prop_string_new(OF_env, kbd, "device_type", "keyboard"); +            OF_prop_int_new(OF_env, kbd, "reg", 2); + +            mouse = OF_node_new(OF_env, adb, "mouse", 3); +            if (mouse == NULL) { +                ERROR("Cannot create 'mouse'\n"); +                goto out; +            } +            OF_prop_string_new(OF_env, mouse, "device_type", "mouse"); +            OF_prop_int_new(OF_env, mouse, "reg", 3); +            OF_prop_int_new(OF_env, mouse, "#buttons", 3); +        } +        { +            OF_node_t *rtc; +         +        rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE); +        if (rtc == NULL) { +            ERROR("Cannot create 'rtc'\n"); +            goto out; +        } +        OF_prop_string_new(OF_env, rtc, "device_type", "rtc"); +#if 0 +        OF_prop_string_new(OF_env, rtc, "compatible", "rtc,via-pmu"); +#else +        OF_prop_string_new(OF_env, rtc, "compatible", "rtc"); +#endif +        OF_node_put(OF_env, rtc); +    } +        //        OF_node_put(OF_env, via); +    } +    { +        OF_node_t *pmgt; +        pmgt = OF_node_new(OF_env, mio, "power-mgt", OF_ADDRESS_NONE); +        OF_prop_string_new(OF_env, pmgt, "device_type", "power-mgt"); +        OF_prop_string_new(OF_env, pmgt, "compatible", "cuda"); +        OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led"); +        OF_node_put(OF_env, pmgt); +    } + +    if (arch == ARCH_HEATHROW) { +        /* NVRAM */ +        OF_node_t *nvr; +        OF_regprop_t regs; +        nvr = OF_node_new(OF_env, mio, "nvram", 0x60000); +        OF_prop_string_new(OF_env, nvr, "device_type", "nvram"); +        regs.address = 0x60000; +        regs.size = 0x00020000; +        OF_property_new(OF_env, nvr, "reg", ®s, sizeof(regs)); +        OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000); +        OF_node_put(OF_env, nvr); +    } + + out: +    //    OF_node_put(OF_env, mio); +    OF_node_put(OF_env, chs); +    OF_node_put(OF_env, als); +} + +void OF_finalize_pci_ide (void *dev,  +                          uint32_t io_base0, uint32_t io_base1, +                          uint32_t io_base2, uint32_t io_base3) +{ +    OF_env_t *OF_env = OF_env_main; +    OF_node_t *pci_ata = dev; +    OF_node_t *ata, *atas[2]; +    int i; + +    OF_prop_int_new(OF_env, pci_ata, "#address-cells", 1); +    OF_prop_int_new(OF_env, pci_ata, "#size-cells", 0); + +    /* XXX: Darwin handles only one device */ +    for(i = 0; i < 1; i++) { +        ata = OF_node_new(OF_env, pci_ata, "ata-4", i); +        if (ata == NULL) { +            ERROR("Cannot create 'ata-4'\n"); +            return; +        } +        OF_prop_string_new(OF_env, ata, "device_type", "ata"); +        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); +        OF_prop_string_new(OF_env, ata, "model", "ata-4"); +        OF_prop_int_new(OF_env, ata, "#address-cells", 1); +        OF_prop_int_new(OF_env, ata, "#size-cells", 0); +        OF_prop_int_new(OF_env, ata, "reg", i); +        atas[i] = ata; +    } +    ide_pci_pc_register(io_base0, io_base1, io_base2, io_base3, +                        atas[0], atas[1]); +} + +/*****************************************************************************/ +/* Fake package */ +static void OF_method_fake (OF_env_t *OF_env) +{ +    uint32_t ihandle; + +    ihandle = popd(OF_env); +    OF_DPRINTF("ih: %0x %d\n", ihandle, stackd_depth(OF_env)); +    pushd(OF_env, ihandle); +} + +static void OF_mmu_translate (OF_env_t *OF_env) +{ +    const unsigned char *args; +    uint32_t address, more; +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 4); +    /* As we get a 1:1 mapping, do nothing */ +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    address = popd(OF_env); +    more = popd(OF_env); +    OF_DPRINTF("Translate address %0x %0x %0x\n", ihandle, address, more); +    //    BAT_setup(3, more, address, 0x10000000, 1, 1, 2); +    pushd(OF_env, address); +    pushd(OF_env, 0x00000000); +    pushd(OF_env, 0x00000000); +    pushd(OF_env, 0); +} + +static void OF_mmu_map (OF_env_t *OF_env) +{ +    const unsigned char *args; +    uint32_t address, virt, size; +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 6); +    /* As we get a 1:1 mapping, do nothing */ +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    popd(OF_env); +    size = popd(OF_env); +    virt = popd(OF_env); +    address = popd(OF_env); +    OF_DPRINTF("Map %0x %0x %0x %0x\n", ihandle, address, +               virt, size); +    pushd(OF_env, 0); +} + +/* Serial device package */ +static void OF_serial_write (OF_env_t *OF_env) +{ +    const unsigned char *args; +    OF_inst_t *inst; +    OF_node_t *node; +    uint32_t ihandle; +    unsigned char *str; +    int len; + +    OF_CHECK_NBARGS(OF_env, 4); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    str = (void *)popd(OF_env); +    len = popd(OF_env); +    inst = OF_inst_find(OF_env, ihandle); +    if (inst == NULL) { +        pushd(OF_env, -1); +        ERROR("Cannot get serial instance\n"); +        return; +    } +    node = inst->node; +    //    OF_DPRINTF("args: %p str: %p\n", args, str); +    /* XXX: should use directly the serial port +     *      and have another console package. +     */ +    console_write(str, len); +    pushd(OF_env, 0); +} + +static void OF_serial_read (OF_env_t *OF_env) +{ +    const unsigned char *args; +    char *dest; +    uint32_t len; +    uint32_t ihandle; +    uint16_t phandle; +    int ret, count; + +    OF_CHECK_NBARGS(OF_env, 4); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    phandle = (ihandle >> 16) & 0xFFFF; +    dest = (void *)popd(OF_env); +    len = popd(OF_env); +    ret = -1; /* Don't know why gcc thinks it might be uninitialized... */ +    for (count = 0; count < 1000; count++) { +        ret = console_read(dest, len); +        /* Stop if we read something or got an error */ +        if (ret != 0) +            break; +        /* Random sleep. Seems allright for serial port */ +        usleep(10000); +    } +    if (ret <= 0) { +        pushd(OF_env, 0); +    } else { +        OF_DPRINTF("send '%s'\n", dest); +        pushd(OF_env, ret); +    } +} + +typedef struct blockdev_inst_t { +    int type; +    union { +        bloc_device_t *bd; +        part_t *part; +        inode_t *file; +    } u; +} blockdev_inst_t; + +static int OF_split_args (unsigned char *args, unsigned char **argv, +                          int max_args) +{ +    unsigned char *pos, *end; +    int i; + +    pos = args; +    end = pos; +    for (i = 0; i < max_args && *pos != '\0' && end != NULL; i++) { +        end = strchr(pos, ','); +        if (end != NULL) +            *end = '\0'; +        argv[i] = pos; +        pos = end + 1; +    } + +    return i; +} + +static void OF_convert_path (unsigned char **path) +{ +    unsigned char *pos; + +    OF_DPRINTF("%s: '%s'\n", __func__, *path); +    for (pos = *path; *pos != '\0'; pos++) { +        if (*pos == '\\') +            *pos = '/'; +    } +    OF_DPRINTF("%s: '%s'\n", __func__, *path); +    pos = *path; +#if 1 +    if (pos[0] == '/' && pos[1] == '/') { +        pos += 2; +        *path = pos; +    } +#else +    for (; *pos == '/'; pos++) +        continue; +    *path = pos; +#endif +    OF_DPRINTF("%s: '%s'\n", __func__, *path); +} + +/* Block devices package */ +static void OF_blockdev_open (OF_env_t *OF_env) +{ +    unsigned char tmp[OF_NAMELEN_MAX]; +    unsigned char *args, *argv[4]; +    OF_inst_t *dsk_inst; +    OF_node_t *dsk; +    bloc_device_t *bd; +    blockdev_inst_t *bdinst; +    uint32_t ihandle; +    uint16_t phandle; +    int nargs, partnum; + +    OF_CHECK_NBARGS(OF_env, 2); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    phandle = (ihandle >> 16) & 0xFFFF; +    dsk_inst = OF_inst_find(OF_env, ihandle); +    if (dsk_inst == NULL) { +        ERROR("Disk not found (ih: %0x)\n", ihandle); +        pushd(OF_env, -1); +        return; +    } +    dsk = dsk_inst->node; +    bd = dsk->private_data; +    bdinst = malloc(sizeof(blockdev_inst_t)); +    if (bdinst == NULL) { +        ihandle = -1; +        ERROR("Cannot alloc blockdev instance\n"); +        goto out; +    } +    memset(bdinst, 0, sizeof(blockdev_inst_t)); +    OF_DPRINTF("called with args '%s'\n", args); +    nargs = OF_split_args(args, argv, 4); +    partnum = -1; +    if (nargs > 0) { +        partnum = strtol(argv[0], NULL, 10); +        if (partnum > 0) { +            OF_DPRINTF("Open partition... %d %d\n", partnum, nargs); +            bdinst->type = 1; +            bdinst->u.part = part_get(bd, partnum); +            if (bdinst->u.part == NULL) { +                OF_DPRINTF("Partition %d not found\n", partnum); +                free(bdinst); +                pushd(OF_env, -1); +                return; +            } +            if (nargs > 1) { +                /* TODO: open file */ +                bdinst->type = 2; +                OF_DPRINTF("Open file... %d %d '%s'\n", +                           partnum, nargs, argv[1]); +                OF_convert_path(&argv[1]); +                if (*argv[1] != '/') { +                    sprintf(tmp, "%s/%s", +                            fs_get_boot_dirname(part_fs(bdinst->u.part)), +                            argv[1]); +                    bdinst->u.file = fs_open(part_fs(bdinst->u.part), tmp); +                } else { +                    bdinst->u.file = fs_open(part_fs(bdinst->u.part), argv[1]); +                } +                if (bdinst->u.file == NULL) { +#if 0 +                    bug(); +#endif +                    pushd(OF_env, 0x00000000); +                    ERROR("File not found '%s'\n", argv[1]); +                    return; +                } +            } +        } +    } +    if (nargs == 0 || partnum == 0) { +        OF_DPRINTF("Open disk... %d %d\n", nargs, partnum); +        bdinst->type = 0; +        bdinst->u.bd = bd; +    } +    /* TODO: find partition &/| file */ +    dsk_inst->data = bdinst; +    OF_node_put(OF_env, dsk); + out: +    pushd(OF_env, ihandle); +} + +static void OF_blockdev_seek (OF_env_t *OF_env) +{ +    const unsigned char *args; +    OF_inst_t *dsk_inst; +    blockdev_inst_t *bdinst; +    uint32_t posh, posl, bloc, pos, blocsize, tmp; +    uint32_t ihandle; +    uint16_t phandle; +    int sh; + +    OF_CHECK_NBARGS(OF_env, 4); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    phandle = (ihandle >> 16) & 0xFFFF; +    posh = popd(OF_env); +    posl = popd(OF_env); +    dsk_inst = OF_inst_find(OF_env, ihandle); +    if (dsk_inst == NULL) { +        ERROR("Disk not found (ih: %0x)\n", ihandle); +        pushd(OF_env, -1); +        return; +    } +    bdinst = dsk_inst->data; +    switch (bdinst->type) { +    case 0: +        blocsize = bd_seclen(bdinst->u.bd); +        for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2) +            sh++; +        bloc = ((posh  << (32 - sh)) | (posl / blocsize)); +        pos = posl % blocsize; +        OF_DPRINTF("disk: bsize %08x %08x %08x => %08x %08x\n", blocsize, +               posh, posl, bloc, pos); +        pushd(OF_env, bd_seek(bdinst->u.bd, bloc, pos)); +        break; +    case 1: +        blocsize = part_blocsize(bdinst->u.part); +        for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2) +            sh++; +        bloc = ((posh  << (32 - sh)) | (posl / blocsize)); +        pos = posl % blocsize; +        OF_DPRINTF("part: bsize %08x %08x %08x => %08x %08x\n", blocsize, +               posh, posl, bloc, pos); +        pushd(OF_env, part_seek(bdinst->u.part, bloc, pos)); +        break; +    case 2: +        blocsize = part_blocsize(fs_inode_get_part(bdinst->u.file)); +        for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2) +            sh++; +        bloc = ((posh  << (32 - sh)) | (posl / blocsize)); +        pos = posl % blocsize; +        OF_DPRINTF("file: bsize %08x %08x %08x => %08x %08x\n", blocsize, +                   posh, posl, bloc, pos); +        pushd(OF_env, fs_seek(bdinst->u.file, bloc, pos)); +        break; +    } +} + +static void OF_blockdev_read (OF_env_t *OF_env) +{ +    const unsigned char *args; +    OF_inst_t *dsk_inst; +    blockdev_inst_t *bdinst; +    void *dest; +    uint32_t len; +    uint32_t ihandle; +    uint16_t phandle; + +    OF_CHECK_NBARGS(OF_env, 4); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    phandle = (ihandle >> 16) & 0xFFFF; +    dest = (void *)popd(OF_env); +    len = popd(OF_env); +    dsk_inst = OF_inst_find(OF_env, ihandle); +    if (dsk_inst == NULL) { +        ERROR("Disk not found (ih: %0x)\n", ihandle); +        pushd(OF_env, -1); +        return; +    } +    bdinst = dsk_inst->data; +    set_check(0); +    OF_DPRINTF("dest: %p len: %d %d\n", dest, len, bdinst->type); +    switch (bdinst->type) { +    case 0: +        OF_DPRINTF("read disk\n"); +        pushd(OF_env, bd_read(bdinst->u.bd, dest, len)); +        break; +    case 1: +        OF_DPRINTF("read partition\n"); +        pushd(OF_env, part_read(bdinst->u.part, dest, len)); +        break; +    case 2: +        OF_DPRINTF("read file\n"); +        pushd(OF_env, fs_read(bdinst->u.file, dest, len)); +        break; +    } +    OF_DPRINTF("%08x %08x %08x %08x\n", +               ((uint32_t *)dest)[0], ((uint32_t *)dest)[1], +               ((uint32_t *)dest)[2], ((uint32_t *)dest)[3]); +    OF_DPRINTF("%08x %08x %08x %08x\n", +               ((uint32_t *)dest)[4], ((uint32_t *)dest)[5], +               ((uint32_t *)dest)[6], ((uint32_t *)dest)[7]); +         +    set_check(1); +} + +static void OF_blockdev_get_blocsize (OF_env_t *OF_env) +{ +    const unsigned char *args; +    OF_inst_t *dsk_inst; +    blockdev_inst_t *bdinst; +    uint32_t ihandle; +    uint16_t phandle; +    uint32_t blocsize; + +    OF_CHECK_NBARGS(OF_env, 2); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    phandle = (ihandle >> 16) & 0xFFFF; +    dsk_inst = OF_inst_find(OF_env, ihandle); +    if (dsk_inst == NULL) { +        ERROR("Disk not found (ih: %0x)\n", ihandle); +        pushd(OF_env, -1); +        return; +    } +    bdinst = dsk_inst->data; +#if 0 +    switch (bdinst->type) { +    case 0: +        blocsize = bd_seclen(bdinst->u.bd); +        break; +    case 1: +        blocsize = part_blocsize(bdinst->u.part); +        break; +    case 2: +        blocsize = 512; +        break; +    } +#else +    blocsize = 512; +#endif +    pushd(OF_env, blocsize); +    pushd(OF_env, 0); +} + +static void OF_blockdev_dma_alloc (OF_env_t *OF_env) +{ +    const unsigned char *args; +    void *address; +    uint32_t ihandle; +    uint32_t size; + +    OF_CHECK_NBARGS(OF_env, 3); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    size = popd(OF_env); +    OF_DPRINTF("size: %08x\n", size); +    mem_align(size); +    address = malloc(size); +    if (address != NULL) +        memset(address, 0, size); +    pushd(OF_env, (uint32_t)address); +    pushd(OF_env, 0); +} + +static void OF_blockdev_dma_free (OF_env_t *OF_env) +{ +    const unsigned char *args; +    void *address; +    uint32_t ihandle; +    uint32_t size; + +    OF_CHECK_NBARGS(OF_env, 4); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    size = popd(OF_env); +    address = (void *)popd(OF_env); +    OF_DPRINTF("address: %p size: %08x\n", address, size); +    free(address); +    pushd(OF_env, 0); +} + +void *OF_blockdev_register (void *parent, void *private, +                            const unsigned char *type, +                            const unsigned char *name, int devnum, +                            const char *alias) +{ +    unsigned char tmp[OF_NAMELEN_MAX], path[OF_NAMELEN_MAX], *pos; +    OF_env_t *OF_env; +    OF_node_t *dsk, *als; +    int i; +     +    OF_env = OF_env_main; +    dsk = OF_node_new(OF_env, parent, name, devnum); +    if (dsk == NULL) { +        ERROR("Cannot create blockdev '%s'\n", name); +        return NULL; +    } +    OF_prop_string_new(OF_env, dsk, "device_type", "block"); +    OF_prop_string_new(OF_env, dsk, "category", type); +    OF_prop_int_new(OF_env, dsk, "device_id", devnum); +    OF_prop_int_new(OF_env, dsk, "reg", devnum); +    OF_method_new(OF_env, dsk, "open", &OF_blockdev_open); +    OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek); +    OF_method_new(OF_env, dsk, "read", &OF_blockdev_read); +    OF_method_new(OF_env, dsk, "block-size", +                  &OF_blockdev_get_blocsize); +    OF_method_new(OF_env, dsk, "dma-alloc", &OF_blockdev_dma_alloc); +    OF_method_new(OF_env, dsk, "dma-free", &OF_blockdev_dma_free); +    if (strcmp(type, "cdrom") == 0) +        OF_method_new(OF_env, dsk, "eject", &OF_method_fake); +    OF_method_new(OF_env, dsk, "close", &OF_method_fake); +    dsk->private_data = private; +    /* Set up aliases */ +    OF_pack_get_path(OF_env, path, OF_NAMELEN_MAX, dsk); +    if (alias != NULL) { +        als = OF_node_get(OF_env, "aliases"); +        if (als == NULL) { +            ERROR("Cannot get 'aliases'\n"); +            return NULL; +        } +        strcpy(tmp, alias); +        if (OF_property_copy(OF_env, NULL, 0, als, tmp) >= 0) { +            pos = tmp + strlen(alias); +            for (i = 0; ; i++) { +                sprintf(pos, "%d", i); +                if (OF_property_copy(OF_env, NULL, 0, als, tmp) < 0) +                    break; +            } +        } +        OF_DPRINTF("Set alias to %s\n", tmp); +        OF_prop_string_new(OF_env, dsk, "alias", tmp); +        OF_prop_string_new(OF_env, als, tmp, path); +        OF_node_put(OF_env, als); +    } +     +    return dsk; +} + +void OF_blockdev_set_boot_device (void *disk, int partnum, +                                  const unsigned char *file) +{ +    unsigned char tmp[OF_NAMELEN_MAX], *pos; +    OF_env_t *OF_env; +    OF_node_t *dsk = disk, *opts, *chs; +     +    OF_env = OF_env_main; +     +    if (OF_property_copy(OF_env, tmp, OF_NAMELEN_MAX, dsk, "alias") < 0) +        OF_pack_get_path(OF_env, tmp, OF_NAMELEN_MAX, dsk); +    sprintf(tmp + strlen(tmp), ":%d", partnum); +    /* OpenDarwin 6.02 seems to need this one */ +    opts = OF_node_get(OF_env, "options"); +    if (opts == NULL) { +        ERROR("Cannot get 'options'\n"); +        return; +    } +    OF_prop_string_set(OF_env, OF_node_root, "boot-device", tmp); +    OF_prop_string_set(OF_env, opts, "boot-device", tmp); +    OF_DPRINTF("Set boot device to: '%s'\n", tmp); +    OF_node_put(OF_env, opts); +    /* Set the real boot path */ +    pos = tmp + strlen(tmp); +    sprintf(pos, ",%s", file); +    /* Convert all '/' into '\' in the boot file name */ +    for (; *pos != '\0'; pos++) { +        if (*pos == '/') +            *pos = '\\'; +    } +    chs = OF_node_get(OF_env, "chosen"); +    if (chs == NULL) { +        ERROR("Cannot get 'chosen'\n"); +        return; +    } +    OF_prop_string_set(OF_env, chs, "bootpath", tmp); +    OF_DPRINTF("Set boot path to: '%s'\n", tmp); +    OF_node_put(OF_env, chs); +} + +/* Display package */ +static void OF_vga_draw_rectangle (OF_env_t *OF_env) +{ +    const void *buf; +    const unsigned char *args; +    uint32_t posx, posy, width, height; +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 7); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    height = popd(OF_env); +    width = popd(OF_env); +    posy = popd(OF_env); +    posx = popd(OF_env); +    buf = (const void *)popd(OF_env); +    OF_DPRINTF("x=%d y=%d h=%d ", posx, posy, width); +    OF_DPRINTF("w=%d buf=%p\n", height, buf); +    set_check(0); +    vga_draw_buf(buf, width * vga_fb_bpp, posx, posy, width, height); +    set_check(1); +    pushd(OF_env, 0); +} + +static void OF_vga_fill_rectangle (OF_env_t *OF_env) +{ +    const unsigned char *args; +    uint32_t color, posx, posy, width, height; +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 7); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    height = popd(OF_env); +    width = popd(OF_env); +    posy = popd(OF_env); +    posx = popd(OF_env); +    color = popd(OF_env); +    OF_DPRINTF("x=%d y=%d\n", posx, posy); +    OF_DPRINTF("h=%d w=%d c=%0x\n", width, height, color); +    vga_fill_rect(posx, posy, width, height, color); +    pushd(OF_env, 0); +} + +static void OF_vga_set_width (OF_env_t *OF_env, OF_prop_t *prop, +                              const void *data, int len) +{ +    uint32_t width, height, depth; + +    if (len == sizeof(uint32_t)) { +        width = *(uint32_t *)data; +        OF_property_copy(OF_env, &height, 4, prop->node, "height"); +        OF_property_copy(OF_env, &depth, 4, prop->node, "depth"); +        vga_set_mode(width, height, depth); +    } +} + +static void OF_vga_set_height (OF_env_t *OF_env, OF_prop_t *prop, +                               const void *data, int len) +{ +    uint32_t width, height, depth; + +    if (len == sizeof(uint32_t)) { +        OF_property_copy(OF_env, &width, 4, prop->node, "width"); +        height = *(uint32_t *)data; +        OF_property_copy(OF_env, &depth, 4, prop->node, "depth"); +        vga_set_mode(width, height, depth); +    } +} + +static void OF_vga_set_depth (OF_env_t *OF_env, OF_prop_t *prop, +                              const void *data, int len) +{ +    uint32_t width, height, depth; + +    if (len == sizeof(uint32_t)) { +        OF_property_copy(OF_env, &width, 4, prop->node, "width"); +        OF_property_copy(OF_env, &height, 4, prop->node, "height"); +        depth = *(uint32_t *)data; +        vga_set_mode(width, height, depth); +    } +} + +void OF_vga_register (const unsigned char *name, unused uint32_t address, +                      int width, int height, int depth, +                      unsigned long vga_bios_addr, unsigned long vga_bios_size) +{ +    OF_env_t *OF_env; +    unsigned char tmp[OF_NAMELEN_MAX]; +    OF_node_t *disp, *chs, *als; +    OF_prop_t *prop; +     +    OF_DPRINTF("Set frame buffer %08x %dx%dx%d\n", +               address, width, height, depth); +    OF_env = OF_env_main; +    disp = OF_node_get(OF_env, name); +    if (disp == NULL) { +        ERROR("Cannot get display '%s'\n", name); +        return; +    } +    prop = OF_prop_int_new(OF_env, disp, "width", width); +    if (prop == NULL) { +        OF_node_put(OF_env, disp); +        ERROR("Cannot create display width property\n"); +        return; +    } +    OF_property_set_cb(OF_env, prop, &OF_vga_set_width); +    prop = OF_prop_int_new(OF_env, disp, "height", height); +    if (prop == NULL) { +        OF_node_put(OF_env, disp); +        ERROR("Cannot create display height property\n"); +        return; +    } +    OF_property_set_cb(OF_env, prop, &OF_vga_set_height); +    switch (depth) { +    case 8: +        break; +    case 15: +        depth = 16; +        break; +    case 32: +        break; +    default: +        /* OF spec this is mandatory, but we have no support for it */ +        printf("%d bits VGA isn't implemented\n", depth); +        bug(); +        /* Never come here */ +        break; +    } +    prop = OF_prop_int_new(OF_env, disp, "depth", depth); +    if (prop == NULL) { +        ERROR("Cannot create display depth\n"); +        goto out; +    } +    OF_property_set_cb(OF_env, prop, &OF_vga_set_depth); +    OF_prop_int_new(OF_env, disp, "linebytes", vga_fb_linesize); +    OF_method_new(OF_env, disp, "draw-rectangle", &OF_vga_draw_rectangle); +    OF_method_new(OF_env, disp, "fill-rectangle", &OF_vga_fill_rectangle); +    OF_method_new(OF_env, disp, "color!", &OF_method_fake); +    chs = OF_node_get(OF_env, "chosen"); +    if (chs == NULL) { +        ERROR("Cannot get 'chosen'\n"); +        goto out; +    } +    OF_prop_int_new(OF_env, chs, "display", OF_pack_handle(OF_env, disp)); +    OF_node_put(OF_env, chs); +    OF_pack_get_path(OF_env, tmp, 512, disp); +    printf("Set display '%s' path to '%s'\n", name, tmp); +    als = OF_node_get(OF_env, "aliases"); +    if (als == NULL) { +        ERROR("Cannot get 'aliases'\n"); +        goto out; +    } +    OF_prop_string_new(OF_env, als, "screen", tmp); +    OF_prop_string_new(OF_env, als, "display", tmp); +    OF_node_put(OF_env, als); +    /* XXX: may also need read-rectangle */ + +    if (vga_bios_size >= 8) { +        const uint8_t *p; +        int size; +        /* check the QEMU VGA BIOS header */ +        p = (const uint8_t *)vga_bios_addr; +        if (p[0] == 'N' && p[1] == 'D' && p[2] == 'R' && p[3] == 'V') { +            size = *(uint32_t *)(p + 4); +            OF_property_new(OF_env, disp, "driver,AAPL,MacOS,PowerPC",  +                            p + 8, size); +        } +    } + out: +    OF_node_put(OF_env, disp); +} + +/* Pseudo packages to make BootX happy */ +/* sl_words package */ +static void slw_set_output_level (OF_env_t *OF_env) +{ +    OF_node_t *slw; +    const unsigned char *args; +    int level; + +    OF_CHECK_NBARGS(OF_env, 3); +    popd(OF_env); +    args = (void *)popd(OF_env); +    level = popd(OF_env); +    slw = OF_node_get(OF_env, "sl_words"); +    if (slw == NULL) { +        pushd(OF_env, -1); +    } else { +        OF_DPRINTF("Set output level to: %d\n", level); +        OF_prop_int_set(OF_env, slw, "outputLevel", level); +        OF_node_put(OF_env, slw); +        pushd(OF_env, 0); +    } +} + +#ifdef DEBUG_BIOS +#define EMIT_BUFFER_LEN 256 +static unsigned char emit_buffer[EMIT_BUFFER_LEN]; +static int emit_pos = 0; +#endif + +static void slw_emit (OF_env_t *OF_env) +{ +    const unsigned char *args; +    int c; + +    OF_CHECK_NBARGS(OF_env, 3); +    popd(OF_env); +    args = (void *)popd(OF_env); +    c = popd(OF_env); +    //    OF_DPRINTF("Emit char %d\n", c); +#ifdef DEBUG_BIOS +    if (emit_pos < EMIT_BUFFER_LEN - 1) { +        emit_buffer[emit_pos++] = c; +        //        outb(0xFF00, c); +        outb(0x0F00, c); +    } else { +        emit_buffer[emit_pos] = '\0'; +    } +#else +    outb(0x0F00, c); +#endif +    pushd(OF_env, 0); +} + +static void slw_cr (OF_env_t *OF_env) +{ +    const unsigned char *args; + +    OF_CHECK_NBARGS(OF_env, 2); +    popd(OF_env); +    args = (void *)popd(OF_env); +    //    OF_DPRINTF("Emit CR char\n"); +    //    outb(0xFF01, '\n'); +    outb(0x0F01, '\n'); +#ifdef DEBUG_BIOS +    emit_buffer[emit_pos] = '\0'; +    if (strcmp(emit_buffer, "Call Kernel!") == 0) { +        /* Set qemu in debug mode: +         * log in_asm,op,int,ioport,cpu +         */ +        uint16_t loglevel = 0x02 | 0x10 | 0x80; +        //        outw(0xFF02, loglevel); +        outb(0x0F02, loglevel); +    } +    emit_pos = 0; +#endif +    pushd(OF_env, 0); +} + +static void slw_init_keymap (OF_env_t *OF_env) +{ +    const unsigned char *args; +    OF_node_t *node; +    OF_prop_t *prop; +    uint32_t phandle, ihandle; + +    OF_CHECK_NBARGS(OF_env, 3); +    ihandle = popd(OF_env); +    args = (void *)popd(OF_env); +    phandle = ihandle >> 16; +    ihandle &= 0xFFFF; +    OF_DPRINTF("\n"); +    node = OF_pack_find(OF_env, phandle); +    if (node == NULL) { +        ERROR("Cant' init slw keymap\n"); +        pushd(OF_env, -1); +    } else { +        prop = OF_property_get(OF_env, node, "keyMap"); +        if (prop == NULL) { +            pushd(OF_env, -1); +        } else { +            pushd(OF_env, (uint32_t)prop->value); +            pushd(OF_env, 0); +        } +    } +} + +static void slw_update_keymap (OF_env_t *OF_env) +{ +    const unsigned char *args; + +    OF_CHECK_NBARGS(OF_env, 2); +    popd(OF_env); +    args = (void *)popd(OF_env); +    OF_DPRINTF("\n"); +    pushd(OF_env, 0); +} + +static void slw_spin (OF_env_t *OF_env) +{ +    const unsigned char *args; +    /* XXX: cur_spin should be in sl_words package */ +    static int cur_spin = 0; +    int c; + +    OF_CHECK_NBARGS(OF_env, 2); +    popd(OF_env); +    args = (void *)popd(OF_env); +    if (cur_spin > 15) { +        c = RGB(0x30, 0x30, 0x50); +    } else { +        c = RGB(0x11, 0x11, 0x11); +    } +    c = vga_get_color(c); +    vga_fill_rect((cur_spin % 15) * 5 + 280, 420, 4, 3, c); +    cur_spin = (cur_spin + 1) & 31; +    OF_DPRINTF("\n"); +    pushd(OF_env, -1); +} + +static void slw_spin_init (OF_env_t *OF_env) +{ +    const unsigned char *args; + +    OF_CHECK_NBARGS(OF_env, 8); +    popd(OF_env); +    args = (void *)popd(OF_env); +    popd(OF_env); +    popd(OF_env); +    popd(OF_env); +    popd(OF_env); +    popd(OF_env); +    popd(OF_env); +    pushd(OF_env, -1); +} + +static void slw_pwd (OF_env_t *OF_env) +{ +    const unsigned char *args; + +    OF_CHECK_NBARGS(OF_env, 3); +    popd(OF_env); +    args = (void *)popd(OF_env); +    OF_DPRINTF("\n"); +    pushd(OF_env, -1); +} + +static void slw_sum (OF_env_t *OF_env) +{ +    const unsigned char *args; + +    OF_CHECK_NBARGS(OF_env, 3); +    popd(OF_env); +    args = (void *)popd(OF_env); +    OF_DPRINTF("\n"); +    pushd(OF_env, -1); +} + +/*****************************************************************************/ +/*                       Client program interface                            */ +/* Client interface services */ +static void OF_test (OF_env_t *OF_env); + +/* Device tree services */ +/* Get next package */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_peer (OF_env_t *OF_env) +{ +    OF_node_t *node; +    uint32_t phandle; + +    OF_CHECK_NBARGS(OF_env, 1); +    phandle = popd(OF_env); +    OF_DPRINTF("phandle 0x%0x\n", phandle); +    if (phandle == 0) +        node = OF_node_root; +    else +        node = OF_pack_next(OF_env, phandle); +    if (node == NULL) +        pushd(OF_env, 0); +    else +        pushd(OF_env, OF_pack_handle(OF_env, node)); +} + +/* Get first child package */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_child (OF_env_t *OF_env) +{ +    OF_node_t *node; +    uint32_t phandle; + +    OF_CHECK_NBARGS(OF_env, 1); +    phandle = popd(OF_env); +    OF_DPRINTF("phandle 0x%0x\n", phandle); +    node = OF_pack_child(OF_env, phandle); +    if (node == NULL) +        pushd(OF_env, 0); +    else +        pushd(OF_env, OF_pack_handle(OF_env, node)); +} + +/* Get parent package */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_parent (OF_env_t *OF_env) +{ +    OF_node_t *node; +    uint32_t phandle; + +    OF_CHECK_NBARGS(OF_env, 1); +    phandle = popd(OF_env); +    OF_DPRINTF("phandle 0x%0x\n", phandle); +    node = OF_pack_parent(OF_env, phandle); +    if (node == NULL) +        pushd(OF_env, 0); +    else +        pushd(OF_env, OF_pack_handle(OF_env, node)); +} + +/* Get package related to an instance */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_instance_to_package (OF_env_t *OF_env) +{ +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 1); +    ihandle = popd(OF_env); +    OF_DPRINTF("ihandle 0x%0x\n", ihandle); +    pushd(OF_env, (ihandle >> 16) & 0xFFFF); +} + +/* Get property len */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_getproplen (OF_env_t *OF_env) +{ +    unsigned char name[OF_NAMELEN_MAX], *namep; +    OF_node_t *node; +    uint32_t phandle; + +    OF_CHECK_NBARGS(OF_env, 2); +    phandle = popd(OF_env); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name); +    node = OF_pack_find(OF_env, phandle); +    if (node == NULL) +        pushd(OF_env, -1); +    else +        pushd(OF_env, OF_property_len(OF_env, node, name)); +} + +/* Get property */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_getprop (OF_env_t *OF_env) +{ +    unsigned char name[OF_NAMELEN_MAX], *namep; +    OF_node_t *node; +    void *buffer; +    uint32_t phandle; +    int len, nb_args; + +    //    OF_CHECK_NBARGS(OF_env, 4); +    nb_args = stackd_depth(OF_env); +    phandle = popd(OF_env); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    buffer = (void *)popd(OF_env); +    if (nb_args == 3) { +        /* This hack is needed to boot MacOS X panther (10.3) */ +        len = 1024; +    } else { +        len = popd(OF_env); +    } +    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name); +    OF_DPRINTF("buffer %p len %d\n", buffer, len); +    node = OF_pack_find(OF_env, phandle); +    if (node == NULL) { +        len = -1; +    } else { +        len = OF_property_copy(OF_env, buffer, len, node, name); +        if (len != -1) { +            OF_DPRINTF("Copied %d bytes\n", len); +        } +    } +    pushd(OF_env, len); +} + +/* Check existence of next property */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_nextprop (OF_env_t *OF_env) +{ +    unsigned char name[OF_NAMELEN_MAX], *namep; +    OF_node_t *node; +    OF_prop_t *next; +    unsigned char *next_name; +    uint32_t phandle; + +    OF_CHECK_NBARGS(OF_env, 3); +    phandle = popd(OF_env); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name); +    next_name = (unsigned char *)popd(OF_env); +    node = OF_pack_find(OF_env, phandle); +    if (node == NULL) { +        pushd(OF_env, -1); +    } else { +        next = OF_property_next(OF_env, node, name); +        if (next == NULL || next->name == NULL) { +            OF_DPRINTF("No next property found [%s]\n", name); +            pushd(OF_env, 0); +        } else { +            OF_DPRINTF("Return property name [%s]\n", next->name); +            OF_sts(next_name, (void *)(next->name)); +            OF_DUMP_STRING(OF_env, next_name); +            pushd(OF_env, strlen(next->name) + 1); +        } +    } +} + +/* Set a property */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_setprop (OF_env_t *OF_env) +{ +    unsigned char name[OF_NAMELEN_MAX], *namep; +    unsigned char *value, *buffer; +    OF_node_t *node; +    OF_prop_t *prop; +    uint32_t phandle; +    int len; +    int i; + +    OF_CHECK_NBARGS(OF_env, 4); +    phandle = popd(OF_env); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name); +    buffer = (unsigned char *)popd(OF_env); +    len = popd(OF_env); +    node = OF_pack_find(OF_env, phandle); +    if (node == NULL) { +        pushd(OF_env, -1); +        ERROR("Cannot get pack %04x\n", phandle); +        return; +    } +    value = malloc(len); +    if (value == NULL && len != 0) { +        pushd(OF_env, -1); +        ERROR("%s: Cannot alloc property '%s' (%d)\n", __func__, name, len); +        return; +    } +    for (i = 0; i < len; i++) +        value[i] = buffer[i]; +    prop = OF_property_set(OF_env, node, name, value, len); +    if (prop == NULL) +        len = -1; +   pushd(OF_env, len); +} + +/* "canon" */ + +/* Find a device given its path */ +__attribute__ (( section (".OpenFirmware") )) +static OF_node_t *OF_get_alias (OF_env_t *OF_env, const unsigned char *name) +{ +    unsigned char tmp[OF_NAMELEN_MAX], *pos, *st; +    const unsigned char *alias, *npos; +    OF_node_t *als, *node; +    OF_prop_t *prop; + +    node = NULL; +    strcpy(tmp, name); +    for (st = tmp; *st == '/'; st++) +        continue; +    pos = strchr(st, '/'); +    if (pos == NULL) { +        pos = strchr(st, ':'); +    } +    if (pos != NULL) { +        *pos = '\0'; +        npos = name + (pos - tmp); +    } else { +        npos = ""; +    } +    OF_DPRINTF("Look for alias for '%s' => '%s' '%s'\n", name, tmp, npos); +    als = OF_pack_find_by_name(OF_env, OF_node_root, "/aliases"); +    if (als == NULL) { +        ERROR("Cannot get 'aliases'\n"); +        return NULL; +    } +    prop = OF_property_get(OF_env, als, tmp); +    if (prop == NULL) { +        OF_DPRINTF("No %s alias !\n", tmp); +        goto out; +    } +    alias = prop->value; +    OF_DPRINTF("Found alias '%s' '%s'\n", alias, npos); +    sprintf(tmp, "%s%s", alias, npos); +    node = OF_pack_find_by_name(OF_env, OF_node_root, tmp); +    if (node == NULL) { +        printf("%s alias is a broken link !\n", name); +        goto out; +    } +    OF_node_put(OF_env, node); + out: +    OF_node_put(OF_env, als); + +    return node; +} + +__attribute__ (( section (".OpenFirmware") )) +static void OF_finddevice (OF_env_t *OF_env) +{ +    unsigned char name[OF_NAMELEN_MAX], *namep; +    OF_node_t *node; +    int ret; + +    OF_CHECK_NBARGS(OF_env, 1); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    OF_DPRINTF("name %p [%s]\n", namep, name); +    /* Search first in "/aliases" */ +    node = OF_get_alias(OF_env, name); +    if (node == NULL) { +        node = OF_pack_find_by_name(OF_env, OF_node_root, name); +    } +    if (node == NULL) +        ret = -1; +    else +        ret = OF_pack_handle(OF_env, node); +    OF_DPRINTF("ret 0x%0x\n", ret); +    pushd(OF_env, ret); +} + +/* "instance-to-path */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_instance_to_path (OF_env_t *OF_env) +{ +    void *buffer; +    OF_inst_t *inst; +    uint32_t ihandle; +    int len; + +    OF_CHECK_NBARGS(OF_env, 3); +    OF_DPRINTF("\n"); +    ihandle = popd(OF_env); +    buffer = (void *)popd(OF_env); +    len = popd(OF_env); +    OF_DPRINTF("ihandle: 0x%0x len=%d\n", ihandle, len); +    inst = OF_inst_find(OF_env, ihandle); +    if (inst == NULL) +        len = -1; +    else +        len = OF_inst_get_path(OF_env, buffer, len, inst) + 1; +    OF_DUMP_STRING(OF_env, buffer); +    pushd(OF_env, len); +} + +/* "package-to-path" */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_package_to_path (OF_env_t *OF_env) +{ +    void *buffer; +    OF_node_t *node; +    uint32_t phandle; +    int len; + +    OF_CHECK_NBARGS(OF_env, 3); +    OF_DPRINTF("\n"); +    phandle = popd(OF_env); +    buffer = (void *)popd(OF_env); +    len = popd(OF_env); +    node = OF_pack_find(OF_env, phandle); +    if (node == NULL) +        len = -1; +    else +        len = OF_pack_get_path(OF_env, buffer, len, node) + 1; +    OF_DUMP_STRING(OF_env, buffer); +    pushd(OF_env, len); +} + +/* Call a package's method */ +__attribute__ (( section (".OpenFirmware") )) +static void _OF_callmethod (OF_env_t *OF_env, const unsigned char *name, +                            uint32_t ihandle, const unsigned char *argp) +{ +    OF_node_t *node; +    OF_inst_t *inst; +    OF_method_t *method; +    OF_cb_t cb; + +    inst = OF_inst_find(OF_env, ihandle); +    OF_DPRINTF("Attempt to call method [%s] of package instance 0x%0x\n", +               name, ihandle); +    if (inst == NULL) { +        OF_DPRINTF("No instance %0x\n", ihandle); +        pushd(OF_env, -1); +        return; +    } +    node = inst->node; +    method = OF_method_get(OF_env, node, name); +    if (method != NULL) { +        cb = method->func; +    } else { +        if (strcmp(name, "open") == 0) { +            cb = &OF_method_fake; +        } else { +            printf("Method '%s' not found in '%s'\n", +                   name, node->prop_name->value); +            pushd(OF_env, -1); +            bug(); +            return; +        } +    } +#if 0 +    OF_DPRINTF("Push instance method %p (%p)...\n", &method->func, +               &slw_emit); +#endif +    pushf(OF_env, &cb); +    if (argp != NULL) +        pushd(OF_env, (uint32_t)argp); +    else +        pushd(OF_env, 0x00000000); +    pushd(OF_env, ihandle); +} + +__attribute__ (( section (".OpenFirmware") )) +static unsigned char *OF_get_args (unused OF_env_t *env, unsigned char *name) +{ +    unsigned char *sd; + +    sd = strchr(name, ':'); +    if (sd == NULL) +        return NULL; +    *sd = '\0'; + +    return sd + 1; +} + +__attribute__ (( section (".OpenFirmware") )) +static void OF_callmethod (OF_env_t *OF_env) +{ +    const unsigned char *args; +    unsigned char name[OF_NAMELEN_MAX], *namep; +    uint32_t ihandle; + +    OF_DPRINTF("\n\n\n#### CALL METHOD ####\n\n"); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    args = OF_get_args(OF_env, name); +    ihandle = popd(OF_env); +    _OF_callmethod(OF_env, name, ihandle, args); +} + +/* Device IO services */ +/* Create a new instance of a device's package */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_open (OF_env_t *OF_env) +{ +    const unsigned char *args; +    unsigned char name[OF_NAMELEN_MAX], *namep; +    OF_node_t *node; +    OF_inst_t *inst; +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 1); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    OF_DPRINTF("package [%s]\n", name); +    args = OF_get_args(OF_env, name); +    node = OF_get_alias(OF_env, name); +    if (node == NULL) { +        node = OF_pack_find_by_name(OF_env, OF_node_root, name); +    } +    if (node == NULL) { +        OF_DPRINTF("package not found !\n"); +        pushd(OF_env, -1); +        return; +    } +    inst = OF_instance_new(OF_env, node); +    if (inst == NULL) { +        pushd(OF_env, -1); +        ERROR("Cannot create package instance\n"); +        return; +    } +    ihandle = OF_instance_get_id(OF_env, inst); +    /* If an "open" method exists in the package, call it */ +    OF_DPRINTF("package [%s] => %0x\n", name, ihandle); +    OF_node_put(OF_env, node); +    _OF_callmethod(OF_env, "open", ihandle, args); +} + +/* De-instanciate a package */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_close (OF_env_t *OF_env) +{ +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 1); +    ihandle = popd(OF_env); +    /* If an "close" method exists in the package, call it */ +    _OF_callmethod(OF_env, "close", ihandle, NULL); +    /* XXX: Should free the instance */ +} + +/* "read" */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_read (OF_env_t *OF_env) +{ +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 3); +    ihandle = popd(OF_env); +    OF_DPRINTF("ih: %0x\n", ihandle); +    /* If a "read" method exists in the package, call it */ +    _OF_callmethod(OF_env, "read", ihandle, NULL); +} + +/* Try call the "read" method of a device's package */ +/* "write" */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_write (OF_env_t *OF_env) +{ +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 3); +    ihandle = popd(OF_env); +    //    OF_DPRINTF("ih: %0x\n", ihandle); +    /* If a "write" method exists in the package, call it */ +    _OF_callmethod(OF_env, "write", ihandle, NULL); +} + +/* "seek" */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_seek (OF_env_t *OF_env) +{ +    uint32_t ihandle; + +    OF_CHECK_NBARGS(OF_env, 3); +    ihandle = popd(OF_env); +    OF_DPRINTF("ih: %0x\n", ihandle); +    /* If a "seek" method exists in the package, call it */ +    _OF_callmethod(OF_env, "seek", ihandle, NULL); +} + +/* Memory services */ +/* Claim some memory space */ +__attribute__ (( section (".OpenFirmware") )) +uint32_t OF_claim_virt (uint32_t virt, uint32_t size, int *range) +{ +    int i, keep = -1; + +    OF_DPRINTF("Claim %d bytes at 0x%0x\n", size, virt); +    /* First check that the requested memory stands in the physical memory */ +    if (OF_mem_ranges[0].start > virt || +        (OF_mem_ranges[0].start + OF_mem_ranges[0].size) < (virt + size)) { +        ERROR("not in memory: start 0x%0x virt 0x%0x end 0x%0x 0x%0x\n", +              OF_mem_ranges[0].start, virt, +              OF_mem_ranges[0].start + OF_mem_ranges[0].size, +              virt + size); +        return (uint32_t)(-1); +    } +    /* Now check that it doesn't overlap with already claimed areas */ +    for (i = 1; i < OF_MAX_MEMRANGES + 1; i++) { +        if (OF_mem_ranges[i].start == (uint32_t)(-1) || +            OF_mem_ranges[i].size == (uint32_t)(-1)) { +            if (keep == -1) +                keep = i; +            continue; +        } +        if (OF_mem_ranges[i].start == virt && +            (OF_mem_ranges[i].start + OF_mem_ranges[i].size) == (virt + size)) { +            return virt; +        } +        if (!((OF_mem_ranges[i].start >= (virt + size) || +               (OF_mem_ranges[i].start + OF_mem_ranges[i].size) <= virt))) { +            ERROR("overlap: start 0x%0x virt 0x%0x end 0x%0x 0x%0x\n", +                  OF_mem_ranges[i].start, virt, +                  OF_mem_ranges[i].start + OF_mem_ranges[i].size, +                  virt + size); +            /* Aie... */ +            return (uint32_t)(-1); +        } +    } +    OF_DPRINTF("return range: %d\n", keep); +    if (keep == -1) { +        /* no more rooms */ +        ERROR("No more rooms\n"); +        return (uint32_t)(-1); +    } else { +        ERROR("Give range: start 0x%0x 0x%0x\n", virt, size); +    } +    if (range != NULL) +        *range = keep; + +    return virt; +} + +/* We always try to get the upper address we can */ +__attribute__ (( section (".OpenFirmware") )) +static uint32_t OF_claim_size (uint32_t size, int align, int *range) +{ +    uint32_t addr, max = (uint32_t)(-1); +    int i; +     +    OF_DPRINTF("Try map %d bytes at 0x00000000\n", size); +    if (OF_claim_virt(0, size, range) != (uint32_t)(-1)) +        max = 0; +    for (i = 1; i < OF_MAX_MEMRANGES + 1; i++) { +        if (OF_mem_ranges[i].start == (uint32_t)(-1) || +            OF_mem_ranges[i].size == (uint32_t)(-1)) +            continue; +        addr = (OF_mem_ranges[i].start + OF_mem_ranges[i].size + align - 1) & +            ~(align - 1); +        OF_DPRINTF("Try map %d bytes at 0x%0x\n", size, addr); +        if ((addr + 1) > (max + 1)) { +            if (OF_claim_virt(addr, size, range) != (uint32_t)(-1)) +                max = addr; +        } +    } + +    return max; +} + +__attribute__ (( section (".OpenFirmware") )) +static void OF_claim (OF_env_t *OF_env) +{ +    uint32_t virt, size, addr; +    int align; +    int i, range; + +    OF_CHECK_NBARGS(OF_env, 3); +    virt = popd(OF_env); +    size = popd(OF_env); +    align = popd(OF_env); +    DPRINTF("virt 0x%0x size 0x%0x align %d\n", virt, size, align); +    if (align == 0) { +        addr = OF_claim_virt(virt, size, &range); +    } else { +        for (i = 1; i < align; i = i << 1) +            continue; +        align = i; +        size = (size + align - 1) & ~(align - 1); +        addr = OF_claim_size(size, align, &range); +    } +    if (addr == (uint32_t)-1) { +        ERROR("No range match !\n"); +        pushd(OF_env, -1); +    } +    if (range != -1) { +        OF_mem_ranges[range].start = addr; +        OF_mem_ranges[range].size = size; +    } +    OF_DPRINTF("Give address 0x%0x\n", addr); +    pushd(OF_env, addr); +} + +/* release some previously claimed memory */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_release (OF_env_t *OF_env) +{ +    uint32_t virt, size; +    int i; + +    OF_CHECK_NBARGS(OF_env, 2); +    virt = popd(OF_env); +    size = popd(OF_env); +    OF_DPRINTF("virt 0x%0x size 0x%0x\n", virt, size); +    for (i = 0; i < OF_MAX_MEMRANGES; i++) { +        if (OF_mem_ranges[i].start == virt && OF_mem_ranges[i].size == size) { +            OF_mem_ranges[i].start = (uint32_t)(-1); +            OF_mem_ranges[i].size = (uint32_t)(-1); +            break; +        } +    } +} + +/* Control transfer services */ +/* "boot" */ + +/* Enter Open-Firmware interpreter */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_enter (OF_env_t *OF_env) +{ +    int n_args; + +    n_args = stackd_depth(OF_env); +    /* means that the bootloader has ended. +     * So qemu will... +     */ +    OF_DPRINTF("%d \n", n_args); +    //    printf("Bootloader has quitted...\n"); +    //    abort(); +} + +/* Exit client program */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_exit (OF_env_t *OF_env) +{ +    int n_args; + +    n_args = stackd_depth(OF_env); +    /* means that the bootloader has ended. +     * So qemu will... +     */ +    OF_DPRINTF("%d \n", n_args); +    //    printf("Bootloader has quitted...\n"); +    //    abort(); +} + +/* "chain" */ + +/* User interface services */ +/* "interpret" */ + +__attribute__ (( section (".OpenFirmware") )) +static void OF_interpret (OF_env_t *OF_env) +{ +    const unsigned char *FString; +    void *buf; +    OF_inst_t *inst; +    OF_node_t *pks, *slw, *chs, *disp; +    uint32_t ihandle, crc; + +    OF_DPRINTF("\n"); +    //    OF_CHECK_NBARGS(OF_env, 1); +    FString = (const void *)popd(OF_env); +    crc = crc32(0, FString, strlen(FString)); +    OF_DPRINTF("\n\nOF INTERPRETER CALL:\n [%s]\n crc=%0x\n", FString, crc); +    /* Do some hacks to make BootX happy */ +    switch (crc) { +    case 0x225b6748: /* MacOS X 10.2 and OpenDarwin 1.41 */ +    case 0xb1cd4d25: /* OpenDarwin 6.02 */ +        /* Create "sl_words" package */ +        popd(OF_env); +        /* Find "/packages" */ +        pks = OF_pack_find_by_name(OF_env, OF_node_root, "/packages"); +        if (pks == NULL) { +            OF_node_put(OF_env, pks); +            pushd(OF_env, -1); +            ERROR("Cannot get '/packages'\n"); +            break; +        } +        slw = OF_node_new(OF_env, pks, "sl_words", OF_ADDRESS_NONE); +        if (slw == NULL) { +            OF_node_put(OF_env, pks); +            pushd(OF_env, -1); +            ERROR("Cannot create 'sl_words'\n"); +            break; +        } +        /* Create methods */ +        OF_method_new(OF_env, slw, "slw_set_output_level", +                      &slw_set_output_level); +        OF_method_new(OF_env, slw, "slw_emit", &slw_emit); +        OF_method_new(OF_env, slw, "slw_cr", &slw_cr); +        OF_method_new(OF_env, slw, "slw_init_keymap", &slw_init_keymap); +        OF_method_new(OF_env, slw, "slw_update_keymap", &slw_update_keymap); +        OF_method_new(OF_env, slw, "slw_spin", &slw_spin); +        OF_method_new(OF_env, slw, "slw_spin_init", &slw_spin_init); +        OF_method_new(OF_env, slw, "slw_pwd", &slw_pwd); +        OF_method_new(OF_env, slw, "slw_sum", &slw_sum); +        /* Init properties */ +        OF_prop_int_new(OF_env, slw, "outputLevel", 0); +        OF_prop_int_new(OF_env, slw, "keyboardIH", 0); +        { +#if 0 +            OF_node_t *kbd; +            kbd = OF_pack_find_by_name(OF_env, OF_node_root, "/keyboard"); +            if (kbd == NULL) { +                OF_node_put(OF_env, pks); +                pushd(OF_env, -1); +                ERROR("Cannot get '/keyboard'\n"); +                break; +            } +            buf = malloc(0x20); +            if (buf == NULL) { +                OF_node_put(OF_env, pks); +                pushd(OF_env, -1); +                ERROR("Cannot allocate keyboard buff\n"); +                break; +            } +#else +            buf = malloc(0x20); +            if (buf == NULL) { +                OF_node_put(OF_env, pks); +                pushd(OF_env, -1); +                ERROR("Cannot allocate keyboard buff\n"); +                break; +            } +            memset(buf, 0, 0x20); +            OF_property_new(OF_env, slw, "keyMap", buf, 0x20); +#endif +        } +        OF_prop_int_new(OF_env, slw, "screenIH", 0); +        OF_prop_int_new(OF_env, slw, "cursorAddr", 0); +        OF_prop_int_new(OF_env, slw, "cursorX", 0); +        OF_prop_int_new(OF_env, slw, "cursorY", 0); +        OF_prop_int_new(OF_env, slw, "cursorW", 0); +        OF_prop_int_new(OF_env, slw, "cursorH", 0); +        OF_prop_int_new(OF_env, slw, "cursorFrames", 0); +        OF_prop_int_new(OF_env, slw, "cursorPixelSize", 0); +        OF_prop_int_new(OF_env, slw, "cursorStage", 0); +        OF_prop_int_new(OF_env, slw, "cursorTime", 0); +        OF_prop_int_new(OF_env, slw, "cursorDelay", 0); +        /* Instanciate sl_words */ +        inst = OF_instance_new(OF_env, slw); +        if (inst == NULL) { +            OF_node_put(OF_env, pks); +            pushd(OF_env, -1); +            ERROR("Cannot create sl_words instance\n"); +            break; +        } +        ihandle = OF_instance_get_id(OF_env, inst); +        /* Release packages */ +        OF_node_put(OF_env, slw); +        OF_node_put(OF_env, pks); +        OF_DPRINTF("sl_words instance: %0x\n", ihandle); +        /* Set return value */ +        if (crc == 0xb1cd4d25) /* Hack for OpenDarwin 6.02 */ +            pushd(OF_env, ihandle); +        pushd(OF_env, ihandle); +        pushd(OF_env, 0); +        break; +    case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */ +        /* Create "memory-map" pseudo device */ +        { +            OF_node_t *map; +            uint32_t phandle; + +        /* Find "/packages" */ +        chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen"); +        if (chs == NULL) { +            pushd(OF_env, -1); +            ERROR("Cannot get '/chosen'\n"); +            break; +        } +            map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE); +            if (map == NULL) { +                pushd(OF_env, -1); +                ERROR("Cannot create 'memory-map'\n"); +                break; +            } +            phandle = OF_pack_handle(OF_env, map); +            OF_node_put(OF_env, map); +            OF_node_put(OF_env, chs); +            pushd(OF_env, phandle); +        pushd(OF_env, 0); +        } +        break; +    case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */ +        /* Return screen ihandle */ +        disp = OF_get_alias(OF_env, "screen"); +        if (disp == NULL) { +            pushd(OF_env, 0); +            pushd(OF_env, -1); +            ERROR("Cannot get 'screen' alias\n"); +            break; +        } +        inst = OF_instance_new(OF_env, disp); +        if (inst == NULL) { +            OF_node_put(OF_env, disp); +            pushd(OF_env, 0); +            pushd(OF_env, -1); +            ERROR("Cannot create 'screen' instance\n"); +            break; +        } +        ihandle = OF_instance_get_id(OF_env, inst); +        OF_node_put(OF_env, disp); +        OF_DPRINTF("Return screen ihandle: %0x\n", ihandle); +        pushd(OF_env, ihandle); +        pushd(OF_env, 0); +        break; +    case 0xF3A9841F: /* MacOS X 10.2 */ +    case 0x76fbdf18: /* OpenDarwin 6.02 */ +        /* Set current display as active package */ +        disp = OF_get_alias (OF_env, "screen"); +        if (disp == NULL) { +            pushd(OF_env, 0); +            pushd(OF_env, -1); +        } +        OF_node_put(OF_env, disp); +        break; +    case 0x1c3bc93f: /* MacOS X 10.3 */ +        /* get-package-property if 0 0 then */ +        OF_getprop(OF_env); +        { +            uint32_t len; +            len = popd(OF_env); +            if (len == (uint32_t)-1) +                len = 0; +            pushd(OF_env, len); +        } +        break; +    case 0x218d5ccb: /* yaboot */ +    case 0x27b32255: +    case 0x05d332ef: +    case 0xc7b5d3b5: +        /* skip it */ +        break; +    case 0xf541a878: +    case 0x6a9b2be6: +        /* Yaboot: set background color to black */ +        break; +    case 0x846077fb: +    case 0x299c2c5d: /* gentoo */ +        /* Yaboot: set foreground color to grey */ +        break; +    case 0x4ad41f2d: +        /* Yaboot: wait 10 ms: sure ! */ +        break; + +    default: +        /* ERROR */ +        printf("Script: len=%d\n%s\n", (int)strlen(FString), FString); +        printf("Call %0x NOT IMPLEMENTED !\n", crc); +        bug(); +        break; +    } +    OF_DPRINTF("\n\nOF INTERPRETER CALL DONE\n\n"); +} + +/* "set-callback" */ +/* "set-symbol-lookup" */ + +/* Time services */ +/* "milliseconds" */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_milliseconds (OF_env_t *OF_env) +{ +#if 0 +    struct timeval tv; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(OF_env, 0); +    gettimeofday(&tv, NULL); +    pushd(OF_env, (tv.tv_sec * 1000) + (tv.tv_usec / 1000)); +#else +    static uint32_t ms = 0; + +    OF_CHECK_NBARGS(OF_env, 0); +    pushd(OF_env, ms); +    usleep(10000); /* XXX: TOFIX: Random sleep */ +    ms += 10; +#endif +} + +/* Undocumented in IEEE 1275 */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_quiesce (OF_env_t *OF_env) +{ +    OF_CHECK_NBARGS(OF_env, 0); +    /* Should free all OF resources */ +    bd_reset_all(); +#if defined (DEBUG_BIOS) +    { +        uint16_t loglevel = 0x02 | 0x10 | 0x80; +        //        outw(0xFF02, loglevel); +        outb(0x0F02, loglevel); +    } +#endif +} + +typedef struct OF_service_t OF_service_t; +struct OF_service_t { +    const unsigned char *name; +    OF_cb_t cb; +}; + +static OF_service_t services[] = { +    { "test",                &OF_test,                }, +    { "peer",                &OF_peer,                }, +    { "child",               &OF_child,               }, +    { "parent",              &OF_parent,              }, +    { "instance-to-package", &OF_instance_to_package, }, +    { "getproplen",          &OF_getproplen,          }, +    { "getprop",             &OF_getprop,             }, +    { "nextprop",            &OF_nextprop,            }, +    { "setprop",             &OF_setprop,             }, +    { "finddevice",          &OF_finddevice,          }, +    { "instance-to-path",    &OF_instance_to_path,    }, +    { "package-to-path",     &OF_package_to_path,     }, +    { "call-method",         &OF_callmethod,          }, +    { "open",                &OF_open,                }, +    { "open-package",        &OF_open,                }, +    { "close",               &OF_close,               }, +    { "read",                &OF_read,                }, +    { "write",               &OF_write,               }, +    { "seek",                &OF_seek,                }, +    { "claim",               &OF_claim,               }, +    { "release",             &OF_release,             }, +    { "enter",               &OF_enter,               }, +    { "exit",                &OF_exit,                }, +    { "interpret",           &OF_interpret,           }, +    { "milliseconds",        &OF_milliseconds,        }, +    { "quiesce",             &OF_quiesce,             }, +}; + +/* Probe if a named service exists */ +__attribute__ (( section (".OpenFirmware") )) +static void OF_test (OF_env_t *OF_env) +{ +    unsigned char name[OF_NAMELEN_MAX], *namep; +    uint32_t i; +    int ret = -1; + +    OF_CHECK_NBARGS(OF_env, 1); +    namep = (unsigned char *)popd(OF_env); +    OF_lds(name, namep); +    OF_DPRINTF("service [%s]\n", name); +    for (i = 0; i < (sizeof(services) / sizeof(OF_service_t)); i++) { +        if (strcmp(services[i].name, name) == 0) { +            ret = 0; +            break; +        } +    } +    pushd(OF_env, ret); +} + +/* Main entry point for PPC clients */ +__attribute__ (( section (".OpenFirmware") )) +int OF_client_entry (void *p) +{ +    unsigned char buffer[OF_NAMELEN_MAX]; +    OF_env_t OF_env; +    OF_cb_t cb; +    unsigned char *namep; +    uint32_t i; + +    /* set our environment */ +    MMU_off(); +    OF_DPRINTF("Called with arg: %p\n", p); +    /* Load function name string */ +    namep = (unsigned char *)(*(uint32_t *)p); +    OF_lds(buffer, namep); +    /* Find callback */ +    cb = NULL; +    OF_DPRINTF("Look for service [%s]\n", buffer); +    for (i = 0; i < (sizeof(services) / sizeof(OF_service_t)); i++) { +        if (strcmp(services[i].name, buffer) == 0) { +            cb = services[i].cb; +            break; +        } +    } +    if (cb == NULL) { +        OF_DPRINTF("service [%s] not implemented\n", buffer); +        //        bug(); +        return -1; +    } +#if 0 +    OF_DPRINTF("Service [%s] found\n", buffer); +#endif +    /* Set up stack *NON REENTRANT* */ +    OF_env_init(&OF_env); +    /* Launch Forth glue */ +    C_to_Forth(&OF_env, (uint32_t *)p + 1, &cb); +    OF_DPRINTF("done\n"); +    MMU_on(); + +    return 0; +} + +/*****************************************************************************/ +/* Run-time abstraction services */ +/* RTAS RAM is organised this way: + * RTAS_memory is given by the OS when instanciating RTAS. + * it's an 32 kB area divided in 2 zones: + * Up is a stack, used to call RTAS services + * Down is the variables area. + */ + +__attribute__ (( section (".RTAS_vars") )) +static OF_cb_t *RTAS_callbacks[32]; +#if 0 +__attribute__ (( section (".RTAS_vars") )) +static uint8_t *RTAS_base; +#endif + +/* RTAS is called in real mode (ie no MMU), privileged with all exceptions + * disabled. It has to preserve all registers except R3 to R12. + * The OS should ensure it's not re-entered. + */ +__attribute__ (( section (".RTAS") )) +int RTAS_entry (void *p) +{ +    OF_env_t RTAS_env; +    uint32_t token; + +    OF_DPRINTF("Called with arg: %p\n", p); +    /* set our environment */ +    token = *(uint32_t *)p; +    /* Set up stack */ +    RTAS_env.stackb = (uint32_t *)(RTAS_memory + 0x8000 - 4); +    RTAS_env.stackp = RTAS_env.stackb; +    RTAS_env.funcb = (uint32_t *)(RTAS_memory + 0x8000 - OF_STACK_SIZE - 4); +    RTAS_env.funcp = RTAS_env.funcb; +    /* Call Forth glue */ +    C_to_Forth(&RTAS_env, (uint32_t *)p + 1, RTAS_callbacks[token & 0x3F]); +    OF_DPRINTF("done\n"); + +    return 0; +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_restart_rtas (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 0); +    /* No implementation: return error */ +    pushd(RTAS_env, -1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_nvram_fetch (OF_env_t *RTAS_env) +{ +    uint8_t *buffer; +    int offset, length; +    int i; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    offset = popd(RTAS_env); +    buffer = (uint8_t *)popd(RTAS_env); +    length = popd(RTAS_env); +    for (i = 0; i < length; i++) { +        if ((i + offset) >= NVRAM_get_size(nvram)) { +            pushd(RTAS_env, -3); +            return; +        } +        *buffer++ = NVRAM_read(nvram, i + offset); +    } +    pushd(RTAS_env, length); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_nvram_store (OF_env_t *RTAS_env) +{ +    uint8_t *buffer; +    int offset, length; +    int i; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    offset = popd(RTAS_env); +    buffer = (uint8_t *)popd(RTAS_env); +    length = popd(RTAS_env); +    for (i = 0; i < length; i++) { +        if ((i + offset) >= NVRAM_get_size(nvram)) { +            pushd(RTAS_env, -3); +            return; +        } +        NVRAM_write(nvram, i + offset, *buffer++); +    } +    pushd(RTAS_env, length); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_get_time_of_day (OF_env_t *RTAS_env) +{ +#if 0 +    struct tm tm; +    time_t t; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 0); +    t = get_time(); +    localtime_r(&t, &tm); +    pushd(RTAS_env, 0); /* nanoseconds */ +    pushd(RTAS_env, tm.tm_sec); +    pushd(RTAS_env, tm.tm_min); +    pushd(RTAS_env, tm.tm_hour); +    pushd(RTAS_env, tm.tm_mday); +    pushd(RTAS_env, tm.tm_mon); +    pushd(RTAS_env, tm.tm_year); +    pushd(RTAS_env, 0); /* status */ +#else +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +    pushd(RTAS_env, 0); +#endif +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_set_time_of_day (OF_env_t *RTAS_env) +{ +#if 0 +    struct tm tm; +    time_t t; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 7); +    tm.tm_year = popd(RTAS_env); +    tm.tm_mon = popd(RTAS_env); +    tm.tm_mday = popd(RTAS_env); +    tm.tm_hour = popd(RTAS_env); +    tm.tm_min = popd(RTAS_env); +    tm.tm_sec = popd(RTAS_env); +    popd(RTAS_env); /* nanoseconds */ +    t = mktime(&tm); +    set_time_offset(t); +#endif +    pushd(RTAS_env, 0); /* status */ +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_set_time_for_power_on (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 7); +    /* Do nothing */ +    pushd(RTAS_env, 0); /* status */ +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_event_scan (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 4); +    /* Pretend there are no new events */ +    pushd(RTAS_env, 1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_check_exception (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 6); +    /* Pretend we found no exceptions */ +    pushd(RTAS_env, 1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_read_pci_config (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 2); +    /* Hardware error */ +    pushd(RTAS_env, -1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_write_pci_config (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    /* Hardware error */ +    pushd(RTAS_env, -1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_display_character (OF_env_t *RTAS_env) +{ +    int c; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 1); +    c = popd(RTAS_env); +#if 0 +    printf("%c", c); +#else +    outb(0x0F00, c); +#endif +    pushd(RTAS_env, 0); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_set_indicator (OF_env_t *RTAS_env) +{ +    const unsigned char *name; +    int indic, state; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    indic = popd(RTAS_env); +    state = popd(RTAS_env); +    switch (indic) { +    case 1: +        name = "tone frequency"; +        break; +    case 2: +        name = "tone volume"; +        break; +    case 3: +        name = "system power state"; +        break; +    case 4: +        name = "warning light"; +        break; +    case 5: +        name = "disk activity light"; +        break; +    case 6: +        name = "hexadecimal display unit"; +        break; +    case 7: +        name = "batery warning time"; +        break; +    case 8: +        name = "condition cycle request"; +        break; +    case 9000 ... 9999: +        name = "vendor specific"; +        break; +    default: +        pushd(RTAS_env, -3); +        return; +    }         +    OF_DPRINTF("Set indicator %d [%s] to %d\n", indic, name, state); +    pushd(RTAS_env, 0); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_get_sensor_state (OF_env_t *RTAS_env) +{ +    const unsigned char *name; +    int type, index; +    int state; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 2); +    type = popd(RTAS_env); +    index = popd(RTAS_env); +    switch (index) { +    case 1: +        name = "key switch"; +        state = 1; /* Normal */ +        break; +    case 2: +        name = "enclosure switch"; +        state = 0; /* Closed */ +        break; +    case 3: +        name = "thermal sensor"; +        state = 40; /* in degrees Celsius (not too hot !) */ +        break; +    case 4: +        name = "lid status"; +        state = 1; /* Open */ +        break; +    case 5: +        name = "power source"; +        state = 0; /* AC */ +        break; +    case 6: +        name = "battery voltage"; +        state = 6; /* Let's have a moderated answer :-) */ +        break; +    case 7: +        name = "battery capacity remaining"; +        state = 3; /* High */ +        break; +    case 8: +        name = "battery capacity percentage"; +        state = 1000; /* 100 % */ +        break; +    case 9: +        name = "EPOW sensor"; +        state = 5; /* ? */ +        break; +    case 10: +        name = "battery condition cycle state"; +        state = 0; /* none */ +        break; +    case 11: +        name = "battery charge state"; +        state = 2; /* No current flow */ +        break; +    case 9000 ... 9999: +        name = "vendor specific"; +        state = 0; +        break; +    default: +        pushd(RTAS_env, -3); +        return; +    }         +    OF_DPRINTF("Pretend sensor %d [%s] is in state %d\n", index, name, state); +    pushd(RTAS_env, state); +    pushd(RTAS_env, 0); +} + +#if 0 // No power management */ +__attribute__ (( section (".RTAS") )) +static void RTAS_set_power_level (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_get_power_level (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_assume_power_management (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_relinquish_power_management (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} +#endif + +__attribute__ (( section (".RTAS") )) +static void RTAS_power_off (OF_env_t *RTAS_env) +{ +    printf("RTAS was asked to switch off\n"); +    OF_CHECK_NBARGS(RTAS_env, 2); +    //    abort(); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_suspend (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    /* Pretend we don't succeed */ +    pushd(RTAS_env, -1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_hibernate (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    /* Pretend we don't succeed */ +    pushd(RTAS_env, -1); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_system_reboot (OF_env_t *RTAS_env) +{ +    printf("RTAS was asked to reboot\n"); +    OF_CHECK_NBARGS(RTAS_env, 0); +    //    abort(); +} + +#if 0 // No power management nor SMP */ +__attribute__ (( section (".RTAS") )) +static void RTAS_cache_control (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_freeze_time_base (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_thaw_time_base (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_stop_self (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_start_cpu (OF_env_t *RTAS_env) +{ +    OF_DPRINTF("\n"); +} +#endif + +__attribute__ (( section (".RTAS") )) +static void RTAS_instantiate (OF_env_t *RTAS_env) +{ +    const unsigned char *args; +    uint32_t ihandle; +    uint32_t base_address; + +    OF_DPRINTF("\n"); +    OF_CHECK_NBARGS(RTAS_env, 3); +    ihandle = popd(RTAS_env); +    args = (void *)popd(RTAS_env); +    base_address = popd(RTAS_env); +    memmove((void *)base_address, (void *)(&_RTAS_start), +            (char *)(&_RTAS_data_end) - (char *)(&_RTAS_start)); +    OF_DPRINTF("base_address=0x%0x\n", base_address); +    pushd(RTAS_env, base_address); +    pushd(RTAS_env, 0); +} + +__attribute__ (( section (".RTAS") )) +static void RTAS_new_cb (OF_env_t *env, OF_node_t *rtas, +                         const unsigned char *name, +                         OF_cb_t cb, uint32_t *token_next) +{ +    OF_prop_int_new(env, rtas, name, 0xabcd0000 | *token_next); +    RTAS_callbacks[*token_next] = &cb; +    (*token_next)++; +} + +__attribute__ (( section (".RTAS") )) +void RTAS_init (void) +{ +    OF_env_t *RTAS_env; +    OF_node_t *rtas, *chs; +    OF_prop_t *stdout; +    uint32_t token_next = 0, size; + +    RTAS_env = OF_env_main; +    rtas = OF_node_new(RTAS_env, OF_node_root, "rtas", OF_ADDRESS_NONE); +    if (rtas == NULL) { +        ERROR("RTAS not found\n"); +        return; +    } +    size = ((char *)(&_RTAS_data_end) - (char *)(&_RTAS_start) + 0x0000FFFF) & +        ~0x0000FFFF; +    OF_DPRINTF("RTAS size: %d bytes (%d)\n", size, +               (char *)(&_RTAS_data_end) - (char *)(&_RTAS_start)); +    OF_prop_int_new(RTAS_env, rtas, "rtas-size", size); +    OF_prop_int_new(RTAS_env, rtas, "rtas-version", 1); +    OF_prop_int_new(RTAS_env, rtas, "rtas-event-scan-rate", 0); +    OF_prop_int_new(RTAS_env, rtas, "rtas-error-log-max", 0); +    chs = OF_node_get(RTAS_env, "chosen"); +    if (chs == NULL) { +        ERROR("choosen not found\n"); +        return; +    } +    stdout = OF_property_get(RTAS_env, chs, "stdout"); +    if (stdout == NULL) { +        OF_node_put(RTAS_env, chs); +        ERROR("stdout not found\n"); +        return; +    } +    OF_prop_int_new(RTAS_env, rtas, "rtas-display-device", +                    *(uint32_t *)stdout->value); +    /* RTAS tokens */ +    RTAS_new_cb(RTAS_env, rtas, "restart_rtas", +                &RTAS_restart_rtas, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "nvram_fetch", +                &RTAS_nvram_fetch, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "nvram_store", +                &RTAS_nvram_store, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "get-time-of_day", +                &RTAS_get_time_of_day, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "set-time-of-day", +                &RTAS_set_time_of_day, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "set-time-for-power-on", +                &RTAS_set_time_for_power_on, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "event-scan", &RTAS_event_scan, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "check-exception", +                &RTAS_check_exception, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "read-pci-config", +                &RTAS_read_pci_config, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "write-pci-config", +                &RTAS_write_pci_config, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "display-character", +                &RTAS_display_character, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "set-indicator", +                &RTAS_set_indicator, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "get-sensor-state", +                &RTAS_get_sensor_state, &token_next); +#if 0 // No power management */ +    RTAS_new_cb(RTAS_env, rtas, "set-power-level", +                &RTAS_set_power_level, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "get-power-level", +                &RTAS_get_power_level, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "assume-power-management", +                &RTAS_assume_power_management, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "relinquish-power-management", +                &RTAS_relinquish_power_management, &token_next); +#endif +    RTAS_new_cb(RTAS_env, rtas, "power-off", &RTAS_power_off, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "suspend", &RTAS_suspend, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "hibernate", &RTAS_hibernate, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "system-reboot", +                &RTAS_system_reboot, &token_next); +#if 0 // No power management nor SMP */ +    RTAS_new_cb(RTAS_env, rtas, "cache-control", +                &RTAS_cache_control, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "freeze_time_base", +                &RTAS_freeze_time_base, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "thaw_time_base", +                &RTAS_thaw_time_base, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "stop-self", &RTAS_stop_self, &token_next); +    RTAS_new_cb(RTAS_env, rtas, "start-cpu", &RTAS_start_cpu, &token_next); +#endif +    /* missing +     * "update-flash" +     * "update-flash-and-reboot" +     * "query-cpu-stopped-state" for SMP +     */ +    OF_method_new(RTAS_env, rtas, "instantiate-rtas", &RTAS_instantiate); +    OF_node_put(RTAS_env, rtas); +    OF_node_new(RTAS_env, OF_node_root, "nomore", OF_ADDRESS_NONE); +    DPRINTF("RTAS done\n"); +} + +/*****************************************************************************/ +/*                          That's all for now...                            */ +/*****************************************************************************/ diff --git a/roms/openhackware/src/pci.c b/roms/openhackware/src/pci.c new file mode 100644 index 00000000..d9173700 --- /dev/null +++ b/roms/openhackware/src/pci.c @@ -0,0 +1,2419 @@ +/* PCI BIOS. + * + *  Copyright (c) 2004-2005 Jocelyn Mayer + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" + +//#define DEBUG_PCI 1 + +#if defined (DEBUG_PCI) +#define PCI_DPRINTF(fmt, args...) \ +do { dprintf("PCI %s: " fmt, __func__ , ##args); } while (0) +#else +#define PCI_DPRINTF(fmt, args...) \ +do { } while (0) +#endif + +/* On PMAC, there are four kind of PCI bridges: + * - uninorth, for all recent machines (all Core99 and more). + * - chaos : buggy bandit like + * - grackle, for powerbook 1998 & some powermac G3 + * - bandit : some early PCI powermacs. + * For now, only uninorth will be supported, as other ones are deprecated. + */ + +enum { +    /* Fake devices */ +    PCI_FAKE_HOST   = 0x00000001, +    PCI_FAKE_BRIDGE = 0x00000002, +    /* Device found during PCI probe */ +    PCI_HOST_BRIDGE = 0x00000003, +    PCI_DEV_BRIDGE  = 0x00000004, +    PCI_DEVICE      = 0x00000005, +}; + +enum { +    BRIDGE_TYPE_UNINORTH = 0x0001, +}; + +/* PCI devices database */ +typedef struct pci_class_t pci_class_t; +typedef struct pci_subclass_t pci_subclass_t; +typedef struct pci_iface_t pci_iface_t; + +struct pci_iface_t { +    uint8_t iface; +    const unsigned char *name; +    const unsigned char *type; +    const pci_dev_t *devices; +    int (*config_cb)(pci_device_t *device); +    const void *private; +}; + +struct pci_subclass_t { +    uint8_t subclass; +    const unsigned char *name; +    const unsigned char *type; +    const pci_dev_t *devices; +    const pci_iface_t *iface; +    int (*config_cb)(pci_device_t *device); +    const void *private; +}; + +struct pci_class_t { +    const unsigned char *name; +    const unsigned char *type; +    const pci_subclass_t *subc; +}; + +/* PCI devices tree */ +struct pci_common_t { +    int type; +    const pci_dev_t *device; +    const pci_u_t *parent; +    void *OF_private; +}; + +struct pci_device_t { +    pci_common_t common; +    uint8_t bus; +    uint8_t devfn; +    uint16_t rev; +    uint32_t class_code; +    uint16_t min_grant; +    uint16_t max_latency; +    uint8_t  irq_line; +    uint32_t regions[7]; /* the region 6 is the PCI ROM */ +    uint32_t sizes[7]; +    pci_device_t *next; +}; + +struct pci_host_t { +    pci_device_t dev; +    pci_bridge_t *bridge; +    pci_host_t *next; +}; + +struct pci_bridge_t { +    pci_device_t dev; +    uint32_t cfg_base; +    uint32_t cfg_len; +    uint32_t io_base; +    uint32_t io_len; +    uint32_t io_cur; +    uint32_t mem_base; +    uint32_t mem_len; +    uint32_t mem_cur; +    uint32_t rbase; +    uint32_t rlen; +    uint32_t cfg_addr; +    uint32_t cfg_data; +    uint32_t flags; +    const pci_ops_t *ops; +    pci_device_t *devices; +    pci_bridge_t *next; +}; + +union pci_u_t { +    pci_common_t common; +    pci_host_t host; +    pci_device_t device; +    pci_bridge_t bridge; +}; + +/* Low level access helpers */ +struct pci_ops_t { +    uint8_t (*config_readb)(pci_bridge_t *bridge, +                            uint8_t bus, uint8_t devfn, uint8_t offset); +    void (*config_writeb)(pci_bridge_t *bridge, +                          uint8_t bus, uint8_t devfn, +                          uint8_t offset, uint8_t val); +    uint16_t (*config_readw)(pci_bridge_t *bridge, +                             uint8_t bus, uint8_t devfn, uint8_t offset); +    void (*config_writew)(pci_bridge_t *bridge, +                          uint8_t bus, uint8_t devfn, +                          uint8_t offset, uint16_t val); +    uint32_t (*config_readl)(pci_bridge_t *bridge, +                             uint8_t bus, uint8_t devfn, uint8_t offset); +    void (*config_writel)(pci_bridge_t *bridge, +                          uint8_t bus, uint8_t devfn, +                          uint8_t offset, uint32_t val); +}; + +/* IRQ numbers assigned to PCI IRQs */ +static uint8_t prep_pci_irqs[4] = { 9, 11, 9, 11 }; +static uint8_t heathrow_pci_irqs[4] = { 0x15, 0x16, 0x17, 0x18 }; +static uint8_t pmac_pci_irqs[4] = { 8, 9, 10, 11 }; + +/* PREP PCI host */ +static inline uint32_t PREP_cfg_addr (pci_bridge_t *bridge, unused uint8_t bus, +                                      uint8_t devfn, uint8_t offset) +{ +#if 0 +    printf("Translate %0x %0x %d %x %x => %0x", +           bridge->cfg_addr, bridge->cfg_data, bus, devfn, offset, +           bridge->cfg_addr | +           (1 << (devfn >> 3)) | ((devfn & 7) << 8) | offset); +#endif +    return bridge->cfg_addr | +        (1 << (devfn >> 3)) | ((devfn & 7) << 8) | offset; +} + +static uint8_t PREP_config_readb (pci_bridge_t *bridge, +                                  uint8_t bus, uint8_t devfn, +                                  uint8_t offset) +{ +    uint32_t addr; + +    if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21) +        return 0xFF; +    addr = PREP_cfg_addr(bridge, bus, devfn, offset); +     +    return *((uint8_t *)addr); +} + +static void PREP_config_writeb (pci_bridge_t *bridge, +                                uint8_t bus, uint8_t devfn, +                                uint8_t offset, uint8_t val) +{ +    uint32_t addr; + +    if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21) +        return; +    addr = PREP_cfg_addr(bridge, bus, devfn, offset); +    *((uint8_t *)addr) = val; +} + +static uint16_t PREP_config_readw (pci_bridge_t *bridge, +                                   uint8_t bus, uint8_t devfn, +                                   uint8_t offset) +{ +    uint32_t addr; + +    if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21) +        return 0xFFFF; +    addr = PREP_cfg_addr(bridge, bus, devfn, offset); +     +    return ldswap16((uint16_t *)addr); +} + +static void PREP_config_writew (pci_bridge_t *bridge, +                                uint8_t bus, uint8_t devfn, +                                uint8_t offset, uint16_t val) +{ +    uint32_t addr; + +    if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21) +        return; +    addr = PREP_cfg_addr(bridge, bus, devfn, offset); +    stswap16((uint16_t *)addr, val); +} + +static uint32_t PREP_config_readl (pci_bridge_t *bridge, +                                   uint8_t bus, uint8_t devfn, +                                   uint8_t offset) +{ +    uint32_t addr; + +    if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21) +        return 0xFFFFFFFF; +    addr = PREP_cfg_addr(bridge, bus, devfn, offset); +     +    return ldswap32((uint32_t *)addr); +} + +static void PREP_config_writel (pci_bridge_t *bridge, +                                uint8_t bus, uint8_t devfn, +                                uint8_t offset, uint32_t val) +{ +    uint32_t addr; + +    if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21) +        return; +    addr = PREP_cfg_addr(bridge, bus, devfn, offset); +    stswap32((uint32_t *)addr, val); +} + +static pci_ops_t PREP_pci_ops = { +    &PREP_config_readb, &PREP_config_writeb, +    &PREP_config_readw, &PREP_config_writew, +    &PREP_config_readl, &PREP_config_writel, +}; + +/* Uninorth PCI host */ +static uint32_t macrisc_cfg_address (pci_bridge_t *bridge, +                                     uint8_t bus, uint8_t devfn, +                                     uint8_t offset) +{ +    uint32_t addr; +    int i; + +    /* Kind of magic... */ +    if (bridge->cfg_base == 0xF2000000) { +        if (bus != 0) { +#if 0 +            printf("Skip bus: %d dev: %x offset: %x\n", bus, devfn, offset); +#endif +            return -1; +        } +        addr = (1 << (devfn >> 3)); +    } else { +        addr = (bus << 16) | ((devfn & 0xF8) << 8) | 0x01; +    } +    addr |= ((devfn & 0x07) << 8) | (offset & 0xFC); +    /* Avoid looping forever */ +#if 0 +    printf("Translate %0x %0x %d %x %x => %0x", +           bridge->cfg_addr, bridge->cfg_data, bus, devfn, offset, addr); +#endif +    for (i = 0; i < 100; i++) { +        stswap32((uint32_t *)bridge->cfg_addr, addr); +        eieio(); +        if (ldswap32((uint32_t *)bridge->cfg_addr) == addr) +            break; +    } +    if (i == 100) { +#if 1 +    printf("Translate %0x %0x %d %x %x => %0x", +           bridge->cfg_addr, bridge->cfg_data, bus, devfn, offset, addr); +        printf("\nTimeout accessing PCI bridge cfg address\n"); +#endif +        return -1; +    } +    if (bridge->flags & BRIDGE_TYPE_UNINORTH) +        offset &= 0x07; +    else +        offset &= 0x03; +#if 0 +    printf(" %0x\n", bridge->cfg_data + offset); +#endif + +    return bridge->cfg_data + offset; +} + +static uint8_t uninorth_config_readb (pci_bridge_t *bridge, +                                      uint8_t bus, uint8_t devfn, +                                      uint8_t offset) +{ +    uint32_t addr; + +    if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11) +        return 0xFF; +    addr = macrisc_cfg_address(bridge, bus, devfn, offset); +    if (addr == (uint32_t)(-1)) +        return 0xFF; +     +    return *((uint8_t *)addr); +} + +static void uninorth_config_writeb (pci_bridge_t *bridge, +                                    uint8_t bus, uint8_t devfn, +                                    uint8_t offset, uint8_t val) +{ +    uint32_t addr; + +    if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11) +        return; +    addr = macrisc_cfg_address(bridge, bus, devfn, offset); +    if (addr != (uint32_t)(-1)) +        *((uint8_t *)addr) = val; +} + +static uint16_t uninorth_config_readw (pci_bridge_t *bridge, +                                       uint8_t bus, uint8_t devfn, +                                       uint8_t offset) +{ +    uint32_t addr; + +    if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11) +        return 0xFFFF; +    addr = macrisc_cfg_address(bridge, bus, devfn, offset); +    if (addr == (uint32_t)(-1)) +        return 0xFFFF; +     +    return ldswap16((uint16_t *)addr); +} + +static void uninorth_config_writew (pci_bridge_t *bridge, +                                    uint8_t bus, uint8_t devfn, +                                    uint8_t offset, uint16_t val) +{ +    uint32_t addr; + +    if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11) +        return; +    addr = macrisc_cfg_address(bridge, bus, devfn, offset); +    if (addr != (uint32_t)(-1)) +        stswap16((uint16_t *)addr, val); +} + +static uint32_t uninorth_config_readl (pci_bridge_t *bridge, +                                       uint8_t bus, uint8_t devfn, +                                       uint8_t offset) +{ +    uint32_t addr; + +    if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11) +        return 0xFFFFFFFF; +    addr = macrisc_cfg_address(bridge, bus, devfn, offset); +    if (addr == (uint32_t)(-1)) { +        //        printf("bad address -1\n"); +        return 0xFFFFFFFF; +    } +    //    printf("%s: addr=%0x\n", __func__, addr); +     +    return ldswap32((uint32_t *)addr); +} + +static void uninorth_config_writel (pci_bridge_t *bridge, +                                    uint8_t bus, uint8_t devfn, +                                    uint8_t offset, uint32_t val) +{ +    uint32_t addr; + +    if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11) +        return; +    addr = macrisc_cfg_address(bridge, bus, devfn, offset); +    if (addr != (uint32_t)(-1)) +        stswap32((uint32_t *)addr, val); +} + +static pci_ops_t uninorth_pci_ops = { +    &uninorth_config_readb, &uninorth_config_writeb, +    &uninorth_config_readw, &uninorth_config_writew, +    &uninorth_config_readl, &uninorth_config_writel, +}; + +/* Grackle PCI host */ + +static uint32_t grackle_cfg_address (pci_bridge_t *bridge, +                                     uint8_t bus, uint8_t devfn, +                                     uint8_t offset) +{ +    uint32_t addr; +    addr = 0x80000000 | (bus << 16) | (devfn << 8) | (offset & 0xfc); +    stswap32((uint32_t *)bridge->cfg_addr, addr); +    return bridge->cfg_data + (offset & 3); +} + +static uint8_t grackle_config_readb (pci_bridge_t *bridge, +                                      uint8_t bus, uint8_t devfn, +                                      uint8_t offset) +{ +    uint32_t addr; +    addr = grackle_cfg_address(bridge, bus, devfn, offset); +    return *((uint8_t *)addr); +} + +static void grackle_config_writeb (pci_bridge_t *bridge, +                                    uint8_t bus, uint8_t devfn, +                                    uint8_t offset, uint8_t val) +{ +    uint32_t addr; +    addr = grackle_cfg_address(bridge, bus, devfn, offset); +    *((uint8_t *)addr) = val; +} + +static uint16_t grackle_config_readw (pci_bridge_t *bridge, +                                       uint8_t bus, uint8_t devfn, +                                       uint8_t offset) +{ +    uint32_t addr; +    addr = grackle_cfg_address(bridge, bus, devfn, offset); +    return ldswap16((uint16_t *)addr); +} + +static void grackle_config_writew (pci_bridge_t *bridge, +                                    uint8_t bus, uint8_t devfn, +                                    uint8_t offset, uint16_t val) +{ +    uint32_t addr; +    addr = grackle_cfg_address(bridge, bus, devfn, offset); +    stswap16((uint16_t *)addr, val); +} + +static uint32_t grackle_config_readl (pci_bridge_t *bridge, +                                       uint8_t bus, uint8_t devfn, +                                       uint8_t offset) +{ +    uint32_t addr; +    addr = grackle_cfg_address(bridge, bus, devfn, offset); +    return ldswap32((uint32_t *)addr); +} + +static void grackle_config_writel (pci_bridge_t *bridge, +                                    uint8_t bus, uint8_t devfn, +                                    uint8_t offset, uint32_t val) +{ +    uint32_t addr; + +    addr = grackle_cfg_address(bridge, bus, devfn, offset); +    stswap32((uint32_t *)addr, val); +} + +static pci_ops_t grackle_pci_ops = { +    &grackle_config_readb, &grackle_config_writeb, +    &grackle_config_readw, &grackle_config_writew, +    &grackle_config_readl, &grackle_config_writel, +}; + +static inline uint8_t pci_config_readb (pci_bridge_t *bridge, +                                        uint8_t bus, uint8_t devfn, +                                        uint8_t offset) +{ +    return (*bridge->ops->config_readb)(bridge, bus, devfn, offset); +} + +static inline void pci_config_writeb (pci_bridge_t *bridge, +                                      uint8_t bus, uint8_t devfn, +                                      uint8_t offset, uint8_t val) +{ +    (*bridge->ops->config_writeb)(bridge, bus, devfn, offset, val); +} + +static inline uint16_t pci_config_readw (pci_bridge_t *bridge, +                                         uint8_t bus, uint8_t devfn, +                                         uint8_t offset) +{ +    return (*bridge->ops->config_readw)(bridge, bus, devfn, offset); +} + +static inline void pci_config_writew (pci_bridge_t *bridge, +                                      uint8_t bus, uint8_t devfn, +                                      uint8_t offset, uint16_t val) +{ +    (*bridge->ops->config_writew)(bridge, bus, devfn, offset, val); +} + +static inline uint32_t pci_config_readl (pci_bridge_t *bridge, +                                         uint8_t bus, uint8_t devfn, +                                         uint8_t offset) +{ +    return (*bridge->ops->config_readl)(bridge, bus, devfn, offset); +} + + +static inline void pci_config_writel (pci_bridge_t *bridge, +                                      uint8_t bus, uint8_t devfn, +                                      uint8_t offset, uint32_t val) +{ +    (*bridge->ops->config_writel)(bridge, bus, devfn, offset, val); +} + +unused static void *get_parent_OF_private (pci_device_t *device) +{ +    const pci_u_t *u; + +    for (u = (pci_u_t *)device; u != NULL; u = u->common.parent) { +        if (u->common.OF_private != NULL) +            return u->common.OF_private; +    } +     +    return NULL; +} + +/* PCI devices database */ +static pci_subclass_t undef_subclass[] = { +    { +        0x00, "misc undefined", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, NULL, NULL, +        NULL, NULL, +    }, +}; + +static int ide_config_cb2 (pci_device_t *device) +{ +    OF_finalize_pci_ide(device->common.OF_private, +                        device->regions[0] & ~0x0000000F, +                        device->regions[1] & ~0x0000000F, +                        device->regions[2] & ~0x0000000F, +                        device->regions[3] & ~0x0000000F); +    return 0; +} + +static pci_dev_t ide_devices[] = { +    { +        0x1095, 0x0646, /* CMD646 IDE controller */ +        "pci-ide", "pci-ata", NULL, NULL, +        0, 0, 0, +        ide_config_cb2, NULL, +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +#if 0 +/* should base it on PCI ID, not on arch */ +static int ide_config_cb (unused pci_device_t *device) +{ +    printf("Register IDE controller\n"); +    switch (arch) { +    case ARCH_MAC99: +        ide_pci_pmac_register(device->regions[0] & ~0x0000000F, +                              device->regions[1] & ~0x0000000F, +                              device->common.OF_private); +        break; +    default: +        break; +    } +    return 0; +} + +static int ata_config_cb (pci_device_t *device) +{ +    printf("Register ATA  controller\n"); +    switch (arch) { +    case ARCH_MAC99: +        ide_pci_pmac_register(device->regions[0] & ~0x0000000F, +                              device->regions[1] & ~0x0000000F, +                              device->common.OF_private); +        break; +    default: +        break; +    } + +    return 0; +} +#endif + +static pci_subclass_t mass_subclass[] = { +    { +        0x00, "SCSI bus controller",        NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x01, "IDE controller",             "ide", ide_devices, NULL, +        NULL, NULL, +    }, +    { +        0x02, "Floppy disk controller",     NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x03, "IPI bus controller",         NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x04, "RAID controller",            NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x05, "ATA controller",             "ata", NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc mass-storage controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_dev_t eth_devices[] = { +    { 0x10EC, 0x8029, +      NULL, "NE2000",   "NE2000 PCI",  NULL, +      0, 0, 0, +      NULL, "ethernet", +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +static pci_subclass_t net_subclass[] = { +    { +        0x00, "ethernet controller",       NULL, eth_devices, NULL, +        NULL, "ethernet", +    }, +    { +        0x01, "token ring controller",      NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x02, "FDDI controller",            NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x03, "ATM controller",             NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x04, "ISDN controller",            NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x05, "WordFip controller",         NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x06, "PICMG 2.14 controller",      NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc network controller",    NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_dev_t vga_devices[] = { +    { +        0x1002, 0x5046, +        NULL, "ATY",      "ATY Rage128", "VGA", +        0, 0, 0, +        NULL, NULL, +    }, +    { +        0x1234, 0x1111, +        NULL, "Qemu VGA", "Qemu VGA",    "VGA", +        0, 0, 0, +        NULL, NULL, +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +/* VGA configuration */ +/* HACK... */ +extern int vga_width, vga_height, vga_depth; +int vga_console_register (void); +static int vga_config_cb (pci_device_t *device) +{ +    /* Found a VGA device. Let's configure it ! */ +    printf("Set VGA to %0x\n", device->regions[0] & ~0x0000000F); +    if (device->regions[0] != 0x00000000) { +        vga_set_mode(vga_width, vga_height, vga_depth); +        vga_set_address(device->regions[0] & ~0x0000000F); +        /* VGA 640x480x16 */ +        OF_vga_register(device->common.device->name, +                        device->regions[0] & ~0x0000000F, +                        vga_width, vga_height, vga_depth, +                        device->regions[6] & ~0x0000000F, +                        device->sizes[6]); +    } +    vga_console_register(); + +    return 0; +} + +static struct pci_iface_t vga_iface[] = { +    {  +        0x00, "VGA controller", NULL, +        vga_devices, &vga_config_cb, NULL, +    }, +    { +        0x01, "8514 compatible controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_subclass_t displ_subclass[] = { +    { +        0x00, "display controller",         NULL,  NULL, vga_iface, +        NULL, NULL, +    }, +    { +        0x01, "XGA display controller",     NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x02, "3D display controller",      NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc display controller",    NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t media_subclass[] = { +    { +        0x00, "video device",              NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x01, "audio device",              NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x02, "computer telephony device", NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc multimedia device",    NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t mem_subclass[] = { +    { +        0x00, "RAM controller",             NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x01, "flash controller",           NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_dev_t uninorth_agp_fake_bridge = { +    0xFFFF, 0xFFFF, +    "uni-north-agp", "uni-north-agp", NULL, "uni-north-agp", +    -1, -1, -1, +    NULL, &uninorth_pci_ops, +}; + +static pci_dev_t uninorth_fake_bridge = { +    0xFFFF, 0xFFFF, +    "uni-north", "uni-north", NULL, "uni-north", +    -1, -1, -1, +    NULL, &uninorth_pci_ops, +}; + +static pci_dev_t PREP_fake_bridge = { +    0xFFFF, 0xFFFF, +    "pci", "pci", NULL, "pci", +    -1, -1, -1, +    NULL, &PREP_pci_ops, +}; + +pci_dev_t grackle_fake_bridge = { +    0xFFFF, 0xFFFF, +    "pci", "pci-bridge", "DEC,21154", "DEC,21154.pci-bridge", +    -1, -1, -1, +    NULL, &grackle_pci_ops, +}; + +static pci_dev_t hbrg_devices[] = { +    { +        0x106B, 0x0020, NULL, +        "pci", "AAPL,UniNorth", "uni-north", +        3, 2, 1, +        NULL, &uninorth_agp_fake_bridge, +    }, +    { +        0x106B, 0x001F, NULL,  +        "pci", "AAPL,UniNorth", "uni-north", +        3, 2, 1, +        NULL, &uninorth_fake_bridge, +    }, +    { +        0x106B, 0x001E, NULL, +        "pci", "AAPL,UniNorth", "uni-north", +        3, 2, 1, +        NULL, &uninorth_fake_bridge, +    }, +    { +        0x1057, 0x0002, "pci", +        "pci", "MOT,MPC106", "grackle", +        3, 2, 1, +        NULL, &grackle_fake_bridge, +    }, +    { +        0x1057, 0x4801, NULL, +        "pci-bridge", "PREP Host PCI Bridge - Motorola Raven", NULL, +        3, 2, 1, +        NULL, &PREP_pci_ops, +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +static pci_dev_t PCIbrg_devices[] = { +    { +        0x1011, 0x0026, NULL, +        "pci-bridge", NULL, NULL, +        3, 2, 1, +        NULL, &PREP_pci_ops, +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +static pci_subclass_t bridg_subclass[] = { +    { +        0x00, "PCI host bridge",           NULL,  hbrg_devices, NULL, +        NULL, NULL, +    }, +    { +        0x01, "ISA bridge",                NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x02, "EISA bridge",               NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x03, "MCA bridge",                NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x04, "PCI-to-PCI bridge",         NULL,  PCIbrg_devices, NULL, +        NULL, NULL, +    }, +    { +        0x05, "PCMCIA bridge",             NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x06, "NUBUS bridge",              NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x07, "cardbus bridge",            NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x08, "raceway bridge",            NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x09, "semi-transparent PCI-to-PCI bridge", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x0A, "infiniband-to-PCI bridge",  NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc PCI bridge",           NULL,  NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_iface_t serial_iface[] = { +    { +        0x00, "XT serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "16450 serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "16550 serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x03, "16650 serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x04, "16750 serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x05, "16850 serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x06, "16950 serial controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_iface_t par_iface[] = { +    { +        0x00, "parallel port", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "bi-directional parallel port", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "ECP 1.x parallel port", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x03, "IEEE 1284 controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFE, "IEEE 1284 device", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_iface_t modem_iface[] = { +    { +        0x00, "generic modem", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "Hayes 16450 modem", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "Hayes 16550 modem", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x03, "Hayes 16650 modem", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x04, "Hayes 16750 modem", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_subclass_t comm_subclass[] = { +    { +        0x00, "serial controller",          NULL, NULL, serial_iface, +        NULL, NULL, +    }, +    { +        0x01, "parallel port",             NULL, NULL, par_iface, +        NULL, NULL, +    }, +    { +        0x02, "multiport serial controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x03, "modem",                     NULL, NULL, modem_iface, +        NULL, NULL, +    }, +    { +        0x04, "GPIB controller",           NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x05, "smart card",                NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc communication device", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL, NULL, NULL, +        NULL, NULL, +    }, +}; + +static pci_iface_t pic_iface[] = { +    { +        0x00, "8259 PIC", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "ISA PIC", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "EISA PIC", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x10, "I/O APIC", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x20, "I/O APIC", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_iface_t dma_iface[] = { +    { +        0x00, "8237 DMA controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "ISA DMA controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "EISA DMA controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_iface_t tmr_iface[] = { +    { +        0x00, "8254 system timer", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "ISA system timer", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "EISA system timer", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_iface_t rtc_iface[] = { +    { +        0x00, "generic RTC controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "ISA RTC controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static const pci_dev_t sys_devices[] = { +    /* IBM MPIC controller */ +    {  +        0x1014, 0x0002, +        "open-pic", "MPIC", NULL, "chrp,open-pic", +        0, 0, 2, +        NULL, NULL, +    }, +    /* IBM MPIC2 controller */ +    {  +        0x1014, 0xFFFF, +        "open-pic", "MPIC2", NULL, "chrp,open-pic", +        0, 0, 2, +        NULL, NULL, +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +static pci_subclass_t sys_subclass[] = { +    { +        0x00, "PIC",                       NULL, NULL, pic_iface, +        NULL, NULL, +    }, +    { +        0x01, "DMA controller",             NULL, NULL, dma_iface, +        NULL, NULL, +    }, +    { +        0x02, "system timer",              NULL, NULL, tmr_iface, +        NULL, NULL, +    }, +    { +        0x03, "RTC controller",             NULL, NULL, rtc_iface, +        NULL, NULL, +    }, +    { +        0x04, "PCI hotplug controller",     NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc system peripheral",    NULL, sys_devices, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t inp_subclass[] = { +    { +        0x00, "keyboard controller",        NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x01, "digitizer",                 NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x02, "mouse controller",           NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x03, "scanner controller",         NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x04, "gameport controller",        NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc input device",         NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t dock_subclass[] = { +    { +        0x00, "generic docking station",   NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc docking station",      NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t cpu_subclass[] = { +    { +        0x00, "i386 processor",            NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x01, "i486 processor",            NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x02, "pentium processor",         NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x10, "alpha processor",           NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x20, "PowerPC processor",         NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x30, "MIPS processor",            NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x40, "co-processor",              NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_iface_t usb_iface[] = { +    { +        0x00, "UHCI USB controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x10, "OHCI USB controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x20, "EHCI USB controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x80, "misc USB controller", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFE, "USB device", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_iface_t ipmi_iface[] = { +    { +        0x00, "IPMI SMIC interface", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x01, "IPMI keyboard interface", NULL, +        NULL, NULL, NULL, +    }, +    { +        0x02, "IPMI block transfer interface", NULL, +        NULL, NULL, NULL, +    }, +    { +        0xFF, NULL, NULL, +        NULL, NULL, NULL, +    }, +}; + +static pci_subclass_t ser_subclass[] = { +    { +        0x00, "Firewire bus controller",    "ieee1394", NULL, NULL, +        NULL, NULL, +    }, +    { +        0x01, "ACCESS bus controller",      NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x02, "SSA controller",             NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x03, "USB controller",             "usb", NULL, usb_iface, +        NULL, NULL, +    }, +    { +        0x04, "fibre channel controller",   NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x05, "SMBus controller",           NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x06, "InfiniBand controller",      NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x07, "IPMI interface",            NULL, NULL,  ipmi_iface, +        NULL, NULL, +    }, +    { +        0x08, "SERCOS controller",          NULL, NULL,  ipmi_iface, +        NULL, NULL, +    }, +    { +        0x09, "CANbus controller",          NULL, NULL,  ipmi_iface, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t wrl_subclass[] = { +    { +        0x00, "IRDA controller",           NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x01, "consumer IR controller",    NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x10, "RF controller",             NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x11, "bluetooth controller",      NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x12, "broadband controller",      NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc wireless controller",  NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t sat_subclass[] = { +    { +        0x01, "satellite TV controller",   NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x02, "satellite audio controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x03, "satellite voice controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x04, "satellite data controller", NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t crypt_subclass[] = { +    { +        0x00, "cryptographic network controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x10, "cryptographic entertainment controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc cryptographic controller",    NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static pci_subclass_t spc_subclass[] = { +    { +        0x00, "DPIO module",               NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x01, "performances counters",     NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x10, "communication synchronisation", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0x20, "management card",           NULL, NULL,  NULL, +        NULL, NULL, +    }, +    { +        0x80, "misc signal processing controller", NULL, NULL, NULL, +        NULL, NULL, +    }, +    { +        0xFF, NULL,                        NULL,  NULL,  NULL, +        NULL, NULL, +    }, +}; + +static const pci_class_t pci_classes[] = { +    /* 0x00 */ +    { "undefined",                         NULL,             undef_subclass, }, +    /* 0x01 */ +    { "mass-storage controller",           NULL,              mass_subclass, }, +    /* 0x02 */ +    { "network controller",                "network",          net_subclass, }, +    /* 0x03 */ +    { "display controller",                "display",        displ_subclass, }, +    /* 0x04 */ +    { "multimedia device",                 NULL,             media_subclass, }, +    /* 0x05 */  +    { "memory controller",                 "memory-controller", mem_subclass, }, +    /* 0x06 */ +    { "PCI bridge",                        "pci",            bridg_subclass, }, +    /* 0x07 */ +    { "communication device",              NULL,               comm_subclass,}, +    /* 0x08 */ +    { "system peripheral",                 NULL,               sys_subclass, }, +    /* 0x09 */ +    { "input device",                      NULL,               inp_subclass, }, +    /* 0x0A */ +    { "docking station",                   NULL,              dock_subclass, }, +    /* 0x0B */ +    { "processor",                         NULL,               cpu_subclass, }, +    /* 0x0C */ +    { "serial bus controller",             NULL,               ser_subclass, }, +    /* 0x0D */ +    { "wireless controller",               NULL,               wrl_subclass, }, +    /* 0x0E */ +    { "intelligent I/O controller",        NULL,               NULL,         }, +    /* 0x0F */ +    { "satellite communication controller", NULL,               sat_subclass, }, +    /* 0x10 */ +    { "cryptographic controller",           NULL,             crypt_subclass, }, +    /* 0x11 */ +    { "signal processing controller",       NULL,               spc_subclass, }, +}; + +static int macio_config_cb (pci_device_t *device) +{ +    void *private_data; + +    private_data = cuda_init(device->regions[0] + 0x16000); +    OF_finalize_pci_macio(device->common.OF_private, +                          device->regions[0] & ~0x0000000F, device->sizes[0], +                          private_data); + +    return 0; +} + +static const pci_dev_t misc_pci[] = { +    /* Paddington Mac I/O */ +    {  +        0x106B, 0x0017, +        "mac-io", "mac-io", "AAPL,343S1211", "paddington\1heathrow", +        1, 1, 1, +        &macio_config_cb, NULL, +    }, +    /* KeyLargo Mac I/O */ +    {  +        0x106B, 0x0022, +        "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo", +        1, 1, 2, +        &macio_config_cb, NULL, +    }, +    { +        0xFFFF, 0xFFFF, +        NULL, NULL, NULL, NULL, +        -1, -1, -1, +        NULL, NULL, +    }, +}; + +static pci_dev_t *pci_find_device (uint8_t class, uint8_t subclass, +                                   uint8_t iface, uint16_t vendor, +                                   uint16_t product) +{ +    int (*config_cb)(pci_device_t *device); +    const pci_class_t *pclass; +    const pci_subclass_t *psubclass; +    const pci_iface_t *piface; +    const pci_dev_t *dev; +    const void *private; +    pci_dev_t *new; +    const unsigned char *name, *type; + +    name = "unknown"; +    type = "unknown"; +    config_cb = NULL; +    private = NULL; +#if 0 +    printf("check PCI device : %x %x (%x %x %x)\n", +           vendor, product, class, subclass, iface); +#endif +    if (class == 0x00 && subclass == 0x01) { +        /* Special hack for old style VGA devices */ +        class = 0x03; +        subclass = 0x00; +    } else if (class == 0xFF) { +        /* Special case for misc devices */ +        dev = misc_pci; +        goto find_device; +    } +    if (class > (sizeof(pci_classes) / sizeof(pci_class_t))) { +        name = "invalid PCI device"; +        type = "invalid"; +        goto bad_device; +    } +    pclass = &pci_classes[class]; +    name = pclass->name; +    type = pclass->type; +    for (psubclass = pclass->subc; ; psubclass++) { +        if (psubclass->subclass == 0xFF) +            goto bad_device; +        if (psubclass->subclass == subclass) { +            if (psubclass->name != NULL) +                name = psubclass->name; +            if (psubclass->type != NULL) +                type = psubclass->type; +            if (psubclass->config_cb != NULL) { +                config_cb = psubclass->config_cb; +            } +            if (psubclass->private != NULL) +                private = psubclass->private; +            if (psubclass->iface != NULL) +                break; +            dev = psubclass->devices; +            goto find_device; +        } +    } +    for (piface = psubclass->iface; ; piface++) { +        if (piface->iface == 0xFF) { +            dev = psubclass->devices; +            break; +        } +        if (piface->iface == iface) { +            if (piface->name != NULL) +                name = piface->name; +            if (piface->type != NULL) +                type = piface->type; +            if (piface->config_cb != NULL) { +                config_cb = piface->config_cb; +            } +            if (piface->private != NULL) +                private = piface->private; +            dev = piface->devices; +            break; +        } +    } +    find_device: +    for (;; dev++) { +        if (dev->vendor == 0xFFFF && dev->product == 0xFFFF) { +            goto bad_device; +        } +        if (dev->vendor == vendor && dev->product == product) { +            if (dev->name != NULL) +                name = dev->name; +            if (dev->type != NULL) +                type = dev->type; +            if (dev->config_cb != NULL) { +                config_cb = dev->config_cb; +            } +            if (dev->private != NULL) +                private = dev->private; +            new = malloc(sizeof(pci_dev_t)); +            if (new == NULL) +                return NULL; +            new->vendor = vendor; +            new->product = product; +            new->type = type; +            new->name = name; +            new->model = dev->model; +            new->compat = dev->compat; +            new->acells = dev->acells; +            new->scells = dev->scells; +            new->icells = dev->icells; +            new->config_cb = config_cb; +            new->private = private; + +            return new; +        } +    } + bad_device: +    printf("Cannot manage '%s' PCI device type '%s':\n %x %x (%x %x %x)\n", +           name, type, vendor, product, class, subclass, iface); + +    return NULL; +} + +/* PCI devices discovery helpers */ +static inline void pci_fill_common (pci_common_t *comm, pci_u_t *parent, +                                    int type, pci_dev_t *device) +{ +    comm->type = type; +    comm->device = device; +    comm->parent = parent; +} + +static inline void pci_fill_device (pci_device_t *device, pci_u_t *parent, +                                    int type, uint8_t bus, uint8_t devfn, +                                    pci_dev_t *dev, uint32_t class_code) +{ +    pci_fill_common(&device->common, parent, type, dev); +    device->bus = bus; +    device->devfn = devfn; +    device->class_code = class_code; +    device->rev = class_code; +} + +static inline void pci_update_device (pci_bridge_t *bridge, +                                      pci_device_t *device, +                                      uint8_t min_grant, uint8_t max_latency, +                                      int irq_line) +{ +    uint32_t cmd, addr; +    int i; + +    device->min_grant = min_grant; +    device->max_latency = max_latency; +    device->irq_line = irq_line; +    if (irq_line != -1) { +        pci_config_writeb(bridge, device->bus, device->devfn, +                          0x3c, device->irq_line); +        printf("MAP PCI device %d:%d to IRQ %d\n", +               device->bus, device->devfn, irq_line); +    } +    for (i = 0; i < 7; i++) { +        if ((device->regions[i] & ~0xF) != 0x00000000 && +            (device->regions[i] & ~0xF) != 0xFFFFFFF0) { +            printf("Map PCI device %d:%d %d to %0x %0x (%s)\n", +                   device->bus, device->devfn, i, +                   device->regions[i], device->sizes[i], +                   (device->regions[i] & 0x00000001) && i != 6 ? "I/O" :  +                    "memory"); +            if (i != 6) { +            cmd = pci_config_readl(bridge, device->bus, device->devfn, 0x04); +            if (device->regions[i] & 0x00000001) +                cmd |= 0x00000001; +            else +                cmd |= 0x00000002; +            pci_config_writel(bridge, device->bus, device->devfn, 0x04, cmd); +            } +            if (i == 6) +                addr = 0x30; /* PCI ROM */ +            else +                addr = 0x10 + (i * sizeof(uint32_t)); +            if (device->regions[i] & 0x00000001) { +            pci_config_writel(bridge, device->bus, device->devfn, +                              addr, device->regions[i] - 0x80000000); +            } else { +            pci_config_writel(bridge, device->bus, device->devfn, +                              addr, device->regions[i] - 0xc0000000); +            } +        } +    } +} + +static pci_host_t *pci_add_host (pci_host_t **hostp, pci_dev_t *device, +                                 uint32_t class_code) +{ +    pci_host_t *new, **lnk; + +    new = malloc(sizeof(pci_host_t)); +    if (new == NULL) +        return NULL; +    pci_fill_common(&new->dev.common, NULL, PCI_HOST_BRIDGE, device); +    new->dev.class_code = class_code; +    new->dev.rev = class_code; +    for (lnk = hostp; *lnk != NULL; lnk = &((*lnk)->next)) +        continue; +    *lnk = new; +     +    return new; +} + +static pci_bridge_t *pci_add_bridge (pci_host_t *host, +                                     uint8_t bus, uint8_t devfn, +                                     pci_dev_t *dev, uint32_t class_code, +                                     uint32_t cfg_base, uint32_t cfg_len, +                                     uint32_t cfg_addr, uint32_t cfg_data, +                                     uint32_t mem_base, uint32_t mem_len, +                                     uint32_t io_base, uint32_t io_len, +                                     uint32_t rbase, uint32_t rlen, +                                     uint32_t flags, const pci_ops_t *ops) +{ +    pci_u_t *u; +    pci_bridge_t *new, **lnk; + +    new = malloc(sizeof(pci_bridge_t)); +    if (new == NULL) +        return NULL; +    u = (pci_u_t *)host; +    pci_fill_device(&new->dev, u, PCI_DEV_BRIDGE, bus, devfn, dev, class_code); +    new->cfg_base = cfg_base; +    new->cfg_len = cfg_len; +    new->mem_base = mem_base; +    new->mem_len = mem_len; +    new->io_base = io_base; +    new->io_len = io_len; +    new->mem_cur = mem_base; +    if (io_base != 0x00000000) +        new->io_cur = io_base + 0x1000; +    else +        new->io_cur = 0x00000000; +    new->cfg_addr = cfg_addr; +    new->cfg_data = cfg_data; +    new->rbase = rbase; +    new->rlen = rlen; +    new->flags = flags; +    new->ops = ops; +    for (lnk = &host->bridge; *lnk != NULL; lnk = &((*lnk)->next)) +        continue; +    *lnk = new; +     +    return new; +} + +static pci_device_t *pci_add_device (pci_bridge_t *bridge, +                                     uint8_t bus, uint8_t devfn, +                                     pci_dev_t *dev, uint32_t class_code) +{ +    pci_u_t *u; +    pci_device_t *new, **lnk; + +    new = malloc(sizeof(pci_device_t)); +    if (new == NULL) +        return NULL; +    u = (pci_u_t *)bridge; +    pci_fill_device(new, u, PCI_DEV_BRIDGE, bus, devfn, dev, class_code); +    for (lnk = &bridge->devices; *lnk != NULL; lnk = &((*lnk)->next)) +        continue; +    *lnk = new; + +    return new; +} + +static pci_u_t *pci_check_device (pci_host_t **hostp, pci_host_t **phost, +                                  uint8_t bus, uint8_t devfn, +                                  uint16_t checkv, uint16_t checkp, +                                  uint8_t cclass, uint8_t csubclass, +                                  uint8_t ciface, int check_bridges) +{ +    pci_u_t *ret; +    pci_host_t *host, *newh; +    pci_bridge_t *bridge, *newb; +    pci_device_t *newd; +    pci_dev_t *dev; +    uint32_t *io_base, *mem_base, *base; +    uint32_t ccode, addr, omask, amask, size, smask, reloc, min_align; +    uint16_t vendor, product; +    uint8_t class, subclass, iface, rev, min_grant, max_latency; +    int i, max_areas, irq_line, irq_pin; +     +    ret = NULL; +    newd = NULL; +    host = *hostp; +    irq_line = -1; +    bridge = host->bridge; +    vendor = pci_config_readw(bridge, bus, devfn, 0x00); +    product = pci_config_readw(bridge, bus, devfn, 0x02); +    if (vendor == 0xFFFF && product == 0xFFFF) { +        /* No device: do nothing */ +        goto out; +    } +    ccode = pci_config_readl(bridge, bus, devfn, 0x08); +    class = ccode >> 24; +    subclass = ccode >> 16; +    iface = ccode >> 8; +    rev = ccode; +    if (checkv != 0xFFFF && vendor != checkv) { +#if 0 +        printf("Mismatching vendor for dev %x %x: %x %x\n", +               bus, devfn, checkv, vendor); +#endif +        goto out; +    } +    if (checkp != 0xFFFF && product != checkp) { +#if 0 +        printf("Mismatching product for dev %x %x: %x %x\n", +               bus, devfn, checkp, product); +#endif +        goto out; +    } +    if (cclass != 0xFF && class != cclass) { +#if 0 +        printf("Mismatching class for dev %x %x: %x %x\n", +               bus, devfn, cclass, class); +#endif +        goto out; +    } +    if (csubclass != 0xFF && subclass != csubclass) { +#if 0 +        printf("Mismatching subclass for dev %x %x: %x %x\n", +               bus, devfn, csubclass, subclass); +#endif +        goto out; +    } +    if (ciface != 0xFF && iface != ciface) { +#if 0 +        printf("Mismatching iface for dev %x %x: %x %x\n", +               bus, devfn, ciface, iface); +#endif +        goto out; +    } +    dev = pci_find_device(class, subclass, iface, vendor, product); +    if (dev == NULL) { +        goto out; +    } +    min_grant = pci_config_readb(bridge, bus, devfn, 0x3C); +    max_latency = pci_config_readb(bridge, bus, devfn, 0x3D); +    /* Special cases for bridges */ +    if (class == 0x06) { +        if (check_bridges < 1) +            goto out; +        if (subclass == 0x00) {             +            if (check_bridges < 2) +                goto out; +            /* host bridge case */ +            printf("Found new host bridge '%s' '%s' '%s'...\n", +                   dev->type, dev->model, dev->compat); +            newh = pci_add_host(phost, dev, ccode); +            if (newh == NULL) { +                printf("Can't allocate new host bridge...\n"); +                goto out; +            } +            ret = (pci_u_t *)newh; +#if 0 +            if ((*hostp)->bridge->dev.common.type != PCI_FAKE_BRIDGE) { +                printf("Keep PCI bridge\n"); +                /* If we already found a PCI bridge, keep it */ +                newh->bridge = (*phost)->bridge; +                goto out; +            } +            printf("Add fake PCI bridge\n"); +            /* Add fake PCI bridge */ +            newh->bridge = NULL; +            dev = dev->private; +            newb = pci_add_bridge(host, bus, devfn, dev, ccode, +                                  bridge->cfg_base, bridge->cfg_len, +                                  bridge->cfg_addr, bridge->cfg_data, +                                  bridge->mem_base, bridge->mem_len, +                                  bridge->io_base, bridge->io_len, +                                  bridge->rbase, bridge->rlen, +                                  bridge->flags, dev->private); +            if (newb == NULL) { +                printf("Can't allocate new PCI bridge\n"); +                goto out; +            } +            newb->dev.common.type = PCI_FAKE_BRIDGE; +            newb->devices = bridge->devices; +#else +            newh->bridge = (*hostp)->bridge; +            newb = newh->bridge; +#endif +            newd = &bridge->dev; +            host = newh; +            host->dev.common.OF_private = +                OF_register_pci_host(dev, rev, ccode, +                                     bridge->cfg_base, bridge->cfg_len, +                                     bridge->mem_base, bridge->mem_len, +                                     bridge->io_base, bridge->io_len, +                                     bridge->rbase, bridge->rlen, +                                     min_grant, max_latency); +            goto update_device; +        } else if (subclass == 0x04) { +            /* PCI-to-PCI bridge case */ +            printf("Found new PCI bridge '%s' '%s' '%s' '%s' %p...\n", +                   dev->name, dev->type, dev->model, dev->compat, +                   dev->private); +            newb = pci_add_bridge(host, bus + 1, devfn, dev, ccode, +                                  bridge->cfg_base, bridge->cfg_len, +                                  bridge->cfg_addr, bridge->cfg_data, +                                  bridge->mem_base, bridge->mem_len, +                                  bridge->io_base, bridge->io_len, +                                  bridge->rbase, bridge->rlen, +                                  0, dev->private); +            if (newb == NULL) { +                printf("Can't allocate new PCI bridge...\n"); +                goto out; +            } +            ret = (pci_u_t *)newb; +#if 0 +            printf("Config addr: 0x%0x data: 0x%0x cfg_base: 0x%08x " +                   "base: 0x%0x\n", +                   newb->cfg_addr, newb->cfg_data, newb->cfg_base, newb->base); +            printf("newb: %p hb: %p b: %p next: %p\n", newb, +                   host->bridge, bridge, host->bridge->next); +#endif +            if (bridge->dev.common.type == PCI_FAKE_BRIDGE) { +                /* Free fake bridge if it's still present +                 * Note: it should always be first... +                 */ +                printf("Free fake bridge\n"); +                newb->devices = host->bridge->devices; +                host->bridge = bridge->next; +            } +            bridge = host->bridge; +            newd = &bridge->dev; +#if 0 +            printf("newb: %p hb: %p b: %p next: %p dev: %p\n", newb, +                   host->bridge, bridge, host->bridge->next, newd); +#endif +            max_areas = 2; +            bridge->dev.common.OF_private = +                OF_register_pci_bridge(host->dev.common.OF_private, +                                       dev, devfn, rev, ccode, +                                       bridge->cfg_base, bridge->cfg_len, +                                       min_grant, max_latency); +            goto configure_device; +        } +        printf("Bridges type %x aren't managed for now\n", subclass); +        free(dev); +        goto out; +    } +    /* Main case */ +    printf("Found PCI device %x:%x %d-%d %d %d\n", +           vendor, product, bus, devfn, class, subclass); +    printf("=> '%s' '%s' '%s' '%s' (%p)\n", +           dev->name, dev->type, dev->model, dev->compat, dev->config_cb); +    newd = pci_add_device(bridge, bus, devfn, dev, ccode); +    if (newd == NULL) { +        printf("Cannot allocate new PCI device: %x %x (%x %x %x) '%s' '%s'\n", +               vendor, product, class, subclass, iface, dev->type, dev->name); +        goto out; +    } +    ret = (pci_u_t *)newd; +    max_areas = 7; +    /* register PCI device in OF tree */ +    if (bridge->dev.common.type == PCI_FAKE_BRIDGE) { +        newd->common.OF_private = +            OF_register_pci_device(host->dev.common.OF_private, dev, devfn, +                                   rev, ccode, min_grant, max_latency); +    } else { +        newd->common.OF_private = +            OF_register_pci_device(bridge->dev.common.OF_private, dev, devfn, +                                   rev, ccode, min_grant, max_latency); +    } + configure_device: +#if 0 +    printf("Config addr: 0x%08x data: 0x%08x cfg_base: 0x%08x base: 0x%08x\n", +           bridge->cfg_addr, bridge->cfg_data, bridge->cfg_base, bridge->base); +    printf("ops: %p uni-ops: %p\n", bridge->ops, &uninorth_pci_ops); +#endif +    io_base = &bridge->io_cur; +    mem_base = &bridge->mem_cur; +    omask = 0x00000000; +    for (i = 0; i < max_areas; i++) { +        newd->regions[i] = 0x00000000; +        newd->sizes[i] = 0x00000000; +        if ((omask & 0x0000000F) == 0x4) { +            /* Handle 64 bits memory mapping */ +            continue; +        } +        if (i == 6) +            addr = 0x30; /* PCI ROM */ +        else +        addr = 0x10 + (i * sizeof(uint32_t)); +        /* Get region size +         * Note: we assume it's always a power of 2 +         */ +        pci_config_writel(bridge, bus, devfn, addr, 0xFFFFFFFF); +        smask = pci_config_readl(bridge, bus, devfn, addr); +        if (smask == 0x00000000 || smask == 0xFFFFFFFF) +            continue; +        if ((smask & 0x00000001) != 0 && i != 6) { +            /* I/O space */ +            base = io_base; +            /* Align to a minimum of 256 bytes (arbitrary) */ +            min_align = 1 << 8; +            amask = 0x00000001; +        } else { +            /* Memory space */ +            base = mem_base; +            /* Align to a minimum of 64 kB (arbitrary) */ +            min_align = 1 << 16; +            amask = 0x0000000F; +            if (i == 6) +                smask |= 1; /* PCI ROM enable */ +        } +        omask = smask & amask; +        smask &= ~amask; +        size = (~smask) + 1; +        reloc = *base; +#if 0 +        printf("Relocate %s area %d of size %0x to 0x%0x (0x%0x 0x%0x %0x)\n", +               omask & 0x00000001 ? "I/O" : "memory", i, +               size, reloc, reloc + size, smask); +#endif +        if (size < min_align) { +            size = min_align; +        } +        /* Align reloc to size */ +        reloc = (reloc + size - 1) & ~(size - 1); +        (*base) = reloc + size; +        if (omask & 0x00000001) { +            /* I/O resources are offsets */ +            reloc -= bridge->io_base; +        } +        /* Set region address */ +        newd->regions[i] = reloc | omask; +        newd->sizes[i] = size; +    } +    /* Realign io-base to 4 kB */ +    bridge->io_base = (bridge->io_base + (1 << 12) - 1) & ~((1 << 12) - 1); +    /* Realign mem-base to 1 MB */ +    bridge->mem_base = (bridge->mem_base + (1 << 20) - 1) & ~((1 << 20) - 1); + +    irq_pin = pci_config_readb(bridge, bus, devfn, 0x3d); +    if (irq_pin > 0) { +        /* assign the IRQ */ +        irq_pin = ((devfn >> 3) + irq_pin - 1) & 3; +        /* XXX: should base it on the PCI bridge type, not the arch */ +        switch(arch) { +        case ARCH_PREP: +            { +            int elcr_port, val; +            irq_line = prep_pci_irqs[irq_pin]; +            /* set the IRQ to level-sensitive */ +            elcr_port = 0x4d0 + (irq_line >> 8); +            val = inb(elcr_port); +            val |= 1 << (irq_line & 7); +            outb(elcr_port, val); +            } +            break; +        case ARCH_MAC99: +            irq_line = pmac_pci_irqs[irq_pin]; +            break; +        case ARCH_HEATHROW: +            irq_line = heathrow_pci_irqs[irq_pin]; +            break; +        default: +            break; +        } +    } + update_device: +    pci_update_device(bridge, newd, min_grant, max_latency, irq_line); +    OF_finalize_pci_device(newd->common.OF_private, bus, devfn, +                           newd->regions, newd->sizes, irq_line); +    /* Call special inits if needed */ +    if (dev->config_cb != NULL) +        (*dev->config_cb)(newd); + + out: +    return ret; +} + +static int pci_check_host (pci_host_t **hostp, +                           uint32_t cfg_base, uint32_t cfg_len, +                           uint32_t mem_base, uint32_t mem_len, +                           uint32_t io_base, uint32_t io_len, +                           uint32_t rbase, uint32_t rlen, +                           uint16_t checkv, uint16_t checkp) +{ +    pci_host_t *fake_host, *host, **phost; +    pci_bridge_t *fake_bridge; +    pci_dev_t *dev; +    int bus, devfn; +    int ret; + +    fake_host = NULL; +    ret = -1; +    switch (arch) { +    case ARCH_PREP: +        dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); +        if (dev == NULL) +            return -1; +        fake_host = pci_add_host(hostp, dev, +                                 (0x06 << 24) | (0x00 << 16) | (0xFF << 8)); +        if (fake_host == NULL) +            return -1; +        fake_host->dev.common.type = PCI_FAKE_HOST; +        dev = &PREP_fake_bridge; +        if (dev == NULL) +            goto free_fake_host; +        fake_bridge = pci_add_bridge(fake_host, 0, 11, dev, +                                     (0x06 << 24) | (0x00 << 16) | (0xFF << 8), +                                     cfg_base, cfg_len, +                                     cfg_base + 0x00800000, +                                     cfg_base + 0x00C00000, +                                     mem_base, mem_len, +                                     io_base, io_len, +                                     rbase, rlen, +                                     0, +                                     &PREP_pci_ops); +        if (fake_bridge == NULL) +            goto free_fake_host; +        fake_bridge->dev.common.type = PCI_FAKE_BRIDGE; +        break; +    case ARCH_CHRP: +        /* TODO */ +        break; +    case ARCH_HEATHROW: +        dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); +        if (dev == NULL) +            return -1; +        fake_host = pci_add_host(hostp, dev, +                                 (0x06 << 24) | (0x00 << 16) | (0xFF << 8)); +        if (fake_host == NULL) +            return -1; +        fake_host->dev.common.type = PCI_FAKE_HOST; +        dev = &grackle_fake_bridge; +        if (dev == NULL) +            goto free_fake_host; +        fake_bridge = pci_add_bridge(fake_host, 0, 0, dev, +                                     (0x06 << 24) | (0x04 << 16) | (0xFF << 8), +                                     cfg_base, cfg_len, +                                     cfg_base + 0x7ec00000, +                                     cfg_base + 0x7ee00000, +                                     mem_base, mem_len, +                                     io_base, io_len, +                                     rbase, rlen, +                                     0, +                                     &grackle_pci_ops); +        if (fake_bridge == NULL) +            goto free_fake_host; +        fake_bridge->dev.common.type = PCI_FAKE_BRIDGE; +        break; +    case ARCH_MAC99: +        dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); +        if (dev == NULL) +            return -1; +        fake_host = pci_add_host(hostp, dev, +                                 (0x06 << 24) | (0x00 << 16) | (0xFF << 8)); +        if (fake_host == NULL) +            return -1; +        fake_host->dev.common.type = PCI_FAKE_HOST; +        dev = &uninorth_fake_bridge; +        if (dev == NULL) +            goto free_fake_host; +        fake_bridge = pci_add_bridge(fake_host, 0, 11, dev, +                                     (0x06 << 24) | (0x00 << 16) | (0xFF << 8), +                                     cfg_base, cfg_len, +                                     cfg_base + 0x00800000, +                                     cfg_base + 0x00C00000, +                                     mem_base, mem_len, +                                     io_base, io_len, +                                     rbase, rlen, +                                     BRIDGE_TYPE_UNINORTH, +                                     &uninorth_pci_ops); +        if (fake_bridge == NULL) +            goto free_fake_host; +        fake_bridge->dev.common.type = PCI_FAKE_BRIDGE; +        fake_bridge->flags |= BRIDGE_TYPE_UNINORTH; +        break; +    case ARCH_POP: +        /* TODO */ +        break; +    } +    host = NULL; +    phost = &host; +    for (bus = 0; bus < 256; bus++) { +        for (devfn = 0; devfn < 256; devfn++) { +            /* Find host bridge */ +            pci_check_device(hostp, phost, bus, devfn, +                             checkv, checkp, 0x06, 0x00, 0xFF, 2); +            if (host != NULL) { +                *hostp = host; +                OF_finalize_pci_host(host->dev.common.OF_private, bus, 1); +                ret = 0; +                goto done; +            } +        } +    } + done: +    free(fake_host->bridge); + free_fake_host: +    free(fake_host); + +    return ret; +} + +static int pci_check_devices (pci_host_t *host) +{ +    int bus, devfn; + +    /* Find all PCI bridges */ +    printf("Check PCI bridges\n"); +    for (bus = 0; bus < 256; bus++) { +        for (devfn = 0; devfn < 256; devfn++) { +            pci_check_device(&host, &host, bus, devfn, 0xFFFF, 0xFFFF, +                             0x06, 0xFF, 0xFF, 1); +        } +    } +    /* Now, find all other devices */ +    /* XXX: should recurse thru all host and bridges ! */ +    printf("Check PCI devices\n"); +    for (bus = 0; bus < 256; bus++) { +        for (devfn = 0; devfn < 256; devfn++) { +            pci_check_device(&host, &host, bus, devfn, 0xFFFF, 0xFFFF, +                             0xFF, 0xFF, 0xFF, 0); +        } +    } + +    return 0; +} + +pci_host_t *pci_init (void) +{ +    pci_host_t *pci_main = NULL, *curh; +    uint32_t rbase, rlen, cfg_base, cfg_len; +    uint32_t mem_base, mem_len, io_base, io_len; +    uint8_t busnum; + +    printf("Probing PCI devices\n"); +    /* We need to discover PCI bridges and devices */ +    switch (arch) { +    case ARCH_PREP: +        /* supposed to have 1 host bridge: +         * - the Motorola Raven PCI bridge +         */ +        cfg_base = 0x80000000; +        cfg_len  = 0x00100000; +        mem_base = 0xF0000000; +        mem_len  = 0x10000000; +        io_base  = 0x80000000; +        io_len   = 0x00010000; +#if 0 +        rbase    = 0x80C00000; /* ? */ +#else +        rbase    = 0x00000000; +#endif +        rlen     = 0x00400000; /* ? */ +        if (pci_check_host(&pci_main, cfg_base, cfg_len, +                           mem_base, mem_len, io_base, io_len, rbase, rlen, +                           0x1057, 0x4801) == 0) { +            isa_io_base = io_base; +            busnum++; +        } +        for (curh = pci_main; curh->next != NULL; curh = curh->next) +            continue; +        pci_check_devices(curh); +        break; +    case ARCH_CHRP: +        /* TODO */ +        break; +    case ARCH_HEATHROW: +        cfg_base = 0x80000000; +        cfg_len  = 0x7f000000; +        mem_base = 0x80000000; +        mem_len  = 0x01000000; +        io_base  = 0xfe000000; +        io_len   = 0x00800000; +#if 1 +        rbase    = 0xfd000000; +        rlen     = 0x01000000; +#else +        rbase    = 0x00000000; +        rlen     = 0x01000000; +#endif +        if (pci_check_host(&pci_main, cfg_base, cfg_len, +                           mem_base, mem_len, io_base, io_len, rbase, rlen, +                           0x1057, 0x0002) == 0) { +            isa_io_base = io_base; +            busnum++; +        } +        for (curh = pci_main; curh->next != NULL; curh = curh->next) +            continue; +        pci_check_devices(curh); +        break; +    case ARCH_MAC99: +        /* We are supposed to have 3 host bridges: +         * - the uninorth AGP bridge at 0xF0000000 +         * - the uninorth PCI expansion bridge at 0xF2000000 +         * - the uninorth PCI internal bridge at 0xF4000000 +         */ +        cfg_base = 0xF0000000; +        cfg_len  = 0x02000000; +        mem_base = 0x90000000; +        mem_len  = 0x10000000; +        io_base  = 0xF0000000; +        io_len   = 0x00800000; +        rbase    = 0xF1000000; +        rlen     = 0x01000000; +#if 0 +        if (pci_check_host(&pci_main, cfg_base, cfg_len, +                           mem_base, mem_len, io_base, io_len, rbase, rlen, +                           0x106b, 0x0020) == 0) { +            busnum++; +        } +        for (curh = pci_main; curh->next != NULL; curh = curh->next) +            continue; +        pci_check_devices(curh); +#endif + +        cfg_base = 0xF2000000; +        cfg_len  = 0x02000000; +        mem_base = 0x80000000; +        mem_len  = 0x10000000; +        io_base  = 0xF2000000; +        io_len   = 0x00800000; +#if 0 // Hack +        rbase    = 0xF3000000; +        rlen     = 0x01000000; +#else +        rbase    = 0x00000000; +        rlen     = 0x01000000; +#endif +        if (pci_check_host(&pci_main, cfg_base, cfg_len, +                           mem_base, mem_len, io_base, io_len, rbase, rlen, +                           0x106b, 0x001F) == 0) { +            isa_io_base = io_base; +            busnum++; +        } +        for (curh = pci_main; curh->next != NULL; curh = curh->next) +            continue; +        pci_check_devices(curh); + +#if 0 +        cfg_base = 0xF4000000; +        cfg_len  = 0x02000000; +        mem_base = 0xA0000000; +        mem_len  = 0x10000000; +        io_base  = 0xF4000000; +        io_len   = 0x00800000; +        rbase    = 0xF5000000; +        rlen     = 0x01000000; +        if (pci_check_host(&pci_main, cfg_base, cfg_len, +                           mem_base, mem_len, io_base, io_len, rbase, rlen, +                           0x106b, 0x001F) == 0) { +            busnum++; +        } +        for (curh = pci_main; curh->next != NULL; curh = curh->next) +            continue; +        pci_check_devices(curh); +#endif +        break; +    case ARCH_POP: +        /* TODO */ +        break; +    } +    printf("PCI probe done (%p)\n", pci_main); + +    return pci_main; +} + +void pci_get_mem_range (pci_host_t *host, uint32_t *start, uint32_t *len) +{ +    *start = host->bridge->mem_base; +    *len = host->bridge->mem_len; +} diff --git a/roms/openhackware/src/start.S b/roms/openhackware/src/start.S new file mode 100644 index 00000000..471e56fe --- /dev/null +++ b/roms/openhackware/src/start.S @@ -0,0 +1,379 @@ +/*  + *	<start.S> + *	 + *     BIOS start code for Open Hack'Ware. + *    + *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) + *    + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#define ASSEMBLY_CODE +#include "bios.h" + +.section .start, "ax" +.align 2 + +.globl _start +_start: +        /* Save our stack pointer */ +        lis    r11, saved_params@h                           ; +        ori    r11, r11, saved_params@l                      ; +        stw    r1, 0(r11)                                    ; +        /* Fill space from _bss_start to _ram_start with zeroes */ +        lis    r11, _bss_start@h                             ; +        ori    r11, r11, _bss_start@l                        ; +        lis    r12, _ram_start@h                             ; +        ori    r12, r12, _ram_start@l                        ; +        subf   r12, r11, r12                                 ; +        srawi  r12, r12, 2                                   ; +        cmpi   0, r12, 0                                     ; +        beq    _bss_done                                     ; +        mtctr  r12                                           ; +        subi   r11, r11, 4                                   ; +        li     r12, 0                                        ; +_bss_loop: +        stwu   r12, 4(r11)                                   ; +        bdnz   _bss_loop                                     ; +_bss_done: +        /* Now, we have a real C environment: call main */ +        bl     main                                          ; +        /* If we return, stop */ +.globl bug +bug: +        li     r0, 0x80                                      ; +        mtlr   r0                                            ; +        blr                                                  ; +_return_loop: +        b      _return_loop                                  ; + +.section .data +.align 2 +saved_params: +        .long 0x00000000 /* OF stack     */ +        .long 0x00000000 /* client stack */ +        .long 0x00000000 /* client link  */ +         +.section .text +.align 2 + +.globl transfer_handler +transfer_handler: +        /* Build a new stack room and launch loaded image +         * void transfer_handler (void *residual, void *load_addr, +         *                        void *OF_entry, void *bootinfos, +         *                        void *cmdline, void *unused, +         *                        void *nip, void *stack_base); +         */ +        mfmsr  r0                                            ; +        mtspr  SRR1, r0                                      ; +        mtspr  SRR0, r9                                      ; +        li     r0, 0                                         ; +        mr     r1, r10                                       ; +        stw    r1, -16(r1)                                   ; +        stwu   r0, -4(r1)                                    ; +        stwu   r0, -4(r1)                                    ; +        stwu   r0, -4(r1)                                    ; +        stwu   r0, -4(r1)                                    ; +        /* Skip frame pointer */         +        stwu   r0, -8(r1)                                    ; +        stwu   r0, -4(r1)                                    ; +        stwu   r0, -4(r1)                                    ; +        rfi                                                  ; +        /* Should never return, but who knows... */ +        bl     bug                                           ; + +.globl  OF_entry +OF_entry: +        /* Save the stack pointer and get our own one */ +        lis    r11, saved_params@h                           ; +        ori    r11, r11, saved_params@l                      ; +        mflr   r12                                           ; +        stw    r12, 8(r11)                                   ; +        stw    r1, 4(r11)                                    ; +        lwz    r1, 0(r11)                                    ; +        bl     OF_client_entry                               ; +        lis    r11, saved_params@h                           ; +        ori    r11, r11, saved_params@l                      ; +        lwz    r12, 8(r11)                                   ; +        mtlr   r12                                           ; +        lwz    r1, 4(r11)                                    ; +        blr                                                  ; +         +        /* PPC helpers */ +.globl mfmsr +mfmsr: +        /* uint32_t mfmsr (void); */ +        mfmsr  r3                                            ; +        blr                                                  ; +.globl mtmsr +mtmsr: +        /* void mtmsr (uint32_t msr); */ +        lis    r0, _mtmsr_rfi@h                              ; +        ori    r0, r0, _mtmsr_rfi@l                          ; +        mtspr  26, r0                                        ; +        mtspr  27, r3                                        ; +        rfi                                                  ; +_mtmsr_rfi: +        blr                                                  ; +.globl MMU_on +MMU_on: +        /* void MMU_on (void); */ +        stwu   r1, -16(r1)                                   ; +        mflr   r0                                            ; +        stw    r0, 20(r1)                                    ; +        mfmsr  r3                                            ; +        ori    r3, r3, 0x30                                  ; +        bl     mtmsr                                         ; +        lwz    r0, 20(r1)                                    ; +        mtlr   r0                                            ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; +         +.globl MMU_off +MMU_off: +        /* void MMU_off (void); */ +        stwu   r1, -16(r1)                                   ; +        mflr   r0                                            ; +        stw    r0, 20(r1)                                    ; +        mfmsr  r3                                            ; +        andi.  r3, r3, 0xFFCF                                ; +        bl     mtmsr                                         ; +        lwz    r0, 20(r1)                                    ; +        mtlr   r0                                            ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; +         +.globl mfpvr +mfpvr: +        /* uint32_t mfpvr (void); */ +        mfpvr  r3                                            ; +        blr                                                  ; + +.globl mftb +mftb: +        /* void mftb (uint32_t *tb); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        stw    r12,  8(r1)                                   ; +        /* No need to save lr */ +_tb_loop: +        mftbu  r11                                           ; +        mftb   r12                                           ; +        mftbu  r0                                            ; +        cmpw   r0, r11                                       ; +        bne    _tb_loop                                      ; +        stw    r11,  0(r3)                                   ; +        stw    r12,  4(r3)                                   ; +        lwz    r12,  8(r1)                                   ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ;       + +        /* IO helpers */ +.globl inb +inb: +        /* uint32_t inb (uint16_t port); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        lis    r11, isa_io_base@h                            ; +        ori    r11, r11, isa_io_base@l                       ; +        lwz    r11, 0(r11)                                   ; +        add    r3, r3, r11                                   ; +        lbz    r3, 0(r3)                                     ; +        eieio                                                ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl outb +outb: +        /* void outb (uint16_t port, uint32_t val); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        lis    r11, isa_io_base@h                            ; +        ori    r11, r11, isa_io_base@l                       ; +        lwz    r11, 0(r11)                                   ; +        add    r3, r3, r11                                   ; +        eieio                                                ; +        stb    r4, 0(r3)                                     ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl inw +inw: +        /* uint32_t inw (uint16_t port); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        lis    r11, isa_io_base@h                            ; +        ori    r11, r11, isa_io_base@l                       ; +        lwz    r11, 0(r11)                                   ; +        add    r3, r3, r11                                   ; +        lhbrx  r3, 0, r3                                     ; +        eieio                                                ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl outw +outw: +        /* void outw (uint16_t port, uint32_t val); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        lis    r11, isa_io_base@h                            ; +        ori    r11, r11, isa_io_base@l                       ; +        lwz    r11, 0(r11)                                   ; +        add    r3, r3, r11                                   ; +        eieio                                                ; +        sthbrx r4, 0, r3                                     ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl inl +inl: +        /* uint32_t inl (uint16_t port); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        lis    r11, isa_io_base@h                            ; +        ori    r11, r11, isa_io_base@l                       ; +        lwz    r11, 0(r11)                                   ; +        add    r3, r3, r11                                   ; +        lwbrx  r3, 0, r3                                     ; +        eieio                                                ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl outl +outl: +        /* void outl (uint16_t port, uint32_t val); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        lis    r11, isa_io_base@h                            ; +        ori    r11, r11, isa_io_base@l                       ; +        lwz    r11, 0(r11)                                   ; +        add    r3, r3, r11                                   ; +        eieio                                                ; +        stwbrx r4, 0, r3                                     ; +        lwz    r11, 12(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl eieio +eieio: +        eieio                                                ; +        blr                                                  ; +         +        /* Misc helpers */ +.globl ldswap16 +ldswap16: +        /* uint16_t ldswap16 (uint16_t *addr); */ +        lhbrx  r3, 0, r3                                     ; +        blr                                                  ; + +.globl stswap16 +stswap16: +        /* void stswap16 (void *addr, uint16_t val); */ +        sthbrx r4, 0, r3                                     ; +        blr                                                  ; + +.globl ldswap32 +ldswap32: +        /* uint32_t ldswap32 (uint32_t *addr); */ +        lwbrx  r3, 0, r3                                     ; +        blr                                                  ; + +.globl stswap32 +stswap32: +        /* void stswap32 (void *addr, uint32_t val); */ +        stwbrx r4, 0, r3                                     ; +        blr                                                  ; + +.globl mul64 +mul64: +        /* void mul64 (uint32_t *ret, uint32_t a, uint32_t b); */ +        mulhwu r0, r4, r5                                    ; +        stw    r0, 0(r3)                                     ; +        mullw  r0, r4, r5                                    ; +        stw    r0, 4(r3)                                     ; +        blr                                                  ; + +.globl add64 +add64: +        /* void add64 (uint32_t *ret, uint32_t *a, uint32_t *b); */ +        stwu   r1, -16(r1)                                   ; +        stw    r11, 12(r1)                                   ; +        stw    r12,  8(r1)                                   ; +        lwz    r11,  4(r4)                                   ; +        lwz    r12,  4(r5)                                   ; +        addc   r0, r11, r12                                  ; +        stw    r0,   4(r3)                                   ; +        lwz    r11,  0(r4)                                   ; +        lwz    r12,  0(r5)                                   ; +        adde   r0, r11, r12                                  ; +        stw    r0,   0(r3)                                   ; +        lwz    r12,  8(r1)                                   ; +        lwz    r11,  4(r1)                                   ; +        addi   r1, r1, 16                                    ; +        blr                                                  ; + +.globl setjmp +setjmp: +        /* int setjmp (jmp_buf env); */ +        /* save gprs */ +        stmw   r0, 0(r3)                                     ; +        /* save lr, ctr, xer and ccr */ +        mflr   r0                                            ; +        stw    r0, 0x80(r3)                                  ; +        mfctr  r0                                            ; +        stw    r0, 0x84(r3)                                  ; +        mfxer  r0                                            ; +        stw    r0, 0x88(r3)                                  ; +        mfcr   r0                                            ; +        stw    r0, 0x8C(r3)                                  ; +        /* return 0 */ +        li     r3, 0                                         ; +        blr                                                  ; + +.globl longjmp +longjmp: +        /* void longjmp (jmp_buf env, int val); */ +        /* Let's pretend env is our stack */ +        mr     r1, r3                                        ; +        /* Be sure we won't return 0 */ +        cmpi   0, r4, 0                                      ; +        bne    _longjmp_cont                                 ; +        addi   r4, r4, 1                                     ; +_longjmp_cont: +        /* Store return value in jmp_buf */ +        stw    r4, 0x0C(r1)                                  ; +        /* restore lr, ctr, xer and ccr */ +        lwz    r0, 0x80(r1)                                  ; +        mtlr   r0                                            ; +        lwz    r0, 0x84(r1)                                  ; +        mtctr  r0                                            ; +        lwz    r0, 0x88(r1)                                  ; +        mtxer  r0                                            ; +        lwz    r0, 0x8C(r1)                                  ; +        mtcr   r0                                            ; +        /* Restore r2 to r31 */ +        lmw    r2, 0x08(r1)                                  ; +        /* Restore r0 (could forget it...) */ +        lwz    r0, 0x00(r1)                                  ; +        /* Restore stack */ +        lwz    r1, 0x04(r1)                                  ; +        /* Return */ +        blr                                                  ; diff --git a/roms/openhackware/src/vectors.S b/roms/openhackware/src/vectors.S new file mode 100644 index 00000000..1c1bfee5 --- /dev/null +++ b/roms/openhackware/src/vectors.S @@ -0,0 +1,468 @@ +/*  + *   <vectors.S> + *       + *   Second stage boot-loader and exception vectors for Open Hack'Ware. + *    + *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) + *    + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#define ASSEMBLY_CODE +#include "bios.h" + +.section .text +.align 2 + +.globl _start +_start: +        /* Entry point */ +        li      r0, 0                                     ; +_turn_off_mmu: +        /* Be sure MMU is off and we are in 32 bits mode (for PPC64) */ +        lis     r11, _hw_init@h                           ; +        ori     r11, r11, _hw_init@l                      ; +        mtspr   26, r11                                   ; +        mtspr   27, r0                                    ; +        rfi                                               ; +_hw_init: +        /* May need more hw init here */ +_load_bios: +        /* Load the full BIOS into RAM */ +        lis     r12, bios_base@h                          ; +        ori     r12, r12, bios_base@l                     ; +        lmw     r29, 0(r12)                               ; +        /* Set up the C stack */ +        addis   r1, r29, 0x0040                           ; +        clrrwi  r1, r1, 19                                ; +        stw     r1, -16(r1)                               ; +        stwu    r0, -4(r1)                                ; +        stwu    r0, -4(r1)                                ; +        stwu    r0, -4(r1)                                ; +        stwu    r0, -4(r1)                                ; +        /* Skip frame pointer */         +        stwu    r0, -8(r1)                                ; +        stwu    r0, -4(r1)                                ; +        stwu    r0, -4(r1)                                ; +        /* Start copying */ +        mtctr   r30                                       ; +        subi    r12, r3, 4                                ; +        subi    r13, r29, 4                               ; +_bios_copy_loop: +        lwzu    r14, 4(r12)                               ; +        stwu    r14, 4(r13)                               ; +        bdnz    _bios_copy_loop                           ; +        /* Synchronize the whole execution context */ +        /* Also enable FPU */ +        ori     r0, r0, (1 << 13)                         ; +        mtspr   26, r29                                   ; +        mtspr   27, r0                                    ; +        rfi                                               ; +        /* If we ever return, stop */ +        bl      bug                                       ; + +.org 0x0080 +.section .text +.align 2 +bug: +        /* Dump the exception and its context */ +        mflr    r3                                        ; +        mfspr   r4, SRR0                                  ; +        mfspr   r5, SRR1                                  ; +        mfspr   r6, DAR                                   ; +        mfspr   r7, DSISR                                 ; +        /* Turn MMU off */ +        lis     r0, _bug_no_mmu@h                         ; +        ori     r0, r0, _bug_no_mmu@l                     ; +        mtspr   26, r0                                    ; +        li      r0, 0                                     ; +        mtspr   27, r0                                    ; +        rfi                                               ; +_bug_no_mmu: +        bl      dump_exception                            ; +_forever: +        /* Loop forever */ +        b       _forever                                  ; + +skip_exception: +        /* Skip external interrupts and decrementer exception */ +        /* BEWARE: be sure not to modify any register */ +        stw     r11, save_area@l(0)                       ; +        mfspr   r11, 27                                   ; +        clrlwi  r11, r11, 16                              ; +        mtspr   27, r11                                   ; +        lwz     r11, save_area@l(0)                       ; +        rfi                                               ; + +#define EXCP_BUG(entry)                                     \ +.org 0x##entry                                            ; \ +.section .text                                            ; \ +.align 2                                                  ; \ +excp_##entry:                                             ; \ +        bl bug + +#define EXCP_SKIP(entry)                                    \ +.org 0x##entry                                            ; \ +.section .text                                            ; \ +.align 2                                                  ; \ +excp_##entry##:                                           ; \ +        b skip_exception + +        /* Exception vectors */ +        /* Reset exception */ +.org 0x0100 +excp_0100: +        ba 0xfffffffc + +        /* Machine check exception */ +        EXCP_BUG(0200)                                    ; + +        /* DSI exception */ +        EXCP_BUG(0300)                                    ; + +        /* ISI exception */ +        EXCP_BUG(0400)                                    ; + +        /* External interrupt: skip it */ +        EXCP_SKIP(0500)                                   ; + +        /* Alignment exception */ +        EXCP_BUG(0600)                                    ; + +        /* Program exception */ +        EXCP_BUG(0700)                                    ; + +        /* No floating point exception */ +        EXCP_BUG(0800)                                    ; + +        /* Decrementer exception: skip it */ +        EXCP_SKIP(0900)                                   ; + +        /* Reserved A exception */ +        EXCP_BUG(0A00)                                    ; + +        /* Reserved B exception */ +        EXCP_BUG(0B00)                                    ; + +        /* System call exception */ +        EXCP_BUG(0C00)                                    ; + +        /* Trace exception */ +        EXCP_BUG(0D00)                                    ; + +        /* Floating point assist exception */ +        EXCP_BUG(0E00)                                    ; + +        /* Performance monitor exception */ +        EXCP_BUG(0F00)                                    ; + +        /* Instruction TLB miss exception */ +        EXCP_BUG(1000)                                    ; + +        /* Data TLB miss for store exception */ +        EXCP_BUG(1100)                                    ; + +        /* Data TLB miss for load exception */ +        EXCP_BUG(1200)                                    ; + +        /* Instruction address breakpoint exception */ +        EXCP_BUG(1300)                                    ; + +        /* System management interrupt exception */ +        EXCP_BUG(1400)                                    ; + +        /* Thermal management exception */ +        EXCP_BUG(1500)                                    ; + +        /* Unknown exceptions */ +        EXCP_BUG(1600)                                    ; + +        EXCP_BUG(1700)                                    ; + +        EXCP_BUG(1800)                                    ; + +        EXCP_BUG(1900)                                    ; + +        EXCP_BUG(1A00)                                    ; + +        EXCP_BUG(1B00)                                    ; + +        EXCP_BUG(1C00)                                    ; + +        EXCP_BUG(1D00)                                    ; + +        EXCP_BUG(1E00)                                    ; + +        EXCP_BUG(1F00)                                    ; +        /* End of exception vectors list */ + +.org 0x2000 +.section .text +.align 2 +helpers_start: + +outb: +        /* void outb (uint32_t port, uint32_t data); +         * Writes a single character on an IO port. +         * Used for serial console. +         */ +        stb     r4, 0(r3)                                 ; +        eieio                                             ; +        blr                                               ; + +outstr: +        /* void outstr (uint32_t port, const unsigned char *str); +         * Writes a string on an IO port. +         */ +        mflr    r20                                       ; +        subi    r11, r4, 1                                ; +         +_outstr_next: +        lbzu    r4, 1(r11)                                ; +        cmpi    0, r4, 0                                  ; +        beq     _outstr_done                              ; +        bl      outb                                      ; +        b       _outstr_next                              ; +_outstr_done: +        mtlr    r20                                       ; +        blr                                               ; + +outdigit: +        /* void outdigit (uint32_t port, uint32_t digit); +         * Dumps a single digit on serial port. +         */ +        mflr    r20                                       ; +        addi    r4, r4, '0'                               ; +        bl      outb                                      ; +        mtlr    r20                                       ; +        blr                                               ; + +outhex: +        /* void outhex (uint32_t port, uint32_t value); +         * Dumps a 32 bits hex number on serial port +         */ +        mflr    r21 +        li      r11, 8                                    ; +        mtctr   r11                                       ; +        mr      r11, r4                                   ; +_outhex_next: +        rlwinm  r11, r11, 4, 0, 31                        ; +        clrlwi  r4, r11, 28                               ; +        cmpi    0, r4, 9                                  ; +        bgt     _outhex_xdigit                            ; +        bl      outdigit                                  ; +        bdnz    _outhex_next                              ; +        b       _outhex_done                              ; +_outhex_xdigit: +        addi    r4, r4, 'a' - 10                          ; +        bl      outb                                      ; +        bdnz    _outhex_next                              ; +_outhex_done: +        mtlr    r21                                       ; +        blr                                               ; + +        /* void dump_exception (uint32_t lr, uint32_t srr0, uint32_t srr1, +         *                      uint32_t dar, uint32_t dsisr); +         * Dump a message when catching an exception +         */ +dump_exception: +        /* Save call parameters */ +        mflr    r19                                       ; +        mr      r22, r3                                   ; +        mr      r23, r4                                   ; +        mr      r24, r5                                   ; +        mr      r25, r6                                   ; +        mr      r26, r7                                   ; +        lis     r11, registers_area@h                     ; +        ori     r11, r11, registers_area@l                ; +        lmw     r27, 0(r11)                               ; +        /* Now, serial IO port is in r27, +         * message table start is in r28, +         * first exception message offset is in r29, +         * and last known exception number is in r30 +         */ +        /* Print error prompt message */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        /* Find message corresponding to the caught exception */ +        srwi    r12, r22, 8                               ; +        cmp     0, r12, r30                               ; +        ble     _dump_excp_msg                            ; +        subi    r12, r30, 1                               ; +_dump_excp_msg: +        rlwinm  r12, r12, 2, 0, 31                        ; +        /* Dump execption message */ +        mr      r3, r27                                   ; +        lwzx    r4, r12, r29                              ; +        bl      outstr                                    ; +        /* Complete exception message */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        /* Dump nip */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        mr      r3, r27                                   ; +        mr      r4, r23                                   ; +        bl      outhex                                    ; +        /* dump msr */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        mr      r3, r27                                   ; +        mr      r4, r24                                   ; +        bl      outhex                                    ; +        /* dump dar */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        mr      r3, r27                                   ; +        mr      r4, r25                                   ; +        bl      outhex                                    ; +        /* dump dsisr */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        mr      r3, r27                                   ; +        mr      r4, r26                                   ; +        bl      outhex                                    ; +        /* All done, dump last message and return */ +        mr      r3, r27                                   ; +        lwzu    r4, 4(r28)                                ; +        bl      outstr                                    ; +        mtlr    r19                                       ; +        blr                                               ; + +.section .rodata +.align 2 +_BUG_message_0: +        .string "ERROR: BUG caught...\n" +_BUG_message_1: +        .string " exception" +_BUG_message_2: +        .string "\nnip=0x" +_BUG_message_3: +        .string " msr=0x" +_BUG_message_4: +        .string " dar=0x" +_BUG_message_5: +        .string " dsisr=0x" +_BUG_message_6: +        .string "\nStopping execution\n" + +_excp_message_0x00: +        .string "BIOS execution" +_excp_message_0x01: +        .string "Reset" +_excp_message_0x02: +        .string "Machine check" +_excp_message_0x03: +        .string "Data memory access" +_excp_message_0x04: +        .string "Instruction fetch" +_excp_message_0x05: +        .string "External" +_excp_message_0x06: +        .string "Alignment" +_excp_message_0x07: +        .string "Program" +_excp_message_0x08: +        .string "No floating point" +_excp_message_0x09: +        .string "Decrementer" +_excp_message_0x0a: +        .string "Reserved A" +_excp_message_0x0b: +        .string "Reserved B" +_excp_message_0x0c: +        .string "System call" +_excp_message_0x0d: +        .string "Trace" +_excp_message_0x0e: +        .string "Floating point assist" +_excp_message_0x0f: +        .string "Performance monitor" +_excp_message_0x10: +        .string "Instruction TLB miss" +_excp_message_0x11: +        .string "Data TLB miss for store" +_excp_message_0x12: +        .string "Data TLB miss for load" +_excp_message_0x13: +        .string "Instruction address breakpoint" +_excp_message_0x14: +        .string "System management" +_excp_message_0x15: +        .string "Thermal management" +_excp_message_0x16: +        .string "Unknown" +_messages_table: +        .long _BUG_message_0 +        .long _BUG_message_1 +        .long _BUG_message_2 +        .long _BUG_message_3 +        .long _BUG_message_4 +        .long _BUG_message_5 +        .long _BUG_message_6 +_excp_messages_table: +        .long _excp_message_0x00 +        .long _excp_message_0x01 +        .long _excp_message_0x02 +        .long _excp_message_0x03 +        .long _excp_message_0x04 +        .long _excp_message_0x05 +        .long _excp_message_0x06 +        .long _excp_message_0x07 +        .long _excp_message_0x08 +        .long _excp_message_0x09 +        .long _excp_message_0x0a +        .long _excp_message_0x0b +        .long _excp_message_0x0c +        .long _excp_message_0x0d +        .long _excp_message_0x0e +        .long _excp_message_0x0f +        .long _excp_message_0x10 +        .long _excp_message_0x11 +        .long _excp_message_0x12 +        .long _excp_message_0x13 +        .long _excp_message_0x14 +        .long _excp_message_0x15 +        .long _excp_message_0x16 +_last_excp_message: + +bios_base: +        .long BIOS_BASE +bios_size: +        .long BIOS_SIZE / 4 +_dummy_0: +        .long 0x00000000 + +registers_area: /* To be loaded in register when an exception is caught */ +_serial_IO:      /* r27 */ +        .long 0x800003F8 +_messages_start: /* r28 */ +        .long _messages_table - 4 +_excp_messages:  /* r29 */ +        .long _excp_messages_table +_max_excp:       /* r30 */ +        .long (_last_excp_message - _excp_messages_table) / 4 +_dummy_1:        /* r31: dummy */ +        .long 0x00000000 +         +.section .data +.align 2 +save_area: /* Area for r11 save when an exception is skipped */ +        .long 0x00000000 diff --git a/roms/openhackware/src/vectors.ld b/roms/openhackware/src/vectors.ld new file mode 100644 index 00000000..cc83b6a9 --- /dev/null +++ b/roms/openhackware/src/vectors.ld @@ -0,0 +1,45 @@ +/*  + *   <vectors.ld> + *       + *   Second stage boot-loader and exception vectors for Open Hack'Ware + *   linker script + *    + *   Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) + *    + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +OUTPUT_ARCH(powerpc:common) + +MEMORY +{ +        text   (rx)   : ORIGIN = 0x00000000, LENGTH = 0x3000 +        rodata (r)    : ORIGIN = 0x00003000, LENGTH = 0x0C00 +        data   (rw)   : ORIGIN = 0x00003C00, LENGTH = 0x0200 +} + +SECTIONS +{ +        .text     : { *(.text)    } > text +        .rodata   : { *(.rodata)  } > rodata +        .data     : { *(.data)    } > data +        /DISCARD/ : { *(.bss)     } +        /DISCARD/ : { *(.sbss)    } +        /DISCARD/ : { *(.sdata)   } +        /DISCARD/ : { *(.sdata2)  } +        /DISCARD/ : { *(.stab)    } +        /DISCARD/ : { *(.stabstr) } +        /DISCARD/ : { *(.comment) } +        /DISCARD/ : { *(.note)    } +} diff --git a/roms/openhackware/src/vga.c b/roms/openhackware/src/vga.c new file mode 100644 index 00000000..d671bea5 --- /dev/null +++ b/roms/openhackware/src/vga.c @@ -0,0 +1,429 @@ +/* + *  Copyright (c) 2004-2005 Fabrice Bellard + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <stdlib.h> +#include "bios.h" + +/* VGA init. We use the Bochs VESA VBE extensions  */ +#define VBE_DISPI_INDEX_ID              0x0 +#define VBE_DISPI_INDEX_XRES            0x1 +#define VBE_DISPI_INDEX_YRES            0x2 +#define VBE_DISPI_INDEX_BPP             0x3 +#define VBE_DISPI_INDEX_ENABLE          0x4 +#define VBE_DISPI_INDEX_BANK            0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7 +#define VBE_DISPI_INDEX_X_OFFSET        0x8 +#define VBE_DISPI_INDEX_Y_OFFSET        0x9 +#define VBE_DISPI_INDEX_NB              0xa +       +#define VBE_DISPI_ID0                   0xB0C0 +#define VBE_DISPI_ID1                   0xB0C1 +#define VBE_DISPI_ID2                   0xB0C2 +   +#define VBE_DISPI_DISABLED              0x00 +#define VBE_DISPI_ENABLED               0x01 +#define VBE_DISPI_LFB_ENABLED           0x40 +#define VBE_DISPI_NOCLEARMEM            0x80 +   +#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000 + +static void vga_text_init(void); + +unsigned long vga_fb_phys_addr; +int vga_fb_width; +int vga_fb_height; +int vga_fb_linesize; +int vga_fb_bpp; +int vga_fb_depth; +uint8_t rgb_to_index[256]; + +static void vbe_outw(int index, int val) +{ +    outw(0x1ce, index); +    outw(0x1d0, val); +} + +/* init VGA in standard state for PREP boot */ +void vga_prep_init(void) +{ +    outb(0x3c0, 0x00); /* set blanking */ +    vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); +} + +/* build standard RGB palette */ +void vga_build_rgb_palette(void) +{ +    static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff }; +    int i, r, g, b; + +    i = 0; +    for(r = 0; r < 6; r++) { +        for(g = 0; g < 6; g++) { +            for(b = 0; b < 6; b++) { +                vga_set_palette(i, RGB(pal_value[r], pal_value[g],  +                                       pal_value[b])); +                i++; +            } +        } +    } +    for(i = 0; i < 256; i++) { +        rgb_to_index[i] = ((i * 5) + 128) / 255; +    } +} + +void vga_set_address (uint32_t address) +{ +    vga_fb_phys_addr = address; +} + +/* depth = 8, 15, 16 or 32 */ +void vga_set_mode(int width, int height, int depth) +{ +    vbe_outw(VBE_DISPI_INDEX_XRES, width); +    vbe_outw(VBE_DISPI_INDEX_YRES, height); +    vbe_outw(VBE_DISPI_INDEX_BPP, depth); +    vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED); +    outb(0x3c0, 0x20); /* disable blanking */ + +    if (vga_fb_phys_addr == 0x00000000) +        vga_fb_phys_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS; +    vga_fb_width = width; +    vga_fb_height = height; +    vga_fb_depth = depth; +    vga_fb_bpp = (depth + 7) >> 3; +    vga_fb_linesize = width * vga_fb_bpp; +     +    if (depth == 8) +        vga_build_rgb_palette(); +    vga_text_init(); +} + +/* for depth = 8 mode, set a hardware palette entry */ +void vga_set_palette(int i, unsigned int rgba) +{ +    unsigned int r, g, b; + +    r = (rgba >> 16) & 0xff; +    g = (rgba >> 8) & 0xff; +    b = (rgba) & 0xff; +    outb(0x3c8, i); +    outb(0x3c9, r >> 2); +    outb(0x3c9, g >> 2); +    outb(0x3c9, b >> 2); +} + +/* convert a RGBA color to a color index usable in graphic primitives */ +unsigned int vga_get_color(unsigned int rgba) +{ +    unsigned int r, g, b, color; + +    switch(vga_fb_depth) { +    case 8: +        r = (rgba >> 16) & 0xff; +        g = (rgba >> 8) & 0xff; +        b = (rgba) & 0xff; +        color = (rgb_to_index[r] * 6 * 6) +  +            (rgb_to_index[g] * 6) +  +            (rgb_to_index[b]); +        break; +    case 15: +        r = (rgba >> 16) & 0xff; +        g = (rgba >> 8) & 0xff; +        b = (rgba) & 0xff; +        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +        break; +    case 16: +        r = (rgba >> 16) & 0xff; +        g = (rgba >> 8) & 0xff; +        b = (rgba) & 0xff; +        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +        break; +    case 32: +    default: +        color = rgba; +        break; +    } +    return color; +} + +void vga_draw_buf (const void *buf, int buf_linesize, +                   int posx, int posy, int width, int height) +{ +    const uint8_t *s; +    uint8_t *d; +    int y, wb; +     +    s = buf; +    d = (uint8_t *)vga_fb_phys_addr +  +        vga_fb_linesize * posy + vga_fb_bpp * posx; +    wb = width * vga_fb_bpp; +    for (y = 0; y < height; y++) { +        memcpy(d, s, wb); +        s += buf_linesize; +        d += vga_fb_linesize; +    } +} + +void vga_fill_rect (int posx, int posy, int width, int height, uint32_t color) +{ +    uint8_t *d, *d1; +    int x, y; +     +    d1 = (uint8_t *)vga_fb_phys_addr +  +        vga_fb_linesize * posy + vga_fb_bpp * posx; +    for (y = 0; y < height; y++) { +        d = d1; +        switch(vga_fb_bpp) { +        case 1: +            for (x = 0; x < width; x++) { +                *((uint8_t *)d) = color; +                d++; +            } +            break; +        case 2: +            for (x = 0; x < width; x++) { +                *((uint16_t *)d) = color; +                d += 2; +            } +            break; +        case 4: +            for (x = 0; x < width; x++) { +                *((uint32_t *)d) = color; +                d += 4; +            } +            break; +        } +        d1 += vga_fb_linesize; +    } +} + +/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ +void vga_bitblt(int xs, int ys, int xd, int yd, int w, int h) +{ +    const uint8_t *s; +    uint8_t *d; +    int wb, y; + +    wb = w * vga_fb_bpp; +    if (yd <= ys) { +        s = (uint8_t *)vga_fb_phys_addr +  +            vga_fb_linesize * ys + vga_fb_bpp * xs; +        d = (uint8_t *)vga_fb_phys_addr +  +            vga_fb_linesize * yd + vga_fb_bpp * xd; +        for (y = 0; y < h; y++) { +            memmove(d, s, wb); +            d += vga_fb_linesize; +            s += vga_fb_linesize; +        } +    } else { +        s = (uint8_t *)vga_fb_phys_addr +  +            vga_fb_linesize * (ys + h - 1) + vga_fb_bpp * xs; +        d = (uint8_t *)vga_fb_phys_addr +  +            vga_fb_linesize * (yd + h - 1) + vga_fb_bpp * xd; +       for (y = 0; y < h; y++) { +            memmove(d, s, wb); +            d -= vga_fb_linesize; +            s -= vga_fb_linesize; +        } +    } +} + +/***********************************************************/ +/* basic char display */ + +#define FONT_HEIGHT 16 +#define FONT_WIDTH 8 + +#include "vgafont.h" + +#define cbswap_32(__x) \ +((uint32_t)( \ +		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ +		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \ +		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \ +		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) + +/* XXX: endianness */ +#if 0 +#define PAT(x) cbswap_32(x) +#else +#define PAT(x) x +#endif + +static const uint32_t dmask16[16] = { +    PAT(0x00000000), +    PAT(0x000000ff), +    PAT(0x0000ff00), +    PAT(0x0000ffff), +    PAT(0x00ff0000), +    PAT(0x00ff00ff), +    PAT(0x00ffff00), +    PAT(0x00ffffff), +    PAT(0xff000000), +    PAT(0xff0000ff), +    PAT(0xff00ff00), +    PAT(0xff00ffff), +    PAT(0xffff0000), +    PAT(0xffff00ff), +    PAT(0xffffff00), +    PAT(0xffffffff), +}; + +static const uint32_t dmask4[4] = { +    PAT(0x00000000), +    PAT(0x0000ffff), +    PAT(0xffff0000), +    PAT(0xffffffff), +}; + +int text_width, text_height, text_fgcol, text_bgcol, text_x, text_y; + +static void vga_text_init(void) +{ +    text_width = vga_fb_width / FONT_WIDTH; +    text_height = vga_fb_height / FONT_HEIGHT; +    text_x = 0; +    text_y = 0; +    vga_text_set_fgcol(RGB(0xff, 0xff, 0xff)); +    vga_text_set_bgcol(RGB(0x00, 0x00, 0x00)); +} + +static inline unsigned int col_expand(unsigned int col) +{ +    switch(vga_fb_bpp) { +    case 1: +        col |= col << 8; +        col |= col << 16; +        break; +    case 2: +        col |= col << 16; +        break; +    default: +        text_fgcol = 0xffffff; +        break; +    } + +    return col; +} + +void vga_text_set_fgcol(unsigned int rgba) +{ +    text_fgcol = col_expand(vga_get_color(rgba)); +} + +void vga_text_set_bgcol(unsigned int rgba) +{ +    text_bgcol = col_expand(vga_get_color(rgba)); +} + +void vga_putcharxy(int x, int y, int ch,  +                   unsigned int fgcol, unsigned int bgcol) +{ +    uint8_t *d; +    const uint8_t *font_ptr; +    unsigned int font_data, linesize, xorcol; +    int i; + +    d = (uint8_t *)vga_fb_phys_addr +  +        vga_fb_linesize * y * FONT_HEIGHT + vga_fb_bpp * x * FONT_WIDTH; +    linesize = vga_fb_linesize; +    font_ptr = vgafont16 + FONT_HEIGHT * ch; +    xorcol = bgcol ^ fgcol; +    switch(vga_fb_depth) { +    case 8: +        for(i = 0; i < FONT_HEIGHT; i++) { +            font_data = *font_ptr++; +            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; +            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; +            d += linesize; +        } +        break; +    case 16: +    case 15: +        for(i = 0; i < FONT_HEIGHT; i++) { +            font_data = *font_ptr++; +            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; +            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; +            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; +            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; +            d += linesize; +        } +        break; +    case 32: +        for(i = 0; i < FONT_HEIGHT; i++) { +            font_data = *font_ptr++; +            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; +            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; +            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; +            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; +            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; +            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; +            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; +            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; +            d += linesize; +        } +        break; +    } +} + +static void vga_put_lf(void) +{ +    text_x = 0; +    text_y++; +    if (text_y >= text_height) { +        text_y = text_height - 1; +        vga_bitblt(0, FONT_HEIGHT, 0, 0,  +                   text_width * FONT_WIDTH,  +                   (text_height - 1) * FONT_HEIGHT); +        vga_fill_rect(0, (text_height - 1) * FONT_HEIGHT, +                      text_width * FONT_WIDTH, FONT_HEIGHT, text_bgcol); +    } +} + +void vga_putchar(int ch) +{ +    if (ch == '\r') { +        text_x = 0; +    } else if (ch == '\n') { +        vga_put_lf(); +    } else if (ch == '\b') { +        if (text_x == 0) { +            if (text_y != 0) { +                text_x = text_width; +                text_y--; +                goto eat_char; +            } +        } else { +        eat_char: +            vga_putcharxy(--text_x, text_y, ' ', text_fgcol, text_bgcol); +        } +    } else { +        vga_putcharxy(text_x, text_y, ch, text_fgcol, text_bgcol); +        text_x++; +        if (text_x >= text_width) +            vga_put_lf(); +    } +} + +void vga_puts(const char *s) +{ +    while (*s) { +        vga_putchar(*(uint8_t *)s); +        s++; +    } +} diff --git a/roms/openhackware/src/vgafont.h b/roms/openhackware/src/vgafont.h new file mode 100644 index 00000000..b571e651 --- /dev/null +++ b/roms/openhackware/src/vgafont.h @@ -0,0 +1,4627 @@ +/* + *  Copyright (c) 2004-2005 Fabrice Bellard + * + *   This program is free software; you can redistribute it and/or + *   modify it under the terms of the GNU General Public License V2 + *   as published by the Free Software Foundation + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ +static uint8_t vgafont16[256 * 16] = { + +	/* 0 0x00 '^@' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 1 0x01 '^A' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x81, /* 10000001 */ +	0xa5, /* 10100101 */ +	0x81, /* 10000001 */ +	0x81, /* 10000001 */ +	0xbd, /* 10111101 */ +	0x99, /* 10011001 */ +	0x81, /* 10000001 */ +	0x81, /* 10000001 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 2 0x02 '^B' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0xff, /* 11111111 */ +	0xdb, /* 11011011 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xc3, /* 11000011 */ +	0xe7, /* 11100111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 3 0x03 '^C' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x6c, /* 01101100 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0x7c, /* 01111100 */ +	0x38, /* 00111000 */ +	0x10, /* 00010000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 4 0x04 '^D' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x7c, /* 01111100 */ +	0xfe, /* 11111110 */ +	0x7c, /* 01111100 */ +	0x38, /* 00111000 */ +	0x10, /* 00010000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 5 0x05 '^E' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x3c, /* 00111100 */ +	0xe7, /* 11100111 */ +	0xe7, /* 11100111 */ +	0xe7, /* 11100111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 6 0x06 '^F' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x7e, /* 01111110 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 7 0x07 '^G' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 8 0x08 '^H' */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xe7, /* 11100111 */ +	0xc3, /* 11000011 */ +	0xc3, /* 11000011 */ +	0xe7, /* 11100111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ + +	/* 9 0x09 '^I' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0x42, /* 01000010 */ +	0x42, /* 01000010 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 10 0x0a '^J' */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xc3, /* 11000011 */ +	0x99, /* 10011001 */ +	0xbd, /* 10111101 */ +	0xbd, /* 10111101 */ +	0x99, /* 10011001 */ +	0xc3, /* 11000011 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ + +	/* 11 0x0b '^K' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1e, /* 00011110 */ +	0x0e, /* 00001110 */ +	0x1a, /* 00011010 */ +	0x32, /* 00110010 */ +	0x78, /* 01111000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x78, /* 01111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 12 0x0c '^L' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 13 0x0d '^M' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3f, /* 00111111 */ +	0x33, /* 00110011 */ +	0x3f, /* 00111111 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x70, /* 01110000 */ +	0xf0, /* 11110000 */ +	0xe0, /* 11100000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 14 0x0e '^N' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7f, /* 01111111 */ +	0x63, /* 01100011 */ +	0x7f, /* 01111111 */ +	0x63, /* 01100011 */ +	0x63, /* 01100011 */ +	0x63, /* 01100011 */ +	0x63, /* 01100011 */ +	0x67, /* 01100111 */ +	0xe7, /* 11100111 */ +	0xe6, /* 11100110 */ +	0xc0, /* 11000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 15 0x0f '^O' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xdb, /* 11011011 */ +	0x3c, /* 00111100 */ +	0xe7, /* 11100111 */ +	0x3c, /* 00111100 */ +	0xdb, /* 11011011 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 16 0x10 '^P' */ +	0x00, /* 00000000 */ +	0x80, /* 10000000 */ +	0xc0, /* 11000000 */ +	0xe0, /* 11100000 */ +	0xf0, /* 11110000 */ +	0xf8, /* 11111000 */ +	0xfe, /* 11111110 */ +	0xf8, /* 11111000 */ +	0xf0, /* 11110000 */ +	0xe0, /* 11100000 */ +	0xc0, /* 11000000 */ +	0x80, /* 10000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 17 0x11 '^Q' */ +	0x00, /* 00000000 */ +	0x02, /* 00000010 */ +	0x06, /* 00000110 */ +	0x0e, /* 00001110 */ +	0x1e, /* 00011110 */ +	0x3e, /* 00111110 */ +	0xfe, /* 11111110 */ +	0x3e, /* 00111110 */ +	0x1e, /* 00011110 */ +	0x0e, /* 00001110 */ +	0x06, /* 00000110 */ +	0x02, /* 00000010 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 18 0x12 '^R' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 19 0x13 '^S' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 20 0x14 '^T' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7f, /* 01111111 */ +	0xdb, /* 11011011 */ +	0xdb, /* 11011011 */ +	0xdb, /* 11011011 */ +	0x7b, /* 01111011 */ +	0x1b, /* 00011011 */ +	0x1b, /* 00011011 */ +	0x1b, /* 00011011 */ +	0x1b, /* 00011011 */ +	0x1b, /* 00011011 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 21 0x15 '^U' */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0x60, /* 01100000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x0c, /* 00001100 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 22 0x16 '^V' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 23 0x17 '^W' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 24 0x18 '^X' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 25 0x19 '^Y' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 26 0x1a '^Z' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0xfe, /* 11111110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 27 0x1b '^[' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xfe, /* 11111110 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 28 0x1c '^\' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 29 0x1d '^]' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x28, /* 00101000 */ +	0x6c, /* 01101100 */ +	0xfe, /* 11111110 */ +	0x6c, /* 01101100 */ +	0x28, /* 00101000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 30 0x1e '^^' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x38, /* 00111000 */ +	0x7c, /* 01111100 */ +	0x7c, /* 01111100 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 31 0x1f '^_' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0x7c, /* 01111100 */ +	0x7c, /* 01111100 */ +	0x38, /* 00111000 */ +	0x38, /* 00111000 */ +	0x10, /* 00010000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 32 0x20 ' ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 33 0x21 '!' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x3c, /* 00111100 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 34 0x22 '"' */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x24, /* 00100100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 35 0x23 '#' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0xfe, /* 11111110 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0xfe, /* 11111110 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 36 0x24 '$' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc2, /* 11000010 */ +	0xc0, /* 11000000 */ +	0x7c, /* 01111100 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x86, /* 10000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 37 0x25 '%' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc2, /* 11000010 */ +	0xc6, /* 11000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc6, /* 11000110 */ +	0x86, /* 10000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 38 0x26 '&' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 39 0x27 ''' */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 40 0x28 '(' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 41 0x29 ')' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 42 0x2a '*' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0xff, /* 11111111 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 43 0x2b '+' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 44 0x2c ',' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 45 0x2d '-' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 46 0x2e '.' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 47 0x2f '/' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x02, /* 00000010 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc0, /* 11000000 */ +	0x80, /* 10000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 48 0x30 '0' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 49 0x31 '1' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x38, /* 00111000 */ +	0x78, /* 01111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 50 0x32 '2' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 51 0x33 '3' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x3c, /* 00111100 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 52 0x34 '4' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x0c, /* 00001100 */ +	0x1c, /* 00011100 */ +	0x3c, /* 00111100 */ +	0x6c, /* 01101100 */ +	0xcc, /* 11001100 */ +	0xfe, /* 11111110 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x1e, /* 00011110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 53 0x35 '5' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xfc, /* 11111100 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 54 0x36 '6' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x60, /* 01100000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xfc, /* 11111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 55 0x37 '7' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 56 0x38 '8' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 57 0x39 '9' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7e, /* 01111110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x78, /* 01111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 58 0x3a ':' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 59 0x3b ';' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 60 0x3c '<' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x06, /* 00000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 61 0x3d '=' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 62 0x3e '>' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 63 0x3f '?' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 64 0x40 '@' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xde, /* 11011110 */ +	0xde, /* 11011110 */ +	0xde, /* 11011110 */ +	0xdc, /* 11011100 */ +	0xc0, /* 11000000 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 65 0x41 'A' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 66 0x42 'B' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfc, /* 11111100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x7c, /* 01111100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0xfc, /* 11111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 67 0x43 'C' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0xc2, /* 11000010 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc2, /* 11000010 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 68 0x44 'D' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xf8, /* 11111000 */ +	0x6c, /* 01101100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x6c, /* 01101100 */ +	0xf8, /* 11111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 69 0x45 'E' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x66, /* 01100110 */ +	0x62, /* 01100010 */ +	0x68, /* 01101000 */ +	0x78, /* 01111000 */ +	0x68, /* 01101000 */ +	0x60, /* 01100000 */ +	0x62, /* 01100010 */ +	0x66, /* 01100110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 70 0x46 'F' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x66, /* 01100110 */ +	0x62, /* 01100010 */ +	0x68, /* 01101000 */ +	0x78, /* 01111000 */ +	0x68, /* 01101000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0xf0, /* 11110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 71 0x47 'G' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0xc2, /* 11000010 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xde, /* 11011110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x66, /* 01100110 */ +	0x3a, /* 00111010 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 72 0x48 'H' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 73 0x49 'I' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 74 0x4a 'J' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1e, /* 00011110 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x78, /* 01111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 75 0x4b 'K' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xe6, /* 11100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x6c, /* 01101100 */ +	0x78, /* 01111000 */ +	0x78, /* 01111000 */ +	0x6c, /* 01101100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0xe6, /* 11100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 76 0x4c 'L' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xf0, /* 11110000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x62, /* 01100010 */ +	0x66, /* 01100110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 77 0x4d 'M' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xee, /* 11101110 */ +	0xfe, /* 11111110 */ +	0xfe, /* 11111110 */ +	0xd6, /* 11010110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 78 0x4e 'N' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xe6, /* 11100110 */ +	0xf6, /* 11110110 */ +	0xfe, /* 11111110 */ +	0xde, /* 11011110 */ +	0xce, /* 11001110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 79 0x4f 'O' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 80 0x50 'P' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfc, /* 11111100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x7c, /* 01111100 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0xf0, /* 11110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 81 0x51 'Q' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xd6, /* 11010110 */ +	0xde, /* 11011110 */ +	0x7c, /* 01111100 */ +	0x0c, /* 00001100 */ +	0x0e, /* 00001110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 82 0x52 'R' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfc, /* 11111100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x7c, /* 01111100 */ +	0x6c, /* 01101100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0xe6, /* 11100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 83 0x53 'S' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x60, /* 01100000 */ +	0x38, /* 00111000 */ +	0x0c, /* 00001100 */ +	0x06, /* 00000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 84 0x54 'T' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x5a, /* 01011010 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 85 0x55 'U' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 86 0x56 'V' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x10, /* 00010000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 87 0x57 'W' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xfe, /* 11111110 */ +	0xee, /* 11101110 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 88 0x58 'X' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x7c, /* 01111100 */ +	0x38, /* 00111000 */ +	0x38, /* 00111000 */ +	0x7c, /* 01111100 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 89 0x59 'Y' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 90 0x5a 'Z' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0x86, /* 10000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc2, /* 11000010 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 91 0x5b '[' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 92 0x5c '\' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x80, /* 10000000 */ +	0xc0, /* 11000000 */ +	0xe0, /* 11100000 */ +	0x70, /* 01110000 */ +	0x38, /* 00111000 */ +	0x1c, /* 00011100 */ +	0x0e, /* 00001110 */ +	0x06, /* 00000110 */ +	0x02, /* 00000010 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 93 0x5d ']' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 94 0x5e '^' */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 95 0x5f '_' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 96 0x60 '`' */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 97 0x61 'a' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0x0c, /* 00001100 */ +	0x7c, /* 01111100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 98 0x62 'b' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xe0, /* 11100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x78, /* 01111000 */ +	0x6c, /* 01101100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 99 0x63 'c' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 100 0x64 'd' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1c, /* 00011100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x3c, /* 00111100 */ +	0x6c, /* 01101100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 101 0x65 'e' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 102 0x66 'f' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1c, /* 00011100 */ +	0x36, /* 00110110 */ +	0x32, /* 00110010 */ +	0x30, /* 00110000 */ +	0x78, /* 01111000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x78, /* 01111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 103 0x67 'g' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x7c, /* 01111100 */ +	0x0c, /* 00001100 */ +	0xcc, /* 11001100 */ +	0x78, /* 01111000 */ +	0x00, /* 00000000 */ + +	/* 104 0x68 'h' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xe0, /* 11100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x6c, /* 01101100 */ +	0x76, /* 01110110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0xe6, /* 11100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 105 0x69 'i' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 106 0x6a 'j' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x00, /* 00000000 */ +	0x0e, /* 00001110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ + +	/* 107 0x6b 'k' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xe0, /* 11100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x66, /* 01100110 */ +	0x6c, /* 01101100 */ +	0x78, /* 01111000 */ +	0x78, /* 01111000 */ +	0x6c, /* 01101100 */ +	0x66, /* 01100110 */ +	0xe6, /* 11100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 108 0x6c 'l' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 109 0x6d 'm' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xec, /* 11101100 */ +	0xfe, /* 11111110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 110 0x6e 'n' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xdc, /* 11011100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 111 0x6f 'o' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 112 0x70 'p' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xdc, /* 11011100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x7c, /* 01111100 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0xf0, /* 11110000 */ +	0x00, /* 00000000 */ + +	/* 113 0x71 'q' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x7c, /* 01111100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x1e, /* 00011110 */ +	0x00, /* 00000000 */ + +	/* 114 0x72 'r' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xdc, /* 11011100 */ +	0x76, /* 01110110 */ +	0x66, /* 01100110 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0xf0, /* 11110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 115 0x73 's' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0x60, /* 01100000 */ +	0x38, /* 00111000 */ +	0x0c, /* 00001100 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 116 0x74 't' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0xfc, /* 11111100 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x36, /* 00110110 */ +	0x1c, /* 00011100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 117 0x75 'u' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 118 0x76 'v' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 119 0x77 'w' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xd6, /* 11010110 */ +	0xfe, /* 11111110 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 120 0x78 'x' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x38, /* 00111000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 121 0x79 'y' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7e, /* 01111110 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0xf8, /* 11111000 */ +	0x00, /* 00000000 */ + +	/* 122 0x7a 'z' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xcc, /* 11001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 123 0x7b '{' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x0e, /* 00001110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x70, /* 01110000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x0e, /* 00001110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 124 0x7c '|' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 125 0x7d '}' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x70, /* 01110000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x0e, /* 00001110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x70, /* 01110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 126 0x7e '~' */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 127 0x7f '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 128 0x80 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0xc2, /* 11000010 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc2, /* 11000010 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x70, /* 01110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 129 0x81 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 130 0x82 '' */ +	0x00, /* 00000000 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 131 0x83 '' */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0x0c, /* 00001100 */ +	0x7c, /* 01111100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 132 0x84 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0x0c, /* 00001100 */ +	0x7c, /* 01111100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 133 0x85 '
' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0x0c, /* 00001100 */ +	0x7c, /* 01111100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 134 0x86 '' */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0x0c, /* 00001100 */ +	0x7c, /* 01111100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 135 0x87 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x18, /* 00011000 */ +	0x70, /* 01110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 136 0x88 '' */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 137 0x89 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 138 0x8a '' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 139 0x8b '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 140 0x8c '' */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 141 0x8d '' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 142 0x8e '' */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 143 0x8f '' */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 144 0x90 '' */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x66, /* 01100110 */ +	0x62, /* 01100010 */ +	0x68, /* 01101000 */ +	0x78, /* 01111000 */ +	0x68, /* 01101000 */ +	0x62, /* 01100010 */ +	0x66, /* 01100110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 145 0x91 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xec, /* 11101100 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x7e, /* 01111110 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0x6e, /* 01101110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 146 0x92 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3e, /* 00111110 */ +	0x6c, /* 01101100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xfe, /* 11111110 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xce, /* 11001110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 147 0x93 '' */ +	0x00, /* 00000000 */ +	0x10, /* 00010000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 148 0x94 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 149 0x95 '' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 150 0x96 '' */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x78, /* 01111000 */ +	0xcc, /* 11001100 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 151 0x97 '' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 152 0x98 '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7e, /* 01111110 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x78, /* 01111000 */ +	0x00, /* 00000000 */ + +	/* 153 0x99 '' */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 154 0x9a '' */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 155 0x9b '' */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 156 0x9c '' */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x64, /* 01100100 */ +	0x60, /* 01100000 */ +	0xf0, /* 11110000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0xe6, /* 11100110 */ +	0xfc, /* 11111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 157 0x9d '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 158 0x9e '' */ +	0x00, /* 00000000 */ +	0xf8, /* 11111000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xf8, /* 11111000 */ +	0xc4, /* 11000100 */ +	0xcc, /* 11001100 */ +	0xde, /* 11011110 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 159 0x9f '' */ +	0x00, /* 00000000 */ +	0x0e, /* 00001110 */ +	0x1b, /* 00011011 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xd8, /* 11011000 */ +	0x70, /* 01110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 160 0xa0 ' ' */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0x0c, /* 00001100 */ +	0x7c, /* 01111100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 161 0xa1 '¡' */ +	0x00, /* 00000000 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 162 0xa2 '¢' */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 163 0xa3 '£' */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x00, /* 00000000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 164 0xa4 '¤' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0x00, /* 00000000 */ +	0xdc, /* 11011100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 165 0xa5 '¥' */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0x00, /* 00000000 */ +	0xc6, /* 11000110 */ +	0xe6, /* 11100110 */ +	0xf6, /* 11110110 */ +	0xfe, /* 11111110 */ +	0xde, /* 11011110 */ +	0xce, /* 11001110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 166 0xa6 '¦' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x3e, /* 00111110 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 167 0xa7 '§' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 168 0xa8 '¨' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc0, /* 11000000 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x7c, /* 01111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 169 0xa9 '©' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 170 0xaa 'ª' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 171 0xab '«' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0xe0, /* 11100000 */ +	0x62, /* 01100010 */ +	0x66, /* 01100110 */ +	0x6c, /* 01101100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xdc, /* 11011100 */ +	0x86, /* 10000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x3e, /* 00111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 172 0xac '¬' */ +	0x00, /* 00000000 */ +	0x60, /* 01100000 */ +	0xe0, /* 11100000 */ +	0x62, /* 01100010 */ +	0x66, /* 01100110 */ +	0x6c, /* 01101100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x66, /* 01100110 */ +	0xce, /* 11001110 */ +	0x9a, /* 10011010 */ +	0x3f, /* 00111111 */ +	0x06, /* 00000110 */ +	0x06, /* 00000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 173 0xad '' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x3c, /* 00111100 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 174 0xae '®' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x36, /* 00110110 */ +	0x6c, /* 01101100 */ +	0xd8, /* 11011000 */ +	0x6c, /* 01101100 */ +	0x36, /* 00110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 175 0xaf '¯' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xd8, /* 11011000 */ +	0x6c, /* 01101100 */ +	0x36, /* 00110110 */ +	0x6c, /* 01101100 */ +	0xd8, /* 11011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 176 0xb0 '°' */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ +	0x11, /* 00010001 */ +	0x44, /* 01000100 */ + +	/* 177 0xb1 '±' */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ +	0x55, /* 01010101 */ +	0xaa, /* 10101010 */ + +	/* 178 0xb2 '²' */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ +	0xdd, /* 11011101 */ +	0x77, /* 01110111 */ + +	/* 179 0xb3 '³' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 180 0xb4 '´' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 181 0xb5 'µ' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 182 0xb6 '¶' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xf6, /* 11110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 183 0xb7 '·' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 184 0xb8 '¸' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 185 0xb9 '¹' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xf6, /* 11110110 */ +	0x06, /* 00000110 */ +	0xf6, /* 11110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 186 0xba 'º' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 187 0xbb '»' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x06, /* 00000110 */ +	0xf6, /* 11110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 188 0xbc '¼' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xf6, /* 11110110 */ +	0x06, /* 00000110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 189 0xbd '½' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 190 0xbe '¾' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 191 0xbf '¿' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xf8, /* 11111000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 192 0xc0 'À' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 193 0xc1 'Á' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 194 0xc2 'Â' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 195 0xc3 'Ã' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 196 0xc4 'Ä' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 197 0xc5 'Å' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xff, /* 11111111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 198 0xc6 'Æ' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 199 0xc7 'Ç' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x37, /* 00110111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 200 0xc8 'È' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x37, /* 00110111 */ +	0x30, /* 00110000 */ +	0x3f, /* 00111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 201 0xc9 'É' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3f, /* 00111111 */ +	0x30, /* 00110000 */ +	0x37, /* 00110111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 202 0xca 'Ê' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xf7, /* 11110111 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 203 0xcb 'Ë' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0xf7, /* 11110111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 204 0xcc 'Ì' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x37, /* 00110111 */ +	0x30, /* 00110000 */ +	0x37, /* 00110111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 205 0xcd 'Í' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 206 0xce 'Î' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xf7, /* 11110111 */ +	0x00, /* 00000000 */ +	0xf7, /* 11110111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 207 0xcf 'Ï' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 208 0xd0 'Ð' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 209 0xd1 'Ñ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 210 0xd2 'Ò' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 211 0xd3 'Ó' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x3f, /* 00111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 212 0xd4 'Ô' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 213 0xd5 'Õ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 214 0xd6 'Ö' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x3f, /* 00111111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 215 0xd7 '×' */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0xff, /* 11111111 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ + +	/* 216 0xd8 'Ø' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xff, /* 11111111 */ +	0x18, /* 00011000 */ +	0xff, /* 11111111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 217 0xd9 'Ù' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xf8, /* 11111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 218 0xda 'Ú' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1f, /* 00011111 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 219 0xdb 'Û' */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ + +	/* 220 0xdc 'Ü' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ + +	/* 221 0xdd 'Ý' */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ +	0xf0, /* 11110000 */ + +	/* 222 0xde 'Þ' */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ +	0x0f, /* 00001111 */ + +	/* 223 0xdf 'ß' */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0xff, /* 11111111 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 224 0xe0 'à' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0xdc, /* 11011100 */ +	0x76, /* 01110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 225 0xe1 'á' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x78, /* 01111000 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xcc, /* 11001100 */ +	0xd8, /* 11011000 */ +	0xcc, /* 11001100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xcc, /* 11001100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 226 0xe2 'â' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0xc0, /* 11000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 227 0xe3 'ã' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 228 0xe4 'ä' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 229 0xe5 'å' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0x70, /* 01110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 230 0xe6 'æ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x7c, /* 01111100 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0xc0, /* 11000000 */ +	0x00, /* 00000000 */ + +	/* 231 0xe7 'ç' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 232 0xe8 'è' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 233 0xe9 'é' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xfe, /* 11111110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 234 0xea 'ê' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0xee, /* 11101110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 235 0xeb 'ë' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1e, /* 00011110 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x3e, /* 00111110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x66, /* 01100110 */ +	0x3c, /* 00111100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 236 0xec 'ì' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0xdb, /* 11011011 */ +	0xdb, /* 11011011 */ +	0xdb, /* 11011011 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 237 0xed 'í' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x03, /* 00000011 */ +	0x06, /* 00000110 */ +	0x7e, /* 01111110 */ +	0xdb, /* 11011011 */ +	0xdb, /* 11011011 */ +	0xf3, /* 11110011 */ +	0x7e, /* 01111110 */ +	0x60, /* 01100000 */ +	0xc0, /* 11000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 238 0xee 'î' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x1c, /* 00011100 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x7c, /* 01111100 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x1c, /* 00011100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 239 0xef 'ï' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7c, /* 01111100 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0xc6, /* 11000110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 240 0xf0 'ð' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0xfe, /* 11111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 241 0xf1 'ñ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x7e, /* 01111110 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 242 0xf2 'ò' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x06, /* 00000110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 243 0xf3 'ó' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x30, /* 00110000 */ +	0x60, /* 01100000 */ +	0x30, /* 00110000 */ +	0x18, /* 00011000 */ +	0x0c, /* 00001100 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 244 0xf4 'ô' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x0e, /* 00001110 */ +	0x1b, /* 00011011 */ +	0x1b, /* 00011011 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ + +	/* 245 0xf5 'õ' */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0xd8, /* 11011000 */ +	0x70, /* 01110000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 246 0xf6 'ö' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 247 0xf7 '÷' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0x00, /* 00000000 */ +	0x76, /* 01110110 */ +	0xdc, /* 11011100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 248 0xf8 'ø' */ +	0x00, /* 00000000 */ +	0x38, /* 00111000 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x38, /* 00111000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 249 0xf9 'ù' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 250 0xfa 'ú' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x18, /* 00011000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 251 0xfb 'û' */ +	0x00, /* 00000000 */ +	0x0f, /* 00001111 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0x0c, /* 00001100 */ +	0xec, /* 11101100 */ +	0x6c, /* 01101100 */ +	0x6c, /* 01101100 */ +	0x3c, /* 00111100 */ +	0x1c, /* 00011100 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 252 0xfc 'ü' */ +	0x00, /* 00000000 */ +	0x6c, /* 01101100 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x36, /* 00110110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 253 0xfd 'ý' */ +	0x00, /* 00000000 */ +	0x3c, /* 00111100 */ +	0x66, /* 01100110 */ +	0x0c, /* 00001100 */ +	0x18, /* 00011000 */ +	0x32, /* 00110010 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 254 0xfe 'þ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x7e, /* 01111110 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +	/* 255 0xff 'ÿ' */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ +	0x00, /* 00000000 */ + +};  | 
