panthema / 2006 / SDIOS06 / sdios06 / src / root / ramdisk-server.cc (Download File)
/*****************************************************************
 * Source file : src/root/ramdisk.idl
 * Platform    : V4 IA32
 * Mapping     : CORBA C
 * 
 * Generated by IDL4 1.0.2 (roadrunner) on 12/07/2006 21:56
 * Report bugs to haeberlen@ira.uka.de
 *****************************************************************/
#include <config.h>

#include <new>
#include <stdio.h>
#include <string.h>

#include <l4/schedule.h>

#include <sdi/panic.h>
#include <sdi/log.h>
#include <sdi/locator.h>

#include "root.h"

#include <idl4glue.h>
#include <if/ifblockdev.h>
#include <if/iflocator.h>
#include "ramdisk-server.h"

#define SHOW_ERRORS
//#define TRACE_CALLS

namespace {
	const size_t BLOCKSIZE = 1024;
	const size_t MAX_RAMDISKCOUNT = 10;
	
	static char buffer[BLOCKSIZE];
	
	struct Ramdisk
	{
		void* ptr;
		size_t size;
	};

	Ramdisk ramdisks[MAX_RAMDISKCOUNT];
	size_t ramdisk_count = 0;
	
	void announce()
	{
		for(size_t i = 0; i < ramdisk_count; ++i) {
			// Announce ramdisk
			char name[128];
			snprintf(name, sizeof(name), "ramdisk%u", i);
			if(Register(GetLocator(), name, IF_BLOCKDEV_ID, i) != OK)
				panic("Couldn't register ramdisk");
			LogMessage("Ramdisk '%s' registered", name);
		}	
	}
	
	bool is_minixdisk(const L4_BootRec_t* bootrec)
	{
		const uint16_t MINIXFS_MAGIC = 0x138f;		// minix fs, 30 char names
		
		/* Check type of module */
		if(L4_Type (bootrec) != L4_BootInfo_Module)
			return false;
		
		if(L4_Module_Size(bootrec) < 2048)
			return false;
		
		L4_Word_t addr = L4_Module_Start(bootrec);
		char* magic_ptr = reinterpret_cast<char*> (addr) + 1040;
		uint16_t magic = * (reinterpret_cast<uint16_t*> (magic_ptr));
		if(magic != MINIXFS_MAGIC)
			return false;
			
		return true;
	}
	
	void detect_ramdisks()
	{
		const L4_BootInfo_t* bootinfo = get_bootinfo();
	
		const L4_BootRec_t* bootrec = L4_BootInfo_FirstEntry(bootinfo);
		for(L4_Word_t i = 0; i < L4_BootInfo_Entries(bootinfo); ++i,
		    bootrec = L4_BootRec_Next(bootrec)) {
		    	
			if(!is_minixdisk(bootrec))
				continue;
				
			if(ramdisk_count >= MAX_RAMDISKCOUNT) {
				printf("Too many ramdisks, skipping module %lu", i);
				break;
			}
			Ramdisk& ramdisk = ramdisks[ramdisk_count];
			
			ramdisk.ptr = reinterpret_cast<void*> (L4_Module_Start(bootrec));
			ramdisk.size = static_cast<size_t> (L4_Module_Size(bootrec));
			ramdisk_count++;
			LogMessage("Module %lu is a ramdisk at %p Len %u\n", i, ramdisk.ptr, ramdisk.size);
		}				
	}
}

/* Interface ramdisk */
IDL4_INLINE void ramdisk_GetBlockSize_implementation(CORBA_Object _caller, const objectid_t devhandle, idlsize_t *blocksize, idl4_server_environment *_env)
{
	if(devhandle >= ramdisk_count) {
#ifdef SHOW_ERRORS
		printf("Invalid devhandle");
#endif
		CORBA_exception_set(_env, ex_no_such_device, 0);
		return;
	}
	*blocksize = BLOCKSIZE;
}

IDL4_PUBLISH_RAMDISK_GETBLOCKSIZE(ramdisk_GetBlockSize_implementation);

IDL4_INLINE void ramdisk_ReadBlock_implementation(CORBA_Object _caller, const objectid_t devhandle, const uint32_t block, buffer_t *buffer, idl4_server_environment *_env)
{
	if(devhandle >= ramdisk_count) {
#ifdef SHOW_ERRORS
		printf("Invalid devhandle\n");
#endif
		buffer->_length = 0;
		CORBA_exception_set(_env, ex_no_such_device, 0);
		return;
	}
	Ramdisk* ramdisk = & ramdisks[devhandle];
	
	size_t offset = block * BLOCKSIZE;
	if(offset + BLOCKSIZE > ramdisk->size) {
#ifdef SHOW_ERRORS
		printf("Invalid block %u\n", block);
#endif
		CORBA_exception_set(_env, ex_invalid_parameter, 0);
		buffer->_length = 0;
		return;
	}
	
#ifdef TRACE_CALLSE
	LogMessage("ReadBlock %u", block);
#endif
	char* memory = reinterpret_cast<char*> (ramdisk->ptr) + offset;
	memcpy(buffer->_buffer, memory, BLOCKSIZE);
	buffer->_length = BLOCKSIZE;
}

IDL4_PUBLISH_RAMDISK_READBLOCK(ramdisk_ReadBlock_implementation);

IDL4_INLINE void ramdisk_WriteBlock_implementation(CORBA_Object _caller, const objectid_t devhandle, const uint32_t block, const buffer_t *buffer, idl4_server_environment *_env)
{
	if(devhandle >= ramdisk_count) {
#ifdef SHOW_ERRORS
		printf("Invalid devhandle\n");
#endif
		CORBA_exception_set(_env, ex_no_such_device, 0);
		return;
	}
	Ramdisk* ramdisk = & ramdisks[devhandle];
	
	if(buffer->_length != BLOCKSIZE) {
#ifdef SHOW_ERRORS
		printf("Invalid buffersize %d\n", buffer->_length);
#endif
		CORBA_exception_set(_env, ex_invalid_parameter, 0);
		return;
	}
	
	size_t offset = block * BLOCKSIZE;
	if(offset + BLOCKSIZE > ramdisk->size) {
#ifdef SHOW_ERRORS
		printf("Invalid block %u\n", block);
#endif
		CORBA_exception_set(_env, ex_invalid_parameter, 0);
		return;
	}

#ifdef TRACE_CALLS
	LogMessage("WriteBlock %u", block);
#endif
	char* memory = reinterpret_cast<char*> (ramdisk->ptr) + offset;
	memcpy(memory, buffer->_buffer, BLOCKSIZE);
}

IDL4_PUBLISH_RAMDISK_WRITEBLOCK(ramdisk_WriteBlock_implementation);

void *ramdisk_vtable_3[RAMDISK_DEFAULT_VTABLE_SIZE] = RAMDISK_DEFAULT_VTABLE_3;
void *ramdisk_vtable_discard[RAMDISK_DEFAULT_VTABLE_SIZE] = RAMDISK_DEFAULT_VTABLE_DISCARD;
void **ramdisk_itable[4] = { ramdisk_vtable_discard, ramdisk_vtable_discard, ramdisk_vtable_discard, ramdisk_vtable_3 };

void ramdisk_server()
{
	L4_ThreadId_t partner;
	L4_MsgTag_t msgtag;
	idl4_msgbuf_t msgbuf;
	long cnt;

	idl4_msgbuf_init(&msgbuf);
	idl4_msgbuf_add_buffer(&msgbuf, buffer, BLOCKSIZE);

	detect_ramdisks();
	announce();

	while (1)
	{
		partner = L4_nilthread;
		msgtag.raw = 0;
		cnt = 0;

		while (1)
		{
			idl4_msgbuf_sync(&msgbuf);

			idl4_reply_and_wait(&partner, &msgtag, &msgbuf, &cnt);

			if (idl4_is_error(&msgtag))
				break;

			idl4_process_request(&partner, &msgtag, &msgbuf, &cnt, ramdisk_itable[idl4_get_interface_id(&msgtag) & RAMDISK_IID_MASK][idl4_get_function_id(&msgtag) & RAMDISK_FID_MASK]);
		}
	}
}

void ramdisk_discard()
{
	panic("message for ramdisk discarded");
}