Ipc.c
Jump to navigation
Jump to search
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
// Copyright 2007,2008 tmbinc
// Copyright 2007,2008 bushing
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <console.h>
#include <processor.h>
#include <string.h>
#include <cache.h>
#include <time.h>
#define PHYSADDR(x) ((unsigned long *)(0x7FFFFFFF & ((unsigned long)(x))))
#define VIRTADDR(x) ((unsigned long *)(0x80000000 | ((unsigned long)(x))))
unsigned long IPCReadReg(unsigned long reg) {
unsigned long *IPCBase=(unsigned long *)0xCD000000;
return IPCBase[reg];
}
void IPCWriteReg(unsigned long reg, unsigned long value) {
unsigned long *IPCBase=(unsigned long *)0xCD000000;
IPCBase[reg] = value;
}
void dump_buffer(unsigned long _ptr, int size) {
u32 *ptr = VIRTADDR(_ptr);
int i;
printf("ptr=%p, size=%x ", ptr, size);
for (i=0; i<size/4; i++) printf("%08x ", ptr[i]);
printf("\n");
}
void IPCInterruptHandler() {
if ((IPCReadReg(1) & 0x14) == 0x14) {
printf("IPCInterruptHandler: have reply.\n");
int reply_ptr = IPCReadReg(2);
if (!reply_ptr)
printf("no reply ptr?\n");
else
{
unsigned int *reply = (void*)(reply_ptr | 0x80000000);
dcache_inv(reply, 0x40);
IPCWriteReg(1, (IPCReadReg(1) & 0x30) | 4); /* reply early ack */
int command = reply[2];
printf("reply_command: %d\n", command);
switch (command) {
case 3: // read
{
int _ptr = reply[3];
int size = reply[1];
printf("read: "); dump_buffer(_ptr, size);
break;
}
case 6: // ioctl
{
printf("command ioctl: retval=%d, fd=%d, request=%x, in={%08x, %08x}, out={%08x, %08x}\n",
reply[1], reply[2], reply[3], reply[4], reply[5], reply[6], reply[7]);
printf("in: "); dump_buffer(reply[4], reply[5]);
printf("out: "); dump_buffer(reply[6], reply[7]);
break;
}
case 7: // ioctlv
{
int i;
unsigned int *vec = (void*)(reply[6] | 0x80000000);
int in = reply[4], out = reply[5];
dcache_inv(vec, (in+out)*8);
printf("command ioctlv: retval=%d, fd=%d, request=%x, in=%d out=%d ptr=%p\n",
reply[1], reply[2], reply[3], in, out, vec);
for (i=0; i<(in+out); i++) {
if (i<in) printf("In: ");
else printf("Out: ");
dump_buffer(vec[i*2], vec[i*2+1]);
}
break;
}
default:
printf("unknown reply command\n");
}
if (reply[8])
printf("callback: ptr=%08x, a=%08x b=%08x\n",
reply[8], reply[1], reply[9]); */
IPCWriteReg(1, (IPCReadReg(1) & 0x30) | 8); /* end of reply */
}
}
if ((IPCReadReg(1) & 0x22 ) == 0x22) {
printf("whatever-has-been-done\n");
IPCWriteReg(1, (IPCReadReg(1) & 0x30) | 2);
*(unsigned long*)0xCD000030 = 0x40000000;
}
}
void ipc_bell(int w)
{
IPCWriteReg(1, (IPCReadReg(1) & 0x30) | w);
}
int ipc_receive(void)
{
if ((IPCReadReg(1) & 0x14) == 0x14)
{
int reply_ptr = IPCReadReg(2);
if (!reply_ptr)
printf("no reply ptr?\n");
else
{
unsigned int *reply = (void*)(reply_ptr | 0x80000000);
dcache_inv(reply, 0x40);
ipc_bell(4); /* reply early ack */
printf("reply: ");
dump_buffer(reply, 0x30);
printf("reply [cmd=%d, data=%08x/%d, a={%08x,%08x}, b={%08x,%08x}, cb=%p]\n",
reply[2], reply[3], reply[1], reply[4], reply[5], reply[6], reply[7], reply[8]);
ipc_bell(8); /* end of reply */
}
return 1;
}
return 0;
}
void ipc_send(void *cmd)
{
int i;
printf("ipc_send(%p) sending packet:\n");
dump_buffer(cmd, 0x30);
dcache_flush(cmd, 0x30);
IPCWriteReg(0, ((int)cmd) & 0x7FFFFFFF);
ipc_bell(1);
// printf("waiting for ack...\n");
while ((IPCReadReg(1) & 0x22 ) != 0x22);
ipc_bell(2);
*(unsigned long*)0xCD000030 = 0x40000000; /* ack IRQ */
}
void ipc_wait(void)
{
while (1)
{
int res = ipc_receive();
if (res)
break;
}
}
/*
1 - open
2 - close
3 - read
4 - write
5 - seek
6 - ioctl
7 - ioctlv
*/
int ios_ioctl(int fd, int ioctl_no, u8 *inbuf, int inlen, u8 *outbuf, int outlen)
{
static unsigned int cmd[0x40];
int inptr = ((int)inbuf) & 0x7FFFFFFF;
int outptr = ((int)outbuf) & 0x7FFFFFFF;
memset(cmd, 0, sizeof(cmd));
printf("ios_ioctl(%d, %d, %p, %d, %p, %d)\n", fd, ioctl_no, inbuf, inlen, outbuf, outlen);
if(inbuf && inlen) dcache_flush(inptr, inlen);
if(outbuf && outlen) dcache_flush(outptr, outlen);
cmd[0] = 6;
cmd[2] = fd;
cmd[3] = ioctl_no;
cmd[4] = inptr;
cmd[5] = inlen;
cmd[6] = outptr;
cmd[7] = outlen;
ipc_send(cmd);
ipc_wait();
printf("result=%d\n", cmd[1]);
if(inbuf && inlen) dcache_flush(inptr, inlen);
if(outbuf && outlen) dcache_flush(outptr, outlen);
return cmd[1];
}
int ios_ioctlv(int fd, int ioctl_no, int in_count, int out_count, u32* vec)
{
static unsigned int cmd[0x40];
int i;
memset(cmd, 0, sizeof(cmd));
printf("ios_ioctlv(%d, %d, %d, %d, %p)\n", fd, ioctl_no, in_count, out_count, vec);
dcache_flush(PHYSADDR(vec), (in_count + out_count)*8);
printf("vec = ");
dump_buffer(vec, (in_count + out_count)*8);
for (i=0; i<in_count; i++) {
int inptr = PHYSADDR(vec[i*2]);
printf("in: ");
dump_buffer(vec[i*2], vec[i*2+1]);
if(inptr && vec[i*2+1]) dcache_flush(inptr, vec[i*2+1]);
}
for (i=in_count; i<in_count+out_count; i++) {
int outptr = PHYSADDR(vec[i*2]);
printf("out: ");
dump_buffer(vec[i*2], vec[i*2+1]);
if(outptr && vec[i*2+1]) dcache_flush(outptr, vec[i*2+1]);
}
cmd[0] = 7;
//cmd[1] is retval
cmd[2] = fd;
cmd[3] = ioctl_no;
cmd[4] = in_count;
cmd[5] = out_count;
cmd[6] = PHYSADDR(vec);
ipc_send(cmd);
ipc_wait();
printf("result=%d\n", cmd[1]);
for (i=0; i<in_count; i++) {
int inptr = vec[i*2] & 0x7FFFFFFF;
printf("in: addr %x, len %d\n", inptr, vec[i*2+1]);
if(inptr && vec[i*2+1]) dcache_flush(inptr, vec[i*2+1]);
}
for (i=in_count; i<in_count+out_count; i++) {
int outptr = vec[i*2] & 0x7FFFFFFF;
printf("out: addr %x, len %d\n", outptr, vec[i*2+1]);
if(outptr && vec[i*2+1]) dcache_flush(outptr, vec[i*2+1]);
}
return cmd[1];
}
int isfs_readdir(const char *filename) {
u32 *ipc_buf_1 = 0x933e0820, *ipc_buf_2 = 0x933e0840, *ipc_buf_3 = 0x933e0880;
int fs_fd = ios_open("/dev/fs");
int retval;
printf("ios_open(/dev/fs) = %d\n", fs_fd);
if (fs_fd<0) return fs_fd;
ipc_buf_1[0]=PHYSADDR(ipc_buf_2);
ipc_buf_1[1]=0x40;
ipc_buf_1[2]=PHYSADDR(ipc_buf_3);
ipc_buf_1[3]=4;
strcpy(ipc_buf_2, "/");
printf("ipc_buf_2 (%p) = %08x\n", ipc_buf_2, *ipc_buf_2);
retval = ios_ioctlv(fs_fd, 4, 1, 1, ipc_buf_1);
printf("retval = %d\n", retval);
return retval;
}
int ios_open(const char *filename)
{
unsigned char *filename_ptr = (u8 *)0x91330800;
u32 *cmd = (u32 *)0x91330840;
strcpy(filename_ptr, filename);
dcache_flush(PHYSADDR(filename_ptr), 0x40);
memset(cmd, 0, 0x40);
cmd[0] = 1;
cmd[4] = 1;
cmd[3] = filename_ptr;
dcache_flush(PHYSADDR(cmd), 0x40);
printf("sending ios_open(%s)\n", filename);
dump_buffer(cmd, 0x40);
ipc_send(cmd);
ipc_wait();
printf("ios_open returned %d\n", cmd[1]);
return cmd[1];
}
int ios_read(int fd, void *ptr, int len)
{
int addr = ((int)ptr) & 0x7FFFFFFF;
dcache_inv(ptr, len);
static unsigned int cmd[0x40];
memset(cmd, 0, sizeof(cmd));
cmd[0] = 3;
cmd[2] = fd;
cmd[3] = addr;
cmd[4] = len;
// printf("ios_read(%d, %08x, %d)=", fd, addr, len);
ipc_send(cmd);
ipc_wait();
// printf("%d\n", cmd[1]);
return cmd[1];
}
/* posix behaviour */
int ios_seek(int fd, int where, int whence)
{
static unsigned int cmd[0x40];
memset(cmd, 0, sizeof(cmd));
cmd[0] = 5;
cmd[2] = fd;
cmd[3] = where;
cmd[4] = whence;
// printf("ios_seek(%d, %08x, %d)=", fd, where, whence);
ipc_send(cmd);
ipc_wait();
// printf("%d\n", cmd[1]);
return cmd[1];
}
int ios_close(int fd)
{
static unsigned int cmd[0x40];
memset(cmd, 0, sizeof(cmd));
cmd[0] = 2;
cmd[2] = fd;
ipc_send(cmd);
ipc_wait();
return cmd[1];
}
void flush_IPC(void) {
int i;
static unsigned char *buffer = (void*)0x80100000;
unsigned int *result = (unsigned int *)buffer;
for (i=0; i<10; ++i) /* make sure to flush it all out */
{
mdelay(100);
IPCInterruptHandler();
}
*(unsigned long*)0xCD000030 = 0x40000000; /* ACK irq */
// close all files.. up to 0xE should be enough.
printf("Closing file descriptors ");
for (i=0; i<15; ++i) printf(".");
printf("done.\n");
// printf("ios_close(%d) = %d\n", i, ios_close(i));
delay(1);
*(unsigned long*)0xCD000030 = 0x40000000; /* ACK irq */
// printf("our work is done, bye.\n");
return;
}