[SOFT386]

Implement Soft386LoadSegment.
[NTVDM]
Fix BiosPrintCharacter (Adapted from a patch by Hermes Belusca-Maito).


svn path=/branches/ntvdm/; revision=59764
This commit is contained in:
Aleksandar Andrejevic 2013-08-17 18:44:16 +00:00
parent c7b66d26f6
commit 99302b9d00
3 changed files with 201 additions and 26 deletions

View file

@ -10,6 +10,16 @@
#include "common.h"
/* PRIVATE FUNCTIONS **********************************************************/
static
inline
INT
Soft386GetCurrentPrivLevel(PSOFT386_STATE State)
{
return GET_SEGMENT_RPL(State->SegmentRegs[SOFT386_REG_CS].Selector);
}
/* PUBLIC FUNCTIONS ***********************************************************/
inline
@ -48,7 +58,7 @@ Soft386ReadMemory(PSOFT386_STATE State,
return FALSE;
}
if (GET_SEGMENT_DPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
if (GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
{
// TODO: Generate exception #GP
return FALSE;
@ -131,7 +141,7 @@ Soft386WriteMemory(PSOFT386_STATE State,
return FALSE;
}
if (GET_SEGMENT_DPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
if (GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
{
// TODO: Generate exception #GP
return FALSE;
@ -299,4 +309,114 @@ Soft386StackPop(PSOFT386_STATE State, PULONG Value)
return TRUE;
}
inline
BOOLEAN
Soft386LoadSegment(PSOFT386_STATE State, INT Segment, WORD Selector)
{
PSOFT386_SEG_REG CachedDescriptor;
SOFT386_GDT_ENTRY GdtEntry;
ASSERT(Segment < SOFT386_NUM_SEG_REGS);
/* Get the cached descriptor */
CachedDescriptor = &State->SegmentRegs[Segment];
/* Check for protected mode */
if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
{
/* Make sure the GDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
{
// TODO: Exception #GP
return FALSE;
}
/* Read the GDT */
// FIXME: This code is only correct when paging is disabled!!!
if (State->MemReadCallback)
{
State->MemReadCallback(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
&GdtEntry,
sizeof(GdtEntry));
}
else
{
RtlMoveMemory(&GdtEntry,
(LPVOID)(State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector)),
sizeof(GdtEntry));
}
/* Check if we are loading SS */
if (Segment == SOFT386_REG_SS)
{
if (GET_SEGMENT_INDEX(Selector) == 0)
{
// TODO: Exception #GP
return FALSE;
}
if (GdtEntry.Executable || !GdtEntry.ReadWrite)
{
// TODO: Exception #GP
return FALSE;
}
if ((GET_SEGMENT_RPL(Selector) != Soft386GetCurrentPrivLevel(State))
|| (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
{
// TODO: Exception #GP
return FALSE;
}
if (!GdtEntry.Present)
{
// TODO: Exception #SS
return FALSE;
}
}
else
{
if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
&& (Soft386GetCurrentPrivLevel(State) > GdtEntry.Dpl))
{
// TODO: Exception #GP
return FALSE;
}
if (!GdtEntry.Present)
{
// TODO: Exception #NP
return FALSE;
}
}
/* Update the cache entry */
CachedDescriptor->Selector = Selector;
CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
CachedDescriptor->Accessed = GdtEntry.Accessed;
CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
CachedDescriptor->DirConf = GdtEntry.DirConf;
CachedDescriptor->Executable = GdtEntry.Executable;
CachedDescriptor->SystemType = GdtEntry.SystemType;
CachedDescriptor->Dpl = GdtEntry.Dpl;
CachedDescriptor->Present = GdtEntry.Present;
CachedDescriptor->Size = GdtEntry.Size;
/* Check for page granularity */
if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
}
else
{
/* Update the selector and base */
CachedDescriptor->Selector = Selector;
CachedDescriptor->Base = Selector << 4;
}
return TRUE;
}
/* EOF */

View file

@ -15,7 +15,8 @@
/* DEFINES ********************************************************************/
#define GET_SEGMENT_DPL(s) ((s) & 3)
#define GET_SEGMENT_RPL(s) ((s) & 3)
#define GET_SEGMENT_INDEX(s) ((s) & 0xFFF8)
/* FUNCTIONS ******************************************************************/
@ -58,6 +59,15 @@ Soft386StackPop
PULONG Value
);
inline
BOOLEAN
Soft386LoadSegment
(
PSOFT386_STATE State,
INT Segment,
WORD Selector
);
#endif // _COMMON_H_
/* EOF */

View file

@ -356,7 +356,7 @@ static VOID BiosWriteWindow(LPWORD Buffer, SMALL_RECT Rectangle, BYTE Page)
{
Character = Buffer[Counter++];
/* Read from video memory */
/* Write to video memory */
VgaWriteMemory(VideoAddress + (i * Bda->ScreenColumns + j) * sizeof(WORD),
(LPVOID)&Character,
sizeof(WORD));
@ -701,33 +701,78 @@ VOID BiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page)
Row = HIBYTE(Bda->CursorPosition[Page]);
Column = LOBYTE(Bda->CursorPosition[Page]);
/* Write the character */
VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG,
(Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
(LPVOID)&CharData,
sizeof(WORD));
if (Character == '\a')
{
/* Bell control character */
// NOTE: We may use what the terminal emulator offers to us...
Beep(800, 200);
return;
}
else if (Character == '\b')
{
/* Backspace control character */
if (Column > 0)
{
Column--;
}
else if (Row > 0)
{
Column = Bda->ScreenColumns - 1;
Row--;
}
/* Advance the cursor */
Column++;
/* Erase the existing character */
CharData = (Attribute << 8) | ' ';
VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG,
Page * Bda->VideoPageSize
+ (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
(LPVOID)&CharData,
sizeof(WORD));
}
else if (Character == '\n')
{
/* Line Feed control character */
Row++;
}
else if (Character == '\r')
{
/* Carriage Return control character */
Column = 0;
}
else
{
/* Default character */
/* Write the character */
VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG,
Page * Bda->VideoPageSize
+ (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
(LPVOID)&CharData,
sizeof(WORD));
/* Advance the cursor */
Column++;
}
/* Check if it passed the end of the row */
if (Column == Bda->ScreenColumns)
if (Column >= Bda->ScreenColumns)
{
/* Return to the first column */
/* Return to the first column and go to the next line */
Column = 0;
Row++;
}
if (Row == Bda->ScreenRows)
{
/* The screen must be scrolled */
SMALL_RECT Rectangle = { 0, 0, Bda->ScreenColumns - 1, Bda->ScreenRows };
/* Scroll the screen up if needed */
if (Row > Bda->ScreenRows)
{
/* The screen must be scrolled up */
SMALL_RECT Rectangle = { 0, 0, Bda->ScreenColumns - 1, Bda->ScreenRows };
BiosScrollWindow(SCROLL_DIRECTION_UP,
1,
Rectangle,
Page,
DEFAULT_ATTRIBUTE);
}
else Row++;
BiosScrollWindow(SCROLL_DIRECTION_UP,
1,
Rectangle,
Page,
DEFAULT_ATTRIBUTE);
}
/* Set the cursor position */
@ -820,8 +865,8 @@ VOID BiosVideoService(LPWORD Stack)
};
/* Call the internal function */
BiosScrollWindow((HIBYTE(Eax) == 0x06)
? SCROLL_DIRECTION_UP : SCROLL_DIRECTION_DOWN,
BiosScrollWindow((HIBYTE(Eax) == 0x06) ? SCROLL_DIRECTION_UP
: SCROLL_DIRECTION_DOWN,
LOBYTE(Eax),
Rectangle,
Bda->VideoPage,