Page 2 of 2

Posted: Thu Apr 05, 2007 11:32 am
by anon19287473
The idea is good, but in practice...

Nobody would agree on anything, not even what language to use.

I suspect, I better plan would be this: find a hobby OS project that already has a viable kernel (e.g. AtheOS, Menuet (32-bit, most of 64 is proprietary), Solar, Dex and thats just a start, there are dozens more) and develop userland apps and drivers for it. T

The advantages of this would be:
  • * There would be no fighting, as people would each be designing their own app
    * It would make the OS more viable for practical use (to some extent)
My assumption is that your reasoning is that focusing on one project will create a better result. In many cases, people arent developing (hobby) OS's becuase they think it will dethrown M$, but because its fun and interesting to design and build an OS. Obviously, this is not true of everyone.[/list]

Posted: Thu Apr 05, 2007 1:38 pm
by Dex
anon19287473 is right, what is needed is more drivers and program for the the OS that have got past the first stage level, why reinvent the wheel ?.
Thats why DexOS's licence, is such that anyone that add to the OS, becomes a part owner. if your want to test a new file sys or code a new GUI etc its much better to build it on top of a already built OS, theres lots to chose from, to suite any taste.
You will learn so much too, and remember the most, importance thing about code your own OS is understanding every part of it, if you chose a small OS and grow with it you will understand it as good as if you made it from scratch, and you will beable to code anything you like for it.
Here is a good example of when even M$ needs a hobby OS
If anyone gets the time listen to the pod casts Episode #9 | 13 Oct 2005 | 32 min
About Rootkits http://www.grc.com/SecurityNow.htm
Not only will you find there mp3's very informative, but also the one on Rootkits #9 shows that even M$ as a need for a small hobby OS :) .

Posted: Thu Apr 05, 2007 2:58 pm
by Kevin McGuire
Yeah. Here is the 8253 driver.

Code: Select all

#include "shared.h"
#include <asm/io.h>
#include "dev.h"
#include "clock.h"
#include "error.h"

#define BASE 0x40
#define COUNTER0 (0x0+0x40)
#define COUNTER1 (0x1+0x40)
#define COUNTER2 (0x2+0x40)
#define CONTROL  (0x3+0x40)
#define IRQ 0x0

#define MODE_INTONTERMINALCOUNT 0x0
#define MODE_SQUAREWAVE		0x3
#define MODE_ONESHOT		0x1

// 1,193,181Hz or 1.193181MHz
#define FREQUENCY 1193181

/// Requested Hertz and Current Hertz show that the clock may not be able to provide the request cycles per second, but instead
/// will pick the closest value possible. These are used to track the state of the clock for now.
static CLOCKHZ curHz = 0;
static CLOCKHZ reqHz = 0;
static ICLOCK_CLOCK ifaceClockClock;
static u32 gshz = 0;

/// A quick routine that will change the clock's cycles per second.
inline void c8253_w(u8 counterIndex, u8 mode, CLOCKHZ hz){
	u8 df = 0;
	CLOCKHZ shz;
	/*
		H=F/X
		X=F/H
	
		F/H=0xFFFF
		F/0xFFFF=MINH
		F/1=
	
		F/0xFFFF
		F/1
	*/
	if(hz == 0){
		hz = 1;
		df = 1;
	}
	reqHz = hz;
	shz = FREQUENCY/hz;

	if(shz > 0xFFFF){
		shz = 0xFFFF;
	}
	/// convert the actual clock speed in Hz back incase we were shz > 0xFFFF.
	curHz = FREQUENCY/shz;

	gshz = shz;
	if(df != 1){
		outb(0x30 | (counterIndex << 6) | (mode << 1), CONTROL);
		outb(shz, BASE+counterIndex);
		outb(shz>>8, BASE+counterIndex);
	}else{
		outb(0x30 | (counterIndex << 6) | (mode << 1), CONTROL);
	}
	return;
}

/// The interrupt handler for clock ticks, which in return calls the clock multiplexer.
i32 Interrupt(PPRIVATE priv, IRQVECTOR vector){
	/// I am trying MODE_INTONTERMINALCOUNT.. so lets reload the counters.
	outb(0x30 | (0 << 6) | (MODE_INTONTERMINALCOUNT << 1), 0x43);
	outb(gshz, 0x40);
	outb(gshz>>8, 0x40);

	/// In any clock driver design this should be the last function call and no other
	/// important function should reside afterwards except the normal handler function returns to unwind out of this
	/// driver. This is dependant on the clock being used by the scheduler subsystem which will never allow a return
	/// to this point after clock_tick, until this exact threads gets more time added to it's time slice.
	clock_tick((u32)priv->instance);
	return IO_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////// ENTRY ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
DRIVER mobo_clock_8253;
i32 clock_8253_init(){
	u32 x;
	PDEVINSTANCE inst;
	/// Make sure the device actually exists.
	if(inb(COUNTER0) != 0xFF){
		console_write("[8253PIT] driver initialized and device found. \x10");
		inst = (PDEVINSTANCE)dev_CreateInstance(&mobo_clock_8253);
		if(dev_res_alloc(inst->priv, DEV_RES_IO, 0x40, 0x4) != IO_SUCCESS){
			/// The resource allocation failed. Exit.
			console_write("[8253PIT] Resource allocation failed. \x10");
			return IO_NORESOURCES;
		}
		/// There is no easy way to lookup the used interface from the PRIVATE structure so lets
		/// hand the clock multiplexer a direct link to it with the PRIVATE structure.
		/// The multiplexer will enable, disable, and change the clock hertz as needed.
		inst->priv.instance = (void*)clock_register(&inst->priv, &ifaceClockClock);
		/// Register our interrupt handler, which in return calls the clock multiplexer tick function.
		irqrouter_RegisterInterrupt(&inst->priv, &Interrupt, IRQ+IRQROUTER_HWBASEVECTOR, IRQROUTER_DIRECTCALL);
		/// Exit.
		return IO_SUCCESS;
	}
	/// This driver was unable to detect the hardware's presence.
	console_write("[8253PIT] device not detected. \x10");
	return IO_DEVICENOTFOUND;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// EXPORTS /////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
static i32 GetInfo(PPRIVATE priv, PCLOCKINFO info){
	info->curHz = curHz;
	info->reqHz = reqHz;
	info->minHz = FREQUENCY/0xFFFF;
	info->maxHz = FREQUENCY;
	return IO_SUCCESS;
}
static i32 SetHz(PPRIVATE priv, CLOCKHZ hz){
	/*
		Using counter zero. If other counters can be used I do not know about it.
	*/
	if(hz == 0){
		console_write("[8253PIT] Told to disable. \x10");
		c8253_w(0, MODE_INTONTERMINALCOUNT, hz);
	}else{
		c8253_w(0, MODE_INTONTERMINALCOUNT, hz);
	}
	return IO_SUCCESS;
}

///////////////////////////////////////////////////
///////////////// HEADER //////////////////////////
///////////////////////////////////////////////////
static ICLOCK_CLOCK ifaceClockClock = {
	.GetInfo=&GetInfo,
	.SetHz=&SetHz
};

static DEV_CONNECTION_MOTHERBOARD_DATA connectionDataMotherboard = {
	DEV_MOTHERBOARD_CLOCK,
	&clock_8253_init
};

DRIVER mobo_clock_8253 = {
	.szName = "8253PIT",
	.connection = DEV_CONNECTION_MOTHERBOARD,
	.connectionVersion = DEV_CONNECTION_MOTHERBOARD_VERSION,
	.connectionData = &connectionDataMotherboard,
	.priv = 0,
	.ifaceCount = 1,
	.iface = {
		{
			.szName = "CLOCK.CLOCK",
			.major = DEV_CLOCK,
			.minor = DEV_CLOCK_CLOCK,
			.iface = &ifaceClockClock
		}
	}
};
Here is the clock header.

Code: Select all

#ifndef CLOCK_H
#define CLOCK_H
#include "shared.h"
#include "error.h"
#include "module.h"
typedef u32 CLOCKRES;
typedef u32 CLOCKTICK;
typedef u32 CLOCKHZ;

struct tclockInfo{
	CLOCKHZ		curHz;
	CLOCKHZ		reqHz;
	CLOCKHZ		maxHz;
	CLOCKHZ		minHz;
}; typedef struct tclockInfo CLOCKINFO; typedef CLOCKINFO* PCLOCKINFO;

struct iClockClock{
	i32 (*GetInfo)(PPRIVATE priv, PCLOCKINFO clock);
	i32 (*SetHz)(PPRIVATE, CLOCKHZ hz);	
}; typedef struct iClockClock ICLOCK_CLOCK;

#define MAXCLOCK 25
#define MAXEVENTS 10

struct tclock{
	CLOCKINFO	info;
	CLOCKTICK	curTick;
	PPRIVATE	priv;
	ICLOCK_CLOCK    *interface;
}; typedef struct tclock CLOCK; typedef CLOCK* PCLOCK;

typedef i32 (*CLOCK_EVENT_HANDLER)(PPRIVATE priv);

#define CLOCK_F_KERNELTHREAD 	0x0			/// default
#define CLOCK_F_DIRECTCALL	 	0x1		/// a direct call instead of the default kernel thread is made.
#define CLOCK_F_INFINITE 		0x2		/// this event is just reset once it triggers.
#define CLOCK_F_SCHEDULER		0x4		/// this should be a direct call and handled last since no return will
							/// occur back t the clock multiplexer until the thread comes up for a
							/// time slice again potentialy starving other events if this flag is
							/// not set when making a registration for the scheduler.

struct tclockEvent{
	u32			flags;
	u32			ticks_start;
	u32			ticks_left;
	PPRIVATE		priv;
	CLOCK_EVENT_HANDLER	handler;
}; typedef struct tclockEvent CLOCKEVENT; typedef CLOCKEVENT* PCLOCKEVENT;

typedef i32 (*CLOCK_GETINFO)(PPRIVATE priv, PCLOCKINFO clock);
#endif
Here is the clock multiplexer.

Code: Select all

/*
	Translates clock timer events into user threads and kernel function calls.
*/
#include "clock.h"

CLOCK clock_clock[MAXCLOCK];
u32 clock_mutex = 0;	/* default is unlocked */
i32 clock_master = MAXCLOCK+1;
CLOCKEVENT clock_event[MAXEVENTS];

i32 clock_tick(u32 id){
	i32 scheduler_service_call = -1;
	u32 x;
	/// ignore and attempt to turn off non-master clocks.
	if(id != clock_master){
		console_write("[CLOCK] non-master clock was active. trying to turn off.\x10");
		dv(id);
		dv(clock_clock[id].interface);
		clock_clock[id].interface->SetHz(clock_clock[id].priv, 0);
		console_write("OFF\x10");
		return;
	}
	//console_write("[CLOCK] tick\x10");
	/// advance clock ticks and check events.
	++clock_clock[id].curTick;
	if(clock_mutex == 1){
		return;
	}
	/// update ticks for each event
	for(x = 0; x < MAXEVENTS; ++x){
		if(clock_event[x].handler != 0){
			--clock_event[x].ticks_left;
			if(clock_event[x].ticks_left == 0){
				debugthis:;
				/// if event is infinite or repeating just add the original requested ticks again.
				if((clock_event[x].flags & CLOCK_F_INFINITE) == CLOCK_F_INFINITE){
					clock_event[x].ticks_left = clock_event[x].ticks_start;
				}
				/// service the scheduler, and ONLY THE SCHEDULER. (actually we wait first)
				if((clock_event[x].flags & CLOCK_F_SCHEDULER) == CLOCK_F_SCHEDULER){
					scheduler_service_call = x;
					continue;
				}
				/// service with a direct call instead of the kernel thread approach.
				if((clock_event[x].flags & CLOCK_F_DIRECTCALL) == CLOCK_F_DIRECTCALL){
					/// not implemented
					console_write("[CLOCK] DIRECT CALL NOT IMPLEMENTED!\x10");
					continue;
				}
				console_write("[CLOCK] Servicing Event With Kernel Thread.\x10");
				/// service with a kernel thread by default.
				// TODO: CREATE THREAD TO HANDLE EVENT
				// NOTE: contention should be non-existance in this kernel build and version.
				// FIXME: in case of contention..
				sched_kernel_thread_create(clock_event[x].handler, clock_event[x].priv);
			}
		}
	}

	/// TODO: Do we need a better way? Maybe let the clock multiplexer, clock driver, and irqrouter functions unwind so to not
	/// TODO: leave this burdon on _this_ thread that has been interrupted when it returns...
	//console_write("[CLOCK] exiting\x10");
	if(scheduler_service_call > -1){
		//console_write("[CLOCK] handing control to the scheduler.\x10");
		/// special support for the scheduler from clock to irqrouter
		irqrouter_inthandler_scheduler_terminate();
		//xxx();
		/// service the scheduler now.
		sched_switch();
	}
	return IO_SUCCESS;
}



i32 clock_selectMaster(CLOCKHZ needed_hz){
	u32 x;
	u32 om = clock_master;
	CLOCKHZ bestlow = 0xFFFFFFFF;
	for(x = 0; x < MAXCLOCK; ++x){
		if(clock_clock[x].priv != 0){
			if(clock_clock[x].info.minHz < bestlow){
				clock_master = x;
			}
		}
	}
	/// engage the master clock for operation.
	if(om != (MAXCLOCK+1)){
		console_write("[CLOCK] multiplexer switched master clocks. \x10");
		/// update the new selected master clock from the old one.
		clock_clock[clock_master].interface->SetHz(clock_clock[clock_master].priv, clock_clock[om].info.reqHz);
		/// update the info structure.
		clock_clock[clock_master].interface->GetInfo(clock_clock[clock_master].priv, &clock_clock[clock_master].info);
		/// turn off the old clock
		clock_clock[om].interface->SetHz(clock_clock[om].priv, 0);
	}else{
		console_write("[CLOCK] multiplexer selected master clock. \x10");
		/// This is the first clock ever so lets try to use needed_hz.
		clock_clock[clock_master].interface->SetHz(clock_clock[clock_master].priv, needed_hz);
		/// update the info structure.
		clock_clock[clock_master].interface->GetInfo(clock_clock[clock_master].priv, &clock_clock[clock_master].info);
	}
	return IO_SUCCESS;
}

// TODO: potential denial of service by a unprivledged user having access to registering events.
i32 clock_revent(PPRIVATE priv, CLOCKHZ hz_from_now, CLOCK_EVENT_HANDLER handler, u32 flags){
	u32 x, old, y;
	/// Lets make sure our master clock is the best selected.	
	clock_selectMaster(hz_from_now);
	/// Lets add this event to our list in the proper order.
	clock_mutex = 1;
	/// The list is locked and the clock is disabled momentarily.
	for(x = 0; x < MAXEVENTS; ++x){
		if(clock_event[x].handler == 0){
			clock_event[x].priv = priv;
			clock_event[x].flags = flags;
			clock_event[x].ticks_start = hz_from_now;
			clock_event[x].ticks_left = hz_from_now;
			clock_event[x].handler = handler;
			/// NOTE: clock was disabled, no events, we assume it is being started.
			if(clock_clock[clock_master].info.curHz == 0){
				clock_clock[clock_master].interface->SetHz(clock_clock[clock_master].priv, hz_from_now);
				/// update the master clock info structure.
				clock_clock[clock_master].interface->GetInfo(clock_clock[clock_master].priv, &clock_clock[clock_master].info);
				clock_mutex = 0;
				return IO_SUCCESS;
			}
			if(clock_clock[clock_master].info.curHz <= hz_from_now){
				dv(clock_clock[clock_master].info.curHz);
				/// if the clock is current at a higher resolution then divide the current master clock.
				clock_event[x].ticks_left = hz_from_now / clock_clock[clock_master].info.curHz;
				clock_mutex = 0;
				return IO_SUCCESS;
			}else{
				old = clock_clock[clock_master].info.curHz;
				/// if the clock is at a lower resolution then change the master clock and update existing events.
				clock_event[x].ticks_left = 1;
				clock_clock[clock_master].interface->SetHz(clock_clock[clock_master].priv, hz_from_now);
				/// update the master clock info structure.
				clock_clock[clock_master].interface->GetInfo(clock_clock[clock_master].priv, &clock_clock[clock_master].info);
				/// fix all existing events.
				for(y = 0; y < MAXEVENTS; ++y){
					if(y != x){
						/// using the formula "old/new*ticks_left=ticks_left"
						clock_event[y].ticks_left = clock_event[y].ticks_left * (old/hz_from_now);
					}
				}
				/// unlock the mutex and exit.
				clock_mutex = 0;
				return IO_SUCCESS;
			}
		}
	}
	clock_mutex = 0;
	return IO_NORESOURCES;
}

i32 clock_register(PPRIVATE priv, ICLOCK_CLOCK *interface){
	u32 x;
	console_write("[CLOCK] clock registration event with multiplexer.\x10");
	for(x = 0; x < MAXCLOCK; ++x){
		if(clock_clock[x].priv == 0){
			clock_clock[x].priv = priv;
			clock_clock[x].interface = interface;
			clock_clock[x].curTick = 0;
			/*
				Disable the clock.
			*/
			interface->SetHz(priv, 0);
			interface->GetInfo(priv, &clock_clock[x].info);
			return x;
		}
	}
	return IO_NORESOURCES;
}

i32 clock_init(void){
	u32 x;
	console_write("[CLOCK] multiplexer initialization.\x10");
	for(x = 0; x < MAXCLOCK; ++x){
		clock_clock[x].priv = 0;
	}
	return IO_SUCCESS;
}
Here is the 8259x2 driver.

Code: Select all

#include "shared.h"
#include <asm/io.h>
#include "dev.h"
#include "pic.h"
#include "error.h"

#define PIC1 	0x20
#define PIC2 	0xA0

#define ICW1 	0x11
#define ICW4 	0x01

#define IER	0x001
#define IIR	0x002
#define FCR	0x002
#define LCR	0x003


// will enable and disable hardware interrupts selected by bit in the mask. supports thirty-two interrupts.
i32 InterruptEnableMask(PPRIVATE priv, u32 mask){
	u8 emask;
	emask = inb(PIC1 + IER);
	emask = emask & (~mask);
	console_write(ksprintf(0, "pic1 emask is %u\x10", emask));
	outb(emask, PIC1 + IER);
	emask = inb(PIC2 + IER);
	emask = emask & (~(mask>>8));
	console_write(ksprintf(0, "pic2 emask is %u\x10", emask));
	outb(emask, PIC2 + IER);
	return IO_SUCCESS;
}
i32 InterruptDisableMask(PPRIVATE priv, u32 mask){
	u8 emask;
	emask = inb(PIC1 + IER);
	emask = emask | mask;
	outb(emask, PIC1 + IER);
	emask = inb(PIC2 + IER);
	emask = emask | (mask>>8);
	outb(emask, PIC2 + IER);
	return IO_SUCCESS;
}
// should aquire the last interrupt fired index.
i32 ThisInterruptIndex(PPRIVATE priv){
	u32 a, b;
	outb(0x8, PIC1);
	a = inb(PIC1);
	outb(0x8, PIC2);
	b = inb(PIC2);
	return a | (b << 8);
}
// used to acknowledge a interrupt if needed.
i32 AckInterrupt(PPRIVATE priv){
	outb(0x20, PIC1);
	outb(0x20, PIC2);
	return IO_SUCCESS;
}
// should map hardware interrupts at base in order to preserve room for processor exceptions.
i32 MapHardware(PPRIVATE priv, u8 base){
	/// http://www.osdever.net - remapping IRQs
	/* send ICW1 */
	outb(ICW1, PIC1);
	outb(ICW1, PIC2);
	/* send ICW2 */
	outb(base, PIC1 + IER);		        /* remap */
	outb((base+0x8), PIC2 + IER);		/*  pics */
	/* send ICW3 */
	outb(4, PIC1 + IER);	/* IRQ2 -> connection to slave */
	outb(2, PIC2 + IER);
	/* send ICW4 */
	outb(ICW4, PIC1 + IER);
	outb(ICW4, PIC2 + IER);
	/* disable all IRQs */
	outb(0xFF, PIC1 + IER);
	outb(0xFF, PIC2 + IER);
	return IO_SUCCESS;
}

DRIVER mobo_pic_8259;
i32 pic_8259_init(){
	PDEVINSTANCE inst;
	if(dev_res_alloc(inst->priv, DEV_RES_IO, PIC1, 3) != IO_SUCCESS){
		/// The resource allocation failed. Exit.
		console_write("[8253PIT] Resource allocation failed. \x10");
		return IO_NORESOURCES;
	}
	if(dev_res_alloc(inst->priv, DEV_RES_IO, PIC2, 3) != IO_SUCCESS){
		/// The resource allocation failed. Exit.
		console_write("[8253PIT] Resource allocation failed. \x10");
		return IO_NORESOURCES;
	}
	inst = (PDEVINSTANCE)dev_CreateInstance(&mobo_pic_8259);
	console_write("[8259PIC] Initializing \x10");
	return IO_SUCCESS;
}

static IPIC_PIC ifacePicPic = {
	.InterruptEnableMask = &InterruptEnableMask,
	.InterruptDisableMask = &InterruptDisableMask,
	.ThisInterruptIndex = &ThisInterruptIndex,
	.AckInterrupt = &AckInterrupt,
	.MapHardware = &MapHardware
};

static DEV_CONNECTION_MOTHERBOARD_DATA connectionDataMotherboard = {
	DEV_MOTHERBOARD_PIC,
	&pic_8259_init
};

DRIVER mobo_pic_8259 = {
	.szName = "8259PIC",
	.connection = DEV_CONNECTION_MOTHERBOARD,
	.connectionVersion = DEV_CONNECTION_MOTHERBOARD_VERSION,
	.connectionData = &connectionDataMotherboard,
	.priv = 0,
	.ifaceCount = 1,
	.iface = {
		{
			.szName = "PIC.PIC",
			.major = DEV_PIC,
			.minor = DEV_PIC_PIC,
			.iface = &ifacePicPic
		}
	}
};
Here is the IRQ router header.

Code: Select all

#ifndef IRQ_H
#define IRQ_H
#include "dev.h"
#define IRQROUTER_HWBASEVECTOR 0x20
#define IRQROUTER_HWVECTORCOUNT 0x20
typedef u8 IRQVECTOR;
typedef i32 (*IRQHANDLERFUNC)(void *priv, IRQVECTOR vector);
#define IRQROUTER_DIRECTCALL 0x1
#define IRQROUTER_KERNELTHREAD 0x0
struct tirqrouter_handler{
	u32			flags;
	void			*priv;
	IRQHANDLERFUNC		handler;
}; typedef struct tirqrouter_handler IRQHANDLER; typedef IRQHANDLER* PIRQHANDLER;
#endif
Here is the IRQ router implementation.

Code: Select all

#include "shared.h"
#include "dev.h"
#include "error.h"
#include "pic.h"
#include <asm/io.h>
#include "it.h"
#include "alpha.h"
#include "vmm.h"
#include "irq.h"

i32 irqrouter_hwenable(void){
	asm("sti");
}
i32 irqrouter_hwdisable(void){
	asm("cli");
}

static PDEVINTERFACE interface;

struct __attribute__((__packed__)) tirqrouter_jumpentry{
	u8 	push;
	u8 	mov1;
	u32 	movValue1;
	u8	mov2;
	u32	movValue2;
	u8 	jump[2];
}; typedef struct tirqrouter_jumpentry JUMPENTRY;
extern u8 irqrouter_intstub;

static JUMPENTRY *irqrouter_jumptable = 0;
static PIRQHANDLER* irqrouter_handler = 0;


/*
	Lets route interrupts from a centralized point here. Allow us to do any type of priority checking or such not.
*/
u32 irqrouter_saveEsp = 0;
u32 irqrouter_saveEbp = 0;
u32 irqrouter_ieip = 0;
extern u32 sched_kernel_threads_index;

void irqrouter_inthandler(u32 vector){
	PIRQHANDLER ih;
	u32 hwVector;
	u32 x;
	//console_write("irqrouter enter\x10");
	hwVector = ((IPIC_PIC*)(interface->iface))->ThisInterruptIndex(0);
	/// Go ahead and acknowledge the interrupt.
	((IPIC_PIC*)(interface->iface))->AckInterrupt(0);
	if(vector != 0x20){
		console_write(ksprintf(0, "current vector:%u irr:%u handlerlist[vector]:%u TI:%u\x10", vector, hwVector, irqrouter_handler[vector], sched_kernel_threads_index));
	}
	/// work through registrations to allow a acceptance by any if possible.
	for(x = 0, ih = irqrouter_handler[vector]; ih != 0; ih = LISTNEXT(ih,PIRQHANDLER)){
		//console_write(ksprintf(0, "--calling irq handler for %u \x10", (u32)ih));
		/// TODO: Do we need drivers to get a hardware reported vector relative to the mapping done by a PIC?
		if((ih->flags & IRQROUTER_DIRECTCALL) == IRQROUTER_DIRECTCALL){
			//console_write(ksprintf(0, "current vector:%u irr:%u handlerlist[vector]:%u\x10", vector, hwVector, irqrouter_handler[vector]));
			//console_write(ksprintf(0, "[IRQROUTER] DIRECT CALL ih:%u handler:%u\x10", ih, ih->handler));
			x |= ih->handler(ih->priv, vector);
		}else{
			console_write("[IRQROUTER] CREATED KERNEL THREAD\x10");
			sched_kernel_thread_create((u32)ih->handler, ih->priv);
			/// TODO:
			/// FIXME: figure a way to check for these conditions when kernel threads return 0 then say
			/// FIXME: I guess no one cared. ...
			/// TODO:
			x |= 0x1;
		}
		///
	}
	/// TODO: handle this condition, maybe disabling the irq if no other handlers are present.. *confused*
	if(x == 0){
		console_write(ksprintf(0, "current vector:%u irr:%u handlerlist[vector]:%u\x10", vector, hwVector, irqrouter_handler[vector]));
		console_write("I guess no one cared about it. \x10");
		if(vector < 0x10){
			console_write(ksprintf(0, "In exception range! HALTED (EIP:%u ESP:%u)\x10", 
					irqrouter_ieip, irqrouter_saveEsp));
			for(;;);
		}
	}
	//console_write("irqrouter exit\x10");
	return;
}

void irqrouter_inthandler_scheduler_terminate(void){
	((IPIC_PIC*)(interface->iface))->AckInterrupt(0);
}

u32 lmask = 0, loaded = 0;
i32 irqrouter_RegisterInterrupt(PPRIVATE priv, IRQHANDLERFUNC handler, u8 vector, u32 flags){
	irqrouter_handler[vector] = LISTADD(irqrouter_handler[vector],IRQHANDLER);
	irqrouter_handler[vector]->priv = priv;
	irqrouter_handler[vector]->handler = handler;
	irqrouter_handler[vector]->flags = flags;

	//console_write(ksprintf(0, "check### %u\x10", irqrouter_handler[vector]));
	console_write(ksprintf(0, "irqrouter: registering interrupt for vector:%u \x10", vector));
	/// lets enable that interrupt if it is a hardware one in the PIC.
	if((vector >= IRQROUTER_HWBASEVECTOR) && (vector < (IRQROUTER_HWBASEVECTOR+IRQROUTER_HWVECTORCOUNT))){
		console_write("- irq resided in hardware interrupt vector range. \x10");
		if(loaded == 0){
			console_write("[IRQROUTER] lmasking hw vector for late enable. \x10");
			lmask = lmask | (0x1<<(vector-IRQROUTER_HWBASEVECTOR));
		}else{
			console_write("[IRQROUTER] enabling hw vector. \x10");
			((IPIC_PIC*)(interface->iface))->InterruptEnableMask(0,0x1<<(vector-IRQROUTER_HWBASEVECTOR));
		}
	}
	return IO_SUCCESS;
}

/*
	Creates a jump table by copying a machine functon two-hundred-fifty-six times. The machine function must be
	no greater than twelve bytes in total for this to work. It is stored in irqrouter86.s.
*/
i32 irqrouter_CreateJumpTable(void){
	u32 x;
	irqrouter_jumptable = (JUMPENTRY*)vmm_kvalloc(g_k_vmm, 1, VMM_KERNEL);
	for(x = 0; x < 256; ++x){
		irqrouter_jumptable[x].push = 0x60;				/// PUSHAD
		irqrouter_jumptable[x].mov1 = 0xb8;				/// MOV EAX,<value>
		irqrouter_jumptable[x].movValue1 = x;
		irqrouter_jumptable[x].mov2 = 0xbb;				/// MOV EBX,<value>
		irqrouter_jumptable[x].movValue2 = (u32)&irqrouter_intstub;
		irqrouter_jumptable[x].jump[0] = 0xff;				/// JUMP EBX
		irqrouter_jumptable[x].jump[1] = 0xe3;
		it_set(g_k_idt, x, &irqrouter_jumptable[x], 0x8, IT_PRESENT);
	}
	return IO_SUCCESS;
}

/// initializes basic elements so the remaining kernel can boot
i32 irqrouter_preinit(void){
	u32 x;
	/// create interrupt mapping
	irqrouter_handler = (PIRQHANDLER*)vmm_kvalloc(g_k_vmm, 1, VMM_KERNEL);
	for(x = 0; x < 256; ++x){
		irqrouter_handler[x] = 0;
	}
	irqrouter_CreateJumpTable();
	return IO_SUCCESS;
}
/// continues initilization to enable the irq routing
i32 irqrouter_init(void){
	PDEVINSTANCE instance;
	PPRIVATE private;

	console_write(ksprintf(0, "check### %u\x10", irqrouter_handler[1]));

	// find pic instance
	if(dev_Find(0, DEV_PIC, DEV_PIC_PIC, &instance, &interface, &private) != IO_SUCCESS){
		console_write("irqrouter_test failed to find a programmable interrupt controller \x10");
		return IO_NOTFOUND;
	}
	console_write(ksprintf(0, "irqrouter_test found a programmable interrupt controller (%u/%u)\x10", instance, interface));

	console_write(ksprintf(0, "using lmask:%u\x10", lmask));
	((IPIC_PIC*)(interface->iface))->MapHardware(private, IRQROUTER_HWBASEVECTOR);
	irqrouter_hwenable();
	loaded = 1;
	((IPIC_PIC*)(interface->iface))->InterruptEnableMask(0,lmask);

	return IO_SUCCESS;
}
You said put it in code blocks. =)

The floppy driver.

Code: Select all

#include "shared.h"
#include <asm/io.h>
#include "dev.h"
#include "error.h"
#include "irq.h"
#include "kheap.h"

struct fdPrivData{
	u16		base;
	u8		state;
	u8		drive;
};
typedef struct fdPrivData PRIVDATA;
typedef PRIVDATA* PPRIVDATA;

#define FD_IRQ 0x6
#define FD_BASE ((PPRIVDATA)priv->instance)->base
#define FD_STATA ( ((PPRIVDATA)priv->instance)->base+0x0)
#define FD_STATB (((PPRIVDATA)priv->instance)->base+0x1)
#define FD_DOR (((PPRIVDATA)priv->instance)->base+0x2)
#define FD_TDR (((PPRIVDATA)priv->instance)->base+0x3)
#define FD_MSR (((PPRIVDATA)priv->instance)->base+0x4)
#define FD_DRSR (((PPRIVDATA)priv->instance)->base+0x4)
#define FD_DATA (((PPRIVDATA)priv->instance)->base+0x5)
#define FD_RESERVED (((PPRIVDATA)priv->instance)->base+0x6)
#define FD_DIR (((PPRIVDATA)priv->instance)->base+0x7)
#define FD_CCR (((PPRIVDATA)priv->instance)->base+0x7)

enum DRATE{RATE1MBPS = 0,RATE500KBPS = 1,RATE300KBPS = 2,RATE250KBPS = 3};
struct{
	u32 	drate;
	u8	drsr_bits;
	u8	ccr_bits;
} precompDelays[] = {
	{1000000, (0x1<<2), 0x3},
	{ 500000, (0x3<<2), 0x0},
	{ 300000, (0x3<<2), 0x1},
	{ 250000, (0x3<<2), 0x2}
};

struct que{
	u32		lba;
	u32		buffer;
	PPRIVATE	priv;
};

static inline void setdrate(PPRIVATE priv, u8 rate){
	outb((inb(FD_DRSR)&0xE)|precompDelays[rate].drsr_bits|precompDelays[rate].ccr_bits, FD_DRSR);
	outb(precompDelays[RATE250KBPS].ccr_bits, FD_CCR);
}

#define CMD_READDATA 		0x06
#define CMD_SENSEINTERRUPT 	0x08
#define CMD_SPECIFY		0x03
#define CMD_CONFIGURE		0x13
#define CMD_LOCK		0x14
#define CMD_RECALIBRATE		0x07

static void recalibrate(PPRIVATE priv, u8 head){
	outb(CMD_RECALIBRATE, FD_DATA);
	outb(head, FD_DATA);
	return;
}
static inline void specify(PPRIVATE priv){
	outb(CMD_SPECIFY, FD_DATA);
	outb(0xff, FD_DATA);
	outb(0xff, FD_DATA);
}

static inline void readsector(PPRIVATE priv, u32 lba){
	u8 head = 1;
	u8 track = 0;
	u8 sector = 0;
	u8 drive = ((PPRIVDATA)priv->instance)->drive;

	outb(0x40 | CMD_READDATA, FD_DATA);
	outb(drive | (head<<2), FD_DATA);
	// cylinder
	outb(track, FD_DATA);
	// head
	outb(head, FD_DATA);
	// sector			R
	outb(sector, FD_DATA);
	// sector size 512 bytes	N
	outb(0x02, FD_DATA);
	// eot
	outb(79, FD_DATA);
	// gpl
	outb(128, FD_DATA);
	//
	outb(0xff, FD_DATA);
	return;
}


static inline void unlock(PPRIVATE priv){
	outb(CMD_LOCK, FD_DATA);
}

/// (enable fifo, enable polling routines, enable implied seek, 
static inline void configure(PPRIVATE priv, u8 nofifo, u8 nopoll, u8 eis, u8 fifothr, u8 pretrack){
	outb(CMD_CONFIGURE, FD_DATA);
	outb(0x0, FD_DATA);
	outb((eis<<6)|((nofifo)<<5)|((nopoll)<<4)|fifothr, FD_DATA);
	outb(pretrack, FD_DATA);
	return;
}
static inline void senseinterrupt(PPRIVATE priv){
	outb(CMD_SENSEINTERRUPT, FD_DATA);
	inb(FD_DATA);
	inb(FD_DATA);
}

/*
		/// some debug info for the instance of this driver
		dv(((PPRIVDATA)priv->instance)->base);
		dv(((PPRIVDATA)priv->instance)->state);
		dv(((PPRIVDATA)priv->instance)->drive);
*/
#define STATE_CALIBRATE 1
#define STATE_INIT 0
#define STATE (((PPRIVDATA)priv->instance)->state)
static void InterruptThread(PPRIVATE priv){
	u32 x;
	dv(priv);
	switch(STATE){
		case STATE_INIT:
			/// turn floppy motor on..
			outb(inb(FD_DOR) | 0x10, FD_DOR);
			/// configure
			configure(priv, 0, 0, 1, 16, 1);
			/// turn DMA off.
			specify(priv);
			STATE = STATE_CALIBRATE;
			console_write("EE\x10");
			recalibrate(priv, 0);
			console_write("EE\x10");
			//recalibrate(priv, 1);
			return;
		case STATE_CALIBRATE:
			/// read unlock command results
			inb(FD_DATA);
			STATE = 99;
			return;
		default:
			console_write("Unimplemented State\x10");
			return;	

	}
	return;
}
static i32 Interrupt(PPRIVATE priv, IRQVECTOR vector){
	u32 x;
	senseinterrupt(priv);					/// tell the floppy controller to shut the **** up!
	console_write("[FLOPPY] GOT A INTERRUPT!\x10");
	////////////////////////////////////////////
	dv(inb(FD_MSR));
	////////////////////////////////////////////
	sched_kernel_thread_create((u32)&InterruptThread, priv);
	return IO_SUCCESS;
}

DRIVER floppy_generic;
i32 floppy_generic_init(void){
	/// create a instance for each drive that is detected..
	PDEVINSTANCE inst;
	console_write("[FLOPPY] detecting controller. \x10");
	
	if(inb(0x3f0+0x2) == 0xFF){
		/// floppy drive was not detected.
		console_write("[FLOPPY] failed on detected controller. \x10"); 
		return IO_UNSUPPORTED;
	}
	inst = (PDEVINSTANCE)dev_CreateInstance(&floppy_generic);
	inst->priv.instance = (void*)kalloc(sizeof(PRIVDATA));
	((PPRIVDATA)inst->priv.instance)->base = 0x3f0;
	((PPRIVDATA)inst->priv.instance)->state = 0x0;
	((PPRIVDATA)inst->priv.instance)->drive = 0x0;

	
	dv(&inst->priv);
	dv(inst->priv.instance);

	console_write("[FLOPPY] detecting drives \x10");
	/// register interrupt
	irqrouter_RegisterInterrupt(&inst->priv, &Interrupt, FD_IRQ+IRQROUTER_HWBASEVECTOR, IRQROUTER_DIRECTCALL);

	/// reset controller
	outb(0x00, 0x3f0+0x2);
	outb(0x0C, 0x3f0+0x2);

	/// continue initialization (select drive one)
	//outb(0x10, FD_DOR);
	/// try to change data rate and see if effect happens.
	//setdrate(FD_BASE, RATE300KBPS);

	//for(;;);
	//console_write("[8259PIC] Initializing \x10");

	return IO_SUCCESS;
}

static DEV_CONNECTION_MOTHERBOARD_DATA connectionDataMotherboard = {
	DEV_MOTHERBOARD_FLOPPY,
	&floppy_generic_init
};

DRIVER floppy_generic = {
	.szName = "FLOPPYGENERIC",
	.connection = DEV_CONNECTION_MOTHERBOARD,
	.connectionVersion = DEV_CONNECTION_MOTHERBOARD_VERSION,
	.connectionData = &connectionDataMotherboard,
	.priv = 0,
	.ifaceCount = 0,
	.iface = {
		{
			.szName = "VFS.IO",
			.major = DEV_VFS,
			.minor = DEV_VFS_IO,
			.iface = 0
		}
	}
};
Those are straight out of my editor. Some have lots of debug printing. Never the less they show the general concept of abtracting the clocks and interrupt controllers.

The drivers all support multiple instances, but for lack of actually implemented it in them they do not. The priv argument for a lot of functions is the actual instance data which you can see the floppy driver using it through the macros for the ports.

Posted: Thu Apr 05, 2007 3:13 pm
by mystran
I suspect, I better plan would be this: find a hobby OS project that already has a viable kernel (e.g. AtheOS, Menuet (32-bit, most of 64 is proprietary), Solar, Dex and thats just a start, there are dozens more) and develop userland apps and drivers for it.
Wasn't that just different words for what I tried to say, except I think you can hack the kernel as well. It just needs to be in a point where it works already, so that it has a structure to build upon. :)

Posted: Thu Apr 05, 2007 3:34 pm
by mystran
Kevin McGuire: yeah I said in code-blocks, which is much better than not in code-blocks, but if you really want to post lots of code, there's also a relatively decent attachment system. :)

Have you tried supporting several alternatives in each of those cases? I'm going to claim (without claiming your approach doesn't work) that it's not the first driver for an interface, but the second (or third) that shows if an interface is viable. (say, both PIC and APIC) :)

Also, have you tried supporting the same drivers in several kernels. To some extend, we need to deal with alternatives for those in every kernel (well every kernel that wants to support wide range of hardware well) but the discussion was about sharing the drivers between kernels. This implies that the whole interface for the driver is well defined, and you never step outside it, because outside the well-defined interfaces, there could be completely different concepts in different systems. The futher complication is that when you add requirements to the interfaces, every time you're going to assume more of the kernel structure, limiting the drivers portability.

But yeah, like I said (after your comment), PIC/PIT wasn't necessarily good examples as such. It's also known that you can solve anything through sufficient levels of indirection. Every indirection level will eats some performance though.

Finally, about your floppy driver... you can't blindly SENSE_INTERRUPT in the interrupt handler, because you can't READ/WRITE with interrupt then, because you get interrupts from those but they have their own result phase and shouldn't be handled with a SENSE_INTERRUPT (in fact, doing so will cause problems in both emulators and real hardware.. I bothered trying this).

Not that your senseinterrupt() will necessarily work anyway on real hardware. You shouldn't read the ports before you've checked that the data is ready, for which you need to poll MSR and check bit7, preferably sleeping between the polling (because the hardware could be slow), which is why it's not necessarily such a good idea to run it from the interrupt handler at all (you could wake up a thread instead).

When the driver is in such a state, I think it's documentary and example value for whatever purpose is extremely low.

Posted: Thu Apr 05, 2007 4:34 pm
by Kevin McGuire
When the driver is in such a state, I think it's documentary and example value for whatever purpose is extremely low.
I was trying to post in the thread about the "Community Operating System", but apparently the forum software bugged out, and the previous post from me got into this "High Performance Floppy Driver Implementation For Documentation And Learning" thread. Well. I do not know what to say frankly. I suppose..I apologize for posting in this thread and apparently with out knowing it. I also apologize for putting this floppy driver up for a example of a floppy driver's implementation. to anyone whom I may have confused by looking at it since it really does have poor value.
yeah I said in code-blocks, which is much better than not in code-blocks, but if you really want to post lots of code, there's also a relatively decent attachment system.
I also apologize for posting way to much code and wasting the server resources, end user resources, and the end users time having to scroll past all of it. I will not do it again I promise! :D

Also I wanted to ask you what forum software do you think has the best attachment system?
Also, have you tried supporting the same drivers in several kernels.
I knew I was forgetting about something. I was trying to manage writing my own kernel, but should have been worrying about it working on multiple kernels at the same time.
To some extend, we need to deal with alternatives for those in every kernel (well every kernel that wants to support wide range of hardware well) but the discussion was about sharing the drivers between kernels.
Umm.. That was the thread I was wanting to post to! You must be posting in the wrong threads too. You think the forum software is bugged or something? Thread-Discussion: sharing the drivers between kernels.
The futher complication is that when you add requirements to the interfaces, every time you're going to assume more of the kernel structure, limiting the drivers portability.
What did you need a multi dimensionally warp engine? Just let me know and I can ship one to you in a few days.
It's also known that you can solve anything through sufficient levels of indirection. Every indirection level will eats some performance though.
I thought I was abstracting things. No big deal. I would rather use multiple levels of indirection instead of have a abstraction. But just to be funny if I had a rabbit, wand, and hat along with my multiple levels of indirection I would be a magician.
Finally, about your floppy driver... you can't blindly SENSE_INTERRUPT in the interrupt handler, because you can't READ/WRITE with interrupt then, because you get interrupts from those but they have their own result phase and shouldn't be handled with a SENSE_INTERRUPT (in fact, doing so will cause problems in both emulators and real hardware.. I bothered trying this).
Why did you not fix it??? You were supposed to fix it and repost it...shoot. You know those dumb little goblins of mine I found in a hole run through my code all the time when I have my back turned. :D

Posted: Thu Apr 05, 2007 5:45 pm
by mystran
Kevin McGuire wrote: I was trying to post in the thread about the "Community Operating System", but apparently the forum software bugged out, and the previous post from me got into this "High Performance Floppy Driver Implementation For Documentation And Learning" thread. Well. I do not know what to say frankly. I suppose..I apologize for posting in this thread and apparently with out knowing it. I also apologize for putting this floppy driver up for a example of a floppy driver's implementation. to anyone whom I may have confused by looking at it since it really does have poor value.
You are getting me wrong, on purpose I guess. Point was, that a driver which is nowhere near being functional doesn't necessarily demonstrate much of anything about a driver interface abstraction.
Umm.. That was the thread I was wanting to post to! You must be posting in the wrong threads too. You think the forum software is bugged or something? Thread-Discussion: sharing the drivers between kernels.
Ok, I must have misunderstood what you tried to say in your first post. I apologize for that. If you were simply trying to demonstrate modularity for the purpose of building one common operating system, then I don't understand why you quoted my comment about PIC/PIT originally, from a context where I was specifically discussing sharing drivers between different kernels.
What did you need a multi dimensionally warp engine? Just let me know and I can ship one to you in a few days.
I've been meaning to ask this for a while now... are you on drugs? :)
Why did you not fix it???
You are obviously taking an offence, when I am offering advice. That was not ment to be critique, as it's obvious the driver is nowhere near completion. I admit I could have used more filling words in order to more clearly separate the discussion and the advice about handling floppies, but I was in a hurry.

It took me a full day (that's 24h straight, coding/testing/searching for info) last weekend to figure out how the hell do floppy drives actually work. I found the information hard enough to figure out, that I wrote a tutorial about it. That's also why I'd give advice, but obviously you don't want any, and since we are getting into off-topic meta-discussion....actually, now that I think of, that demonstrates exactly why a community project of the kind "let's build a community OS" will typically get nowhere. :)

Posted: Thu Apr 05, 2007 8:14 pm
by Kevin McGuire
There are some drivers ofcourse, which there is no point of sharing. Timers and interrupt controllers are too fundamental to abstract, because not only the rest of the kernel, but every other driver will depend on them. Most will want console output available before even interrupts have been initialized, so that's another thing that needs to be special cased for each kernel (though code is mostly trivial).
The Original Reason
This is the original reason I post the code which you may remember as being two files only in really small text so it would not bulk up the thread. Lets see how I understood a part of you're post.
There are some drivers ofcourse,
The topic is drivers, which you say there is no point of sharing. Ok. Lets get to the meat.
Timers and interrupt controllers are too fundamental to abstract, because not only the rest of the kernel, but every other driver will depend on them.
Alright. Here you go. They are too fundamental to abstract. Yet honestly you just abstracted them you're self. You took a driver/device and its complex workings, which I mean as one timer device which may not be initialized and controlled the same as another, and you abstracted it by considering it to do one thing such as provide a time as a timer by ignoring the inner workings of how you make it provide this time or timer concept. You might write a certain sequence of bytes that could be completely different from device to device that is considered a programmable interrupt timer (which programmable interrupt timer is a abstraction).

You took the device (8253 or APIC) as a specific object or instance and pulled a characteristic from it. The APIC provides more than a timer therefore it is abstracted and looks just like the 8253 when abstracted considering it a programmable interrupt timer. The characteristic is the pulses for the timer when it triggers its self.
A meaning of the word abstract:
2. expressing a quality or characteristic apart from any specific object or instance, as justice, poverty, and speed.
One characteristic of the APIC is timing. One characteristic of the ISA bus to PCI bus device in QEMU is to provide timing, but they both provide other things. The interface provides the abstraction or the expressing of a characteristic with this in C:

Code: Select all

struct tclockInfo{
	CLOCKHZ		curHz;
	CLOCKHZ		reqHz;
	CLOCKHZ		maxHz;
	CLOCKHZ		minHz;
}; typedef struct tclockInfo CLOCKINFO; typedef CLOCKINFO* PCLOCKINFO;
struct iClockClock{
	i32 (*GetInfo)(PPRIVATE priv, PCLOCKINFO clock);
	i32 (*SetHz)(PPRIVATE, CLOCKHZ hz);	
}; typedef struct iClockClock ICLOCK_CLOCK;
The driver provides this since only it knows how to provide it. That is a abstraction.. It could provide multiple abstractions from a single driver instance. The above is a abstraction.
....because not only the rest of the kernel, but every other driver will depend on them.
Okay. So we can not abstract them because they are too fundamental. We should have just realized this because we are talking about drivers which directly talks about the complex device which can not be fundamental since each device is entirely different. Each device can be composed of fundamental circuitry components, but never the less each is individual. You are really saying that the abstraction of the devices is a fundamental abstraction. The abstraction of the devices you are talking about is said as programmable interrupt controller and timer. Lets see the entire sentence once more.
There are some drivers ofcourse, which there is no point of sharing. Timers and interrupt controllers are too fundamental to abstract, because not only the rest of the kernel, but every other driver will depend on them.
So I abstracted them, and if I write a APIC driver it will export a ICLOCK_CLOCK interface for each timer instance on board. Therfore abstracting each one to provide a characteristic or actually multiple characteristics.

The Point Was Really
Ok. So now you got a different point.
You are getting me wrong, on purpose I guess. Point was, that a driver which is nowhere near being functional doesn't necessarily demonstrate much of anything about a driver interface abstraction.
I could have sworn I posted a 8253 driver, 8259x2 driver, and a floppy driver. I think there was sufficient demonstration of abstraction using driver interfaces! What the hell do you mean by, driver interface abstraction? Is this a abstraction of a driver interface? How do I abstract a driver interface. I have enough trouble abstracting characteristics of devices using the driver let along trying to abstract the actual driver interface. I asked you do you want a multi-dimensional warp drive....

Ok. So the floppy driver was supposed to be a abstraction? Did you miss something. Lets go back and see.
There are some drivers ofcourse, which there is no point of sharing. Timers and interrupt controllers are too fundamental to abstract, because not only the rest of the kernel, but every other driver will depend on them.
Where in the world is floppy driver in here?

The only reason I posted the floppy driver was for a example of the usage of the abstractions.
....
Here is the driver for the floppy I am working on at the moment the point being it is using the abstractions, and the generic idea of it not being too complicated to get a general interface designed.
....
Can you read what I said? Go back to the page one of this thread and find my first post!

And once again there are two fully functional drivers which are actually part of the original topic!

And.. Once Again
Here is the original topic... you wrote it. You should remember it.
There are some drivers ofcourse, which there is no point of sharing. Timers and interrupt controllers are too fundamental to abstract, because not only the rest of the kernel, but every other driver will depend on them. Most will want console output available before even interrupts have been initialized, so that's another thing that needs to be special cased for each kernel (though code is mostly trivial).
So when did my floppy driver become a source of learning or documentation? If you still can not understand this then go read this post again. You said it like I should have never posted it because it was meant to be used as a example of the abstraction. Lets read what I wrote one more time.
....
Here is the driver for the floppy I am working on at the moment the point being it is using the abstractions, and the generic idea of it not being too complicated to get a general interface designed.
....
You can find this one the first page of this thread's post and the first post I made right before the super small code text.
The floppy driver really had squat to do with anything but just a example.

The clock and irqrouter abstract those interfaces even more by providing another interface which is:

Code: Select all

i32 irqrouter_RegisterInterrupt(PPRIVATE priv, IRQHANDLERFUNC handler, u8 vector, u32 flags);
i32 clock_revent(PPRIVATE priv, CLOCKHZ hz_from_now, CLOCK_EVENT_HANDLER handler, u32 flags);
[driver]--->[abstraction]---->[abstraction]--->[thread(kernel/user space)]

The End
So I found you're last two posts very annoying and completely off topic with me by means of my intentions in the beginning. I actually felt the real topic avoided and misunderstood while you used the floppy driver as a false argument to something not being abstractable. So get all these floppy drivers out of you head..the floppy driver is not of concern. Leave the floppy drivers in peace. I do not want to hear about the floppy driver anymore. I like that you have figured out how to work the floppy driver, but lets leave that for another place and not this one.

You have switched you're point from:
1. A driver for programmable interrupt timers and programmable interrupt controllers can not be abstracted because they are to fundamental.
2. When the driver is in such a state, I think it's documentary and example value for whatever purpose is extremely low.
3. Point was, that a driver which is nowhere near being functional doesn't necessarily demonstrate much of anything about a driver interface abstraction.

When my original intent was:
1. Here is the driver for the floppy I am working on at the moment the point being it is using the abstractions, and the generic idea of it not being too complicated to get a general interface designed.

.... There was more than just a floppy driver posted ....

It took me a full day (that's 24h straight, coding/testing/searching for info) last weekend to figure out how the hell do floppy drives actually work. I found the information hard enough to figure out, that I wrote a tutorial about it. That's also why I'd give advice, but obviously you don't want any, and since we are getting into off-topic meta-discussion....actually, now that I think of, that demonstrates exactly why a community project of the kind "let's build a community OS" will typically get nowhere.
No. My opinion is that part of the problem is people like you can not stay on topic. I mean stay on topic. I loved that you made a suggestion about the floppy driver which was:
Finally, about your floppy driver... you can't blindly SENSE_INTERRUPT in the interrupt handler, because you can't READ/WRITE with interrupt then, because you get interrupts from those but they have their own result phase and shouldn't be handled with a SENSE_INTERRUPT (in fact, doing so will cause problems in both emulators and real hardware.. I bothered trying this).

Not that your senseinterrupt() will necessarily work anyway on real hardware. You shouldn't read the ports before you've checked that the data is ready, for which you need to poll MSR and check bit7, preferably sleeping between the polling (because the hardware could be slow), which is why it's not necessarily such a good idea to run it from the interrupt handler at all (you could wake up a thread instead).
I hate that the other two thirds of your post was about:
Kevin McGuire: yeah I said in code-blocks, which is much better than not in code-blocks, but if you really want to post lots of code, there's also a relatively decent attachment system. Smile
Have you tried supporting several alternatives in each of those cases? I'm going to claim (without claiming your approach doesn't work) that it's not the first driver for an interface, but the second (or third) that shows if an interface is viable. (say, both PIC and APIC) Smile
Also, have you tried supporting the same drivers in several kernels. To some extend, we need to deal with alternatives for those in every kernel (well every kernel that wants to support wide range of hardware well) but the discussion was about sharing the drivers between kernels. This implies that the whole interface for the driver is well defined, and you never step outside it, because outside the well-defined interfaces, there could be completely different concepts in different systems. The futher complication is that when you add requirements to the interfaces, every time you're going to assume more of the kernel structure, limiting the drivers portability.
But yeah, like I said (after your comment), PIC/PIT wasn't necessarily good examples as such. It's also known that you can solve anything through sufficient levels of indirection. Every indirection level will eats some performance though.
When the driver is in such a state, I think it's documentary and example value for whatever purpose is extremely low.
It looks a little out of proportion and strangely biased towards it will not work because of the floppy driver's state. *shrug*

Posted: Thu Apr 05, 2007 9:08 pm
by mystran
This discussion will get neither of us nowhere. I apologized for any possible offence, which was unintentional, so I suggest you just get over it.

I still rest my case that even with "full sentences" you are pulling my text out of it's original context, which was abstracting devices for the purpose of sharing them between kernels. You are also ignoring the fact that I've now repeatedly admitted that the PIC/PIT example might have been a flawed one. It also won't benefit anyone to pretend that there can only be single point in a given forum post, if they aren't explicitly enumerated.

But there's now been more thermal energy in this conversation that it is definitely pointless to go any futher.

Posted: Thu Apr 05, 2007 9:25 pm
by Kevin McGuire
I'm happy. Just leave the goblin wrecked floppy driver along. Those little green midgets were just trying to help me debug it. See, a community operating system could work since we came to a agreement. :D

And. Yes. My argument was flawed too based on there being multiple topics/points in a forum thread. I apologize.

Posted: Thu Apr 05, 2007 9:29 pm
by pcmattman
IMHO there is one core reason why a community OS won't work: there will be far too many arguments over the core design features. It's fine if someone develops the core of the OS then the community contributes drives, shell code etc... but a completely community-driven OS cannot possibly work.

Human nature will always get in the way, and unless all 3,000 people of the OSDev community can meet together in one place and discuss and argue humanely there is no real way that a community OS is plausible.