Author: aandrejevic Date: Fri Sep 13 23:01:18 2013 New Revision: 60089
URL: http://svn.reactos.org/svn/reactos?rev=60089&view=rev Log: [SOFT386] Start implementing paging support. Add support for exception error codes.
Modified: branches/ntvdm/lib/soft386/common.c branches/ntvdm/lib/soft386/common.h
Modified: branches/ntvdm/lib/soft386/common.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/lib/soft386/common.c?rev=6... ============================================================================== --- branches/ntvdm/lib/soft386/common.c [iso-8859-1] (original) +++ branches/ntvdm/lib/soft386/common.c [iso-8859-1] Fri Sep 13 23:01:18 2013 @@ -28,6 +28,18 @@ return GET_SEGMENT_RPL(State->SegmentRegs[SOFT386_REG_CS].Selector); }
+static +inline +ULONG +Soft386GetPageTableEntry(PSOFT386_STATE State, + ULONG VirtualAddress) +{ + // TODO: NOT IMPLEMENTED + UNIMPLEMENTED; + + return 0; +} + /* PUBLIC FUNCTIONS ***********************************************************/
inline @@ -41,6 +53,7 @@ { ULONG LinearAddress; PSOFT386_SEG_REG CachedDescriptor; + INT Cpl = Soft386GetCurrentPrivLevel(State);
ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS);
@@ -97,18 +110,75 @@ /* Find the linear address */ LinearAddress = CachedDescriptor->Base + Offset;
- // TODO: Paging support! - - /* Did the host provide a memory hook? */ - if (State->MemReadCallback) - { - /* Yes, call the host */ - State->MemReadCallback(State, LinearAddress, Buffer, Size); + /* Check if paging is enabled */ + if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PG) + { + ULONG Page; + SOFT386_PAGE_TABLE TableEntry; + + for (Page = PAGE_ALIGN(LinearAddress); + Page <= PAGE_ALIGN(LinearAddress + Size - 1); + Page += PAGE_SIZE) + { + ULONG PageOffset = 0, PageLength = PAGE_SIZE; + + /* Get the table entry */ + TableEntry.Value = Soft386GetPageTableEntry(State, Page); + + if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0))) + { + /* Exception */ + Soft386ExceptionWithErrorCode(State, + SOFT386_EXCEPTION_PF, + TableEntry.Value & 0x07); + return FALSE; + } + + /* Check if this is the first page */ + if (Page == PAGE_ALIGN(LinearAddress)) + { + /* Start copying from the offset from the beginning of the page */ + PageOffset = PAGE_OFFSET(LinearAddress); + } + + /* Check if this is the last page */ + if (Page == PAGE_ALIGN(LinearAddress + Size - 1)) + { + /* Copy only a part of the page */ + PageLength = PAGE_OFFSET(LinearAddress + Size); + } + + /* Did the host provide a memory hook? */ + if (State->MemReadCallback) + { + /* Yes, call the host */ + State->MemReadCallback(State, + (TableEntry.Address << 12) | PageOffset, + Buffer, + PageLength); + } + else + { + /* Read the memory directly */ + RtlMoveMemory(Buffer, + (PVOID)((TableEntry.Address << 12) | PageOffset), + PageLength); + } + } } else { - /* Read the memory directly */ - RtlMoveMemory(Buffer, (PVOID)LinearAddress, Size); + /* Did the host provide a memory hook? */ + if (State->MemReadCallback) + { + /* Yes, call the host */ + State->MemReadCallback(State, LinearAddress, Buffer, Size); + } + else + { + /* Read the memory directly */ + RtlMoveMemory(Buffer, (PVOID)LinearAddress, Size); + } }
return TRUE; @@ -124,6 +194,7 @@ { ULONG LinearAddress; PSOFT386_SEG_REG CachedDescriptor; + INT Cpl = Soft386GetCurrentPrivLevel(State);
ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS);
@@ -174,18 +245,77 @@ /* Find the linear address */ LinearAddress = CachedDescriptor->Base + Offset;
- // TODO: Paging support! - - /* Did the host provide a memory hook? */ - if (State->MemWriteCallback) - { - /* Yes, call the host */ - State->MemWriteCallback(State, LinearAddress, Buffer, Size); + /* Check if paging is enabled */ + if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PG) + { + ULONG Page; + SOFT386_PAGE_TABLE TableEntry; + + for (Page = PAGE_ALIGN(LinearAddress); + Page <= PAGE_ALIGN(LinearAddress + Size - 1); + Page += PAGE_SIZE) + { + ULONG PageOffset = 0, PageLength = PAGE_SIZE; + + /* Get the table entry */ + TableEntry.Value = Soft386GetPageTableEntry(State, Page); + + if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0))) + || ((State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_WP) + && !TableEntry.Writeable)) + { + /* Exception */ + Soft386ExceptionWithErrorCode(State, + SOFT386_EXCEPTION_PF, + TableEntry.Value & 0x07); + return FALSE; + } + + /* Check if this is the first page */ + if (Page == PAGE_ALIGN(LinearAddress)) + { + /* Start copying from the offset from the beginning of the page */ + PageOffset = PAGE_OFFSET(LinearAddress); + } + + /* Check if this is the last page */ + if (Page == PAGE_ALIGN(LinearAddress + Size - 1)) + { + /* Copy only a part of the page */ + PageLength = PAGE_OFFSET(LinearAddress + Size); + } + + /* Did the host provide a memory hook? */ + if (State->MemWriteCallback) + { + /* Yes, call the host */ + State->MemWriteCallback(State, + (TableEntry.Address << 12) | PageOffset, + Buffer, + PageLength); + } + else + { + /* Read the memory directly */ + RtlMoveMemory((PVOID)((TableEntry.Address << 12) | PageOffset), + Buffer, + PageLength); + } + } } else { - /* Write the memory directly */ - RtlMoveMemory((PVOID)LinearAddress, Buffer, Size); + /* Did the host provide a memory hook? */ + if (State->MemWriteCallback) + { + /* Yes, call the host */ + State->MemWriteCallback(State, LinearAddress, Buffer, Size); + } + else + { + /* Write the memory directly */ + RtlMoveMemory((PVOID)LinearAddress, Buffer, Size); + } }
return TRUE; @@ -709,7 +839,7 @@
VOID FASTCALL -Soft386Exception(PSOFT386_STATE State, INT ExceptionCode) +Soft386ExceptionWithErrorCode(PSOFT386_STATE State, INT ExceptionCode, ULONG ErrorCode) { SOFT386_IDT_ENTRY IdtEntry;
@@ -752,6 +882,20 @@ */ return; } + + if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode)) + { + /* Push the error code */ + Soft386StackPush(State, ErrorCode); + } +} + +inline +VOID +Soft386Exception(PSOFT386_STATE State, INT ExceptionCode) +{ + /* Call the internal function */ + Soft386ExceptionWithErrorCode(State, ExceptionCode, 0); }
inline
Modified: branches/ntvdm/lib/soft386/common.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/lib/soft386/common.h?rev=6... ============================================================================== --- branches/ntvdm/lib/soft386/common.h [iso-8859-1] (original) +++ branches/ntvdm/lib/soft386/common.h [iso-8859-1] Fri Sep 13 23:01:18 2013 @@ -20,6 +20,13 @@ #define SIGN_FLAG_LONG 0x80000000 #define GET_SEGMENT_RPL(s) ((s) & 3) #define GET_SEGMENT_INDEX(s) ((s) & 0xFFF8) +#define EXCEPTION_HAS_ERROR_CODE(x) (((x) == 8) || ((x) >= 10 && (x) <= 14)) +#define PAGE_ALIGN(x) ((x) & 0xFFFFF000) +#define PAGE_OFFSET(x) ((x) & 0x00000FFF) + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif
typedef struct _SOFT386_MOD_REG_RM { @@ -32,6 +39,47 @@ }; } SOFT386_MOD_REG_RM, *PSOFT386_MOD_REG_RM;
+#pragma pack(push, 1) + +typedef struct _SOFT386_PAGE_DIR +{ + union + { + ULONG Present : 1; + ULONG Writeable : 1; + ULONG Usermode : 1; + ULONG WriteThrough : 1; + ULONG NoCache : 1; + ULONG Accessed : 1; + ULONG AlwaysZero : 1; + ULONG Size : 1; + ULONG Unused : 4; + ULONG TableAddress : 20; + }; + ULONG Value; +} SOFT386_PAGE_DIR, *PSOFT386_PAGE_DIR; + +typedef struct _SOFT386_PAGE_TABLE +{ + union + { + ULONG Present : 1; + ULONG Writeable : 1; + ULONG Usermode : 1; + ULONG WriteThrough : 1; + ULONG NoCache : 1; + ULONG Accessed : 1; + ULONG Dirty : 1; + ULONG AlwaysZero : 1; + ULONG Global : 1; + ULONG Unused : 3; + ULONG Address : 20; + }; + ULONG Value; +} SOFT386_PAGE_TABLE, *PSOFT386_PAGE_TABLE; + +#pragma pack(pop) + /* FUNCTIONS ******************************************************************/
inline @@ -126,7 +174,16 @@ );
VOID -__fastcall +FASTCALL +Soft386ExceptionWithErrorCode +( + PSOFT386_STATE State, + INT ExceptionCode, + ULONG ErrorCode +); + +inline +VOID Soft386Exception ( PSOFT386_STATE State,