From: John Hodge Date: Tue, 11 May 2010 13:47:01 +0000 (+0800) Subject: x86_64 support, requiring a slight refactor to the build system. X-Git-Tag: rel0.06~196 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=a79ebcb3a2e206251f44e99376ec2ed6c2bacc63;p=tpg%2Facess2.git x86_64 support, requiring a slight refactor to the build system. - The x86_64 port does not compile yet, still working on that - The new cross compiler I'm using for the 32-bit builds is a little more pedantic, so it seems that the i386 doesn't build either. --- diff --git a/Kernel/Makefile.BuildNum b/Kernel/Makefile.BuildNum index 334be63d..c6eedfba 100644 --- a/Kernel/Makefile.BuildNum +++ b/Kernel/Makefile.BuildNum @@ -1 +1 @@ -BUILD_NUM = 2145 +BUILD_NUM = 2150 diff --git a/Kernel/arch/x86/include/proc.h b/Kernel/arch/x86/include/proc.h index 0a1d7548..baf9402c 100644 --- a/Kernel/arch/x86/include/proc.h +++ b/Kernel/arch/x86/include/proc.h @@ -7,9 +7,6 @@ #include -// === CONSTANTS === -#define GETMSG_IGNORE ((void*)-1) - // === TYPES === #if USE_MP typedef struct sCPU diff --git a/Kernel/arch/x86_64/Makefile b/Kernel/arch/x86_64/Makefile index 3820a691..68b9b615 100644 --- a/Kernel/arch/x86_64/Makefile +++ b/Kernel/arch/x86_64/Makefile @@ -10,7 +10,7 @@ #OBJDUMP = objdump CPPFLAGS = -CFLAGS = +CFLAGS = $(KERNEL_CFLAGS) ASFLAGS = -f elf ifeq ($(ARCH),amd64) diff --git a/Kernel/arch/x86_64/include/arch.h b/Kernel/arch/x86_64/include/arch.h index d812a514..e076b08e 100644 --- a/Kernel/arch/x86_64/include/arch.h +++ b/Kernel/arch/x86_64/include/arch.h @@ -5,17 +5,24 @@ #ifndef _ARCH_H_ #define _ARCH_H_ +#include #define KERNEL_BASE 0xFFFF8000##00000000 +#define BITS 64 // === Core Types === typedef signed char Sint8; typedef unsigned char Uint8; typedef signed short Sint16; typedef unsigned short Uint16; -typedef signed long Sint32; -typedef unsigned long Uint32; -typedef signed long long Sint64; -typedef unsigned long long Uint64; +typedef signed int Sint32; +typedef unsigned int Uint32; +#if __WORDSIZE == 64 +typedef signed long int Sint64; +typedef unsigned long int Uint64; +#else +typedef signed long long int Sint64; +typedef unsigned long long int Uint64; +#endif typedef Uint64 Uint; typedef Uint64 tPAddr; @@ -24,10 +31,38 @@ typedef Uint64 tVAddr; //typedef unsigned int size_t; typedef Uint64 size_t; -typedef int tSpinlock; +typedef volatile int tSpinlock; +#define IS_LOCKED(lockptr) (!!(*(tSpinlock*)lockptr)) +#define LOCK(lockptr) do {int v=1;\ + while(v)\ + __asm__ __volatile__("lock xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(lockptr));\ + }while(0) +#define RELEASE(lockptr) __asm__ __volatile__("lock andl $0, (%%edi)"::"D"(lockptr)); +#define HALT() __asm__ __volatile__ ("hlt") -#define LOCK(_ptr) -#define RELEASE(_ptr) +// Systemcall Registers +typedef struct sSyscallRegs +{ + Uint Arg4, Arg5; // RDI, RSI + Uint Arg6; // RBP + Uint Resvd2[1]; // Kernel RSP + union { + Uint Arg1; + Uint Error; + }; // RBX + union { + Uint Arg3; + Uint RetHi; // High 64 bits of ret + }; // RDX + Uint Arg2; // RCX + union { + Uint Num; + Uint Return; + }; // RAX + Uint Resvd3[5]; // Int, Err, rip, CS, ... + Uint StackPointer; // RSP + Uint Resvd4[1]; // SS +} tSyscallRegs; #endif diff --git a/Kernel/arch/x86_64/include/mm_virt.h b/Kernel/arch/x86_64/include/mm_virt.h index 2dd28dd6..8032cc77 100644 --- a/Kernel/arch/x86_64/include/mm_virt.h +++ b/Kernel/arch/x86_64/include/mm_virt.h @@ -9,6 +9,8 @@ #ifndef _VMEM_H_ #define _VMEM_H_ +#include + // === Memory Location Definitions === /* * Userland - Lower Half @@ -17,11 +19,19 @@ * 0xFFFF8000 00000000 - 0xFFFFFFFF FFFFFFFF 2**47 Kernel Range * 8000 00000000 - 8000 7FFFFFFF 2 GiB Identity Map * 8000 80000000 - 8001 00000000 2 GiB Kernel Heap - * 9000 00000000 0 9800 00000000 cbf Module Space + * 9000 00000000 - 9800 00000000 cbf Module Space + * 9800 00000000 - 9900 00000000 cbf Per-Process Data + * 9900 00000000 - 9A00 00000000 cbf Kernel VFS */ -#define KERNEL_BASE 0xFFF8000##00000000 -#define MM_KHEAP_BASE (KERNEL_BASE|0x80000000) -#define MM_KHEAP_MAX (KERNEL_BASE|0x1##00000000) +#define MM_USER_MIN 0x00008FFF##FFFFF000 +//#define KERNEL_BASE 0xFFF8000##00000000 +#define MM_KHEAP_BASE (KERNEL_BASE|(0x0000##80000000)) +#define MM_KHEAP_MAX (KERNEL_BASE|(0x0001##00000000)) +#define MM_MODULE_MIN (KERNEL_BASE|(0x1000##00000000)) +#define MM_MODULE_MAX (KERNEL_BASE|(0x1800##00000000)) +#define MM_PPD_BASE (KERNEL_BASE|(0x1800##00000000)) +#define MM_PPD_VFS (KERNEL_BASE|(0x1880##00000000)) +#define MM_KERNEL_VFS (KERNEL_BASE|(0x1900##00000000)) #endif diff --git a/Kernel/arch/x86_64/include/proc.h b/Kernel/arch/x86_64/include/proc.h new file mode 100644 index 00000000..016375f6 --- /dev/null +++ b/Kernel/arch/x86_64/include/proc.h @@ -0,0 +1,22 @@ +/* + * Acess2 x86_64 Port + * + * proc.h - Process/Thread management code + */ +#ifndef _PROC_H_ +#define _PROC_H_ + +#include + +typedef struct sMemoryState +{ + tPAddr CR3; +} tMemoryState; + +typedef struct sTaskState +{ + Uint RIP, RSP, RBP; +} tTaskState; + +#endif + diff --git a/Kernel/arch/x86_64/include/vm8086.h b/Kernel/arch/x86_64/include/vm8086.h new file mode 100644 index 00000000..353ad7a3 --- /dev/null +++ b/Kernel/arch/x86_64/include/vm8086.h @@ -0,0 +1,67 @@ +/* + * Acess2 VM8086 BIOS Interface + * - By John Hodge (thePowersGang) + * + * vm8086.h + * - Core Header + */ +#ifndef _VM80806_H_ +#define _VM80806_H_ + +// === TYPES === +/** + * \note Semi-opaque - Past \a .IP, the implementation may add any data + * it needs to the state. + */ +typedef struct sVM8086 +{ + Uint16 AX, CX, DX, BX; + Uint16 BP, SP, SI, DI; + + Uint16 SS, DS, ES; + + Uint16 CS, IP; + + struct sVM8086_InternalData *Internal; +} tVM8086; + +// === FUNCTIONS === +/** + * \brief Create an instance of the VM8086 Emulator + * \note Do not free this pointer with ::free, instead use ::VM8086_Free + * \return Pointer to a tVM8086 structure, this structure may be larger than + * tVM8086 due to internal data. + */ +extern tVM8086 *VM8086_Init(void); +/** + * \brief Free an allocated tVM8086 structure + * \param State Emulator state to free + */ +extern void VM8086_Free(tVM8086 *State); +/** + * \brief Allocate a piece of memory in the emulated address space and + * return a host and emulated pointer to it. + * \param State Emulator state + * \param Size Size of memory block + * \param Segment Pointer to location to store the allocated memory's segment + * \param Offset Pointet to location to store the allocated memory's offset + * \return Host pointer to the allocated memory + */ +extern void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset); +/** + * \brief Gets a pointer to a piece of emulated memory + * \todo Only 1 machine page is garenteed to be contiguous + * \param State Emulator State + * \param Segment Source Segment + * \param Offset Source Offset + * \return Host pointer to the emulated memory + */ +extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Ofs); +/** + * \brief Calls a real-mode interrupt described by the current state of the IVT. + * \param State Emulator State + * \param Interrupt BIOS Interrupt to call + */ +extern void VM8086_Int(tVM8086 *State, Uint8 Interrupt); + +#endif diff --git a/Kernel/arch/x86_64/lib.c b/Kernel/arch/x86_64/lib.c index e69de29b..e3669c04 100644 --- a/Kernel/arch/x86_64/lib.c +++ b/Kernel/arch/x86_64/lib.c @@ -0,0 +1,93 @@ +/* + */ +#include +#include + +// === CODE === + +void outb(Uint16 Port, Uint8 Data) +{ + __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data)); +} +void outw(Uint16 Port, Uint16 Data) +{ + __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data)); +} +void outd(Uint16 Port, Uint32 Data) +{ + __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data)); +} +Uint8 inb(Uint16 Port) +{ + Uint8 ret; + __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port)); + return ret; +} +Uint16 inw(Uint16 Port) +{ + Uint16 ret; + __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port)); + return ret; +} +Uint32 ind(Uint16 Port) +{ + Uint32 ret; + __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port)); + return ret; +} + +// === Endianness === +Uint32 BigEndian32(Uint32 Value) +{ + Uint32 ret; + ret = (Value >> 24); + ret |= ((Value >> 16) & 0xFF) << 8; + ret |= ((Value >> 8) & 0xFF) << 16; + ret |= ((Value >> 0) & 0xFF) << 24; + return ret; +} + +Uint16 BigEndian16(Uint16 Value) +{ + return (Value>>8)|(Value<<8); +} + +// === Memory Manipulation === +void *memcpy(void *__dest, const void *__src, size_t __count) +{ + if( ((tVAddr)__dest & 7) != ((tVAddr)__src & 7) ) + __asm__ __volatile__ ("rep movsb" : : "D"(__dest),"S"(__src),"c"(__count)); + else { + const Uint8 *src = __src; + Uint8 *dst = __dest; + while( (tVAddr)src & 7 && __count ) { + *dst++ = *src++; + __count --; + } + + __asm__ __volatile__ ("rep movsq" : : "D"(dst),"S"(src),"c"(__count/8)); + src += __count & ~7; + dst += __count & ~7; + __count = __count & 7; + while( __count-- ) + *dst++ = *src++; + } + return __dest; +} + +void *memset(void *__dest, int __val, size_t __count) +{ + if( __val != 0 || ((tVAddr)__dest & 7) != 0 ) + __asm__ __volatile__ ("rep stosb" : : "D"(__dest),"a"(__val),"c"(__count)); + else { + Uint8 *dst = __dest; + + __asm__ __volatile__ ("rep stosq" : : "D"(dst),"a"(0),"c"(__count/8)); + dst += __count & ~7; + __count = __count & 7; + while( __count-- ) + *dst++ = 0; + } + return __dest; +} + diff --git a/Kernel/arch/x86_64/link.ld b/Kernel/arch/x86_64/link.ld new file mode 100644 index 00000000..cab3c5c1 --- /dev/null +++ b/Kernel/arch/x86_64/link.ld @@ -0,0 +1,73 @@ +/* + * AcessMicro Kernel + * Linker Script + */ + +_kernel_base = 0xFFFF800000000000; + +//lowStart = start - _kernel_base; +ENTRY(start) +OUTPUT_FORMAT(elf64-x86-64) + +SECTIONS { + . = 0x100000; + __load_addr = .; + .multiboot : AT(ADDR(.multiboot)) { + *(.multiboot) + } + + . += _kernel_base; + + .text ALIGN(0x1000): AT(ADDR(.text) - _kernel_base) { + *(.text) + } + + .usertext ALIGN(0x1000): AT(ADDR(.usertext) - _kernel_base) { + _UsertextBase = .; + *(.usertext) + } + _UsertextEnd = .; + + .rodata ALIGN(0x1000): AT(ADDR(.rodata) - _kernel_base) { + *(.initpd) + *(.rodata) + *(.rdata) + gKernelModules = .; + *(KMODULES) + gKernelModulesEnd = .; + . = ALIGN(4); + gKernelSymbols = .; + *(KEXPORT) + gKernelSymbolsEnd = .; + + + } + /* + .debug_abbrev : { *(.debug_abbrev) } + .debug_info : { *(.debug_info) } + .debug_line : { *(.debug_line) } + .debug_loc : { *(.debug_loc) } + .debug_pubnames : { *(.debug_pubnames) } + .debug_aranges : { *(.debug_aranges) } + .debug_ranges : { *(.debug_ranges) } + .debug_str : { *(.debug_str) } + .debug_frame : { *(.debug_frame) } + */ + + .padata ALIGN (0x1000) : AT(ADDR(.padata) - _kernel_base) { + *(.padata) + } + + .data ALIGN (0x1000) : AT(ADDR(.data) - _kernel_base) { + *(.data) + } + + __bss_start = .; + .bss : AT(ADDR(.bss) - _kernel_base) { + _sbss = .; + *(COMMON) + *(.bss) + _ebss = .; + } + gKernelEnd = (. + 0xFFF)&0xFFFFFFFFFFFFF000; +} diff --git a/Kernel/arch/x86_64/rme.c b/Kernel/arch/x86_64/rme.c new file mode 120000 index 00000000..330f4f5f --- /dev/null +++ b/Kernel/arch/x86_64/rme.c @@ -0,0 +1 @@ +/home/tpg/Projects/RealmodeEmulator/src/rme.c \ No newline at end of file diff --git a/Kernel/arch/x86_64/rme.h b/Kernel/arch/x86_64/rme.h new file mode 120000 index 00000000..98b2739f --- /dev/null +++ b/Kernel/arch/x86_64/rme.h @@ -0,0 +1 @@ +/home/tpg/Projects/RealmodeEmulator/src/rme.h \ No newline at end of file diff --git a/Kernel/bin/elf.c b/Kernel/bin/elf.c index ad8edb0c..3209c044 100644 --- a/Kernel/bin/elf.c +++ b/Kernel/bin/elf.c @@ -297,7 +297,7 @@ int Elf_Relocate(void *Base) Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n"); continue; } - dynamicTab = (void *) phtab[i].VAddr; + dynamicTab = (void *) (tVAddr) phtab[i].VAddr; j = i; // Save Dynamic Table ID break; } @@ -326,20 +326,20 @@ int Elf_Relocate(void *Base) // --- Symbol Table --- case DT_SYMTAB: dynamicTab[j].d_val += iBaseDiff; - dynsymtab = (void*)(dynamicTab[j].d_val); + dynsymtab = (void*) (tVAddr) dynamicTab[j].d_val; hdr->misc.SymTable = dynamicTab[j].d_val; // Saved in unused bytes of ident break; // --- String Table --- case DT_STRTAB: dynamicTab[j].d_val += iBaseDiff; - dynstrtab = (void*)(dynamicTab[j].d_val); + dynstrtab = (void*) (tVAddr) dynamicTab[j].d_val; break; // --- Hash Table -- case DT_HASH: dynamicTab[j].d_val += iBaseDiff; - iSymCount = ((Uint*)(dynamicTab[j].d_val))[1]; + iSymCount = ((Uint*)((tVAddr)dynamicTab[j].d_val))[1]; hdr->misc.HashTable = dynamicTab[j].d_val; // Saved in unused bytes of ident break; } diff --git a/Kernel/binary.c b/Kernel/binary.c index 77309f38..ffa07304 100644 --- a/Kernel/binary.c +++ b/Kernel/binary.c @@ -1,831 +1,832 @@ -/* - * Acess2 - * Common Binary Loader - */ -#define DEBUG 0 -#include -#include - -// === CONSTANTS === -#define BIN_LOWEST MM_USER_MIN // 1MiB -#define BIN_GRANUALITY 0x10000 // 64KiB -//! \todo Move 0xBC000000 to mm_virt.h -#define BIN_HIGHEST (0xBC000000-BIN_GRANUALITY) // Just below the kernel -#define KLIB_LOWEST MM_MODULE_MIN -#define KLIB_GRANUALITY 0x10000 // 32KiB -#define KLIB_HIGHEST (MM_MODULE_MAX-KLIB_GRANUALITY) - -// === TYPES === -typedef struct sKernelBin { - struct sKernelBin *Next; - void *Base; - tBinary *Info; -} tKernelBin; - -// === IMPORTS === -extern int Proc_Clone(Uint *Err, Uint Flags); -extern char *Threads_GetName(int ID); -extern void Threads_Exit(int, int); -extern Uint MM_ClearUser(); -extern void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize); -extern tKernelSymbol gKernelSymbols[]; -extern void gKernelSymbolsEnd; -extern tBinaryType gELF_Info; - -// === PROTOTYPES === - int Proc_Execve(char *File, char **ArgV, char **EnvP); -Uint Binary_Load(char *file, Uint *entryPoint); -tBinary *Binary_GetInfo(char *truePath); -Uint Binary_MapIn(tBinary *binary); -Uint Binary_IsMapped(tBinary *binary); -tBinary *Binary_DoLoad(char *truePath); -void Binary_Dereference(tBinary *Info); -Uint Binary_Relocate(void *Base); -Uint Binary_GetSymbolEx(char *Name, Uint *Value); -Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val); - -// === GLOBALS === - int glBinListLock = 0; -tBinary *glLoadedBinaries = NULL; -char **gsaRegInterps = NULL; - int giRegInterps = 0; - int glKBinListLock = 0; -tKernelBin *glLoadedKernelLibs; -tBinaryType *gRegBinTypes = &gELF_Info; - -// === FUNCTIONS === -/** - * \brief Registers a binary type - */ -int Binary_RegisterType(tBinaryType *Type) -{ - Type->Next = gRegBinTypes; - gRegBinTypes = Type; - return 1; -} - -/** - * \fn int Proc_Spawn(char *Path) - */ -int Proc_Spawn(char *Path) -{ - char stackPath[strlen(Path)+1]; - - strcpy(stackPath, Path); - - LOG("stackPath = '%s'\n", stackPath); - - if(Proc_Clone(NULL, CLONE_VM) == 0) - { - // CHILD - char *args[2] = {stackPath, NULL}; - LOG("stackPath = '%s'\n", stackPath); - Proc_Execve(stackPath, args, &args[1]); - for(;;); - } - return 0; -} - -/** - * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP) - * \brief Replace the current user image with another - * \param File File to load as the next image - * \param ArgV Arguments to pass to user - * \param EnvP User's environment - * \note Called Proc_ for historical reasons - */ -int Proc_Execve(char *File, char **ArgV, char **EnvP) -{ - int argc, envc, i; - int argenvBytes; - char *argenvBuf, *strBuf; - char **argvSaved, **envpSaved; - char *savedFile; - Uint entry; - Uint bases[2] = {0}; - - ENTER("sFile pArgV pEnvP", File, ArgV, EnvP); - - // --- Save File, ArgV and EnvP (also get argc) - - // Count Arguments, Environment Variables and total string sizes - argenvBytes = 0; - for( argc = 0; ArgV && ArgV[argc]; argc++ ) - argenvBytes += strlen(ArgV[argc])+1; - for( envc = 0; EnvP && EnvP[envc]; envc++ ) - argenvBytes += strlen(EnvP[envc])+1; - argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1); - argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*); - - // Allocate - argenvBuf = malloc(argenvBytes); - if(argenvBuf == NULL) { - Warning("Proc_Execve - What the hell? The kernel is out of heap space"); - return 0; - } - strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*); - - // Populate - argvSaved = (char **) argenvBuf; - for( i = 0; i < argc; i++ ) - { - argvSaved[i] = strBuf; - strcpy(argvSaved[i], ArgV[i]); - strBuf += strlen(ArgV[i])+1; - } - argvSaved[i] = NULL; - envpSaved = &argvSaved[i+1]; - for( i = 0; i < envc; i++ ) - { - envpSaved[i] = strBuf; - strcpy(envpSaved[i], EnvP[i]); - strBuf += strlen(EnvP[i])+1; - } - - savedFile = malloc(strlen(File)+1); - strcpy(savedFile, File); - - // --- Set Process Name - Threads_SetName(File); - - // --- Clear User Address space - MM_ClearUser(); - - // --- Load new binary - bases[0] = Binary_Load(savedFile, &entry); - free(savedFile); - if(bases[0] == 0) - { - Warning("Proc_Execve - Unable to load '%s'", Threads_GetName(-1)); - Threads_Exit(0, 0); - for(;;); - } - - LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]); - LEAVE('-'); - // --- And... Jump to it - Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes); - for(;;); // Tell GCC that we never return -} - -/** - * \fn Uint Binary_Load(char *file, Uint *entryPoint) - */ -Uint Binary_Load(char *file, Uint *entryPoint) -{ - char *sTruePath; - tBinary *pBinary; - Uint base = -1; - - ENTER("sfile", file); - - // Sanity Check Argument - if(file == NULL) { - LEAVE('x', 0); - return 0; - } - - // Get True File Path - sTruePath = VFS_GetTruePath(file); - - if(sTruePath == NULL) { - Warning("[BIN ] '%s' does not exist.", file); - LEAVE('x', 0); - return 0; - } - - LOG("sTruePath = '%s'", sTruePath); - - // Check if the binary has already been loaded - if( !(pBinary = Binary_GetInfo(sTruePath)) ) - pBinary = Binary_DoLoad(sTruePath); // Else load it - - // Clean Up - free(sTruePath); - - // Error Check - if(pBinary == NULL) { - LEAVE('x', 0); - return 0; - } - - #if 0 - if( (base = Binary_IsMapped(pBinary)) ) { - LEAVE('x', base); - return base; - } - #endif - - // Map into process space - base = Binary_MapIn(pBinary); // If so then map it in - - // Check for errors - if(base == 0) { - LEAVE('x', 0); - return 0; - } - - // Interpret - if(pBinary->Interpreter) { - Uint start; - if( Binary_Load(pBinary->Interpreter, &start) == 0 ) { - LEAVE('x', 0); - return 0; - } - *entryPoint = start; - } - else - *entryPoint = pBinary->Entry - pBinary->Base + base; - - // Return - LOG("*entryPoint = 0x%x", *entryPoint); - LEAVE('x', base); - return base; // Pass the base as an argument to the user if there is an interpreter -} - -/** - * \brief Finds a matching binary entry - * \param TruePath File Identifier (True path name) - */ -tBinary *Binary_GetInfo(char *TruePath) -{ - tBinary *pBinary; - pBinary = glLoadedBinaries; - while(pBinary) - { - if(strcmp(pBinary->TruePath, TruePath) == 0) - return pBinary; - pBinary = pBinary->Next; - } - return NULL; -} - -/** - \fn Uint Binary_MapIn(tBinary *binary) - \brief Maps an already-loaded binary into an address space. - \param binary Pointer to globally stored data. -*/ -Uint Binary_MapIn(tBinary *binary) -{ - Uint base; - Uint addr; - int i; - - // Reference Executable (Makes sure that it isn't unloaded) - binary->ReferenceCount ++; - - // Get Binary Base - base = binary->Base; - - // Check if base is free - if(base != 0) - { - for(i=0;iNumPages;i++) - { - if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) { - base = 0; - LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF); - break; - } - } - } - - // Check if the executable has no base or it is not free - if(base == 0) - { - // If so, give it a base - base = BIN_HIGHEST; - while(base >= BIN_LOWEST) - { - for(i=0;iNumPages;i++) - { - addr = binary->Pages[i].Virtual & ~0xFFF; - addr -= binary->Base; - addr += base; - if( MM_GetPhysAddr( addr ) ) break; - } - // If space was found, break - if(i == binary->NumPages) break; - // Else decrement pointer and try again - base -= BIN_GRANUALITY; - } - } - - // Error Check - if(base < BIN_LOWEST) { - Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath); - return 0; - } - - // Map Executable In - for(i=0;iNumPages;i++) - { - addr = binary->Pages[i].Virtual & ~0xFFF; - addr -= binary->Base; - addr += base; - LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical); - MM_Map( addr, (Uint) (binary->Pages[i].Physical) ); - - // Read-Only? - if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO) - MM_SetFlags( addr, MM_PFLAG_RO, -1 ); - else - MM_SetFlags( addr, MM_PFLAG_COW, -1 ); - - // Execute? - if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC ) - MM_SetFlags( addr, MM_PFLAG_EXEC, -1 ); - else - MM_SetFlags( addr, MM_PFLAG_EXEC, 0 ); - - } - - //Log("Mapped '%s' to 0x%x", binary->TruePath, base); - - //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual); - - return base; -} - -#if 0 -/** - * \fn Uint Binary_IsMapped(tBinary *binary) - * \brief Check if a binary is already mapped into the address space - * \param binary Binary information to check - * \return Current Base or 0 - */ -Uint Binary_IsMapped(tBinary *binary) -{ - Uint iBase; - - // Check prefered base - iBase = binary->Base; - if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF)) - return iBase; - - for(iBase = BIN_HIGHEST; - iBase >= BIN_LOWEST; - iBase -= BIN_GRANUALITY) - { - if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF)) - return iBase; - } - - return 0; -} -#endif - -/** - * \fn tBinary *Binary_DoLoad(char *truePath) - * \brief Loads a binary file into memory - * \param truePath Absolute filename of binary - */ -tBinary *Binary_DoLoad(char *truePath) -{ - tBinary *pBinary; - int fp, i; - Uint ident; - tBinaryType *bt = gRegBinTypes; - - ENTER("struePath", truePath); - - // Open File - fp = VFS_Open(truePath, VFS_OPENFLAG_READ); - if(fp == -1) { - LOG("Unable to load file, access denied"); - LEAVE('n'); - return NULL; - } - - // Read File Type - VFS_Read(fp, 4, &ident); - VFS_Seek(fp, 0, SEEK_SET); - - for(; bt; bt = bt->Next) - { - if( (ident & bt->Mask) != (Uint)bt->Ident ) - continue; - pBinary = bt->Load(fp); - break; - } - if(!bt) { - Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)", - truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF); - LEAVE('n'); - return NULL; - } - - // Error Check - if(pBinary == NULL) { - LEAVE('n'); - return NULL; - } - - // Initialise Structure - pBinary->ReferenceCount = 0; - pBinary->TruePath = malloc( strlen(truePath) + 1 ); - strcpy(pBinary->TruePath, truePath); - - // Debug Information - LOG("Interpreter: '%s'", pBinary->Interpreter); - LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry); - LOG("NumPages: %i", pBinary->NumPages); - - // Read Data - for(i=0;iNumPages;i++) - { - Uint dest; - tPAddr paddr; - paddr = (Uint)MM_AllocPhys(); - if(paddr == 0) { - Warning("Binary_DoLoad - Physical memory allocation failed"); - for( ; i--; ) { - MM_DerefPhys( pBinary->Pages[i].Physical ); - } - return NULL; - } - MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be - dest = MM_MapTemp( paddr ); - dest += pBinary->Pages[i].Virtual & 0xFFF; - LOG("dest = 0x%x, paddr = 0x%x", dest, paddr); - LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}", - i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size); - - // Pure Empty Page - if(pBinary->Pages[i].Physical == -1) { - LOG("%i - ZERO", i); - memsetd( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF)/4 ); - } - else - { - VFS_Seek( fp, pBinary->Pages[i].Physical, 1 ); - if(pBinary->Pages[i].Size != 0x1000) { - LOG("%i - 0x%llx - 0x%x bytes", - i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size); - memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) ); - VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest ); - } else { - LOG("%i - 0x%x", i, pBinary->Pages[i].Physical); - VFS_Read( fp, 0x1000, (void*)dest ); - } - } - pBinary->Pages[i].Physical = paddr; - MM_FreeTemp( dest ); - } - LOG("Page Count: %i", pBinary->NumPages); - - // Close File - VFS_Close(fp); - - // Add to the list - LOCK(&glBinListLock); - pBinary->Next = glLoadedBinaries; - glLoadedBinaries = pBinary; - RELEASE(&glBinListLock); - - // Return - LEAVE('p', pBinary); - return pBinary; -} - -/** - * \fn void Binary_Unload(void *Base) - * \brief Unload / Unmap a binary - * \param Base Loaded Base - * \note Currently used only for kernel libaries - */ -void Binary_Unload(void *Base) -{ - tKernelBin *pKBin; - tKernelBin *prev = NULL; - int i; - - if((Uint)Base < 0xC0000000) - { - // TODO: User Binaries - Warning("[BIN ] Unloading user binaries is currently unimplemented"); - return; - } - - // Kernel Libraries - for(pKBin = glLoadedKernelLibs; - pKBin; - prev = pKBin, pKBin = pKBin->Next) - { - // Check the base - if(pKBin->Base != Base) continue; - // Deallocate Memory - for(i = 0; i < pKBin->Info->NumPages; i++) { - MM_Deallocate( (Uint)Base + (i << 12) ); - } - // Dereference Binary - Binary_Dereference( pKBin->Info ); - // Remove from list - if(prev) prev->Next = pKBin->Next; - else glLoadedKernelLibs = pKBin->Next; - // Free Kernel Lib - free(pKBin); - return; - } -} - -/** - * \fn void Binary_Dereference(tBinary *Info) - * \brief Dereferences and if nessasary, deletes a binary - * \param Info Binary information structure - */ -void Binary_Dereference(tBinary *Info) -{ - // Decrement reference count - Info->ReferenceCount --; - - // Check if it is still in use - if(Info->ReferenceCount) return; - - /// \todo Implement binary freeing -} - -/** - * \fn char *Binary_RegInterp(char *Path) - * \brief Registers an Interpreter - * \param Path Path to interpreter provided by executable - */ -char *Binary_RegInterp(char *Path) -{ - int i; - // NULL Check Argument - if(Path == NULL) return NULL; - // NULL Check the array - if(gsaRegInterps == NULL) - { - giRegInterps = 1; - gsaRegInterps = malloc( sizeof(char*) ); - gsaRegInterps[0] = malloc( strlen(Path) ); - strcpy(gsaRegInterps[0], Path); - return gsaRegInterps[0]; - } - - // Scan Array - for( i = 0; i < giRegInterps; i++ ) - { - if(strcmp(gsaRegInterps[i], Path) == 0) - return gsaRegInterps[i]; - } - - // Interpreter is not in list - giRegInterps ++; - gsaRegInterps = malloc( sizeof(char*)*giRegInterps ); - gsaRegInterps[i] = malloc( strlen(Path) ); - strcpy(gsaRegInterps[i], Path); - return gsaRegInterps[i]; -} - -// ============ -// Kernel Binary Handling -// ============ -/** - * \fn void *Binary_LoadKernel(char *File) - * \brief Load a binary into kernel space - * \note This function shares much with #Binary_Load, but does it's own mapping - * \param File File to load into the kernel - */ -void *Binary_LoadKernel(char *File) -{ - char *sTruePath; - tBinary *pBinary; - tKernelBin *pKBinary; - Uint base = -1; - Uint addr; - int i; - - ENTER("sfile", File); - - // Sanity Check Argument - if(File == NULL) { - LEAVE('n'); - return 0; - } - - // Get True File Path - sTruePath = VFS_GetTruePath(File); - if(sTruePath == NULL) { - LEAVE('n'); - return 0; - } - - // Check if the binary has already been loaded - if( (pBinary = Binary_GetInfo(sTruePath)) ) - { - for(pKBinary = glLoadedKernelLibs; - pKBinary; - pKBinary = pKBinary->Next ) - { - if(pKBinary->Info == pBinary) { - LEAVE('p', pKBinary->Base); - return pKBinary->Base; - } - } - } - else - pBinary = Binary_DoLoad(sTruePath); // Else load it - - // Error Check - if(pBinary == NULL) { - LEAVE('n'); - return NULL; - } - - // -------------- - // Now pBinary is valid (either freshly loaded or only user mapped) - // So, map it into kernel space - // -------------- - - // Reference Executable (Makes sure that it isn't unloaded) - pBinary->ReferenceCount ++; - - // Check compiled base - base = pBinary->Base; - // - Sanity Check - if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) { - base = 0; - } - // - Check if it is a valid base address - if(base != 0) - { - for(i=0;iNumPages;i++) - { - if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) { - base = 0; - LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF); - break; - } - } - } - - // Check if the executable has no base or it is not free - if(base == 0) - { - // If so, give it a base - base = KLIB_LOWEST; - while(base < KLIB_HIGHEST) - { - for(i = 0; i < pBinary->NumPages; i++) - { - addr = pBinary->Pages[i].Virtual & ~0xFFF; - addr -= pBinary->Base; - addr += base; - if( MM_GetPhysAddr( addr ) ) break; - } - // If space was found, break - if(i == pBinary->NumPages) break; - // Else decrement pointer and try again - base += KLIB_GRANUALITY; - } - } - - // - Error Check - if(base >= KLIB_HIGHEST) { - Warning("[BIN ] Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath); - Binary_Dereference( pBinary ); - LEAVE('n'); - return 0; - } - - LOG("base = 0x%x", base); - - // - Map binary in - LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages); - for(i = 0; i < pBinary->NumPages; i++) - { - addr = pBinary->Pages[i].Virtual & ~0xFFF; - addr -= pBinary->Base; - addr += base; - LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical); - MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) ); - MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL ); - - if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only? - MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL ); - } - - // Relocate Library - if( !Binary_Relocate( (void*)base ) ) - { - Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath); - Binary_Unload( (void*)base ); - Binary_Dereference( pBinary ); - LEAVE('n'); - return 0; - } - - // Add to list (relocator must look at itself manually, not via Binary_GetSymbol) - pKBinary = malloc(sizeof(*pKBinary)); - pKBinary->Base = (void*)base; - pKBinary->Info = pBinary; - LOCK( &glKBinListLock ); - pKBinary->Next = glLoadedKernelLibs; - glLoadedKernelLibs = pKBinary; - RELEASE( &glKBinListLock ); - - LEAVE('p', base); - return (void*)base; -} - -/** - * \fn Uint Binary_Relocate(void *Base) - * \brief Relocates a loaded binary (used by kernel libraries) - * \param Base Loaded base address of binary - * \return Boolean Success - */ -Uint Binary_Relocate(void *Base) -{ - Uint32 ident = *(Uint32*) Base; - tBinaryType *bt = gRegBinTypes; - - for(; bt; bt = bt->Next) - { - if( (ident & bt->Mask) == (Uint)bt->Ident ) - return bt->Relocate( (void*)Base); - } - - Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)", - Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF); - return 0; -} - -/** - * \fn int Binary_GetSymbol(char *Name, Uint *Val) - * \brief Get a symbol value - * \return Value of symbol or -1 on error - * - * Gets the value of a symbol from either the currently loaded - * libraries or the kernel's exports. - */ -int Binary_GetSymbol(char *Name, Uint *Val) -{ - if( Binary_GetSymbolEx(Name, Val) ) return 1; - return 0; -} - -/** - * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value) - * \brief Get a symbol value - * - * Gets the value of a symbol from either the currently loaded - * libraries or the kernel's exports. - */ -Uint Binary_GetSymbolEx(char *Name, Uint *Value) -{ - int i; - tKernelBin *pKBin; - int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol); - - // Scan Kernel - for( i = 0; i < numKSyms; i++ ) - { - if(strcmp(Name, gKernelSymbols[i].Name) == 0) { - *Value = gKernelSymbols[i].Value; - return 1; - } - } - - // Scan Loaded Libraries - for(pKBin = glLoadedKernelLibs; - pKBin; - pKBin = pKBin->Next ) - { - if( Binary_FindSymbol(pKBin->Base, Name, Value) ) { - return 1; - } - } - - Warning("[BIN ] Unable to find symbol '%s'", Name); - return 0; -} - -/** - * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val) - * \brief Get a symbol from the specified library - * \param Base Base address - * \param Name Name of symbol to find - * \param Val Pointer to place final value - */ -Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val) -{ - Uint32 ident = *(Uint32*) Base; - tBinaryType *bt = gRegBinTypes; - - for(; bt; bt = bt->Next) - { - if( (ident & bt->Mask) == (Uint)bt->Ident ) - return bt->GetSymbol(Base, Name, Val); - } - - Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)", - Base, ident&0xFF, ident>>8, ident>>16, ident>>24); - return 0; -} - -// === EXPORTS === -EXPORT(Binary_FindSymbol); -EXPORT(Binary_Unload); +/* + * Acess2 + * Common Binary Loader + */ +#define DEBUG 0 +#include +#include +#include + +// === CONSTANTS === +#define BIN_LOWEST MM_USER_MIN // 1MiB +#define BIN_GRANUALITY 0x10000 // 64KiB +//! \todo Move 0xBC000000 to mm_virt.h +#define BIN_HIGHEST (0xBC000000-BIN_GRANUALITY) // Just below the kernel +#define KLIB_LOWEST MM_MODULE_MIN +#define KLIB_GRANUALITY 0x10000 // 32KiB +#define KLIB_HIGHEST (MM_MODULE_MAX-KLIB_GRANUALITY) + +// === TYPES === +typedef struct sKernelBin { + struct sKernelBin *Next; + void *Base; + tBinary *Info; +} tKernelBin; + +// === IMPORTS === +extern int Proc_Clone(Uint *Err, Uint Flags); +extern char *Threads_GetName(int ID); +extern void Threads_Exit(int, int); +extern Uint MM_ClearUser(); +extern void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize); +extern tKernelSymbol gKernelSymbols[]; +extern void gKernelSymbolsEnd; +extern tBinaryType gELF_Info; + +// === PROTOTYPES === + int Proc_Execve(char *File, char **ArgV, char **EnvP); +Uint Binary_Load(char *file, Uint *entryPoint); +tBinary *Binary_GetInfo(char *truePath); +Uint Binary_MapIn(tBinary *binary); +Uint Binary_IsMapped(tBinary *binary); +tBinary *Binary_DoLoad(char *truePath); +void Binary_Dereference(tBinary *Info); +Uint Binary_Relocate(void *Base); +Uint Binary_GetSymbolEx(char *Name, Uint *Value); +Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val); + +// === GLOBALS === + int glBinListLock = 0; +tBinary *glLoadedBinaries = NULL; +char **gsaRegInterps = NULL; + int giRegInterps = 0; + int glKBinListLock = 0; +tKernelBin *glLoadedKernelLibs; +tBinaryType *gRegBinTypes = &gELF_Info; + +// === FUNCTIONS === +/** + * \brief Registers a binary type + */ +int Binary_RegisterType(tBinaryType *Type) +{ + Type->Next = gRegBinTypes; + gRegBinTypes = Type; + return 1; +} + +/** + * \fn int Proc_Spawn(char *Path) + */ +int Proc_Spawn(char *Path) +{ + char stackPath[strlen(Path)+1]; + + strcpy(stackPath, Path); + + LOG("stackPath = '%s'\n", stackPath); + + if(Proc_Clone(NULL, CLONE_VM) == 0) + { + // CHILD + char *args[2] = {stackPath, NULL}; + LOG("stackPath = '%s'\n", stackPath); + Proc_Execve(stackPath, args, &args[1]); + for(;;); + } + return 0; +} + +/** + * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP) + * \brief Replace the current user image with another + * \param File File to load as the next image + * \param ArgV Arguments to pass to user + * \param EnvP User's environment + * \note Called Proc_ for historical reasons + */ +int Proc_Execve(char *File, char **ArgV, char **EnvP) +{ + int argc, envc, i; + int argenvBytes; + char *argenvBuf, *strBuf; + char **argvSaved, **envpSaved; + char *savedFile; + Uint entry; + Uint bases[2] = {0}; + + ENTER("sFile pArgV pEnvP", File, ArgV, EnvP); + + // --- Save File, ArgV and EnvP (also get argc) + + // Count Arguments, Environment Variables and total string sizes + argenvBytes = 0; + for( argc = 0; ArgV && ArgV[argc]; argc++ ) + argenvBytes += strlen(ArgV[argc])+1; + for( envc = 0; EnvP && EnvP[envc]; envc++ ) + argenvBytes += strlen(EnvP[envc])+1; + argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1); + argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*); + + // Allocate + argenvBuf = malloc(argenvBytes); + if(argenvBuf == NULL) { + Warning("Proc_Execve - What the hell? The kernel is out of heap space"); + return 0; + } + strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*); + + // Populate + argvSaved = (char **) argenvBuf; + for( i = 0; i < argc; i++ ) + { + argvSaved[i] = strBuf; + strcpy(argvSaved[i], ArgV[i]); + strBuf += strlen(ArgV[i])+1; + } + argvSaved[i] = NULL; + envpSaved = &argvSaved[i+1]; + for( i = 0; i < envc; i++ ) + { + envpSaved[i] = strBuf; + strcpy(envpSaved[i], EnvP[i]); + strBuf += strlen(EnvP[i])+1; + } + + savedFile = malloc(strlen(File)+1); + strcpy(savedFile, File); + + // --- Set Process Name + Threads_SetName(File); + + // --- Clear User Address space + MM_ClearUser(); + + // --- Load new binary + bases[0] = Binary_Load(savedFile, &entry); + free(savedFile); + if(bases[0] == 0) + { + Warning("Proc_Execve - Unable to load '%s'", Threads_GetName(-1)); + Threads_Exit(0, 0); + for(;;); + } + + LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]); + LEAVE('-'); + // --- And... Jump to it + Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes); + for(;;); // Tell GCC that we never return +} + +/** + * \fn Uint Binary_Load(char *file, Uint *entryPoint) + */ +Uint Binary_Load(char *file, Uint *entryPoint) +{ + char *sTruePath; + tBinary *pBinary; + Uint base = -1; + + ENTER("sfile", file); + + // Sanity Check Argument + if(file == NULL) { + LEAVE('x', 0); + return 0; + } + + // Get True File Path + sTruePath = VFS_GetTruePath(file); + + if(sTruePath == NULL) { + Warning("[BIN ] '%s' does not exist.", file); + LEAVE('x', 0); + return 0; + } + + LOG("sTruePath = '%s'", sTruePath); + + // Check if the binary has already been loaded + if( !(pBinary = Binary_GetInfo(sTruePath)) ) + pBinary = Binary_DoLoad(sTruePath); // Else load it + + // Clean Up + free(sTruePath); + + // Error Check + if(pBinary == NULL) { + LEAVE('x', 0); + return 0; + } + + #if 0 + if( (base = Binary_IsMapped(pBinary)) ) { + LEAVE('x', base); + return base; + } + #endif + + // Map into process space + base = Binary_MapIn(pBinary); // If so then map it in + + // Check for errors + if(base == 0) { + LEAVE('x', 0); + return 0; + } + + // Interpret + if(pBinary->Interpreter) { + Uint start; + if( Binary_Load(pBinary->Interpreter, &start) == 0 ) { + LEAVE('x', 0); + return 0; + } + *entryPoint = start; + } + else + *entryPoint = pBinary->Entry - pBinary->Base + base; + + // Return + LOG("*entryPoint = 0x%x", *entryPoint); + LEAVE('x', base); + return base; // Pass the base as an argument to the user if there is an interpreter +} + +/** + * \brief Finds a matching binary entry + * \param TruePath File Identifier (True path name) + */ +tBinary *Binary_GetInfo(char *TruePath) +{ + tBinary *pBinary; + pBinary = glLoadedBinaries; + while(pBinary) + { + if(strcmp(pBinary->TruePath, TruePath) == 0) + return pBinary; + pBinary = pBinary->Next; + } + return NULL; +} + +/** + \fn Uint Binary_MapIn(tBinary *binary) + \brief Maps an already-loaded binary into an address space. + \param binary Pointer to globally stored data. +*/ +Uint Binary_MapIn(tBinary *binary) +{ + Uint base; + Uint addr; + int i; + + // Reference Executable (Makes sure that it isn't unloaded) + binary->ReferenceCount ++; + + // Get Binary Base + base = binary->Base; + + // Check if base is free + if(base != 0) + { + for(i=0;iNumPages;i++) + { + if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) { + base = 0; + LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF); + break; + } + } + } + + // Check if the executable has no base or it is not free + if(base == 0) + { + // If so, give it a base + base = BIN_HIGHEST; + while(base >= BIN_LOWEST) + { + for(i=0;iNumPages;i++) + { + addr = binary->Pages[i].Virtual & ~0xFFF; + addr -= binary->Base; + addr += base; + if( MM_GetPhysAddr( addr ) ) break; + } + // If space was found, break + if(i == binary->NumPages) break; + // Else decrement pointer and try again + base -= BIN_GRANUALITY; + } + } + + // Error Check + if(base < BIN_LOWEST) { + Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath); + return 0; + } + + // Map Executable In + for(i=0;iNumPages;i++) + { + addr = binary->Pages[i].Virtual & ~0xFFF; + addr -= binary->Base; + addr += base; + LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical); + MM_Map( addr, (Uint) (binary->Pages[i].Physical) ); + + // Read-Only? + if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO) + MM_SetFlags( addr, MM_PFLAG_RO, -1 ); + else + MM_SetFlags( addr, MM_PFLAG_COW, -1 ); + + // Execute? + if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC ) + MM_SetFlags( addr, MM_PFLAG_EXEC, -1 ); + else + MM_SetFlags( addr, MM_PFLAG_EXEC, 0 ); + + } + + //Log("Mapped '%s' to 0x%x", binary->TruePath, base); + + //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual); + + return base; +} + +#if 0 +/** + * \fn Uint Binary_IsMapped(tBinary *binary) + * \brief Check if a binary is already mapped into the address space + * \param binary Binary information to check + * \return Current Base or 0 + */ +Uint Binary_IsMapped(tBinary *binary) +{ + Uint iBase; + + // Check prefered base + iBase = binary->Base; + if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF)) + return iBase; + + for(iBase = BIN_HIGHEST; + iBase >= BIN_LOWEST; + iBase -= BIN_GRANUALITY) + { + if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF)) + return iBase; + } + + return 0; +} +#endif + +/** + * \fn tBinary *Binary_DoLoad(char *truePath) + * \brief Loads a binary file into memory + * \param truePath Absolute filename of binary + */ +tBinary *Binary_DoLoad(char *truePath) +{ + tBinary *pBinary; + int fp, i; + Uint ident; + tBinaryType *bt = gRegBinTypes; + + ENTER("struePath", truePath); + + // Open File + fp = VFS_Open(truePath, VFS_OPENFLAG_READ); + if(fp == -1) { + LOG("Unable to load file, access denied"); + LEAVE('n'); + return NULL; + } + + // Read File Type + VFS_Read(fp, 4, &ident); + VFS_Seek(fp, 0, SEEK_SET); + + for(; bt; bt = bt->Next) + { + if( (ident & bt->Mask) != (Uint)bt->Ident ) + continue; + pBinary = bt->Load(fp); + break; + } + if(!bt) { + Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)", + truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF); + LEAVE('n'); + return NULL; + } + + // Error Check + if(pBinary == NULL) { + LEAVE('n'); + return NULL; + } + + // Initialise Structure + pBinary->ReferenceCount = 0; + pBinary->TruePath = malloc( strlen(truePath) + 1 ); + strcpy(pBinary->TruePath, truePath); + + // Debug Information + LOG("Interpreter: '%s'", pBinary->Interpreter); + LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry); + LOG("NumPages: %i", pBinary->NumPages); + + // Read Data + for(i=0;iNumPages;i++) + { + Uint dest; + tPAddr paddr; + paddr = (Uint)MM_AllocPhys(); + if(paddr == 0) { + Warning("Binary_DoLoad - Physical memory allocation failed"); + for( ; i--; ) { + MM_DerefPhys( pBinary->Pages[i].Physical ); + } + return NULL; + } + MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be + dest = MM_MapTemp( paddr ); + dest += pBinary->Pages[i].Virtual & 0xFFF; + LOG("dest = 0x%x, paddr = 0x%x", dest, paddr); + LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}", + i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size); + + // Pure Empty Page + if(pBinary->Pages[i].Physical == -1) { + LOG("%i - ZERO", i); + memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) ); + } + else + { + VFS_Seek( fp, pBinary->Pages[i].Physical, 1 ); + if(pBinary->Pages[i].Size != 0x1000) { + LOG("%i - 0x%llx - 0x%x bytes", + i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size); + memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) ); + VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest ); + } else { + LOG("%i - 0x%x", i, pBinary->Pages[i].Physical); + VFS_Read( fp, 0x1000, (void*)dest ); + } + } + pBinary->Pages[i].Physical = paddr; + MM_FreeTemp( dest ); + } + LOG("Page Count: %i", pBinary->NumPages); + + // Close File + VFS_Close(fp); + + // Add to the list + LOCK(&glBinListLock); + pBinary->Next = glLoadedBinaries; + glLoadedBinaries = pBinary; + RELEASE(&glBinListLock); + + // Return + LEAVE('p', pBinary); + return pBinary; +} + +/** + * \fn void Binary_Unload(void *Base) + * \brief Unload / Unmap a binary + * \param Base Loaded Base + * \note Currently used only for kernel libaries + */ +void Binary_Unload(void *Base) +{ + tKernelBin *pKBin; + tKernelBin *prev = NULL; + int i; + + if((Uint)Base < 0xC0000000) + { + // TODO: User Binaries + Warning("[BIN ] Unloading user binaries is currently unimplemented"); + return; + } + + // Kernel Libraries + for(pKBin = glLoadedKernelLibs; + pKBin; + prev = pKBin, pKBin = pKBin->Next) + { + // Check the base + if(pKBin->Base != Base) continue; + // Deallocate Memory + for(i = 0; i < pKBin->Info->NumPages; i++) { + MM_Deallocate( (Uint)Base + (i << 12) ); + } + // Dereference Binary + Binary_Dereference( pKBin->Info ); + // Remove from list + if(prev) prev->Next = pKBin->Next; + else glLoadedKernelLibs = pKBin->Next; + // Free Kernel Lib + free(pKBin); + return; + } +} + +/** + * \fn void Binary_Dereference(tBinary *Info) + * \brief Dereferences and if nessasary, deletes a binary + * \param Info Binary information structure + */ +void Binary_Dereference(tBinary *Info) +{ + // Decrement reference count + Info->ReferenceCount --; + + // Check if it is still in use + if(Info->ReferenceCount) return; + + /// \todo Implement binary freeing +} + +/** + * \fn char *Binary_RegInterp(char *Path) + * \brief Registers an Interpreter + * \param Path Path to interpreter provided by executable + */ +char *Binary_RegInterp(char *Path) +{ + int i; + // NULL Check Argument + if(Path == NULL) return NULL; + // NULL Check the array + if(gsaRegInterps == NULL) + { + giRegInterps = 1; + gsaRegInterps = malloc( sizeof(char*) ); + gsaRegInterps[0] = malloc( strlen(Path) ); + strcpy(gsaRegInterps[0], Path); + return gsaRegInterps[0]; + } + + // Scan Array + for( i = 0; i < giRegInterps; i++ ) + { + if(strcmp(gsaRegInterps[i], Path) == 0) + return gsaRegInterps[i]; + } + + // Interpreter is not in list + giRegInterps ++; + gsaRegInterps = malloc( sizeof(char*)*giRegInterps ); + gsaRegInterps[i] = malloc( strlen(Path) ); + strcpy(gsaRegInterps[i], Path); + return gsaRegInterps[i]; +} + +// ============ +// Kernel Binary Handling +// ============ +/** + * \fn void *Binary_LoadKernel(char *File) + * \brief Load a binary into kernel space + * \note This function shares much with #Binary_Load, but does it's own mapping + * \param File File to load into the kernel + */ +void *Binary_LoadKernel(char *File) +{ + char *sTruePath; + tBinary *pBinary; + tKernelBin *pKBinary; + Uint base = -1; + Uint addr; + int i; + + ENTER("sfile", File); + + // Sanity Check Argument + if(File == NULL) { + LEAVE('n'); + return 0; + } + + // Get True File Path + sTruePath = VFS_GetTruePath(File); + if(sTruePath == NULL) { + LEAVE('n'); + return 0; + } + + // Check if the binary has already been loaded + if( (pBinary = Binary_GetInfo(sTruePath)) ) + { + for(pKBinary = glLoadedKernelLibs; + pKBinary; + pKBinary = pKBinary->Next ) + { + if(pKBinary->Info == pBinary) { + LEAVE('p', pKBinary->Base); + return pKBinary->Base; + } + } + } + else + pBinary = Binary_DoLoad(sTruePath); // Else load it + + // Error Check + if(pBinary == NULL) { + LEAVE('n'); + return NULL; + } + + // -------------- + // Now pBinary is valid (either freshly loaded or only user mapped) + // So, map it into kernel space + // -------------- + + // Reference Executable (Makes sure that it isn't unloaded) + pBinary->ReferenceCount ++; + + // Check compiled base + base = pBinary->Base; + // - Sanity Check + if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) { + base = 0; + } + // - Check if it is a valid base address + if(base != 0) + { + for(i=0;iNumPages;i++) + { + if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) { + base = 0; + LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF); + break; + } + } + } + + // Check if the executable has no base or it is not free + if(base == 0) + { + // If so, give it a base + base = KLIB_LOWEST; + while(base < KLIB_HIGHEST) + { + for(i = 0; i < pBinary->NumPages; i++) + { + addr = pBinary->Pages[i].Virtual & ~0xFFF; + addr -= pBinary->Base; + addr += base; + if( MM_GetPhysAddr( addr ) ) break; + } + // If space was found, break + if(i == pBinary->NumPages) break; + // Else decrement pointer and try again + base += KLIB_GRANUALITY; + } + } + + // - Error Check + if(base >= KLIB_HIGHEST) { + Warning("[BIN ] Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath); + Binary_Dereference( pBinary ); + LEAVE('n'); + return 0; + } + + LOG("base = 0x%x", base); + + // - Map binary in + LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages); + for(i = 0; i < pBinary->NumPages; i++) + { + addr = pBinary->Pages[i].Virtual & ~0xFFF; + addr -= pBinary->Base; + addr += base; + LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical); + MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) ); + MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL ); + + if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only? + MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL ); + } + + // Relocate Library + if( !Binary_Relocate( (void*)base ) ) + { + Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath); + Binary_Unload( (void*)base ); + Binary_Dereference( pBinary ); + LEAVE('n'); + return 0; + } + + // Add to list (relocator must look at itself manually, not via Binary_GetSymbol) + pKBinary = malloc(sizeof(*pKBinary)); + pKBinary->Base = (void*)base; + pKBinary->Info = pBinary; + LOCK( &glKBinListLock ); + pKBinary->Next = glLoadedKernelLibs; + glLoadedKernelLibs = pKBinary; + RELEASE( &glKBinListLock ); + + LEAVE('p', base); + return (void*)base; +} + +/** + * \fn Uint Binary_Relocate(void *Base) + * \brief Relocates a loaded binary (used by kernel libraries) + * \param Base Loaded base address of binary + * \return Boolean Success + */ +Uint Binary_Relocate(void *Base) +{ + Uint32 ident = *(Uint32*) Base; + tBinaryType *bt = gRegBinTypes; + + for(; bt; bt = bt->Next) + { + if( (ident & bt->Mask) == (Uint)bt->Ident ) + return bt->Relocate( (void*)Base); + } + + Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)", + Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF); + return 0; +} + +/** + * \fn int Binary_GetSymbol(char *Name, Uint *Val) + * \brief Get a symbol value + * \return Value of symbol or -1 on error + * + * Gets the value of a symbol from either the currently loaded + * libraries or the kernel's exports. + */ +int Binary_GetSymbol(char *Name, Uint *Val) +{ + if( Binary_GetSymbolEx(Name, Val) ) return 1; + return 0; +} + +/** + * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value) + * \brief Get a symbol value + * + * Gets the value of a symbol from either the currently loaded + * libraries or the kernel's exports. + */ +Uint Binary_GetSymbolEx(char *Name, Uint *Value) +{ + int i; + tKernelBin *pKBin; + int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol); + + // Scan Kernel + for( i = 0; i < numKSyms; i++ ) + { + if(strcmp(Name, gKernelSymbols[i].Name) == 0) { + *Value = gKernelSymbols[i].Value; + return 1; + } + } + + // Scan Loaded Libraries + for(pKBin = glLoadedKernelLibs; + pKBin; + pKBin = pKBin->Next ) + { + if( Binary_FindSymbol(pKBin->Base, Name, Value) ) { + return 1; + } + } + + Warning("[BIN ] Unable to find symbol '%s'", Name); + return 0; +} + +/** + * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val) + * \brief Get a symbol from the specified library + * \param Base Base address + * \param Name Name of symbol to find + * \param Val Pointer to place final value + */ +Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val) +{ + Uint32 ident = *(Uint32*) Base; + tBinaryType *bt = gRegBinTypes; + + for(; bt; bt = bt->Next) + { + if( (ident & bt->Mask) == (Uint)bt->Ident ) + return bt->GetSymbol(Base, Name, Val); + } + + Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)", + Base, ident&0xFF, ident>>8, ident>>16, ident>>24); + return 0; +} + +// === EXPORTS === +EXPORT(Binary_FindSymbol); +EXPORT(Binary_Unload); diff --git a/Kernel/include/acess.h b/Kernel/include/acess.h index 8e62578a..2bb60ca6 100644 --- a/Kernel/include/acess.h +++ b/Kernel/include/acess.h @@ -8,7 +8,7 @@ #define NULL ((void*)0) #define PACKED __attribute__ ((packed)) -#include +//#include #include #include #include "errno.h" diff --git a/Kernel/include/threads.h b/Kernel/include/threads.h index 2b066d9f..f23c5b56 100644 --- a/Kernel/include/threads.h +++ b/Kernel/include/threads.h @@ -5,6 +5,7 @@ #include #include +#include typedef struct sMessage { @@ -77,6 +78,8 @@ enum eFaultNumbers FAULT_FLOAT }; +#define GETMSG_IGNORE ((void*)-1) + // === FUNCTIONS === extern tThread *Proc_GetCurThread(); extern tThread *Threads_GetThread(Uint TID); diff --git a/Kernel/messages.c b/Kernel/messages.c index aaedf5c0..32e579b3 100644 --- a/Kernel/messages.c +++ b/Kernel/messages.c @@ -3,7 +3,7 @@ * messages.c */ #include -#include +#include #include // === CODE === diff --git a/Kernel/vfs/open.c b/Kernel/vfs/open.c index d5e940ec..04facc7d 100644 --- a/Kernel/vfs/open.c +++ b/Kernel/vfs/open.c @@ -4,6 +4,7 @@ */ #define DEBUG 0 #include +#include #include "vfs.h" #include "vfs_int.h" #include "vfs_ext.h" diff --git a/Makefile b/Makefile index ba53f122..905f5ca1 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,11 @@ SUBMAKE = $(MAKE) --no-print-directory -MODULES += $(DYNMODS) +#MODULES += $(DYNMODS) USRLIBS := crt0.o acess.ld ld-acess.so libacess.so libgcc.so libc.so USRAPPS := init login CLIShell cat ls mount ifconfig -#ALL_DYNMODS = $(addprefix all-,$(DYNMODS)) +ALL_DYNMODS = $(addprefix all-,$(DYNMODS)) ALL_MODULES := $(addprefix all-,$(MODULES)) ALL_USRLIBS := $(addprefix all-,$(USRLIBS)) ALL_USRAPPS := $(addprefix all-,$(USRAPPS)) @@ -43,6 +43,8 @@ clean: $(CLEAN_DYNMODS) $(CLEAN_MODULES) clean-Kernel $(CLEAN_USRLIBS) $(CLEAN_U install: $(INSTALL_DYNMODS) $(INSTALL_MODULES) install-Kernel $(INSTALL_USRLIBS) $(INSTALL_USRAPPS) # Compile Only +$(ALL_DYNMODS): all-%: + @echo === Dynamic Module: $* && BUILDTYPE=dynamic $(SUBMAKE) all -C Modules/$* $(ALL_MODULES): all-%: @echo === Module: $* && $(SUBMAKE) all -C Modules/$* all-Kernel: @@ -53,8 +55,8 @@ $(ALL_USRAPPS): all-%: @echo === User Application: $* && $(SUBMAKE) all -C Usermode/Applications/$*_src # Compile & Install -#$(AI_DYNMODS): allinstall-%: -# @echo === Dynamic Module: $* && STATIC_MODULE=yes $(SUBMAKE) all install -C Modules/$* +$(AI_DYNMODS): allinstall-%: + @echo === Dynamic Module: $* && BUILDTYPE=dynamic $(SUBMAKE) all install -C Modules/$* $(AI_MODULES): allinstall-%: @echo === Module: $* && $(SUBMAKE) all install -C Modules/$* allinstall-Kernel: diff --git a/Makefile.cfg b/Makefile.cfg index ad972f70..cb134bed 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -2,40 +2,42 @@ # Acess2 Build Configuration # -CC = i586-elf-gcc -LD = i586-elf-ld -AS = nasm -OBJDUMP = i586-elf-objdump -RM = @rm -f -STRIP = strip -MKDIR = mkdir -RMDIR = rm -rf -lCP = cp -xCP = mcopy -D o -xMKDIR = mmd -xRMDIR = mdeltree -xRM = mdel +# Source and destination configuration +DISTROOT := a:/Acess2 +ACESSDIR := /home/tpg/Projects/Acess2 +# Default build programs +CC := gcc +LD := ld +AS := nasm +OBJDUMP := objdump +RM := @rm -f +STRIP := strip +MKDIR := mkdir +RMDIR := rm -rf +lCP := cp +xCP := mcopy -D o +xMKDIR := mmd +xRMDIR := mdeltree +xRM := mdel + +# Load Architecture settings ifeq ($(ARCH),) - ARCH = i386 + ARCH := i386 endif --include Makefile.$(ARCH).cfg +-include $(ACESSDIR)/Makefile.$(ARCH).cfg ifeq ($(ARCHDIR),) - ARCHDIR = x86 + ARCHDIR := x86 endif +-include $(ACESSDIR)/Makefile.$(ARCHDIR).cfg -FILESYSTEMS = -DRIVERS = -MODULES = Storage/ATA Storage/FDD +FILESYSTEMS := +DRIVERS := +MODULES := Storage/ATA Storage/FDD MODULES += Network/NE2000 MODULES += Display/VESA MODULES += Display/BochsGA MODULES += Filesystems/Ext2 MODULES += Filesystems/FAT MODULES += IPStack -DYNMODS = USB/Core Interfaces/UDI - -#DISTROOT = /mnt/AcessHDD/Acess2 -#DISTROOT = ~/Projects/Acess2/Filesystem -DISTROOT = a:/Acess2 -ACESSDIR = /home/tpg/Projects/Acess2 +DYNMODS := USB/Core Interfaces/UDI diff --git a/Makefile.i386.cfg b/Makefile.i386.cfg new file mode 100644 index 00000000..8f8b9ca5 --- /dev/null +++ b/Makefile.i386.cfg @@ -0,0 +1,14 @@ +# +# Acess2 Build Configuration +# + +CC = i586-elf-gcc +LD = i586-elf-ld +AS = nasm +OBJDUMP = i586-elf-objdump +RM = @rm -f +STRIP = strip +MKDIR = mkdir + +ARCHDIR = x86 + diff --git a/Makefile.x86_64.cfg b/Makefile.x86_64.cfg new file mode 100644 index 00000000..ac012f62 --- /dev/null +++ b/Makefile.x86_64.cfg @@ -0,0 +1,8 @@ + +CC = x86_64-linux-gnu-gcc +LD = ld + +KERNEL_CFLAGS = -mcmodel=large + +ARCHDIR = x86_64 + diff --git a/Modules/IPStack/Makefile b/Modules/IPStack/Makefile index a79f09aa..08cbe609 100644 --- a/Modules/IPStack/Makefile +++ b/Modules/IPStack/Makefile @@ -1,7 +1,7 @@ # # -OBJ = main.o link.o arp.o +OBJ := main.o link.o arp.o OBJ += ipv4.o icmp.o OBJ += ipv6.o OBJ += udp.o tcp.o diff --git a/Modules/Makefile.tpl b/Modules/Makefile.tpl index 9a1b6e82..a1775ddf 100644 --- a/Modules/Makefile.tpl +++ b/Modules/Makefile.tpl @@ -4,26 +4,33 @@ _CPPFLAGS := $(CPPFLAGS) -CFGFILES = +CFGFILES := CFGFILES += $(shell test -f ../../../Makefile.cfg && echo ../../../Makefile.cfg) CFGFILES += $(shell test -f ../../Makefile.cfg && echo ../../Makefile.cfg) CFGFILES += $(shell test -f ../Makefile.cfg && echo ../Makefile.cfg) CFGFILES += $(shell test -f Makefile.cfg && echo Makefile.cfg) -include $(CFGFILES) -CPPFLAGS = -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) $(_CPPFLAGS) -CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS) -O3 - -OBJ := $(addsuffix .$(ARCH),$(OBJ)) -ifneq ($(CATEGORY),) - BIN := ../$(CATEGORY)_$(NAME).kmd.$(ARCH) +CPPFLAGS := -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) $(_CPPFLAGS) +CFLAGS := $(KERNEL_CFLAGS) -Wall -Werror -fno-stack-protector $(CPPFLAGS) -O3 -fno-builtin + +ifeq ($(BUILDTYPE),dynamic) + _SUFFIX := dyn_$(ARCH) + ifneq ($(CATEGORY),) + BIN := ../$(CATEGORY)_$(NAME).kmd.$(ARCH) + else + BIN := ../$(NAME).kmd.$(ARCH) + endif + CFLAGS += -fPIC else - BIN := ../$(NAME).kmd.$(ARCH) + _SUFFIX := st_$(ARCH) + BIN := ../$(NAME).xo.$(ARCH) endif -KOBJ = ../$(NAME).xo.$(ARCH) -DEPFILES = $(filter %.o.$(ARCH),$(OBJ)) -DEPFILES := $(DEPFILES:%.o.$(ARCH)=%.d.$(ARCH)) +OBJ := $(addsuffix .$(_SUFFIX),$(OBJ)) + +DEPFILES := $(filter %.o.$(_SUFFIX),$(OBJ)) +DEPFILES := $(DEPFILES:%.o.$(_SUFFIX)=%.d.$(ARCH)) .PHONY: all clean @@ -35,14 +42,19 @@ clean: install: $(BIN) $(xCP) $(BIN) $(DISTROOT)/Modules/$(NAME).kmd -$(BIN): $(OBJ) +ifeq ($(BUILDTYPE),dynamic) +$(BIN): %.kmd.$(ARCH): $(OBJ) @echo --- $(LD) -o $@ - @$(LD) -T $(ACESSDIR)/Modules/link.ld -shared -nostdlib -o $@ $(OBJ) +# $(LD) -T $(ACESSDIR)/Modules/link.ld --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ) + $(LD) --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ) @$(OBJDUMP) -d $(BIN) > $(BIN).dsm - @echo --- $(LD) -o $(KOBJ) - @$(CC) -Wl,-r -nostdlib -o $(KOBJ) $(OBJ) +else +$(BIN): %.xo.$(ARCH): $(OBJ) + @echo --- $(LD) -o $@ + @$(LD) -r -o $@ $(OBJ) +endif -%.o.$(ARCH): %.c Makefile ../Makefile.tpl $(CFGFILES) +%.o.$(_SUFFIX): %.c Makefile ../Makefile.tpl $(CFGFILES) @echo --- $(CC) -o $@ @$(CC) $(CFLAGS) -o $@ -c $< @$(CC) -M $(CPPFLAGS) -MT $@ -o $*.d.$(ARCH) $< diff --git a/Modules/Storage/ATA/main.c b/Modules/Storage/ATA/main.c index dac5a2a7..376563b3 100644 --- a/Modules/Storage/ATA/main.c +++ b/Modules/Storage/ATA/main.c @@ -150,7 +150,7 @@ int ATA_SetupIO() if( !(gATA_BusMasterBase & 1) ) { if( gATA_BusMasterBase < 0x100000 ) - gATA_BusMasterBasePtr = (void*)(KERNEL_BASE|gATA_BusMasterBase); + gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase); else gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) ); LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr); @@ -164,15 +164,15 @@ int ATA_SetupIO() IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri ); IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec ); - gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] ); - gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] ); + gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] ); + gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] ); LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr); - addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] ); + addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] ); LOG("addr = 0x%x", addr); ATA_int_BusMasterWriteDWord(4, addr); - addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] ); + addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] ); LOG("addr = 0x%x", addr); ATA_int_BusMasterWriteDWord(12, addr); @@ -238,9 +238,11 @@ void ATA_SetupVFS() */ int ATA_ScanDisk(int Disk) { - Uint16 buf[256]; - tIdentify *identify = (void*)buf; - tMBR *mbr = (void*)buf; + union { + Uint16 buf[256]; + tIdentify identify; + tMBR mbr; + } data; Uint16 base; Uint8 val; int i; @@ -275,13 +277,13 @@ int ATA_ScanDisk(int Disk) } // Read Data - for(i=0;i<256;i++) buf[i] = inw(base); + for(i=0;i<256;i++) data.buf[i] = inw(base); // Populate Disk Structure - if(identify->Sectors48 != 0) - gATA_Disks[ Disk ].Sectors = identify->Sectors48; + if(data.identify.Sectors48 != 0) + gATA_Disks[ Disk ].Sectors = data.identify.Sectors48; else - gATA_Disks[ Disk ].Sectors = identify->Sectors28; + gATA_Disks[ Disk ].Sectors = data.identify.Sectors28; LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors); @@ -318,10 +320,10 @@ int ATA_ScanDisk(int Disk) // --- Scan Partitions --- LOG("Reading MBR"); // Read Boot Sector - ATA_ReadDMA( Disk, 0, 1, mbr ); + ATA_ReadDMA( Disk, 0, 1, &data.mbr ); // Check for a GPT table - if(mbr->Parts[0].SystemID == 0xEE) + if(data.mbr.Parts[0].SystemID == 0xEE) ATA_ParseGPT(Disk); else // No? Just parse the MBR ATA_ParseMBR(Disk); diff --git a/Modules/Storage/FDD/fdd.c b/Modules/Storage/FDD/fdd.c index f72e548c..6ad2b1a1 100644 --- a/Modules/Storage/FDD/fdd.c +++ b/Modules/Storage/FDD/fdd.c @@ -1,808 +1,808 @@ -/* - * AcessOS 0.1 - * Floppy Disk Access Code - */ -#define DEBUG 0 -#include -#include -#include -#include -#include -#include - -#define WARN 0 - -// === CONSTANTS === -// --- Current Version -#define FDD_VERSION ((0<<8)|(75)) - -// --- Options -#define FDD_SEEK_TIMEOUT 10 // Timeout for a seek operation -#define MOTOR_ON_DELAY 500 // Miliseconds -#define MOTOR_OFF_DELAY 2000 // Miliseconds -#define FDD_MAX_READWRITE_ATTEMPTS 16 - -// === TYPEDEFS === -/** - * \brief Representation of a floppy drive - */ -typedef struct sFloppyDrive -{ - int type; - volatile int motorState; //2 - On, 1 - Spinup, 0 - Off - int track[2]; - int timer; - tVFS_Node Node; - #if !USE_CACHE - tIOCache *CacheHandle; - #endif -} t_floppyDevice; - -/** - * \brief Cached Sector - */ -typedef struct { - Uint64 timestamp; - Uint16 disk; - Uint16 sector; // Allows 32Mb of addressable space (Plenty for FDD) - Uint8 data[512]; -} t_floppySector; - -// === CONSTANTS === -static const char *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" }; -static const int cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 }; -static const short cPORTBASE[] = { 0x3F0, 0x370 }; -#if DEBUG -static const char *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"}; -#endif - -enum FloppyPorts { - PORT_STATUSA = 0x0, - PORT_STATUSB = 0x1, - PORT_DIGOUTPUT = 0x2, - PORT_MAINSTATUS = 0x4, - PORT_DATARATE = 0x4, - PORT_DATA = 0x5, - PORT_DIGINPUT = 0x7, - PORT_CONFIGCTRL = 0x7 -}; - -enum FloppyCommands { - FIX_DRIVE_DATA = 0x03, - HECK_DRIVE_STATUS = 0x04, - CALIBRATE_DRIVE = 0x07, - CHECK_INTERRUPT_STATUS = 0x08, - SEEK_TRACK = 0x0F, - READ_SECTOR_ID = 0x4A, - FORMAT_TRACK = 0x4D, - READ_TRACK = 0x42, - READ_SECTOR = 0x66, - WRITE_SECTOR = 0xC5, - WRITE_DELETE_SECTOR = 0xC9, - READ_DELETE_SECTOR = 0xCC, -}; - -// === PROTOTYPES === -// --- Filesystem - int FDD_Install(char **Arguments); -void FDD_UnloadModule(); -// --- VFS Methods -char *FDD_ReadDir(tVFS_Node *Node, int pos); -tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, char *Name); - int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data); -Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); -// --- Functions for IOCache/DrvUtil -Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk); -// --- Raw Disk Access - int FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer); - int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer); -// --- Helpers -void FDD_IRQHandler(int Num); -inline void FDD_WaitIRQ(); -void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl); -void FDD_int_SendByte(int base, char byte); - int FDD_int_GetByte(int base); -void FDD_Reset(int id); -void FDD_Recalibrate(int disk); - int FDD_int_SeekTrack(int disk, int head, int track); -void FDD_int_TimerCallback(int arg); -void FDD_int_StopMotor(int disk); -void FDD_int_StartMotor(int disk); - int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt); - -// === GLOBALS === -MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL); -t_floppyDevice gFDD_Devices[2]; -tSpinlock glFDD; -volatile int gbFDD_IrqFired = 0; -tDevFS_Driver gFDD_DriverInfo = { - NULL, "fdd", - { - .Size = -1, - .NumACLs = 1, - .ACLs = &gVFS_ACL_EveryoneRX, - .Flags = VFS_FFLAG_DIRECTORY, - .ReadDir = FDD_ReadDir, - .FindDir = FDD_FindDir, - .IOCtl = FDD_IOCtl - } -}; - -// === CODE === -/** - * \fn int FDD_Install(char **Arguments) - * \brief Installs floppy driver - */ -int FDD_Install(char **Arguments) -{ - Uint8 data; - - // Determine Floppy Types (From CMOS) - outb(0x70, 0x10); - data = inb(0x71); - gFDD_Devices[0].type = data >> 4; - gFDD_Devices[1].type = data & 0xF; - gFDD_Devices[0].track[0] = -1; - gFDD_Devices[1].track[1] = -1; - - Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]); - - if( data == 0 ) { - return MODULE_ERR_NOTNEEDED; - } - - // Clear FDD IRQ Flag - FDD_SensInt(0x3F0, NULL, NULL); - // Install IRQ6 Handler - IRQ_AddHandler(6, FDD_IRQHandler); - // Reset Primary FDD Controller - FDD_Reset(0); - - // Initialise Root Node - gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime - = gFDD_DriverInfo.RootNode.ATime = now(); - - // Initialise Child Nodes - gFDD_Devices[0].Node.Inode = 0; - gFDD_Devices[0].Node.Flags = 0; - gFDD_Devices[0].Node.NumACLs = 0; - gFDD_Devices[0].Node.Read = FDD_ReadFS; - gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS; - memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node)); - - gFDD_Devices[1].Node.Inode = 1; - - // Set Lengths - gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4]; - gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF]; - - // Create Sector Cache - if( cFDD_SIZES[data >> 4] ) - { - gFDD_Devices[0].CacheHandle = IOCache_Create( - FDD_WriteSector, 0, 512, - gFDD_Devices[0].Node.Size / (512*4) - ); // Cache is 1/4 the size of the disk - } - if( cFDD_SIZES[data & 15] ) - { - gFDD_Devices[1].CacheHandle = IOCache_Create( - FDD_WriteSector, 0, 512, - gFDD_Devices[1].Node.Size / (512*4) - ); // Cache is 1/4 the size of the disk - } - - // Register with devfs - DevFS_AddDevice(&gFDD_DriverInfo); - - return MODULE_ERR_OK; -} - -/** - * \brief Prepare the module for removal - */ -void FDD_UnloadModule() -{ - int i; - //DevFS_DelDevice( &gFDD_DriverInfo ); - LOCK(&glFDD); - for(i=0;i<4;i++) { - Time_RemoveTimer(gFDD_Devices[i].timer); - FDD_int_StopMotor(i); - } - RELEASE(&glFDD); - //IRQ_Clear(6); -} - -/** - * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos) - * \brief Read Directory - */ -char *FDD_ReadDir(tVFS_Node *Node, int Pos) -{ - char name[2] = "0\0"; - - if(Pos >= 2 || Pos < 0) return NULL; - - if(gFDD_Devices[Pos].type == 0) return VFS_SKIP; - - name[0] += Pos; - - return strdup(name); -} - -/** - * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename); - * \brief Find File Routine (for vfs_node) - */ -tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *Filename) -{ - int i; - - ENTER("sFilename", Filename); - - // Sanity check string - if(Filename == NULL) { - LEAVE('n'); - return NULL; - } - - // Check string length (should be 1) - if(Filename[0] == '\0' || Filename[1] != '\0') { - LEAVE('n'); - return NULL; - } - - // Get First character - i = Filename[0] - '0'; - - // Check for 1st disk and if it is present return - if(i == 0 && gFDD_Devices[0].type != 0) { - LEAVE('p', &gFDD_Devices[0].Node); - return &gFDD_Devices[0].Node; - } - - // Check for 2nd disk and if it is present return - if(i == 1 && gFDD_Devices[1].type != 0) { - LEAVE('p', &gFDD_Devices[1].Node); - return &gFDD_Devices[1].Node; - } - - // Else return null - LEAVE('n'); - return NULL; -} - -static const char *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL}; -/** - * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data) - * \brief Stub ioctl function - */ -int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data) -{ - switch(ID) - { - case DRV_IOCTL_TYPE: return DRV_TYPE_DISK; - case DRV_IOCTL_IDENT: return ModUtil_SetIdent(Data, "FDD"); - case DRV_IOCTL_VERSION: return FDD_VERSION; - case DRV_IOCTL_LOOKUP: return ModUtil_LookupString((char**)casIOCTLS, Data); - - case DISK_IOCTL_GETBLOCKSIZE: return 512; - - default: - return 0; - } -} - -/** - * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - * \brief Read Data from a disk -*/ -Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - int ret; - - ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); - - if(Node == NULL) { - LEAVE('i', -1); - return -1; - } - - if(Node->Inode != 0 && Node->Inode != 1) { - LEAVE('i', -1); - return -1; - } - - ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode); - LEAVE('i', ret); - return ret; -} - -/** - * \brief Reads \a Count contiguous sectors from a disk - * \param SectorAddr Address of the first sector - * \param Count Number of sectors to read - * \param Buffer Destination Buffer - * \param Disk Disk Number - * \return Number of sectors read - * \note Used as a ::DrvUtil_ReadBlock helper - */ -Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk) -{ - Uint ret = 0; - while(Count --) - { - if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 ) - return ret; - - Buffer = (void*)( (tVAddr)Buffer + 512 ); - SectorAddr ++; - ret ++; - } - return ret; -} - -int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer) -{ - int cyl, head, sec; - int spt, base; - int i; - int lba = SectorAddr; - Uint8 st0, st1, st2, rcy, rhe, rse, bps; // Status Values - - ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer); - - base = cPORTBASE[Disk >> 1]; - - LOG("Calculating Disk Dimensions"); - // Get CHS position - if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1) - { - LEAVE('i', -1); - return -1; - } - LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec); - - LOCK(&glFDD); // Lock to stop the motor stopping on us - Time_RemoveTimer(gFDD_Devices[Disk].timer); // Remove Old Timer - // Start motor if needed - if(gFDD_Devices[Disk].motorState != 2) FDD_int_StartMotor(Disk); - RELEASE(&glFDD); - - LOG("Wait for the motor to spin up"); - - // Wait for spinup - while(gFDD_Devices[Disk].motorState == 1) Threads_Yield(); - - LOG("Acquire Spinlock"); - LOCK(&glFDD); - - // Seek to track - outb(base + CALIBRATE_DRIVE, 0); - i = 0; - while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT ) - Threads_Yield(); - if( i > FDD_SEEK_TIMEOUT ) { - RELEASE(&glFDD); - LEAVE('i', 0); - return 0; - } - //FDD_SensInt(base, NULL, NULL); // Wait for IRQ - - // Read Data from DMA - LOG("Setting DMA for read"); - DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2 - - LOG("Sending command"); - - //Threads_Wait(100); // Wait for Head to settle - Time_Delay(100); - - for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ ) - { - if( Write ) - FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 - else - FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 - FDD_int_SendByte(base, (head << 2) | (Disk&1)); - FDD_int_SendByte(base, (Uint8)cyl); - FDD_int_SendByte(base, (Uint8)head); - FDD_int_SendByte(base, (Uint8)sec); - FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val}) - FDD_int_SendByte(base, spt); // SPT - FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default) - FDD_int_SendByte(base, 0xFF); // Data Length - - // Wait for IRQ - if( Write ) { - LOG("Writing Data"); - DMA_WriteData(2, 512, Buffer); - LOG("Waiting for Data to be written"); - FDD_WaitIRQ(); - } - else { - LOG("Waiting for data to be read"); - FDD_WaitIRQ(); - LOG("Reading Data"); - DMA_ReadData(2, 512, Buffer); - } - - // Clear Input Buffer - LOG("Clearing Input Buffer"); - // Status Values - st0 = FDD_int_GetByte(base); - st1 = FDD_int_GetByte(base); - st2 = FDD_int_GetByte(base); - - // Cylinder, Head and Sector (mutilated in some way - rcy = FDD_int_GetByte(base); - rhe = FDD_int_GetByte(base); - rse = FDD_int_GetByte(base); - // Should be the BPS set above (0x02) - bps = FDD_int_GetByte(base); - - // Check Status - // - Error Code - if(st0 & 0xC0) { - LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]); - continue; - } - // - Status Flags - if(st0 & 0x08) { LOG("Drive not ready"); continue; } - if(st1 & 0x80) { LOG("End of Cylinder"); continue; } - if(st1 & 0x20) { LOG("CRC Error"); continue; } - if(st1 & 0x10) { LOG("Controller Timeout"); continue; } - if(st1 & 0x04) { LOG("No Data Found"); continue; } - if(st1 & 0x01 || st2 & 0x01) { - LOG("No Address mark found"); - continue; - } - if(st2 & 0x40) { LOG("Deleted address mark"); continue; } - if(st2 & 0x20) { LOG("CRC error in data"); continue; } - if(st2 & 0x10) { LOG("Wrong Cylinder"); continue; } - if(st2 & 0x04) { LOG("uPD765 sector not found"); continue; } - if(st2 & 0x02) { LOG("Bad Cylinder"); continue; } - - if(bps != 0x2) { - LOG("Returned BPS = 0x%02x, not 0x02", bps); - continue; - } - - if(st1 & 0x02) { - LOG("Floppy not writable"); - i = FDD_MAX_READWRITE_ATTEMPTS+1; - break; - } - - // Success! - break; - } - - // Release Spinlock - LOG("Realeasing Spinlock and setting motor to stop"); - RELEASE(&glFDD); - - if(i == FDD_MAX_READWRITE_ATTEMPTS) { - Log_Warning("FDD", "Exceeded %i attempts in %s the disk", - FDD_MAX_READWRITE_ATTEMPTS, - (Write ? "writing to" : "reading from") - ); - } - - // Don't turn the motor off now, wait for a while - gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk); - - if( i < FDD_MAX_READWRITE_ATTEMPTS ) { - LEAVE('i', 0); - return 0; - } - else { - LEAVE('i', 1); - return 1; - } -} - -/** - * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) - * \brief Read a sector from disk - * \todo Make real-hardware safe (account for read errors) -*/ -int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) -{ - int ret; - - ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer); - - if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) { - LEAVE('i', 1); - return 1; - } - - // Pass to general function +/* + * AcessOS 0.1 + * Floppy Disk Access Code + */ +#define DEBUG 0 +#include +#include +#include +#include +#include +#include + +#define WARN 0 + +// === CONSTANTS === +// --- Current Version +#define FDD_VERSION ((0<<8)|(75)) + +// --- Options +#define FDD_SEEK_TIMEOUT 10 // Timeout for a seek operation +#define MOTOR_ON_DELAY 500 // Miliseconds +#define MOTOR_OFF_DELAY 2000 // Miliseconds +#define FDD_MAX_READWRITE_ATTEMPTS 16 + +// === TYPEDEFS === +/** + * \brief Representation of a floppy drive + */ +typedef struct sFloppyDrive +{ + int type; + volatile int motorState; //2 - On, 1 - Spinup, 0 - Off + int track[2]; + int timer; + tVFS_Node Node; + #if !USE_CACHE + tIOCache *CacheHandle; + #endif +} t_floppyDevice; + +/** + * \brief Cached Sector + */ +typedef struct { + Uint64 timestamp; + Uint16 disk; + Uint16 sector; // Allows 32Mb of addressable space (Plenty for FDD) + Uint8 data[512]; +} t_floppySector; + +// === CONSTANTS === +static const char *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" }; +static const int cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 }; +static const short cPORTBASE[] = { 0x3F0, 0x370 }; +#if DEBUG +static const char *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"}; +#endif + +enum FloppyPorts { + PORT_STATUSA = 0x0, + PORT_STATUSB = 0x1, + PORT_DIGOUTPUT = 0x2, + PORT_MAINSTATUS = 0x4, + PORT_DATARATE = 0x4, + PORT_DATA = 0x5, + PORT_DIGINPUT = 0x7, + PORT_CONFIGCTRL = 0x7 +}; + +enum FloppyCommands { + FIX_DRIVE_DATA = 0x03, + HECK_DRIVE_STATUS = 0x04, + CALIBRATE_DRIVE = 0x07, + CHECK_INTERRUPT_STATUS = 0x08, + SEEK_TRACK = 0x0F, + READ_SECTOR_ID = 0x4A, + FORMAT_TRACK = 0x4D, + READ_TRACK = 0x42, + READ_SECTOR = 0x66, + WRITE_SECTOR = 0xC5, + WRITE_DELETE_SECTOR = 0xC9, + READ_DELETE_SECTOR = 0xCC, +}; + +// === PROTOTYPES === +// --- Filesystem + int FDD_Install(char **Arguments); +void FDD_UnloadModule(); +// --- VFS Methods +char *FDD_ReadDir(tVFS_Node *Node, int pos); +tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, char *Name); + int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data); +Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); +// --- Functions for IOCache/DrvUtil +Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk); +// --- Raw Disk Access + int FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer); + int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer); +// --- Helpers +void FDD_IRQHandler(int Num); +inline void FDD_WaitIRQ(); +void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl); +void FDD_int_SendByte(int base, char byte); + int FDD_int_GetByte(int base); +void FDD_Reset(int id); +void FDD_Recalibrate(int disk); + int FDD_int_SeekTrack(int disk, int head, int track); +void FDD_int_TimerCallback(int arg); +void FDD_int_StopMotor(int disk); +void FDD_int_StartMotor(int disk); + int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt); + +// === GLOBALS === +MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL); +t_floppyDevice gFDD_Devices[2]; +tSpinlock glFDD; +volatile int gbFDD_IrqFired = 0; +tDevFS_Driver gFDD_DriverInfo = { + NULL, "fdd", + { + .Size = -1, + .NumACLs = 1, + .ACLs = &gVFS_ACL_EveryoneRX, + .Flags = VFS_FFLAG_DIRECTORY, + .ReadDir = FDD_ReadDir, + .FindDir = FDD_FindDir, + .IOCtl = FDD_IOCtl + } +}; + +// === CODE === +/** + * \fn int FDD_Install(char **Arguments) + * \brief Installs floppy driver + */ +int FDD_Install(char **Arguments) +{ + Uint8 data; + + // Determine Floppy Types (From CMOS) + outb(0x70, 0x10); + data = inb(0x71); + gFDD_Devices[0].type = data >> 4; + gFDD_Devices[1].type = data & 0xF; + gFDD_Devices[0].track[0] = -1; + gFDD_Devices[1].track[1] = -1; + + Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]); + + if( data == 0 ) { + return MODULE_ERR_NOTNEEDED; + } + + // Clear FDD IRQ Flag + FDD_SensInt(0x3F0, NULL, NULL); + // Install IRQ6 Handler + IRQ_AddHandler(6, FDD_IRQHandler); + // Reset Primary FDD Controller + FDD_Reset(0); + + // Initialise Root Node + gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime + = gFDD_DriverInfo.RootNode.ATime = now(); + + // Initialise Child Nodes + gFDD_Devices[0].Node.Inode = 0; + gFDD_Devices[0].Node.Flags = 0; + gFDD_Devices[0].Node.NumACLs = 0; + gFDD_Devices[0].Node.Read = FDD_ReadFS; + gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS; + memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node)); + + gFDD_Devices[1].Node.Inode = 1; + + // Set Lengths + gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4]; + gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF]; + + // Create Sector Cache + if( cFDD_SIZES[data >> 4] ) + { + gFDD_Devices[0].CacheHandle = IOCache_Create( + FDD_WriteSector, 0, 512, + gFDD_Devices[0].Node.Size / (512*4) + ); // Cache is 1/4 the size of the disk + } + if( cFDD_SIZES[data & 15] ) + { + gFDD_Devices[1].CacheHandle = IOCache_Create( + FDD_WriteSector, 0, 512, + gFDD_Devices[1].Node.Size / (512*4) + ); // Cache is 1/4 the size of the disk + } + + // Register with devfs + DevFS_AddDevice(&gFDD_DriverInfo); + + return MODULE_ERR_OK; +} + +/** + * \brief Prepare the module for removal + */ +void FDD_UnloadModule() +{ + int i; + //DevFS_DelDevice( &gFDD_DriverInfo ); + LOCK(&glFDD); + for(i=0;i<4;i++) { + Time_RemoveTimer(gFDD_Devices[i].timer); + FDD_int_StopMotor(i); + } + RELEASE(&glFDD); + //IRQ_Clear(6); +} + +/** + * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos) + * \brief Read Directory + */ +char *FDD_ReadDir(tVFS_Node *Node, int Pos) +{ + char name[2] = "0\0"; + + if(Pos >= 2 || Pos < 0) return NULL; + + if(gFDD_Devices[Pos].type == 0) return VFS_SKIP; + + name[0] += Pos; + + return strdup(name); +} + +/** + * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename); + * \brief Find File Routine (for vfs_node) + */ +tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *Filename) +{ + int i; + + ENTER("sFilename", Filename); + + // Sanity check string + if(Filename == NULL) { + LEAVE('n'); + return NULL; + } + + // Check string length (should be 1) + if(Filename[0] == '\0' || Filename[1] != '\0') { + LEAVE('n'); + return NULL; + } + + // Get First character + i = Filename[0] - '0'; + + // Check for 1st disk and if it is present return + if(i == 0 && gFDD_Devices[0].type != 0) { + LEAVE('p', &gFDD_Devices[0].Node); + return &gFDD_Devices[0].Node; + } + + // Check for 2nd disk and if it is present return + if(i == 1 && gFDD_Devices[1].type != 0) { + LEAVE('p', &gFDD_Devices[1].Node); + return &gFDD_Devices[1].Node; + } + + // Else return null + LEAVE('n'); + return NULL; +} + +static const char *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL}; +/** + * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data) + * \brief Stub ioctl function + */ +int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data) +{ + switch(ID) + { + case DRV_IOCTL_TYPE: return DRV_TYPE_DISK; + case DRV_IOCTL_IDENT: return ModUtil_SetIdent(Data, "FDD"); + case DRV_IOCTL_VERSION: return FDD_VERSION; + case DRV_IOCTL_LOOKUP: return ModUtil_LookupString((char**)casIOCTLS, Data); + + case DISK_IOCTL_GETBLOCKSIZE: return 512; + + default: + return 0; + } +} + +/** + * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + * \brief Read Data from a disk +*/ +Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + int ret; + + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + + if(Node == NULL) { + LEAVE('i', -1); + return -1; + } + + if(Node->Inode != 0 && Node->Inode != 1) { + LEAVE('i', -1); + return -1; + } + + ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode); + LEAVE('i', ret); + return ret; +} + +/** + * \brief Reads \a Count contiguous sectors from a disk + * \param SectorAddr Address of the first sector + * \param Count Number of sectors to read + * \param Buffer Destination Buffer + * \param Disk Disk Number + * \return Number of sectors read + * \note Used as a ::DrvUtil_ReadBlock helper + */ +Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk) +{ + Uint ret = 0; + while(Count --) + { + if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 ) + return ret; + + Buffer = (void*)( (tVAddr)Buffer + 512 ); + SectorAddr ++; + ret ++; + } + return ret; +} + +int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer) +{ + int cyl, head, sec; + int spt, base; + int i; + int lba = SectorAddr; + Uint8 st0, st1, st2, rcy, rhe, rse, bps; // Status Values + + ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer); + + base = cPORTBASE[Disk >> 1]; + + LOG("Calculating Disk Dimensions"); + // Get CHS position + if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1) + { + LEAVE('i', -1); + return -1; + } + LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec); + + LOCK(&glFDD); // Lock to stop the motor stopping on us + Time_RemoveTimer(gFDD_Devices[Disk].timer); // Remove Old Timer + // Start motor if needed + if(gFDD_Devices[Disk].motorState != 2) FDD_int_StartMotor(Disk); + RELEASE(&glFDD); + + LOG("Wait for the motor to spin up"); + + // Wait for spinup + while(gFDD_Devices[Disk].motorState == 1) Threads_Yield(); + + LOG("Acquire Spinlock"); + LOCK(&glFDD); + + // Seek to track + outb(base + CALIBRATE_DRIVE, 0); + i = 0; + while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT ) + Threads_Yield(); + if( i > FDD_SEEK_TIMEOUT ) { + RELEASE(&glFDD); + LEAVE('i', 0); + return 0; + } + //FDD_SensInt(base, NULL, NULL); // Wait for IRQ + + // Read Data from DMA + LOG("Setting DMA for read"); + DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2 + + LOG("Sending command"); + + //Threads_Wait(100); // Wait for Head to settle + Time_Delay(100); + + for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ ) + { + if( Write ) + FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 + else + FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 + FDD_int_SendByte(base, (head << 2) | (Disk&1)); + FDD_int_SendByte(base, (Uint8)cyl); + FDD_int_SendByte(base, (Uint8)head); + FDD_int_SendByte(base, (Uint8)sec); + FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val}) + FDD_int_SendByte(base, spt); // SPT + FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default) + FDD_int_SendByte(base, 0xFF); // Data Length + + // Wait for IRQ + if( Write ) { + LOG("Writing Data"); + DMA_WriteData(2, 512, Buffer); + LOG("Waiting for Data to be written"); + FDD_WaitIRQ(); + } + else { + LOG("Waiting for data to be read"); + FDD_WaitIRQ(); + LOG("Reading Data"); + DMA_ReadData(2, 512, Buffer); + } + + // Clear Input Buffer + LOG("Clearing Input Buffer"); + // Status Values + st0 = FDD_int_GetByte(base); + st1 = FDD_int_GetByte(base); + st2 = FDD_int_GetByte(base); + + // Cylinder, Head and Sector (mutilated in some way + rcy = FDD_int_GetByte(base); + rhe = FDD_int_GetByte(base); + rse = FDD_int_GetByte(base); + // Should be the BPS set above (0x02) + bps = FDD_int_GetByte(base); + + // Check Status + // - Error Code + if(st0 & 0xC0) { + LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]); + continue; + } + // - Status Flags + if(st0 & 0x08) { LOG("Drive not ready"); continue; } + if(st1 & 0x80) { LOG("End of Cylinder"); continue; } + if(st1 & 0x20) { LOG("CRC Error"); continue; } + if(st1 & 0x10) { LOG("Controller Timeout"); continue; } + if(st1 & 0x04) { LOG("No Data Found"); continue; } + if(st1 & 0x01 || st2 & 0x01) { + LOG("No Address mark found"); + continue; + } + if(st2 & 0x40) { LOG("Deleted address mark"); continue; } + if(st2 & 0x20) { LOG("CRC error in data"); continue; } + if(st2 & 0x10) { LOG("Wrong Cylinder"); continue; } + if(st2 & 0x04) { LOG("uPD765 sector not found"); continue; } + if(st2 & 0x02) { LOG("Bad Cylinder"); continue; } + + if(bps != 0x2) { + LOG("Returned BPS = 0x%02x, not 0x02", bps); + continue; + } + + if(st1 & 0x02) { + LOG("Floppy not writable"); + i = FDD_MAX_READWRITE_ATTEMPTS+1; + break; + } + + // Success! + break; + } + + // Release Spinlock + LOG("Realeasing Spinlock and setting motor to stop"); + RELEASE(&glFDD); + + if(i == FDD_MAX_READWRITE_ATTEMPTS) { + Log_Warning("FDD", "Exceeded %i attempts in %s the disk", + FDD_MAX_READWRITE_ATTEMPTS, + (Write ? "writing to" : "reading from") + ); + } + + // Don't turn the motor off now, wait for a while + gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)(tVAddr)Disk); + + if( i < FDD_MAX_READWRITE_ATTEMPTS ) { + LEAVE('i', 0); + return 0; + } + else { + LEAVE('i', 1); + return 1; + } +} + +/** + * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) + * \brief Read a sector from disk + * \todo Make real-hardware safe (account for read errors) +*/ +int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) +{ + int ret; + + ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer); + + if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) { + LEAVE('i', 1); + return 1; + } + + // Pass to general function ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer); - - if( ret == 0 ) { + + if( ret == 0 ) { IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ); - LEAVE('i', 1); - return 1; - } - else { - LOG("Reading failed"); - LEAVE('i', 0); - return 0; - } -} - -/** - * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer) - * \brief Write a sector to the floppy disk - * \note Not Implemented - */ -int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer) -{ - Warning("[FDD ] Read Only at the moment"); - return -1; -} - -/** - * \fn int FDD_int_SeekTrack(int disk, int track) - * \brief Seek disk to selected track - */ -int FDD_int_SeekTrack(int disk, int head, int track) -{ - Uint8 sr0, cyl; - int base; - - base = cPORTBASE[disk>>1]; - - // Check if seeking is needed - if(gFDD_Devices[disk].track[head] == track) - return 1; - - // - Seek Head 0 - FDD_int_SendByte(base, SEEK_TRACK); - FDD_int_SendByte(base, (head<<2)|(disk&1)); - FDD_int_SendByte(base, track); // Send Seek command - FDD_WaitIRQ(); - FDD_SensInt(base, &sr0, &cyl); // Wait for IRQ + LEAVE('i', 1); + return 1; + } + else { + LOG("Reading failed"); + LEAVE('i', 0); + return 0; + } +} + +/** + * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer) + * \brief Write a sector to the floppy disk + * \note Not Implemented + */ +int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer) +{ + Warning("[FDD ] Read Only at the moment"); + return -1; +} + +/** + * \fn int FDD_int_SeekTrack(int disk, int track) + * \brief Seek disk to selected track + */ +int FDD_int_SeekTrack(int disk, int head, int track) +{ + Uint8 sr0, cyl; + int base; + + base = cPORTBASE[disk>>1]; + + // Check if seeking is needed + if(gFDD_Devices[disk].track[head] == track) + return 1; + + // - Seek Head 0 + FDD_int_SendByte(base, SEEK_TRACK); + FDD_int_SendByte(base, (head<<2)|(disk&1)); + FDD_int_SendByte(base, track); // Send Seek command + FDD_WaitIRQ(); + FDD_SensInt(base, &sr0, &cyl); // Wait for IRQ if((sr0 & 0xF0) != 0x20) { LOG("sr0 = 0x%x", sr0); return 0; //Check Status - } - if(cyl != track) return 0; - - // Set Track in structure - gFDD_Devices[disk].track[head] = track; - return 1; -} - -/** - * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt) - * \brief Get Dimensions of a disk - */ -int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt) -{ - switch(type) { - case 0: - return 0; - - // 360Kb 5.25" - case 1: - *spt = 9; - *s = (lba % 9) + 1; - *c = lba / 18; - *h = (lba / 9) & 1; - break; - - // 1220Kb 5.25" - case 2: - *spt = 15; - *s = (lba % 15) + 1; - *c = lba / 30; - *h = (lba / 15) & 1; - break; - - // 720Kb 3.5" - case 3: - *spt = 9; - *s = (lba % 9) + 1; - *c = lba / 18; - *h = (lba / 9) & 1; - break; - - // 1440Kb 3.5" - case 4: - *spt = 18; - *s = (lba % 18) + 1; - *c = lba / 36; - *h = (lba / 18) & 1; - //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h); - break; - - // 2880Kb 3.5" - case 5: - *spt = 36; - *s = (lba % 36) + 1; - *c = lba / 72; - *h = (lba / 32) & 1; - break; - - default: - return -2; - } - return 1; -} - -/** - * \fn void FDD_IRQHandler(int Num) - * \brief Handles IRQ6 - */ -void FDD_IRQHandler(int Num) -{ - gbFDD_IrqFired = 1; -} - -/** - * \fn FDD_WaitIRQ() - * \brief Wait for an IRQ6 - */ -inline void FDD_WaitIRQ() -{ - // Wait for IRQ - while(!gbFDD_IrqFired) Threads_Yield(); - gbFDD_IrqFired = 0; -} - -void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl) -{ - FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS); - if(sr0) *sr0 = FDD_int_GetByte(base); - else FDD_int_GetByte(base); - if(cyl) *cyl = FDD_int_GetByte(base); - else FDD_int_GetByte(base); -} - -/** - * void FDD_int_SendByte(int base, char byte) - * \brief Sends a command to the controller - */ -void FDD_int_SendByte(int base, char byte) -{ - volatile int state; - int timeout = 128; - for( ; timeout--; ) - { - state = inb(base + PORT_MAINSTATUS); - if ((state & 0xC0) == 0x80) - { - outb(base + PORT_DATA, byte); - return; - } - inb(0x80); //Delay - } - - #if WARN - Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base); - #endif -} - -/** - * int FDD_int_GetByte(int base, char byte) - * \brief Receive data from fdd controller - */ -int FDD_int_GetByte(int base) -{ - volatile int state; - int timeout; - for( timeout = 128; timeout--; ) - { - state = inb((base + PORT_MAINSTATUS)); - if ((state & 0xd0) == 0xd0) - return inb(base + PORT_DATA); - inb(0x80); - } - return -1; -} - -/** - * \brief Recalibrate the specified disk - */ -void FDD_Recalibrate(int disk) -{ - ENTER("idisk", disk); - - LOG("Starting Motor"); - FDD_int_StartMotor(disk); - // Wait for Spinup - while(gFDD_Devices[disk].motorState == 1) Threads_Yield(); - - LOG("Sending Calibrate Command"); - FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE); - FDD_int_SendByte(cPORTBASE[disk>>1], disk&1); - - LOG("Waiting for IRQ"); - FDD_WaitIRQ(); - FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL); - - LOG("Stopping Motor"); - FDD_int_StopMotor(disk); - LEAVE('-'); -} - -/** - * \brief Reset the specified FDD controller - */ -void FDD_Reset(int id) -{ - int base = cPORTBASE[id]; - - ENTER("iID", id); - - outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC - outb(base + PORT_DIGOUTPUT, 0x0C); // Re-enable FDC (DMA and Enable) - - LOG("Awaiting IRQ"); - - FDD_WaitIRQ(); - FDD_SensInt(base, NULL, NULL); - - LOG("Setting Driver Info"); - outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s - FDD_int_SendByte(base, FIX_DRIVE_DATA); // 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 - while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track - while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track - - LOG("Recalibrating Disk"); - FDD_Recalibrate((id<<1)|0); + } + if(cyl != track) return 0; + + // Set Track in structure + gFDD_Devices[disk].track[head] = track; + return 1; +} + +/** + * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt) + * \brief Get Dimensions of a disk + */ +int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt) +{ + switch(type) { + case 0: + return 0; + + // 360Kb 5.25" + case 1: + *spt = 9; + *s = (lba % 9) + 1; + *c = lba / 18; + *h = (lba / 9) & 1; + break; + + // 1220Kb 5.25" + case 2: + *spt = 15; + *s = (lba % 15) + 1; + *c = lba / 30; + *h = (lba / 15) & 1; + break; + + // 720Kb 3.5" + case 3: + *spt = 9; + *s = (lba % 9) + 1; + *c = lba / 18; + *h = (lba / 9) & 1; + break; + + // 1440Kb 3.5" + case 4: + *spt = 18; + *s = (lba % 18) + 1; + *c = lba / 36; + *h = (lba / 18) & 1; + //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h); + break; + + // 2880Kb 3.5" + case 5: + *spt = 36; + *s = (lba % 36) + 1; + *c = lba / 72; + *h = (lba / 32) & 1; + break; + + default: + return -2; + } + return 1; +} + +/** + * \fn void FDD_IRQHandler(int Num) + * \brief Handles IRQ6 + */ +void FDD_IRQHandler(int Num) +{ + gbFDD_IrqFired = 1; +} + +/** + * \fn FDD_WaitIRQ() + * \brief Wait for an IRQ6 + */ +inline void FDD_WaitIRQ() +{ + // Wait for IRQ + while(!gbFDD_IrqFired) Threads_Yield(); + gbFDD_IrqFired = 0; +} + +void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl) +{ + FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS); + if(sr0) *sr0 = FDD_int_GetByte(base); + else FDD_int_GetByte(base); + if(cyl) *cyl = FDD_int_GetByte(base); + else FDD_int_GetByte(base); +} + +/** + * void FDD_int_SendByte(int base, char byte) + * \brief Sends a command to the controller + */ +void FDD_int_SendByte(int base, char byte) +{ + volatile int state; + int timeout = 128; + for( ; timeout--; ) + { + state = inb(base + PORT_MAINSTATUS); + if ((state & 0xC0) == 0x80) + { + outb(base + PORT_DATA, byte); + return; + } + inb(0x80); //Delay + } + + #if WARN + Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base); + #endif +} + +/** + * int FDD_int_GetByte(int base, char byte) + * \brief Receive data from fdd controller + */ +int FDD_int_GetByte(int base) +{ + volatile int state; + int timeout; + for( timeout = 128; timeout--; ) + { + state = inb((base + PORT_MAINSTATUS)); + if ((state & 0xd0) == 0xd0) + return inb(base + PORT_DATA); + inb(0x80); + } + return -1; +} + +/** + * \brief Recalibrate the specified disk + */ +void FDD_Recalibrate(int disk) +{ + ENTER("idisk", disk); + + LOG("Starting Motor"); + FDD_int_StartMotor(disk); + // Wait for Spinup + while(gFDD_Devices[disk].motorState == 1) Threads_Yield(); + + LOG("Sending Calibrate Command"); + FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE); + FDD_int_SendByte(cPORTBASE[disk>>1], disk&1); + + LOG("Waiting for IRQ"); + FDD_WaitIRQ(); + FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL); + + LOG("Stopping Motor"); + FDD_int_StopMotor(disk); + LEAVE('-'); +} + +/** + * \brief Reset the specified FDD controller + */ +void FDD_Reset(int id) +{ + int base = cPORTBASE[id]; + + ENTER("iID", id); + + outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC + outb(base + PORT_DIGOUTPUT, 0x0C); // Re-enable FDC (DMA and Enable) + + LOG("Awaiting IRQ"); + + FDD_WaitIRQ(); + FDD_SensInt(base, NULL, NULL); + + LOG("Setting Driver Info"); + outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s + FDD_int_SendByte(base, FIX_DRIVE_DATA); // 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 + while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track + while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track + + LOG("Recalibrating Disk"); + FDD_Recalibrate((id<<1)|0); FDD_Recalibrate((id<<1)|1); - - LEAVE('-'); -} - -/** - * \fn void FDD_int_TimerCallback() - * \brief Called by timer - */ -void FDD_int_TimerCallback(int arg) -{ - ENTER("iarg", arg); - if(gFDD_Devices[arg].motorState == 1) - gFDD_Devices[arg].motorState = 2; - Time_RemoveTimer(gFDD_Devices[arg].timer); - gFDD_Devices[arg].timer = -1; - LEAVE('-'); -} - -/** - * \fn void FDD_int_StartMotor(char disk) - * \brief Starts FDD Motor - */ -void FDD_int_StartMotor(int disk) -{ - Uint8 state; - state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT ); - state |= 1 << (4+disk); - outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state ); - gFDD_Devices[disk].motorState = 1; - gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)disk); -} - -/** - * \fn void FDD_int_StopMotor(int disk) - * \brief Stops FDD Motor - */ -void FDD_int_StopMotor(int disk) -{ - Uint8 state; - if( IS_LOCKED(&glFDD) ) return ; - ENTER("iDisk", disk); - - state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT ); - state &= ~( 1 << (4+disk) ); - outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state ); - gFDD_Devices[disk].motorState = 0; - LEAVE('-'); -} + + LEAVE('-'); +} + +/** + * \fn void FDD_int_TimerCallback() + * \brief Called by timer + */ +void FDD_int_TimerCallback(int arg) +{ + ENTER("iarg", arg); + if(gFDD_Devices[arg].motorState == 1) + gFDD_Devices[arg].motorState = 2; + Time_RemoveTimer(gFDD_Devices[arg].timer); + gFDD_Devices[arg].timer = -1; + LEAVE('-'); +} + +/** + * \fn void FDD_int_StartMotor(char disk) + * \brief Starts FDD Motor + */ +void FDD_int_StartMotor(int disk) +{ + Uint8 state; + state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT ); + state |= 1 << (4+disk); + outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state ); + gFDD_Devices[disk].motorState = 1; + gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)(tVAddr)disk); +} + +/** + * \fn void FDD_int_StopMotor(int disk) + * \brief Stops FDD Motor + */ +void FDD_int_StopMotor(int disk) +{ + Uint8 state; + if( IS_LOCKED(&glFDD) ) return ; + ENTER("iDisk", disk); + + state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT ); + state &= ~( 1 << (4+disk) ); + outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state ); + gFDD_Devices[disk].motorState = 0; + LEAVE('-'); +}