; RDI - IRQ Number
; RSI - Callback
+ ; Check for RDI >= 16
cmp rdi, 16
jb .numOK
xor rax, rax
jmp .ret
.numOK:
- mov rax, rdi
- shr rax, 3+2
+ ; Get handler base into RAX
+ lea rax, [rdi*4]
mov rcx, gaIRQ_Handlers
- add rax, rcx
+ lea rax, [rcx+rax*8]
; Find a free callback slot
%rep NUM_IRQ_CALLBACKS
pop rsi
pop rdi
+ ; Assign and return
mov [rax], rsi
xor rax, rax
push gs
push fs
- mov rbx, [rsp+(16+2)*8] ; Calculate address
- shr rbx, 3+2 ; *8*4
+ mov rbx, [rsp+(16+2)*8] ; Get interrupt number (16 GPRS + 2 SRs)
+; xchg bx, bx ; Bochs Magic break (NOTE: will clear the high-bits of RBX)
+ shl rbx, 2 ; *8*4
mov rax, gaIRQ_Handlers
- add rbx, rax
+ lea rbx, [rax+rbx*8]
; Check all callbacks
+ sub rsp, 8 ; Shadow of argument
%assign i 0
%rep NUM_IRQ_CALLBACKS
; Get callback address
test rax, rax ; Check if it exists
jz .skip.%[i]
; Set RDI to IRQ number
- mov rdi, [rsp+16*8] ; Get IRQ number
+ mov rdi, [rsp+(16+2+1)*8] ; Get IRQ number
call rax ; Call
.skip.%[i]:
add rbx, 8 ; Next!
%assign i i+1
%endrep
+ add rsp, 8
; ACK
+ mov al, 0x20
mov rdi, [rsp+16*8] ; Get IRQ number
cmp rdi, 8
- mov al, 0x20
jb .skipAckSecondary
mov dx, 0x00A0
out dx, al
#if USE_MP
# include <mp.h>
#endif
+#include <arch_config.h>
// === FLAGS ===
#define DEBUG_TRACE_SWITCH 0
// === CONSTANTS ===
#define SWITCH_MAGIC 0x55ECAFFF##FFFACE55 // There is no code in this area
-// Base is 1193182
-#define TIMER_DIVISOR 11931 //~100Hz
// === TYPES ===
typedef struct sCPU
extern void Threads_Dump(void);
extern void Proc_ReturnToUser(void);
extern int GetCPUNum(void);
+extern void Time_UpdateTimestamp(void);
// === PROTOTYPES ===
void ArchThreads_Init(void);
// Set timer frequency
outb(0x43, 0x34); // Set Channel 0, Low/High, Rate Generator
- outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
- outb(0x40, (TIMER_DIVISOR>>8)&0xFF); // High Byte
+ outb(0x40, PIT_TIMER_DIVISOR&0xFF); // Low Byte of Divisor
+ outb(0x40, (PIT_TIMER_DIVISOR>>8)&0xFF); // High Byte
// Create Per-Process Data Block
if( !MM_Allocate(MM_PPD_CFG) )
rip = GetRIP();
if(rip == SWITCH_MAGIC) {
outb(0x20, 0x20); // ACK Timer and return as child
+ __asm__ __volatile__ ("sti");
return 0;
}
rip = GetRIP();
if(rip == SWITCH_MAGIC) {
outb(0x20, 0x20); // ACK Timer and return as child
+ __asm__ __volatile__ ("sti");
return 0;
}
{
Uint rsp, rbp, rip;
tThread *thread;
+
+ if( CPU == 0 )
+ Time_UpdateTimestamp();
// If the spinlock is set, let it complete
if(IS_LOCKED(&glThreadListLock)) return;
* arch/x86_64/time.c
*/
#include <acess.h>
+#include <arch_config.h>
// === MACROS ===
#define TIMER_QUANTUM 100
-// 2^(15-rate), 15: 1HZ, 5: 1024Hz, 2: 8192Hz
-// (Max: 15, Min: 2) - 15 = 1Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
-//#define TIMER_RATE 10 // 32 Hz
-//#define TIMER_RATE 12 // 8 Hz
-#define TIMER_RATE 14 // 2Hz
-//#define TIMER_RATE 15 // 1HZ
-#define TIMER_FREQ (0x8000>>TIMER_RATE) //Hz
-#define MS_PER_TICK_WHOLE (1000/(TIMER_FREQ))
-#define MS_PER_TICK_FRACT ((0x80000000*(1000%TIMER_FREQ))/TIMER_FREQ)
+#define TIMER_FREQ PIT_TIMER_BASE_N/(PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR)
+#define MS_PER_TICK_WHOLE (1000*(PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR)/PIT_TIMER_BASE_N)
+#define MS_PER_TICK_FRACT ((0x80000000ULL*1000ULL*PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR/PIT_TIMER_BASE_N)&0x7FFFFFFF)
// === IMPORTS ===
extern volatile Sint64 giTimestamp;
// === PROTOTYPES ===
//Sint64 now(void);
int Time_Setup(void);
-void Time_Interrupt(int);
+void Time_UpdateTimestamp(void);
Uint64 Time_ReadTSC(void);
// === CODE ===
*/
int Time_Setup(void)
{
- Uint8 val;
-
- Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
- TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
-
- outb(0x70, inb(0x70)&0x7F); // Disable NMIs
- __asm__ __volatile__ ("cli"); // Disable normal interrupts
-
- // Set IRQ8 firing rate
- outb(0x70, 0x0A); // Set the index to register A
- val = inb(0x71); // Get the current value of register A
- outb(0x70, 0x0A); // Reset index to A
- val &= 0xF0;
- val |= TIMER_RATE;
- outb(0x71, val); // Update the timer rate
-
- // Enable IRQ8
- outb(0x70, 0x0B); // Set the index to register B
- val = inb(0x71); // Read the current value of register B
- outb(0x70, 0x0B); // Set the index again (a read will reset the index to register D)
- outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
-
- __asm__ __volatile__ ("sti"); // Re-enable normal interrupts
- outb(0x70, inb(0x70)|0x80); // Re-enable NMIs
-
- // Install IRQ Handler
- IRQ_AddHandler(8, Time_Interrupt);
-
- // Make sure the RTC actually fires
- outb(0x70, 0x0C); // Select register C
- inb(0x71); // Just throw away contents.
+ Log_Log("Timer", "PIT Timer firing at %iHz, %i.0x%08x miliseconds per tick",
+ TIMER_FREQ, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
+
+ // TODO: Read time from RTC
return 0;
}
/**
* \brief Called on the timekeeping IRQ
- * \param irq IRQ number (unused)
*/
-void Time_Interrupt(int irq)
+void Time_UpdateTimestamp(void)
{
- //Log("RTC Tick");
Uint64 curTSC = Time_ReadTSC();
if( giTime_TSCAtLastTick )
}
Timer_CallTimers();
-
- // Make sure the RTC Fires again
- outb(0x70, 0x0C); // Select register C
- inb(0x71); // Just throw away contents.
}
#if 0
#define LOCK_DEBUG_OUTPUT 1
// === IMPORTS ===
-extern void Threads_Dump(void);
+extern void Threads_Dump(void);
extern void KernelPanic_SetMode(void);
extern void KernelPanic_PutChar(char Ch);
*/
void Time_Delay(int Delay)
{
- Sint64 dest = giTimestamp + Delay;
+ Sint64 dest = now() + Delay;
//Log("Time_Delay: dest = %lli", dest);
- while(dest > giTimestamp) Threads_Yield();
+ while(dest > now()) Threads_Yield();
//Log("Time_Delay: giTimestamp = %lli", giTimestamp);
}
// HACK: Ensure the PRDT is reset
ATA_int_BusMasterWriteDWord(cont*8+4, gaATA_PRDT_PAddrs[cont]);
-
+ ATA_int_BusMasterWriteByte(cont*8, 4); // Reset IRQ
+
LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
if( Address > 0x0FFFFFFF )
outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
int FDD_int_GetByte(int base, Uint8 *Byte);
int FDD_Reset(int id);
void FDD_Recalibrate(int disk);
+ int FDD_Reconfigure(int ID);
int FDD_int_SeekTrack(int disk, int head, int track);
void FDD_int_TimerCallback(void *Arg);
void FDD_int_StopMotor(void *Arg);
// Install IRQ6 Handler
IRQ_AddHandler(6, FDD_IRQHandler);
+
+ // Ensure the FDD version is 0x90
+ {
+ Uint8 tmp;
+ FDD_int_SendByte(cPORTBASE[0], CMD_VERSION);
+ FDD_int_GetByte(cPORTBASE[0], &tmp);
+ if( tmp != 0x90 ) {
+ Log_Error("FDD", "Version(0x%2x) != 0x90", tmp);
+ return MODULE_ERR_NOTNEEDED;
+ }
+ }
+
+ // Configure
+ FDD_Reconfigure(0);
+
// Reset Primary FDD Controller
if( FDD_Reset(0) != 0 ) {
return MODULE_ERR_MISC;
// Set Track in structure
gFDD_Devices[disk].track[head] = track;
-
+
+ LOG("Time_Delay(100)");
// Wait for Head to settle
Time_Delay(100);
outb(base + PORT_DIGOUTPUT, 0); // Disable FDC
// Wait 4 microseconds - or use 1 thread delay
Threads_Yield();
- outb(base + PORT_DIGOUTPUT, 0x0C); // Re-enable FDC (DMA and Enable)
+ Threads_Yield();
+ outb(base + PORT_DIGOUTPUT, 8|4); // Re-enable FDC (DMA and Enable)
+ // Set the data rate
+ outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s
+
+ // Wait for IRQ
LOG("Awaiting IRQ");
FDD_WaitIRQ();
+ LOG("4x SenseInterrupt");
FDD_SensInt(base, NULL, NULL);
FDD_SensInt(base, NULL, NULL);
FDD_SensInt(base, NULL, NULL);
FDD_SensInt(base, NULL, NULL);
- // Set the data rate
- outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s
-
- // Configure
+ // Specify
FDD_int_SendByte(base, CMD_SPECIFY); // Step and Head Load Times
FDD_int_SendByte(base, 0xDF); // Step Rate Time, Head Unload Time (Nibble each)
FDD_int_SendByte(base, 0x02); // Head Load Time >> 1
+ // Recalibrate disks
+ LOG("Recalibrate disks (16x seek)");
retries = 16;
while(FDD_int_SeekTrack(0, 0, 1) == 0 && retries --); // set track
- if(retries < 0) return -1;
+ if(retries < 0) LEAVE_RET('i', -1);
retries = 16;
- while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track
- if(retries < 0) return -1;
+ while(FDD_int_SeekTrack(0, 1, 1) == 0 && retries --); // set track
+ if(retries < 0) LEAVE_RET('i', -1);
LOG("Recalibrating Disk");
FDD_Recalibrate((id<<1)|0);
FDD_Recalibrate((id<<1)|1);
- LEAVE('i',0);
- return 0;
+ LEAVE_RET('i', 0);
}
/**
Y /= giVT_CharHeight;
H /= giVT_CharHeight;
- if( X > VGA_WIDTH || Y > VGA_HEIGHT ) return ;
- if( X + W > VGA_WIDTH ) W = VGA_WIDTH - X;
- if( Y + H > VGA_HEIGHT ) H = VGA_HEIGHT - Y;
-
ch.Ch = 0x20;
ch.BGCol = (Colour & 0x0F0000) >> (16-8);
ch.BGCol |= (Colour & 0x000F00) >> (8-4);
ch.BGCol |= (Colour & 0x00000F);
+ word = VGA_int_GetWord(&ch);
+
+ Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
+
+ if( X > VGA_WIDTH || Y > VGA_HEIGHT ) return ;
+ if( X + W > VGA_WIDTH ) W = VGA_WIDTH - X;
+ if( Y + H > VGA_HEIGHT ) H = VGA_HEIGHT - Y;
buf = gVGA_Framebuffer + Y*VGA_WIDTH + X;
- word = VGA_int_GetWord(&ch);
while( H -- ) {
int i;
// Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
+ if( SrcX > VGA_WIDTH || SrcY > VGA_HEIGHT ) return ;
+ if( SrcX + W > VGA_WIDTH ) W = VGA_WIDTH - SrcX;
+ if( SrcY + H > VGA_HEIGHT ) H = VGA_HEIGHT - SrcY;
+ if( DstX > VGA_WIDTH || DstY > VGA_HEIGHT ) return ;
+ if( DstX + W > VGA_WIDTH ) W = VGA_WIDTH - DstX;
+ if( DstY + H > VGA_HEIGHT ) H = VGA_HEIGHT - DstY;
+
+
src = gVGA_Framebuffer + SrcY*VGA_WIDTH + SrcX;
dst = gVGA_Framebuffer + DstY*VGA_WIDTH + DstX;