/[pcsx2_0.9.7]/trunk/pcsx2/IopBios.cpp
ViewVC logotype

Contents of /trunk/pcsx2/IopBios.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months ago) by william
File size: 13969 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16
17 #include "PrecompiledHeader.h"
18 #include "IopCommon.h"
19 #include "R5900.h" // for g_GameStarted
20
21 #include <ctype.h>
22 #include <string.h>
23
24 #ifndef O_BINARY
25 #define O_BINARY 0
26 #endif
27
28 // set this to 0 to disable rewriting 'host:' paths!
29 #define USE_HOST_REWRITE 1
30
31 #if USE_HOST_REWRITE
32 # ifdef WIN32
33 // disable this if you DON'T want "host:/usr/local/" paths
34 // to get rewritten into host:/
35 # define HOST_REWRITE_USR_LOCAL 1
36 # else
37 // unix/linux users might want to set it to 1
38 // if they DO want to keep demos from accessing their systems' /usr/local
39 # define HOST_REWRITE_USR_LOCAL 0
40 # endif
41
42 static char HostRoot[1024];
43 #endif
44
45 void Hle_SetElfPath(const char* elfFileName)
46 {
47 #if USE_HOST_REWRITE
48 DevCon.WriteLn("HLE Host: Will load ELF: %s\n", elfFileName);
49
50 const char* pos1 = strrchr(elfFileName,'/');
51 const char* pos2 = strrchr(elfFileName,'\\');
52
53 if(pos2 > pos1) // we want the LAST path separator
54 pos1=pos2;
55
56 if(!pos1) // if pos1 is NULL, then pos2 was not > pos1, so it must also be NULL
57 {
58 Console.Warning("HLE Warning: ELF does not have a path!!\n");
59
60 // use %CD%/host/
61 getcwd(HostRoot,1000); // save the other 23 chars to append /host/ :P
62 HostRoot[1000]=0; // Be Safe.
63
64 char* last = HostRoot + strlen(HostRoot) - 1;
65
66 if((*last!='/') && (*last!='\\')) // PathAppend()-ish
67 last++;
68
69 strcpy(last,"/host/");
70
71 return;
72 }
73
74 int len = pos1-elfFileName+1;
75 memcpy(HostRoot,elfFileName,len); // include the / (or \\)
76 HostRoot[len] = 0;
77
78 Console.WriteLn("HLE Host: Set 'host:' root path to: %s\n", HostRoot);
79
80 #endif
81 }
82
83 namespace R3000A {
84
85 #define v0 (psxRegs.GPR.n.v0)
86 #define a0 (psxRegs.GPR.n.a0)
87 #define a1 (psxRegs.GPR.n.a1)
88 #define a2 (psxRegs.GPR.n.a2)
89 #define a3 (psxRegs.GPR.n.a3)
90 #define sp (psxRegs.GPR.n.sp)
91 #define ra (psxRegs.GPR.n.ra)
92 #define pc (psxRegs.pc)
93
94 #define Ra0 (iopVirtMemR<char>(a0))
95 #define Ra1 (iopVirtMemR<char>(a1))
96 #define Ra2 (iopVirtMemR<char>(a2))
97 #define Ra3 (iopVirtMemR<char>(a3))
98
99 // TODO: sandbox option, other permissions
100 class HostFile : public IOManFile
101 {
102 public:
103 int fd;
104
105 HostFile(int hostfd)
106 {
107 fd = hostfd;
108 }
109
110 static __fi int translate_error(int err)
111 {
112 if (err >= 0)
113 return err;
114
115 switch(err)
116 {
117 case -ENOENT:
118 return -IOP_ENOENT;
119 case -EACCES:
120 return -IOP_EACCES;
121 case -EISDIR:
122 return -IOP_EISDIR;
123 case -EIO:
124 default:
125 return -IOP_EIO;
126 }
127 }
128
129 static int open(IOManFile **file, const char *name, s32 flags, u16 mode)
130 {
131 const char *path = strchr(name, ':') + 1;
132
133 // host: actually DOES let you write!
134 //if (flags != IOP_O_RDONLY)
135 // return -IOP_EROFS;
136
137 // WIP code. Works well on win32, not so sure on unixes
138 // TODO: get rid of dependency on CWD/PWD
139 #if USE_HOST_REWRITE
140 // we want filenames to be relative to pcs2dir / host
141
142 static char pathMod[1024];
143
144 // partial "rooting",
145 // it will NOT avoid a path like "../../x" from escaping the pcsx2 folder!
146
147 #if HOST_REWRITE_USR_LOCAL
148 const char *_local_root = "/usr/local/";
149 if(strncmp(path,_local_root,strlen(_local_root))==0)
150 {
151 strcpy(pathMod,HostRoot);
152 strcat(pathMod,path+strlen(_local_root));
153 }
154 else
155 #endif
156 if((path[0] == '/') || (path[0] == '\\') || (isalpha(path[0]) && (path[1] == ':'))) // absolute NATIVE path (X:\blah)
157 {
158 // TODO: allow some way to use native paths in non-windows platforms
159 // maybe hack it so linux prefixes the path with "X:"? ;P
160 // or have all platforms use a common prefix for native paths
161 strcpy(pathMod,path);
162 }
163 else // relative paths
164 {
165 strcpy(pathMod,HostRoot);
166 strcat(pathMod,path);
167 }
168 #else
169 const char* pathMod = path;
170 #endif
171
172 int native_flags = O_BINARY; // necessary in Windows.
173
174 switch(flags&IOP_O_RDWR)
175 {
176 case IOP_O_RDONLY: native_flags |= O_RDONLY; break;
177 case IOP_O_WRONLY: native_flags |= O_WRONLY; break;
178 case IOP_O_RDWR: native_flags |= O_RDWR; break;
179 }
180
181 if(flags&IOP_O_APPEND) native_flags |= O_APPEND;
182 if(flags&IOP_O_CREAT) native_flags |= O_CREAT;
183 if(flags&IOP_O_TRUNC) native_flags |= O_TRUNC;
184
185 int hostfd = ::open(pathMod, native_flags);
186 if (hostfd < 0)
187 return translate_error(hostfd);
188
189 *file = new HostFile(hostfd);
190 if (!*file)
191 return -IOP_ENOMEM;
192
193 return 0;
194 }
195
196 virtual void close()
197 {
198 ::close(fd);
199 delete this;
200 }
201
202 virtual int lseek(s32 offset, s32 whence)
203 {
204 int err;
205
206 switch (whence)
207 {
208 case IOP_SEEK_SET:
209 err = ::lseek(fd, offset, SEEK_SET);
210 break;
211 case IOP_SEEK_CUR:
212 err = ::lseek(fd, offset, SEEK_CUR);
213 break;
214 case IOP_SEEK_END:
215 err = ::lseek(fd, offset, SEEK_END);
216 break;
217 default:
218 return -IOP_EIO;
219 }
220
221 return translate_error(err);
222 }
223
224 virtual int read(void *buf, u32 count)
225 {
226 return translate_error(::read(fd, buf, count));
227 }
228
229 virtual int write(void *buf, u32 count)
230 {
231 return translate_error(::write(fd, buf, count));
232 }
233 };
234
235 namespace ioman {
236 const int firstfd = 0x100;
237 const int maxfds = 0x100;
238 int openfds = 0;
239
240 int freefdcount()
241 {
242 return maxfds - openfds;
243 }
244
245 struct filedesc
246 {
247 enum {
248 FILE_FREE,
249 FILE_FILE,
250 FILE_DIR,
251 } type;
252 union {
253 IOManFile *file;
254 IOManDir *dir;
255 };
256
257 operator bool() const { return type != FILE_FREE; }
258 operator IOManFile*() const { return type == FILE_FILE ? file : NULL; }
259 operator IOManDir*() const { return type == FILE_DIR ? dir : NULL; }
260 void operator=(IOManFile *f) { type = FILE_FILE; file = f; openfds++; }
261 void operator=(IOManDir *d) { type = FILE_DIR; dir = d; openfds++; }
262
263 void close()
264 {
265 if (type == FILE_FREE)
266 return;
267
268 switch (type)
269 {
270 case FILE_FILE:
271 file->close();
272 file = NULL;
273 break;
274 case FILE_DIR:
275 dir->close();
276 dir = NULL;
277 break;
278 }
279
280 type = FILE_FREE;
281 openfds--;
282 }
283 };
284
285 filedesc fds[maxfds];
286
287 template<typename T>
288 T* getfd(int fd)
289 {
290 fd -= firstfd;
291
292 if (fd < 0 || fd >= maxfds)
293 return NULL;
294
295 return fds[fd];
296 }
297
298 template <typename T>
299 int allocfd(T *obj)
300 {
301 for (int i = 0; i < maxfds; i++)
302 {
303 if (!fds[i])
304 {
305 fds[i] = obj;
306 return firstfd + i;
307 }
308 }
309
310 obj->close();
311 return -IOP_EMFILE;
312 }
313
314 void freefd(int fd)
315 {
316 fd -= firstfd;
317
318 if (fd < 0 || fd >= maxfds)
319 return;
320
321 fds[fd].close();
322 }
323
324 void reset()
325 {
326 for (int i = 0; i < maxfds; i++)
327 fds[i].close();
328 }
329
330 int open_HLE()
331 {
332 IOManFile *file = NULL;
333 const char *name = Ra0;
334 s32 flags = a1;
335 u16 mode = a2;
336
337 if ((!g_GameStarted || EmuConfig.HostFs)
338 && !strncmp(name, "host", 4) && name[4 + strspn(name + 4, "0123456789")] == ':')
339 {
340 if (!freefdcount())
341 {
342 v0 = -IOP_EMFILE;
343 pc = ra;
344 return 1;
345 }
346
347 int err = HostFile::open(&file, name, flags, mode);
348
349 if (err != 0 || !file)
350 {
351 if (err == 0) // ???
352 err = -IOP_EIO;
353 if (file) // ??????
354 file->close();
355 v0 = err;
356 }
357 else
358 {
359 v0 = allocfd(file);
360 if ((s32)v0 < 0)
361 file->close();
362 }
363
364 pc = ra;
365 return 1;
366 }
367
368 return 0;
369 }
370
371 int close_HLE()
372 {
373 s32 fd = a0;
374
375 if (getfd<IOManFile>(fd))
376 {
377 freefd(fd);
378 v0 = 0;
379 pc = ra;
380 return 1;
381 }
382
383 return 0;
384 }
385
386 int lseek_HLE()
387 {
388 s32 fd = a0;
389 s32 offset = a1;
390 s32 whence = a2;
391
392 if (IOManFile *file = getfd<IOManFile>(fd))
393 {
394 v0 = file->lseek(offset, whence);
395 pc = ra;
396 return 1;
397 }
398
399 return 0;
400 }
401
402 int read_HLE()
403 {
404 s32 fd = a0;
405 u32 buf = a1;
406 u32 count = a2;
407
408 if (IOManFile *file = getfd<IOManFile>(fd))
409 {
410 if (!iopVirtMemR<void>(buf))
411 return 0;
412
413 v0 = file->read(iopVirtMemW<void>(buf), count);
414 pc = ra;
415 return 1;
416 }
417
418 return 0;
419 }
420
421 int write_HLE()
422 {
423 s32 fd = a0;
424 u32 buf = a1;
425 u32 count = a2;
426
427 if (fd == 1) // stdout
428 {
429 iopConLog(ShiftJIS_ConvertString(Ra1, a2));
430 pc = ra;
431 v0 = a2;
432 return 1;
433 }
434 else if (IOManFile *file = getfd<IOManFile>(fd))
435 {
436 if (!iopVirtMemR<void>(buf))
437 return 0;
438
439 v0 = file->write(iopVirtMemW<void>(buf), count);
440 pc = ra;
441 return 1;
442 }
443
444 return 0;
445 }
446 }
447
448 namespace sysmem {
449 int Kprintf_HLE()
450 {
451 // Emulate the expected Kprintf functionality:
452 iopMemWrite32(sp, a0);
453 iopMemWrite32(sp + 4, a1);
454 iopMemWrite32(sp + 8, a2);
455 iopMemWrite32(sp + 12, a3);
456 pc = ra;
457
458
459 // From here we're intercepting the Kprintf and piping it to our console, complete with
460 // printf-style formatting processing. This part can be skipped if the user has the
461 // console disabled.
462
463 if (!SysConsole.iopConsole.IsActive()) return 1;
464
465 char tmp[1024], tmp2[1024];
466 char *ptmp = tmp;
467 int n=1, i=0, j = 0;
468
469 while (Ra0[i])
470 {
471 switch (Ra0[i])
472 {
473 case '%':
474 j = 0;
475 tmp2[j++] = '%';
476 _start:
477 switch (Ra0[++i])
478 {
479 case '.':
480 case 'l':
481 tmp2[j++] = Ra0[i];
482 goto _start;
483 default:
484 if (Ra0[i] >= '0' && Ra0[i] <= '9')
485 {
486 tmp2[j++] = Ra0[i];
487 goto _start;
488 }
489 break;
490 }
491
492 tmp2[j++] = Ra0[i];
493 tmp2[j] = 0;
494
495 switch (Ra0[i])
496 {
497 case 'f': case 'F':
498 ptmp+= sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4));
499 n++;
500 break;
501
502 case 'a': case 'A':
503 case 'e': case 'E':
504 case 'g': case 'G':
505 ptmp+= sprintf(ptmp, tmp2, (double)iopMemRead32(sp + n * 4));
506 n++;
507 break;
508
509 case 'p':
510 case 'i':
511 case 'd': case 'D':
512 case 'o': case 'O':
513 case 'x': case 'X':
514 ptmp+= sprintf(ptmp, tmp2, (u32)iopMemRead32(sp + n * 4));
515 n++;
516 break;
517
518 case 'c':
519 ptmp+= sprintf(ptmp, tmp2, (u8)iopMemRead32(sp + n * 4));
520 n++;
521 break;
522
523 case 's':
524 ptmp+= sprintf(ptmp, tmp2, iopVirtMemR<char>(iopMemRead32(sp + n * 4)));
525 n++;
526 break;
527
528 case '%':
529 *ptmp++ = Ra0[i];
530 break;
531
532 default:
533 break;
534 }
535 i++;
536 break;
537
538 default:
539 *ptmp++ = Ra0[i++];
540 break;
541 }
542 }
543 *ptmp = 0;
544 iopConLog( ShiftJIS_ConvertString(tmp, 1023) );
545
546 return 1;
547 }
548 }
549
550 namespace loadcore {
551 void RegisterLibraryEntries_DEBUG()
552 {
553 DbgCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s", iopVirtMemR<char>(a0 + 12));
554 }
555 }
556
557 namespace intrman {
558 static const char* intrname[] = {
559 "INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00
560 "INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04
561 "INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08
562 "INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C
563 "INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10
564 "INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14
565 "INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18
566 "INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C
567 "INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20
568 "INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24
569 "INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28
570 "INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C
571 "INT_30", "INT_31", "INT_32", "INT_33", //30
572 "INT_34", "INT_35", "INT_36", "INT_37", //34
573 "INT_38", "INT_39", "INT_3A", "INT_3B", //38
574 "INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C
575 "INT_MAX" //40
576 };
577
578 void RegisterIntrHandler_DEBUG()
579 {
580 DbgCon.WriteLn(Color_Gray, "RegisterIntrHandler: intr %s, handler %x", intrname[a0], a2);
581 }
582 }
583
584 namespace sifcmd {
585 void sceSifRegisterRpc_DEBUG()
586 {
587 DbgCon.WriteLn( Color_Gray, "sifcmd sceSifRegisterRpc: rpc_id %x", a1);
588 }
589 }
590
591 const char* irxImportLibname(u32 entrypc)
592 {
593 u32 i;
594
595 i = entrypc;
596 while (iopMemRead32(i -= 4) != 0x41e00000) // documented magic number
597 ;
598
599 return iopVirtMemR<char>(i + 12);
600 }
601
602 const char* irxImportFuncname(const char libname[8], u16 index)
603 {
604 #include "IopModuleNames.cpp"
605
606 switch (index) {
607 case 0: return "start";
608 // case 1: reinit?
609 case 2: return "shutdown";
610 // case 3: ???
611 }
612
613 return 0;
614 }
615
616 #define MODULE(n) if (!strncmp(libname, #n, 8)) { using namespace n; switch (index) {
617 #define END_MODULE }}
618 #define EXPORT_D(i, n) case (i): return n ## _DEBUG;
619 #define EXPORT_H(i, n) case (i): return n ## _HLE;
620
621 irxHLE irxImportHLE(const char libname[8], u16 index)
622 {
623 // debugging output
624 MODULE(sysmem)
625 EXPORT_H( 14, Kprintf)
626 END_MODULE
627
628 MODULE(ioman)
629 EXPORT_H( 4, open)
630 EXPORT_H( 5, close)
631 EXPORT_H( 6, read)
632 EXPORT_H( 7, write)
633 EXPORT_H( 8, lseek)
634 END_MODULE
635
636 return 0;
637 }
638
639 irxDEBUG irxImportDebug(const char libname[8], u16 index)
640 {
641 MODULE(loadcore)
642 EXPORT_D( 6, RegisterLibraryEntries)
643 END_MODULE
644 MODULE(intrman)
645 EXPORT_D( 4, RegisterIntrHandler)
646 END_MODULE
647 MODULE(sifcmd)
648 EXPORT_D( 17, sceSifRegisterRpc)
649 END_MODULE
650
651 return 0;
652 }
653
654 #undef MODULE
655 #undef END_MODULE
656 #undef EXPORT_D
657 #undef EXPORT_H
658
659 void __fastcall irxImportLog(const char libname[8], u16 index, const char *funcname)
660 {
661 PSXBIOS_LOG("%8.8s.%03d: %s (%x, %x, %x, %x)",
662 libname, index, funcname ? funcname : "unknown",
663 a0, a1, a2, a3);
664 }
665
666 int __fastcall irxImportExec(const char libname[8], u16 index)
667 {
668 const char *funcname = irxImportFuncname(libname, index);
669 irxHLE hle = irxImportHLE(libname, index);
670 irxDEBUG debug = irxImportDebug(libname, index);
671
672 irxImportLog(libname, index, funcname);
673
674 if (debug)
675 debug();
676
677 if (hle)
678 return hle();
679 else
680 return 0;
681 }
682
683 } // end namespace R3000A

  ViewVC Help
Powered by ViewVC 1.1.22