mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +00:00
Improved GDT managment
svn path=/trunk/; revision=369
This commit is contained in:
parent
99fa281af1
commit
5503a0f0e4
21 changed files with 222 additions and 188 deletions
|
@ -209,6 +209,8 @@ NTSTATUS MinixCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
Irp->IoStatus.Status = Status;
|
Irp->IoStatus.Status = Status;
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
|
|
||||||
|
DPRINT("Finished MinixCreate()\n");
|
||||||
|
|
||||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <internal/bitops.h>
|
#include <internal/bitops.h>
|
||||||
#include <ddk/ntifs.h>
|
#include <ddk/ntifs.h>
|
||||||
|
|
||||||
#define NDEBUG
|
//#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
#include "minix.h"
|
#include "minix.h"
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#
|
all: minix.sys
|
||||||
#
|
|
||||||
#
|
|
||||||
OBJECTS = block.o rw.o inode.o dir.o mount.o blockdev.o
|
|
||||||
|
|
||||||
all: minix.o
|
OBJECTS = block.o rw.o inode.o dir.o mount.o blockdev.o \
|
||||||
|
../../../ntoskrnl/ntoskrnl.a
|
||||||
|
|
||||||
.phony: all
|
.phony: all
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <internal/string.h>
|
#include <internal/string.h>
|
||||||
#include <wstring.h>
|
#include <wstring.h>
|
||||||
|
|
||||||
#define NDEBUG
|
//#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
#include "minix_fs.h"
|
#include "minix_fs.h"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <ddk/ntddk.h>
|
#include <ddk/ntddk.h>
|
||||||
#include <ddk/ntifs.h>
|
#include <ddk/ntifs.h>
|
||||||
|
|
||||||
#define NDEBUG
|
//#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
#include "minix.h"
|
#include "minix.h"
|
||||||
|
@ -87,8 +87,8 @@ NTSTATUS MinixFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject,
|
NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT _DriverObject,
|
||||||
PUNICODE_STRING RegistryPath)
|
PUNICODE_STRING RegistryPath)
|
||||||
/*
|
/*
|
||||||
* FUNCTION: Called by the system to initalize the driver
|
* FUNCTION: Called by the system to initalize the driver
|
||||||
* ARGUMENTS:
|
* ARGUMENTS:
|
||||||
|
|
|
@ -11,6 +11,20 @@ typedef struct
|
||||||
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
|
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct _BCB
|
||||||
|
{
|
||||||
|
LIST_ENTRY CacheSegmentListHead;
|
||||||
|
PFILE_OBJECT FileObject;
|
||||||
|
KSPIN_LOCK BcbLock;
|
||||||
|
} BCB, *PBCB;
|
||||||
|
|
||||||
|
NTSTATUS CcRequestCachePage(PBCB Bcb,
|
||||||
|
ULONG FileOffset,
|
||||||
|
PVOID* BaseAddress,
|
||||||
|
PBOOLEAN UptoDate);
|
||||||
|
NTSTATUS CcInitializeFileCache(PFILE_OBJECT FileObject,
|
||||||
|
PBCB* Bcb);
|
||||||
|
|
||||||
#include <ddk/cctypes.h>
|
#include <ddk/cctypes.h>
|
||||||
|
|
||||||
#include <ddk/ccfuncs.h>
|
#include <ddk/ccfuncs.h>
|
||||||
|
|
|
@ -5099,7 +5099,10 @@ NTSTATUS STDCALL NtRequestPort(VOID);
|
||||||
|
|
||||||
NTSTATUS STDCALL NtSetDefaultLocale(VOID);
|
NTSTATUS STDCALL NtSetDefaultLocale(VOID);
|
||||||
|
|
||||||
NTSTATUS STDCALL NtSetLdtEntries(VOID);
|
//NTSTATUS STDCALL NtSetLdtEntries(VOID);
|
||||||
|
NTSTATUS STDCALL NtSetLdtEntries(PEPROCESS Process,
|
||||||
|
ULONG FirstEntry,
|
||||||
|
PULONG Entries);
|
||||||
|
|
||||||
NTSTATUS STDCALL NtSetSystemPowerState(VOID);
|
NTSTATUS STDCALL NtSetSystemPowerState(VOID);
|
||||||
|
|
||||||
|
|
|
@ -37,24 +37,9 @@ void set_page(unsigned int vaddr, unsigned int attributes,
|
||||||
#define PA_SYSTEM (0)
|
#define PA_SYSTEM (0)
|
||||||
|
|
||||||
#define KERNEL_BASE (0xc0000000)
|
#define KERNEL_BASE (0xc0000000)
|
||||||
#define IDMAP_BASE (0xd0000000)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return a linear address which can be used to access the physical memory
|
|
||||||
* starting at x
|
|
||||||
*/
|
|
||||||
extern inline unsigned int physical_to_linear(unsigned int x)
|
|
||||||
{
|
|
||||||
return(x+IDMAP_BASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern inline unsigned int linear_to_physical(unsigned int x)
|
|
||||||
{
|
|
||||||
return(x-IDMAP_BASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FLUSH_TLB __asm__("movl %cr3,%eax\n\tmovl %eax,%cr3\n\t")
|
#define FLUSH_TLB __asm__("movl %cr3,%eax\n\tmovl %eax,%cr3\n\t")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type,
|
||||||
ULONG Size, ULONG SignalState);
|
ULONG Size, ULONG SignalState);
|
||||||
|
|
||||||
VOID KeDumpStackFrames(ULONG DummyArg, ULONG NrFrames);
|
VOID KeDumpStackFrames(ULONG DummyArg, ULONG NrFrames);
|
||||||
|
ULONG KeAllocateGdtSelector(ULONG Desc[2]);
|
||||||
|
VOID KeFreeGdtSelector(ULONG Entry);
|
||||||
|
|
||||||
/* INITIALIZATION FUNCTIONS *************************************************/
|
/* INITIALIZATION FUNCTIONS *************************************************/
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ enum
|
||||||
MEMORY_AREA_COMMIT,
|
MEMORY_AREA_COMMIT,
|
||||||
MEMORY_AREA_RESERVE,
|
MEMORY_AREA_RESERVE,
|
||||||
MEMORY_AREA_SECTION_VIEW_RESERVE,
|
MEMORY_AREA_SECTION_VIEW_RESERVE,
|
||||||
|
MEMORY_AREA_CACHE_SEGMENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
|
@ -16,6 +16,8 @@ VOID PsDispatchThread(VOID);
|
||||||
VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus);
|
VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus);
|
||||||
VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus);
|
VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus);
|
||||||
VOID PsReleaseThread(PETHREAD Thread);
|
VOID PsReleaseThread(PETHREAD Thread);
|
||||||
|
VOID PsBeginThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext);
|
||||||
|
VOID PsBeginThreadWithContextInternal(VOID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PURPOSE: Thread states
|
* PURPOSE: Thread states
|
||||||
|
|
|
@ -9,18 +9,7 @@
|
||||||
#include <internal/stddef.h>
|
#include <internal/stddef.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
#include <string.h>
|
||||||
* On a 486 or Pentium, we are better off not using the
|
|
||||||
* byte string operations. But on a 386 or a PPro the
|
|
||||||
* byte string ops are faster than doing it by hand
|
|
||||||
* (MUCH faster on a Pentium).
|
|
||||||
*
|
|
||||||
* Also, the byte strings actually work correctly. Forget
|
|
||||||
* the i486 routines for now as they may be broken..
|
|
||||||
*/
|
|
||||||
#if FIXED_486_STRING && (CPU == 486 || CPU == 586)
|
|
||||||
#include <asm/string-486.h>
|
|
||||||
#else
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This string-include defines all string functions as inline
|
* This string-include defines all string functions as inline
|
||||||
|
@ -492,4 +481,3 @@ extern inline void * memscan(void * addr, int c, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
#ifndef _LINUX_TYPES_H
|
#ifndef _LINUX_TYPES_H
|
||||||
#define _LINUX_TYPES_H
|
#define _LINUX_TYPES_H
|
||||||
|
|
||||||
|
|
|
@ -12,32 +12,26 @@
|
||||||
|
|
||||||
#include <ddk/ntddk.h>
|
#include <ddk/ntddk.h>
|
||||||
#include <ddk/ntifs.h>
|
#include <ddk/ntifs.h>
|
||||||
#include <internal/bitops.h>
|
#include <internal/mm.h>
|
||||||
|
|
||||||
#define NDEBUG
|
//#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/* TYPES *********************************************************************/
|
/* TYPES *********************************************************************/
|
||||||
|
|
||||||
#define CACHE_SEGMENT_SIZE (0x10000)
|
#define CACHE_SEGMENT_SIZE (0x1000)
|
||||||
|
|
||||||
typedef struct _CACHE_SEGMENT
|
typedef struct _CACHE_SEGMENT
|
||||||
{
|
{
|
||||||
PVOID BaseAddress;
|
PVOID BaseAddress;
|
||||||
PMEMORY_AREA MemoryArea;
|
PMEMORY_AREA MemoryArea;
|
||||||
ULONG ValidPages;
|
BOOLEAN Valid;
|
||||||
ULONG AllocatedPages;
|
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
ULONG FileOffset;
|
ULONG FileOffset;
|
||||||
|
KEVENT Lock;
|
||||||
|
ULONG ReferenceCount;
|
||||||
} CACHE_SEGMENT, *PCACHE_SEGMENT;
|
} CACHE_SEGMENT, *PCACHE_SEGMENT;
|
||||||
|
|
||||||
typedef struct _BCB
|
|
||||||
{
|
|
||||||
LIST_ENTRY CacheSegmentListHead;
|
|
||||||
PFILE_OBJECT FileObject;
|
|
||||||
KSPIN_LOCK BcbLock;
|
|
||||||
} BCB, *PBCB;
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
NTSTATUS CcRequestCachePage(PBCB Bcb,
|
NTSTATUS CcRequestCachePage(PBCB Bcb,
|
||||||
|
@ -48,59 +42,74 @@ NTSTATUS CcRequestCachePage(PBCB Bcb,
|
||||||
KIRQL oldirql;
|
KIRQL oldirql;
|
||||||
PLIST_ENTRY current_entry;
|
PLIST_ENTRY current_entry;
|
||||||
PCACHE_SEGMENT current;
|
PCACHE_SEGMENT current;
|
||||||
ULONG InternalOffset;
|
|
||||||
|
DPRINT("CcRequestCachePage(Bcb %x, FileOffset %x)\n");
|
||||||
|
|
||||||
KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
|
||||||
|
|
||||||
current_entry = Bcb->CacheSegmentListHead.Flink;
|
current_entry = Bcb->CacheSegmentListHead.Flink;
|
||||||
while (current_entry != &Bcb->CacheSegmentListHead)
|
while (current_entry != &Bcb->CacheSegmentListHead)
|
||||||
{
|
{
|
||||||
current = CONTAING_RECORD(current, CACHE_SEGMENT, ListEntry);
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, ListEntry);
|
||||||
if (current->FileOffset <= FileOffset &&
|
if (current->FileOffset == PAGE_ROUND_DOWN(FileOffset))
|
||||||
(current->FileOffset + CACHE_SEGMENT_SIZE) > FileOffset)
|
|
||||||
{
|
{
|
||||||
InternalOffset = (FileOffset - current->FileOffset);
|
current->ReferenceCount++;
|
||||||
|
|
||||||
if (!test_bit(InternalOffset / PAGESIZE,
|
|
||||||
current->AllocatedPages))
|
|
||||||
{
|
|
||||||
MmSetPageEntry(PsGetCurrentProcess(),
|
|
||||||
current->BaseAddress + InternalOffset,
|
|
||||||
PAGE_READWRITE,
|
|
||||||
get_free_page());
|
|
||||||
}
|
|
||||||
if (!test_bit(InternalOffset / PAGESIZE,
|
|
||||||
current->ValidPages))
|
|
||||||
{
|
|
||||||
UptoDate = False;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UptoDate = True;
|
|
||||||
}
|
|
||||||
(*BaseAddress) = current->BaseAddress + InternalOffset;
|
|
||||||
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
||||||
|
KeWaitForSingleObject(¤t->Lock,
|
||||||
|
Executive,
|
||||||
|
KernelMode,
|
||||||
|
FALSE,
|
||||||
|
NULL);
|
||||||
|
*UptoDate = current->Valid;
|
||||||
|
BaseAddress = current->BaseAddress;
|
||||||
return(STATUS_SUCCESS);
|
return(STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
current_entry = current_entry->Flink;
|
current_entry = current_entry->Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current = ExAllocatePool(NonPagedPool, sizeof(CACHE_SEGMENT));
|
||||||
|
current->BaseAddress = NULL;
|
||||||
|
MmCreateMemoryArea(KernelMode,
|
||||||
|
PsGetCurrentProcess(),
|
||||||
|
MEMORY_AREA_CACHE_SEGMENT,
|
||||||
|
¤t->BaseAddress,
|
||||||
|
CACHE_SEGMENT_SIZE,
|
||||||
|
PAGE_READWRITE,
|
||||||
|
¤t->MemoryArea);
|
||||||
|
current->Valid = FALSE;
|
||||||
|
current->FileOffset = PAGE_ROUND_DOWN(FileOffset);
|
||||||
|
KeInitializeEvent(¤t->Lock, SynchronizationEvent, TRUE);
|
||||||
|
current->ReferenceCount = 1;
|
||||||
|
InsertTailList(&Bcb->CacheSegmentListHead, ¤t->ListEntry);
|
||||||
|
*UptoDate = current->Valid;
|
||||||
|
*BaseAddress = current->BaseAddress;
|
||||||
|
MmSetPage(PsGetCurrentProcess(),
|
||||||
|
current->BaseAddress,
|
||||||
|
(ULONG)MmAllocPage(),
|
||||||
|
PAGE_READWRITE);
|
||||||
|
|
||||||
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
||||||
|
|
||||||
|
return(STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS CcInitializeFileCache(PFILE_OBJECT FileObject,
|
NTSTATUS CcInitializeFileCache(PFILE_OBJECT FileObject,
|
||||||
PBCB* Bcb)
|
PBCB* Bcb)
|
||||||
{
|
{
|
||||||
|
DPRINT("CcInitializeFileCache(FileObject %x)\n",FileObject);
|
||||||
|
|
||||||
(*Bcb) = ExAllocatePool(NonPagedPool, sizeof(BCB));
|
(*Bcb) = ExAllocatePool(NonPagedPool, sizeof(BCB));
|
||||||
if ((*Bcb) == NULL)
|
if ((*Bcb) == NULL)
|
||||||
{
|
{
|
||||||
return(STATUS_OUT_OF_MEMORY);
|
return(STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*Bcb)->FileObject = FileObject;
|
(*Bcb)->FileObject = FileObject;
|
||||||
InitializeListHead(&(*Bcb)->CacheSegmentListHead);
|
InitializeListHead(&(*Bcb)->CacheSegmentListHead);
|
||||||
KeInitializeSpinLock(&(*Bcb)->BcbLock);
|
KeInitializeSpinLock(&(*Bcb)->BcbLock);
|
||||||
|
|
||||||
|
DPRINT("Finished CcInitializeFileCache() = %x\n", *Bcb);
|
||||||
|
|
||||||
return(STATUS_SUCCESS);
|
return(STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,38 +28,6 @@ start:
|
||||||
jmp __main
|
jmp __main
|
||||||
|
|
||||||
.data
|
.data
|
||||||
_gdt:
|
|
||||||
.word 0
|
|
||||||
.word 0
|
|
||||||
.word 0
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
.word 0x0000
|
|
||||||
.word 0x0000
|
|
||||||
.word 0xfa00
|
|
||||||
.word 0x00cc
|
|
||||||
|
|
||||||
.word 0x0000
|
|
||||||
.word 0x0000
|
|
||||||
.word 0xf200
|
|
||||||
.word 0x00cc
|
|
||||||
|
|
||||||
.word 0xffff
|
|
||||||
.word 0x0000
|
|
||||||
.word 0x9200
|
|
||||||
.word 0x00cf
|
|
||||||
|
|
||||||
.word 0xffff
|
|
||||||
.word 0x0000
|
|
||||||
.word 0x9a00
|
|
||||||
.word 0x00cf
|
|
||||||
|
|
||||||
.word 0xffff
|
|
||||||
.word 0x0000
|
|
||||||
.word 0x9200
|
|
||||||
.word 0x00cf
|
|
||||||
|
|
||||||
.fill 128,8,0
|
|
||||||
|
|
||||||
_idt_descr:
|
_idt_descr:
|
||||||
.word (256*8)-1
|
.word (256*8)-1
|
||||||
|
@ -67,7 +35,7 @@ _idt_descr:
|
||||||
|
|
||||||
_gdt_descr:
|
_gdt_descr:
|
||||||
.word ((6+NR_TASKS)*8)-1
|
.word ((6+NR_TASKS)*8)-1
|
||||||
.long _gdt
|
.long _KiGdt
|
||||||
|
|
||||||
_idt:
|
_idt:
|
||||||
.fill 256,8,0
|
.fill 256,8,0
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <internal/hal.h>
|
#include <internal/hal.h>
|
||||||
#include <internal/i386/segment.h>
|
#include <internal/i386/segment.h>
|
||||||
#include <internal/mmhal.h>
|
#include <internal/mmhal.h>
|
||||||
|
#include <internal/ke.h>
|
||||||
|
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
@ -26,25 +27,22 @@
|
||||||
|
|
||||||
#define NR_TASKS 128
|
#define NR_TASKS 128
|
||||||
|
|
||||||
VOID PsBeginThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext);
|
|
||||||
VOID PsBeginThreadWithContextInternal(VOID);
|
|
||||||
|
|
||||||
#define FIRST_TSS_SELECTOR (KERNEL_DS + 0x8)
|
#define FIRST_TSS_SELECTOR (KERNEL_DS + 0x8)
|
||||||
#define FIRST_TSS_OFFSET (FIRST_TSS_SELECTOR / 8)
|
#define FIRST_TSS_OFFSET (FIRST_TSS_SELECTOR / 8)
|
||||||
|
|
||||||
static char null_ldt[8]={0,};
|
static char KiNullLdt[8] = {0,};
|
||||||
static unsigned int null_ldt_sel=0;
|
static unsigned int KiNullLdtSel = 0;
|
||||||
static PETHREAD FirstThread=NULL;
|
static PETHREAD FirstThread = NULL;
|
||||||
|
|
||||||
/* FUNCTIONS **************************************************************/
|
/* FUNCTIONS **************************************************************/
|
||||||
|
|
||||||
void HalTaskSwitch(PKTHREAD thread)
|
VOID HalTaskSwitch(PKTHREAD thread)
|
||||||
/*
|
/*
|
||||||
* FUNCTION: Switch tasks
|
* FUNCTION: Switch tasks
|
||||||
* ARGUMENTS:
|
* ARGUMENTS:
|
||||||
* thread = Thread to switch to
|
* thread = Thread to switch to
|
||||||
* NOTE: This function will not return until the current thread is scheduled
|
* NOTE: This function will not return until the current thread is scheduled
|
||||||
* again
|
* again (possibly never);
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
DPRINT("Scheduling thread %x\n",thread);
|
DPRINT("Scheduling thread %x\n",thread);
|
||||||
|
@ -74,10 +72,6 @@ void HalTaskSwitch(PKTHREAD thread)
|
||||||
DPRINT("trap %x iomap_base %x nr %x io_bitmap[0] %x\n",
|
DPRINT("trap %x iomap_base %x nr %x io_bitmap[0] %x\n",
|
||||||
thread->Context.trap,thread->Context.iomap_base,
|
thread->Context.trap,thread->Context.iomap_base,
|
||||||
thread->Context.nr,thread->Context.io_bitmap[0]);
|
thread->Context.nr,thread->Context.io_bitmap[0]);
|
||||||
DPRINT("&gdt[nr/8].a %.8x gdt[nr/8].a %.8x gdt[nr/8].b %.8x\n",
|
|
||||||
&(gdt[thread->Context.nr/8].a),
|
|
||||||
gdt[thread->Context.nr/8].a,
|
|
||||||
gdt[thread->Context.nr/8].b);
|
|
||||||
DPRINT("thread->Context.cr3 %x\n",thread->Context.cr3);
|
DPRINT("thread->Context.cr3 %x\n",thread->Context.cr3);
|
||||||
__asm__("pushfl\n\t"
|
__asm__("pushfl\n\t"
|
||||||
"cli\n\t"
|
"cli\n\t"
|
||||||
|
@ -88,25 +82,6 @@ void HalTaskSwitch(PKTHREAD thread)
|
||||||
: "ax","dx");
|
: "ax","dx");
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int allocate_tss_descriptor(void)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Allocates a slot within the GDT to describe a TSS
|
|
||||||
* RETURNS: The offset within the GDT of the slot allocated on succcess
|
|
||||||
* Zero on failure
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
for (i=0;i<NR_TASKS;i++)
|
|
||||||
{
|
|
||||||
if (gdt[FIRST_TSS_OFFSET + i].a==0 &&
|
|
||||||
gdt[FIRST_TSS_OFFSET + i].b==0)
|
|
||||||
{
|
|
||||||
return(FIRST_TSS_OFFSET + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FLAG_NT (1<<14)
|
#define FLAG_NT (1<<14)
|
||||||
#define FLAG_VM (1<<17)
|
#define FLAG_VM (1<<17)
|
||||||
#define FLAG_IF (1<<9)
|
#define FLAG_IF (1<<9)
|
||||||
|
@ -165,8 +140,7 @@ NTSTATUS HalReleaseTask(PETHREAD Thread)
|
||||||
* NOTE: The thread had better not be running when this is called
|
* NOTE: The thread had better not be running when this is called
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
gdt[Thread->Tcb.Context.nr/8].a=0;
|
KeFreeGdtSelector(Thread->Tcb.Context.nr);
|
||||||
gdt[Thread->Tcb.Context.nr/8].b=0;
|
|
||||||
ExFreePool(Thread->Tcb.Context.KernelStackBase);
|
ExFreePool(Thread->Tcb.Context.KernelStackBase);
|
||||||
if (Thread->Tcb.Context.SavedKernelStackBase != NULL)
|
if (Thread->Tcb.Context.SavedKernelStackBase != NULL)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +164,7 @@ NTSTATUS HalInitTaskWithContext(PETHREAD Thread, PCONTEXT Context)
|
||||||
PVOID kernel_stack;
|
PVOID kernel_stack;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PVOID stack_start;
|
PVOID stack_start;
|
||||||
|
ULONG GdtDesc[2];
|
||||||
|
|
||||||
DPRINT("HalInitTaskWithContext(Thread %x, Context %x)\n",
|
DPRINT("HalInitTaskWithContext(Thread %x, Context %x)\n",
|
||||||
Thread,Context);
|
Thread,Context);
|
||||||
|
@ -200,13 +175,7 @@ NTSTATUS HalInitTaskWithContext(PETHREAD Thread, PCONTEXT Context)
|
||||||
{
|
{
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
desc = allocate_tss_descriptor();
|
|
||||||
if (desc == 0)
|
|
||||||
{
|
|
||||||
return(STATUS_UNSUCCESSFUL);
|
|
||||||
}
|
|
||||||
|
|
||||||
length = sizeof(hal_thread_state) - 1;
|
length = sizeof(hal_thread_state) - 1;
|
||||||
base = (unsigned int)(&(Thread->Tcb.Context));
|
base = (unsigned int)(&(Thread->Tcb.Context));
|
||||||
kernel_stack = ExAllocatePool(NonPagedPool,PAGESIZE);
|
kernel_stack = ExAllocatePool(NonPagedPool,PAGESIZE);
|
||||||
|
@ -214,9 +183,14 @@ NTSTATUS HalInitTaskWithContext(PETHREAD Thread, PCONTEXT Context)
|
||||||
/*
|
/*
|
||||||
* Setup a TSS descriptor
|
* Setup a TSS descriptor
|
||||||
*/
|
*/
|
||||||
gdt[desc].a = (length & 0xffff) | ((base & 0xffff) << 16);
|
GdtDesc[0] = (length & 0xffff) | ((base & 0xffff) << 16);
|
||||||
gdt[desc].b = ((base & 0xff0000)>>16) | 0x8900 | (length & 0xf0000)
|
GdtDesc[1] = ((base & 0xff0000)>>16) | 0x8900 | (length & 0xf0000)
|
||||||
| (base & 0xff000000);
|
| (base & 0xff000000);
|
||||||
|
desc = KeAllocateGdtSelector(GdtDesc);
|
||||||
|
if (desc == 0)
|
||||||
|
{
|
||||||
|
return(STATUS_UNSUCCESSFUL);
|
||||||
|
}
|
||||||
|
|
||||||
stack_start = kernel_stack + 4096 - sizeof(CONTEXT);
|
stack_start = kernel_stack + 4096 - sizeof(CONTEXT);
|
||||||
memcpy(stack_start, Context, sizeof(CONTEXT));
|
memcpy(stack_start, Context, sizeof(CONTEXT));
|
||||||
|
@ -225,7 +199,7 @@ NTSTATUS HalInitTaskWithContext(PETHREAD Thread, PCONTEXT Context)
|
||||||
* Initialize the thread context
|
* Initialize the thread context
|
||||||
*/
|
*/
|
||||||
memset(&Thread->Tcb.Context,0,sizeof(hal_thread_state));
|
memset(&Thread->Tcb.Context,0,sizeof(hal_thread_state));
|
||||||
Thread->Tcb.Context.ldt = null_ldt_sel;
|
Thread->Tcb.Context.ldt = KiNullLdtSel;
|
||||||
Thread->Tcb.Context.eflags = (1<<1) + (1<<9);
|
Thread->Tcb.Context.eflags = (1<<1) + (1<<9);
|
||||||
Thread->Tcb.Context.iomap_base = FIELD_OFFSET(hal_thread_state,io_bitmap);
|
Thread->Tcb.Context.iomap_base = FIELD_OFFSET(hal_thread_state,io_bitmap);
|
||||||
Thread->Tcb.Context.esp0 = (ULONG)stack_start;
|
Thread->Tcb.Context.esp0 = (ULONG)stack_start;
|
||||||
|
@ -263,7 +237,8 @@ NTSTATUS HalInitTask(PETHREAD thread, PKSTART_ROUTINE fn, PVOID StartContext)
|
||||||
unsigned int desc;
|
unsigned int desc;
|
||||||
unsigned int length = sizeof(hal_thread_state) - 1;
|
unsigned int length = sizeof(hal_thread_state) - 1;
|
||||||
unsigned int base = (unsigned int)(&(thread->Tcb.Context));
|
unsigned int base = (unsigned int)(&(thread->Tcb.Context));
|
||||||
PULONG kernel_stack = ExAllocatePool(NonPagedPool,4096);
|
PULONG KernelStack = ExAllocatePool(NonPagedPool,4096);
|
||||||
|
ULONG GdtDesc[2];
|
||||||
|
|
||||||
DPRINT("HalInitTask(Thread %x, fn %x, StartContext %x)\n",
|
DPRINT("HalInitTask(Thread %x, fn %x, StartContext %x)\n",
|
||||||
thread,fn,StartContext);
|
thread,fn,StartContext);
|
||||||
|
@ -274,47 +249,43 @@ NTSTATUS HalInitTask(PETHREAD thread, PKSTART_ROUTINE fn, PVOID StartContext)
|
||||||
*/
|
*/
|
||||||
assert(sizeof(hal_thread_state)>=0x68);
|
assert(sizeof(hal_thread_state)>=0x68);
|
||||||
|
|
||||||
desc = allocate_tss_descriptor();
|
/*
|
||||||
|
* Setup a TSS descriptor
|
||||||
|
*/
|
||||||
|
GdtDesc[0] = (length & 0xffff) | ((base & 0xffff) << 16);
|
||||||
|
GdtDesc[1] = ((base & 0xff0000)>>16) | 0x8900 | (length & 0xf0000)
|
||||||
|
| (base & 0xff000000);
|
||||||
|
desc = KeAllocateGdtSelector(GdtDesc);
|
||||||
if (desc == 0)
|
if (desc == 0)
|
||||||
{
|
{
|
||||||
return(STATUS_UNSUCCESSFUL);
|
return(STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup a TSS descriptor
|
|
||||||
*/
|
|
||||||
gdt[desc].a = (length & 0xffff) | ((base & 0xffff) << 16);
|
|
||||||
gdt[desc].b = ((base & 0xff0000)>>16) | 0x8900 | (length & 0xf0000)
|
|
||||||
| (base & 0xff000000);
|
|
||||||
|
|
||||||
// DPRINT("sizeof(descriptor) %d\n",sizeof(descriptor));
|
// DPRINT("sizeof(descriptor) %d\n",sizeof(descriptor));
|
||||||
// DPRINT("desc %d\n",desc);
|
// DPRINT("desc %d\n",desc);
|
||||||
DPRINT("&gdt[desc].a %.8x gdt[desc].a %.8x\ngdt[desc].b %.8x\n",
|
|
||||||
&(gdt[desc].a),
|
|
||||||
gdt[desc].a,
|
|
||||||
gdt[desc].b);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the stack for the thread (including the two arguments to
|
* Initialize the stack for the thread (including the two arguments to
|
||||||
* the general start routine).
|
* the general start routine).
|
||||||
*/
|
*/
|
||||||
kernel_stack[1023] = (unsigned int)StartContext;
|
KernelStack[1023] = (unsigned int)StartContext;
|
||||||
kernel_stack[1022] = (unsigned int)fn;
|
KernelStack[1022] = (unsigned int)fn;
|
||||||
kernel_stack[1021] = 0;
|
KernelStack[1021] = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the thread context
|
* Initialize the thread context
|
||||||
*/
|
*/
|
||||||
memset(&thread->Tcb.Context,0,sizeof(hal_thread_state));
|
memset(&thread->Tcb.Context,0,sizeof(hal_thread_state));
|
||||||
thread->Tcb.Context.ldt = null_ldt_sel;
|
thread->Tcb.Context.ldt = KiNullLdtSel;
|
||||||
thread->Tcb.Context.eflags = (1<<1)+(1<<9);
|
thread->Tcb.Context.eflags = (1<<1)+(1<<9);
|
||||||
thread->Tcb.Context.iomap_base = FIELD_OFFSET(hal_thread_state,io_bitmap);
|
thread->Tcb.Context.iomap_base = FIELD_OFFSET(hal_thread_state,io_bitmap);
|
||||||
thread->Tcb.Context.esp0 = (ULONG)&kernel_stack[1021];
|
thread->Tcb.Context.esp0 = (ULONG)&KernelStack[1021];
|
||||||
thread->Tcb.Context.ss0 = KERNEL_DS;
|
thread->Tcb.Context.ss0 = KERNEL_DS;
|
||||||
thread->Tcb.Context.esp = (ULONG)&kernel_stack[1021];
|
thread->Tcb.Context.esp = (ULONG)&KernelStack[1021];
|
||||||
thread->Tcb.Context.ss = KERNEL_DS;
|
thread->Tcb.Context.ss = KERNEL_DS;
|
||||||
thread->Tcb.Context.cs = KERNEL_CS;
|
thread->Tcb.Context.cs = KERNEL_CS;
|
||||||
thread->Tcb.Context.eip = (unsigned long)PsBeginThread;
|
thread->Tcb.Context.eip = (ULONG)PsBeginThread;
|
||||||
thread->Tcb.Context.io_bitmap[0] = 0xff;
|
thread->Tcb.Context.io_bitmap[0] = 0xff;
|
||||||
thread->Tcb.Context.cr3 = (ULONG)
|
thread->Tcb.Context.cr3 = (ULONG)
|
||||||
thread->ThreadsProcess->Pcb.PageTableDirectory;
|
thread->ThreadsProcess->Pcb.PageTableDirectory;
|
||||||
|
@ -323,7 +294,7 @@ NTSTATUS HalInitTask(PETHREAD thread, PKSTART_ROUTINE fn, PVOID StartContext)
|
||||||
thread->Tcb.Context.fs = KERNEL_DS;
|
thread->Tcb.Context.fs = KERNEL_DS;
|
||||||
thread->Tcb.Context.gs = KERNEL_DS;
|
thread->Tcb.Context.gs = KERNEL_DS;
|
||||||
thread->Tcb.Context.nr = desc * 8;
|
thread->Tcb.Context.nr = desc * 8;
|
||||||
thread->Tcb.Context.KernelStackBase = kernel_stack;
|
thread->Tcb.Context.KernelStackBase = KernelStack;
|
||||||
thread->Tcb.Context.SavedKernelEsp = 0;
|
thread->Tcb.Context.SavedKernelEsp = 0;
|
||||||
thread->Tcb.Context.SavedKernelStackBase = NULL;
|
thread->Tcb.Context.SavedKernelStackBase = NULL;
|
||||||
DPRINT("Allocated %x\n",desc*8);
|
DPRINT("Allocated %x\n",desc*8);
|
||||||
|
@ -337,18 +308,19 @@ void HalInitFirstTask(PETHREAD thread)
|
||||||
* initial thread
|
* initial thread
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned int base;
|
ULONG base;
|
||||||
unsigned int length;
|
ULONG length;
|
||||||
unsigned int desc;
|
ULONG desc;
|
||||||
|
ULONG GdtDesc[2];
|
||||||
|
|
||||||
memset(null_ldt,0,sizeof(null_ldt));
|
memset(KiNullLdt, 0, sizeof(KiNullLdt));
|
||||||
desc = allocate_tss_descriptor();
|
base = (unsigned int)&KiNullLdt;
|
||||||
base = (unsigned int)&null_ldt;
|
length = sizeof(KiNullLdt) - 1;
|
||||||
length = sizeof(null_ldt) - 1;
|
GdtDesc[0] = (length & 0xffff) | ((base & 0xffff) << 16);
|
||||||
gdt[desc].a = (length & 0xffff) | ((base & 0xffff) << 16);
|
GdtDesc[1] = ((base & 0xff0000)>>16) | 0x8200 | (length & 0xf0000)
|
||||||
gdt[desc].b = ((base & 0xff0000)>>16) | 0x8200 | (length & 0xf0000)
|
| (base & 0xff000000);
|
||||||
| (base & 0xff000000);
|
desc = KeAllocateGdtSelector(GdtDesc);
|
||||||
null_ldt_sel = desc*8;
|
KiNullLdtSel = desc*8;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the thread context
|
* Initialize the thread context
|
||||||
|
|
82
reactos/ntoskrnl/ke/gdt.c
Normal file
82
reactos/ntoskrnl/ke/gdt.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS kernel
|
||||||
|
* FILE: ntoskrnl/ke/gdt.c
|
||||||
|
* PURPOSE: GDT managment
|
||||||
|
* PROGRAMMER: David Welch (welch@cwcom.net)
|
||||||
|
* UPDATE HISTORY:
|
||||||
|
* Created 22/05/98
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *****************************************************************/
|
||||||
|
|
||||||
|
#include <ddk/ntddk.h>
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
#define NR_TASKS 128
|
||||||
|
|
||||||
|
USHORT KiGdt[(6 + NR_TASKS) * 4] = {0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0xfa00, 0xcc,
|
||||||
|
0x0, 0x0, 0xf200, 0xcc,
|
||||||
|
0xffff, 0x0, 0x9200, 0xcf,
|
||||||
|
0xffff, 0x0, 0x9a00, 0xcf,
|
||||||
|
0xffff, 0x0, 0x9200, 0xcf};
|
||||||
|
static KSPIN_LOCK GdtLock;
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
VOID KeDumpGdtSelector(ULONG Entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID KeFreeGdtSelector(ULONG Entry)
|
||||||
|
/*
|
||||||
|
* FUNCTION: Free a gdt selector
|
||||||
|
* ARGUMENTS:
|
||||||
|
* Entry = Entry to free
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
KIRQL oldIrql;
|
||||||
|
|
||||||
|
DPRINT("KeFreeGdtSelector(Entry %x)\n",Entry);
|
||||||
|
|
||||||
|
KeAcquireSpinLock(&GdtLock, &oldIrql);
|
||||||
|
KiGdt[Entry*4] = 0;
|
||||||
|
KiGdt[Entry*4 + 2] = 0;
|
||||||
|
KeReleaseSpinLock(&GdtLock, oldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG KeAllocateGdtSelector(ULONG Desc[2])
|
||||||
|
/*
|
||||||
|
* FUNCTION: Allocate a gdt selector
|
||||||
|
* ARGUMENTS:
|
||||||
|
* Desc = Contents for descriptor
|
||||||
|
* RETURNS: The index of the entry allocated
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ULONG i;
|
||||||
|
KIRQL oldIrql;
|
||||||
|
|
||||||
|
DPRINT("KeAllocateGdtSelector(Desc[0] %x, Desc[1] %x)\n",
|
||||||
|
Desc[0], Desc[1]);
|
||||||
|
|
||||||
|
KeAcquireSpinLock(&GdtLock, &oldIrql);
|
||||||
|
for (i=6; i<(6 + NR_TASKS); i++)
|
||||||
|
{
|
||||||
|
if (KiGdt[i*4] == 0 &&
|
||||||
|
KiGdt[i*4 + 2] == 0)
|
||||||
|
{
|
||||||
|
((PULONG)KiGdt)[i*2] = Desc[0];
|
||||||
|
((PULONG)KiGdt)[i*2 + 1] = Desc[1];
|
||||||
|
KeReleaseSpinLock(&GdtLock, oldIrql);
|
||||||
|
DPRINT("KeAllocateGdtSelector() = %x\n",i);
|
||||||
|
return(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeReleaseSpinLock(&GdtLock, oldIrql);
|
||||||
|
return(0);
|
||||||
|
}
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
NTSTATUS STDCALL NtSetLdtEntries(VOID)
|
|
||||||
|
|
||||||
|
NTSTATUS STDCALL NtSetLdtEntries(PEPROCESS Process,
|
||||||
|
ULONG FirstEntry,
|
||||||
|
PULONG Entries)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,7 +302,8 @@ LdrPEProcessDriver(PVOID ModuleLoadBase)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
CHECKPOINT;
|
CHECKPOINT;
|
||||||
|
DbgPrint("Module is at base %x\n",DriverBase);
|
||||||
|
|
||||||
/* Copy image sections into virtual section */
|
/* Copy image sections into virtual section */
|
||||||
memcpy(DriverBase, ModuleLoadBase, PESectionHeaders[0].PointerToRawData);
|
memcpy(DriverBase, ModuleLoadBase, PESectionHeaders[0].PointerToRawData);
|
||||||
CurrentBase = (PVOID) ((DWORD)DriverBase + PESectionHeaders[0].PointerToRawData);
|
CurrentBase = (PVOID) ((DWORD)DriverBase + PESectionHeaders[0].PointerToRawData);
|
||||||
|
@ -486,6 +487,7 @@ LdrPEProcessDriver(PVOID ModuleLoadBase)
|
||||||
|
|
||||||
/* Compute address of entry point */
|
/* Compute address of entry point */
|
||||||
EntryPoint = (PVOID) ((DWORD)DriverBase + PEOptionalHeader->AddressOfEntryPoint);
|
EntryPoint = (PVOID) ((DWORD)DriverBase + PEOptionalHeader->AddressOfEntryPoint);
|
||||||
|
DbgPrint("Calling entrypoint at %x\n",EntryPoint);
|
||||||
|
|
||||||
return IoInitializeDriver(EntryPoint);
|
return IoInitializeDriver(EntryPoint);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ KE_OBJECTS = ke/main.o ke/timer.o ke/error.o ke/catch.o ke/exports.o \
|
||||||
ke/dpc.o ke/wait.o ke/kqueue.o ke/dispatch.o \
|
ke/dpc.o ke/wait.o ke/kqueue.o ke/dispatch.o \
|
||||||
ke/sem.o ke/critical.o ke/event.o ke/apc.o ke/bug.o \
|
ke/sem.o ke/critical.o ke/event.o ke/apc.o ke/bug.o \
|
||||||
ke/mutex.o ke/kernel.o ke/ldt.o ke/apchelp.o \
|
ke/mutex.o ke/kernel.o ke/ldt.o ke/apchelp.o \
|
||||||
ke/process.o
|
ke/process.o ke/gdt.o
|
||||||
|
|
||||||
MM_OBJECTS = mm/mm.o mm/freelist.o mm/pool.o mm/virtual.o \
|
MM_OBJECTS = mm/mm.o mm/freelist.o mm/pool.o mm/virtual.o \
|
||||||
mm/mdl.o mm/zone.o mm/special.o mm/paging.o \
|
mm/mdl.o mm/zone.o mm/special.o mm/paging.o \
|
||||||
|
@ -50,7 +50,7 @@ DBG_OBJECTS = dbg/brkpoint.o dbg/errinfo.o
|
||||||
|
|
||||||
LDR_OBJECTS = ldr/loader.o
|
LDR_OBJECTS = ldr/loader.o
|
||||||
|
|
||||||
CC_OBJECTS = cc/cacheman.o cc/block.o
|
CC_OBJECTS = cc/cacheman.o cc/block.o cc/view.o
|
||||||
|
|
||||||
objects: ../ntoskrnl/objects
|
objects: ../ntoskrnl/objects
|
||||||
mkdir objects
|
mkdir objects
|
||||||
|
|
|
@ -64,3 +64,6 @@ RtlLargeIntegerGreaterThan
|
||||||
RtlLargeIntegerShiftRight
|
RtlLargeIntegerShiftRight
|
||||||
RtlZeroMemory
|
RtlZeroMemory
|
||||||
ZwCreateDirectoryObject@12
|
ZwCreateDirectoryObject@12
|
||||||
|
CbInitDccb
|
||||||
|
CbAcquireForRead
|
||||||
|
CbReleaseFromRead
|
||||||
|
|
Loading…
Reference in a new issue