├── .gitignore ├── README.md └── src ├── Makefile.in ├── autogen.sh ├── configure.ac ├── host ├── Makefile.in ├── cmdline │ ├── Makefile.in │ └── main.c ├── common │ ├── Makefile.in │ ├── bswap.h │ ├── msglog.c │ ├── msglog.h │ └── toc.h ├── configure.ac ├── datasource │ ├── Makefile.in │ ├── datafile.c │ ├── datafile.h │ ├── datasource.c │ ├── datasource.h │ ├── directory.c │ ├── directory.h │ ├── isofile.c │ ├── isofile.h │ ├── isofsparser.c │ ├── isofsparser.h │ ├── jukebox.c │ ├── jukebox.h │ ├── nrgfile.c │ └── nrgfile.h ├── network │ ├── Makefile.in │ ├── serverport.c │ └── serverport.h └── server │ ├── Makefile.in │ ├── server.c │ └── server.h ├── install-sh └── target ├── Makefile.in ├── common ├── Makefile.in ├── proto.c ├── proto.h ├── util.h └── util1.c ├── configure.ac ├── launcher ├── Makefile.in ├── bin2obj.pike ├── launch.s ├── main.c ├── startup.s ├── util2.c ├── video.c └── video.h ├── network ├── Makefile.in ├── arp.c ├── arp.h ├── ether.c ├── ether.h ├── icmp.c ├── icmp.h ├── ip.c ├── ip.h ├── pci.c ├── pci.h ├── udp.c └── udp.h └── skel ├── Makefile.in ├── schandler.c └── sub.s /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | autom4te.cache/ 3 | configure 4 | config.h.in 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DC-VIRTCD 2 | ========= 3 | 4 | DC-VIRTCD is a CD virtualization system for the Dreamcast. It allows you 5 | to run software which accesses files on CD-ROM, without actually burning 6 | those files on a CD-ROM. Instead, the files are accessed over the network. 7 | This happens transparantly, without any modifications having to be made 8 | to the software itself. 9 | 10 | Requirements 11 | ------------ 12 | 13 | * Broadband adapter 14 | * A computer to run the host side of the application on 15 | * A network cable 16 | 17 | Features 18 | -------- 19 | 20 | * Works with any software using Gdc system calls to read the disc 21 | * Supports ISO and NRG images 22 | 23 | Misfeatures 24 | ----------- 25 | 26 | * No support for CD-DA 27 | * Does not work with e.g. NetBSD, which accesses the GD-ROM drive directly 28 | 29 | -------------------------------------------------------------------------------- /src/Makefile.in: -------------------------------------------------------------------------------- 1 | top_srcdir=@top_srcdir@ 2 | srcdir=@srcdir@ 3 | VPATH=@srcdir@ 4 | 5 | all clean install : 6 | cd target && make $@ 7 | cd host && make $@ 8 | 9 | Makefile: Makefile.in config.status 10 | ./config.status 11 | 12 | config.status : configure 13 | ./config.status --recheck 14 | 15 | configure : configure.ac 16 | cd $(srcdir) && autoconf 17 | 18 | -------------------------------------------------------------------------------- /src/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | autoconf 4 | ( cd target && autoconf ) 5 | ( cd host && autoheader && autoconf ) 6 | 7 | -------------------------------------------------------------------------------- /src/configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(target/launcher/main.c) 2 | AC_CONFIG_SUBDIRS(target host) 3 | AC_OUTPUT(Makefile) 4 | -------------------------------------------------------------------------------- /src/host/Makefile.in: -------------------------------------------------------------------------------- 1 | CC = @CC@ 2 | AR = @AR@ 3 | CFLAGS = @CFLAGS@ 4 | 5 | top_srcdir=@top_srcdir@ 6 | srcdir=@srcdir@ 7 | VPATH=@srcdir@ 8 | 9 | all clean : 10 | cd common && make $@ 11 | cd network && make $@ 12 | cd server && make $@ 13 | cd datasource && make $@ 14 | cd cmdline && make $@ 15 | make local-$@ 16 | 17 | local-all : 18 | 19 | local-clean : 20 | 21 | install : 22 | 23 | MAKEFILES_OUT = Makefile common/Makefile network/Makefile \ 24 | server/Makefile datasource/Makefile cmdline/Makefile 25 | 26 | MAKEFILES_IN = Makefile.in common/Makefile.in network/Makefile.in \ 27 | server/Makefile.in datasource/Makefile.in cmdline/Makefile.in 28 | 29 | $(MAKEFILES_OUT): $(MAKEFILES_IN) config.status 30 | ./config.status 31 | 32 | config.status : configure 33 | ./config.status --recheck 34 | 35 | configure config.h.in : configure.ac 36 | cd $(srcdir) && autoheader && autoconf 37 | -------------------------------------------------------------------------------- /src/host/cmdline/Makefile.in: -------------------------------------------------------------------------------- 1 | CC = @CC@ 2 | AR = @AR@ 3 | CFLAGS = @CFLAGS@ -I$(top_srcdir)/common -I$(top_srcdir)/server -I$(top_srcdir)/datasource 4 | 5 | top_srcdir=@top_srcdir@ 6 | top_builddir=@top_builddir@ 7 | srcdir=@srcdir@ 8 | VPATH=@srcdir@ 9 | 10 | OBJS = main.o 11 | LIBS = $(top_builddir)/server/libserver.a $(top_builddir)/network/libnetwork.a $(top_builddir)/datasource/libdatasource.a $(top_builddir)/common/libcommon.a 12 | 13 | PROGTARGET = dc-virtcd-cmdline 14 | 15 | all : $(PROGTARGET) 16 | 17 | clean : 18 | -rm -f $(PROGTARGET) $(OBJS) 19 | 20 | $(PROGTARGET) : $(OBJS) $(LIBS) 21 | $(CC) -o $@ $(OBJS) $(LIBS) 22 | 23 | main.o : main.c $(top_srcdir)/common/msglog.h $(top_srcdir)/server/server.h 24 | 25 | -------------------------------------------------------------------------------- /src/host/cmdline/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "msglog.h" 6 | #include "toc.h" 7 | #include "datasource.h" 8 | #include "jukebox.h" 9 | #include "server.h" 10 | 11 | static void print_log(msglogger l, msglevel level, const char *msg) 12 | { 13 | fprintf(stderr, "%s\n", msg); 14 | } 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | struct msglogger_s logger = { 19 | print_log 20 | }; 21 | int i; 22 | server s; 23 | jukebox j = jukebox_new(&logger); 24 | if (!j) 25 | return 1; 26 | s = server_new(&logger, j); 27 | if (!s) { 28 | jukebox_delete(j); 29 | return 1; 30 | } 31 | 32 | for (i=1; i 3 | #endif 4 | 5 | #ifdef HAVE_DECL___BUILTIN_BSWAP32 6 | #define SWAP32 __builtin_bswap32 7 | #else 8 | #ifdef HAVE_DECL_BSWAP_32 9 | #define SWAP32 bswap_32 10 | #else 11 | #define SWAP16(n) (((uint16_t)((n)<<8))|(((uint16_t)(n))>>8)) 12 | #define SWAP32(n) ((SWAP16((uint32_t)(n))<<16)|SWAP16(((uint32_t)(n))>>16)) 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /src/host/common/msglog.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "msglog.h" 10 | 11 | void msglog_logv(msglogger l, msglevel level, const char *msg, va_list va) 12 | { 13 | char buf[512]; 14 | vsnprintf(buf, sizeof(buf), msg, va); 15 | (*l->log)(l, level, buf); 16 | } 17 | 18 | void msglog_log(msglogger l, msglevel level, const char *msg, ...) 19 | { 20 | va_list va; 21 | va_start(va, msg); 22 | msglog_logv(l, level, msg, va); 23 | va_end(va); 24 | } 25 | 26 | void msglog_debug(msglogger l, const char *msg, ...) 27 | { 28 | va_list va; 29 | va_start(va, msg); 30 | msglog_logv(l, MSG_DEBUG, msg, va); 31 | va_end(va); 32 | } 33 | 34 | void msglog_info(msglogger l, const char *msg, ...) 35 | { 36 | va_list va; 37 | va_start(va, msg); 38 | msglog_logv(l, MSG_INFO, msg, va); 39 | va_end(va); 40 | } 41 | 42 | void msglog_notice(msglogger l, const char *msg, ...) 43 | { 44 | va_list va; 45 | va_start(va, msg); 46 | msglog_logv(l, MSG_NOTICE, msg, va); 47 | va_end(va); 48 | } 49 | 50 | void msglog_warning(msglogger l, const char *msg, ...) 51 | { 52 | va_list va; 53 | va_start(va, msg); 54 | msglog_logv(l, MSG_WARNING, msg, va); 55 | va_end(va); 56 | } 57 | 58 | void msglog_error(msglogger l, const char *msg, ...) 59 | { 60 | va_list va; 61 | va_start(va, msg); 62 | msglog_logv(l, MSG_ERROR, msg, va); 63 | va_end(va); 64 | } 65 | 66 | void msglog_oomerror(msglogger l) 67 | { 68 | msglog_error(l, "out of memory"); 69 | } 70 | 71 | void msglog_perror(msglogger l, const char *prefix) 72 | { 73 | const char *sysmsg = strerror(errno); 74 | if (prefix) 75 | msglog_error(l, "%s: %s", prefix, sysmsg); 76 | else 77 | msglog_error(l, "%s", sysmsg); 78 | } 79 | -------------------------------------------------------------------------------- /src/host/common/msglog.h: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | MSG_DEBUG, 3 | MSG_INFO, 4 | MSG_NOTICE, 5 | MSG_WARNING, 6 | MSG_ERROR, 7 | } msglevel; 8 | typedef struct msglogger_s *msglogger; 9 | struct msglogger_s { 10 | void (*log)(msglogger l, msglevel level, const char *msg); 11 | }; 12 | extern void msglog_log(msglogger l, msglevel level, const char *msg, ...); 13 | extern void msglog_debug(msglogger l, const char *msg, ...); 14 | extern void msglog_info(msglogger l, const char *msg, ...); 15 | extern void msglog_notice(msglogger l, const char *msg, ...); 16 | extern void msglog_warning(msglogger l, const char *msg, ...); 17 | extern void msglog_error(msglogger l, const char *msg, ...); 18 | extern void msglog_perror(msglogger l, const char *prefix); 19 | extern void msglog_oomerror(msglogger l); 20 | 21 | -------------------------------------------------------------------------------- /src/host/common/toc.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint32_t entry[99]; 3 | uint32_t first, last; 4 | uint32_t dunno; 5 | } dc_toc; 6 | #define MAKE_DC_TOC_ENTRY(lba, adr, ctrl) ((lba)|((adr)<<24)|((ctrl)<<28)) 7 | #define MAKE_DC_TOC_TRACK(n) (((n)&0xff)<<16) 8 | #define GET_DC_TOC_ENTRY_LBA(n) ((n)&0x00ffffff) 9 | #define GET_DC_TOC_ENTRY_ADR(n) (((n)&0x0f000000)>>24) 10 | #define GET_DC_TOC_ENTRY_CTRL(n) (((n)&0xf0000000)>>28) 11 | #define GET_DC_TOC_TRACK(n) (((n)&0x00ff0000)>>16) 12 | -------------------------------------------------------------------------------- /src/host/configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(common/msglog.c) 2 | AC_CONFIG_HEADER(config.h) 3 | 4 | AC_CHECK_TOOL(AR, ar) 5 | AC_PROG_CC 6 | AC_C_BIGENDIAN 7 | AC_CHECK_HEADERS(byteswap.h sys/stat.h) 8 | AC_CHECK_DECLS([__builtin_bswap32,bswap_32],,,[[ 9 | #ifdef HAVE_BYTESWAP_H 10 | #include 11 | #endif 12 | ]]) 13 | AC_CHECK_FUNCS(pread stat) 14 | 15 | AC_OUTPUT(Makefile common/Makefile network/Makefile server/Makefile 16 | datasource/Makefile cmdline/Makefile) 17 | -------------------------------------------------------------------------------- /src/host/datasource/Makefile.in: -------------------------------------------------------------------------------- 1 | CC = @CC@ 2 | AR = @AR@ 3 | CFLAGS = @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)/common 4 | 5 | top_srcdir=@top_srcdir@ 6 | top_builddir=@top_builddir@ 7 | srcdir=@srcdir@ 8 | VPATH=@srcdir@ 9 | 10 | OBJS = datafile.o isofile.o nrgfile.o directory.o isofsparser.o datasource.o jukebox.o 11 | 12 | LIBTARGET = libdatasource.a 13 | 14 | all : $(LIBTARGET) 15 | 16 | clean : 17 | -rm -f $(LIBTARGET) $(OBJS) 18 | 19 | $(LIBTARGET) : $(OBJS) 20 | $(AR) rc $@ $(OBJS) 21 | 22 | datafile.o : datafile.c datafile.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h 23 | 24 | isofile.o : isofile.c isofile.h datafile.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h 25 | 26 | nrgfile.o : nrgfile.c nrgfile.h datafile.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h $(top_srcdir)/common/bswap.h 27 | 28 | directory.o : directory.c directory.h datafile.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h 29 | 30 | isofsparser.o : isofsparser.c isofsparser.h isofile.h datafile.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h 31 | 32 | datasource.o : datasource.c datasource.h isofsparser.h isofile.h nrgfile.h directory.h datafile.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h 33 | 34 | jukebox.o : jukebox.c jukebox.h datasource.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h 35 | -------------------------------------------------------------------------------- /src/host/datasource/datafile.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "msglog.h" 11 | #include "datafile.h" 12 | 13 | struct datafile_s { 14 | msglogger logger; 15 | int fd; 16 | }; 17 | 18 | void datafile_delete(datafile d) 19 | { 20 | if (d) { 21 | if (d->fd >= 0) 22 | close(d->fd); 23 | free(d); 24 | } 25 | } 26 | 27 | datafile datafile_new_from_filename(msglogger logger, const char *filename) 28 | { 29 | datafile d = calloc(1, sizeof(struct datafile_s)); 30 | if (d) { 31 | d->logger = logger; 32 | d->fd = open(filename, O_RDONLY); 33 | if (d->fd >= 0){ 34 | msglog_debug(logger, "Opened file %s", filename); 35 | return d; 36 | } else 37 | msglog_perror(logger, filename); 38 | datafile_delete(d); 39 | } else 40 | msglog_oomerror(logger); 41 | return NULL; 42 | } 43 | 44 | bool datafile_read(datafile d, datafile_offset offset, size_t size, void *buf) 45 | { 46 | #ifdef HAVE_PREAD 47 | ssize_t sz; 48 | sz = pread(d->fd, buf, size, offset); 49 | if (sz < 0) 50 | msglog_perror(d->logger, "pread"); 51 | else if (sz != size) 52 | msglog_warning(d->logger, "End of file reached"); 53 | else 54 | return true; 55 | return false; 56 | #else 57 | off_t pos; 58 | pos = lseek(d->fd, offset, SEEK_SET); 59 | if (pos < 0) 60 | msglog_perror(d->logger, "lseek"); 61 | else if (pos != offset) 62 | msglog_warning(d->logger, "End of file reached"); 63 | else { 64 | ssize_t sz; 65 | sz = read(d->fd, buf, size); 66 | if (sz < 0) 67 | msglog_perror(d->logger, "read"); 68 | else if (sz != size) 69 | msglog_warning(d->logger, "End of file reached"); 70 | else 71 | return true; 72 | } 73 | return false; 74 | #endif 75 | } 76 | 77 | size_t datafile_size(datafile d) 78 | { 79 | off_t pos; 80 | pos = lseek(d->fd, 0, SEEK_END); 81 | if (pos < 0) 82 | msglog_perror(d->logger, "lseek"); 83 | else 84 | return pos; 85 | return 0; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/host/datasource/datafile.h: -------------------------------------------------------------------------------- 1 | typedef struct datafile_s *datafile; 2 | typedef uint32_t datafile_offset; 3 | extern void datafile_delete(datafile d); 4 | extern datafile datafile_new_from_filename(msglogger logger, const char *filename); 5 | extern bool datafile_read(datafile d, datafile_offset offset, size_t size, void *buf); 6 | extern size_t datafile_size(datafile d); 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/host/datasource/datasource.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "msglog.h" 10 | #include "toc.h" 11 | #include "datafile.h" 12 | #include "isofile.h" 13 | #include "nrgfile.h" 14 | #include "directory.h" 15 | #include "datasource.h" 16 | #include "isofsparser.h" 17 | 18 | #define MAX_1ST_READ_SIZE (16*1024*1024) 19 | 20 | #define DESCRAMBLE_CHUNK (2048*1024) 21 | #define MAX_DESCRAMBLE_CHUNK_COUNT ((MAX_1ST_READ_SIZE+DESCRAMBLE_CHUNK-1)/DESCRAMBLE_CHUNK) 22 | 23 | typedef struct descrambler_buffer_s { 24 | uint16_t idx[DESCRAMBLE_CHUNK/32]; 25 | uint8_t secbuf[2048]; 26 | uint8_t dscrambuf[DESCRAMBLE_CHUNK]; 27 | } *descrambler_buffer; 28 | 29 | typedef struct descrambler_s { 30 | descrambler_buffer buffer; 31 | uint32_t offs, len; 32 | bool last; 33 | uint16_t seed[MAX_DESCRAMBLE_CHUNK_COUNT]; 34 | bool seed_valid[MAX_DESCRAMBLE_CHUNK_COUNT]; 35 | } *descrambler; 36 | 37 | typedef struct realization_s *realization; 38 | 39 | struct datasource_s { 40 | msglogger logger; 41 | realization realization; 42 | unsigned realize_count; 43 | char *filename; 44 | scramblingmode scrammode; 45 | }; 46 | 47 | struct realization_s { 48 | msglogger logger; 49 | datafile data; 50 | isofile iso; 51 | nrgfile nrg; 52 | directory dir; 53 | descrambler dscram; 54 | uint32_t bootsector0; 55 | uint32_t bootfile_sector, bootfile_length; 56 | char devinfo[8]; 57 | bool (*read_sector)(realization r, uint32_t sector, uint8_t *buffer); 58 | bool (*get_toc)(realization r, int session, dc_toc *toc); 59 | bool (*get_ipbin)(realization r, uint32_t n, uint8_t *buffer); 60 | int32_t (*get_1st_read_size)(realization r); 61 | bool (*get_1st_read)(realization r, uint32_t n, uint8_t *buffer); 62 | }; 63 | 64 | static descrambler descrambler_new(msglogger logger) 65 | { 66 | descrambler d = calloc(1, sizeof(struct descrambler_s)); 67 | if (d) { 68 | int i; 69 | d->buffer = NULL; 70 | d->offs = 0; 71 | d->len = 0; 72 | d->last = false; 73 | for(i=0; iseed_valid[i] = false; 75 | return d; 76 | } else 77 | msglog_oomerror(logger); 78 | return NULL; 79 | } 80 | 81 | static void descrambler_delete(descrambler d) 82 | { 83 | if (d) { 84 | if (d->buffer) 85 | free(d->buffer); 86 | free(d); 87 | } 88 | } 89 | 90 | static bool realization_read_sector_from_isofile(realization r, 91 | uint32_t sector, 92 | uint8_t *buffer) 93 | { 94 | return isofile_read_sector(r->iso, sector, buffer); 95 | } 96 | 97 | static bool realization_get_toc_from_isofile(realization r, int session, 98 | dc_toc *toc) 99 | { 100 | return isofile_get_toc(r->iso, session, toc); 101 | } 102 | 103 | static bool realization_read_sector_from_nrgfile(realization r, 104 | uint32_t sector, 105 | uint8_t *buffer) 106 | { 107 | return nrgfile_read_sector(r->nrg, sector, buffer); 108 | } 109 | 110 | static bool realization_get_toc_from_nrgfile(realization r, int session, 111 | dc_toc *toc) 112 | { 113 | return nrgfile_get_toc(r->nrg, session, toc); 114 | } 115 | 116 | static bool realization_read_sector_from_directory(realization r, 117 | uint32_t sector, 118 | uint8_t *buffer) 119 | { 120 | return directory_read_sector(r->dir, sector, buffer); 121 | } 122 | 123 | static bool realization_get_toc_from_directory(realization r, int session, 124 | dc_toc *toc) 125 | { 126 | return directory_get_toc(r->dir, session, toc); 127 | } 128 | 129 | static bool realization_get_ipbin_from_datasource(realization r, 130 | uint32_t n, uint8_t *buffer) 131 | { 132 | return r->read_sector(r, r->bootsector0+n, buffer); 133 | } 134 | 135 | static int32_t realization_get_1st_read_size_generic(realization r) 136 | { 137 | return r->bootfile_length; 138 | } 139 | 140 | static bool realization_get_1st_read_from_datasource(realization r, 141 | uint32_t n, uint8_t *buffer) 142 | { 143 | return r->read_sector(r, r->bootfile_sector+n, buffer); 144 | } 145 | 146 | static void realization_delete(realization r) 147 | { 148 | if (r) { 149 | if (r->dscram) 150 | descrambler_delete(r->dscram); 151 | if (r->iso) 152 | isofile_delete(r->iso); 153 | if (r->nrg) 154 | nrgfile_delete(r->nrg); 155 | if (r->dir) 156 | directory_delete(r->dir); 157 | if (r->data) 158 | datafile_delete(r->data); 159 | free(r); 160 | } 161 | } 162 | 163 | static uint16_t compute_descrambling(uint16_t seed, uint32_t slice, 164 | uint16_t *idx) 165 | { 166 | int32_t i; 167 | 168 | slice >>= 5; 169 | 170 | for(i = 0; i < slice; i++) 171 | idx[i] = i; 172 | 173 | for(i = slice-1; i >= 0; --i) { 174 | 175 | seed = (seed * 2109 + 9273) & 0x7fff; 176 | 177 | uint16_t x = (((seed + 0xc000) & 0xffff) * (uint32_t)i) >> 16; 178 | 179 | uint16_t tmp = idx[i]; 180 | idx[i] = idx[x]; 181 | idx[x] = tmp; 182 | } 183 | 184 | return seed; 185 | } 186 | 187 | static bool realization_fill_and_descramble(realization r) 188 | { 189 | descrambler d = r->dscram; 190 | uint32_t n = d->offs; 191 | uint8_t *buffer = d->buffer->dscrambuf; 192 | uint32_t cnt = d->len; 193 | int chunk = n / (DESCRAMBLE_CHUNK>>11); 194 | uint16_t *idx = d->buffer->idx; 195 | uint8_t *secbuf = d->buffer->secbuf; 196 | 197 | if (!d->seed_valid[chunk]) { 198 | int i; 199 | for (i=0; iseed_valid[i] && !d->seed_valid[i+1]) { 201 | d->seed[i+1] = compute_descrambling(d->seed[i], DESCRAMBLE_CHUNK, idx); 202 | d->seed_valid[i+1] = true; 203 | } 204 | if (!d->seed_valid[chunk]) { 205 | msglog_error(r->logger, "Unable to compute seed for chunk %d!", chunk); 206 | return false; 207 | } 208 | } 209 | 210 | uint16_t seed = d->seed[chunk]; 211 | uint32_t slice = DESCRAMBLE_CHUNK; 212 | while (cnt >= 2048) 213 | if (slice > cnt) 214 | slice >>= 1; 215 | else { 216 | seed = compute_descrambling(seed, slice, idx); 217 | int32_t x = (slice>>5)-1; 218 | uint32_t disp = 0; 219 | while (x>=0) { 220 | if (!((~x)&((2048>>5)-1))) { 221 | if (!r->get_1st_read(r, n++, secbuf)) 222 | return false; 223 | disp = 0; 224 | } 225 | memcpy(buffer+32*idx[x], secbuf+disp, 32); 226 | disp += 32; 227 | --x; 228 | } 229 | buffer += slice; 230 | cnt -= slice; 231 | } 232 | if (cnt > 0) { 233 | uint32_t disp = 0; 234 | if (!r->get_1st_read(r, n, secbuf)) 235 | return false; 236 | while (cnt >= 32) 237 | if (slice > cnt) 238 | slice >>= 1; 239 | else { 240 | seed = compute_descrambling(seed, slice, idx); 241 | int32_t x = (slice>>5)-1; 242 | while (x>=0) { 243 | memcpy(buffer+32*idx[x], secbuf+disp, 32); 244 | disp += 32; 245 | --x; 246 | } 247 | buffer += slice; 248 | cnt -= slice; 249 | } 250 | if (cnt > 0) 251 | memcpy(buffer, secbuf+disp, cnt); 252 | } 253 | 254 | if (!d->last) { 255 | d->seed[chunk+1] = seed; 256 | d->seed_valid[chunk+1] = true; 257 | } 258 | return true; 259 | } 260 | 261 | static bool realization_descramble_1st_read(realization r, uint32_t n, uint8_t *buffer) 262 | { 263 | descrambler d = r->dscram; 264 | if (d->buffer == NULL) { 265 | if((d->buffer = malloc(sizeof(struct descrambler_buffer_s))) == NULL) { 266 | msglog_oomerror(r->logger); 267 | return false; 268 | } 269 | msglog_debug(r->logger, "Allocated a descrambling buffer"); 270 | d->offs = 0; 271 | d->len = 0; 272 | d->last = false; 273 | } 274 | 275 | if (n < d->offs || ((n - d->offs)<<11) >= d->len) { 276 | d->offs = n & ~((DESCRAMBLE_CHUNK>>11)-1); 277 | d->len = 0; 278 | d->last = false; 279 | int32_t totsize = r->get_1st_read_size(r); 280 | if (totsize < 0 || ((uint32_t)totsize) <= (n << 11)) { 281 | msglog_error(r->logger, "Descrambling after end of 1ST_READ.BIN"); 282 | return false; 283 | } 284 | if (((uint32_t)totsize) > ((d->offs << 11)+DESCRAMBLE_CHUNK)) 285 | d->len = DESCRAMBLE_CHUNK; 286 | else { 287 | d->len = ((uint32_t)totsize) - (d->offs << 11); 288 | d->last = true; 289 | } 290 | if (!realization_fill_and_descramble(r)) { 291 | d->offs = 0; 292 | d->len = 0; 293 | d->last = false; 294 | return false; 295 | } 296 | } 297 | 298 | n -= d->offs; 299 | if (d->last && (n<<11)+2048 >= d->len) { 300 | memset(buffer, 0, 2048); 301 | memcpy(buffer, d->buffer->dscrambuf + (n<<11), d->len - (n<<11)); 302 | free(d->buffer); 303 | msglog_debug(r->logger, "Freed the descrambling buffer"); 304 | d->buffer = NULL; 305 | d->offs = 0; 306 | d->len = 0; 307 | d->last = false; 308 | } else 309 | memcpy(buffer, d->buffer->dscrambuf + (n<<11), 2048); 310 | return true; 311 | } 312 | 313 | static bool realization_setup_fs(realization r, datasource ds, isofs fs) 314 | { 315 | uint8_t ip0000[2048]; 316 | char bootname[20]; 317 | int namelen; 318 | r->bootsector0 = isofs_get_bootsector(fs, 0); 319 | if (!datasource_read_sector(ds, r->bootsector0, ip0000)) 320 | return false; 321 | if (memcmp(ip0000, "SEGA SEGAKATANA ", 16)) { 322 | msglog_error(r->logger, "Invalid bootsector"); 323 | return false; 324 | } 325 | r->get_ipbin = realization_get_ipbin_from_datasource; 326 | memcpy(r->devinfo, ip0000+0x25, 6); 327 | r->devinfo[6] = 0; 328 | msglog_debug(r->logger, "Device info: \"%s\"", r->devinfo); 329 | memcpy(bootname, ip0000+0x60, 16); 330 | for(namelen=16; namelen>0; --namelen) 331 | if(bootname[namelen-1] != ' ') 332 | break; 333 | bootname[namelen] = 0; 334 | msglog_debug(r->logger, "Boot filename: \"%s\"", bootname); 335 | if (!isofs_find_file(fs, bootname, 336 | &r->bootfile_sector, &r->bootfile_length)) { 337 | msglog_error(r->logger, "Boot file \"%s\" not found!", bootname); 338 | return false; 339 | } 340 | r->get_1st_read_size = realization_get_1st_read_size_generic; 341 | r->get_1st_read = realization_get_1st_read_from_datasource; 342 | msglog_debug(r->logger, "Found file at LBA %lu, size is %lu bytes", 343 | (unsigned long)r->bootfile_sector, 344 | (unsigned long)r->bootfile_length); 345 | return true; 346 | } 347 | 348 | static bool realization_setup_descrambling(realization r, datasource ds) 349 | { 350 | switch(ds->scrammode) { 351 | case SCRAMBLING_ENABLED: 352 | break; 353 | 354 | case SCRAMBLING_DISABLED: 355 | /* No descrambling needed */ 356 | return true; 357 | 358 | case SCRAMBLING_AUTODETECT: 359 | if (!strcmp(r->devinfo, "CD-ROM")) { 360 | msglog_info(r->logger, "CD-ROM (MIL-CD) detected, assuming scrambled"); 361 | break; 362 | } else if (!strcmp(r->devinfo, "MIL CD")) { 363 | msglog_info(r->logger, "MIL-CD detected, assuming scrambled"); 364 | break; 365 | } else if (!strcmp(r->devinfo, "GD-ROM")) { 366 | msglog_info(r->logger, "GD-ROM detected, assuming not scrambled"); 367 | /* No descrambling needed */ 368 | return true; 369 | } else { 370 | msglog_warning(r->logger, "Device information \"%s\" unknown, " 371 | "assuming scrambled", r->devinfo); 372 | break; 373 | } 374 | } 375 | 376 | if ((r->dscram = descrambler_new(r->logger)) == NULL) { 377 | msglog_oomerror(r->logger); 378 | return false; 379 | } 380 | 381 | r->dscram->seed[0] = r->get_1st_read_size(r) & 0xffff; 382 | r->dscram->seed_valid[0] = true; 383 | 384 | return true; 385 | } 386 | 387 | static bool realization_setup_disc(realization r, datasource ds) 388 | { 389 | isofs fs; 390 | bool result = false; 391 | 392 | if (directory_check(r->logger, ds->filename)) { 393 | 394 | if ((r->dir = directory_new(r->logger, ds->filename)) == NULL) 395 | return false; 396 | 397 | r->read_sector = realization_read_sector_from_directory; 398 | r->get_toc = realization_get_toc_from_directory; 399 | 400 | } else { 401 | 402 | if ((r->data = datafile_new_from_filename(r->logger, ds->filename)) == NULL) 403 | return false; 404 | 405 | if (nrgfile_check(r->logger, r->data)) { 406 | 407 | if ((r->nrg = nrgfile_new(r->logger, r->data)) == NULL) 408 | return false; 409 | 410 | r->read_sector = realization_read_sector_from_nrgfile; 411 | r->get_toc = realization_get_toc_from_nrgfile; 412 | 413 | } else { 414 | 415 | if ((r->iso = isofile_new(r->logger, r->data)) == NULL) 416 | return false; 417 | 418 | r->read_sector = realization_read_sector_from_isofile; 419 | r->get_toc = realization_get_toc_from_isofile; 420 | 421 | } 422 | 423 | } 424 | 425 | fs = isofs_new(r->logger, ds); 426 | if (fs != NULL) { 427 | result = realization_setup_fs(r, ds, fs); 428 | isofs_delete(fs); 429 | } 430 | 431 | if (result) 432 | if (r->get_1st_read_size(r) > MAX_1ST_READ_SIZE) { 433 | msglog_error(r->logger, "Main binary is too lage (>16MiB)"); 434 | result = false; 435 | } else 436 | result = realization_setup_descrambling(r, ds); 437 | 438 | return result; 439 | } 440 | 441 | static realization realization_new(msglogger logger) 442 | { 443 | realization r = calloc(1, sizeof(struct realization_s)); 444 | if (r) { 445 | r->logger = logger; 446 | r->data = NULL; 447 | r->iso = NULL; 448 | r->nrg = NULL; 449 | r->dir = NULL; 450 | r->dscram = NULL; 451 | r->read_sector = NULL; 452 | r->get_toc = NULL; 453 | r->get_ipbin = NULL; 454 | r->get_1st_read_size = NULL; 455 | r->get_1st_read = NULL; 456 | return r; 457 | } else 458 | msglog_oomerror(logger); 459 | return NULL; 460 | } 461 | 462 | bool datasource_realize(datasource ds) 463 | { 464 | if (ds->realize_count) { 465 | ds->realize_count++; 466 | return true; 467 | } 468 | if ((ds->realization = realization_new(ds->logger)) == NULL) 469 | return false; 470 | if (!realization_setup_disc(ds->realization, ds)) { 471 | realization_delete(ds->realization); 472 | ds->realization = NULL; 473 | return false; 474 | } 475 | ds->realize_count = 1; 476 | return true; 477 | } 478 | 479 | void datasource_unrealize(datasource ds) 480 | { 481 | if (!ds->realize_count) { 482 | msglog_warning(ds->logger, "Unrealized already unrealized datasource"); 483 | return; 484 | } 485 | if (!--ds->realize_count) { 486 | realization_delete(ds->realization); 487 | ds->realization = NULL; 488 | } 489 | } 490 | 491 | bool datasource_read_sector(datasource ds, uint32_t sector, uint8_t *buffer) 492 | { 493 | if (ds->realization) 494 | return ds->realization->read_sector(ds->realization, sector, buffer); 495 | else { 496 | msglog_error(ds->logger, "Read sector on unrealized datasource"); 497 | return false; 498 | } 499 | } 500 | 501 | extern bool datasource_get_toc(datasource ds, int session, dc_toc *toc) 502 | { 503 | if (ds->realization) 504 | return ds->realization->get_toc(ds->realization, session, toc); 505 | else { 506 | msglog_error(ds->logger, "Get TOC on unrealized datasource"); 507 | return false; 508 | } 509 | } 510 | 511 | extern bool datasource_get_ipbin(datasource ds, uint32_t n, uint8_t *buffer) 512 | { 513 | if (ds->realization) 514 | return ds->realization->get_ipbin(ds->realization, n, buffer); 515 | else { 516 | msglog_error(ds->logger, "Get IP.BIN on unrealized datasource"); 517 | return false; 518 | } 519 | } 520 | 521 | extern int32_t datasource_get_1st_read_size(datasource ds) 522 | { 523 | if (ds->realization) 524 | return ds->realization->get_1st_read_size(ds->realization); 525 | else { 526 | msglog_error(ds->logger, "Get 1ST_READ.BIN size on unrealized datasource"); 527 | return -1; 528 | } 529 | } 530 | 531 | extern bool datasource_get_1st_read(datasource ds, uint32_t n, uint8_t *buffer) 532 | { 533 | if (ds->realization) { 534 | if (ds->realization->dscram) 535 | return realization_descramble_1st_read(ds->realization, n, buffer); 536 | else 537 | return ds->realization->get_1st_read(ds->realization, n, buffer); 538 | } else { 539 | msglog_error(ds->logger, "Get 1ST_READ.BIN on unrealized datasource"); 540 | return false; 541 | } 542 | } 543 | 544 | void datasource_delete(datasource ds) 545 | { 546 | if (ds) { 547 | if (ds->realize_count > 0) 548 | msglog_warning(ds->logger, "Deleting datasource with realize_count > 0"); 549 | if (ds->realization) 550 | realization_delete(ds->realization); 551 | if (ds->filename) 552 | free(ds->filename); 553 | free(ds); 554 | } 555 | } 556 | 557 | datasource datasource_new_from_filename(msglogger logger, const char *filename) 558 | { 559 | datasource ds = calloc(1, sizeof(struct datasource_s)); 560 | if (ds) { 561 | ds->logger = logger; 562 | ds->realization = NULL; 563 | ds->scrammode = SCRAMBLING_AUTODETECT; 564 | if ((ds->filename = strdup(filename)) != NULL) 565 | return ds; 566 | else 567 | msglog_oomerror(logger); 568 | datasource_delete(ds); 569 | } else 570 | msglog_oomerror(logger); 571 | return NULL; 572 | } 573 | -------------------------------------------------------------------------------- /src/host/datasource/datasource.h: -------------------------------------------------------------------------------- 1 | typedef struct datasource_s *datasource; 2 | typedef enum { 3 | SCRAMBLING_ENABLED, 4 | SCRAMBLING_DISABLED, 5 | SCRAMBLING_AUTODETECT, 6 | } scramblingmode; 7 | extern void datasource_delete(datasource ds); 8 | extern datasource datasource_new_from_filename(msglogger logger, const char *filename); 9 | extern bool datasource_realize(datasource ds); 10 | extern void datasource_unrealize(datasource ds); 11 | extern bool datasource_read_sector(datasource ds, uint32_t sector, uint8_t *buffer); 12 | extern bool datasource_get_toc(datasource ds, int session, dc_toc *toc); 13 | extern bool datasource_get_ipbin(datasource ds, uint32_t n, uint8_t *buffer); 14 | extern int32_t datasource_get_1st_read_size(datasource ds); 15 | extern bool datasource_get_1st_read(datasource ds, uint32_t n, uint8_t *buffer); 16 | 17 | -------------------------------------------------------------------------------- /src/host/datasource/directory.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #ifdef HAVE_SYS_STAT_H 12 | #include 13 | #endif 14 | #include 15 | #include 16 | 17 | #include "msglog.h" 18 | #include "toc.h" 19 | #include "datafile.h" 20 | #include "directory.h" 21 | #include "bswap.h" 22 | 23 | #define BASE_SECTOR 45150 24 | 25 | typedef struct direntry_s *direntry; 26 | typedef struct dirnode_s *dirnode; 27 | 28 | typedef struct datanode_s { 29 | uint32_t first_sector, num_sectors; 30 | bool (*read_sector)(directory d, uint32_t sector, uint8_t *buffer, struct datanode_s *node); 31 | } *datanode; 32 | 33 | struct direntry_s { 34 | struct datanode_s node; 35 | direntry next; 36 | char *path; 37 | dirnode dirnode; 38 | uint32_t size; 39 | }; 40 | 41 | struct dirnode_s { 42 | struct datanode_s node; 43 | direntry first; 44 | uint8_t *dirdata; 45 | }; 46 | 47 | struct directory_s { 48 | msglogger logger; 49 | dirnode rootdir; 50 | datanode current; 51 | datafile current_file; 52 | datanode ip_bin; 53 | uint32_t fs_num_sectors; 54 | }; 55 | 56 | static void dirnode_delete(dirnode dn); 57 | static dirnode dirnode_new(directory d, const char *path); 58 | 59 | #ifdef HAVE_STAT 60 | static bool stat_file(msglogger logger, const char *path, 61 | uint32_t *size, bool *isdir) 62 | { 63 | struct stat buf; 64 | if (stat(path, &buf)>=0) { 65 | if (size != NULL) 66 | *size = buf.st_size; 67 | if (isdir != NULL) 68 | *isdir = S_ISDIR(buf.st_mode); 69 | return true; 70 | } else { 71 | msglog_perror(logger, path); 72 | return false; 73 | } 74 | } 75 | #else 76 | #error stat() not available, please provide a fallback implementation... 77 | #endif 78 | 79 | static void direntry_delete(direntry de) 80 | { 81 | if (de) { 82 | if (de->dirnode) 83 | dirnode_delete(de->dirnode); 84 | if (de->path) 85 | free(de->path); 86 | free(de); 87 | } 88 | } 89 | 90 | static bool direntry_read_sector(directory d, uint32_t sector, 91 | uint8_t *buffer, struct datanode_s *node) 92 | { 93 | direntry de = (direntry)node; 94 | if (d->current_file == NULL) 95 | if ((d->current_file = 96 | datafile_new_from_filename(d->logger, de->path)) == NULL) 97 | return false; 98 | if (sector >= 16) /* special case for IP.BIN */ 99 | sector -= de->node.first_sector; 100 | sector <<= 11; 101 | if (sector < de->size && sector+2048 > de->size) { 102 | /* final sector */ 103 | uint32_t len = de->size - sector; 104 | memset(buffer+len, 0, 2048-len); 105 | return datafile_read(d->current_file, sector, len, buffer); 106 | } else 107 | return datafile_read(d->current_file, sector, 2048, buffer); 108 | } 109 | 110 | static direntry direntry_new(directory d, const char *base_path, 111 | struct dirent *dire) 112 | { 113 | msglogger logger = d->logger; 114 | direntry de = calloc(1, sizeof(struct direntry_s)); 115 | if (de) { 116 | uint32_t f_size; 117 | bool f_isdir; 118 | de->next = NULL; 119 | de->node.read_sector = direntry_read_sector; 120 | if ((de->path = malloc(strlen(base_path)+strlen(dire->d_name)+4))) { 121 | sprintf(de->path, "%s/%s", base_path, dire->d_name); 122 | if (stat_file(logger, de->path, &f_size, &f_isdir)>=0) { 123 | de->size = f_size; 124 | de->node.num_sectors = (f_size + 2047)>>11; 125 | if (!f_isdir || 126 | (de->dirnode = dirnode_new(d, de->path))) 127 | return de; 128 | } 129 | } else 130 | msglog_oomerror(logger); 131 | direntry_delete(de); 132 | } else 133 | msglog_oomerror(logger); 134 | return NULL; 135 | } 136 | 137 | static void dirnode_delete(dirnode dn) 138 | { 139 | if (dn) { 140 | direntry de; 141 | while((de = dn->first)) { 142 | dn->first = de->next; 143 | direntry_delete(de); 144 | } 145 | if (dn->dirdata != NULL) 146 | free(dn->dirdata); 147 | free(dn); 148 | } 149 | } 150 | 151 | static bool skip_dirent(struct dirent *dire) 152 | { 153 | if (dire->d_name[0] == '.' && 154 | (dire->d_name[1] == 0 || 155 | (dire->d_name[1] == '.' && dire->d_name[2] == 0))) 156 | return true; 157 | return false; 158 | } 159 | 160 | static bool dirnode_read_sector(directory d, uint32_t sector, 161 | uint8_t *buffer, struct datanode_s *node) 162 | { 163 | dirnode dn = (dirnode)node; 164 | memcpy(buffer, dn->dirdata+((sector-dn->node.first_sector)<<11), 2048); 165 | return true; 166 | } 167 | 168 | static datanode dirnode_find_sector(directory d, dirnode dn, uint32_t sector) 169 | { 170 | direntry de; 171 | if (sector >= dn->node.first_sector && 172 | sector - dn->node.first_sector < dn->node.num_sectors) 173 | return &dn->node; 174 | for (de = dn->first; de != NULL; de = de->next) 175 | if (sector >= de->node.first_sector && 176 | sector - de->node.first_sector < de->node.num_sectors) { 177 | if (de->dirnode) 178 | return dirnode_find_sector(d, de->dirnode, sector); 179 | return &de->node; 180 | } 181 | return NULL; 182 | } 183 | 184 | static void make_iso_name(char *buf, const char *src) 185 | { 186 | const char *slash = strrchr(src, '/'); 187 | int cnt = 0; 188 | if (slash) 189 | src = slash+1; 190 | while (cnt < 31 && *src) { 191 | int ch = *src++; 192 | *buf++ = toupper(ch); 193 | cnt++; 194 | } 195 | *buf = 0; 196 | if (!strchr(buf, ';')) { 197 | *buf++ = ';'; 198 | *buf++ = '1'; 199 | *buf = 0; 200 | } 201 | } 202 | 203 | static void dirnode_make_record(uint8_t *data, uint32_t sec, uint32_t len, 204 | uint8_t ty, uint8_t nl, const char *name) 205 | { 206 | uint8_t del = (nl+34)&~1; 207 | memset(data, 0, del); 208 | sec += BASE_SECTOR-150; 209 | data[0] = del; 210 | #ifdef WORDS_BIGENDIAN 211 | memcpy(data+6, &sec, 4); 212 | memcpy(data+14, &len, 4); 213 | sec = SWAP32(sec); 214 | len = SWAP32(len); 215 | memcpy(data+2, &sec, 4); 216 | memcpy(data+10, &len, 4); 217 | #else 218 | memcpy(data+2, &sec, 4); 219 | memcpy(data+10, &len, 4); 220 | sec = SWAP32(sec); 221 | len = SWAP32(len); 222 | memcpy(data+6, &sec, 4); 223 | memcpy(data+14, &len, 4); 224 | #endif 225 | data[18] = 0x64; 226 | data[19] = 1; 227 | data[20] = 1; 228 | data[25] = ty; 229 | data[32] = nl; 230 | if (nl) 231 | memcpy(data+33, name, nl); 232 | } 233 | 234 | static uint32_t dirnode_make_dirdata(directory d, dirnode dn, uint32_t sector, 235 | uint8_t *data, dirnode parent) 236 | { 237 | direntry de; 238 | uint32_t cnt = 0, offs = 68; 239 | if (!parent) 240 | parent = dn; 241 | if (data) { 242 | dirnode_make_record(data, dn->node.first_sector, dn->node.num_sectors<<11, 243 | 2, 1, "\0"); 244 | dirnode_make_record(data+34, parent->node.first_sector, 245 | parent->node.num_sectors<<11, 2, 1, "\1"); 246 | } 247 | for (de = dn->first; de != NULL; de = de->next) { 248 | char iso_name[40]; 249 | uint8_t nl, del, et; 250 | uint32_t ln; 251 | if (de->dirnode) { 252 | et = 2; 253 | ln = de->dirnode->node.num_sectors << 11; 254 | } else { 255 | et = 0; 256 | ln = de->size; 257 | } 258 | make_iso_name(iso_name, de->path); 259 | nl = strlen(iso_name); 260 | del = (nl+34)&~1; 261 | if (offs + del > 2048) { 262 | if (data) { 263 | memset(data+offs, 0, 2048-offs); 264 | data += 2048; 265 | } 266 | offs = 0; 267 | cnt++; 268 | } 269 | if (data) 270 | dirnode_make_record(data+offs, de->node.first_sector, ln, et, nl, 271 | iso_name); 272 | offs += del; 273 | } 274 | if (offs) { 275 | if (data) 276 | memset(data+offs, 0, 2048-offs); 277 | cnt++; 278 | } 279 | return cnt; 280 | } 281 | 282 | static uint32_t dirnode_layout(directory d, dirnode dn, uint32_t sector, 283 | dirnode parent) 284 | { 285 | direntry de; 286 | uint32_t size = dirnode_make_dirdata(d, dn, sector, NULL, parent); 287 | dn->node.first_sector = sector; 288 | dn->node.num_sectors = size; 289 | for (de = dn->first; de != NULL; de = de->next) { 290 | if (de->dirnode) { 291 | de->node.num_sectors = dirnode_layout(d, de->dirnode, sector+size, dn); 292 | if (!de->node.num_sectors) 293 | return 0; 294 | } 295 | de->node.first_sector = sector+size; 296 | size += de->node.num_sectors; 297 | } 298 | if (dn->dirdata != NULL) 299 | free(dn->dirdata); 300 | if (!(dn->dirdata = malloc(dn->node.num_sectors<<11))) { 301 | msglog_oomerror(d->logger); 302 | return 0; 303 | } 304 | dirnode_make_dirdata(d, dn, sector, dn->dirdata, parent); 305 | return size; 306 | } 307 | 308 | static dirnode dirnode_new(directory d, const char *path) 309 | { 310 | msglogger logger = d->logger; 311 | dirnode dn = calloc(1, sizeof(struct dirnode_s)); 312 | if (dn) { 313 | DIR *dir; 314 | struct dirent *dire; 315 | dn->first = NULL; 316 | dn->dirdata = NULL; 317 | dn->node.read_sector = dirnode_read_sector; 318 | if ((dir = opendir(path))) { 319 | while((dire = readdir(dir))) { 320 | if (skip_dirent(dire)) 321 | continue; 322 | direntry de = direntry_new(d, path, dire); 323 | if (!de) { 324 | dirnode_delete(dn); 325 | closedir(dir); 326 | return NULL; 327 | } 328 | de->next = dn->first; 329 | dn->first = de; 330 | } 331 | closedir(dir); 332 | return dn; 333 | } else 334 | msglog_perror(logger, path); 335 | dirnode_delete(dn); 336 | } else 337 | msglog_oomerror(logger); 338 | return NULL; 339 | } 340 | 341 | void directory_delete(directory d) 342 | { 343 | if (d) { 344 | if (d->rootdir) 345 | dirnode_delete(d->rootdir); 346 | if (d->current_file) 347 | datafile_delete(d->current_file); 348 | free(d); 349 | } 350 | } 351 | 352 | static datanode directory_find_sector(directory d, uint32_t sector) 353 | { 354 | if (d->current_file != NULL) { 355 | datafile_delete(d->current_file); 356 | d->current_file = NULL; 357 | } 358 | if (sector >= d->rootdir->node.first_sector && 359 | sector - d->rootdir->node.first_sector < d->fs_num_sectors) 360 | return dirnode_find_sector(d, d->rootdir, sector); 361 | else if (sector < 16 && d->ip_bin && sector < d->ip_bin->num_sectors) 362 | return d->ip_bin; 363 | else 364 | return NULL; 365 | } 366 | 367 | static datanode directory_find_ip_bin(directory d) 368 | { 369 | direntry de; 370 | for (de = d->rootdir->first; de != NULL; de = de->next) 371 | if (!de->dirnode) { 372 | char iso_name[40]; 373 | make_iso_name(iso_name, de->path); 374 | if (!strcmp(iso_name, "IP.BIN;1")) 375 | return &de->node; 376 | } 377 | return NULL; 378 | } 379 | 380 | directory directory_new(msglogger logger, const char *dirname) 381 | { 382 | directory d = calloc(1, sizeof(struct directory_s)); 383 | if (d) { 384 | d->logger = logger; 385 | d->current = NULL; 386 | d->current_file = NULL; 387 | if ((d->rootdir = dirnode_new(d, dirname)) && 388 | (d->fs_num_sectors = dirnode_layout(d, d->rootdir, 20, NULL))) { 389 | d->ip_bin = directory_find_ip_bin(d); 390 | return d; 391 | } 392 | directory_delete(d); 393 | } else 394 | msglog_oomerror(logger); 395 | return NULL; 396 | } 397 | 398 | bool directory_check(msglogger logger, const char *dirname) 399 | { 400 | bool f_isdir; 401 | if (!stat_file(logger, dirname, NULL, &f_isdir)) 402 | return false; 403 | return f_isdir; 404 | } 405 | 406 | static bool directory_create_pvd(directory d, uint8_t *buffer) 407 | { 408 | memset(buffer, 0, 2048); 409 | buffer[0] = 1; 410 | strcpy(buffer+1, "CD001"); 411 | buffer[6] = 1; 412 | strcpy(buffer+8, "Solaris"); 413 | memset(buffer+15, ' ', 0x28-15); 414 | strcpy(buffer+0x28, "CDROM"); 415 | memset(buffer+0x2d, ' ', 0x48-0x2d); 416 | buffer[0x50] = 0x1c; 417 | buffer[0x57] = 0x1c; 418 | buffer[0x78] = 1; 419 | buffer[0x7b] = 1; 420 | buffer[0x7c] = 1; 421 | buffer[0x7f] = 1; 422 | buffer[0x81] = 8; 423 | buffer[0x82] = 8; 424 | buffer[0x84] = 10; 425 | buffer[0x8b] = 10; 426 | buffer[0x8c] = 0x12; 427 | buffer[0x97] = 0x14; 428 | memcpy(buffer+156, d->rootdir->dirdata, 34); 429 | memset(buffer+0xbe, ' ', 0x23e -0xbe); 430 | strcpy(buffer+0x23e, "MKISOFS ISO 9660 FILESYSTEM BUILDER & " 431 | "CDRECORD CD-R/DVD CREATOR"); 432 | memset(buffer+0x27d, ' ', 0x32d-0x27d); 433 | strcpy(buffer+0x32d, "2001121616590900"); 434 | buffer[0x33d] = 4; 435 | strcpy(buffer+0x33e, "2001121616590900"); 436 | buffer[0x34e] = 4; 437 | strcpy(buffer+0x34f, "0000000000000000"); 438 | strcpy(buffer+0x360, "2001121616590900"); 439 | buffer[0x370] = 4; 440 | buffer[0x371] = 1; 441 | memset(buffer+0x373, ' ', 0x573-0x373); 442 | } 443 | 444 | bool directory_read_sector(directory d, uint32_t sector, uint8_t *buffer) 445 | { 446 | if (sector >= BASE_SECTOR) { 447 | sector -= BASE_SECTOR; 448 | if (sector == 16) 449 | return directory_create_pvd(d, buffer); 450 | if ((d->current && 451 | sector >= d->current->first_sector && 452 | (sector - d->current->first_sector) < d->current->num_sectors) || 453 | (d->current = directory_find_sector(d, sector))) 454 | return d->current->read_sector(d, sector, buffer, d->current); 455 | } 456 | msglog_warning(d->logger, "read from unassigned sector %d", sector); 457 | return false; 458 | } 459 | 460 | bool directory_get_toc(directory d, int session, dc_toc *toc) 461 | { 462 | memset(toc, 0, sizeof(*toc)); 463 | toc->entry[0] = MAKE_DC_TOC_ENTRY(150, 1, 0); 464 | toc->entry[1] = MAKE_DC_TOC_ENTRY(BASE_SECTOR, 1, 4); 465 | toc->dunno = MAKE_DC_TOC_ENTRY(BASE_SECTOR+d->rootdir->node.first_sector+ 466 | d->fs_num_sectors, 1, 4); 467 | toc->first = MAKE_DC_TOC_TRACK(1); 468 | toc->last = MAKE_DC_TOC_TRACK(2); 469 | return true; 470 | } 471 | 472 | -------------------------------------------------------------------------------- /src/host/datasource/directory.h: -------------------------------------------------------------------------------- 1 | typedef struct directory_s *directory; 2 | extern void directory_delete(directory d); 3 | extern directory directory_new(msglogger logger, const char *dirname); 4 | extern bool directory_check(msglogger logger, const char *dirname); 5 | extern bool directory_read_sector(directory d, uint32_t sector, uint8_t *buffer); 6 | extern bool directory_get_toc(directory d, int session, dc_toc *toc); 7 | -------------------------------------------------------------------------------- /src/host/datasource/isofile.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "msglog.h" 9 | #include "toc.h" 10 | #include "datafile.h" 11 | #include "isofile.h" 12 | 13 | /* Expect to find root directory within this many sectors from the start */ 14 | #define ROOT_DIRECTORY_HORIZON 500 15 | 16 | struct isofile_s { 17 | msglogger logger; 18 | datafile data; 19 | uint32_t num_sectors; 20 | uint32_t start_sector; 21 | }; 22 | 23 | static bool isofile_find_start_sector(isofile i) 24 | { 25 | uint32_t sec; 26 | uint8_t buf1[0x22], buf2[0x22]; 27 | for (sec = 16; sec < ROOT_DIRECTORY_HORIZON; sec++) { 28 | if (!datafile_read(i->data, sec<<11, 6, buf1)) 29 | return false; 30 | if (!memcmp(buf1, "\001CD001", 6)) 31 | break; 32 | else if(!memcmp(buf1, "\377CD001", 6)) 33 | return false; 34 | } 35 | if (sec >= ROOT_DIRECTORY_HORIZON) 36 | return false; 37 | msglog_debug(i->logger, "PVD is at %d", sec); 38 | if (!datafile_read(i->data, (sec<<11)+0x9c, 0x22, buf1)) 39 | return false; 40 | while (++sec < ROOT_DIRECTORY_HORIZON) { 41 | if (!datafile_read(i->data, sec<<11, 0x22, buf2)) 42 | return false; 43 | if (!memcmp(buf1, buf2, 0x12) && 44 | !memcmp(buf1+0x19, buf2+0x19, 0x9)) 45 | break; 46 | } 47 | if (sec >= ROOT_DIRECTORY_HORIZON) 48 | return false; 49 | msglog_debug(i->logger, "Root directory is at %d", sec); 50 | sec = ((((((buf1[5]<<8)|buf1[4])<<8)|buf1[3])<<8)|buf1[2])+150-sec; 51 | msglog_debug(i->logger, "Session offset is %d", sec); 52 | i->start_sector = sec; 53 | return true; 54 | } 55 | 56 | bool isofile_read_sector(isofile i, uint32_t sector, uint8_t *buffer) 57 | { 58 | if (sector < i->start_sector) 59 | return false; 60 | sector -= i->start_sector; 61 | if (sector >= i->num_sectors) 62 | return false; 63 | return datafile_read(i->data, sector<<11, 2048, buffer); 64 | } 65 | 66 | bool isofile_get_toc(isofile i, int session, dc_toc *toc) 67 | { 68 | memset(toc, 0, sizeof(*toc)); 69 | if (i->start_sector > 150) { 70 | toc->entry[0] = MAKE_DC_TOC_ENTRY(150, 1, 0); 71 | toc->entry[1] = MAKE_DC_TOC_ENTRY(i->start_sector, 1, 4); 72 | toc->last = MAKE_DC_TOC_TRACK(2); 73 | } else { 74 | toc->entry[0] = MAKE_DC_TOC_ENTRY(i->start_sector, 1, 4); 75 | toc->last = MAKE_DC_TOC_TRACK(1); 76 | } 77 | toc->dunno = MAKE_DC_TOC_ENTRY(i->start_sector+i->num_sectors, 1, 4); 78 | toc->first = MAKE_DC_TOC_TRACK(1); 79 | return true; 80 | } 81 | 82 | void isofile_delete(isofile i) 83 | { 84 | if (i) { 85 | free(i); 86 | } 87 | } 88 | 89 | isofile isofile_new(msglogger logger, datafile data) 90 | { 91 | isofile i = calloc(1, sizeof(struct isofile_s)); 92 | if (i) { 93 | i->logger = logger; 94 | i->data = data; 95 | i->num_sectors = datafile_size(data)>>11; 96 | if (isofile_find_start_sector(i)) { 97 | return i; 98 | } else 99 | msglog_error(logger, "Unable to determine the start sector for ISO"); 100 | isofile_delete(i); 101 | } else 102 | msglog_oomerror(logger); 103 | return NULL; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/host/datasource/isofile.h: -------------------------------------------------------------------------------- 1 | typedef struct isofile_s *isofile; 2 | extern void isofile_delete(isofile i); 3 | extern isofile isofile_new(msglogger logger, datafile data); 4 | extern bool isofile_read_sector(isofile i, uint32_t sector, uint8_t *buffer); 5 | extern bool isofile_get_toc(isofile i, int session, dc_toc *toc); 6 | 7 | -------------------------------------------------------------------------------- /src/host/datasource/isofsparser.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "msglog.h" 10 | #include "toc.h" 11 | #include "datafile.h" 12 | #include "datasource.h" 13 | #include "isofsparser.h" 14 | 15 | /* Expect to find root directory within this many sectors from the start */ 16 | #define ROOT_DIRECTORY_HORIZON 500 17 | 18 | struct isofs_s { 19 | msglogger logger; 20 | datasource ds; 21 | uint32_t datatrack_lba, root_lba, root_length; 22 | uint8_t buffer[2048]; 23 | }; 24 | 25 | static int ntohlp(const uint8_t *ptr) 26 | { 27 | return (ptr[0]<<24)|(ptr[1]<<16)|(ptr[2]<<8)|ptr[3]; 28 | } 29 | 30 | static bool fncompare(const char *fn1, int fn1len, const char *fn2, int fn2len) 31 | { 32 | while(fn2len--) 33 | if(!fn1len--) 34 | return *fn2 == ';'; 35 | else if(toupper((unsigned char)*fn1++) != toupper((unsigned char)*fn2++)) 36 | return 0; 37 | return fn1len == 0; 38 | } 39 | 40 | static bool isofs_find_datatrack(isofs i) 41 | { 42 | int session; 43 | for (session = 1; session >= 0; --session) { 44 | dc_toc toc; 45 | if (!datasource_get_toc(i->ds, session, &toc)) 46 | continue; 47 | int trk, first, last; 48 | first = GET_DC_TOC_TRACK(toc.first); 49 | last = GET_DC_TOC_TRACK(toc.last); 50 | if(first < 1 || last > 99 || first > last) 51 | continue; 52 | for(trk=last; trk>=first; --trk) 53 | if(GET_DC_TOC_ENTRY_CTRL(toc.entry[trk-1])&4) { 54 | i->datatrack_lba = GET_DC_TOC_ENTRY_LBA(toc.entry[trk-1]); 55 | msglog_debug(i->logger, 56 | "Found data track in session %d, track %d at LBA %d", 57 | session, trk, i->datatrack_lba); 58 | return true; 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | static bool isofs_find_root_directory(isofs i) 65 | { 66 | uint32_t sec; 67 | uint8_t *buf = i->buffer; 68 | for (sec = 16; sec < ROOT_DIRECTORY_HORIZON; sec++) { 69 | if (!datasource_read_sector(i->ds, i->datatrack_lba+sec, buf)) 70 | return false; 71 | if (!memcmp(buf, "\001CD001", 6)) 72 | break; 73 | else if(!memcmp(buf, "\377CD001", 6)) 74 | return false; 75 | } 76 | if (sec >= ROOT_DIRECTORY_HORIZON) 77 | return false; 78 | sec += i->datatrack_lba; 79 | msglog_debug(i->logger, "Found PVD at LBA %d", sec); 80 | i->root_lba = ntohlp(buf+156+6)+150; 81 | i->root_length = ntohlp(buf+156+14); 82 | msglog_debug(i->logger, "Root directory is at LBA %d, length %d bytes", 83 | i->root_lba, i->root_length); 84 | return true; 85 | } 86 | 87 | static bool isofs_find_entry(isofs i, const char *entryname, 88 | uint32_t *sector, uint32_t *length, int enlen, 89 | uint32_t dirsec, uint32_t dirlen, int dirflag) 90 | { 91 | uint32_t len; 92 | uint8_t *buf = i->buffer; 93 | const uint8_t *p; 94 | dirflag = (dirflag? 2 : 0); 95 | while(dirlen > 0) { 96 | if (!datasource_read_sector(i->ds, dirsec, buf)) 97 | return false; 98 | if (dirlen > 2048) { 99 | len = 2048; 100 | dirlen -= 2048; 101 | dirsec++; 102 | } else { 103 | len = dirlen; 104 | dirlen = 0; 105 | } 106 | for (p=buf; len>0; ) { 107 | if(!*p || *p>len) 108 | break; 109 | if (*p>32 && *p>32+p[32]) 110 | if ((p[25]&2) == dirflag && 111 | fncompare(entryname, enlen, (const char *)(p+33), p[32])) { 112 | if (sector) 113 | *sector = ntohlp(p+6)+150; 114 | if (length) 115 | *length = ntohlp(p+14); 116 | return true; 117 | } 118 | len -= *p; 119 | p += *p; 120 | } 121 | } 122 | return false; 123 | } 124 | 125 | bool isofs_find_file(isofs i, const char *filename, 126 | uint32_t *sector, uint32_t *length) 127 | { 128 | return isofs_find_entry(i, filename, sector, length, strlen(filename), 129 | i->root_lba, i->root_length, 0); 130 | } 131 | 132 | uint32_t isofs_get_bootsector(isofs i, uint32_t n) 133 | { 134 | return i->datatrack_lba + n; 135 | } 136 | 137 | void isofs_delete(isofs i) 138 | { 139 | if (i) { 140 | free(i); 141 | } 142 | } 143 | 144 | isofs isofs_new(msglogger logger, datasource ds) 145 | { 146 | isofs i = calloc(1, sizeof(struct isofs_s)); 147 | if (i) { 148 | i->logger = logger; 149 | i->ds = ds; 150 | if (isofs_find_datatrack(i)) { 151 | if (isofs_find_root_directory(i)) { 152 | return i; 153 | } else 154 | msglog_error(logger, "No PVD found"); 155 | } else 156 | msglog_error(logger, "No suitable data track found"); 157 | isofs_delete(i); 158 | } else 159 | msglog_oomerror(logger); 160 | return NULL; 161 | } 162 | -------------------------------------------------------------------------------- /src/host/datasource/isofsparser.h: -------------------------------------------------------------------------------- 1 | typedef struct isofs_s *isofs; 2 | extern void isofs_delete(isofs i); 3 | extern isofs isofs_new(msglogger logger, datasource ds); 4 | extern bool isofs_find_file(isofs i, const char *filename, 5 | uint32_t *sector, uint32_t *length); 6 | extern uint32_t isofs_get_bootsector(isofs i, uint32_t n); 7 | -------------------------------------------------------------------------------- /src/host/datasource/jukebox.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "msglog.h" 10 | #include "toc.h" 11 | #include "datasource.h" 12 | #include "jukebox.h" 13 | 14 | struct jukebox_s { 15 | msglogger logger; 16 | unsigned sourcecount, alloccount; 17 | datasource *list; 18 | }; 19 | 20 | void jukebox_delete(jukebox j) 21 | { 22 | if (j) { 23 | int i; 24 | for (i=0; isourcecount; i++) 25 | datasource_delete(j->list[i]); 26 | if (j->list) 27 | free(j->list); 28 | free(j); 29 | } 30 | } 31 | 32 | extern jukebox jukebox_new(msglogger logger) 33 | { 34 | jukebox j = calloc(1, sizeof(struct jukebox_s)); 35 | if (j) { 36 | j->logger = logger; 37 | j->list = NULL; 38 | return j; 39 | } else 40 | msglog_oomerror(logger); 41 | return NULL; 42 | } 43 | 44 | extern bool jukebox_add_datasource(jukebox j, datasource ds) 45 | { 46 | if (j->sourcecount >= j->alloccount) { 47 | datasource *newlist; 48 | unsigned cnt = j->alloccount + (j->alloccount >> 1); 49 | if (j->sourcecount >= cnt) 50 | cnt = j->sourcecount + 100; 51 | newlist = realloc(j->list, cnt*sizeof(datasource)); 52 | if (newlist == NULL) { 53 | msglog_oomerror(j->logger); 54 | return false; 55 | } 56 | j->list = newlist; 57 | j->alloccount = cnt; 58 | } 59 | j->list[j->sourcecount++] = ds; 60 | return true; 61 | } 62 | 63 | extern datasource jukebox_get_datasource(jukebox j, uint32_t id) 64 | { 65 | if (id >= j->sourcecount) 66 | return NULL; 67 | else 68 | return j->list[id]; 69 | } 70 | -------------------------------------------------------------------------------- /src/host/datasource/jukebox.h: -------------------------------------------------------------------------------- 1 | typedef struct jukebox_s *jukebox; 2 | extern void jukebox_delete(jukebox j); 3 | extern jukebox jukebox_new(msglogger logger); 4 | extern bool jukebox_add_datasource(jukebox j, datasource ds); 5 | extern datasource jukebox_get_datasource(jukebox j, uint32_t id); 6 | -------------------------------------------------------------------------------- /src/host/datasource/nrgfile.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "msglog.h" 10 | #include "toc.h" 11 | #include "datafile.h" 12 | #include "nrgfile.h" 13 | #include "bswap.h" 14 | 15 | #define MAX_TRACKS 100 16 | 17 | #ifdef WORDS_BIGENDIAN 18 | #define MKID(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d)) 19 | #else 20 | #define MKID(a,b,c,d) (((d)<<24)|((c)<<16)|((b)<<8)|(a)) 21 | #endif 22 | 23 | typedef struct nrgtrack_s { 24 | uint32_t first_sector, last_sector; 25 | uint32_t secsize, dataoffs, secskip; 26 | } nrgtrack; 27 | 28 | struct nrgfile_s { 29 | msglogger logger; 30 | datafile data; 31 | dc_toc toc; 32 | nrgtrack track[99], current_track; 33 | }; 34 | 35 | static bool nrgfile_read_cuex(nrgfile n, uint32_t offs, uint32_t sz) 36 | { 37 | struct { uint8_t mm, nn, ii, zz; uint32_t lba; } cuex[2*MAX_TRACKS+2]; 38 | int i, cnt; 39 | if (sz > sizeof(cuex) || sz < 16 || (sz & 15)) { 40 | msglog_error(n->logger, "Invalid length of CUEX chunk"); 41 | return false; 42 | } 43 | if (!datafile_read(n->data, offs, sz, cuex)) 44 | return false; 45 | cnt = sz>>3; 46 | #ifndef WORDS_BIGENDIAN 47 | for (i=0; ilogger, "Incorrect header/footer of CUEX chunk"); 53 | return false; 54 | } 55 | for (i=0; itoc.dunno = (cuex[i].mm << 24)|(cuex[i].lba + 150); 59 | } else { 60 | if (cuex[i].nn != 0&& 61 | (cuex[i].nn&0xf0)<0xa0 && (cuex[i].nn&0x0f)<0x0a) { 62 | int entry = (cuex[i].nn >> 4)*10 + (cuex[i].nn & 0xf); 63 | n->toc.entry[entry-1] = (cuex[i].mm << 24)|(cuex[i].lba + 150); 64 | if (entry < GET_DC_TOC_TRACK(n->toc.first)) 65 | n->toc.first = (cuex[i].mm << 24)|MAKE_DC_TOC_TRACK(entry); 66 | if (entry > GET_DC_TOC_TRACK(n->toc.last)) 67 | n->toc.last = (cuex[i].mm << 24)|MAKE_DC_TOC_TRACK(entry); 68 | n->track[entry-1].first_sector = cuex[i].lba + 150; 69 | n->track[entry-1].last_sector = cuex[i+1].lba + 150; 70 | } else { 71 | msglog_error(n->logger, "Invalid track number %x in CUEX chunk", 72 | cuex[i].nn); 73 | return false; 74 | } 75 | } 76 | } 77 | return true; 78 | } 79 | 80 | static bool nrgfile_read_daox(nrgfile n, uint32_t offs, uint32_t sz) 81 | { 82 | uint8_t daox[22+42*MAX_TRACKS]; 83 | const uint8_t *trk; 84 | int i, cnt; 85 | if (sz > sizeof(daox) || sz < 22 || ((sz - 22) % 42)) { 86 | msglog_error(n->logger, "Invalid length of DAOX chunk"); 87 | return false; 88 | } 89 | if (!datafile_read(n->data, offs, sz, daox)) 90 | return false; 91 | cnt = (sz - 22)/42; 92 | trk = daox+22; 93 | if (cnt != daox[21]-daox[20]+1) { 94 | msglog_error(n->logger, "Invalid length of DAOX chunk"); 95 | return false; 96 | } 97 | for (i=0; ilogger, "Invalid file offset in DAOX"); 110 | return false; 111 | } 112 | int entry = daox[20]+i; 113 | if (entry >= 1 && entry <= 99) { 114 | n->track[entry-1].secsize = trkdata[0]; 115 | n->track[entry-1].dataoffs = trkdata[5]; 116 | } else { 117 | msglog_error(n->logger, "Invalid track number %d in DAOX chunk", entry); 118 | return false; 119 | } 120 | trk += 42; 121 | } 122 | return true; 123 | } 124 | 125 | static bool nrgfile_read_metadata(nrgfile n, uint32_t offs) 126 | { 127 | size_t sz = datafile_size(n->data); 128 | for (;;) { 129 | uint32_t chdr[2]; 130 | if (!datafile_read(n->data, offs, sizeof(chdr), chdr)) 131 | return false; 132 | #ifndef WORDS_BIGENDIAN 133 | chdr[1] = SWAP32(chdr[1]); 134 | #endif 135 | if (chdr[0] == MKID('E','N','D','!') && chdr[1] == 0) 136 | return true; 137 | 138 | offs += 8; 139 | if (chdr[1] > sz - offs) { 140 | msglog_error(n->logger, "Corrupt NRG5 footer"); 141 | return false; 142 | } 143 | 144 | switch(chdr[0]) { 145 | case MKID('C','U','E','S'): 146 | case MKID('D','A','O','I'): 147 | msglog_error(n->logger, "CUES/DAOI chunk not supported"); 148 | return false; 149 | 150 | case MKID('C','U','E','X'): 151 | if (!nrgfile_read_cuex(n, offs, chdr[1])) 152 | return false; 153 | break; 154 | 155 | case MKID('D','A','O','X'): 156 | if (!nrgfile_read_daox(n, offs, chdr[1])) 157 | return false; 158 | break; 159 | 160 | case MKID('S','I','N','F'): 161 | case MKID('E','T','N','F'): 162 | case MKID('E','T','N','2'): 163 | case MKID('M','T','Y','P'): 164 | /* ignored */ 165 | break; 166 | 167 | case MKID('E','N','D','!'): 168 | msglog_error(n->logger, "Broken END! chunk found"); 169 | return false; 170 | 171 | default: 172 | msglog_error(n->logger, "Unexpected NRG chunk \"%.4s\"", 173 | (const char *)&chdr[0]); 174 | return false; 175 | } 176 | 177 | offs += chdr[1]; 178 | } 179 | } 180 | 181 | static uint32_t nrgfile_low_check(msglogger logger, datafile data, bool complain) 182 | { 183 | uint32_t n5[3]; 184 | size_t sz = datafile_size(data); 185 | if (sz < 12) { 186 | if (complain) 187 | msglog_error(logger, "NRG file too short"); 188 | return 0; 189 | } 190 | if (!datafile_read(data, sz-12, sizeof(n5), n5)) 191 | return 0; 192 | if (memcmp(n5, "NER5", 4)) { 193 | if (complain) 194 | msglog_error(logger, "Not a NRG5 file"); 195 | return 0; 196 | } 197 | #ifndef WORDS_BIGENDIAN 198 | n5[2] = SWAP32(n5[2]); 199 | #endif 200 | if (n5[1] || !n5[2] || n5[2] >= sz-12) { 201 | if (complain) 202 | msglog_error(logger, "Invalid NRG5 footer"); 203 | return 0; 204 | } 205 | return n5[2]; 206 | } 207 | 208 | static bool nrgfile_find_track(nrgfile n, uint32_t sector) 209 | { 210 | int i; 211 | for(i=0; i<99; i++) 212 | if(n->track[i].secsize && n->track[i].first_sector <= sector && 213 | n->track[i].last_sector > sector) { 214 | uint32_t secskip; 215 | switch(n->track[i].secsize) { 216 | case 2048: 217 | secskip = 0; 218 | break; 219 | case 2056: 220 | case 2336: 221 | secskip = 8; 222 | break; 223 | default: 224 | msglog_warning(n->logger, "Attempt to read from track with " 225 | "unsupported sector size (%d)", n->track[i].secsize); 226 | return false; 227 | } 228 | n->current_track = n->track[i]; 229 | n->current_track.secskip = secskip; 230 | return true; 231 | } 232 | return false; 233 | } 234 | 235 | void nrgfile_delete(nrgfile n) 236 | { 237 | if (n) { 238 | free(n); 239 | } 240 | } 241 | 242 | nrgfile nrgfile_new(msglogger logger, datafile data) 243 | { 244 | nrgfile n = calloc(1, sizeof(struct nrgfile_s)); 245 | uint32_t metadata; 246 | if (n) { 247 | n->logger = logger; 248 | n->data = data; 249 | memset(&n->toc, 0, sizeof(n->toc)); 250 | n->toc.first = MAKE_DC_TOC_TRACK(0xaa); 251 | memset(n->track, 0, sizeof(n->track)); 252 | memset(&n->current_track, 0, sizeof(n->current_track)); 253 | if ((metadata = nrgfile_low_check(n->logger, n->data, true))) { 254 | if (nrgfile_read_metadata(n, metadata)) 255 | return n; 256 | } 257 | nrgfile_delete(n); 258 | } else 259 | msglog_oomerror(logger); 260 | return NULL; 261 | } 262 | 263 | bool nrgfile_check(msglogger logger, datafile data) 264 | { 265 | return nrgfile_low_check(logger, data, false) != 0; 266 | } 267 | 268 | bool nrgfile_read_sector(nrgfile n, uint32_t sector, uint8_t *buffer) 269 | { 270 | if (sector < n->current_track.first_sector || 271 | sector >= n->current_track.last_sector) { 272 | if (!nrgfile_find_track(n, sector)) 273 | return false; 274 | } 275 | return datafile_read(n->data, n->current_track.dataoffs + 276 | (sector - n->current_track.first_sector) * 277 | n->current_track.secsize + 278 | n->current_track.secskip, 2048, buffer); 279 | } 280 | 281 | bool nrgfile_get_toc(nrgfile n, int session, dc_toc *toc) 282 | { 283 | if (session == 0) { 284 | *toc = n->toc; 285 | return true; 286 | } else 287 | return false; 288 | } 289 | -------------------------------------------------------------------------------- /src/host/datasource/nrgfile.h: -------------------------------------------------------------------------------- 1 | typedef struct nrgfile_s *nrgfile; 2 | extern void nrgfile_delete(nrgfile n); 3 | extern nrgfile nrgfile_new(msglogger logger, datafile data); 4 | extern bool nrgfile_check(msglogger logger, datafile data); 5 | extern bool nrgfile_read_sector(nrgfile n, uint32_t sector, uint8_t *buffer); 6 | extern bool nrgfile_get_toc(nrgfile n, int session, dc_toc *toc); 7 | 8 | -------------------------------------------------------------------------------- /src/host/network/Makefile.in: -------------------------------------------------------------------------------- 1 | CC = @CC@ 2 | AR = @AR@ 3 | CFLAGS = @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)/common 4 | 5 | top_srcdir=@top_srcdir@ 6 | top_builddir=@top_builddir@ 7 | srcdir=@srcdir@ 8 | VPATH=@srcdir@ 9 | 10 | OBJS = serverport.o 11 | 12 | LIBTARGET = libnetwork.a 13 | 14 | all : $(LIBTARGET) 15 | 16 | clean : 17 | -rm -f $(LIBTARGET) $(OBJS) 18 | 19 | $(LIBTARGET) : $(OBJS) 20 | $(AR) rc $@ $(OBJS) 21 | 22 | serverport.o : serverport.c serverport.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/bswap.h 23 | 24 | -------------------------------------------------------------------------------- /src/host/network/serverport.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "msglog.h" 14 | #include "serverport.h" 15 | #include "bswap.h" 16 | 17 | #define CLIENT_PORT 4781 18 | #define SERVER_PORT 4782 19 | 20 | #define MAX_PKT 8 21 | #define MAX_EXTRA 1280 /* Should be less than MTU-28 */ 22 | 23 | typedef clientcontext level4_index[256]; 24 | typedef level4_index *level3_index[256]; 25 | typedef level3_index *level2_index[256]; 26 | typedef level2_index *level1_index[256]; 27 | 28 | struct serverport_s { 29 | msglogger logger; 30 | serverfuncs funcs; 31 | void *ctx; 32 | int sockfd; 33 | level1_index clients; 34 | uint8_t extra_buffer[MAX_EXTRA]; 35 | }; 36 | 37 | struct extra_response { 38 | void *buffer; 39 | size_t size; 40 | }; 41 | 42 | static void clientcontext_delete(serverport s, clientcontext c) 43 | { 44 | (*s->funcs->clientcontext_delete)(s->ctx, c); 45 | } 46 | 47 | static clientcontext clientcontext_new(serverport s, struct in_addr in) 48 | { 49 | clientcontext c = (*s->funcs->clientcontext_new)(s->ctx); 50 | if (c) { 51 | ((struct clientcontext_base_s *)c)->client_addr = in.s_addr; 52 | return c; 53 | } 54 | return NULL; 55 | } 56 | 57 | static clientcontext serverport_get_clientcontext_for_address(serverport s, 58 | struct in_addr in) 59 | { 60 | clientcontext c; 61 | level2_index *l2; 62 | level3_index *l3; 63 | level4_index *l4; 64 | uint32_t a = ntohl(in.s_addr); 65 | uint8_t a1 = a >> 24; 66 | uint8_t a2 = a >> 16; 67 | uint8_t a3 = a >> 8; 68 | uint8_t a4 = a; 69 | 70 | l2 = s->clients[a1]; 71 | if (l2 == NULL) { 72 | int i; 73 | msglog_debug(s->logger, "Creating new level 2 index for prefix %d", a1); 74 | l2 = calloc(1, sizeof(level2_index)); 75 | if (l2 == NULL) { 76 | msglog_oomerror(s->logger); 77 | return NULL; 78 | } 79 | for (i=0; i<256; i++) 80 | (*l2)[i] = NULL; 81 | s->clients[a1] = l2; 82 | } 83 | l3 = (*l2)[a2]; 84 | if (l3 == NULL) { 85 | int i; 86 | msglog_debug(s->logger, "Creating new level 3 index for prefix %d.%d", a1, a2); 87 | l3 = calloc(1, sizeof(level3_index)); 88 | if (l3 == NULL) { 89 | msglog_oomerror(s->logger); 90 | return NULL; 91 | } 92 | for (i=0; i<256; i++) 93 | (*l3)[i] = NULL; 94 | (*l2)[a2] = l3; 95 | } 96 | l4 = (*l3)[a3]; 97 | if (l4 == NULL) { 98 | int i; 99 | msglog_debug(s->logger, "Creating new level 4 index for prefix %d.%d.%d", a1, a2, a3); 100 | l4 = calloc(1, sizeof(level4_index)); 101 | if (l4 == NULL) { 102 | msglog_oomerror(s->logger); 103 | return NULL; 104 | } 105 | for (i=0; i<256; i++) 106 | (*l4)[i] = NULL; 107 | (*l3)[a3] = l4; 108 | } 109 | c = (*l4)[a4]; 110 | if (c == NULL) { 111 | msglog_debug(s->logger, "Creating new client context for %d.%d.%d.%d", a1, a2, a3, a4); 112 | (*l4)[a4] = c = clientcontext_new(s, in); 113 | } 114 | return c; 115 | } 116 | 117 | serverport serverport_new(msglogger logger, serverfuncs funcs, void *ctx) 118 | { 119 | serverport s = calloc(1, sizeof(struct serverport_s)); 120 | if (s) { 121 | int i; 122 | s->logger = logger; 123 | s->funcs = funcs; 124 | s->ctx = ctx; 125 | for (i=0; i<256; i++) 126 | s->clients[i] = NULL; 127 | if ((s->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { 128 | struct sockaddr_in addr; 129 | memset(&addr, 0, sizeof(addr)); 130 | addr.sin_family = AF_INET; 131 | addr.sin_port = htons(SERVER_PORT); 132 | addr.sin_addr.s_addr = INADDR_ANY; 133 | if (bind(s->sockfd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { 134 | return s; 135 | } else 136 | msglog_perror(logger, "bind"); 137 | } else 138 | msglog_perror(logger, "socket"); 139 | serverport_delete(s); 140 | } else 141 | msglog_oomerror(logger); 142 | return NULL; 143 | } 144 | 145 | void serverport_delete(serverport s) 146 | { 147 | if (s) { 148 | int i, j, k, l; 149 | if (s->sockfd >= 0) 150 | close(s->sockfd); 151 | for (i=0; i<256; i++) { 152 | level2_index *l2 = s->clients[i]; 153 | if (l2 != NULL) { 154 | for (j=0; j<256; j++) { 155 | level3_index *l3 = (*l2)[j]; 156 | if (l3 != NULL) { 157 | for (k=0; k<256; k++) { 158 | level4_index *l4 = (*l3)[k]; 159 | if (l4 != NULL) { 160 | for (l=0; l<256; l++) { 161 | clientcontext c = (*l4)[l]; 162 | if (c != NULL) 163 | clientcontext_delete(s, c); 164 | } 165 | free(l4); 166 | } 167 | } 168 | free(l3); 169 | } 170 | } 171 | free(l2); 172 | } 173 | } 174 | free(s); 175 | } 176 | } 177 | 178 | bool serverport_add_extra(serverport s, struct extra_response *extra, const void *data, size_t len) 179 | { 180 | if (!len) 181 | return true; 182 | size_t old = extra->size; 183 | if (!old) 184 | old = 3*sizeof(int32_t); 185 | if (len > MAX_EXTRA - old) { 186 | msglog_error(s->logger, "Overfull extra"); 187 | return false; 188 | } 189 | if (extra->buffer == NULL) 190 | extra->buffer = s->extra_buffer; 191 | memcpy(((uint8_t *)extra->buffer) + old, data, len); 192 | extra->size = old+len; 193 | return true; 194 | } 195 | 196 | void serverport_run_once(serverport s) 197 | { 198 | ssize_t size; 199 | int32_t pkt[MAX_PKT]; 200 | struct sockaddr_in src_addr; 201 | socklen_t addrlen = sizeof(src_addr); 202 | size = recvfrom(s->sockfd, pkt, sizeof(pkt), 0, 203 | (struct sockaddr *)&src_addr, &addrlen); 204 | if (size<0) { 205 | msglog_perror(s->logger, "recvfrom"); 206 | return; 207 | } 208 | if (size<12 || size>MAX_PKT*4 || (size&3)!=0) { 209 | msglog_warning(s->logger, "Invalid packet length"); 210 | return; 211 | } 212 | size /= sizeof(int32_t); 213 | #ifdef SERVERPORT_PACKET_TRACE 214 | msglog_debug(s->logger, "Got a message from %s:%d, %d values", 215 | inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port), size); 216 | #endif 217 | clientcontext c = serverport_get_clientcontext_for_address(s, src_addr.sin_addr); 218 | if (c == NULL) 219 | return; 220 | int i; 221 | int32_t rc; 222 | #ifdef WORDS_BIGENDIAN 223 | for (i=2; ifuncs->handle_packet)(s->ctx, c, pkt+2, size-2, &extra); 228 | if (rc != -1) { 229 | #ifdef WORDS_BIGENDIAN 230 | pkt[2] = SWAP32(rc); 231 | #else 232 | pkt[2] = rc; 233 | #endif 234 | if (extra.buffer) { 235 | memcpy(extra.buffer, pkt, 3*sizeof(int32_t)); 236 | size = sendto(s->sockfd, extra.buffer, extra.size, 0, 237 | (struct sockaddr *)&src_addr, addrlen); 238 | } else 239 | size = sendto(s->sockfd, pkt, 3*sizeof(int32_t), 0, 240 | (struct sockaddr *)&src_addr, addrlen); 241 | if (size<0) 242 | msglog_perror(s->logger, "sendto"); 243 | } 244 | } 245 | 246 | void serverport_run(serverport s) 247 | { 248 | for(;;) { 249 | serverport_run_once(s); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/host/network/serverport.h: -------------------------------------------------------------------------------- 1 | typedef struct serverport_s *serverport; 2 | typedef struct clientcontext_s *clientcontext; 3 | struct extra_response; 4 | struct clientcontext_base_s { 5 | uint32_t client_addr; 6 | }; 7 | typedef struct serverfuncs_s { 8 | clientcontext (*clientcontext_new)(void *ctx); 9 | void (*clientcontext_delete)(void *ctx, clientcontext client); 10 | int32_t (*handle_packet)(void *ctx, clientcontext client, const int32_t *pkt, int cnt, struct extra_response *extra); 11 | } *serverfuncs; 12 | extern serverport serverport_new(msglogger logger, serverfuncs funcs, void *ctx); 13 | extern void serverport_delete(serverport s); 14 | extern void serverport_run_once(serverport s); 15 | extern void serverport_run(serverport s); 16 | extern bool serverport_add_extra(serverport s, struct extra_response *extra, const void *data, size_t len); 17 | -------------------------------------------------------------------------------- /src/host/server/Makefile.in: -------------------------------------------------------------------------------- 1 | CC = @CC@ 2 | AR = @AR@ 3 | CFLAGS = @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)/common \ 4 | -I$(top_srcdir)/network -I$(top_srcdir)/datasource 5 | 6 | top_srcdir=@top_srcdir@ 7 | top_builddir=@top_builddir@ 8 | srcdir=@srcdir@ 9 | VPATH=@srcdir@ 10 | 11 | OBJS = server.o 12 | 13 | LIBTARGET = libserver.a 14 | 15 | all : $(LIBTARGET) 16 | 17 | clean : 18 | -rm -f $(LIBTARGET) $(OBJS) 19 | 20 | $(LIBTARGET) : $(OBJS) 21 | $(AR) rc $@ $(OBJS) 22 | 23 | server.o : server.c server.h $(top_builddir)/config.h $(top_srcdir)/common/msglog.h $(top_srcdir)/common/toc.h $(top_srcdir)/common/bswap.h $(top_srcdir)/network/serverport.h $(top_srcdir)/datasource/datasource.h $(top_srcdir)/datasource/jukebox.h 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/host/server/server.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "msglog.h" 9 | #include "toc.h" 10 | #include "datasource.h" 11 | #include "jukebox.h" 12 | #include "server.h" 13 | #include "serverport.h" 14 | #include "bswap.h" 15 | 16 | #define DOWNLOAD_AREA_START 0x8c008000 17 | #define DOWNLOAD_AREA_END 0x8cf10000 18 | #define DOWNLOAD_MAIN_START 0x8c010000 19 | 20 | struct clientcontext_s { 21 | struct clientcontext_base_s base; 22 | datasource dsource; 23 | }; 24 | 25 | struct server_s { 26 | msglogger logger; 27 | jukebox jbox; 28 | serverport port; 29 | }; 30 | 31 | static void clientcontext_delete(void *ctx, clientcontext client) 32 | { 33 | if (client) { 34 | if (client->dsource) 35 | datasource_unrealize(client->dsource); 36 | free(client); 37 | } 38 | } 39 | 40 | static clientcontext clientcontext_new(void *ctx) 41 | { 42 | server s = ctx; 43 | clientcontext c = calloc(1, sizeof(struct clientcontext_s)); 44 | if (c) { 45 | return c; 46 | } else 47 | msglog_oomerror(s->logger); 48 | return NULL; 49 | } 50 | 51 | static bool clientcontext_set_datasource(clientcontext client, datasource ds) 52 | { 53 | if (ds == client->dsource) 54 | return true; 55 | if (client->dsource) { 56 | datasource_unrealize(client->dsource); 57 | client->dsource = NULL; 58 | } 59 | if (ds && !datasource_realize(ds)) 60 | return false; 61 | client->dsource = ds; 62 | return true; 63 | } 64 | 65 | static int32_t gderror(server s, struct extra_response *extra, int32_t e) 66 | { 67 | uint8_t err[] = { 1, e&0xff, (e>>8)&0xff, (e>>16)&0xff, (e>>24)&0xff, 68 | 0, 0, 0, 0, 69 | 0, 0, 0, 0, 70 | 0, 0, 0, 0 }; 71 | if(!serverport_add_extra(s->port, extra, err, 17)) 72 | return -4; 73 | return -2; 74 | } 75 | 76 | static bool write_data(server s, struct extra_response *extra, 77 | const void *data, size_t len, uint32_t addr) 78 | { 79 | uint8_t header[6] = { 80 | (len>>8)|0xd0, len&0xff, 81 | addr&0xff, (addr>>8)&0xff, (addr>>16)&0xff, addr>>24 82 | }; 83 | if (!len) 84 | return true; 85 | return serverport_add_extra(s->port, extra, header, 6) && 86 | serverport_add_extra(s->port, extra, data, len); 87 | } 88 | 89 | static int32_t select_binary(server s, clientcontext client, uint32_t id) 90 | { 91 | int32_t r; 92 | datasource ds = jukebox_get_datasource(s->jbox, id); 93 | if (!clientcontext_set_datasource(client, ds) || 94 | ds == NULL) 95 | return -2; 96 | r = datasource_get_1st_read_size(ds); 97 | return (r<0? -2 : r); 98 | } 99 | 100 | static int32_t low_download(server s, clientcontext client, 101 | struct extra_response *extra, 102 | uint32_t addr, uint32_t cnt) 103 | { 104 | uint8_t buf[2048]; 105 | if (addr < DOWNLOAD_MAIN_START) { 106 | uint32_t offs = addr & 0x7fff; 107 | if (!datasource_get_ipbin(client->dsource, offs>>11, buf) || 108 | !write_data(s, extra, buf+(offs&2047), cnt, addr)) 109 | return -4; 110 | else 111 | return 0; 112 | } else { 113 | uint32_t offs = addr - DOWNLOAD_MAIN_START; 114 | int32_t len = datasource_get_1st_read_size(client->dsource); 115 | if (len < 0 || offs + cnt > (uint32_t)len) { 116 | msglog_error(s->logger, "Download after end of binary..."); 117 | return -3; 118 | } 119 | if (!datasource_get_1st_read(client->dsource, offs>>11, buf) || 120 | !write_data(s, extra, buf+(offs&2047), cnt, addr)) 121 | return -4; 122 | else 123 | return 0; 124 | } 125 | } 126 | 127 | static int32_t download(server s, clientcontext client, 128 | struct extra_response *extra, 129 | uint32_t addr, uint32_t cnt) 130 | { 131 | if (client->dsource == NULL) { 132 | msglog_error(s->logger, "Download request without a datasource"); 133 | return -2; 134 | } 135 | if (addr < DOWNLOAD_AREA_START || addr > DOWNLOAD_AREA_END || 136 | cnt > DOWNLOAD_AREA_END - addr) { 137 | msglog_error(s->logger, "Download request outside allowed area"); 138 | return -2; 139 | } 140 | if (!cnt) 141 | return 0; 142 | while (((addr + cnt - 1)&~2047) != (addr&~2047)) { 143 | uint32_t chunk = (addr|2047)+1-addr; 144 | int32_t r = low_download(s, client, extra, addr, chunk); 145 | if (r) 146 | return r; 147 | addr += chunk; 148 | cnt -= chunk; 149 | } 150 | return low_download(s, client, extra, addr, cnt); 151 | } 152 | 153 | static int32_t read_data(server s, clientcontext client, 154 | struct extra_response *extra, uint16_t phase, 155 | uint32_t sec, int32_t cnt, uint32_t addr) 156 | { 157 | uint8_t buf[2048]; 158 | if (client->dsource == NULL) { 159 | msglog_error(s->logger, "Read request without a datasource"); 160 | return -2; 161 | } 162 | if (cnt <= 0) 163 | return gderror(s, extra, 15); 164 | sec += phase>>1; 165 | if (!datasource_read_sector(client->dsource, sec, buf)) 166 | return gderror(s, extra, 15); 167 | if (!write_data(s, extra, ((phase&1)? buf+1024 : buf), 1024, 168 | addr+(phase<<10))) 169 | return -4; 170 | 171 | if(++phase == (cnt<<1)) { 172 | uint32_t sz = cnt<<11; 173 | uint8_t err[] = { 1, 0, 0, 0, 0, 174 | 0, 0, 0, 0, 175 | sz&0xff, (sz>>8)&0xff, (sz>>16)&0xff, (sz>>24)&0xff, 176 | 0, 0, 0, 0 }; 177 | if(!serverport_add_extra(s->port, extra, err, 17)) 178 | return -4; 179 | return 0; 180 | } else 181 | return phase<<16; 182 | } 183 | 184 | static int32_t read_toc(server s, clientcontext client, 185 | struct extra_response *extra, 186 | int session, uint32_t addr) 187 | { 188 | dc_toc toc; 189 | if (client->dsource == NULL) { 190 | msglog_error(s->logger, "TOC request without a datasource"); 191 | return -2; 192 | } 193 | if (!datasource_get_toc(client->dsource, session, &toc)) 194 | return gderror(s, extra, 15); 195 | #ifdef WORDS_BIGENDIAN 196 | int i; 197 | for(i=0; i<102; i++) 198 | toc.entry[i] = SWAP32(toc.entry[i]); 199 | #endif 200 | if (!write_data(s, extra, &toc, sizeof(toc), addr)) 201 | return -4; 202 | return 0; 203 | } 204 | 205 | static int32_t get_driver_version(server s, struct extra_response *extra, 206 | uint32_t addr) 207 | { 208 | return (write_data(s, extra, "GDC Version 1.10 1999-03-31\2", 28, addr)? 209 | 0 : -4); 210 | } 211 | 212 | static int32_t handle_packet(void *ctx, clientcontext client, const int32_t *pkt, int cnt, struct extra_response *extra) 213 | { 214 | server s = ctx; 215 | int i; 216 | 217 | if (cnt > 0) { 218 | uint16_t cmd = (uint16_t)pkt[0]; 219 | if (cmd < 48) { 220 | /* gdrom command */ 221 | switch(cmd) { 222 | case 16: /* cpu read */ 223 | case 17: /* dma read */ 224 | return read_data(s, client, extra, (uint16_t)(pkt[0]>>16), 225 | (cnt > 1? (uint32_t)pkt[1] : 0), 226 | (cnt > 2? pkt[2] : 0), 227 | (cnt > 3? (uint32_t)pkt[3] : 0)); 228 | 229 | case 19: /* read toc */ 230 | return read_toc(s, client, extra, 231 | (cnt > 1? (uint32_t)pkt[1] : 0), 232 | (cnt > 2? (uint32_t)pkt[2] : 0)); 233 | 234 | case 24: /* init drive */ 235 | return 0; 236 | 237 | case 40: /* get driver version */ 238 | return get_driver_version(s, extra, (cnt > 1? (uint32_t)pkt[1] : 0)); 239 | 240 | default: 241 | return gderror(s, extra, 32); 242 | } 243 | } else if(cmd >= 990) { 244 | /* monitor command */ 245 | switch(cmd-990) { 246 | case 0: 247 | case 1: 248 | return 0; 249 | case 7: 250 | return download(s, client, extra, 251 | (cnt > 1? (uint32_t)pkt[1] : 0), 252 | (cnt > 2? (uint32_t)pkt[2] : 0)); 253 | break; 254 | case 8: 255 | return select_binary(s, client, (cnt > 1? (uint32_t)pkt[1] : 0)); 256 | case 9: 257 | return 0; 258 | } 259 | } else if(cmd >= 800 && cmd < 816) { 260 | /* unimplemented syscall */ 261 | return -2; 262 | } else if(cmd >= 500 && cmd < 700) { 263 | /* status feedback */ 264 | return -2; 265 | } 266 | } 267 | 268 | return -1; 269 | } 270 | 271 | static struct serverfuncs_s funcs = { 272 | clientcontext_new, 273 | clientcontext_delete, 274 | handle_packet 275 | }; 276 | 277 | void server_delete(server s) 278 | { 279 | if (s) { 280 | serverport_delete(s->port); 281 | free(s); 282 | } 283 | } 284 | 285 | server server_new(msglogger logger, jukebox jbox) 286 | { 287 | server s = calloc(1, sizeof(struct server_s)); 288 | if (s) { 289 | s->logger = logger; 290 | s->jbox = jbox; 291 | if ((s->port = serverport_new(logger, &funcs, s)) != NULL) { 292 | return s; 293 | } 294 | server_delete(s); 295 | } else 296 | msglog_oomerror(logger); 297 | return NULL; 298 | } 299 | 300 | void server_run_once(server s) 301 | { 302 | serverport_run_once(s->port); 303 | } 304 | 305 | void server_run(server s) 306 | { 307 | serverport_run(s->port); 308 | } 309 | -------------------------------------------------------------------------------- /src/host/server/server.h: -------------------------------------------------------------------------------- 1 | typedef struct server_s *server; 2 | extern void server_delete(server s); 3 | extern server server_new(msglogger logger, jukebox jbox); 4 | extern void server_run_once(server s); 5 | extern void server_run(server s); 6 | 7 | -------------------------------------------------------------------------------- /src/install-sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # This comes from X11R5. 5 | # 6 | # Calling this script install-sh is preferred over install.sh, to prevent 7 | # `make' implicit rules from creating a file called install from it 8 | # when there is no Makefile. 9 | # 10 | # This script is compatible with the BSD install script, but was written 11 | # from scratch. 12 | # 13 | 14 | 15 | # set DOITPROG to echo to test this script 16 | 17 | # Don't use :- since 4.3BSD and earlier shells don't like it. 18 | doit="${DOITPROG-}" 19 | 20 | 21 | # put in absolute paths if you don't have them in your path; or use env. vars. 22 | 23 | mvprog="${MVPROG-mv}" 24 | cpprog="${CPPROG-cp}" 25 | chmodprog="${CHMODPROG-chmod}" 26 | chownprog="${CHOWNPROG-chown}" 27 | chgrpprog="${CHGRPPROG-chgrp}" 28 | stripprog="${STRIPPROG-strip}" 29 | rmprog="${RMPROG-rm}" 30 | mkdirprog="${MKDIRPROG-mkdir}" 31 | 32 | transformbasename="" 33 | transform_arg="" 34 | instcmd="$mvprog" 35 | chmodcmd="$chmodprog 0755" 36 | chowncmd="" 37 | chgrpcmd="" 38 | stripcmd="" 39 | rmcmd="$rmprog -f" 40 | mvcmd="$mvprog" 41 | src="" 42 | dst="" 43 | dir_arg="" 44 | 45 | while [ x"$1" != x ]; do 46 | case $1 in 47 | -c) instcmd="$cpprog" 48 | shift 49 | continue;; 50 | 51 | -d) dir_arg=true 52 | shift 53 | continue;; 54 | 55 | -m) chmodcmd="$chmodprog $2" 56 | shift 57 | shift 58 | continue;; 59 | 60 | -o) chowncmd="$chownprog $2" 61 | shift 62 | shift 63 | continue;; 64 | 65 | -g) chgrpcmd="$chgrpprog $2" 66 | shift 67 | shift 68 | continue;; 69 | 70 | -s) stripcmd="$stripprog" 71 | shift 72 | continue;; 73 | 74 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 75 | shift 76 | continue;; 77 | 78 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 79 | shift 80 | continue;; 81 | 82 | *) if [ x"$src" = x ] 83 | then 84 | src=$1 85 | else 86 | # this colon is to work around a 386BSD /bin/sh bug 87 | : 88 | dst=$1 89 | fi 90 | shift 91 | continue;; 92 | esac 93 | done 94 | 95 | if [ x"$src" = x ] 96 | then 97 | echo "install: no input file specified" 98 | exit 1 99 | else 100 | true 101 | fi 102 | 103 | if [ x"$dir_arg" != x ]; then 104 | dst=$src 105 | src="" 106 | 107 | if [ -d $dst ]; then 108 | instcmd=: 109 | else 110 | instcmd=mkdir 111 | fi 112 | else 113 | 114 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 115 | # might cause directories to be created, which would be especially bad 116 | # if $src (and thus $dsttmp) contains '*'. 117 | 118 | if [ -f $src -o -d $src ] 119 | then 120 | true 121 | else 122 | echo "install: $src does not exist" 123 | exit 1 124 | fi 125 | 126 | if [ x"$dst" = x ] 127 | then 128 | echo "install: no destination specified" 129 | exit 1 130 | else 131 | true 132 | fi 133 | 134 | # If destination is a directory, append the input filename; if your system 135 | # does not like double slashes in filenames, you may need to add some logic 136 | 137 | if [ -d $dst ] 138 | then 139 | dst="$dst"/`basename $src` 140 | else 141 | true 142 | fi 143 | fi 144 | 145 | ## this sed command emulates the dirname command 146 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 147 | 148 | # Make sure that the destination directory exists. 149 | # this part is taken from Noah Friedman's mkinstalldirs script 150 | 151 | # Skip lots of stat calls in the usual case. 152 | if [ ! -d "$dstdir" ]; then 153 | defaultIFS=' 154 | ' 155 | IFS="${IFS-${defaultIFS}}" 156 | 157 | oIFS="${IFS}" 158 | # Some sh's can't handle IFS=/ for some reason. 159 | IFS='%' 160 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 161 | IFS="${oIFS}" 162 | 163 | pathcomp='' 164 | 165 | while [ $# -ne 0 ] ; do 166 | pathcomp="${pathcomp}${1}" 167 | shift 168 | 169 | if [ ! -d "${pathcomp}" ] ; 170 | then 171 | $mkdirprog "${pathcomp}" 172 | else 173 | true 174 | fi 175 | 176 | pathcomp="${pathcomp}/" 177 | done 178 | fi 179 | 180 | if [ x"$dir_arg" != x ] 181 | then 182 | $doit $instcmd $dst && 183 | 184 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && 185 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && 186 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && 187 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi 188 | else 189 | 190 | # If we're going to rename the final executable, determine the name now. 191 | 192 | if [ x"$transformarg" = x ] 193 | then 194 | dstfile=`basename $dst` 195 | else 196 | dstfile=`basename $dst $transformbasename | 197 | sed $transformarg`$transformbasename 198 | fi 199 | 200 | # don't allow the sed command to completely eliminate the filename 201 | 202 | if [ x"$dstfile" = x ] 203 | then 204 | dstfile=`basename $dst` 205 | else 206 | true 207 | fi 208 | 209 | # Make a temp file name in the proper directory. 210 | 211 | dsttmp=$dstdir/#inst.$$# 212 | 213 | # Move or copy the file name to the temp name 214 | 215 | $doit $instcmd $src $dsttmp && 216 | 217 | trap "rm -f ${dsttmp}" 0 && 218 | 219 | # and set any options; do chmod last to preserve setuid bits 220 | 221 | # If any of these fail, we abort the whole thing. If we want to 222 | # ignore errors from any of these, just make sure not to ignore 223 | # errors from the above "$doit $instcmd $src $dsttmp" command. 224 | 225 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && 226 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && 227 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && 228 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && 229 | 230 | # Now rename the file to the real destination. 231 | 232 | $doit $rmcmd -f $dstdir/$dstfile && 233 | $doit $mvcmd $dsttmp $dstdir/$dstfile 234 | 235 | fi && 236 | 237 | 238 | exit 0 239 | 240 | -------------------------------------------------------------------------------- /src/target/Makefile.in: -------------------------------------------------------------------------------- 1 | AS = @DCAS@ 2 | LD = @DCLD@ 3 | CC = @DCCC@ 4 | AR = @DCAR@ 5 | CFLAGS = @DCCFLAGS@ 6 | 7 | top_srcdir=@top_srcdir@ 8 | srcdir=@srcdir@ 9 | VPATH=@srcdir@ 10 | 11 | all clean : 12 | cd common && make $@ 13 | cd network && make $@ 14 | cd skel && make $@ 15 | cd launcher && make $@ 16 | make local-$@ 17 | 18 | local-all : 19 | 20 | local-clean : 21 | 22 | install : 23 | 24 | Makefile common/Makefile network/Makefile skel/Makefile launcher/Makefile: Makefile.in common/Makefile.in network/Makefile.in skel/Makefile.in launcher/Makefile.in config.status 25 | ./config.status 26 | 27 | config.status : configure 28 | ./config.status --recheck 29 | 30 | configure : configure.ac 31 | cd $(srcdir) && autoconf 32 | 33 | -------------------------------------------------------------------------------- /src/target/common/Makefile.in: -------------------------------------------------------------------------------- 1 | AS = @DCAS@ 2 | LD = @DCLD@ 3 | CC = @DCCC@ 4 | AR = @DCAR@ 5 | CFLAGS = @DCCFLAGS@ 6 | 7 | top_srcdir=@top_srcdir@ 8 | srcdir=@srcdir@ 9 | VPATH=@srcdir@ 10 | 11 | OBJS = proto.o util1.o 12 | 13 | LIBTARGET = libcommon.a 14 | 15 | all : $(LIBTARGET) 16 | 17 | clean : 18 | -rm -f $(LIBTARGET) $(OBJS) 19 | 20 | $(LIBTARGET) : $(OBJS) 21 | $(AR) rc $@ $(OBJS) 22 | 23 | proto.o : proto.c proto.h util.h 24 | 25 | util1.o : util1.c util.h 26 | 27 | -------------------------------------------------------------------------------- /src/target/common/proto.c: -------------------------------------------------------------------------------- 1 | #include "proto.h" 2 | #include "util.h" 3 | 4 | static int target_ip=-1; 5 | static unsigned char target_hw[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 6 | static int server_detected=0; 7 | 8 | static int seq_id = 1001; 9 | 10 | int num_commands = 0, num_resends = 0; 11 | 12 | #define NUM_SLOTS 8 13 | #define MAX_PKT 8 14 | 15 | #define RESEND_TIME 4 16 | #define RESEND_COUNT 100 17 | 18 | static int slots[NUM_SLOTS][MAX_PKT]; 19 | static int resend_time[NUM_SLOTS]; 20 | static int resend_count[NUM_SLOTS]; 21 | static int pkt_size[NUM_SLOTS]; 22 | 23 | int get_server_ip(unsigned int *addr) 24 | { 25 | *addr = target_ip; 26 | return server_detected; 27 | } 28 | 29 | int get_server_mac(unsigned char *mac) 30 | { 31 | memcpy(mac, target_hw, 6); 32 | return server_detected; 33 | } 34 | 35 | static char *extra_addr; 36 | 37 | static void handle_extra(unsigned char *src, int sz, void *ret) 38 | { 39 | int c, n; 40 | while(sz-->0) 41 | if((c = *src++) & 0x80) { 42 | n = c&0xf; 43 | if(c & 0x10) { 44 | if(--sz<0) return; 45 | n = (n<<8) | *src++; 46 | } 47 | if(c & 0x40) { 48 | if((sz-=4)<0) return; 49 | ((unsigned char *)&extra_addr)[0] = *src++; 50 | ((unsigned char *)&extra_addr)[1] = *src++; 51 | ((unsigned char *)&extra_addr)[2] = *src++; 52 | ((unsigned char *)&extra_addr)[3] = *src++; 53 | } 54 | if(c & 0x20) { 55 | if(--sz<0) return; 56 | memset(extra_addr, *src++, n); 57 | extra_addr += n; 58 | } else { 59 | if((sz -= n) < 0) return; 60 | if((n&3) || (((long)extra_addr)&3)) { 61 | memcpy(extra_addr, src, n); 62 | src += n; 63 | extra_addr += n; 64 | } else { 65 | n>>=2; 66 | while(n--) { 67 | int a = *src++; 68 | a |= (*src++)<<8; 69 | a |= (*src++)<<16; 70 | a |= (*src++)<<24; 71 | *(int *)extra_addr = a; 72 | extra_addr += 4; 73 | } 74 | } 75 | } 76 | } else if(c==1) { 77 | if(sz<16) return; 78 | sz-=16; 79 | memcpy(ret, src, 16); 80 | src += 16; 81 | } 82 | } 83 | 84 | void set_server(void *ip, void *mac) 85 | { 86 | memcpy(&target_ip, ip, 4); 87 | memcpy(target_hw, mac, 6); 88 | } 89 | 90 | void proto_got_packet(void *pkt, int sz, void *ip_pkt) 91 | { 92 | int phase, n, p[3]; 93 | if(sz < 12) 94 | return; 95 | memcpy(p, pkt, 12); 96 | n = p[1]; 97 | if(n<0 || n>=NUM_SLOTS || p[0]<=0 || p[0] != slots[n][0]) 98 | return; 99 | if(!server_detected) { 100 | set_server(((unsigned char *)ip_pkt)+12, ((unsigned char *)ip_pkt)-8); 101 | server_detected = 1; 102 | } 103 | if(p[2]>=0 && (phase=p[2]&~0xffff) && (slots[n][2] & 0xffff)<100) { 104 | slots[n][2] = (slots[n][2] & 0xffff) | phase; 105 | resend_time[n] = RESEND_TIME; 106 | resend_count[n] = RESEND_COUNT; 107 | udp_send_packet(target_hw, target_ip, CLIENT_PORT, SERVER_PORT, 108 | slots[n], pkt_size[n]); 109 | num_commands ++; 110 | } else { 111 | slots[n][0] = -1; 112 | slots[n][2] = p[2]; 113 | bzero(&slots[n][3], 16); 114 | } 115 | if(sz > 12) 116 | handle_extra(((unsigned char *)pkt)+12, sz-12, &slots[n][3]); 117 | } 118 | 119 | void background_process() 120 | { 121 | int i; 122 | ether_check_events(); 123 | for(i=0; i0 && --resend_time[i]<0) { 125 | if(--resend_count[i]) { 126 | udp_send_packet(target_hw, target_ip, CLIENT_PORT, SERVER_PORT, 127 | slots[i], pkt_size[i]); 128 | resend_time[i] = RESEND_TIME * (RESEND_COUNT - resend_count[i]); 129 | num_resends++; 130 | } else { 131 | bzero(&slots[i][3], 16); 132 | slots[i][3] = 99; 133 | slots[i][2] = -1; 134 | slots[i][0] = -1; 135 | } 136 | } 137 | } 138 | 139 | void idle() 140 | { 141 | #if 1 142 | volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c; 143 | 144 | while (!(*vbl & 0x01ff)); 145 | while (*vbl & 0x01ff); 146 | #else 147 | int i; 148 | for(i=0; i<200000; i++); 149 | #endif 150 | background_process(); 151 | } 152 | 153 | static int find_slot() 154 | { 155 | int i, c=0; 156 | 157 | for(;;) { 158 | for(i=0; i=NUM_SLOTS || !slots[n][0]) 193 | return -1; 194 | if(slots[n][0]>0) 195 | return 0; 196 | slots[n][0] = 0; 197 | return 1; 198 | } 199 | 200 | int wait_command_packet(int n) 201 | { 202 | if(n<0 || n>=NUM_SLOTS) 203 | return -1; 204 | while(!check_command_packet(n)) 205 | idle(); 206 | return slots[n][2]; 207 | } 208 | 209 | int *get_packet_slot(int n) 210 | { 211 | return slots[n]; 212 | } 213 | -------------------------------------------------------------------------------- /src/target/common/proto.h: -------------------------------------------------------------------------------- 1 | extern int get_server_ip(unsigned int *addr); 2 | extern int get_server_mac(unsigned char *mac); 3 | extern void set_server(void *ip, void *mac); 4 | extern void proto_got_packet(void *pkt, int sz, void *ip_pkt); 5 | extern int send_command_packet(int cmd, void *param, int pcnt); 6 | extern int check_command_packet(int n); 7 | extern int wait_command_packet(int n); 8 | extern void background_process(void); 9 | extern void idle(void); 10 | extern int *get_packet_slot(int n); 11 | 12 | #define CLIENT_PORT 4781 13 | #define SERVER_PORT 4782 14 | 15 | -------------------------------------------------------------------------------- /src/target/common/util.h: -------------------------------------------------------------------------------- 1 | extern int memcmp(const void *s1, const void *s2, unsigned n); 2 | extern void *memcpy(void *s1, const void *s2, unsigned n); 3 | extern void *memset(void *s, int c, unsigned n); 4 | extern void bzero(void *s, unsigned n); 5 | extern void printf(char *fmt, ...) __attribute__ ((format (printf, 1, 2))); 6 | extern int flash_read_sector(int partition, int sec, char *dst); 7 | 8 | static __inline int getimask(void) 9 | { 10 | register unsigned int sr; 11 | __asm__("stc sr,%0" : "=r" (sr)); 12 | return (sr >> 4) & 0x0f; 13 | } 14 | 15 | static __inline void setimask(int m) 16 | { 17 | register unsigned int sr; 18 | __asm__("stc sr,%0" : "=r" (sr)); 19 | sr = (sr & ~0xf0) | (m << 4); 20 | __asm__("ldc %0,sr" : : "r" (sr)); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/target/common/util1.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | int memcmp(const void *s1, const void *s2, unsigned n) 4 | { 5 | const unsigned char *p1 = s1; 6 | const unsigned char *p2 = s2; 7 | while(n--) 8 | if(*p1 != *p2) 9 | return *p1 - *p2; 10 | else { 11 | p1++; 12 | p2++; 13 | } 14 | return 0; 15 | } 16 | 17 | void *memcpy(void *s1, const void *s2, unsigned n) 18 | { 19 | char *p1 = s1; 20 | const char *p2 = s2; 21 | while(n--) 22 | *p1++ = *p2++; 23 | } 24 | 25 | extern void *memset(void *s, int c, unsigned n) 26 | { 27 | char *p = s; 28 | while(n--) 29 | *p++ = c; 30 | return s; 31 | } 32 | 33 | extern void bzero(void *s, unsigned n) 34 | { 35 | memset(s, 0, n); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/target/configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(launcher/main.c) 2 | 3 | DCAS='sh-elf-as -little' 4 | DCLD='sh-elf-ld -EL' 5 | DCCC='sh-elf-gcc -ml -m4-single-only' 6 | DCAR='sh-elf-ar' 7 | DCOBJCOPY='sh-elf-objcopy' 8 | DCCFLAGS='-Os' 9 | AC_SUBST(DCAS) 10 | AC_SUBST(DCLD) 11 | AC_SUBST(DCCC) 12 | AC_SUBST(DCAR) 13 | AC_SUBST(DCOBJCOPY) 14 | AC_SUBST(DCCFLAGS) 15 | 16 | AC_OUTPUT(Makefile common/Makefile network/Makefile skel/Makefile launcher/Makefile) 17 | -------------------------------------------------------------------------------- /src/target/launcher/Makefile.in: -------------------------------------------------------------------------------- 1 | AS = @DCAS@ 2 | LD = @DCLD@ 3 | CC = @DCCC@ 4 | AR = @DCAR@ 5 | OBJCOPY = @DCOBJCOPY@ 6 | CFLAGS = @DCCFLAGS@ -I$(top_srcdir)/common -I$(top_srcdir)/network 7 | 8 | top_srcdir=@top_srcdir@ 9 | top_builddir=@top_builddir@ 10 | srcdir=@srcdir@ 11 | VPATH=@srcdir@ 12 | 13 | BASEADDR=0x8cf40000 14 | 15 | OBJS = startup.o main.o util2.o video.o launch.o sc.o 16 | LIBS = $(top_builddir)/network/libnetwork.a $(top_builddir)/common/libcommon.a 17 | 18 | all : virtcd.elf 19 | 20 | virtcd.elf : $(OBJS) 21 | $(CC) -o $@ -Wl,--oformat,elf32-shl,-Ttext=$(BASEADDR) -nostartfiles -nostdlib $(OBJS) $(LIBS) -lgcc 22 | 23 | sc.o : $(top_builddir)/skel/sub.bin 24 | $(srcdir)/bin2obj.pike -o $@ _subcode $^ 25 | 26 | clean : 27 | -rm -f virtcd.elf $(OBJS) 28 | 29 | main.o : main.c video.h $(top_srcdir)/common/proto.h $(top_srcdir)/network/pci.h $(top_srcdir)/network/ether.h $(top_srcdir)/common/util.h 30 | 31 | video.o : video.c video.h 32 | 33 | startup.o : startup.s 34 | 35 | launch.o : launch.s 36 | 37 | util2.o : util2.c $(top_srcdir)/common/util.h video.h 38 | 39 | -------------------------------------------------------------------------------- /src/target/launcher/bin2obj.pike: -------------------------------------------------------------------------------- 1 | #! /usr/local/bin/pike -DEMACS_MODE="-*-Pike-*-" 2 | 3 | constant options = ({ 4 | ({ "outfile", Getopt.HAS_ARG, ({"-o","--output"})}), 5 | ({ "writable", Getopt.NO_ARG, ({"-w","--writable"})}), 6 | ({ "align", Getopt.HAS_ARG, ({"-a","--align"})}), 7 | ({ "help", Getopt.NO_ARG, ({"-h","--help"})}), 8 | }); 9 | 10 | int main(int argc, array(string) argv) 11 | { 12 | string outfile = "a.out"; 13 | string section = ".rodata"; 14 | int align = 2; 15 | 16 | foreach(Getopt.find_all_options(argv, options), mixed option) 17 | switch(option[0]) { 18 | case "outfile": outfile=(string)option[1]; break; 19 | case "writable": section=".data"; break; 20 | case "align": align=(int)option[1]; break; 21 | case "help": 22 | werror("Usage: "+argv[0]+ 23 | " [-o outfile] [-w] [-a align] label [file]\n"); 24 | return 1; 25 | } 26 | 27 | argv = Getopt.get_args(argv); 28 | 29 | if(sizeof(argv)<2 || sizeof(argv)>3) { 30 | werror("Illegal arguments.\n"); 31 | return 1; 32 | } 33 | 34 | Stdio.File input; 35 | 36 | if(sizeof(argv)>2) { 37 | input = Stdio.File(); 38 | if(!input->open(argv[-1], "r")) { 39 | werror("%s: %s\n", argv[-1], strerror(input->errno())); 40 | return 1; 41 | } 42 | } else input = Stdio.File("stdin"); 43 | 44 | Stdio.File pipe = Stdio.File(); 45 | Stdio.File p2 = pipe->pipe(); 46 | Process.Process process = Process.Process(({"sh-elf-as", "-little", "-o", outfile}), 47 | (["stdin":p2])); 48 | 49 | p2->close(); 50 | 51 | pipe->write(sprintf("\n\t.section %s\n\n\t.align %d\n\n" 52 | "\t.globl %s,%s_end\n%s:\n", 53 | section, align, argv[1], argv[1], argv[1])); 54 | 55 | string buf; 56 | while((buf = input->read(65536)) && sizeof(buf)) 57 | foreach(buf/32.0, string s) 58 | pipe->write(sprintf("\t.byte 0x%02x%{,0x%02x%}\n", s[0], (array)s[1..])); 59 | 60 | pipe->write(sprintf("\n%s_end:\n", argv[1])); 61 | pipe->write("\n\t.end\n\n"); 62 | pipe->close(); 63 | 64 | return process->wait(); 65 | } 66 | -------------------------------------------------------------------------------- /src/target/launcher/launch.s: -------------------------------------------------------------------------------- 1 | 2 | .globl _launch 3 | 4 | .text 5 | .align 2 6 | 7 | _launch: 8 | mov r4,r14 9 | 10 | mov.l cc2ptr,r2 11 | mov.l ncmask,r3 12 | or r3,r2 13 | jsr @r2 14 | nop 15 | 16 | stc sr,r0 17 | mov.w imask1,r1 18 | and r1,r0 19 | or #-16,r0 20 | ldc r0,sr 21 | 22 | mov.l newsp,r0 23 | mov r0,r15 24 | 25 | mov.l ms_strt,r4 26 | mov.w ms_len,r6 27 | bsr memset 28 | mov #0,r5 29 | 30 | mov.l newsr,r0 31 | ldc r0,sr 32 | 33 | sub r0,r0 34 | mov r0,r1 35 | mov r0,r2 36 | mov r0,r3 37 | mov r0,r4 38 | mov r0,r5 39 | mov r0,r6 40 | mov r0,r7 41 | mov r0,r8 42 | mov r0,r9 43 | mov r0,r10 44 | mov r0,r11 45 | mov r0,r12 46 | mov r0,r13 47 | 48 | mov.l newsp2,r0 49 | mov r0,r15 50 | mov.l newvbr,r0 51 | ldc r0,vbr 52 | mov.l newfpscr,r0 53 | lds r0,fpscr 54 | 55 | mov r1,r0 56 | jsr @r14 57 | mov r1,r14 58 | 59 | foo: 60 | mov.l startaddr,r0 61 | jmp @r0 62 | nop 63 | 64 | 65 | .align 4 66 | 67 | ccache2: 68 | mov.l dcptr2,r0 69 | mov.l @r0,r1 70 | mov.l dcmask,r2 71 | and r2,r1 72 | mov.w dcval,r2 73 | or r2,r1 74 | mov.l r1,@r0 75 | rts 76 | nop 77 | 78 | memset: 79 | mov #0,r7 80 | mov r7,r3 81 | cmp/hs r6,r3 82 | bt/s .mmbye 83 | mov r4,r0 84 | .mmlp: add #1,r7 85 | mov.b r5,@r0 86 | cmp/hs r6,r7 87 | bf/s .mmlp 88 | add #1,r0 89 | .mmbye: rts 90 | mov r4,r0 91 | 92 | .align 4 93 | 94 | cc2ptr: 95 | .long ccache2 96 | ncmask: 97 | .long 0xa0000000 98 | newsp: 99 | .long 0xac00f400 100 | ms_strt: 101 | .long 0xac00fc00 102 | newsr: 103 | .long 0x700000f0 104 | newsp2: 105 | .long 0x8c00f400 106 | newvbr: 107 | .long 0x8c00f400 108 | startaddr: 109 | .long start 110 | newfpscr: 111 | .long 0x40001 112 | dcptr2: 113 | .long 0xff00001c 114 | dcmask: 115 | .long 0x89af 116 | dcval: 117 | .word 0x800 118 | ms_len: 119 | .word 0x400 120 | imask1: 121 | .word 0xff0f 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/target/launcher/main.c: -------------------------------------------------------------------------------- 1 | #include "video.h" 2 | #include "pci.h" 3 | #include "ether.h" 4 | #include "proto.h" 5 | #include "util.h" 6 | 7 | #define MAX_BINARY (15*1024*1024) 8 | 9 | #define SUBSTART 0x8c008300 10 | 11 | static int download_addr, download_size; 12 | 13 | void debug_dump(unsigned char *data, int sz) 14 | { 15 | int i; 16 | for(i=0; i MAX_BINARY) { 99 | printf("FAILED!"); 100 | halt(); 101 | } 102 | printf("%d bytes\n", sz); 103 | download_addr = 0x8c008000; 104 | download_size = sz+0x8000; 105 | } 106 | 107 | void download() 108 | { 109 | int tot = download_size; 110 | int tmp, cur = 10; 111 | int c[8], param[2]; 112 | int i; 113 | printf("Downloading [ ]\r "); 114 | for(i=0; i<8; i++) 115 | c[i] = -1; 116 | i = 0; 117 | for(;;) { 118 | tmp = (10*download_size)/tot; 119 | while(tmp=0) 126 | if(wait_command_packet(c[i])<0) { 127 | printf(" FAILED!"); 128 | halt(); 129 | } 130 | printf(" Done\n"); 131 | return; 132 | } 133 | if(c[i]>=0) 134 | if(wait_command_packet(c[i])<0) { 135 | printf(" FAILED!"); 136 | halt(); 137 | } 138 | tmp = download_size; 139 | if(tmp > 1024) 140 | tmp = 1024; 141 | param[0] = download_addr; 142 | param[1] = tmp; 143 | c[i] = send_command_packet(997, param, 2); 144 | download_addr += tmp; 145 | download_size -= tmp; 146 | if(++i >= 8) 147 | i = 0; 148 | } 149 | } 150 | 151 | void run() 152 | { 153 | extern char subcode[], subcode_end[]; 154 | unsigned char server_mac[6]; 155 | unsigned int my_ip, server_ip; 156 | 157 | get_server_mac(server_mac); 158 | get_server_ip(&server_ip); 159 | ip_get_my_ip(&my_ip); 160 | printf("Running..."); 161 | ether_teardown(); 162 | setimask(15); 163 | memcpy((void*)SUBSTART, subcode, subcode_end - subcode); 164 | ((void (*)(unsigned int, unsigned int, void *))(void*)(SUBSTART+4)) 165 | (my_ip, server_ip, server_mac); 166 | launch(0x8c010000); 167 | printf("Execution terminated."); 168 | } 169 | 170 | void main() 171 | { 172 | setup_video(); 173 | setup_network(); 174 | select_binary(0); 175 | download(); 176 | run(); 177 | halt(); 178 | } 179 | -------------------------------------------------------------------------------- /src/target/launcher/startup.s: -------------------------------------------------------------------------------- 1 | 2 | .globl start, _start 3 | 4 | .text 5 | 6 | start: 7 | _start: 8 | stc sr,r0 9 | or #0xf0,r0 10 | ldc r0,sr 11 | nop 12 | 13 | ! First, make sure to run in the P2 area 14 | mova setup_cache,r0 15 | mov.l p2_mask,r1 16 | or r1,r0 17 | jmp @r0 18 | nop 19 | nop 20 | nop 21 | nop 22 | setup_cache: 23 | ! Now that we are in P2, it's safe 24 | ! to disable the cache 25 | mov.l ccr_addr,r1 26 | mov.w ccr_0data,r2 27 | mov.l r2,@r1 28 | ! Check if we're where we want to be... 29 | mov.l setup_cache_addr,r1 30 | mov.l p2_mask,r2 31 | or r2,r1 32 | cmp/eq r1,r0 33 | bt ok_place 34 | ! Nope, need to copy... 35 | add #-(setup_cache-start),r0 36 | add #-(setup_cache-start),r1 37 | mov.l bss_start_addr,r3 38 | mov.l start_addr,r2 39 | sub r2,r3 40 | add #3,r3 41 | shlr2 r3 42 | copyloop: 43 | mov.l @r0+,r2 44 | dt r3 45 | mov.l r2,@r1 46 | bf/s copyloop 47 | add #4,r1 48 | 49 | ok_place: 50 | ! Reenable cache 51 | mov.l ccr_addr,r0 52 | mov.w ccr_data,r1 53 | mov.l r1,@r0 54 | ! After changing CCR, eight instructions 55 | ! must be executed before it's safe to enter 56 | ! a cached area such as P1 57 | mov.l initaddr,r0 ! 1 58 | mov #0,r1 ! 2 59 | nop ! 3 60 | nop ! 4 61 | nop ! 5 62 | nop ! 6 63 | nop ! 7 64 | nop ! 8 65 | jmp @r0 ! go 66 | mov r1,r0 67 | 68 | 69 | 70 | ! Clear BSS section 71 | init: 72 | mov.l bss_start_addr,r0 73 | mov.l bss_end_addr,r2 74 | mov #3,r1 75 | add r1,r0 76 | add r1,r2 77 | not r1,r1 78 | and r1,r0 79 | and r1,r2 80 | sub r0,r2 81 | shlr r2 82 | shlr r2 83 | mov #0,r1 84 | .loop: dt r2 85 | mov.l r1,@r0 86 | bf/s .loop 87 | add #4,r0 88 | mov.l stack_max,r15 89 | mov #0,r2 90 | mov #0,r1 91 | mov.l mainaddr,r0 92 | jmp @r0 93 | mov r1,r0 94 | 95 | 96 | .align 2 97 | mainaddr: 98 | .long _main 99 | initaddr: 100 | .long init 101 | bss_start_addr: 102 | .long __bss_start 103 | bss_end_addr: 104 | .long _end 105 | p2_mask: 106 | .long 0xa0000000 107 | setup_cache_addr: 108 | .long setup_cache 109 | stack_max: 110 | .long 0x8cff0000 111 | start_addr: 112 | .long start 113 | ccr_addr: 114 | .long 0xff00001c 115 | ccr_data: 116 | .word 0x0909 117 | ccr_0data: 118 | .word 0x0808 119 | 120 | 121 | .end 122 | 123 | -------------------------------------------------------------------------------- /src/target/launcher/util2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "video.h" 4 | #include "util.h" 5 | 6 | /* Dummy stub to make libgcc happy... */ 7 | void atexit() { } 8 | 9 | extern int syscall_read_flash(int offs, void *ptr, int cnt); 10 | 11 | int syscall_info_flash(int sect, int *info) 12 | { 13 | return (*(int (**)())0x8c0000b8)(sect,info,0,0); 14 | } 15 | 16 | unsigned short flash_crc(char *buf, int cnt) 17 | { 18 | static unsigned short table[] = { 19 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 20 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 21 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 22 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 23 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 24 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 25 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 26 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 27 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 28 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 29 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 30 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 31 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 32 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 33 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 34 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 35 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 36 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 37 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 38 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 39 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 40 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 41 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 42 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 43 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 44 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 45 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 46 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 47 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 48 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 49 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 50 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, 51 | }; 52 | unsigned short tmp = ~0; 53 | while(cnt--) 54 | tmp = (tmp<<8)^table[(tmp>>8)^(unsigned char)*buf++]; 55 | return ~tmp; 56 | } 57 | 58 | int flash_read_sector(int partition, int sec, char *dst) 59 | { 60 | int s, r, n, b, bmb, got=0; 61 | int info[2]; 62 | static char buf[64]; 63 | static char bm[64]; 64 | 65 | if((r = syscall_info_flash(partition, info))<0) 66 | return r; 67 | 68 | if((r = syscall_read_flash(info[0], buf, 64))<0) 69 | return r; 70 | 71 | if(memcmp(buf, "KATANA_FLASH", 12) || 72 | buf[16] != partition || buf[17] != 0) 73 | return -2; 74 | 75 | n = (info[1]>>6)-1-((info[1] + 0x7fff)>>15); 76 | bmb = n+1; 77 | for(b = 0; b < n; b++) { 78 | if(!(b&511)) { 79 | if((r = syscall_read_flash(info[0] + (bmb++ << 6), bm, 64))<0) 80 | return r; 81 | } 82 | if(!(bm[(b>>3)&63] & (0x80>>(b&7)))) 83 | if((r = syscall_read_flash(info[0] + ((b+1) << 6), buf, 64))<0) 84 | return r; 85 | else if((s=*(unsigned short *)(buf+0)) == sec && 86 | flash_crc(buf, 62) == *(unsigned short *)(buf+62)) { 87 | memcpy(dst+(s-sec)*60, buf+2, 60); 88 | got=1; 89 | } 90 | } 91 | 92 | return got; 93 | } 94 | 95 | static int do_plot_string(int x, int y, char *p, unsigned short col) 96 | { 97 | int n = 0; 98 | while(*p) { 99 | video_plot_char(x, y, *(unsigned char *)p, col); 100 | x += 12; 101 | n += 12; 102 | p++; 103 | } 104 | return n; 105 | } 106 | 107 | static char *format_num(int n, int base, int w, int pad) 108 | { 109 | static char buf[32]; 110 | char *p=buf+32; 111 | int s=0; 112 | *--p = '\0'; 113 | if(base==10 && n<0) { 114 | n = -n; 115 | s = 1; 116 | --w; 117 | } 118 | do { 119 | if(base == 16) { 120 | *--p = "0123456789abcdef"[n & 15]; 121 | n = ((unsigned int)n)>>4; 122 | } else { 123 | *--p = (n % base) + '0'; 124 | n /= base; 125 | } 126 | --w; 127 | } while(n); 128 | if(pad<0) 129 | pad = ' '; 130 | while(w>0) { 131 | *--p = pad; 132 | --w; 133 | } 134 | if(s) 135 | *--p = '-'; 136 | return p; 137 | } 138 | 139 | void vprintf(char *fmt, va_list va) 140 | { 141 | static int x=8, y=8; 142 | int w=-1, pad=-1; 143 | unsigned short col = C_BLACK; 144 | while(*fmt++) 145 | if(fmt[-1]=='%') 146 | while(1) { 147 | switch(*fmt++) { 148 | case '%': 149 | video_plot_char(x, y, '%', col); x+=12; 150 | break; 151 | case '\0': 152 | return; 153 | case 's': 154 | x += do_plot_string(x, y, va_arg(va, char *), col); 155 | w = pad = -1; 156 | break; 157 | case 'c': 158 | { 159 | int c = va_arg(va, int); 160 | video_plot_char(x, y, c, col); 161 | x+=(c>0xff? 24:12); 162 | w = pad = -1; 163 | } 164 | break; 165 | case '0': 166 | if(w<0) { 167 | pad='0'; 168 | continue; 169 | } 170 | case '1': 171 | case '2': 172 | case '3': 173 | case '4': 174 | case '5': 175 | case '6': 176 | case '7': 177 | case '8': 178 | case '9': 179 | if(w<0) w=0; 180 | w = w*10 + (fmt[-1]&0xf); 181 | continue; 182 | case 'p': 183 | w = 8; 184 | pad = '0'; 185 | case 'd': 186 | case 'x': 187 | x += do_plot_string(x, y, format_num(va_arg(va, int), 188 | (fmt[-1]=='d'? 10:16), 189 | w, pad), col); 190 | w = pad = -1; 191 | } 192 | break; 193 | } 194 | else if(fmt[-1]=='\n') { 195 | x = 8; 196 | y += 24; 197 | } else if(fmt[-1]=='\r') 198 | x = 8; 199 | else if(fmt[-1]=='\014') { 200 | x = y = 8; 201 | } else { 202 | video_plot_char(x, y, ((unsigned char *)fmt)[-1], col); 203 | x += 12; 204 | } 205 | } 206 | 207 | void printf(char *fmt, ...) 208 | { 209 | va_list va; 210 | va_start(va, fmt); 211 | vprintf(fmt, va); 212 | va_end(va); 213 | } 214 | -------------------------------------------------------------------------------- /src/target/launcher/video.c: -------------------------------------------------------------------------------- 1 | #include "video.h" 2 | 3 | static void *halffontbase, *fullfontbase; 4 | 5 | struct sysinfo { 6 | unsigned char id[8]; 7 | unsigned char settings[16]; 8 | }; 9 | 10 | int syscall_read_flash(int offs, void *ptr, int cnt) 11 | { 12 | return (*(int (**)(int, void *, int, int))0x8c0000b8)(offs,ptr,cnt,1); 13 | } 14 | 15 | static void get_sysinfo(struct sysinfo *si) 16 | { 17 | int i; 18 | 19 | syscall_read_flash(0x1a056, si->id, 8); 20 | syscall_read_flash(0x1a000, si->settings, 5); 21 | for(i=0; i<11; i++) 22 | si->settings[5+i] = 0; 23 | } 24 | 25 | static int query_tv() 26 | { 27 | //PALM (Brazil) is 60Hz. The sweep frequency is closer to NTSC than 28 | //PAL and it only has 525 lines. 29 | // 30 | //PALM (Uruguay, Paraguay and Argentina) has Lower bandwith than 31 | //PAL, but otherwise pretty much the same. 32 | // 33 | //http://www.alkenmrs.com/video/standards.html for details 34 | 35 | struct sysinfo si; 36 | 37 | get_sysinfo(&si); 38 | return si.settings[4]-'0'; 39 | } 40 | 41 | int video_check_cable(int *tv) 42 | { 43 | volatile unsigned int *porta = (volatile unsigned int *)0xff80002c; 44 | unsigned short v; 45 | 46 | /* PORT8 and PORT9 is input */ 47 | *porta = (*porta & ~0xf0000) | 0xa0000; 48 | 49 | /* Read PORT8 and PORT9 */ 50 | v = ((*(volatile unsigned short *)(porta+1))>>8)&3; 51 | 52 | if(tv) 53 | if (! (v&2) ) 54 | *tv = 0; 55 | else 56 | *tv = query_tv(); 57 | 58 | return v; 59 | } 60 | 61 | 62 | /* Initialize the PVR subsystem to a known state */ 63 | 64 | static unsigned int scrn_params[] = { 65 | 0x80e8, 0x00160000, /* screen control */ 66 | 0x8044, 0x00800000, /* pixel mode (vb+0x11) */ 67 | 0x805c, 0x00000000, /* Size modulo and display lines (vb+0x17) */ 68 | 0x80d0, 0x00000100, /* interlace flags */ 69 | 0x80d8, 0x020c0359, /* M */ 70 | 0x80cc, 0x001501fe, /* M */ 71 | 0x80d4, 0x007e0345, /* horizontal border */ 72 | 0x80dc, 0x00240204, /* vertical position */ 73 | 0x80e0, 0x07d6c63f, /* sync control */ 74 | 0x80ec, 0x000000a4, /* horizontal position */ 75 | 0x80f0, 0x00120012, /* vertical border */ 76 | 0x80c8, 0x03450000, /* set to same as border H in 80d4 */ 77 | 0x8068, 0x027f0000, /* (X resolution - 1) << 16 */ 78 | 0x806c, 0x01df0000, /* (Y resolution - 1) << 16 */ 79 | 0x804c, 0x000000a0, /* display align */ 80 | 0x8118, 0x00008040, /* M */ 81 | 0x80f4, 0x00000401, /* anti-aliasing */ 82 | 0x8048, 0x00000009, /* alpha config */ 83 | 0x7814, 0x00000000, /* More interrupt control stuff (so it seems)*/ 84 | 0x7834, 0x00000000, 85 | 0x7854, 0x00000000, 86 | 0x7874, 0x00000000, 87 | 0x78bc, 0x4659404f, 88 | 0x8040, 0x00000000 /* border color */ 89 | }; 90 | 91 | static void set_regs(unsigned int *values, int cnt) 92 | { 93 | volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000; 94 | unsigned int r, v; 95 | 96 | while(cnt--) { 97 | r = *values++; 98 | v = *values++; 99 | *(volatile unsigned int *)(regs+r) = v; 100 | } 101 | } 102 | 103 | 104 | static unsigned long syscall_b4(int n) 105 | { 106 | unsigned long r; 107 | asm("jsr @%1\nmov %2,r1\nmov r0,%0" : 108 | "=r" (r) : "r" (*(void **)0x8c0000b4), "r" (n) : 109 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "pr"); 110 | return r; 111 | } 112 | 113 | void video_init_pvr() 114 | { 115 | volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c; 116 | 117 | while (!(*vbl & 0x01ff)); 118 | while (*vbl & 0x01ff); 119 | set_regs(scrn_params, sizeof(scrn_params)/sizeof(scrn_params[0])/2); 120 | 121 | halffontbase = (void*)syscall_b4(0); 122 | fullfontbase = ((char *)halffontbase) + (96*3)*(24*3/2); 123 | } 124 | 125 | 126 | /* Set up video registers to the desired 127 | video mode 128 | 129 | in: 130 | cabletype (0=VGA, 2=RGB, 3=Composite) 131 | pixel mode (0=RGB555, 1=RGB565, 3=RGB888) 132 | tvmode (0 = off, 1 = on) 133 | res (0 = 320 x 240, 1 = 640 x 240, 2 = 640 x 480) 134 | hz50 (0 = 60Hz, 1 = 50 Hz) 135 | pal (0 = NTSC, 1 = PAL, 2 = PALM, 3 = PALN) 136 | voffset (vertical offset of screen in TV mode. Added to the 137 | base offset.) 138 | */ 139 | void video_init_video(int cabletype, int mode, int tvmode, int res, 140 | int hz50, int pal, int voffset) 141 | { 142 | static int bppshifttab[]= { 1,1,0,2 }; 143 | static int videobase=0xa05f8000; 144 | static int cvbsbase=0xa0702c00; 145 | static int hpos=0xa4; 146 | static int hvcounter31=0x020c0359; 147 | static int hvcounter15=0x01060359; 148 | static int hvcounter3150=0x02700359; 149 | static int hvcounter1550=0x01380359; 150 | static int hborder=0x007e0345; 151 | int laceoffset=0; 152 | 153 | int shift, lines, hvcounter, modulo, words_per_line, vpos; 154 | unsigned int tmp, videoflags, displaytmp, attribs; 155 | 156 | volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c; 157 | 158 | while (!(*vbl & 0x01ff)); 159 | while (*vbl & 0x01ff); 160 | 161 | *(int *)(videobase+0x44)=0; 162 | *(int *)(videobase+0xd0)=0; 163 | 164 | if(!(cabletype&2)) 165 | hz50 = pal = 0; 166 | 167 | if(res==0 || res==1) 168 | hvcounter=(hz50? hvcounter1550 : hvcounter15); 169 | else 170 | hvcounter=(hz50? hvcounter3150 : hvcounter31); 171 | 172 | // Look up bytes per pixel as shift value 173 | mode=mode&3; //&3 is safety left over from asm. 174 | shift=bppshifttab[mode]; 175 | // Get video HW address 176 | *(int *)(videobase+8)=0; // Reset??? 177 | *(int *)(videobase+0x40)=0; // Set border colour to black 178 | // Set pixel clock and colour mode 179 | mode = (mode<<2)+1; 180 | lines = 240; // Non-VGA screen has 240 display lines 181 | if(!(cabletype&2)) // VGA 182 | { 183 | if((res==0 && !tvmode) || res == 1) 184 | mode+=2; 185 | 186 | hvcounter=hvcounter31; 187 | 188 | lines = lines<<1; // Double # of display lines for VGA 189 | mode = mode|0x800000; // Set double pixel clock 190 | } else 191 | tvmode=0; // Running TV-mode on a TV isn't really helpful. 192 | 193 | *(int *)(videobase+0x50)=0; // Set video base address 194 | // Video base address for short fields should be offset by one line 195 | *(int *)(videobase+0x54)=640< No interlace 207 | { 208 | if(res==0 && !tvmode) 209 | modulo+=words_per_line; //Render black on every other line. 210 | } else { 211 | if(res!=1) 212 | modulo+=words_per_line; //Skip the black part (lores) or 213 | //add one line to offset => display 214 | //every other line (hires) 215 | if(res==2) 216 | videoflags|=1<<4; //enable LACE 217 | 218 | #if 0 219 | if(!pal) 220 | videoflags|=1<<6; //enable NTSC (doesn't matter on jp systems, 221 | // european systems seems to be able to produce 222 | // it, US systems are unknown) 223 | 224 | if(hz50) 225 | videoflags|=1<<7; //50Hz 226 | #else 227 | videoflags|=(pal&3)<<6; 228 | #endif 229 | } 230 | 231 | //modulo, height, width 232 | *(int *)(videobase+0x5c)=(((modulo<<10)+lines-1)<<10)+words_per_line-1; 233 | 234 | // Set vertical pos and border 235 | 236 | if(!(cabletype&2)) //VGA 237 | voffset += 36; 238 | else 239 | voffset += (hz50? 44 : 18); 240 | 241 | #if 0 242 | if(res==2 && pal) // PAL Lace 243 | laceoffset = 0; 244 | else if(res==2 && hz50) // NTSC Lace 50Hz (tested on EU,JP machine. strange) 245 | laceoffset = 0; 246 | #endif 247 | 248 | vpos=(voffset<<16)|(voffset+laceoffset); 249 | 250 | *(int *)(videobase+0xf0)=vpos; // V start 251 | *(int *)(videobase+0xdc)=vpos+lines; // start and end border 252 | *(int *)(videobase+0xec)=hpos; // Horizontal pos 253 | *(int *)(videobase+0xd8)=hvcounter; // HV counter 254 | *(int *)(videobase+0xd4)=hborder; // Horizontal border 255 | if(res==0) 256 | attribs=((22<<8)+1)<<8; //X-way pixel doubler 257 | else 258 | attribs=22<<16; 259 | *(int *)(videobase+0xe8)=attribs; // Screen attributes 260 | 261 | #if 0 262 | if(!(cabletype&2)) 263 | *(int *)(videobase+0xe0)=(0x0f<<22)|(793<<12)|(3<<8)|0x3f; 264 | else { 265 | attribs = 0x3f; 266 | if(hz50) 267 | attribs |= 5<<8; 268 | else 269 | attribs |= (res==2? 6:3)<<8; 270 | if(hz50) 271 | attribs |= (res==2? 362:799)<<12; 272 | else 273 | attribs |= (res==2? 364:793)<<12; 274 | attribs |= 0x1f<<22; 275 | *(int *)(videobase+0xe0)=attribs; 276 | } 277 | #endif 278 | 279 | vpos = (hz50? 310:260); 280 | if(!(cabletype&2)) 281 | vpos = 510; 282 | 283 | /* Set up vertical blank event */ 284 | vpos = 242+voffset; 285 | if(!(cabletype&2)) 286 | vpos = 482+voffset; 287 | *(int *)(videobase+0xcc)=((voffset-2)<<16)|(voffset+lines+2); 288 | 289 | // Select RGB/CVBS 290 | if(cabletype&1) //!rgbmode 291 | tmp=3; 292 | else 293 | tmp=0; 294 | tmp=tmp<<8; 295 | *(int *)cvbsbase = tmp; 296 | 297 | *(int *)(videobase+0x44)=mode;// Set bpp 298 | *(int *)(videobase+0xd0)=videoflags; //video enable, 60Hz, NTSC, lace 299 | 300 | *(volatile unsigned int *)(void*)0xa05f6900 = 0x08; 301 | 302 | return; 303 | } 304 | 305 | 306 | void video_clrscr(unsigned short c) 307 | { 308 | short *p = (void*)0xa5000000; 309 | int i; 310 | for(i=0; i<640*480; i++) 311 | *p++ = c; 312 | } 313 | 314 | 315 | 316 | #define SCREENADDR(y,x) \ 317 | (((unsigned short *)0xa5000000)+640*(y)+(x)) 318 | #define NEXTLINE(a) ((a)+640) 319 | #define FONTADDR(b,n,w) (((unsigned char *)(b))+(n)*((w)*3)) 320 | 321 | #define PLOT \ 322 | do { \ 323 | s[640] = fg; \ 324 | s[1] = fg; \ 325 | *s++ = fg; \ 326 | } while(0) 327 | 328 | static void drawhalf(int y, int x, int n, unsigned short fg) 329 | { 330 | unsigned short *s = SCREENADDR(y, x); 331 | unsigned char *f = FONTADDR(halffontbase, n, 12); 332 | int i, j; 333 | asm("pref @%0" : : "r" (f)); 334 | asm("pref @%0" : : "r" (f+32)); 335 | for(i=0; i<12; i++) { 336 | int d = (*f++)<<16; 337 | d |= (*f++)<<8; 338 | d |= *f++; 339 | for(j=0; j<12; j++) { 340 | if(d&0x800000) 341 | PLOT; 342 | else 343 | s++; 344 | d<<=1; 345 | } 346 | s = NEXTLINE(s-12); 347 | for(j=0; j<12; j++) { 348 | if(d&0x800000) 349 | PLOT; 350 | else 351 | s++; 352 | d<<=1; 353 | } 354 | s = NEXTLINE(s-12); 355 | } 356 | } 357 | 358 | static void drawfull(int y, int x, int n, unsigned short fg) 359 | { 360 | unsigned short *s = SCREENADDR(y, x); 361 | unsigned char *f = FONTADDR(fullfontbase, n, 24); 362 | int i, j; 363 | asm("pref @%0" : : "r" (f)); 364 | asm("pref @%0" : : "r" (f+32)); 365 | asm("pref @%0" : : "r" (f+64)); 366 | asm("pref @%0" : : "r" (f+68)); 367 | for(i=0; i<24; i++) { 368 | int d = (*f++)<<16; 369 | d |= (*f++)<<8; 370 | d |= *f++; 371 | for(j=0; j<24; j++) { 372 | if(d&0x800000) 373 | PLOT; 374 | else 375 | s++; 376 | d<<=1; 377 | } 378 | s = NEXTLINE(s-24); 379 | } 380 | } 381 | 382 | static int kuten(int sj) 383 | { 384 | unsigned char lo = sj; 385 | unsigned char hi = ((unsigned int)sj)>>8; 386 | if(sj<0x8140 || sj>0xeaa4 || lo<0x40 || lo>0xfc || lo==0x7f) 387 | return -1; 388 | if(sj>=0xa000 && sj<0xe000) 389 | return -1; 390 | hi = ((hi-0x81)*2+0x21)&0x7f; 391 | if(lo>=0x9f) { 392 | hi++; 393 | lo -= 0x9f; 394 | } else if(lo>0x7f) { 395 | lo -= 0x41; 396 | } else 397 | lo -= 0x40; 398 | return (hi<40? (hi-33)*94+lo : (hi>=48? (hi-41)*94+lo : -1)); 399 | } 400 | 401 | void video_plot_char(int x, int y, int ch, unsigned short colour) 402 | { 403 | if(ch>=0x100) 404 | if((ch&0xff9f)<=0x115) 405 | drawfull(y, x, (ch&0x1f)+(7078-22), colour); 406 | else if((ch=kuten(ch))>=0) 407 | drawfull(y, x, ch, colour); 408 | else 409 | drawfull(y, x, 0, colour); 410 | else if(ch>=0xa0) 411 | drawhalf(y, x, ch+(1*96-0xa0), colour); 412 | else if(ch>32 && ch<127) 413 | drawhalf(y, x, ch-32, colour); 414 | else 415 | drawhalf(y, x, 288, colour); 416 | } 417 | 418 | void video_fill_bar(int x, int y, int w, int h, unsigned short c) 419 | { 420 | unsigned short * p = SCREENADDR(y, x); 421 | while(h--) { 422 | int i; 423 | for(i=0; i used_entries) 19 | used_entries = entry_robin; 20 | 21 | if(entry_robin >= NUM_ARP_ENTRIES) 22 | entry_robin = 0; 23 | 24 | for(i=0; i<4; i++) 25 | e->ip[i] = ip[i]; 26 | for(i=0; i<6; i++) 27 | e->hw[i] = hw[i]; 28 | 29 | return e; 30 | } 31 | 32 | static struct arp_entry *arp_find_ip(unsigned char *ip) 33 | { 34 | int i; 35 | struct arp_entry *e = entries; 36 | 37 | for(i=0; iip[0] == ip[0] && e->ip[1] == ip[1] && 39 | e->ip[2] == ip[2] && e->ip[3] == ip[3]) 40 | return e; 41 | 42 | return 0; 43 | } 44 | 45 | 46 | void arp_got_packet(void *pkt, int size) 47 | { 48 | struct { 49 | unsigned short hwspace; 50 | unsigned short protospace; 51 | unsigned char hwlength; 52 | unsigned char protolength; 53 | unsigned short opcode; 54 | } *arp_pkt = pkt; 55 | unsigned char *senderhw = (unsigned char *)(arp_pkt+1); 56 | unsigned char *senderproto = senderhw + arp_pkt->hwlength; 57 | unsigned char *targethw = senderproto + arp_pkt->protolength; 58 | unsigned char *targetproto = targethw + arp_pkt->hwlength; 59 | unsigned int myip; 60 | int i, merge_flag = 0; 61 | struct arp_entry *entry; 62 | 63 | /* Discard short ARP packet... */ 64 | if(targetproto + arp_pkt->protolength - (unsigned char *)pkt > size) 65 | return; 66 | 67 | /* Only ethernet & IP below this point... */ 68 | if(htons(arp_pkt->hwspace) != 1 || htons(arp_pkt->protospace) != 0x800 || 69 | arp_pkt->hwlength != 6 || arp_pkt->protolength != 4) 70 | return; 71 | 72 | if((entry = arp_find_ip(senderproto)) != 0) { 73 | for(i=0; i<6; i++) 74 | entry->hw[i] = senderhw[i]; 75 | merge_flag = 1; 76 | } 77 | 78 | if(!ip_get_my_ip(&myip)) 79 | return; 80 | 81 | for(i=0; i<4; i++) 82 | if(targetproto[i] != ((unsigned char *)&myip)[i]) 83 | return; 84 | 85 | if(!merge_flag) { 86 | arp_add_entry(senderproto, senderhw); 87 | } 88 | 89 | if(htons(arp_pkt->opcode) != 1) 90 | return; 91 | 92 | for(i=0; i<6; i++) { 93 | (((unsigned char *)pkt)-14)[i] = targethw[i] = senderhw[i]; 94 | (((unsigned char *)pkt)-8)[i] = senderhw[i] = ether_MAC[i]; 95 | } 96 | 97 | for(i=0; i<4; i++) { 98 | targetproto[i] = senderproto[i]; 99 | senderproto[i] = ((unsigned char *)&myip)[i]; 100 | } 101 | 102 | ether_send_packet(((unsigned char *)pkt)-14, 42); 103 | } 104 | -------------------------------------------------------------------------------- /src/target/network/arp.h: -------------------------------------------------------------------------------- 1 | void arp_got_packet(void *pkt, int size); 2 | -------------------------------------------------------------------------------- /src/target/network/ether.c: -------------------------------------------------------------------------------- 1 | #include "pci.h" 2 | #include "ether.h" 3 | #include "ip.h" 4 | #include "arp.h" 5 | #include "util.h" 6 | 7 | /* PCI Tuning Parameters 8 | Threshold is bytes transferred to chip before transmission starts. */ 9 | #define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ 10 | 11 | /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ 12 | #define RX_FIFO_THRESH 6 /* Rx buffer level before first PCI xfer. */ 13 | #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ 14 | #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ 15 | 16 | /* Size of the in-memory receive ring. */ 17 | #define RX_BUF_LEN 16384 18 | 19 | /* Maximum allowed input packet size (should be >= ethernet MTU) */ 20 | #define MAX_PKT_SIZE 2048 21 | 22 | /* Number of Tx descriptor registers. */ 23 | #define NUM_TX_DESC 4 24 | 25 | /* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ 26 | #define MAX_ETH_FRAME_SIZE 1536 27 | 28 | /* Symbolic offsets to registers. */ 29 | enum RTL8139_registers { 30 | MAC0 = 0, /* Ethernet hardware address. */ 31 | MAR0 = 8, /* Multicast filter. */ 32 | TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ 33 | TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ 34 | RxBuf = 0x30, 35 | RxEarlyCnt = 0x34, 36 | RxEarlyStatus = 0x36, 37 | ChipCmd = 0x37, 38 | RxBufPtr = 0x38, 39 | RxBufAddr = 0x3A, 40 | IntrMask = 0x3C, 41 | IntrStatus = 0x3E, 42 | TxConfig = 0x40, 43 | ChipVersion = 0x43, 44 | RxConfig = 0x44, 45 | Timer = 0x48, /* A general-purpose counter. */ 46 | RxMissed = 0x4C, /* 24 bits valid, write clears. */ 47 | Cfg9346 = 0x50, 48 | Config0 = 0x51, 49 | Config1 = 0x52, 50 | FlashReg = 0x54, 51 | MediaStatus = 0x58, 52 | Config3 = 0x59, 53 | Config4 = 0x5A, /* absent on RTL-8139A */ 54 | HltClk = 0x5B, 55 | MultiIntr = 0x5C, 56 | TxSummary = 0x60, 57 | BasicModeCtrl = 0x62, 58 | BasicModeStatus = 0x64, 59 | NWayAdvert = 0x66, 60 | NWayLPAR = 0x68, 61 | NWayExpansion = 0x6A, 62 | /* Undocumented registers, but required for proper operation. */ 63 | FIFOTMS = 0x70, /* FIFO Control and test. */ 64 | CSCR = 0x74, /* Chip Status and Configuration Register. */ 65 | PARA78 = 0x78, 66 | PARA7c = 0x7c, /* Magic transceiver parameter register. */ 67 | Config5 = 0xD8, /* absent on RTL-8139A */ 68 | }; 69 | 70 | 71 | enum ClearBitMasks { 72 | MultiIntrClear = 0xF000, 73 | ChipCmdClear = 0xE2, 74 | Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), 75 | }; 76 | 77 | enum ChipCmdBits { 78 | CmdReset = 0x10, 79 | CmdRxEnb = 0x08, 80 | CmdTxEnb = 0x04, 81 | RxBufEmpty = 0x01, 82 | }; 83 | 84 | /* Interrupt register bits, using my own meaningful names. */ 85 | enum IntrStatusBits { 86 | PCIErr = 0x8000, 87 | PCSTimeout = 0x4000, 88 | RxFIFOOver = 0x40, 89 | RxUnderrun = 0x20, 90 | RxOverflow = 0x10, 91 | TxErr = 0x08, 92 | TxOK = 0x04, 93 | RxErr = 0x02, 94 | RxOK = 0x01, 95 | }; 96 | enum TxStatusBits { 97 | TxHostOwns = 0x2000, 98 | TxUnderrun = 0x4000, 99 | TxStatOK = 0x8000, 100 | TxOutOfWindow = 0x20000000, 101 | TxAborted = 0x40000000, 102 | TxCarrierLost = 0x80000000, 103 | }; 104 | enum RxStatusBits { 105 | RxMulticast = 0x8000, 106 | RxPhysical = 0x4000, 107 | RxBroadcast = 0x2000, 108 | RxBadSymbol = 0x0020, 109 | RxRunt = 0x0010, 110 | RxTooLong = 0x0008, 111 | RxCRCErr = 0x0004, 112 | RxBadAlign = 0x0002, 113 | RxStatusOK = 0x0001, 114 | }; 115 | 116 | /* Bits in RxConfig. */ 117 | enum rx_mode_bits { 118 | AcceptErr = 0x20, 119 | AcceptRunt = 0x10, 120 | AcceptBroadcast = 0x08, 121 | AcceptMulticast = 0x04, 122 | AcceptMyPhys = 0x02, 123 | AcceptAllPhys = 0x01, 124 | }; 125 | 126 | /* Bits in TxConfig. */ 127 | enum tx_config_bits { 128 | TxIFG1 = (1 << 25), /* Interframe Gap Time */ 129 | TxIFG0 = (1 << 24), /* Enabling these bits violates IEEE 802.3 */ 130 | TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ 131 | TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ 132 | TxClearAbt = (1 << 0), /* Clear abort (WO) */ 133 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ 134 | 135 | TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ 136 | }; 137 | 138 | /* Bits in Config1 */ 139 | enum Config1Bits { 140 | Cfg1_PM_Enable = 0x01, 141 | Cfg1_VPD_Enable = 0x02, 142 | Cfg1_PIO = 0x04, 143 | Cfg1_MMIO = 0x08, 144 | Cfg1_LWAKE = 0x10, 145 | Cfg1_Driver_Load = 0x20, 146 | Cfg1_LED0 = 0x40, 147 | Cfg1_LED1 = 0x80, 148 | }; 149 | 150 | enum RxConfigBits { 151 | /* Early Rx threshold, none or X/16 */ 152 | RxCfgEarlyRxNone = 0, 153 | RxCfgEarlyRxShift = 24, 154 | 155 | /* rx fifo threshold */ 156 | RxCfgFIFOShift = 13, 157 | RxCfgFIFONone = (7 << RxCfgFIFOShift), 158 | 159 | /* Max DMA burst */ 160 | RxCfgDMAShift = 8, 161 | RxCfgDMAUnlimited = (7 << RxCfgDMAShift), 162 | 163 | /* rx ring buffer length */ 164 | RxCfgRcv8K = 0, 165 | RxCfgRcv16K = (1 << 11), 166 | RxCfgRcv32K = (1 << 12), 167 | RxCfgRcv64K = (1 << 11) | (1 << 12), 168 | 169 | /* Disable packet wrap at end of Rx buffer */ 170 | RxNoWrap = (1 << 7), 171 | }; 172 | 173 | enum Cfg9346Bits { 174 | Cfg9346_Lock = 0x00, 175 | Cfg9346_Unlock = 0xC0, 176 | }; 177 | 178 | 179 | #define RTL_R8(reg) pci_read8(reg) 180 | #define RTL_R16(reg) pci_read16(reg) 181 | #define RTL_R32(reg) pci_read32(reg) 182 | #define RTL_W8(reg,val8) pci_write8(reg,val8) 183 | #define RTL_W16(reg,val16) pci_write16(reg,val16) 184 | #define RTL_W32(reg,val32) pci_write32(reg,val32) 185 | #define RTL_W8_F RTL_W8 186 | #define RTL_W16_F RTL_W16 187 | #define RTL_W32_F RTL_W32 188 | 189 | 190 | #define RXBASE 0x1840000 191 | #define TXBASE 0x1844400 192 | 193 | 194 | static int cur_rx; 195 | static int curr_tx = 0; 196 | static int tx_in_use = 0; 197 | static char *rx_ring = (void *)(0xa0000000|RXBASE); 198 | 199 | 200 | unsigned char ether_MAC[6]; 201 | 202 | 203 | static void ether_set_rx_mode(int up) 204 | { 205 | unsigned int rx_mode; 206 | 207 | if(up) 208 | rx_mode = 209 | AcceptBroadcast | AcceptMyPhys; 210 | else 211 | rx_mode = 0; 212 | 213 | RTL_W32_F(RxConfig, RxCfgEarlyRxNone | RxCfgRcv16K | 214 | (RX_FIFO_THRESH << RxCfgFIFOShift) | 215 | (RX_DMA_BURST << RxCfgDMAShift) | 216 | rx_mode | 217 | (RTL_R32 (RxConfig) & 0xf0fc0040)); 218 | 219 | RTL_W32_F (MAR0 + 0, 0); 220 | RTL_W32_F (MAR0 + 4, 0); 221 | } 222 | 223 | 224 | static void ether_hw_start() 225 | { 226 | int i; 227 | unsigned char tmp; 228 | union { unsigned int i[2]; unsigned char b[8]; } MAC; 229 | 230 | /* Soft reset the chip. */ 231 | RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); 232 | 233 | /* Check that the chip has finished the reset. */ 234 | for (i = 1000000; i > 0; i--) 235 | if ((RTL_R8 (ChipCmd) & CmdReset) == 0) 236 | break; 237 | 238 | /* unlock Config[01234] and BMCR register writes */ 239 | RTL_W8_F (Cfg9346, Cfg9346_Unlock); 240 | 241 | #if 0 242 | /* Restore our idea of the MAC address. */ 243 | RTL_W32_F (MAC0 + 0, mac1); 244 | RTL_W32_F (MAC0 + 4, mac2); 245 | #endif 246 | 247 | MAC.i[0] = RTL_R32 (MAC0 + 0); 248 | MAC.i[1] = RTL_R32 (MAC0 + 4); 249 | 250 | for (i = 0; i < 6; i++) 251 | ether_MAC[i] = MAC.b[i]; 252 | 253 | /* Must enable Tx/Rx before setting transfer thresholds! */ 254 | RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | 255 | CmdRxEnb | CmdTxEnb); 256 | 257 | ether_set_rx_mode(0); 258 | 259 | /* Check this value: the documentation for IFG contradicts ifself. */ 260 | RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); 261 | 262 | cur_rx = 0; 263 | 264 | tmp = RTL_R8 (Config1) & Config1Clear; 265 | tmp |= Cfg1_Driver_Load; 266 | RTL_W8_F (Config1, tmp); 267 | 268 | tmp = RTL_R8 (Config4) & ~(1<<2); 269 | /* chip will clear Rx FIFO overflow automatically */ 270 | tmp |= (1<<7); 271 | RTL_W8 (Config4, tmp); 272 | 273 | /* Lock Config[01234] and BMCR register writes */ 274 | RTL_W8_F (Cfg9346, Cfg9346_Lock); 275 | 276 | for (i = 10000; i > 0; i--); 277 | 278 | /* init Rx ring buffer DMA address */ 279 | RTL_W32_F (RxBuf, RXBASE); 280 | 281 | /* init Tx buffer DMA addresses */ 282 | for (i = 0; i < NUM_TX_DESC; i++) 283 | RTL_W32_F (TxAddr0 + (i * 4), TXBASE + i*2048); 284 | 285 | RTL_W32_F (RxMissed, 0); 286 | 287 | ether_set_rx_mode(1); 288 | 289 | /* no early-rx interrupts */ 290 | RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); 291 | 292 | /* make sure RxTx has started */ 293 | RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | 294 | CmdRxEnb | CmdTxEnb); 295 | 296 | #if 0 297 | /* Enable all known interrupts by setting the interrupt mask. */ 298 | RTL_W16_F (IntrMask, PCIErr | PCSTimeout | RxUnderrun | RxOverflow | 299 | RxFIFOOver | TxErr | TxOK | RxErr | RxOK); 300 | #endif 301 | } 302 | 303 | 304 | int ether_setup() 305 | { 306 | int i; 307 | 308 | curr_tx = 0; 309 | tx_in_use = 0; 310 | 311 | RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); 312 | 313 | /* Check that the chip has finished the reset. */ 314 | for (i = 1000000; i > 0; i--) 315 | if ((RTL_R8 (ChipCmd) & CmdReset) == 0) 316 | break; 317 | 318 | /* handle RTL8139A and RTL8139 cases */ 319 | /* XXX from becker driver. is this right?? */ 320 | RTL_W8 (Config1, 0); 321 | 322 | /* simplex, negotiate speed */ 323 | RTL_W16 (BasicModeCtrl, /*0x2100*/0x1200); 324 | 325 | ether_hw_start(); 326 | 327 | return 0; 328 | } 329 | 330 | void ether_teardown() 331 | { 332 | unsigned int txstatus; 333 | int i; 334 | 335 | for(i=0; i> 16; 381 | pkt_size = rx_size - 4; 382 | 383 | /* E. Gill */ 384 | /* Note from BSD driver: 385 | * Here's a totally undocumented fact for you. When the 386 | * RealTek chip is in the process of copying a packet into 387 | * RAM for you, the length will be 0xfff0. If you spot a 388 | * packet header with this value, you need to stop. The 389 | * datasheet makes absolutely no mention of this and 390 | * RealTek should be shot for this. 391 | */ 392 | if (rx_size == 0xfff0) 393 | break; 394 | 395 | /* If Rx err or invalid rx_size/rx_status received 396 | * (which happens if we get lost in the ring), 397 | * Rx process gets reset, so we abort any further 398 | * Rx processing. 399 | */ 400 | if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || 401 | (!(rx_status & RxStatusOK))) { 402 | 403 | unsigned char tmp8; 404 | 405 | tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear; 406 | RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb); 407 | 408 | /* A.C.: Reset the multicast list. */ 409 | ether_set_rx_mode(1); 410 | 411 | /* XXX potentially temporary hack to 412 | * restart hung receiver */ 413 | while (--tmp_work > 0) { 414 | tmp8 = RTL_R8 (ChipCmd); 415 | if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) 416 | break; 417 | RTL_W8_F (ChipCmd, 418 | (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb); 419 | } 420 | 421 | /* G.S.: Re-enable receiver */ 422 | /* XXX temporary hack to work around receiver hang */ 423 | ether_set_rx_mode (1); 424 | 425 | } else if(pkt_size <= MAX_PKT_SIZE) { 426 | 427 | int i; 428 | 429 | for(i=0; i>1); i++) 12 | csum += (unsigned short)~(i==1? 0 : ((short *)pkt)[i]); 13 | 14 | if((csum = ((unsigned short)csum)+(csum >> 16))>=0x10000) 15 | csum = (unsigned short)(csum + 1); 16 | 17 | if(((unsigned short *)pkt)[1] != csum) 18 | return; 19 | 20 | switch(type) { 21 | case 8: { 22 | ((unsigned char *)pkt)[0] = 0; 23 | csum = 0; 24 | for(i=0; i<((size+1)>>1); i++) 25 | csum += (unsigned short)~(i==1? 0 : ((short *)pkt)[i]); 26 | if((csum = ((unsigned short)csum)+(csum >> 16))>=0x10000) 27 | csum = (unsigned short)(csum + 1); 28 | ((short *)pkt)[1] = csum; 29 | ip_reply_packet(ippkt); 30 | break; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/target/network/icmp.h: -------------------------------------------------------------------------------- 1 | void icmp_got_packet(void *pkt, int size, void *ippkt); 2 | -------------------------------------------------------------------------------- /src/target/network/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "ether.h" 3 | #include "udp.h" 4 | #include "icmp.h" 5 | 6 | unsigned short htons(unsigned short n) 7 | { 8 | return (n>>8) | (n<<8); 9 | } 10 | 11 | static unsigned short id = 4711; 12 | 13 | void ip_got_packet(void *pkt, int size) 14 | { 15 | struct { 16 | unsigned char vers_ihl; 17 | unsigned char servicetype; 18 | unsigned short totlength; 19 | unsigned short ident; 20 | unsigned short fragment; 21 | unsigned char ttl; 22 | unsigned char proto; 23 | unsigned short hcsum; 24 | unsigned char source_ip[4]; 25 | unsigned char dest_ip[4]; 26 | } *ip_pkt = pkt; 27 | unsigned char *options = (unsigned char *)(ip_pkt + 1); 28 | int hdr_len, i, sz, csum = 0; 29 | 30 | if(size < 20 || (ip_pkt->vers_ihl>>4) != 4) 31 | return; 32 | 33 | if((hdr_len = ip_pkt->vers_ihl & 0xf)<5 || 34 | hdr_len > ((sz = htons(ip_pkt->totlength))>>2) || 35 | sz > size) 36 | return; 37 | 38 | pkt = ((unsigned int *)pkt) + hdr_len; 39 | size = sz - (hdr_len<<2); 40 | 41 | for(i=0; i<(hdr_len<<1); i++) 42 | csum += (unsigned short)~(i==5? 0 : ((short *)ip_pkt)[i]); 43 | 44 | if((csum = ((unsigned short)csum)+(csum >> 16))>=0x10000) 45 | csum = (unsigned short)(csum + 1); 46 | 47 | if(!csum) 48 | csum = 0xffff; 49 | 50 | if(ip_pkt->hcsum != csum) 51 | return; 52 | 53 | switch(ip_pkt->proto) { 54 | case 1: icmp_got_packet(pkt, size, ip_pkt); break; 55 | /* case 6: tcp_got_packet(pkt, size, ip_pkt); break; */ 56 | case 17: udp_got_packet(pkt, size, ip_pkt); break; 57 | } 58 | } 59 | 60 | void ip_low_reply_packet(void *pkt) 61 | { 62 | int sz = htons(((unsigned short *)pkt)[1])+14; 63 | int i, csum = 0; 64 | int hdr_len = (*(char *)pkt) & 0xf; 65 | 66 | ((unsigned short *)pkt)[2] = htons(id++); 67 | 68 | for(i=0; i<(hdr_len<<1); i++) 69 | csum += (unsigned short)~(i==5? 0 : ((short *)pkt)[i]); 70 | 71 | if((csum = ((unsigned short)csum)+(csum >> 16))>=0x10000) 72 | csum = (unsigned short)(csum + 1); 73 | 74 | ((unsigned short *)pkt)[5] = (csum? csum : 0xffff); 75 | 76 | ether_send_packet(((unsigned char *)pkt)-14, sz); 77 | } 78 | 79 | void ip_reply_packet(void *pkt) 80 | { 81 | unsigned char *p = ((unsigned char *)pkt)-14; 82 | int i, t; 83 | 84 | for(i=0; i<6; i++) { 85 | t = p[i]; p[i] = p[6+i]; p[6+i] = t; 86 | } 87 | for(i=0; i<4; i++) { 88 | t = p[14+12+i]; p[14+12+i] = p[14+12+4+i]; p[14+12+4+i] = t; 89 | } 90 | 91 | ip_low_reply_packet(pkt); 92 | } 93 | 94 | void ip_send_packet(void *target_hw, void *pkt) 95 | { 96 | unsigned char *p = ((unsigned char *)pkt)-14; 97 | int sz = htons(((unsigned short *)pkt)[1])+14; 98 | int i, csum = 0; 99 | 100 | ((unsigned short *)pkt)[0] = 5 | (4<<4); 101 | ((unsigned short *)pkt)[2] = htons(id++); 102 | ((unsigned short *)pkt)[3] = 2<<5; 103 | 104 | for(i=0; i<10; i++) 105 | csum += (unsigned short)~(i==5? 0 : ((short *)pkt)[i]); 106 | 107 | if((csum = ((unsigned short)csum)+(csum >> 16))>=0x10000) 108 | csum = (unsigned short)(csum + 1); 109 | 110 | ((unsigned short *)pkt)[5] = (csum? csum : 0xffff); 111 | 112 | ((unsigned short *)p)[6] = 8; 113 | for(i=0; i<6; i++) { 114 | p[i] = ((unsigned char *)target_hw)[i]; 115 | p[i+6] = ether_MAC[i]; 116 | } 117 | ether_send_packet(((unsigned char *)pkt)-14, sz); 118 | } 119 | 120 | static unsigned int my_ip = 0; 121 | static int ip_is_set = 0; 122 | 123 | void ip_set_my_ip(unsigned int *addr) 124 | { 125 | my_ip = *addr; 126 | ip_is_set = 1; 127 | } 128 | 129 | int ip_get_my_ip(unsigned int *addr) 130 | { 131 | *addr = my_ip; 132 | return ip_is_set; 133 | } 134 | -------------------------------------------------------------------------------- /src/target/network/ip.h: -------------------------------------------------------------------------------- 1 | unsigned short htons(unsigned short n); 2 | void ip_got_packet(void *pkt, int size); 3 | void ip_low_reply_packet(void *pkt); 4 | void ip_reply_packet(void *pkt); 5 | void ip_set_my_ip(unsigned int *addr); 6 | int ip_get_my_ip(unsigned int *addr); 7 | void ip_send_packet(void *target_hw, void *pkt); 8 | -------------------------------------------------------------------------------- /src/target/network/pci.c: -------------------------------------------------------------------------------- 1 | #include "pci.h" 2 | #include "util.h" 3 | 4 | #define G2_LOCK() \ 5 | int _s = getimask(); \ 6 | setimask(15); \ 7 | while((*(volatile unsigned int *)0xa05f688c) & 32) 8 | 9 | #define G2_UNLOCK() \ 10 | setimask(_s) 11 | 12 | int pci_setup() 13 | { 14 | int i; 15 | 16 | G2_LOCK(); 17 | 18 | for(i=0; i<16; i++) 19 | if(*(volatile char *)(void *)(0xa1001400+i) != "GAPSPCI_BRIDGE_2"[i]) { 20 | G2_UNLOCK(); 21 | return -1; 22 | } 23 | 24 | *(volatile unsigned int *)(void *)(0xa1001418) = 0x5a14a501; 25 | 26 | for(i=0; i<1000000; i++) 27 | ; 28 | 29 | if(*(volatile unsigned int *)(void *)(0xa1001418) != 1) { 30 | G2_UNLOCK(); 31 | return -1; 32 | } 33 | 34 | *(volatile unsigned int *)(void *)(0xa1001420) = 0x1000000; 35 | *(volatile unsigned int *)(void *)(0xa1001424) = 0x1000000; 36 | *(volatile unsigned int *)(void *)(0xa1001428) = 0x1840000; 37 | *(volatile unsigned int *)(void *)(0xa1001414) = 1; 38 | *(volatile unsigned int *)(void *)(0xa1001434) = 1; 39 | 40 | *(volatile unsigned short *)(void *)(0xa1001606) = 0xf900; 41 | *(volatile unsigned int *)(void *)(0xa1001630) = 0; 42 | *(volatile unsigned char *)(void *)(0xa100163c) = 0; 43 | *(volatile unsigned char *)(void *)(0xa100160d) = 0xf0; 44 | *(volatile unsigned short *)(void *)(0xa1001604) |= 6; 45 | *(volatile unsigned int *)(void *)(0xa1001614) = 0x1000000; 46 | 47 | if((*(volatile unsigned char *)(void *)(0xa1001650))&1) { 48 | G2_UNLOCK(); 49 | return -1; 50 | } 51 | 52 | G2_UNLOCK(); 53 | return 0; 54 | } 55 | 56 | void pci_teardown() 57 | { 58 | G2_LOCK(); 59 | *(volatile unsigned int *)(void *)(0xa1001418) = 0x5a14a500; 60 | G2_UNLOCK(); 61 | } 62 | 63 | unsigned int pci_read32(int reg) 64 | { 65 | unsigned int ret; 66 | G2_LOCK(); 67 | ret = *(volatile unsigned int*)(void *)(0xa1001700+reg); 68 | G2_UNLOCK(); 69 | return ret; 70 | } 71 | 72 | unsigned short pci_read16(int reg) 73 | { 74 | unsigned short ret; 75 | G2_LOCK(); 76 | ret = *(volatile unsigned short*)(void *)(0xa1001700+reg); 77 | G2_UNLOCK(); 78 | return ret; 79 | } 80 | 81 | unsigned char pci_read8(int reg) 82 | { 83 | unsigned char ret; 84 | G2_LOCK(); 85 | ret = *(volatile unsigned char*)(void *)(0xa1001700+reg); 86 | G2_UNLOCK(); 87 | return ret; 88 | } 89 | 90 | void pci_write32(int reg, unsigned int val) 91 | { 92 | G2_LOCK(); 93 | *(volatile unsigned int*)(void *)(0xa1001700+reg) = val; 94 | G2_UNLOCK(); 95 | } 96 | 97 | void pci_write16(int reg, unsigned short val) 98 | { 99 | G2_LOCK(); 100 | *(volatile unsigned short*)(void *)(0xa1001700+reg) = val; 101 | G2_UNLOCK(); 102 | } 103 | 104 | void pci_write8(int reg, unsigned char val) 105 | { 106 | G2_LOCK(); 107 | *(volatile unsigned char*)(void *)(0xa1001700+reg) = val; 108 | G2_UNLOCK(); 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/target/network/pci.h: -------------------------------------------------------------------------------- 1 | int pci_setup(void); 2 | void pci_teardown(void); 3 | unsigned int pci_read32(int reg); 4 | unsigned short pci_read16(int reg); 5 | unsigned char pci_read8(int reg); 6 | void pci_write32(int reg, unsigned int val); 7 | void pci_write16(int reg, unsigned short val); 8 | void pci_write8(int reg, unsigned char val); 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/target/network/udp.c: -------------------------------------------------------------------------------- 1 | #include "udp.h" 2 | #include "util.h" 3 | #include "proto.h" 4 | 5 | static int udp_calc_checksum(unsigned short *pkt, int sz, void *ip_pkt) 6 | { 7 | int i, csum = 0; 8 | 9 | if(sz & 1) 10 | ((unsigned char *)pkt)[sz] = 0; 11 | 12 | csum += (unsigned short)~((short *)ip_pkt)[6]; 13 | csum += (unsigned short)~((short *)ip_pkt)[7]; 14 | csum += (unsigned short)~((short *)ip_pkt)[8]; 15 | csum += (unsigned short)~((short *)ip_pkt)[9]; 16 | csum += (unsigned short)~(17<<8); 17 | csum += (unsigned short)~htons(sz); 18 | 19 | for(i=0; i<((sz+1)>>1); i++) 20 | if(i != 3) 21 | csum += (unsigned short)~((short *)pkt)[i]; 22 | 23 | if((csum = ((unsigned short)csum)+(csum >> 16))>=0x10000) 24 | csum = (unsigned short)(csum + 1); 25 | 26 | return (csum? csum : 0xffff); 27 | } 28 | 29 | void udp_got_packet(void *pkt, int size, void *ip_pkt) 30 | { 31 | int sz; 32 | if(size < 8) 33 | return; 34 | sz = htons(((unsigned short *)pkt)[2]); 35 | if(sz < size) 36 | size = sz; 37 | if(size < 8) 38 | return; 39 | switch(htons(((unsigned short *)pkt)[1])) { 40 | case CLIENT_PORT: 41 | proto_got_packet(((char *)pkt)+8, size-8, ip_pkt); 42 | break; 43 | } 44 | } 45 | 46 | void udp_send_packet(void *target_hw, unsigned int target_ip, 47 | unsigned short src_port, unsigned short target_port, 48 | void *pkt, unsigned size) 49 | { 50 | static unsigned short udppkt[64]; 51 | udppkt[9] = htons(28+size); 52 | udppkt[12] = (17<<8)|1; 53 | udppkt[18] = htons(src_port); 54 | udppkt[19] = htons(target_port); 55 | udppkt[20] = htons(8+size); 56 | if(size) 57 | memcpy(udppkt+22, pkt, size); 58 | ip_get_my_ip((unsigned int *)&udppkt[14]); 59 | *(unsigned int *)&udppkt[16] = target_ip; 60 | udppkt[21] = 0/*udp_calc_checksum(udppkt+18, size, udppkt+8)*/; 61 | ip_send_packet(target_hw, udppkt+8); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/target/network/udp.h: -------------------------------------------------------------------------------- 1 | void udp_got_packet(void *pkt, int size, void *ip_pkt); 2 | void udp_send_packet(void *target_hw, unsigned int target_ip, 3 | unsigned short src_port, unsigned short target_port, 4 | void *pkt, unsigned size); 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/target/skel/Makefile.in: -------------------------------------------------------------------------------- 1 | AS = @DCAS@ 2 | LD = @DCLD@ 3 | CC = @DCCC@ 4 | AR = @DCAR@ 5 | OBJCOPY = @DCOBJCOPY@ 6 | CFLAGS = @DCCFLAGS@ -I$(top_srcdir)/common -I$(top_srcdir)/network 7 | 8 | top_srcdir=@top_srcdir@ 9 | top_builddir=@top_builddir@ 10 | srcdir=@srcdir@ 11 | VPATH=@srcdir@ 12 | 13 | SUBBASEADDR=0x8c008300 14 | 15 | OBJS = sub.o schandler.o 16 | LIBS = $(top_builddir)/network/libnetwork.a $(top_builddir)/common/libcommon.a 17 | 18 | all : sub.bin 19 | 20 | sub.bin : sub.elf 21 | $(OBJCOPY) -O binary -R .stack $^ $@ 22 | 23 | sub.elf : $(OBJS) $(LIBS) 24 | $(CC) -o $@ -Wl,--oformat,elf32-shl,-Ttext=$(SUBBASEADDR) -nostartfiles -nostdlib $(OBJS) $(LIBS) -lgcc 25 | 26 | clean : 27 | -rm -f sub.bin $(OBJS) 28 | 29 | sub.o : sub.s 30 | 31 | schandler.o : schandler.c $(top_srcdir)/network/pci.h $(top_srcdir)/network/ether.h $(top_srcdir)/common/proto.h $(top_srcdir)/common/util.h 32 | 33 | -------------------------------------------------------------------------------- /src/target/skel/schandler.c: -------------------------------------------------------------------------------- 1 | #include "pci.h" 2 | #include "ether.h" 3 | #include "proto.h" 4 | #include "util.h" 5 | 6 | #define MAX_CMD 47 7 | 8 | static char param_cnt[MAX_CMD+1] = { 9 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-9 */ 10 | 0, 0, 0, 0, 0, 0, 4, 4, 0, 2, /* 10-19 */ 11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20-29 */ 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30-39 */ 13 | 0, 0, 0, 0, 0, 0, 0, 0, /* 40-47 */ 14 | }; 15 | 16 | int gdrom_send_command(int cmd, int *params) 17 | { 18 | int id, s; 19 | if(cmd<0 || cmd>MAX_CMD) 20 | return 0; 21 | s = getimask(); 22 | setimask(15); 23 | id = send_command_packet(cmd, params, param_cnt[cmd]); 24 | setimask(s); 25 | return(id<0? 0 : id+1); 26 | } 27 | 28 | int low_gdrom_check_command(int id, int *status) 29 | { 30 | int *p, r = check_command_packet(id-1); 31 | if(r<0) 32 | return 0; 33 | else if(!r) 34 | return 1; 35 | p = get_packet_slot(id-1); 36 | memcpy(status, p+3, 4*sizeof(int)); 37 | if(p[2]<0) 38 | return -1; 39 | else 40 | return 2; 41 | } 42 | 43 | int gdrom_check_command(int id, int *status) 44 | { 45 | int r, s; 46 | s = getimask(); 47 | setimask(15); 48 | r = low_gdrom_check_command(id, status); 49 | /* 50 | if(r<0) 51 | wait_command_packet(send_command_packet(status[0]+600, 0L, 0)); 52 | else 53 | wait_command_packet(send_command_packet(r+500, 0L, 0)); 54 | */ 55 | setimask(s); 56 | return r; 57 | } 58 | 59 | int gdrom_mainloop() 60 | { 61 | extern int num_commands, num_resends; 62 | static int fallback=0; 63 | int s = getimask(); 64 | setimask(15); 65 | if(fallback) { 66 | idle(); 67 | if(num_commands < 2) 68 | fallback = 0; 69 | } else { 70 | background_process(); 71 | if(num_commands > 1 && num_resends > 20 * num_commands) 72 | fallback = 1; 73 | } 74 | setimask(s); 75 | return 0; 76 | } 77 | 78 | int gdrom_init() 79 | { 80 | extern int num_commands, num_resends; 81 | int s = getimask(); 82 | setimask(15); 83 | if(pci_setup() >=0 && 84 | ether_setup() >= 0 && 85 | wait_command_packet(send_command_packet(991, 0L, 0)) >= 0) { 86 | num_commands = num_resends = 0; 87 | setimask(s); 88 | return 0; 89 | } else { 90 | setimask(s); 91 | return -1; 92 | } 93 | } 94 | 95 | int gdrom_check_drive(int *ret) 96 | { 97 | ret[0] = 1; 98 | ret[1] = 0x80; 99 | return 0; 100 | } 101 | 102 | int gdrom_reset() 103 | { 104 | return 0; 105 | } 106 | 107 | int gdrom_sector_mode(int *mode) 108 | { 109 | if(mode[0]==0) 110 | return 0; 111 | else if(mode[0]==1) { 112 | mode[1] = 8192; 113 | mode[2] = 1024; 114 | mode[3] = 2048; 115 | } else 116 | return -1; 117 | } 118 | 119 | int unimpl_syscall(int r4, int r5, int r6, int r7) 120 | { 121 | setimask(15); 122 | wait_command_packet(send_command_packet(800+r7, 0L, 0)); 123 | for(;;) { 124 | *(volatile unsigned int *)(void *)0xa05f8040 = 0x0000ff00; 125 | *(volatile unsigned int *)(void *)0xa05f8040 = 0x000000ff; 126 | } 127 | return -1; 128 | } 129 | 130 | void init(unsigned int my_ip, unsigned int server_ip, void *server_mac) 131 | { 132 | ip_set_my_ip(&my_ip); 133 | set_server(&server_ip, server_mac); 134 | } 135 | -------------------------------------------------------------------------------- /src/target/skel/sub.s: -------------------------------------------------------------------------------- 1 | 2 | .globl start 3 | 4 | .text 5 | 6 | .align 2 7 | 8 | start: 9 | rts 10 | nop 11 | bra enable 12 | nop 13 | bra disable 14 | nop 15 | bra reset 16 | nop 17 | 18 | 19 | enable: 20 | mova handler,r0 21 | mov.l isysc_vector,r1 22 | mov.l @r1,r2 23 | cmp/eq r0,r1 24 | bt .done_already 25 | mov.l r0,@r1 26 | mov.l r2,@(real_vector-handler,r0) 27 | .done_already: 28 | mov.l bss_start_addr,r0 29 | mov.l bss_end_addr,r2 30 | mov #3,r1 31 | add r1,r0 32 | add r1,r2 33 | not r1,r1 34 | and r1,r0 35 | and r1,r2 36 | sub r0,r2 37 | shlr r2 38 | shlr r2 39 | mov #0,r1 40 | .loop: dt r2 41 | mov.l r1,@r0 42 | bf/s .loop 43 | add #4,r0 44 | mov.l mainaddr,r0 45 | jmp @r0 46 | nop 47 | 48 | disable: 49 | rts 50 | nop 51 | 52 | reset: 53 | rts 54 | nop 55 | 56 | .align 4 57 | 58 | mainaddr: 59 | .long _init 60 | 61 | 62 | .align 4 63 | 64 | handler: 65 | tst r6,r6 66 | bt .new_syscall 67 | mov.l real_vector,r0 68 | jsr @r0 69 | sts.l pr,@-r15 70 | mov.l isysc_vector,r4 71 | lds.l @r15+,pr 72 | mov.l iinstall_addr,r1 73 | rts 74 | mov.l r1,@r4 75 | 76 | .new_syscall: 77 | mov #16,r0 78 | cmp/hi r0,r7 79 | bt .badsysc 80 | shll2 r7 81 | mova jtable,r0 82 | mov.l @(r0,r7),r0 83 | shlr r7 84 | jmp @r0 85 | shlr r7 86 | .badsysc: 87 | rts 88 | mov #-1,r0 89 | 90 | 91 | .align 4 92 | 93 | real_vector: 94 | .long 0 95 | isysc_vector: 96 | .long 0x8c0000bc 97 | iinstall_addr: 98 | .long handler 99 | bss_start_addr: 100 | .long __bss_start 101 | bss_end_addr: 102 | .long _end 103 | 104 | jtable: 105 | .long _gdrom_send_command ! 0 106 | .long _gdrom_check_command 107 | .long _gdrom_mainloop 108 | .long _gdrom_init 109 | .long _gdrom_check_drive ! 4 110 | .long _unimpl_syscall 111 | .long _unimpl_syscall 112 | .long _unimpl_syscall 113 | .long _unimpl_syscall ! 8 114 | .long _gdrom_reset 115 | .long _gdrom_sector_mode 116 | .long _unimpl_syscall 117 | .long _unimpl_syscall ! 12 118 | .long _unimpl_syscall 119 | .long _unimpl_syscall 120 | .long _unimpl_syscall 121 | 122 | 123 | 124 | 125 | --------------------------------------------------------------------------------